您好!利用SSH进行远程接入的世界,您是否觉得有趣?在之前的文章中,我们讲解了SSH密钥生成、基本接入命令以及本地端口转发(-L选项)。这次我们将重点介绍SSH的另一个强大功能——反向端口转发(Reverse Port Forwarding),即-R选项。

如果说-L选项是“从我的计算机通过隧道访问外部资源”,那么-R选项则正好相反。“从外部计算机通过隧道接入我的计算机的内部资源”,就像在墙上打一个门一样的功能。


什么是反向端口转发?(-R选项概述)

通常情况下,从远程服务器(Server A)直接接入本地计算机(Client B)是比较困难的。这是因为Client B大多使用私有IP地址,处于防火墙后面,或者没有固定IP。

这时,如果使用反向端口转发(-R选项),Client B可以在尝试SSH接入Server A的同时,向Server A请求建立隧道,将来自Server A特定端口的请求转发到Client B的特定端口

简单来说:

  1. Client B(我的计算机)尝试接入Server A(外部服务器)
  2. 此时使用-R选项,命令“将进入Server A的X端口的请求发送到我的计算机(Client B)的Y端口!”
  3. 现在,接入Server A的其他外部用户如果通过Server A的X端口接入,该请求将通过SSH隧道转发到Client B的Y端口

就像Client B正在请求Server A“为我开一个可以连接我的门”

SSH反向端口转发流程图:外部请求经过服务器传递到本地的结构


-R命令的组成

反向端口转发的基本命令格式如下:

ssh -R [远程_端口]:[目标_主机]:[目标_端口] [远程_服务器_用户]@[远程_服务器_地址]

我们仔细看看每个元素:

  • ssh:执行SSH客户端的命令。
  • -R:反向端口转发选项。
  • [远程_端口]:要穿透的远程服务器(Server A)的端口号。外部用户通过这个端口接入后,将连接到Client B的资源。
  • [目标_主机][远程_服务器_用户]@[远程_服务器_地址接入时,Client B(我的计算机)内要访问的资源的主机名或IP地址。通常是localhost(即Client B自己)。
  • [目标_端口]Client B(我的计算机)内打开的服务的端口号。外部进入的请求最终到达的地方。
  • [远程_服务器_用户]@[远程_服务器_地址]:要连接的外部服务器(Server A)的用户账户和地址。Client B连接Server A的路径。

示例:

当我希望通过外部服务器(Server A)的8888端口接入我本地计算机(Client B)的8080端口时:

# 在Client B(我的计算机)上执行
ssh -R 8888:localhost:8080 user@server_a_public_ip

如果这个命令成功执行,就表示已接入server_a_public_ip,此时,其他计算机访问http://server_a_public_ip:8888实际上是访问Client B(我的计算机)的8080端口。


反向端口转发适用于何时?(开发中的应用)

反向端口转发在普通SSH接入无法解决的特定情况下展现出极强的功能。尤其是在开发过程中非常有用。

1. 暴露位于NAT/防火墙后的本地开发服务器

  • 问题情况:您正在家中或公司内部网络中开发的网页应用程序(例如在localhost:3000上运行)。您想将这个应用程序展示给外部的团队成员或客户,但本地计算机使用私有IP,外部无法直接接入。共享路由器或公司防火墙配置复杂,需要管理员批准。
  • 解决方案:通过具有公共IP的外部服务器(例如AWS EC2实例,VPS)暴露本地开发服务器。
# 在我的本地开发机器(Client B)上执行
ssh -R 80:localhost:3000 your_user@your_public_server.com
# 或者因为80端口需要root权限,可使用其他端口(例如8080)
ssh -R 8080:localhost:3000 your_user@your_public_server.com
此后,访问`your_public_server.com:8080`,实际上将接入您本地机器上运行的网页应用程序(`localhost:3000`)。现在,外部可以实时查看您的开发进度。

2. 测试Webhook

  • 问题情况:您希望在本地开发服务器上测试由支付系统、Git存储库(GitHub/GitLab)、消息平台等触发的Webhook事件。但Webhook只能发送到公共URL。
  • 解决方案:通过反向端口转发,可以将本地Webhook端点(例如localhost:5000/webhook)映射到公共服务器的特定URL。
# 在我的本地开发机器(Client B)上执行
ssh -R 5000:localhost:5000 your_user@your_public_server.com
现在在Webhook设置中输入`http://your_public_server.com:5000/webhook`,Webhook事件将传送到您的本地服务器进行测试。

3. 直接接入远程服务器的特定端口(绕过安全网络)

  • 问题情况:您希望访问远程特定服务器(Client B)上安装的数据库或内部管理工具(例如在localhost:9000上运行),但该服务器由于防火墙原因,其特定端口被阻塞或位于私有网络中。但是Client B可以接入外部公共服务器(Server A)。
  • 解决方案:Client B通过SSH接入Server A,并请求通过反向端口转发为Server A开放“连接到我的9000端口的通道”。
# 在Client B(防火墙后的服务器)上执行
ssh -R 9000:localhost:9000 your_user@server_a_public_ip
现在,如果您的计算机(或其他外部计算机)访问`server_a_public_ip:9000`,则可以接入Client B的9000端口服务。

4. 临时演示或分享

  • 问题情况:您希望向同事展示您本地运行的特定应用程序的操作方式,或者希望短暂地公开以获得反馈。
  • 解决方案:简单的反向端口转发可以在特定时间段内将本地服务公开。演示结束后,您可以结束SSH会话以阻止访问,非常方便。

使用反向端口转发时的注意事项

  • GatewayPorts yes:通过反向端口转发打开的远程端口默认只能由SSH服务器(server_a_public_ip)所在的机器访问。如果希望SSH服务器外的其他计算机也能接入此端口,需要在SSH服务器的sshd_config文件中添加GatewayPorts yes设置并重启SSH服务。(此设置可能会影响安全性,请小心使用。)

  • 安全:反向端口转发将本地网络的特定端口暴露给外部,因此只能在受信任的服务器上使用。您应提前检查暴露服务的安全漏洞。

  • 保持SSH会话: 反向端口转发隧道仅在SSH会话保持时有效。若想在后台持续运行,通常需要像ssh -fN -R ...那样,结合使用f(后台执行)和N(不执行远程命令)选项。


总结

SSH反向端口转发(-R选项)在复杂的网络环境或需要在防火墙后暴露特定服务时是非常有用的功能。特别是在开发过程中,将本地环境与外部共享或进行Webhook测试时可以成为强大的生产力工具。

如果您觉得这个概念很难理解,不妨亲自尝试一下,通过实践进行掌握。积极利用SSH反向端口转发于您的开发流程吧!

如果有任何问题,欢迎随时在评论中提问!