缘由
我写这篇文章,可以解决如下问题:在内网主机运行网站,无公网 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 秒。
- 第二个参数表示,如果服务器(内网)没有收到心跳包指定次数,就中断连接。
今早起来,发现没掉,很稳定。