内网穿透

less than 1 minute read

Published:

内网穿透的解决方式一般有两种:

  1. 借助有公网IP的服务器当跳板,客户端与内网的服务器进行连接
  2. 借助有公网IP的服务器,将客户端和内网服务器打洞,之后客户端与内网服务器直接通信 一般来说,遇到的问题主要和防火墙有关,可以参考如何解决防火墙的问题

对于Easy防火墙(只要有出包,不管入包是哪里发来的,都可以进),通常打洞比较简单;

对于Hard防火墙(入包必须是出包目的地对应的ip,其它ip进不来),一般需要借助公网IP服务器当跳板了

这篇文章记录的解决方案有两种:

FRP

这个方案部署起来比较简单,参考相关教程,把FRP server部署在有公网IP的服务器上,把FRP client部署在内网的机器上,即可将公网IP对应端口映射到内网机器的对应端口上。 但是这个方案存在问题是FRP流量容易被校园网防火墙查封,服务很容易挂掉,详见:

  1. https://github.com/fatedier/frp/issues/2865
  2. https://github.com/fatedier/frp/issues/3439

目前没有很好的解决方案

Tailscale

这个方案直接部署更简单,按照官网指引把每个设备下载一下tailscale即可互联了,而且不会被校园网防火墙查封。但是默认官方的公共服务器都在境外(最近的是香港),如果打洞不成功的话走官方跳板服务器通信延迟都是100ms起步。

优化方法是自建中继服务器,tailscale使用的中继服务器叫DERP,我们在自己的国内云服务器上部署私有的DERP服务器做跳板可大大降低访问时延。

自建DERP服务器部署方法可以参考:

  1. https://icloudnative.io/posts/custom-derp-servers/
  2. 自建derp中继节点
  3. https://tailscale.com/kb/1118/custom-derp-servers#run-a-derp-server-from-source

值得注意的是,由于DERP服务器只能用ssl通信,当你的域名没有备案时,云服务厂商可能会查封相应的端口,导致客户端连接DERP服务器超时,报错类似这样:

http: TLS handshake erro from (客户端ip+端口): write tcp (服务器ip+端口)->(客户端ip+端口): write: connection reset by peer

流量会被墙,握手都一直失败

这种情况建议DERP服务器使用纯IP,我参考了这个docker镜像部署: https://hub.docker.com/r/yangchuansheng/ip_derper

使用如下命令即可:

sudo docker run --restart always 
--name derper_ip -p 443:443 (https端口)
 -p 3478:3478/udp 
-v /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock 
-e DERP_ADDR=:443
--net host 
-d yangchuansheng/ip_derper

值得注意的是,记得在云服务器控制台放行对应的 https端口3478端口41641端口(用来打洞的,不放行这个端口无法打洞)

然后在tailscale网站上修改控制规则,在Access Controls里添加规则如下:

        "derpMap": {
                // OmitDefaultRegions true的话就忽略官方给的服务器,只用自己私有的
                "OmitDefaultRegions": false,
                "Regions": {
                        "901": {
                                "RegionID":   901, // 901 三个地方保持一致,900开始,多个节点可以往后+1
                                "RegionCode": "GZ",
                                "RegionName": "GuangZhou",
                                "Nodes": [
                                        {
                                                "Name":     "Aliyun_GuangZhou_1",
                                                "RegionID": 901,
                                                "HostName":         "ip", //域名没备案前只能用纯ip
                                                "IPv4":             "ip",
                                                "StunOnly":         false,
                                                "DERPPort":         https端口,
                                                "InsecureForTests": true,
                                        },
                                ],
                        },
                },
        },

部署完后基本就OK了,如果想自己搭建控制服务器还可以部署一个headscale,可以参考https://icloudnative.io/posts/how-to-set-up-or-migrate-headscale

完成后测试输入命令:

tailscale netcheck
tailscale ping xxx(你内网的机器)

看到你部署的DERP服务器后,再ping一下内网机器看看能否ping通过,走的是不是自建的节点。