缘由

我写这篇文章,可以解决如下问题:在内网主机运行网站,无公网ip所以只能内网访问。但是主机内网可以访问外网,外网无法访问内网,现在我要做的就是通过反向代理,访问公网ip就能访问到内网主机网站,只需要一台vps

以下我都会用8080端口来转发,因为我的80端口被占用了。

什么是代理

这里引用下知乎的答案。

代理其实就是一个中介,A和B本来可以直连,中间插入一个C,C就是中介。刚开始的时候,代理多数是帮助内网client访问外网server用的(比如HTTP代理),从内到外。后来出现了反向代理,”反向”这个词在这儿的意思其实是指方向相反,即代理将来自外网client的请求forward到内网server,从外到内。
作者:王明雨
链接:https://www.zhihu.com/question/24723688/answer/28828062
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

执行方案

首先ssh登录到公网主机,修改sshd的配置文件/etc/ssh/sshd_config,加入如下选项。

GatewayPorts yes

重启sshd,如下

# service sshd restart

这个选项的意思是,你通过反向代理的ip是公网ip(0.0.0.0),而不是loopback的ip(127.0.0.1)。后面会提到这个选项的具体作用。

然后ssh登录到内网主机,通过ssh来执行反向代理到公网主机,这里先给出几个参数的解释。

-N ssh不执行命令
-f 后台执行
-R 反向代理

所以只要执行以下命令,键入密码即可:

ssh -NfR 8080:localhost:80 <用户名>@公网主机ip

这里表示将内网主机的80的端口反向代理到公网主机的8080端口,如果你不开启GatewayPorts选项,就只能转发到公网主机的127.0.0.1网络上。

这时候在公网主机上执行:

$ netstat -tnl|grep 8080
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN
tcp6       0      0 :::8080                 :::*                    LISTEN

看到如上结果表明成功,这时候可以通过浏览器访问,公网ip:8080

免密码、稳定隧道

上述的ssh方式不够稳定,而且每次断开重连都要键入密码,这里先给出免密码方式。

内网主机上,执行

$ ssh-copy-id <用户名>@公网主机ip

以后通过这台内网主机ssh公网主机,就不需要输入密码了。

至于稳定隧道,可以用autossh来解决,先安装autossh

# apt-get install autossh

autossh的参数和ssh的参数一致,但是它会在隧道断开重连,省去了手动重连的方式。这里需要指出它的-M参数,-M参数指定一个端口用来做回显echo测试,它会在公网主机开一个端口专门接收内网主机的心跳包,然后回显回去(端口号+1),以表明隧道是否正常,若不正常则重连。

于是最终的命令如下:

autossh -M 23333 -NfR 8080:localhost:80 <用户名>@公网主机ip

为了开机自启动,可在/etc/rc.local写入上述命令。

最终方案

昨晚用autossh发现还是不稳定,8080端口会掉,而-M的端口不会掉,于是又换方案了,为ssh设置重连参数,修改内网主机的~/.ssh/config文件,增加如下参数:

ServerAliveInterval 60
ServerAliveCountMax 9999999999
  • 第一个参数表示如果服务器(外网)没数据发来则过60秒客户端(内网)会发送一个空包到服务器,以保持tcp长连接,默认值为0,表示不会发心跳包,所以这里设置为60秒。
  • 第二个参数表示,如果服务器(内网)没有收到心跳包指定次数,就中断连接。

今早起来,发现没掉,很稳定。