Tailscale是一款构建在Wireguard之上的现代VPN,Tailscale中的大部分内容都是开源的,但是客户端以及控制服务器不开源,Headscale是Tailscale控制服务器的开源替代方案。
DERP中继服务器是后备方案,当NAT打洞无法成功的时候转而使用DERP服务器进行中继连接。虽然Tailscale提供了很多官方的DERP中继服务器,但往往延迟都非常高体验不好,所以就有了自建的必要。
系统我使用的是Debian12,可在Headscale项目页面直接下载deb包进行安装:
apt -y update apt -y install wget wget https://github.com/juanfont/headscale/releases/download/v0.22.3/headscale_0.22.3_linux_amd64.deb dpkg -i headscale_0.22.3_linux_amd64.deb systemctl enable headscale
由于我的这台机器还跑着其他的服务,所以我将配置Headscale在反向代理后面运行,这样可以重用443端口不会影响到机器上其他的服务。安装NGINX/CertBot:
apt -y install nginx python3-certbot-nginx
编辑Headscale的配置文件:
nano /etc/headscale/config.yaml
需要修改的配置如下,其他的内容暂时不用管:
server_url: https://headscale.example.com # 修改为你的域名 listen_addr: 0.0.0.0:8080 metrics_listen_addr: 0.0.0.0:9090
启动Headscale并检查运行状态:
systemctl start headscale
systemctl status headscale
新建NGINX站点配置文件:
nano /etc/nginx/sites-available/headscale
写入如下配置:
map $http_upgrade $connection_upgrade { default keep-alive; 'websocket' upgrade; '' close; } server { listen 80; server_name headscale.example.com; # 修改为你的域名 location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $server_name; proxy_redirect http:// https://; proxy_buffering off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; } error_log /var/log/nginx/headscale-proxy-error.log; access_log /var/log/nginx/headscale-proxy-access.log; }
启用站点:
ln -s /etc/nginx/sites-available/headscale /etc/nginx/sites-enabled/headscale
签发SSL证书:
certbot --nginx
首先需要在Headscale控制服务器创建一个用户:
headscale users create imlala
然后在要接入Headscale网络的机器上安装Tailscale客户端,这里我用一台Windows10和iPhone演示。
Windows客户端下载:https://pkgs.tailscale.com/stable/tailscale-setup-latest.exe
其他平台的客户端下载:https://tailscale.com/download/
安装好客户端后用管理员权限打开PowerShell,执行如下命令登录到我们自建的Headscale:
tailscale login --login-server https://headscale.example.com
接下来在Headscale控制服务器上注册我这台Windows10的机器:
headscale nodes register --user imlala --key nodekey:xxxxx
这样我就将一台Windows10机器加入到了网络内,使用如下命令可检查:
headscale nodes list
在iPhone上安装好Tailscale客户端后,打开设置-找到Tailscale,在ALTERNATE COORDINATION SERVER URL这里填写上你自建的Headscale控制服务器网址:
之后的步骤就和在Windows上的一致了,打开APP登录会回显给你一个注册命令,在Headscale控制服务器上执行给出的命令即可完成注册。
部署DERP中继服务器我使用的系统是Debian12,机器是一台甲骨文ARM。
首先要在这台机器上安装Tailscale客户端,添加Tailscale官方的存储库安装即可,此举是为了后续能启用DERP服务的鉴权功能,防止被其他人滥用:
wget https://pkgs.tailscale.com/stable/debian/bookworm.noarmor.gpg -O /usr/share/keyrings/tailscale-archive-keyring.gpg wget https://pkgs.tailscale.com/stable/debian/bookworm.tailscale-keyring.list -O /etc/apt/sources.list.d/tailscale.list apt -y update apt -y install tailscale
确保tailscaled服务正常运行:
systemctl status tailscaled.service
登录到我们自建的Headscale控制服务器:
tailscale up --login-server https://headscale.example.com
在Headscale控制服务器上注册我这台甲骨文ARM的机器:
headscale nodes register --user imlala --key nodekey:xxxxx
安装Golang:
curl -L https://go.dev/dl/go1.21.1.linux-arm64.tar.gz -o go1.21.1.linux-arm64.tar.gz tar -C /usr/local -xzf go1.21.1.linux-arm64.tar.gz echo 'export PATH=$PATH:/usr/local/go/bin' > /etc/profile.d/golang.sh source /etc/profile.d/golang.sh
新建一个derp用户登录到这个用户:
useradd -r -m -d /opt/derp -s /bin/bash derp su - derp
安装DERP,完成之后退出当前用户:
go install tailscale.com/cmd/derper@main exit
[可选]让DERP服务可以绑定低位端口,例如80、443,由于后续我将使用反向代理所以这个步骤可以省略:
setcap 'cap_net_bind_service=+ep' /opt/derp/go/bin/derper
[可选]做一个软链接方便使用:
ln -s /opt/derp/go/bin/derper /usr/local/bin/derper
新建systemd服务:
nano /etc/systemd/system/derper.service
写入如下配置,你只需要将derp.example.com修改成你自己的域名即可:
[Unit] Description=DERP Server After=network.target [Service] User=derp Group=derp AmbientCapabilities=CAP_NET_BIND_SERVICE WorkingDirectory=/opt/derp ExecStart=/opt/derp/go/bin/derper -hostname=derp.example.com -c /opt/derp/derper.conf -a 0.0.0.0:9981 -http-port -1 --verify-clients Restart=on-failure LimitNOFILE=65536 [Install] WantedBy=multi-user.target
[重要]–verify-clients参数务必要保留,鉴权需要,否则任何人都能连接上你的DERP服务。
启动DERP服务并设置开机自启:
systemctl enable --now derper.service
检查运行状态确保正常运行:
systemctl status derper.service
安装NGINX/CertBot用于反向代理:
apt -y install nginx python3-certbot-nginx
新建NGINX站点配置文件:
nano /etc/nginx/sites-available/derper
写入如下配置:
server { listen 80; server_name derp.example.com; location / { proxy_pass http://127.0.0.1:9981; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } error_log /var/log/nginx/derp-proxy-error.log; access_log /var/log/nginx/derp-proxy-access.log; }
启用站点:
ln -s /etc/nginx/sites-available/derper /etc/nginx/sites-enabled/derper
签发SSL证书:
certbot --nginx
访问DERP服务的域名,如果能看到下图的内容说明DERP服务正常运行:
回到Headscale控制服务器,新建一个DERP服务配置文件:
nano /etc/headscale/derp.yaml
写入如下内容,注意derp.example.com修改为你自己的域名:
regions: 900: regionid: 900 regioncode: kr regionname: oraclekr nodes: - name: 900a regionid: 900 hostname: derp.example.com stunport: 3478 stunonly: false derpport: 443
编辑Headscale控制服务器的配置文件:
nano /etc/headscale/config.yaml
注释掉如下URL以禁用Tailscale官方的DERP服务器,指定刚才新建的DERP服务配置文件:
derp: server: enabled: false ... urls: [] # - https://controlplane.tailscale.com/derpmap/default ... paths: - /etc/headscale/derp.yaml ...
重启Headscale:
systemctl restart headscale
在Windows客户端执行如下命令查看当前的网络状态:
tailscale netcheck
可以看到DERP服务器列表里面只有我们自建的服务器:
如果两台设备之间通过DERP服务器中继连接,那么也可以执行下面的命令查看连接状态:
tailscale status
或者直接使用内置的PING命令:
tailscale ping iphone
这样最直观:
你可以将接入到Headscale网络内的任意节点(设备)设置为Exit Nodes(出口节点)。
这有什么用呢?打个最简单的比方,假设你的Headscale网络内接入了一台境外的VPS,你把这台境外的VPS设置为Exit Nodes,之后你所有接入到Headscale网络内的节点(设备)都可以直接翻墙。
也就是说如果我把自己的这台甲骨文ARM设置为Exit Nodes,那么我之前接入的Windows10、iPhone等设备就可以通过这台甲骨文ARM来翻墙了。下面简单演示一下。
设置Exit Nodes的机器要开启IP转发:
echo 'net.ipv4.ip_forward = 1' | tee -a /etc/sysctl.d/99-tailscale.conf echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.d/99-tailscale.conf sysctl -p /etc/sysctl.d/99-tailscale.conf
宣告自己想成为Exit Nodes:
tailscale set --advertise-exit-node
回到Headscale控制服务器,执行如下命令:
headscale routes list
可以看到有两条路由但还没有启用:
ID | Machine | Prefix | Advertised | Enabled | Primary 1 | moonbridge | ::/0 | true | false | - 2 | moonbridge | 0.0.0.0/0 | true | false | -
再通过执行如下命令来启用这两条路由:
headscale routes enable -r 1 headscale routes enable -r 2
再次查看路由就是启用的状态了:
ID | Machine | Prefix | Advertised | Enabled | Primary 1 | moonbridge | ::/0 | true | true | - 2 | moonbridge | 0.0.0.0/0 | true | true | -
现在我们就可以配置客户端来使用这个出口节点了,在Windows的Tailscale客户端,找到Exit Node选项:
在这里就可以选择使用出口节点了:
iPhone的客户端更简单: