使用SSH反向隧道实现内网穿透

之前在知乎写过一个回答,外网如何访问学校内网资源,

外网如何访问学校内网资源?www.zhihu.com图标

一个老生常谈的问题,其实回答得已经比较明确了,而且方案是肯定没有错的,因为已经亲自使用很久了,但还是有很多网友碰到了各种各样的问题,私下里问该怎么弄,有没有具体教程。

我其实很不喜欢去写这种流程式的傻瓜操作,一个太浪费时间,另一个搞技术,不踩坑哪里来的技术?可是又想了想,自己入门的时候又何尝不是经常折腾的心累交瘁,吐嘈网上的这些资料就不能有一个写得清清楚楚明明白白。

下面我以树莓派为例,尽量按流程顺序把步骤写清楚,虽然不可能每个间接操作也列出来,但尽可能点到。


问题描述:如何在任何地方对处在内网的主机进行操作并访问内部资源(数据库等)?

前提条件:

  1. 处在内网的 Linux 主机,可以是树莓派、刷了类似 OpenWrt 固件的路由器等;
  2. 具有公网 IP 的 Linux VPS 。

假设约定:内网主机为 A ,VPS 服务器为 B ,SSH 端口均为默认值 22 。


  • 在 A 上安装 autossh

其用法几乎和 ssh 一模一样,最大的区别是加入了监听端口,用来维护 ssh 通道的持久连接,然后执行下面的命令:

$ autossh -M 30000 -o "StrictHostKeyChecking=false" -o "ServerAliveInterval 10" -o "ServerAliveCountMax 3" -NR 20000:localhost:22 B-User@B-Address
-M 是监听端口,用来监视 ssh 通道的状态,-R 代表反向连接,该命令表示将内网 A 主机的 22 端口映射到 B 服务器的 20000 端口,如果服务器没有发来数据则每隔 10s 向服务器发一个空包。
  • 远程 SSH 登录 A

你可以在 B 上执行如下命令:

$ ssh -p20000 A-User@localhost

或者在任意一台主机上执行:

$ ssh -p20000 A-User@B-Address
上一命令可能需要在 B 的安全组策略里允许任意连接通过 TCP 访问 20000 端口。
  • 通过动态端口转发访问内网资源

在 B 上执行如下命令:

$ ssh -gD 30002 -p20000 A-User@localhost
-g 允许远程主机连接,-D 设置动态端口转发,即将 30002 端口上的连接都转发到内网主机 A 上。

这样你就可以在任何一台能够上网的电脑上简单配置一下浏览器的代理设置,通过 B 的 30002 端口提供的 socks 服务来访问内网资源了(B 的安全组策略需要通过 30002 端口)。

  • 密钥登录 SSH

实际使用过程中是不可能像测试一样通过密码来连接的,所以需要将 A 和 B 的公钥分别拷进对方的 authorizedkeys 文件中,并在双方的 sshd_config 配置文件中设置允许私钥登录,需要注意的是请不要为私钥设置使用密码。

  • A 的开机运行

可以直接将刚才 A 上执行的命令写入 rc.local 文件中,当然也可以直接做成一个启动服务,我自己比较喜欢使用 supervisor 来进行管理,用法请自行查询。


技术永远不是死板的,重要的是思考,同样的原理完全可以用不同的方法来实现,就像在 A 上执行下面的代码是不是完全可以实现 socks 代理的一直开启?

$ autossh -M 30001 -D 30002 A-User@localhost

$ autossh -M 30000 -o "StrictHostKeyChecking=false" -o "ServerAliveInterval 10" -o "ServerAliveCountMax 3" -NR 30002:localhost:30002 B-User@B-Address

编辑于 2018-03-25