ssh内网穿透
公司内网有台测试服务器,网穿只开了22端口,网穿外网连不上。网穿家里想访问,网穿又不想找运维开防火墙。网穿这种情况我遇到过不下十次,网穿最后都是网穿用 SSH 反向隧道解决的。说白了,网穿就是网穿让内网机器主动连一台公网服务器,把端口"挂"上去,网穿外面的网穿人通过公网服务器中转进来。
原理不复杂。网穿SSH 有本地转发和远程转发两种模式。网穿本地转发是网穿把本地端口映射到远程;远程转发反过来,把远程端口映射到本地。网穿内网穿透用的是远程转发,命令长这样:
ssh -R 8080:localhost:3000 user@public-server.com 这条命令的意思是:在 public-server.com 上监听 8080 端口,所有发到那个端口的流量,通过 SSH 隧道转发到内网机器的 3000 端口。内网机器主动发起的连接,NAT 和防火墙通常不会拦。
几个容易踩的坑
第一个坑:默认情况下,远程转发只绑定在公网服务器的 127.0.0.1 上。也就是说,只有公网服务器自己能访问那个 8080。外面的人连不上。解决办法是在公网服务器的 /etc/ssh/sshd_config 里加上 GatewayPorts yes,然后重启 sshd。这样端口才会绑定到 0.0.0.0。
第二个坑:连接断了隧道就没了。SSH 会话一断,端口映射自动消失。我一般用 autossh 来保持连接:
autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -R 8080:localhost:3000 user@public-server.com -M 0 是关掉 autossh 自己的监控端口,改用 SSH 的 keepalive 机制。ServerAliveInterval 30 表示每 30 秒发一次心跳,连续 3 次没回应就重连。这套配置我跑了大半年,没掉过链子。
第三个坑:公网服务器的 8080 端口可能被防火墙挡了。这个跟 SSH 没关系,得单独开。用 firewall-cmd 或者 ufw 放行就行。
更省事的做法
如果只是临时用一下,懒得改 sshd_config,可以用 -R 指定绑定地址:
ssh -R 0.0.0.0:8080:localhost:3000 user@public-server.com 但要注意,这需要公网服务器的 sshd 允许客户端指定绑定地址。有些发行版默认不允许,会报 Warning: remote port forwarding failed for listen port 8080。遇到这个错误,还是得回去改 GatewayPorts。
还有个细节:如果公网服务器上已经有服务占了 8080,SSH 会直接失败。换个大号端口,比如 18080,省得跟系统服务打架。
安全性怎么处理
别用密码登录。公网服务器上开 PasswordAuthentication no,只允许密钥认证。内网机器生成一对密钥,公钥扔到公网服务器的 ~/.ssh/authorized_keys 里。这样即使端口暴露,爆破也进不来。
再进一步,可以给这个 SSH 连接单独建一个用户,限制它只能做端口转发,不给 shell 权限。在 authorized_keys 里加 no-pty,no-X11-forwarding,permitopen="localhost:3000" 这类限制。不过配置起来麻烦,看你对安全的要求有多高。
我自己的做法是:公网服务器只开密钥登录,SSH 端口从 22 改成 59222,fail2ban 装上。三层防护下来,基本够用。
什么时候不该用 SSH 隧道
流量大的场景别用。SSH 隧道加解密有开销,传大文件或者跑视频流,CPU 会先扛不住。这种需求上 WireGuard 或者 frp 更合适。SSH 隧道适合临时调试、小流量 API 转发、内网 Web 服务临时暴露。够用,但不万能。
另外,如果内网机器连不上公网服务器的 22 端口,那这套方案直接废了。有些公司网络只放行 80 和 443,这时候得把公网服务器的 SSH 也监听在 443 上,或者用 sslh 做端口复用。那是另一个话题了。
(责任编辑:时尚)














