SSH 端口转发笔记
这是 posts/notes/ 下的第一篇。它存在的意义有两个:一是把三种端口转发的区别写清楚,二是验证子目录里的 .md 也能当正常文章看。
三个方向
| 类型 | 参数 | 谁连谁 | 典型用途 |
|---|---|---|---|
| 本地转发 | -L |
本地端口 → 经 SSH → 远端能访问的地址 | 连远端内网里的数据库 |
| 远程转发 | -R |
远端端口 → 经 SSH → 本地能访问的地址 | 把家里机器临时暴露到服务器 |
| 动态转发 | -D |
本地端口当 SOCKS5 代理 | 借远端出口上网 |
本地转发
把远端的 3306 拉到本地 13306:
ssh -N -L 13306:127.0.0.1:3306 user@example.com
-N 表示只开隧道、不执行命令。连上之后,本地程序连 127.0.0.1:13306 就等于连远端的 MySQL。
注意第一个地址是从远端视角看的。写成 127.0.0.1 是远端自己的环回;想连远端内网另一台机器,就写它的内网地址。
远程转发
反过来,把本地的 8080 推给远端:
ssh -N -R 18080:127.0.0.1:8080 user@example.com
之后访问 example.com:18080 就会落到你本地的 8080。默认情况下,远端的 sshd 只把这个端口绑在环回上,要让外部访问,还得在服务器的 sshd_config 里打开 GatewayPorts。
动态转发
ssh -N -D 1080 user@example.com
本地 1080 就成了一个 SOCKS5 代理。浏览器指过去,出口 IP 就变成远端那台机器。
几个常踩的坑
-N忘了加,于是顺便开了个登录 shell,关窗口隧道就断。-f和-N一起用才能后台常驻,但失败时不容易看到报错,调试期先别加。ExitOnForwardFailure:本地端口已被占用时,默认情况下 SSH 会继续登录、只把转发悄悄放弃。加上-o ExitOnForwardFailure=yes才会直接失败。ServerAliveInterval:NAT 空闲超时会把隧道掐掉,设个心跳能少很多"昨天还好用"的困惑。
ssh -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 \
-L 13306:127.0.0.1:3306 user@example.com
和这篇博客的关系
这个站点自己的 SSH 前端也是同一个端口上的一条长连接,只不过它不给你 shell,而是给你一棵只读(对你的视图可写)的目录树。想确认它真的不支持转发以外的花样,可以试试:
visitor@localhost:~$ which ssh
visitor@localhost:~$ ls
没有 ssh 这条命令,也没有 bash、sh、python——它不 spawn 任何子进程,这也是部署时敢开 NoNewPrivileges 和 MemoryDenyWriteExecute 的原因。