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。
以上图为例,左侧的图形适用于例子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用户登入系统,然后执行以下命令:
[root@home-server ~]# ssh-keygen -t rsa -b 4096
在交互中直接回车即可,请勿为私钥设置密码,否则在后续的操作中将要求输入密码:
而后重命名公钥:
[root@home-server ~]# mv .ssh/id_rsa.pub .ssh/authorized_keys
为了能使home server通过免密的方式登入tc-cloud,需要将home server的公钥添加至tc-cloud的authorized_keys中:
# 打印出home-server的公钥 [root@home-server ~]# cat .ssh/authorized_keys | grep home-server ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCjLf83WX/kqrv6bUORMDtFK5RP/pP5Tr8Iep2HIA5l+rI6mqDQ8VvaZyogDBw9pasdWWIRjj9TxaT1ktMff5rrubDHg1ZC8MGMl3K1/ycDJtugopztAz+1YqecMj3buCd59WoVk6V0jVODXRBTnSwGaUXR+9gtMxn/Xcgpvimuh4ivR0ZJe5cPoiQQQq1sOooZ0Dg/T8hPvRwUtmWCIg2eukwEjGsHbO19Zy4mAyam4D4IqqEGVna6MGQyhTdoxi8JQRGpre/QBD5tkBxoK9qNZ/2wpXbO8IOY6oPdKN0ID0QEf5YvMWcUNF0fJ48jQobCGpVHXDhMSojEuPs4SaELqZSGbfIEDW2c7+oVZ9n+F1O7VQkSMpkkjix3ya9qy7W2Muwcj7a0boqESOEfeT+KhoK25jVUHMPsZpfVVUDlkBzRu1b1xOzPGgFffQyORwJ83SyQyE8DOv0S9iXwuGfoOebou3S/WPoWJ2oyL8gJo6zcjBIYEb1HCtOQ7YZvafGoQE3G8kGbcbEvv2OFSuY4vz/GCuV32+YnOYx+znODR5WBo5KEkH+jr0hDRTBpSNrmi6DUrbUK07tRuMnv5O397Q4B8xrayhZUS0lJ1ibunbZM9oGWIhH1AyD/wa+iDYyxJ+dlWvVtZrjMoip80PwAvR29TayC/eiW6qH9SLE+MQ== root@home-server # 将home-server公钥添加至tc-cloud的authorized_keys文件最后一行 [root@tc-cloud ~]# vim .ssh/authorized_keys
为了安全起见,请在tc-cloud(远端服务器)禁止通过密码登入SSH,然后允许root登入:
# 打开SSH配置文件 [root@tc-cloud ~]# vim /etc/ssh/sshd_config # 删除PermitRootLogin配置的注释符号并设为yes PermitRootLogin yes # 删除PasswordAuthentication配置的注释符号并设为no PasswordAuthentication no
而后分别在两台服务器上重新启动SSH服务:
[root@home-server ~]# systemctl restart sshd
最后在home-server上测试SSH免密登入是否成功:
[root@home-server ~]# ssh [email protected] The authenticity of host 'tc-cloud.t.com (10.1.1.115)' can't be established. ECDSA key fingerprint is SHA256:FQi7NN+ckssUdFR8/BZKoL7yYzvIrEGUFZPGpPrfBOU. ECDSA key fingerprint is MD5:bc:e1:a2:83:d4:81:db:d1:73:41:80:1d:ee:b4:54:f6. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'tc-cloud.t.com,10.1.1.115' (ECDSA) to the list of known hosts. Last login: Sun Aug 26 15:43:45 2018 from terence-pc.t.com [root@tc-cloud ~]#
确认功能正常后即可开始配置端口转发功能。
0x04 使用
再继续之前,请先安装autossh,它可以实现SSH自动重连的功能:
[root@tc-cloud ~]# yum install autossh -y
0x04.1 本地监听/正向代理
基本的命令如下:
autossh -M [心跳包端口] -fCNL [本地IP,可省略]:[本地端口]:[远端IP]:[远端端口] [ssh用户名@远端域名或IP]
而后即可撰写SSH端口转发的命令:
autossh -M 10001 -fCNL 10.1.1.115:10002:127.0.0.1:3306 [email protected]
- -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 远端监听/反向代理
基本的命令如下:
autossh -M [心跳包端口] -fCNR [远端IP,可省略]:[远端端口]:[本地IP]:[本地端口] [ssh用户名@远端域名或IP]
在我服务架构中用得比较多的是远端监听端口,命令如下:
autossh -M 10003 -fCNR 127.0.0.1:10004:127.0.0.1:8081 [email protected]
- -R:SSH的参数,将远端的数据转发到本地。
以上命令的意义为:在本地监听TCP 10003端口,用于心跳包的发送与接收;在后台运行SSH端口转发服务,在tc-cloud.t.com的IP 127.0.0.1上监听10004这个端口,并将该端口的数据转发到本地127.0.0.1的80端口。
0x04.3 检查
在home-server中执行以上命令后,通过以下命令即可查看相关进程:
[root@home-server ~]# ps -aux | grep ssh | grep 100 root 1616 0.0 0.0 6512 472 ? Ss 17:02 0:00 autossh -M 10001 -CNL 10.1.1.115:10002:127.0.0.1:3306 [email protected] root 1617 0.2 0.2 181068 4976 ? S 17:02 0:00 /usr/bin/ssh -L 10001:127.0.0.1:10001 -R 10001:127.0.0.1:10002 -CNL 10.1.1.115:10002:127.0.0.1:3306 [email protected] root 1623 0.0 0.0 6512 472 ? Ss 17:02 0:00 autossh -M 10003 -CNR 127.0.0.1:10004:127.0.0.1:8081 [email protected] root 1624 0.1 0.2 181064 4976 ? S 17:02 0:00 /usr/bin/ssh -L 10003:127.0.0.1:10003 -R 10003:127.0.0.1:10004 -CNR 127.0.0.1:10004:127.0.0.1:8081 [email protected]
当SSH成功连接后,可以看到有“/usr/bin/ssh”相关的进程;若无,则表示SSH尚未连接,此时需要检查message日志。
通过以下命令查看监听的端口:
[root@home-server ~]# netstat -anp | grep ssh | grep LIST tcp 0 0 127.0.0.1:10001 0.0.0.0:* LISTEN 1617/ssh tcp 0 0 127.0.0.1:10002 0.0.0.0:* LISTEN 1616/autossh tcp 0 0 127.0.0.1:10003 0.0.0.0:* LISTEN 1624/ssh tcp 0 0 127.0.0.1:10004 0.0.0.0:* LISTEN 1623/autossh tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1257/sshd
在tc-cloud中执行相关命令,也可以看到监听的端口。
再测试业务,若可以接受与发送数据,则说明端口转发正常。
0x05 结语
在我的业务场景需要该服务在服务器启动时启动,此时可以将其加入rc.local文件中。
在实际应用中,端口数量较少的情况,用SSH端口转发会较为方便。在端口较多且相互依存的情况下,SSH端口转发的配置会非常繁琐,此时建议使用VPN承载数据。
另外,在同一台服务器中,autossh命令的心跳包端口不可复用,各个监听的端口也不可复用。