termal.in

← 博客

无需端口转发,SSH 连上 NAT 或 CGNAT 之后的服务器

· Termalin Team sshtunnelingnetworkinghomelab

你想 SSH 连上一台无法接受入站连接的机器:路由器后面的家用服务器、办公室里的一台树莓派、挂在移动网络或 5G 上的一台机器。老办法——在路由器上转发 22 端口——越来越用不上了,而就算能用,也不是个好主意。本文梳理四种真正可行的方案、各自的代价,以及每种方案的实操示例。它们都不会在你要连的那台机器上打开入站端口。

为什么如今不能再直接转发端口了

有两件事挡在路上。第一,运营商级 NAT(CGNAT):如今大多数家用光纤、有线、移动和 Starlink 连接,都把一个公网 IP 分给许多用户共用,所以“你的”地址上根本没有端口可转发——你能控制的那台路由器,并不是持有公网 IP 的那一台。第二,就算你有一个真正的公网 IP,一个转发出去的 SSH 端口也会在几分钟内被扫描器发现;从它上线那一刻起,日志里就会塞满暴力破解的尝试。下面每种方案的解法形状都一样:那台私有机器主动向某个可达的目标发起一条出站连接,你再顺着这条连接反向进来。出站连接即便穿过 CGNAT 和严密封锁的防火墙也能工作,因为它不过是又一条离开网络的连接而已。

四种方案一览

方案你要运行什么额外基础设施机器上是否留有长期密钥?最适合
反向 SSH 隧道机器上跑 ssh -R + autossh一台有公网 IP 的 VPS是(连 VPS 用)你已经租了 VPS
网状 VPN(Tailscale / WireGuard)两端各装一个 VPN 客户端一个协调服务你平常的 SSH 密钥要连好几台机器
Cloudflare Tunnel机器上跑 cloudflared一个 Cloudflare 账户 + 域名你平常的 SSH 密钥你已经在用 Cloudflare
出站 Connector机器上跑一个小代理程序一个 Termalin 账户否——用短期证书浏览器访问,不想要 VPS 或 VPN

前三种方案都让你能从笔记本上照常执行 ssh you@…。最后一种则改为从浏览器或 AI 代理去访问那台机器。接着往下看哪种适合你。

方案一——借道 VPS 的反向 SSH 隧道

如果你已经租了一台便宜的、带公网 IP 的 VPS,那台私有机器就能拨出到它,并把自己的 SSH 端口转发回来。在 NAT 之后的机器上:

ssh -N -R 2222:localhost:22 tunnel@vps.example.com

这会在 VPS 上打开 2222 端口,并把对它的每个连接都引回家用机器的 22 端口。从任何地方,借道 VPS 落到那台机器上:

ssh -J tunnel@vps.example.com -p 2222 you@localhost

一条裸 ssh -R 在网络第一次打嗝时就会断掉,所以用 autossh 把它包起来跑在 systemd 单元里,让它扛过重启和掉线,并加上 -o ServerAliveInterval=30 -o ExitOnForwardFailure=yes。完整原理——包括 GatewayPorts 的坑,以及隧道为何默认绑定到 VPS 的回环地址——都在 SSH 反向隧道详解里。取舍:你得维护一台 VPS,还要在机器上放一把能连到它的长期密钥,而这台 VPS 现在也成了你攻击面的一部分。

方案二——网状 VPN(Tailscale 或 WireGuard)

与其暴露某一个端口,不如把两台机器都放进一个只有它们能看见的私有网络。Tailscale 是最省事的那种做法。在 NAT 之后的机器上:

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

在你的笔记本上也装好 Tailscale,两边都会拿到一个稳定的 100.x.y.z 地址(以及一个 MagicDNS 名称)。然后就只需要:

ssh you@home-box

就像你们在同一个局域网里一样——那台机器根本不会暴露到公网。sudo tailscale up --ssh 甚至能替你搞定 SSH 认证,这样你连密钥都不用管。WireGuard 是同一个思路的手工版:协调工作由你自己运行,对端也要手动配置——工作量更大,但没有第三方协调方。对于一个有 NAS 和几台树莓派的家庭实验室,网状 VPN 通常就是全部答案,也是我在家庭 NAS/服务器指南里默认会用的方案。取舍:每台需要访问的设备都得加入这个网络,也就是要装一个客户端、要有一个账户来运行它。

方案三——Cloudflare Tunnel

如果你的域名已经托管在 Cloudflare 上,cloudflared 能给你一条不需要开放端口的出站隧道。在机器上:

cloudflared tunnel login
cloudflared tunnel create home

在隧道配置里把一个主机名路由到这条隧道,并让它指向本地的 sshd(ssh://localhost:22),然后把 cloudflared 作为服务运行。在客户端一侧,SSH 通过你 ~/.ssh/config(英文)里的 ProxyCommand 连到它:

Host ssh.example.com
    ProxyCommand cloudflared access ssh --hostname %h

现在 ssh you@ssh.example.com 会经由 Cloudflare 的边缘节点流向那台机器。免费套餐就够用。取舍:你把自己的 SSH 路由经过了一个第三方,并且依赖上了一个 Cloudflare 账户和一个托管在那里的域名——如果你本来就这么用,很棒;如果不是,就有点杀鸡用牛刀了。

方案四——一个出站 Connector(不要 VPS,不要 VPN)

上面三种方案各自都要求一套常驻的基础设施——一台 VPS、一个 VPN,或一个 Cloudflare 域名。Termalin 的 Connector 把这一切收拢成一条命令,并改用你的浏览器、Termalin 应用或 AI 代理来访问那台机器,而不是本地的 ssh。在那台私有服务器上,一行命令就能装好一个小型静态代理程序(Linux x86_64 和 arm64):

curl -fsSL https://termal.in/tunnel-install.sh | sudo TERMALIN_TOKEN=<token> sh

这个代理通过一条 WebSocket 向外拨到 Termalin 并保持连接;它从不监听任何端口。当你在网页客户端里打开一个终端时,请求会顺着这条链路下来,代理再在 localhost 上连到机器自己的 sshd——它自始至终只搬运不透明的 SSH 字节,所以永远看不到你的凭据或会话明文。接入过程会让机器的 sshd 信任 Termalin 的 SSH 证书颁发机构,于是登录用的是一张短期证书,而不是一把长期待在服务器上的私钥。这就是表格里「机器上是否留有长期密钥」一栏写着“否”的那一行。

坦白说清楚它的代价:你是通过 Termalin 的托管侧去访问那台机器——网页终端、Termalin 桌面与 iOS 应用(它们走的是同一个网关),或者通过 MCP 服务器接入的 AI 代理——而不是从你自己机器上敲一条裸 ssh 命令,而且 Connector 属于付费套餐(或试用)。如果你要的是从笔记本上开一个普通终端,方案一到三更合适。如果你要的是从任意设备上进行浏览器访问——或者让一个代理去操作一台没有公网地址、也没有密钥可偷的机器——那这就是为此打造的方案。同一条仅出站的 Connector 还能为没有开放端口的机器承载轻量级监控与告警。

你该选哪一种?

  • **你已经租了一台 VPS:**反向隧道正好把它用起来——一条跑在 autossh 下的 ssh -R 就搞定了。
  • **你要连的机器不止一台,或者希望它们用起来像一个局域网:**像 Tailscale 这样的网状 VPN 扩展性最好,而且什么都不暴露。
  • **你的域名托管在 Cloudflare 上:**它家的隧道是最自然的选择,不用再引入新的服务商。
  • **你想要零常驻基础设施、浏览器访问,或受监督的代理访问:**选一个出站 Connector,服务器上不留任何长期密钥。

这四种方案都遵循同一个值得记住的原则:绝不要在一台你承受不起被扫描的机器上打开入站端口。让它主动向外连接——正是这一次方向上的反转,让 NAT 之后的 SSH 变得安全。


Termalin 是一款免费、跨平台的 SSH 客户端,支持保存隧道、提供网页终端,以及面向私有服务器的无密钥 Connector——立即下载,或了解它如何安全地处理你的密钥。

先在一台主机上试试。

Termalin 是为你和你的智能体打造的高速 SSH 客户端。

免费版 · Pro 14 天试用 · 价格