打通大内网第四期 部署并穿透DERP服务器 (基于Lucky的STUN穿透)

前言

上一期介绍了如何通过frp的stcp/sudp来固定访问端口,虽然可靠性和安全性都得到了保障,配置还是麻烦了一点,每添加一个服务都要修改两处frpc的配置文件,并需要每个访问者都手动更新。并且对于访问者而言,处理端口冲突、注册服务也需要一点知识储备,显然不如无脑安装软件来的方便。如果你只打算小范围内共享,那么直接使用tailscale也是个不错的选择。

理论上只要有一方为NAT1,是一定能直连的,但由于tailscale的服务器都在墙外,内陆的网络环境也比较复杂,偶尔会出现打不通的情况。然而我们可以另辟蹊径,在本地自建DERP中继服务器,并通过LUCKY穿透到公网上。

第一步 安装并配置Tailscale

Tailscale官网:https://tailscale.com/

关于Tailscale基本的安装、配置在此不多赘述,教程非常多,在此贴一篇OpenWrt的教程:
openwrt使用tailscale组建网对网的一些补充
如果你需要在外访问整个内网,请正确配置子网路由。

如果可能的话,尽量将Tailscale和DERP安装在同一台机器上。即使不行,最好也在部署DERP的机器上安装Tailscale,用于身份验证。
如果用于验证的Tailscale客户端是通过docker安装的,为了让DERP能够与Tailscale交互,请添加路径映射
-v /run/tailscale:/var/run/tailscale
我将Tailscale装在路由器上,DERP安装在路由器下面的Unraid上。如果以插件的形式直接安装,则无法使用本地局域网地址访问Unraid,只能使用Tailscale的100开头的地址,因此我最后用Docker安装,网络选择br0并指定了另外一个ip。

当配置完成,已经可以在外网通过Tailscale访问后,再注册一个用于共享的小号,并将其加入大号的Tailscale网络,理由有以下两点:

  1. Tailscale免费计划只允许3个用户,但是允许100台设备。通过共享账户的方式,可以允许更多人连接。
  2. DERP服务器若不开启验证,那么谁都可以白嫖;但一旦开启验证,只有本机当前登录Tailscale的账户有权访问,其他用户均无法访问。

然后将所有Tailscale客户端上登录的账号换成小号,加入大号的网络(也就是在最后一步,选择connect device的时候,点击大号邮箱)。

第二步 安装并配置DERP服务器

首先先给DERP服务器准备一个域名,并解析到STUN穿透的ipv4公网地址,如果你之前没有用过ddns,直接使用Lucky的DDNS,通过接口获取ipv4即可。

接着申请证书,使用Lucky申请非常方便,并且可以映射证书路径供其它服务使用,以及在证书更新时调用自定义脚本;如果Lucky和DERP没有部署在同一个机器上,可以用Lucky的webdav功能将映射证书的路径分享出来,或者通过自定义脚本运行scp和ssh命令,上传证书并重启DERP。具体过程略过不表。

接下来安装DERP,我使用docker安装,记得修改证书的映射路径、端口映射和域名。我这里将8051作为derp端口,3478作为stun端口。如果不想开启身份验证,请将第七行的true改为false。

docker run --restart always \
  -p 8051:443 -p 3478:3478/udp \
  -e DERP_CERT_MODE=manual \
  -v /your/cert/path:/app/certs \
  -e DERP_ADDR=:443 \
  -e DERP_DOMAIN=derp.xxxx.com \
  -e DERP_VERIFY_CLIENTS=true \
  -v /var/run/tailscale:/var/run/tailscale \
  fredliang/derper

然后为DERP服务器创建STUN穿透规则,需要两条。一条给derp端口,协议选择tcp,一条给stun端口,协议选择udp,不会的朋友可以去看看第一、第二期教程。

如果一切顺利,就可以在浏览器里访问https://derp域名:derp穿透后的公网端口。

看到以上界面说明成功。

第三步 将DERP服务器添加至Tailscale中

用大号进入Tailscale后台,在顶部切换到Access Controls选项卡,在acls后添加derpMap规则。

    // 前面有一些注释,不修改
    "acls": [
        // Allow all connections.
        // Comment this section out if you want to define specific restrictions.
        {"action": "accept", "src": ["*"], "dst": ["*:*"]},
    ],
    "derpMap": {
        "Regions": {
            "900": {
                "RegionID":   900,
                "RegionCode": "myderp",
                "RegionName": "home",
                "Nodes": [{
                    "Name":             "1",
                    "RegionID":         900,
                    "HostName":         "derp.xxxxx.xxx",
                    "DERPPort":         25814,
                    "STUNPort":         25876,
                    "InsecureForTests": true,
                }],
            },
        },
    },
    // Define users and devices that can use Tailscale SSH.
//...后面是ssh的内容,不修改

修改Hostname为你DERP服务器的域名,DERPPort和STUNPort分别改为对应的公网端口(不知道改成哪个端口就把我的规则和我之前的Lucky截图对比一下)。确认无误后点击保存。

在安装了Tailscale的机器(或容器)上执行

tailscale netcheck

如果没有出现测速结果里没有出现myderp,请检查规则是否编写正确,如果没有这个节点没有测速结果,可以稍等一会儿再试。当看到myderp节点的延迟后,证明配置成功。

第四步 自动更新DERP服务器端口

Tailscale支持通过网页后台面板、GitOps和api更新acl规则。使用GitOps可以清晰的看到每一次更新的时间以及是否成功,使用api则更加简单,本文使用api进行更新。

  • 生成OAuth client并获取id和secret

使用大号登录Tailscale后台,在Settings - OAuth clients中点击Generate OAuth client。OAuth client的名称随便填,勾选对ACL的read和write权限。然后点击Generate client,并复制生成的id和secret。

不同于最大有效期为90天的api key,OAuth clients不会过期,免去了手动更新key的麻烦。

  • 配置更新脚本

回到Lucky后台,编辑derp端口的穿透规则,将以下脚本填入自定义脚本中。
记得修改client_idclient_secret为你刚才获取到的值。

#set your oauth client here
client_id=XXXXXXXXXXXXXXXXX
client_secret=tskey-client-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

api_key=`curl -d "client_id=$client_id" \
  -d "client_secret=$client_secret" \
  "https://api.tailscale.com/api/v2/oauth/token"`
tskey=`echo $api_key | awk -F "\"" '{print $4}'`

DERPPort=${port}
tmp='/tmp/tailscale.hujson'
curl "https://api.tailscale.com/api/v2/tailnet/-/acl" \
-H "Authorization: Bearer $tskey" > $tmp
sed -i 's/"DERPPort".*/"DERPPort":         '$DERPPort',/' $tmp
curl "https://api.tailscale.com/api/v2/tailnet/-/acl" \
-H "Authorization: Bearer $tskey" --data-binary @$tmp

编辑STUN端口的穿透规则,将以下脚本填入自定义脚本中。
记得修改client_idclient_secret

#set your oauth client here
client_id=XXXXXXXXXXXXXXXXX
client_secret=tskey-client-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

api_key=`curl -d "client_id=$client_id" \
  -d "client_secret=$client_secret" \
  "https://api.tailscale.com/api/v2/oauth/token"`
tskey=`echo $api_key | awk -F "\"" '{print $4}'`

STUNPort=${port}
tmp='/tmp/tailscale.hujson'
curl "https://api.tailscale.com/api/v2/tailnet/-/acl" \
-H "Authorization: Bearer $tskey" > $tmp
sed -i 's/"STUNPort".*/"STUNPort":         '$STUNPort',/' $tmp
curl "https://api.tailscale.com/api/v2/tailnet/-/acl" \
-H "Authorization: Bearer $tskey" --data-binary @$tmp

目前Lucky并未提供自定义脚本的测试功能,不过只是填写两个变量而已,应该不会出什么幺蛾子...吧。


第五步 为Tailscale添加本地DNS并劫持域名

愿意折腾到这一步的朋友,有很大概率已经开启了ipv6,并配置好了反向代理。如果想要实现“一个域名,在内网/Tailscale中用内网ipv4,在外网中用ipv6”的效果,可以尝试一下添加本地DNS。如果不想配置反向代理,那么可以跳过这步。

本地劫持泛域名

首先在你是用的dns服务中添加HOSTS,劫持你要访问的泛域名。如果不想在内网劫持,仅想在Tailscale中劫持,可以用Docker再装一个SmartDNS,记得用网桥(如br0)把容器IP绑定到与宿主机同网段,并使用53端口。

  • 对于dnsmasq(也就是OpenWrt的默认dns)

    打开/etc/dnsmasq.conf,添加

    address = /mydomain.com/192.168.0.1
    

    并重启dnsmasq,这会劫持mydomain.com和它的所有子域名到192.168.0.1。

  • 对于SmartDNS
    自定义规则域名地址中添加

    address /mydomain.com/192.168.0.1
    

    并重启SmartDNS,这会劫持mydomain.com和它的所有子域名到192.168.0.1。

然后在内网机器上清除dns缓存,使用nslookup查询刚才劫持的域名。

由于OpenWrt会默认劫持所有访问53端口的流量到OpenWrt的53端口,因此如果你是用OpenWrt作为主路由,但自定义DNS不在OpenWrt的ip上,则需要在网络 - 防火墙 - 自定义规则中注释掉所有跟53端口相关的规则。

如果还不成功,大概率是某些科学插件修改或劫持dns导致的,请关闭劫持功能或者直接在科学插件中设置DNS劫持。

在Tailscale中添加本地DNS

进入Tailscale后台,进入DNS,点击Add nameserver - Custom,输入你内网DNS的IP地址,可以为Tailscale的100开头的地址,也可以是添加进Tailscale的子网地址,并开启Restrict to domain,填入需要劫持的顶级域名。(如填入mydomain.com,会劫持它的所有子域名)请注意,Tailscale不支持指定协议和端口,默认使用53端口、udp协议。

可能部分DNS服务默认拒绝外网请求,需要手动开启。以OpenWrt为例,需要在网络 - DHCP/DNS - 基本设置中取消勾选仅本地服务

结语

至此Tailscale和DERP服务器的配置就结束了,经过这一番折腾,我们实现了100%直连率,并统一了内网、Tailscale、ipv6的使用体验。在SVCB/HTTPS记录普及之前,对STUN穿透的折腾大约就止步如此了吧。

如果你仍对安全性抱有担忧,可以自行修改acl规则,默认拒绝共享账户访问子网,仅允许访问特定的ip和端口。如果你想让特定的设备不受用户权限的限制,可以给它打上tag,再对该tag单独设置权限。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容