tailscale derp中继服务简介
tailscale是一个基于WireGuard的零配置软件,它可以轻松地在多台设备之间建立点对点加密连接。
derp服务器是tailscale网络的重要组成部分。它作为tailscale客户端之间的中继,帮助客户端找到并连接到其他客户端设备。
但Tailscale 官方的服务端和 DERP 中继服务器全部在境外,在国内的网络环境中不一定能稳定连接,所以有必要建立自己的headscale服务端和 DERP 服务器。
准备工作:
- 需要有自己的云服务器,本示例为阿里云轻量应用服务器
- 需要有自己的域名,本示例为阿里云域名
- 云服务器已经安装 docker 运行环境
准备两个子域名,示例如下:
- derper.example.com
- headscale.example.com
DNS解析示例如下,需要将域名解析到云服务器公网IP地址:
以下所有操作在一台ubuntu 22.04 轻量云服务器进行配置。
创建docker网络
创建名为headscale的docker网络,用于不同容器直接通过名称互访。
docker network create headscale
部署tailscale客户端
在需要搭建 DERP Server 的服务器上, 首先安装一个 Tailscale 客户端,这样做的目的是让搭建的 DERP Server 开启客户端认证, 否则你的 DERP Server 可以被任何人白嫖.
为derper容器提供tailscale.sock套接字,用于后续部署derp时指定-v tailscale:/var/run/tailscale参数.
docker run -d --name tailscale \--restart always \-v tailscale:/var/run/tailscale \-v /var/lib:/var/lib \-v /dev/net/tun:/dev/net/tun \--network=host --privileged \tailscale/tailscale tailscaled
部署derp中继服务器
执行以下docker命令,部署derper中继服务器,
docker run -d --name derper \--restart always \-p 8443:8443 -p 3478:3478 \-e DERP_ADDR=:8443 \-e DERP_DOMAIN=derper.example.com \-e DERP_CERT_MODE=letsencrypt \-e DERP_VERIFY_CLIENTS=true \--net headscale \-v tailscale:/var/run/tailscale \docker.io/fredliang/derper:latest
参数说明:
- 3478 端口不要修改
- 8443 端口可以按照自己的喜好来改,DERP_ADDR 变量后面的端口需要与该端口保持一致,冒号不能丢
- DERP_VERIFY_CLIENTS=true,DERP 会验证连接的客户端是否与本机的客户端为同一个账号下,从而避免其他客户端白嫖服务器
- DERP_CERT_MODE=letsencrypt :使用letsencrypt 自动申请ssl证书
-v tailscale:/var/run/tailscale
将tailscale.sock套接字接口挂载进容器中
查看运行的容器
root@ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
445c5fc9e688 fredliang/derper:latest "/bin/sh -c '/app/de…" 6 hours ago Up 6 hours 0.0.0.0:3478->3478/tcp, :::3478->3478/tcp, 0.0.0.0:8443->8443/tcp, :::8443->8443/tcp derper
浏览器访问derper域名:https://derper.example.com
,显示以下内容,说明derp服务端运行正常:
部署headscale
创建headscale目录
mkdir -p /data/headscale/config
touch /data/headscale/config/db.sqlite
下载headscale配置文件
wget -O /data/headscale/config/config.yaml \https://raw.githubusercontent.com/juanfont/headscale/main/config-example.yaml
修改headscale配置文件,以下仅显示修改部分,其他保持默认
$ vim /data/headscale/config/config.yaml
server_url: https://headscale.example.com
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
private_key_path: /etc/headscale/private.key
noise:private_key_path: /etc/headscale/noise_private.key
derp:urls:# - https://controlplane.tailscale.com/derpmap/defaultpaths:- /etc/headscale/derp.yaml
dns_config:override_local_dns: truenameservers:- 223.5.5.5- 223.6.6.6
参数说明:
- derp.urls: 注释掉默认derp中继服务器地址
- derp.paths:使用paths指定自建derp服务器配置文件,注意为容器中的路径
创建derp配置文件
$ vim /data/headscale/config/derp.yaml
regions:900:regionid: 900regioncode: aliyunregionname: aliyund-derpnodes:- name: 900aregionid: 900hostname: derper.example.comstunport: 3478stunonly: falsederpport: 8443
配置说明:
- regions 是 YAML 中的对象,下面的每一个对象表示一个可用区,每个可用区里面可设置多个 DERP 节点,即 nodes。
- 每个可用区的 regionid 不能重复。
- 每个 node 的 name 不能重复。
- regionname 一般用来描述可用区,regioncode 一般设置成可用区的缩写。
- stunonly: false 表示除了使用 STUN 服务,还可以使用 DERP 服务。
部署headscale服务端
docker run -d --name headscale \--restart always \-p 8080:8080 -p 9090:9090 \--net headscale \-v /data/headscale/config:/etc/headscale \headscale/headscale:latest-alpine headscale serve
查看运行的容器
root@ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5a1ddc71318a headscale/headscale:latest-alpine "headscale serve" 5 hours ago Up 5 hours 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:9090->9090/tcp, :::9090->9090/tcp headscale
部署caddy-server
使用caddy用于访问headscale.example.com和deper.example.com时分别反向代理到后端http服务。
创建caddy配置文件目录
mkdir -p /data/caddy
创建caddy配置文件,由于在同一个docker 网络,caddy可直接通过容器名称访问headscale和derper后端。
cat >/data/caddy/Caddyfile<<EOF
https://headscale.example.com {reverse_proxy * http://headscale:8080
}
https://derper.example.com {reverse_proxy * http://derper:8443
}
EOF
部署caddy-server
docker run -d --name caddy \--restart always \-p 80:80 -p 443:443 \--net headscale \-v /data/caddy/Caddyfile:/etc/caddy/Caddyfile \docker.io/caddy/caddy:latest
headscale客户端注册
headscale服务端配置
创建一个命名空间:
docker exec headscale \headscale namespaces create defaultns
生成用于客户端注册的认证key,记录key用于后续客户端注册使用。
docker exec headscale \headscale --namespace defaultns preauthkeys create --reusable --expiration 24h
示例运行结果
root@ubuntu:~# docker exec headscale \
> headscale --namespace defaultns preauthkeys create --reusable --expiration 24h
90e20f91f2497c518144254b0fe66cc0619ae5571e8a2e5c
server端客户端注册
首先在本机将tailscale客户端注册到服务端
docker exec -it tailscale \tailscale up --accept-dns=false --accept-routes=true \--auth-key=90e20f91f2497c518144254b0fe66cc0619ae5571e8a2e5c \--force-reauth --login-server=https://headscale.example.com --reset
windows客户端注册
以下在远程windows机器执行,该机器可以位于home或公司。
1、安装tailscale windows客户端
2、浏览器访问以下链接,下载页面中的reg注册表文件并执行
https://headscale.example.com/windows
点击下载页面中的reg注册表文件并执行该文件。
3、注册客户端到headscale控制端
打开CMD命令行窗口,复制以下几行命令粘贴到CMD命令行窗口,并执行
tailscale up --accept-dns=false --accept-routes ^--login-server=http://headscale.example.com ^--auth-key=90e20f91f2497c518144254b0fe66cc0619ae5571e8a2e5c ^--force-reauth --unattended --reset ^--advertise-routes=192.168.12.0/24,192.168.13.0/24
关于选项设置:
- –login-server: 指定使用的headscale服务器地址(必填)
- –advertise-routes: 向headscale服务器报告当前客户端处于哪个内网网段下, 便于headscale服务器让同内网设备直接内网直连,或者将其他设备指定流量路由到当前内网(可选)
- –accept-routes: 是否接受headscale服务器下发的用于路由到其他客户端内网的路由规则(可选)
- –accept-dns: 是否使用headscale服务器下发的 DNS 相关配置(可选)
客户端开启IP转发:
搜索框中搜索注册表编辑器,展开注册表编辑器以下路径,将参数IPEnableRouter的值从0修改为1,然后关闭注册表编辑器并重新启动系统。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
4、headscale控制端查看注册的节点列表
docker exec -it headscale headscale nodes list
示例运行结果
root@ubuntu:~# docker exec -it headscale headscale nodes list
ID | Hostname | Name | NodeKey | Namespace | IP addresses | Ephemeral | Last seen | Online | Expired
1 | ubuntu | ubuntu | [PpOKS] | defaultns | 100.64.0.1, fd7a:115c:a1e0::1 | false | 2023-10-08 16:35:50 | online | no
2 | winpc-laptop | winpc-laptop | [qMO6V] | defaultns | 10.64.0.2, fd7a:115c:a1e0::2 | false | 2023-10-08 10:41:21 | online| no
3 | winpc | willpc | [6CjhI] | defaultns | 100.64.0.3, fd7a:115c:a1e0::3 | false | 2023-10-08 16:35:50 | online | no
如果需要删除节点执行以下命令,其中2为nodes list显示的节点ID
headscale nodes delete -i 2
5、server端查看客户端发布的subnet
/ # headscale nodes routes list -i 2
Route | Enabled
192.168.12.0/24 | false
192.168.13.0/24 | false
server端启用客户端发布的subnet,这样所有子网接入tailscale网络并能够全部互通。
/ # headscale nodes routes enable -i 2 -r 192.168.12.0/24,192.168.13.0/24
Route | Enabled
192.168.12.0/24 | true
192.168.13.0/24 | true
网络连通性测试
所有客户端按照以上示例注册到headscale-server,并发布本地子网网段后,下图任意网络环境的子网IP可以直接互相通信。
例如从172.16.1.1所在机器测试ping 192.168.12.1。
derp中继测试
tailscale ping 命令
tailscale ping 命令可以用于测试 IP 连通性, 同时可以看到是如何连接目标节点的. 默认情况下 Ping 命令首先会使用 Derper 中继节点通信, 然后尝试 P2P 连接; 一旦 P2P 连接成功则自动停止Ping.
由于其先走 Derper 的特性也可以用来测试 Derper 连通性.
C:\Users\wiinpc>tailscale ping 192.168.12.16
pong from winpc (fd7a:115c:a1e0::2) via DERP(aliyun) in 49ms
pong from winpc (fd7a:115c:a1e0::2) via DERP(aliyun) in 117ms
pong from winpc (fd7a:115c:a1e0::2) via DERP(aliyun) in 46ms
pong from winpc (fd7a:115c:a1e0::2) via DERP(aliyun) in 38ms
pong from winpc (fd7a:115c:a1e0::2) via DERP(aliyun) in 80ms
pong from winpc (fd7a:115c:a1e0::2) via DERP(aliyun) in 42ms
pong from winpc (fd7a:115c:a1e0::2) via DERP(aliyun) in 163ms
pong from winpc (fd7a:115c:a1e0::2) via DERP(aliyun) in 68ms
pong from winpc (fd7a:115c:a1e0::2) via DERP(aliyun) in 41ms
pong from winpc (fd7a:115c:a1e0::2) via DERP(aliyun) in 255ms
direct connection not established
tailscale status 命令
通过 tailscale status 命令可以查看当前节点与其他对等节点的连接方式, 通过此命令可以查看到当前节点可连接的节点以及是否走了 Derper 中继:
C:\Users\winpc>tailscale status
fd7a:115c:a1e0::1 win-laptop defaultns windows -
fd7a:115c:a1e0::2 winpc defaultns windows active; relay "aliyun", tx 45680 rx 49464
tailscale netcheck 命令
有些情况下我们可以确认是当前主机的网络问题导致没法走 P2P 连接, 但是我们又想了解一下当前的网络环境; 此时可以使用 tailscale netcheck 命令来检测当前的网络环境, 此命令将会打印出详细的网络环境报告:
C:\Users\winpc>tailscale netcheckReport:* UDP: false* IPv4: (no addr found)* IPv6: no, but OS has support* MappingVariesByDestIP:* HairPinning:* PortMapping:* CaptivePortal: true* Nearest DERP: aliyund-derp* DERP latency:- aliyun: 126.3ms (aliyund-derp)