内网穿透

买了一台阿里云的VPS,有了公网IP就想着内网穿透的事情

一台内网服务器A,一台外网服务器B,我希望通过外网连接SSH来连接到A

也就是在家里连公司内网的办公虚拟机

中间踩了几波坑,记录一下

ssh反向代理(不推荐)

最简单的内网穿透就是利用ssh反向代理

在B上设置/etc/sshd_config中修改GatewayPorts no为yes来转发外网的ip请求,随后重启sshserver,systemctl restart sshd

在A上安装autossh

执行命令

1
autossh -R [服务器IP或省略]:[服务器端口]:[客户端侧能访问的IP]:[客户端侧能访问的IP的端口] [登陆服务器的用户名@服务器IP] -p [服务器ssh服务端口(默认22)]

后台运行是需要输入密码的,然而autossh并没有提供帐号密码的选择,因此需要配置免密钥登录,把A的公钥拷贝到B上

1
2
3
nohup autossh -M port1 -NR port2:localhost:22 root@B.B.B.B >> autosshlog 2>&1 &
此时就可以用
ssh -p port2 访问B了

用autossh是看中他的重连功能,结果效果并不好,用了一段时间经常整个进程挂掉,于是换工具

dog tunnel lite 反向代理

国人用golang开发的,能完美替代ssh反向代理

这是官网,上面有lite的下载地址,dog tunnel

lite版使用文档

B.B.B.B就是server的地址

1
2
server: ./dtunnel_lite -service :1234
client: ./dtunnel_lite -service B.B.B.B:1234 -local :8787 -action :22

此时连接server的8787端口即可连接到client的22端口上

dog tunnel p2p 打洞

这个就厉害啦

代理模式受限与代理机器的网速

然而P2P打洞,只是一开始寻址要经过公网机器,后面即使公网机器挂了,短时间内也不会影响到打出来的洞

以下是别人整理的文档(本身的P2P版本的文档好像不全),来自Senraの小窝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
dtunnel_s的参数说明

-addr:TCP端口地址,用于C/S模式
-addrudp:UDP端口地址,用于P2P辅助打洞
-admin:管理接口,用于提供API方便管理
-https:启用管理接口的HTTPS支持,需要指定-cert和-cert参数,默认关闭
-ssl:启用ssl支持,启用需要指定-cert和-cert参数,默认关闭
-cert:证书路径
-key:证书密钥路径
-dbhost:数据库服务器
-dbpass:数据库密码
-dbuser:数据库用户
-replace:如果客户端注册名冲突,踢掉之前的,默认关闭
-version:显示版本

dtunnel 的参数说明
-addip:出口IP(单个或列表)
-buster:打洞服务器,用于P2P模式
-remote:远程服务器,用于C/S模式,默认官方服务器(已挂,必须自己设置)
-clientkey:客户端Key,用于远端和近端认证,需一致
-compress:压缩数据,远端和近端需一致
-debug:调试模式
-delay:打洞失败后重试延迟,秒
-dnscache:DNS缓存有效期,如果大于0将定时清空DNS缓存,分钟
-encrypt:P2P模式加密
-f:从文件中加载配置
-kcp:kcp配置,远端和近端需一致
-key:访问Key(服务端数据库中的AuthKey)
-reg:注册名,远端使用
-link:连接的注册名,近端使用,用于识别连接远端
-local:本地监听端口,填socks5则为socks5代理服务
-mode:连接模式(0:P2P打洞失败后切换为C/S 1:只使用P2P 2:只使用C/S)
-pipen:管道数
-ds:数据纠错??仅在P2P模式有效,远端和近端需一致
-ps:奇偶校验??仅在P2P模式有效,远端和近端需一致
-ssl:启用ssl支持,默认启用,服务端没有启用的话请使用-ssl=false来关闭
-v:输出详细日志
-version:显示版本

琢磨了一下这些文档,这里是我的使用方式

port1是机器B对外服务的udp端口,port2是机器B的对外服务tcp端口。

B.B.B.B是B的ip地址

1
2
3
4
5
6
公网机器B:
nohup ./dtunnel_s -addrudp :port1 -addr 0.0.0.0:port2 2>&1 >> log &
内网机器A:
nohup ./dtunnel -reg serviceName -local :22 -buster B.B.B.B:port1 -remote B.B.B.B:port2 -ssl=false -mode 1 >> log 2>&1 &
家里电脑C(windows):
dtunnel.exe -link serviceName -local :8888 -buster B.B.B.B:port1 -remote B.B.B.B:port2 -ssl=false

这样配置以后会以p2p模式连接port1,如果失败的话会以c/s模式去连接port2,这两个模式必须要配置,否则会默认连接官方已经挂掉的服务器。

然后必须加上-ssl=false这个参数项,来关闭TCP的ssl校验

此时ssh家里电脑C的127.0.0.1:8888就可以和内网机器A进行交互了

总结

在大部分情况下p2p模式都是最好的,因为不受代理服务器的限制,也不需要忍受代理服务器的延迟

但是对于使用4G信号的手机或者ipad来说,并不关心速度,此时使用dog tunnel反向代理的端口即可

(当然更重要的原因是在android上用p2p也挺蛋疼的。。)