使用ssh打洞实现反向代理访问内网服务 2015-04-06 17:08:12 不得不佩服ssh的功能之强大,各种隧道代理,n中玩法,看是很复杂的网络包转发处理,一条ssh命令搞定,真乃神器也! 我家里有个非常省电的cubieboard小主机,原来折腾过一段时间的硬件,后来就凉在一边也没再管了,最近想反正一个月也就耗1-2度点,何不用它跑些对外的服务。于是乎拿Python写了个小的web系统。 现在问题来了,我的主机是在自家的路由器环境下的,ip是192.168.1.xx,这就不能对外开放了呀(也许有人会说设置路由器的DMZ主机呀,我能说我用的方正带宽即便是设置DMZ主机,联通或者移动的网络依然无法访问么,且路由器的公网ip是动态分配的呀,有点啰嗦了,总是DMZ主机也搞不定)。 不过,我手头上有一台阿里云的主机,这个主机是对公网开放的,只要能上网哪都能访问得到。突然想到,小主机可以连通阿里云的机器,理论上来说我可以通过阿里云的机器访问到小主机啊。 我在14年10月份左右尝试过通过TCP协议打洞的原理来达到这一目的,貌似路由器上有限制,最后以失败告终。 最近在新单位经常使用ssh做socks代理访问内网的服务,心想,如果反过来应该也是可以的吧,于是研究了下ssh的几种常用代理方式: <http://www.cnblogs.com/wangkangluo1/archive/2011/06/29/2093727.html>。 最终找到了一条路子。 假设我内网的小主机为A,阿里云的主机为B,A可以连通B,A->B,但是B无法连接到A。 我们要实现B->A,可以通过ssh的-R参数实现。 在A上执行:`ssh -R 88:localhost:80 user@B`,这条命令表示将B上的88端口映射到A的80端口上。 在B上执行`netstat -an | grep 88`,可以看到如下结果: ``` tcp 0 0 127.0.0.1:88 0.0.0.0:* LISTEN ``` 由于我映射的是个网站,所以我在B上执行`curl http://localhost:88`可以看到正常返回的html内容。 不过现在还有个问题,B上的88端口绑定的是127.0.0.1这个ip,依然是无法通过公网ip加端口的形式访问。如果有域名的话,可以通过配置nginx代理访问这个端口。 如果想通过公网ip:port的形式访问,就需要改一下B机器的ssh服务配置了,编辑`/etc/ssh/sshd_config`,在文件的最后添加`GatewayPorts yes`,通过`/etc/init.d/ssh restart`重启ssh服务。最后在A上重新执行:`ssh -R 88:localhost:80 user@B`。 现在就可以通过`http://ip-of-b:88`来访问内网小主机A上的web服务了。 ### 设置后台执行 下面是一个参考脚本,假设脚本名为hole.sh 后台执行ssh命令的关键参数为:-CfNgqP ``` #!/bin/bash ps -ef | grep 10080 | grep -v grep | awk '{print $2}' | xargs kill ssh -o TCPKeepAlive=yes -o ServerAliveInterval=300 -CfNgqP \ -R 10080:localhost:80 \ <user>@<your server> ``` 虽然可以在后台执行了,不过难免有网络异常导致ssh进程退掉,我们可以在搞个脚本放到crontab中进行检测并自动恢复: ``` #!/bin/bash proc=$(ps -ef | grep 10080 | grep -v grep) if [ -z "$proc" ]; then sh /home/cubie/hole.sh fi ``` 嗯,这么搞就比较妥了,也不用啥额外的软件。 有个国内的开发者用go实现了相同功能的项目:有兴趣可以研究下:<https://github.com/Lupino/hole> 非特殊说明,均为原创,原创文章,未经允许谢绝转载。 原始链接:使用ssh打洞实现反向代理访问内网服务 赏 Prev 小心Scala/Java的split函数 Next python屏蔽requests模块日志