ssh -L 实现本地端口转发无需改服务器配置或额外工具,5分钟内可通;最常见失败原因是-L后目标地址写错——同机须写localhost,跨机则需跳板机能访问且服务监听0.0.0.0。

ssh -L 命令里目标地址写错是最常见失败原因
很多人执行 ssh -L 后本地能连上跳板机,但访问 localhost:端口 一直超时或拒绝连接,问题几乎都出在 -L 后面的“目标地址”不是跳板机能访问的地址。
- 如果目标服务(比如 MySQL)和跳板机在同一台机器上,目标地址必须写
localhost或127.0.0.1—— 写跳板机自己的局域网 IP(如192.168.1.50)或公网 IP 都会失败 - 如果目标服务在另一台内网机器(如
192.168.1.100),先在跳板机上ping 192.168.1.100和telnet 192.168.1.100 3306确认通路;再确认该服务监听的是0.0.0.0:3306或192.168.1.100:3306,而不是仅127.0.0.1:3306 - 命令中
-L 3306:192.168.1.100:3306的192.168.1.100是对跳板机而言的,不是对你本机而言的
后台常驻运行必须加 -fN,否则终端一关隧道就断
只跑 ssh -L 8080:web.internal:80 user@jump,SSH 会卡在登录 shell 里,关掉终端或 Ctrl+C 就断;想让它静默长期运行,必须加参数:
-
-f:让 SSH 进程 fork 到后台,不占当前终端 -
-N:明确禁止执行远程命令,只做端口转发(没它的话,-f 可能无效) -
-T:可选,禁用伪终端分配,更干净,适合脚本或 systemd service
正确示例:ssh -fNT -L 8080:web.internal:80 user@jump-host。验证是否生效可用:lsof -i :8080 或 ss -tlnp | grep 8080。
本地端口被占用或权限不足时怎么办
Linux 下绑定 1–1023 端口需要 root 权限,普通用户默认只能绑 ≥1024 的端口:
- 报错
bind: Permission denied?换端口,比如用8080代替80,用3307代替3306 - 报错
Address already in use?先查谁占着:lsof -i :3306,再kill或换端口 - 想让局域网其他机器也能访问你本地开的隧道端口(比如同事连你
192.168.1.20:8080)?不能只写-L 8080:...,得写成-L *:8080:target:80,但前提是跳板机的/etc/ssh/sshd_config里有GatewayPorts clientspecified或yes,且你有权限改——一般生产环境不开放,安全风险高
真正容易被忽略的是目标服务的监听地址
很多内网服务(尤其是 Docker 容器、Node.js 开发服务器、MySQL 默认配置)只监听 127.0.0.1,导致跳板机从外部 IP 访问不到。哪怕 ssh -L 命令完全正确,也转不过去。
必须确认目标服务监听的是 0.0.0.0 或对应内网 IP。例如:
- Docker 启动时加
--network host或显式映射-p 0.0.0.0:3306:3306 - MySQL 检查
bind-address是否为0.0.0.0(而非默认的127.0.0.1) - Node.js 服务启动时指定
server.listen(3000, '0.0.0.0')而非server.listen(3000)(后者等价于127.0.0.1)


















