0%

ssh端口转发配置

使用autossh进行端口转发设置

1.1 端口转发

ssh端口转发也称作ssh隧道,通过SSH登陆之后,在SSH客户端与SSH服务端之间建立了一个隧道,从而进行通信。SSH隧道是非常安全的,因为SSH是通过加密传输数据的(SSH全称为Secure Shell)

1.1.1 端口转发分类

端口转发分为以下3种:

  1. 本地端口转发
    1. 所谓本地端口转发,就是将发送到本地端口的请求,转发到目标端口。这样,就可以通过访问本地端口,来访问目标端口的服务
  2. 远程端口转发
    1. 所谓远程端口转发,就是将发送到远程端口的请求,转发到目标端口
  3. 动态端口转发
    1. 可用于科学上网,使用远程主机作为proxy,进行请求转发

1.2 示例

1.2.0 跳板机配置

跳板机是可以被远程连接并用来访问内网主机的代理主机,一般是拥有公网IP的服务器,需要对其ssh服务做一下配置:

  1. 在跳板机执行:

vi /etc/ssh/sshd_config # 添加以下代码,或者解开其注释,否则无法正常实施端口映射功能GatewayPorts clientspecified # 重启ssh服务 sudo service ssh restart

  1. 将内网主机的公钥放到跳板机服务器的***/root/.ssh/authorized_keys***中,直接换行加入即可,不要删除文件中的原有的其他公钥
  2. 在内网主机使用ssh连接到跳板机,*ssh root@${跳板机IP} -p ${跳板机ssh端口}* 直到不用输入yes交互为止
  3. 开启跳板机端口(阿里云或者腾讯云控制台更改或者进行防火墙更改)

1.2.1 本地端口转发

公网主机A部署了监听在3000端口的web服务,但是使用防火墙只开放了22(ssh)端口,其他网域的主机B想要访问web服务,有两种方法:

  1. 更改公网主机的防火墙设置,添加允许主机B的IP,但是如果主机B是内网IP的话,真实访问的IP是动态的,无法有效配置防火墙
  2. 使用本地端口转发,通过建立A与B的ssh隧道,完成B对A的3000端口的访问

本地端口转发的配置方法:

在主机B执行:

ssh -L ${主机B的IP,即主机B的网卡IP可以省略(冒号也一同省略)}:2000:${主机A的网卡IP,一般是localhost,同样可省略}:3000 root@${主机A公网IP}

将对于主机B的2000端口的访问代理到主机A的3000端口

注意事项:

  • 主机B的网卡地址localhost可以省略,即可以将对B主机上的任意网卡的2000端口进行代理
  • 其他场景:
    • 主机B可以通过同一内网的主机C去访问主机A:

在主机B执行:

ssh -L ${主机C内网IP}:2000:localhost:3000 root@${主机A IP}

此时直接访问主机C的内网IP:2000就可以访问到主机A的3000端口

  • 同理的,主机B也可以通过访问和主机A同一子网的主机D去间接访问主机A:在主机B执行:

ssh -L 2000:${主机A内网IP}:3000 root@${主机D的公网IP}

  • 当使用本地端口映射的时候不能同时使用-N -f参数(autossh),这两个参数只能作用于远程端口转发,所以只要关闭端口转发的终端,整个复杂端口转发就会立即失效

1.2 远程端口转发

没有公网IP的内网主机B部署了监听在3000端口的web服务,需要通过公网主机A去代理此服务,以将服务暴露到公网,供任意其他主机访问

远程端口转发的配置方法:

在主机B执行:

ssh -R ${公网主机A 网卡IP一般设置为0.0.0.0 可省略}:2000:${内网主机B的网卡 IP一般为 localhost}:3000 root@${主机A 公网IP}

将对于主机A的2000端口的访问代理到主机B的3000端口

注意事项:

  • 类似的,冒号前后的两个主机也可以进行更改,比如内网主机IP换成是与主机B同一内网的主机C,那么可以通过访问主机A访问到主机C的服务
  • 直接使用ssh会有超时断连的可能,因此常使用autossh工具,此工具会使用一个本地主机的端口去监控是否断连,并尝试进行重连,使用步骤如下:
    1. 在内网主机执行

autossh -N -f -M ${监听端口} -i /root/.ssh/id_rsa -R 0.0.0.0:${跳板机端口}:localhost:${内网机端口,比如 22} root@${跳板机公网IP} -p ${跳板机的ssh 端口,一般为了安全,不会使用默认的22端口}

​ 参数解释:

  • -f表示后台运行
  • -N不执行远程命令,只进行端口转发,意思就是指进行端口转发而不接入远程shell
  • -R表示是远程端 口映射(反向代理)区别于-L 本地端口映射(正向代理),根本区别在于映射的方向

注意事项:

  • 注意各个参数的顺序,不要随意更改
  • -M 后的端口尽量随机,保证这个端口以及其附近端口没有被占用(因为autossh会默认使用此端口以及此端口+1的端口)
  • autossh有-o参数,可以指定一些属性,但是经过测试,在centos上这些-o属性失效,有待验证。如果要使用-o参数的话,可参考wiki
  • 一般来说验证autossh有没有生效的方法就是查看进程中有没有对应的ssh命令,***ps -aux | grep ssh***看看除了autossh之外,有没有自动执行其他的ssh命令,如果有的话,就是执行成功了,如果失败可以尝试更换 -M 后的端口
  • 务必带上 -f -N参数,只有这样端口转发才可以作为一个后台的服务运行,这样只要设置自启动就可以无阻碍使用了,而不用担心关闭终端之后导致的端口转发失效
  • 如果在内网机器上执行SSH连接公网主机失败,提示:Warning: remote port forwarding failed for listen port,可以在跳板机上把这端口对应的进程 kill 掉,然后重新尝试连接
  1. 设置自启动

1.3 动态端口转发

  • 对于本地端口转发和远程端口转发,都存在两个一一对应的端口,分别位于SSH的客户端和服务端,而动态端口转发则只是绑定了一个本地端口,而目标地址:目标端口则是不固定的,由发起的请求决定
  • 可以将在本地主机A发起的请求,转发到远程主机B,而由B去真正地发起请求(对主机B的本机服务,或者是其他服务,比如主机B在海外,就可以访问Google等等)

动态端口转发的步骤:

  1. 在内网主机执行

ssh -D ${内网网卡IP}:${内网代理端口} root@${公网IP}

  1. 本地发起的请求,需要由Socket代理(Socket Proxy)转发到内网代理端口。以Firefox浏览器为例,配置Socket代理需要找到首选项>高级>网络>连接->设置:

img

这样的话,Firefox浏览器发起的请求都会转发到2000端口,然后通过SSH转发到真正地请求地址。若Node.js服务运行在远程云主机上,则在Firefox中访问localhost:${Node.js服务端口}即可以访问服务。如果主机B1能够访问外网的话,则可以科学上网

1.4 链式端口转发

所谓的链式端口转发,就是将本地端口转发与远程端口转发结合起来,适用于如下场景:

内网主机C将发往本机的某端口的请求转发到另一个内网的主机D的某端口的某服务,需要公网主机A做中转

  • 使用本地端口转发,建立主机C与公网主机A的连接
  • 使用远程端口转发,建立主机A与内网主机D的连接