ssh端口转发需注意绑定地址与配置:本地转发(-l)默认仅监听127.0.0.1,需显式指定*或0.0.0.0供外部访问;远程转发(-r)须在服务端启用gatewayports yes,否则静默失败;动态转发(-d)为socks5代理,需浏览器/工具正确配置。

SSH端口转发不需要改服务器配置就能用,但默认只监听 127.0.0.1,想让其他机器访问必须显式指定 * 或 0.0.0.0;远程转发(-R)则必须提前在服务端开启 GatewayPorts yes,否则会静默失败。
本地转发(-L):为什么连上了却访问不了?
最常见问题是本地端口被占用,或远程目标服务没在 localhost 上监听。比如你执行:
ssh -L 8080:localhost:3000 user@remote
但远程的 Web 服务实际绑定在 0.0.0.0:3000,而你写成 localhost 就没问题;可如果它只监听 127.0.0.1:3000,那这个命令本身是有效的——问题出在你本机访问时用了 http://remote-ip:8080,而 -L 默认只绑定到 127.0.0.1,外部根本连不到。
- 想让局域网其他设备也能访问本地映射端口,得写成:
ssh -L *:8080:localhost:3000 user@remote - 如果提示
bind: Cannot assign requested address,说明系统不支持*,换成0.0.0.0:8080 - 加
-N防止登录后直接进 shell,加-f让进程后台运行,组合起来就是:ssh -f -N -L *:8080:localhost:3000 user@remote
远程转发(-R):为什么 ssh -R 8080:localhost:22 user@remote 没反应?
远程转发不是“开箱即用”的功能。它默认被禁用,因为存在安全风险:允许客户端把任意端口暴露在服务端上。所以即使命令执行成功、没报错,你在 remote 上执行 netstat -tln | grep 8080 也看不到监听。
- 必须在远程服务器的
/etc/ssh/sshd_config中设置:GatewayPorts yes,然后重启服务:sudo systemctl restart sshd - 如果只想让该端口能被本机访问(更安全),用
ssh -R 127.0.0.1:8080:localhost:22 user@remote,这样无需改sshd_config - 若仍失败,检查远程防火墙是否放行了该端口(如
ufw allow 8080)
动态转发(-D):浏览器配了 SOCKS 代理还是打不开网页?
-D 创建的是 SOCKS5 代理,不是 HTTP 代理。很多工具(比如 curl)默认不走 SOCKS,浏览器也要明确选“SOCKS Host”,不能选“HTTP Proxy”。
- 启动命令:
ssh -D 1080 -C -N user@remote(-C启用压缩,对低带宽有用) - 浏览器代理设置里,“SOCKS Host”填
localhost,“Port”填1080,协议选SOCKS v5;不要勾选“Proxy DNS when using SOCKS v5”除非你真需要解析远程 DNS - 命令行下要用
curl --socks5-hostname localhost:1080 https://example.com,注意是--socks5-hostname而不是-x - 某些网站(如 Cloudflare 验证页)会检测代理行为,可能触发拦截,这不是隧道问题,是目标站策略
后台运行与稳定性:怎么让隧道不死?
原生命令容易断,尤其网络抖动或休眠唤醒后。别依赖 -f -N 就以为万事大吉。
- 用
autossh替代ssh:安装后直接把命令里ssh换成autossh,它会自动重连、心跳保活 - 避免密钥密码交互:用
ssh-add加载私钥,否则autossh无法自动重连 - 加
-o ServerAliveInterval=30和-o ExitOnForwardFailure=yes,前者防假死,后者确保端口转发失败时立刻退出,方便autossh拉起新连接 - 别把隧道当长期服务跑在前台终端里——关掉终端,SSH 进程就收
SIGHUP退出了
真正麻烦的从来不是命令怎么写,而是搞清流量路径里每一跳的绑定地址、监听范围和权限控制。比如 localhost 在本地转发里指远程服务器的 127.0.0.1,但在远程转发里又变成你本地机器的 127.0.0.1——这种语义切换,才是踩坑最多的地方。










