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