使用ssh从外网访问内网
一、场景如下:
各个角色的对应关系如下:
角色 | 描述 |
---|---|
APP | 个人笔记本,属于内网IP |
sshd server |
公网 VPS ( 映射端口: port 2222 ),拥有公网IP |
ssh client | 内网机器,属于另一个内网IP |
APPSRV |
与 内网 ssh client 是同一台机器 ( 目的端口: |
两个帐号:admin/password为“内网机器”ssh的登录帐号密码,VPS-user
/password为“公网VPS”ssh的登录帐号密码
网络连通情况:“内网机器”可以访问公网VPS,“个人笔记本”可以访问“公网VPS”,但是不可以访问“内网机器”;“公网VPS”不能访问“内网机器”,也不能访问“个人笔记本”
二、目标:实现私网的笔记本访问另一个私网的“内网机器”
三、思路:建立反向代理,把访问公网VPS某个端口的流量映射到“内网机器”的某个端口;然后建立正向代理,把“个人笔记本”对“内网机器”的访问流量、访问请求,通过代理发给“VPS”的那个映射端口
四、步骤:
1、反向代理:“公网VPS”===>”内网机器”,通过内网机器反向连接VPS
在内网机器上配置:(ssh clinet) # ssh -CfnNT -R 2222:localhost:22
VPS-user@VPS
(ssh clinet) #
ssh-p 22 -qngfNTR 6666:localhost:22 VPS-user@VPS
这样就把“内网机器”的22端口转发到了远程机器(VPS)的6666端口上
查看内网机器的进程
[ssh clinet ~]# ps aux | grep “ssh -p”
root 14594 0.0 0.0 59856 1056 ? Ss 11:16 0:00 ssh -p 22 -qngfNTR 6666:localhost:22 VPS-user@VPS
查看公网VPS的端口情况,注意端口6666,只有本地环回地址可以访问
[sshd server ~]# netstat -anpt | grep 6666
tcp 0 0 127.0.0.1:6666 0.0.0.0:* LISTEN 10703/sshd
这时候,在公网VPS上就可以通过ssh连接内网机器,打通了“公网VPS”到“内网机器”的访问通道
[sshd server ~]# ssh -p 6666 admin@localhost
admin@localhost\’s password:
输入“内网机器”ssh帐号的密码“password”,就可以在公网VPS上实现到内网机器的ssh连接
2、正向代理:“个人笔记本”===>“公网VPS”
在“个人笔记本”上配置:[App ~] # ssh
-p 6666 -qngfNTD 6767
VPS-user@VPS,这样,访问“个人笔记本”本机(127.0.0.1)端口6767的流量就流向了“内网机器”
但是目前,上面配置是不生效的,因为“公网VPS”的端口6666,只允许它自己访问。解决办法有两个:
a、思路:修改“公网VPS”的配置sshd_config,使其建立的SSH端口供所有IP访问
方法:把“公网VPS”配置文件/etc/ssh/sshd_config里的配置“GatewayPorts no”修改为“GatewayPorts yes”,重新执行步骤1,执行完查看“公网VPS”的6666端口如下
[sshd server ~]# netstat -anpt | grep 6666
tcp 0 0 0.0.0.0:6666 0.0.0.0:* LISTEN 10703/sshd
b、思路:不修改“公网VPS”的配置sshd_config,仍然采用默认配置“GatewayPorts no”,在“公网VPS”上增加一个本地端口映射,使新增加的端口供所有IP访问,或者供特定的IP访问
方法:在“公网VPS”上配置:[sshd server~] # ssh -fCNL *:6667:localhost:6666 localhost,这一步执行需要“公网VPS”的root帐号密码
查看“公网VPS”的进程和端口情况:
[sshd server ~]# netstat -anpt | grep 6667
tcp 0 0 0.0.0.0:6667 0.0.0.0:* LISTEN 1073/sshd
[ssh server ~]# ps aux | grep “ssh -p”
root 14594 0.0 0.0 59856 1056 ? Ss 11:16 0:00 ssh -fCNL *:6667:localhost:6666 localhost
然后重复执行步骤2,不过端口由6666修改为6667
[App ~] # ssh
-p 6667 -qngfNTD 6767
VPS-user@VPS,这样,访问“个人笔记本”本机(127.0.0.1)端口6767的流量就流向了“内网机器”
这个时候在“内网机器”上开启80端口的服务[ssh clinet~]# python -m SimpleHTTPServer 80
在“个人笔记本”上配置浏览器代理,要选用“socks5”
然后访问
五、保持连接的网络稳定
方法一、客服端发“心跳”,配置ssh_config
使用SSH客户端的ServerAliveInterval和ServerAliveCountMax选项。 ServerAliveInterval会在隧道无通信后的一段设置好的时间后发送一个请求给服务器要求服务器响应。如果服务器在 ServerAliveCountMax次请求后都没能响应,那么SSH客户端就自动断开连接并退出,将控制权交给你的监控程序。这两个选项的设置方法分别是在ssh时加入-o ServerAliveInterval=n和-o ServerAliveCountMax=m。其中n, m可以自行定义
方法二、服务端发“心跳”:配置sshd_config
ClientAliveInterval 60 服务器端向客户端请求消息的时间间隔为60秒
ClientAliveCountMax 3 表示服务器发出请求后客户端没有响应的次数达到3次, 就自动断开
这样的配置就能让一个SSH的配置保持长连接了
六、ssh配置含义:
-f 后台运行,后台认证用户/密码,通常和-N连用,不用登录到远程主机,
将ssh转到后台运行,即认证之后,ssh 自动以后台运行。不再输出信息 告诉SSH客户端在后台运行
-C 允许压缩数据
-R 将端口绑定到远程服务器,反向代理,将远程主机(服务器)的某个端口转发到本地端指定机器的指定端口。工作原理是这样的, 远程主机上分配了一个socket侦听port端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去,同本地主机host的hostport端口建立连接。可以在配置文件中指定端口的转发。
-L 将端口绑定到本地客户端,正向代理,将本地机(客户机)的某个端口转发到远端指定机器的指定端口。工作原理是这样的, 本地机器上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去, 同远程主机host的hostport端口建立连接。可以在配置文件中指定端口的转发。
-L X:Y:Z的含义是,将IP为Y的机器的Z端口通过中间服务器映射到本地机器的X端口。
-D port指定一个本地机器 “动态的’’应用程序端口转发,工作原理是这样的, 本地机器上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去, 根据应用程序的协议可以判断出远程主机将和哪里连接。
-n 将 stdio 重定向到 /dev/null,与 -f 配合使用
-N 不执行脚本或命令,即通知 sshd 不运行设定的 shell 通常与 -f 连用,告诉SSH客户端,这个连接不需要执行任何命令。仅仅做端口转发
-T 不分配 TTY 只做代理用
-q 安静模式,不输出错误/警告信息
-g 在-L/-R/-D参数中,允许远程主机连接到建立的转发的端口,如果不加这个参数,只允许本地主机建立连接
通过远程主机1跳到远程主机2:
命令格式:
ssh -t remoteserver1 ssh remoteserver2
说明:当远程主机remoteserver2无法直接到达时,可以使用-t参数,然后由remoteserver1跳转到remoteserver2。在此过程中要先输入remoteserver1的密码,然后再输入remoteserver2的密码,然后就可以操作remoteserver2了。
man sshd_config
man 5 shells
图示,正向代理:ssh -L
图示,反向代理:ssh -R
参考:
1、http://lvii.github.io/system/2013/10/08/ssh-remote-port-forwarding/
2、http://bobao.360.cn/learning/detail/4234.html
3、https://segmentfault.com/a/1190000002718360
4、http://www.dirk-loss.de/ssh-port-forwarding.htm