利用SSH隧道端口映射进行反向代理的应用

前言

通常公司内部的网络都是对内不对外的,也就是说,外网无法访问内部网络。但如果公司服务器可以访问外网,且有一台公网服务器,可以用ssh隧道进行端口映射来实现外网访问内网的web服务器。

这里先说明一下服务器相关情况:

主机IP用户名描述
A192.168.1.150david内网服务器,可访问外网
B120.27.50.100sshuser公网服务器,充当桥梁的作用

注意:这里主机的IP和用户名都是随便写的,实际操作换成你自己的服务器IP和用户名就可以了。

处理方法

通俗地说,就是在机器A上执行命令,让访问B机器指定端口的请求反向代理到A机器的指定端口;然后在B机器上执行命令,正向代理实现本地端口的转发到A机器。

操作准备

每台服务器都需要安装ssh的客户端。
这里我使用的是 Centos 7,自带ssh。如果使用的其他版本操作系统,自己Google一下。

SSH相关参数

这里介绍3个强大的ssh端口转发命令

1. 转发到本地(反向代理)
-R 将远端主机端口映射到本地端口。格式和说明如下:

参数说明:将远程主机(服务器)的某个端口转发到本地端指定机器的指定端口。
工作原理:远程机器上分配了一个socket侦听port端口,一旦这个端口上有了连接,该连接就经过安全通道转发出去,同时本地主机和host的hostport端口建立连接。可以在配置文件中指定端口的转发,只有root才能转发特权端口。IPv6地址用另一种格式说明:port/host/hostport

ssh -R -CNfg [bind_address:]port:host:hostport user@host

ssh -R -CNfg [B主机IP或省略:]B主机端口:A主机的IP:A主机端口 B主机的用户名@B主机IP

举例:将发往romoteip 80端口的访问转发到本机8080端口

ssh -R -CNfg 80:localhost:8080 user@romoteip

2. 转发到远端(正向代理)
-L 将本地端口映射到远端主机端口。格式和说明如下:

参数说明:将本地机(客户机)的某个端口转发到远端指定机器的指定端口。
工作原理:本地机器上分配了一个socket侦听port端口,一旦这个端口上有了连接,该连接就经过安全通道转发出去,同时远程主机和host的hostport端口建立连接。可以在配置文件中指定端口的转发,只有root 才能转发特权端口。IPv6 地址用另一种格式说明:port/host/hostport

ssh -L -CNfg [bind_address:]port:host:hostport user@host

ssh -L -CNfg [A主机IP或省略:]A主机端口:B主机的IP:B主机端口 B主机的用户名@B主机的IP

举例:将发往本机的80端口访问转发到192.168.1.1的8080端口

ssh -L -CNfg 80:192.168.1.1:8080 user@192.168.1.1

3. 动态转发
-D 将本地动态绑定的端口的数据,全部转发到远程主机。格式和说明如下:

参数说明:指定一个本地机器“动态的”应用程序端口转发。
工作原理:指定一个本地机器“动态的”应用程序端口转发。工作原理是这样的,本地机器上分配了一个socket 侦听port 端口,一旦这个端口上有了连接,该连接就经过安全通道转发出去,根据应用程序的协议可以判断出远程主机将和哪里连接。目前支持SOCKS4 协议,将充当SOCKS4服务器。只有root才能转发特权端口。可以在配置文件中指定动态端口的转发。

ssh -D -CNfg listen_port user@host

其他参数

-C 压缩数据传输。

-f 后台认证用户/密码,通常和-N连用,不用登录到远程主机。

-N 不执行脚本或命令,通常与-f连用,在只是端口转发时这条命令很有用处。

-g 在-L/-R/-D参数中,允许远程主机连接到建立的转发的端口,如果不加这个参数,只允许本地主机建立连接。

-p 被登录的ssd服务器的sshd服务端口。

着手操作

这里A主机我开放了3000端口,并配置了webserver指向3000端口,使用http://127.0.0.1:3333可以正常访问配置好网站demo。如果想在外网访问内网服务器的网站,下面我分步骤给大家讲解。

1.登录A主机,向B主机建立反向代理

输入下面的命令,

ssh -R -CNfg 3000:localhost:80 remoteserver

执行完成后,在B主机上,执行netstat -an | grep 3000,查看有没有开通3000端口。并执行以下命令观察是否可以打开webserver上的网页

$ w3m http://127.0.0.1:3000

如果能打开界面,说明映射成功。但仅限于B主机访问webserver。因为3000端口绑定的是B的127.0.0.1的端口。

2. 登陆B主机,修改ssh配置文件

编辑remoteserver机器上的/etc/ssh/sshd_config文件并添加如下内容:
添加GatewayPorts yes内容,把监听端口3000绑定到 0.0.0.0 地址上,这样外部的所有机器都能访问到这个监听端口,然后保存退出。并重启ssh服务。
完成后,其它机器就可以在浏览器中输入http://remoteserver:3000来访问webserver了。

3. 向A主机建立正向代理

如何想将B主机其他端口映射到A主机,可以使用正向代理的方式实现。执行下面命令,将B主机3001端口映射到B主机3000端口。这里你会发现主机IP和端口都是B主机的,因为A主机已经建立了反向代理,这里只是做了一个内部端口转发。

ssh -L -CNfg *:3001:localhost:3000 localhost

4. 使用更稳定的autossh

经过上面操作,我们已经基本达到了我们的目的。遗憾的是,上面的ssh连接很容易因为网络不稳定或超时而关闭。如果关闭了那从外网连通内网的通道就无法维持了,因此我们需要另外的方法来提供稳定的ssh反向代理隧道。

4.1 安装autossh

centos7上没有默认安装autossh的,使用yum命令安装一下即可。

yum install autossh

4.2 使用autossh

看看具体的autossh的指令如何达到上面的效果

autossh -M 2021 -R -CNfg 3000:localhost:80 root@120.27.50.100 

autossh的参数与ssh的参数是一致的,但是不同的是,在隧道断开的时候,autossh会自动重新连接而ssh不会。另外不同的是需要指出的-M参数,这个参数指定一个端口,这个端口是外网的B主机用来接收内网A主机的信息,如果隧道不正常而返回给A主机让它实现重新连接。

5. 配置开机启动

最后在Linux上配置开机自动启动autossh,免去了重启系统后要自己启动的autossh的麻烦。
修改/etc/rc.d/rc.local文件,将命令添加进去,并且执行chmod +x /etc/rc.d/rc.local修改权限文件权限。

centos7之后,修改/etc/rc.d/rc.local启动脚本自动生效的功能,需要重新赋予可执行权限才会生效

vi /etc/rc.d/rc.local

# 添加命令
autossh -M 2021 -R -CNfg 3000:localhost:80 root@120.27.50.100

结言

其他

如何关闭80端口的监听?
端口不是独立存在的,它依附于进程,所以我们只要找到对应的进程并关掉它,那么端口监听也就关闭了。

netstat -anp | grep ssh

tcp    0    0    0.0.0.0:80    0.0.0.0:*    LISTEN    838/sshd

使用 kill -9 838 关闭这个进程就可以了。

常见问题解决办法

问题1: ssh登录的时候链接端口失败

情况1:

$ ssh 172.16.81.221
ssh: connect to host 172.16.81.221 port 22: No route to host

这由于server端没有开机或是网络不通(这个原因很多,最简单的是网线没有插。还有就是可能会是网卡down了等)

情况2:

$ ssh work@172.16.81.221
ssh: connect to host 172.16.81.221 port 22: Connection refused

这是由于对方server的ssh服务没有开。这个server端开启服务即可。

问题2: ssh到server上的时候密码是对的但是报如下信息:

$ ssh 172.16.81.221
root@172.16.81.221's password:
Permission denied, please try again.

这个是由于如果不输入用户名的时候默认的是root用户,但是安全期间ssh服务默认没有开root用户的ssh权限
解决方法: 要修改root的ssh权限,即修改 /etc/ssh/sshd_config 文件中,PermitRootLogin no 改为 PermitRootLogin yes

问题3: 登录时出现如下提示(警告:远程主机身份已改变!):

$ ssh root@120.27.50.100
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! 
Someone could be eavesdropping on you right now (man-in-the-middle attack)! 
It is also possible that the RSA host key has just been changed. 
The fingerprint for the RSA key sent by the remote host is 
76:fb:b3:70:14:48:19:d6:29:f9:ba:42:46:be:fb:77\. 
Please contact your system administrator. 
Add correct host key in /home/root/.ssh/known_hosts to get rid of this 
message. 
Offending key in /home/root/.ssh/known_hosts:68 
RSA host key for 120.27.50.100 has changed and you have requested strict checking. 
Host key verification failed.

server端密码或是ip对应的server等其他发生改变的时候。
解决方法: 一般就需要删除 ~/.ssh/known_hosts 的对应行,然后再登录即可。

问题4: 如何通过ssh使用远程的图形启动到本地
在本机执行xhost +修改远端 /etc/ssh/sshd_config 文件,X11Forwarding yes 这一行为 yes。重启ssh服务。登录时执行ssh -X [远端IP]登录之后执行图形配置工具可以在本机显示 。

问题5: 无法连接到外网主机,主机A出现“Bad remote forwarding specification '-CNfg'”

$ ssh -R -CNfg 2222:localhost:22 root@remoteip
Bad remote forwarding specification '-CNfg'

解决办法: 由于本地ssh版本问题,我这里是OpenSSH_8.1p1, OpenSSL 1.1.1d 10 Sep 2019,调整参数顺序后即可。

ssh -CNfgR 2222:localhost:22 root@remoteip

如需转载,请注明出处: https://www.chadou.me/p/168

最新发布