你在家里运行着一台 Linux 服务器,它放在一个 NAT 路由器或者限制性防火墙后面。现在你想在外出时用 SSH 登录到这台服务器。你如何才能做到呢?SSH 端口转发当然是一种选择。但是,如果你需要处理多级嵌套的 NAT 环境,端口转发可能会变得非常棘手。另外,在多种 ISP 特定条件下可能会受到干扰,例如阻塞转发端口的限制性 ISP 防火墙、或者在用户间共享 IPv4 地址的运营商级 NAT。
什么是反向 SSH 隧道?SSH 端口转发的一种替代方案是 反向 SSH 隧道。反向 SSH 隧道的概念非常简单。使用这种方案,在你的受限的家庭网络之外你需要另一台主机(所谓的“中继主机”),你能从当前所在地通过 SSH 登录到它。你可以用有公网 IP 地址的 VPS 实例 配置一个中继主机。然后要做的就是从你的家庭网络服务器中建立一个到公网中继主机的永久 SSH 隧道。有了这个隧道,你就可以从中继主机中连接“回”家庭服务器(这就是为什么称之为 “反向” 隧道)。不管你在哪里、你的家庭网络中的 NAT 或 防火墙限制多么严格,只要你可以访问中继主机,你就可以连接到家庭服务器。
在 Linux 上设置反向 SSH 隧道让我们来看看怎样创建和使用反向 SSH 隧道。我们做如下假设:我们会设置一个从家庭服务器(homeserver)到中继服务器(relayserver)的反向 SSH 隧道,然后我们可以通过中继服务器从客户端计算机(clientcomputer) SSH 登录到家庭服务器。本例中的中继服务器 的公网 IP 地址是 1.1.1.1。
在家庭服务器上,按照以下方式打开一个到中继服务器的 SSH 连接。
homeserver~$ ssh -fN -R 10022:localhost:22 relayserver_user@1.1.1.1
这里端口 10022 是任何你可以使用的端口数字。只需要确保中继服务器上不会有其它程序使用这个端口。
“-R 10022:localhost:22” 选项定义了一个反向隧道。它转发中继服务器 10022 端口的流量到家庭服务器的 22 号端口。
用 “-fN” 选项,当你成功通过 SSH 服务器验证时 SSH 会进入后台运行。当你不想在远程 SSH 服务器执行任何命令,就像我们的例子中只想转发端口的时候非常有用。
运行上面的命令之后,你就会回到家庭主机的命令行提示框中。
登录到中继服务器,确认其 127.0.0.1:10022 绑定到了 sshd。如果是的话就表示已经正确设置了反向隧道。
relayserver~$ sudo netstat -nap | grep 10022
tcp 00127.0.0.1:100220.0.0.0:* LISTEN 8493/sshd
现在就可以从任何其它计算机(客户端计算机)登录到中继服务器,然后按照下面的方法访问家庭服务器。
relayserver~$ ssh -p 10022 homeserver_user@localhost
需要注意的一点是你在上面为localhost输入的 SSH 登录/密码应该是家庭服务器的,而不是中继服务器的,因为你是通过隧道的本地端点登录到家庭服务器,因此不要错误输入中继服务器的登录/密码。成功登录后,你就在家庭服务器上了。
通过反向 SSH 隧道直接连接到网络地址变换后的服务器上面的方法允许你访问 NAT 后面的 家庭服务器,但你需要登录两次:首先登录到 中继服务器,然后再登录到家庭服务器。这是因为中继服务器上 SSH 隧道的端点绑定到了回环地址(127.0.0.1)。
事实上,有一种方法可以只需要登录到中继服务器就能直接访问NAT之后的家庭服务器。要做到这点,你需要让中继服务器上的 sshd 不仅转发回环地址上的端口,还要转发外部主机的端口。这通过指定中继服务器上运行的 sshd 的 GatewayPorts 实现。
打开中继服务器的 /etc/ssh/sshd_conf 并添加下面的行。
relayserver~$ vi /etc/ssh/sshd_conf
GatewayPorts clientspecified
重启 sshd。
基于 Debian 的系统:
relayserver~$ sudo /etc/init.d/ssh restart
基于红帽的系统:
relayserver~$ sudo systemctl restart sshd
现在在家庭服务器中按照下面方式初始化一个反向 SSH 隧道。