前言
通常公司内部的网络都是对内不对外的,也就是说,外网无法访问内部网络。但如果公司服务器可以访问外网,且有一台公网服务器,可以用ssh隧道进行端口映射来实现外网访问内网的web服务器。
这里先说明一下服务器相关情况:
主机 | IP | 用户名 | 描述 |
---|---|---|---|
A | 192.168.1.150 | david | 内网服务器,可访问外网 |
B | 120.27.50.100 | sshuser | 公网服务器,充当桥梁的作用 |
注意:这里主机的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