赞
踩
tailscale是一个基于WireGuard的零配置软件,它可以轻松地在多台设备之间建立点对点加密连接。
derp服务器是tailscale网络的重要组成部分。它作为tailscale客户端之间的中继,帮助客户端找到并连接到其他客户端设备。
但Tailscale 官方的服务端和 DERP 中继服务器全部在境外,在国内的网络环境中不一定能稳定连接,所以有必要建立自己的headscale服务端和 DERP 服务器。
准备工作:
准备两个子域名,示例如下:
DNS解析示例如下,需要将域名解析到云服务器公网IP地址:
以下所有操作在一台ubuntu 22.04 轻量云服务器进行配置。
创建名为headscale的docker网络,用于不同容器直接通过名称互访。
docker network create headscale
在需要搭建 DERP Server 的服务器上, 首先安装一个 Tailscale 客户端,这样做的目的是让搭建的 DERP Server 开启客户端认证, 否则你的 DERP Server 可以被任何人白嫖.
为derper容器提供tailscale.sock套接字,用于后续部署derp时指定-v tailscale:/var/run/tailscale参数.
docker run -d --name tailscaled \
--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
执行以下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
参数说明:
-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目录
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/default paths: - /etc/headscale/derp.yaml dns_config: override_local_dns: true nameservers: - 223.5.5.5 - 223.6.6.6 db_type: sqlite3 db_path: /etc/headscale/db.sqlite
参数说明:
创建derp配置文件
$ vim /data/headscale/config/derp.yaml
regions:
900:
regionid: 900
regioncode: aliyun
regionname: aliyund-derp
nodes:
- name: 900a
regionid: 900
hostname: derper.example.com
stunport: 3478
stunonly: false
derpport: 8443
配置说明:
部署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用于访问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
使用traefik+docker-compose
的示例
version: '3.9' services: tailscaled: container_name: tailscaled image: docker.io/tailscale/tailscale:v1.50.1 restart: unless-stopped command: tailscaled network_mode: "host" # Resolve the conflict between aliyun ECS DNS SERVER IP subnet and tailscale subnet 100.64.0.0/10 environment: - TS_EXTRA_ARGS="--netfilter-mod=off" volumes: - /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro - /var/lib:/var/lib - /dev/net/tun:/dev/net/tun - tailscale-sock:/var/run/tailscale cap_add: - NET_ADMIN - NET_RAW derper: container_name: derper image: docker.io/fredliang/derper:latest restart: unless-stopped ports: - "8443:8443" - "3478:3478" environment: - DERP_DOMAIN=derper.example.com - DERP_CERT_DIR=/app/certs - DERP_CERT_MODE=letsencrypt - DERP_ADDR=:8443 - DERP_STUN=true - DERP_HTTP_PORT=-1 - DERP_VERIFY_CLIENTS=true volumes: - /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro - tailscale-sock:/var/run/tailscale networks: - headscale depends_on: - tailscaled labels: - "traefik.enable=true" - "traefik.http.routers.derper.rule=Host(`derper.example.com`)" - "traefik.http.routers.derper.service=derper" - "traefik.http.routers.derper.entrypoints=websecure" - "traefik.http.routers.derper.tls.certresolver=myresolver" - "traefik.http.services.derper.loadbalancer.server.port=8443" headscale: container_name: headscale image: docker.io/headscale/headscale:latest command: headscale serve restart: unless-stopped ports: - "8080:8080" - "9090:9090" volumes: - "/usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro" - "/data/headscale/config:/etc/headscale" networks: - headscale depends_on: - derper labels: - "traefik.enable=true" - "traefik.http.routers.headscale.rule=Host(`headscale.example.com`)" - "traefik.http.routers.headscale.service=headscale" - "traefik.http.routers.headscale.entrypoints=websecure" - "traefik.http.routers.headscale.tls.certresolver=myresolver" - "traefik.http.services.headscale.loadbalancer.server.port=8080" traefik: image: docker.io/library/traefik:v3.0 container_name: traefik restart: unless-stopped command: - "--log.level=INFO" - "--api.dashboard=true" - "--api.insecure=false" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" # redirect-to-https - "--entryPoints.web.address=:80" - "--entrypoints.web.http.redirections.entryPoint.to=websecure" - "--entrypoints.web.http.redirections.entryPoint.scheme=https" - "--entrypoints.web.http.redirections.entrypoint.permanent=true" # letsencrypt - "--entryPoints.websecure.address=:443" - "--certificatesresolvers.myresolver.acme.tlschallenge=true" - "--certificatesresolvers.myresolver.acme.email=<your-email@example.com>" - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" labels: # dashboard with https - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.service=dashboard@internal" - "traefik.http.routers.api.rule=Host(`traefik.example.com`) && PathPrefix(`/api`)" - "traefik.http.routers.api.service=api@internal" - "traefik.http.routers.dashboard.tls=true" - "traefik.http.routers.dashboard.tls.certresolver=myresolver" - "traefik.http.routers.api.tls=true" - "traefik.http.routers.api.tls.certresolver=myresolver" - "traefik.http.services.dashboard.loadbalancer.server.port=8080" # basic auth - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$05$$Yr3eeJUuuKy6TTlexampleTCQReGNy" ports: - "80:80" - "443:443" - "8081:8080" volumes: - "/data/headscale/traefik-letsencrypt:/letsencrypt" - "/var/run/docker.sock:/var/run/docker.sock:ro" networks: - headscale depends_on: - derper - headscale networks: headscale: volumes: tailscale-sock:
说明:使用以下方式生成traefik admin密码
apt install -y apache2-utils
echo $(htpasswd -nbB USER "PASS") | sed -e s/\\$/\\$\\$/g
创建一个命名空间:
docker exec headscale \
headscale user create default
生成用于客户端注册的认证key,记录key用于后续客户端注册使用。
docker exec headscale \
headscale preauthkeys create --user default --reusable --expiration 24h
示例运行结果
root@ubuntu:~# docker exec headscale \
> headscale preauthkeys create --user default --reusable --expiration 24h
90e20f91f2497c518144254b0fe66cc0619ae5571e8a2e5c
首先在本机将tailscale客户端注册到服务端
docker exec -it tailscaled \
tailscale up --accept-dns=false --accept-routes=true \
--auth-key=90e20f91f2497c518144254b0fe66cc0619ae5571e8a2e5c \
--force-reauth --login-server=https://headscale.example.com --reset
以下在远程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
关于选项设置:
客户端开启IP转发:
搜索框中搜索注册表编辑器,展开注册表编辑器以下路径,将参数IPEnableRouter的值从0修改为1,然后关闭注册表编辑器并重新启动系统。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
4、headscale控制端查看注册的节点列表
root@ubuntu:~# docker exec -it headscale bash
root@a9ce9b39f64d:/# headscale nodes list
示例运行结果
root@a9ce9b39f64d:/# 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
root@a9ce9b39f64d:/# headscale routes list
ID | Machine | Prefix | Advertised | Enabled | Primary
3 | winpc | 192.168.12.0/24 | true | true | true
4 | win-laptop | 192.168.13.0/24 | true | false | false
5 | winpc | 192.168.90.0/24 | true | false | false
6 | ubuntu | 172.17.0.0/18 | true | true | true
server端启用客户端发布的subnet,这样所有子网接入tailscale网络并能够全部互通。
root@a9ce9b39f64d:/# headscale routes enable -r 3
所有客户端按照以上示例注册到headscale-server,并发布本地子网网段后,下图任意网络环境的子网IP可以直接互相通信。
例如从172.16.1.1所在机器测试ping 192.168.12.1。
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 命令可以查看当前节点与其他对等节点的连接方式, 通过此命令可以查看到当前节点可连接的节点以及是否走了 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
有些情况下我们可以确认是当前主机的网络问题导致没法走 P2P 连接, 但是我们又想了解一下当前的网络环境; 此时可以使用 tailscale netcheck 命令来检测当前的网络环境, 此命令将会打印出详细的网络环境报告:
C:\Users\winpc>tailscale netcheck
Report:
* 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)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。