大家好,我是冯哥的缓存。
今天我们来聊一下动态转发-D,它是一种"万能"模式,也是很多人最容易忽视的。最后还会聊几个实战组合场景,以及 SSH 隧道 vs frp/ngrok 这类工具。
一、动态转发-D——SOCKS5 代理出口
1.1 原理
本机:本地端口(SOCKS5代理)→ SSH隧道 → 远端服务器 → 目标地址
-D和 -L的区别:
·-L是固定目标:转发到哪个地址和端口,建隧道时就写死了
·-D是动态目标:本机开一个 SOCKS5 代理端口,所有走这个代理的流量,由远端服务器决定最终去哪
说白了,-D就是用远端服务器做出口,在本机开了一个 SOCKS5 代理。
ssh -D 1080 -N user@远端服务器
·-D 1080:本机监听1080 端口,作为 SOCKS5 代理入口
·-N:不执行远端命令,只保持隧道
·所有走这个代理的流量,都从"远端服务器"出去 这个命令只开隧道,不打开终端,加 -f 可以后台运行。
1.2-L vs -D对比
对比项 | 本地转发 -L | 动态转发 -D |
目标地址 | 建隧道时写死 | 运行时动态决定 |
代理协议 | 透明 TCP 转发 | SOCKS5 |
典型用途 | 访问特定数据库/Web管理界面 | 让浏览器、curl等一批工具走代理出口 |
配置复杂度 | 简单 | 客户端需配置代理 |
1.3 后台运行
# 后台运行,不占终端
ssh -D 1080 -N -f user@远端服务器
# 如果 1080 被占用,查看是谁占用了,或换一个端口
ss -tlnp | grep 1080
# 查看是否在运行
ps aux | grep ssh
# 如果想让局域网内其他设备也用这个代理,加 -g参数,SSH 会监听所有网卡
ssh -g -D 1080 user@远端
二、让软件走SOCKS5 代理
-D开起来之后,代理本身已经就绪了。但各个软件走不走这个代理,需要单独配置。
2.1 浏览器(Firefox)
Firefox 可以单独设置代理,不影响系统网络:
1.设置 → 网络设置 → 手动代理
2.SOCKS 主机:127.0.0.1,端口:1080
3.选SOCKS v5,勾选"通过代理服务器发送 DNS 查询"
Chrome/Chromium 不支持单独设置代理,需要启动时加参数:
google-chrome --proxy-server="socks5://127.0.0.1:1080"
设置完后,访问http://ifconfig.me 看看 IP 是否变成了远端服务器的 IP,确认代理生效
2.2 curl
# 单次请求走代理
curl --socks5-hostname 127.0.0.1:1080 https://example.com
# 或者设置环境变量(本终端会话生效)
export ALL_PROXY=socks5://127.0.0.1:1080
curl https://example.com
--socks5-hostname 在远端解析域名,避免 DNS 泄漏; --socks5 在本地解析域名。
2.3 git
# 针对某个仓库
git config http.proxy socks5://127.0.0.1:1080
git config https.proxy socks5://127.0.0.1:1080
# 全局生效
git config --global http.proxy socks5://127.0.0.1:1080
git config --global https.proxy socks5://127.0.0.1:1080
# 用完取消
git config --global --unset http.proxy
git config --global --unset https.proxy
2.4 apt(系统包管理器)
# 临时走代理安装
sudo -E apt-get install -o Acquire::http::proxy="socks5h://127.0.0.1:1080/" 包名
# 或者写进配置文件(永久生效)
echo 'Acquire::http::Proxy "socks5h://127.0.0.1:1080/";' | sudo tee /etc/apt/apt.conf.d/proxy.conf
# 如果程序只支持 HTTP 代理而不支持 SOCKS,可以用 proxychains 将 SOCKS 转为 HTTP 代理
sudo apt install proxychains4
# 配置/etc/proxychains4.conf 里的 SOCKS5 代理地址。
⚠️注意:socks5h中的 h表示 DNS 也走代理解析,推荐用 socks5h而不是 socks5,避免 DNS 泄漏。
2.5 系统全局代理(环境变量)
# 临时设置,只对当前终端生效
export http_proxy=socks5://127.0.0.1:1080
export https_proxy=socks5://127.0.0.1:1080
export ALL_PROXY=socks5://127.0.0.1:1080
# 取消
unset http_proxy https_proxy ALL_PROXY
💡提示:不是所有程序都读环境变量的,图形界面程序一般不读。浏览器、curl、git、pip 等命令行工具大多支持。
三、autossh——让隧道不断线
普通ssh -D断线了就没了,需要手动重连。autossh会自动重连。
3.1 安装
sudo apt install autossh
3.2 基本用法
# 动态转发,断线自动重连
autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \
-D 1080 -N user@远端服务器
参数说明:
参数 | 含义 |
-M 0 | 不用监控端口(推荐,用 ServerAlive 代替) |
ServerAliveInterval 30 | 每 30 秒发心跳包 |
ServerAliveCountMax 3 | 心跳包失败 3 次后重连 |
3.3 systemd 开机自启
新建/etc/systemd/system/ssh-socks.service:
[Unit]
Description=SSH SOCKS5 Proxy
After=network.target
[Service]
User=自己的用户名
ExecStart=/usr/bin/autossh -M 0 \
-o "ServerAliveInterval 30" \
-o "ServerAliveCountMax 3" \
-o "ExitOnForwardFailure yes" \
-o "StrictHostKeyChecking no" \
-D 1080 -N user@远端服务器
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable ssh-socks
sudo systemctl start ssh-socks
# 检查状态
sudo systemctl status ssh-socks
四、多跳转发——隧道套隧道
有时候目标服务器不能直接连,需要先跳一台跳板机,再连目标。
4.1 场景描述
本机→ 跳板机A(有公网IP)→ 内网服务器B → 数据库:3306
4.2 一条命令多跳
# 通过A跳到B,把B上3306映射到本机3306
ssh -L 3306:数据库IP:3306 -J userA@跳板机A userB@内网服务器B -N
数据库IP:例如 127.0.0.1-J是 ProxyJump,上篇详细讲过。
4.3 配置文件方式
# ~/.ssh/config
Host 内网服务器B
HostName 192.168.1.100
User userB
ProxyJump userA@跳板机A
Host 数据库隧道
HostName 内网服务器B
User userB
LocalForward 3306 127.0.0.1:3306
ProxyJump userA@跳板机A
然后:
ssh -N 数据库隧道
# 本机localhost:3306 就能访问到内网数据库了
4.4 动态转发多跳
# 通过A跳到B,以B为出口开SOCKS5代理
ssh -D 1080 -J userA@跳板机A -N userB@内网服务器B
这样出口是内网服务器B,能访问只有B能到的资源。
五、实战场景汇总
5.1 在家访问公司内网系统
公司有一台可以 SSH 的跳板机(对外开放22端口)
公司内网有各种服务(Gitlab/Jenkins/数据库/监控面板)
方案:
# 方案A:用-L逐个映射(每个服务一条命令)
ssh -L 8080:jenkins内网IP:8080 -L 3306:mysql内网IP:3306 -N user@跳板机 &
# 方案B:用-D开SOCKS5代理,浏览器配代理,所有公司内网都能访问
ssh -D 1080 -N user@跳板机 &
# 然后浏览器配代理127.0.0.1:1080,直接访问内网IP
💡提示:服务多的时候,方案B(-D)更省事,不用一个个列端口;服务固定的时候,方案A(-L)更精准。
5.2 把家里 NAS 暴露到公网
家里有台 NAS,没有公网 IP
有一台有公网 IP 的 VPS
方案(-R远程转发):
# 在NAS上运行(把NAS的80端口映射到VPS的8080端口)
ssh -R 8080:localhost:80 -N user@VPS
VPS 上的 /etc/ssh/sshd_config需要加:
GatewayPorts yes
然后公网IP:8080就能访问到家里 NAS 的 80 端口了。
5.3 远程调试——把开发机的端口给同事看
在本地跑了个 Web 服务在 localhost:3000
想看效果,但没有公网 IP
方案(-R远程转发):
# 在机器上运行
ssh -R 3000:localhost:3000 -N user@有公网IP的服务器
同事访问服务器公网IP:3000就能看到本地的服务了。
⚠️注意:调试完记得断开,不要让生产服务长期暴露在这种临时隧道上。
六、SSH 隧道 vs frp/ngrok——怎么选?
SSH 端口转发能做的事,frp、ngrok 这类工具也能做。那什么时候用哪个?
对比项 | SSH 隧道 | frp / ngrok |
前提条件 | 需要一台能 SSH 的服务器 | 需要服务端支持(frp自建/ngrok用官方) |
配置复杂度 | 低(一行命令) | 中(需要配置文件) |
断线重连 | 需要 autossh | 内置 |
支持协议 | TCP(SSH本身) | TCP/UDP/HTTP/HTTPS |
子域名/域名 | 不支持 | ngrok 支持随机子域名 |
性能 | 一般(加密开销) | 较好(专为转发优化) |
适用场景 | 临时、已有SSH服务器、简单需求 | 长期稳定、需要域名/HTTPS、高并发 |
费用 | 零(用自己服务器) | frp自建免费;ngrok免费版有限制 |
决策建议:
·临时用一下、服务器已经有 SSH → 直接用 SSH 隧道,一行命令搞定
·长期稳定内网穿透、需要 HTTP/HTTPS 域名 → frp(自建)
·快速演示、不想折腾服务器 → ngrok 免费版(有连接数、域名和流量限制)
·企业级需求、高并发 → frp 或其他专业工具
七、常见问题排查
问题 | 原因 | 解决方法 |
bind: Address already in use | 本地端口被占用 | 换一个本地端口号,或 kill 占用进程 |
隧道建好了但连不上 | 目标端口服务没起来 | netstat -tlnp 检查目标服务状态 |
-R 只能本地访问,外网访问不了 | GatewayPorts 未开启 | 远端 sshd_config 加 GatewayPorts yes |
隧道频繁断线 | 网络不稳定 / 无心跳包 | 用 autossh,加 ServerAliveInterval |
Channel 3: open failed | 目标地址/端口不通 | 检查目标端口是否开放,防火墙规则 |
DNS 解析不走代理 | 用了 socks5 而非 socks5h | 把 socks5 换成 socks5h |
八、三种转发完整速查表
-L本地转发
# 基本格式
ssh -L 本地端口:目标地址:目标端口 user@跳板机 -N
# 常用示例
ssh -L 3306:127.0.0.1:3306 user@远端-N# 访问远端数据库
ssh -L 8080:内网IP:80 user@跳板机 -N# 访问内网Web服务
ssh -L 5432:db-server:5432 -J user@跳板机 user@内网 -N# 多跳
-R远程转发
# 基本格式
ssh -R 远端端口:本地地址:本地端口 user@远端 -N
# 常用示例
ssh -R 8080:localhost:80 user@VPS -N# 把本机80暴露到VPS:8080
ssh -R 3000:localhost:3000 user@服务器 -N# 调试端口给同事看
-D动态转发
# 基本格式
ssh -D 本地端口 user@远端 -N
# 常用示例
ssh -D 1080 user@服务器 -N# 开SOCKS5代理
autossh -M 0 -o "ServerAliveInterval 30" -D 1080 user@服务器 -N# autossh版
配合config 文件
# ~/.ssh/config
Host 隧道别名
HostName 服务器IP
User username
LocalForward 3306 127.0.0.1:3306
DynamicForward 1080
ServerAliveInterval 30
# 直接用别名建隧道
ssh -N 隧道别名
小结
覆盖了日常用到的绝大多数场景:
篇章 | 内容 |
SSH 基础篇 | 密钥免密、config 别名、scp/rsync 传文件、跳板机 ProxyJump |
端口转发上篇 | 本地转发 -L(拉服务过来)、远程转发 -R(推服务出去) |
端口转发下篇 | 动态转发 -D(SOCKS5 代理)、autossh 持久化、多跳场景、vs frp/ngrok 选择 |
SSH 这个工具已经 30 年了,但它能做的事到现在还是很多人没有充分挖掘。端口转发这块搞清楚之后,很多"访问不到"的问题就有了解法。
下一篇:《Linux UFW 防火墙配置——端口规则与服务保护》,从"进去"转到"守门",聊怎么用 UFW 保护自己的 Linux 机器。