0x01 前言

因为我博客的后端服务器有一台在我家中,为了提升服务的可靠性,经过权衡后我最终选用SSH隧道承载nginx反向代理的流量。

前些天我在知乎发布了一篇专栏文章:

其中详细描述了我博客的服务架构,目前的版本为3.0,简图如下:

从上图可以看到,在我家中有一台后端服务器,这样的架构可以大大地节省云服务器的费用支出。但受限于家庭宽带,绝大部分端口屏蔽了主动传入的流量或者没有公网IP,这时候我有2种解决方案,一种是采用VPN,另一种就是本文要说的SSH端口转发。

因为我的服务器都是centos,为减少工作量与维护难度,我选择了SSH端口转发。

0x02 分析

SSH端口转发分两种,一种是在本地监听端口,将数据转发到远端;另一种是在远端监听端口,将数据转发到本地。

例子1:我在腾讯云 CN 2服务器上部署了mysql服务,但希望在本地的home server建立一个网关,以便让本地的服务都可以通过这个网关连接到腾讯云 CN 2的mysql服务。这就需要将远端的3306端口映射到本地,这时候可以通过SSH在本地监听一个端口,所有通过该端口的请求都会被转发到腾讯云CN 2。

例子2:反过来,我在本地的home server部署了mysql服务,但希望腾讯云 CN 2服务器上的服务也可以连接该服务,这就需要将本地的3306端口映射到腾讯云 CN 2上,因此需要在腾讯云 CN 2上监听一个端口,以便让该服务器上的服务访问home server的mysql服务。

注意!以上两个例子都是以home server为SSH client,腾讯云 CN 2为SSH server。

图片来源:https://unix.stackexchange.com/questions/46235/how-does-reverse-ssh-tunneling-work

以上图为例,左侧的图形适用于例子2,右侧的图形适用于例子1。

其实SSH隧道只有本地和远端的概念,如果是将远端的端口映射到本地,在本地监听并转发到远端,则需要使用“-L”参数,类似正向代理;如果将本地端口映射到远端,在远端监听并转发到本地,则需要使用“-R”参数,类似反向代理。

0x03 准备

因为SSH代理需要监听端口,因此会用到root用户;另外家庭宽带每48小时自动断开,为提供可靠性,需要实现自动连接SSH,这就需要配置SSH免密登录。

注意!因为需要实现SSH免密登入的功能,为了确保数据与系统的独立性,请选择安全性较好且可靠地服务器作为client。

例如我需要确保home server的数据安全,且确认home server比腾讯云 CN 2服务器更可靠,这时候可以在home server上执行SSH命令。

另外还有一个因素,因为家庭宽带一般不允许从外部主动连入,因此建议通过家庭宽带内部的服务器执行SSH命令。

确定好client与server端后,需要分别为两者建立SSH私钥与公钥。先通过root用户登入系统,然后执行以下命令:

在交互中直接回车即可,请勿为私钥设置密码,否则在后续的操作中将要求输入密码:

而后重命名公钥:

为了能使home server通过免密的方式登入tc-cloud,需要将home server的公钥添加至tc-cloud的authorized_keys中:

为了安全起见,请在tc-cloud(远端服务器)禁止通过密码登入SSH,然后允许root登入:

而后分别在两台服务器上重新启动SSH服务:

最后在home-server上测试SSH免密登入是否成功:

确认功能正常后即可开始配置端口转发功能。

0x04 使用

再继续之前,请先安装autossh,它可以实现SSH自动重连的功能:

0x04.1 本地监听/正向代理

基本的命令如下:

而后即可撰写SSH端口转发的命令:

  • -M:autossh的参数,用于监控SSH连接状态,autossh会向该端口发送测试数据,若无返回则认为SSH连接中断,此时会自动重连直至成功,类似心跳包;
  • -f:SSH的参数,将SSH放置在后台运行;
  • -C:SSH的参数,用于数据压缩;
  • -N:SSH的参数,不执行远程指令,请务必配置该参数;
  • -L:SSH的参数,将本地的数据转发到远端。

以上命令的意义为:在本地监听TCP 10001端口,用于心跳包的发送与接收;在后台运行SSH端口转发服务,在本地IP 10.1.1.115上监听10002这个端口,并将该端口的数据转发到tc-cloud.t.com的3306端口。

如果使用本地监听,建议把本地IP添加在命令中,以提高安全性。

0x04.2 远端监听/反向代理

基本的命令如下:

在我服务架构中用得比较多的是远端监听端口,命令如下:

  • -R:SSH的参数,将远端的数据转发到本地。

以上命令的意义为:在本地监听TCP 10003端口,用于心跳包的发送与接收;在后台运行SSH端口转发服务,在tc-cloud.t.com的IP 127.0.0.1上监听10004这个端口,并将该端口的数据转发到本地127.0.0.1的80端口。

0x04.3 检查

在home-server中执行以上命令后,通过以下命令即可查看相关进程:

当SSH成功连接后,可以看到有“/usr/bin/ssh”相关的进程;若无,则表示SSH尚未连接,此时需要检查message日志。

通过以下命令查看监听的端口:

在tc-cloud中执行相关命令,也可以看到监听的端口。

再测试业务,若可以接受与发送数据,则说明端口转发正常。

0x05 结语

在我的业务场景需要该服务在服务器启动时启动,此时可以将其加入rc.local文件中。

在实际应用中,端口数量较少的情况,用SSH端口转发会较为方便。在端口较多且相互依存的情况下,SSH端口转发的配置会非常繁琐,此时建议使用VPN承载数据。

另外,在同一台服务器中,autossh命令的心跳包端口不可复用,各个监听的端口也不可复用。