Headscale搭建-前端、服务、自定义derp

WangZeyu Lv1

目的:在日常的办公使用中尤其是软件开发的一些情况,经常会遇到同步代码服务器在公司,不对外网公开的一些状况;或者使用的一些使用公司内部文件在内部服务器上,在外网无法访问。需要与内网服务器进行组网,目前可用的有openvpn、frp、wiregurd、tailscale等工具可以使用。经过考虑使用tailscale进行组网,考虑到速度及传输问题,使用开源控制工具headscale作为控制端搭建,使用官网的derper工具搭建个人derp。只介绍操作及踩坑,无各个软件说明

1 Headscale搭建

1.1 程序获取

自己编译

headscale的github仓库下载源码,自己下载golang进行编译,具体编译过程再次就不写,若只想部署不要选择改方法

下载现成的二进制程序

直接从headscale的官方github仓库下载编译好的headscale二进制程序,选择合适的版本下载。

1.2 部署

添加执行权限

介绍采用的是程序直接部署,没有使用docker的方式部署,部署在linux服务器上,主要原因headplane只能在linux上运行云服务器为linux系统

以0.27.1版本为例进行介绍

获得headscale的二进制文件headscale_0.27.1_linux_amd64后执行以下命令,

1
2
sudo cp headscale_0.27.1_linux_amd64 /usr/local/bin/headscale
sudo chmod +x /usr/local/bin/headscale

配置文件

创建配置目录

1
$ mkdir -p /etc/headscale

路径 /etc/headscle/config.yaml

主要修改的几项配置

server_url修改为公网ip或者域名,中国大陆访问域名必须备案,访问地址listen_addr前面加上http://

listen_addr 监听地址若不使用域名需要改为 0.0.0.0:port

建议开启随机客户端端口,将 randomize_client_port 设为 true

prefixes.v4 根据使用的主机数量进行调整子网掩码原始值 为100.64.0.0/10 , # Tailscale/Headscale 默认使用的 CGNAT 地址空间一部分 使用的的类似于中国移动宽带的NAT网段 ,设置的ip必须在100.64.0.0/10的网段内,具体的可以在https://ipjisuanqi.com/网站上计算一下

image-20260126160405120

dna.magic_dns 个人建议为false 不适用虚拟的域名直接访问, 简单解释1一下,若主机名xxxx1, base_domain为example.com,则其他客户端可以通过xxxx1.example.com访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
---
server_url: https://xxxxxx.xxxxx.xxxx
listen_addr: 127.0.0.1:16888
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: true
noise:
private_key_path: /var/lib/headscale/noise_private.key
prefixes:
v4: 100.111.0.0/23
v6: fd7a:115c:a1e0::/48
allocation: sequential
derp:
server:
enabled: false
region_id: 999
region_code: "headscale"
region_name: "Headscale Embedded DERP"
verify_clients: true
stun_listen_addr: "0.0.0.0:3478"
private_key_path: /var/lib/headscale/derp_server_private.key
automatically_add_embedded_derp_region: true
ipv4: 1.2.3.4
ipv6: 2001:db8::1

urls: []
- https://controlplane.tailscale.com/derpmap/default

#paths:
#- /etc/headscale/derp.yaml
auto_update_enabled: true
update_frequency: 24h
disable_check_updates: false
ephemeral_node_inactivity_timeout: 30m

database:
type: sqlite
debug: false
gorm:
prepare_stmt: true
parameterized_queries: true
skip_err_record_not_found: true
slow_threshold: 1000
sqlite:
path: /var/lib/headscale/db.sqlite
write_ahead_log: true
wal_autocheckpoint: 1000
acme_url: https://acme-v02.api.letsencrypt.org/directory
acme_email: ""
tls_letsencrypt_hostname: ""
tls_letsencrypt_cache_dir: /var/lib/headscale/cache
tls_letsencrypt_challenge_type: HTTP-01
tls_letsencrypt_listen: ":http"
tls_cert_path: ""
tls_key_path: ""

log:

level: info
format: text
policy:
mode: database
path: ""
dns:
magic_dns: false
base_domain: example.com
override_local_dns: true

nameservers:
global:
- 1.1.1.1
- 1.0.0.1
- 2606:4700:4700::1111
- 2606:4700:4700::1001
split: {}
search_domains: []
extra_records: []
unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
logtail:
enabled: false
randomize_client_port: false
taildrop:
enabled: true

创建文件夹用于存储数据和证书

1
$ mkdir -p /var/lib/headscale

创建空的 SQLite 数据库文件:

1
$ touch /var/lib/headscale/db.sqlite

踩坑点

  • 若想使用https千万不要自签名证书,目前tailscale客户端对于自签名证书无法链接。若要使用需要导入ca证书到系统中为可信任,本人没试过

系统服务文件

路径/etc/systemd/system/headscale.service

下面文件是拿官方仓库提供的进行修改的文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
[Unit]
After=network.target
Description=headscale coordination server for Tailscale
X-Restart-Triggers=/etc/headscale/config.yaml

[Service]
Type=simple
User=headscale
Group=headscale
ExecStart=/usr/local/bin/headscale serve
ExecReload=/usr/bin/kill -HUP $MAINPID
Restart=always
RestartSec=5

WorkingDirectory=/var/lib/headscale
ReadWritePaths=/var/lib/headscale

AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_CHOWN
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_CHOWN
LockPersonality=true
NoNewPrivileges=true
PrivateDevices=true
PrivateMounts=true
PrivateTmp=true
ProcSubset=pid
ProtectClock=true
ProtectControlGroups=true
ProtectHome=true
ProtectHostname=true
ProtectKernelLogs=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectProc=invisible
ProtectSystem=strict
RemoveIPC=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
RuntimeDirectory=headscale
RuntimeDirectoryMode=0750
StateDirectory=headscale
StateDirectoryMode=0750
SystemCallArchitectures=native
SystemCallFilter=@chown
SystemCallFilter=@system-service
SystemCallFilter=~@privileged
UMask=0077

[Install]
WantedBy=multi-user.target

启动headscale

创建 headscale 用户:用以上服务文件必须创建用户

1
$ useradd headscale -d /home/headscale -m

修改 /var/lib/headscale 目录的属主:

1
$ chown -R headscale:headscale /var/lib/headscale

修改配置文件/etc/headscale/config.yaml中的unix_socket` 路径:

1
unix_socket: /var/run/headscale/headscale.sock

Reload SystemD 以加载新的配置文件:

1
$ systemctl daemon-reload

启动 Headscale 服务并设置开机自启:

1
$ systemctl enable --now headscale

查看运行状态:

1
$ systemctl status headscale

查看 Headscale 占用的端口(默认为 8080 HTTP, 9090 gRPC, 50443 Prometheus metrics,具体取决于您的配置):

1
2
3
4
$ ss -tulnp | grep headscale
# 预期输出可能类似:
# tcp LISTEN 0 1024 *:8080 *:* users:(("headscale",pid=...,fd=...))
# tcp LISTEN 0 1024 *:9090 *:* users:(("headscale",pid=...,fd=...))

headscale 相关命令

创建用户

1
2
$ headscale users create default 
# 成功后会提示 User created 用户名为default
1
2
$ headscale users create test -d testA -e aaa@xxx.com
#-d 展示名称,-e用户邮箱 此两项可不加

2 Tailscale接入Headscale

目前主流系统均支持接入headscale,手头只有linux、windows、安装、iPhone,只对这四种进行了测试

登陆坑点

命令行登陆注意 --user USERID填写的是用户id

2.1 linux系统接入

直接下载官方的的tailscale二进制文件,或者配置好官方的软件包仓库后直接用管理工具安装本文用管理工具安装

具体的配置操作见官方https://tailscale.com/download/linux

命令行安装

image-20260126163430283

管理库安装选择合适的版本后按照步骤操作即可

image-20260126163517864

安装完成后直接 启动并设置服务开机自启

1
$ systemctl start tailscaled && systemctl enable tailscaled

链接命令

1
2
# 在自己的服务器上部署的 Headscale,请将 <HEADSCALE_PUB_ENDPOINT> 替换为您的 Headscale 公网 IP 或域名,并注意协议 (http/https) 和端口
$ sudo tailscale up --login-server=http://<HEADSCALE_PUB_ENDPOINT>:8080 --accept-routes=true --accept-dns=false

这里推荐将 --accept-dns=false 选项加上,以避免 Headscale 的 MagicDNS 设置覆盖系统默认 DNS,除非您确实需要并已正确配置了 Headscale 的 DNS 功能。执行完上面的 tailscale up 命令后,终端会显示一个注册链接:

1
2
To authenticate, visit:
https://headscale-rewcdzwp.sealoshzh.site/register/xxxxxxxxxxxxxxxxxxxxxxxxxx

浏览器访问后会让在服务器上执行一条命令 执行完毕即可连接成功

image-20260126164048160

2.2 安卓机接入使用的为1.92.3版本

可以找网上其他人发的apk安装包,大陆境内应用商店没有

点击右上角的人物

image-20260126164553334

点击Acount

image-20260126164701508

image-20260126164921205

输入服务器地址即可

image-20260126164938843

点击 Add account后会弹出浏览器显示内容如下 ,也是需要在服务器运行指令

image-20260126165048681

成功后返回tailscale即可看到类似下面的页面

image-20260126165350456

2.3 windows接入

安装坑点

安装的时候可能会安装失败,在其日志中找到一个含.msi的链接直接复制到浏览器下载 msi格式的为真正的安装程序。

接入方式

打开 windows终端直接运行(直接运行原因,tailscale不改变安装路径的时候会把执行的路径自动加入环境变量)

1
tailscale up --login-server=http://<HEADSCALE_PUB_ENDPOINT>:8080 --accept-routes=true --accept-dns=false

同样会在终端窗口展示一个链接,复制到浏览器访问后即可看到需要在服务器执行的命令

2.4 IOS

ios下载需要一个非中国大陆的icloudid

安装完毕按照下图操作即可,其余步骤和安卓相同

image-20260126170152744

image-20260126170207826

image-20260126170225494

2.5 headplan允许的方式

点击Add device 选择Register Machine Key

image-20260127084303102

image-20260127084354216

在弹出的界面输入网页弹出页面中 –key后面的所有内容,注意去掉首尾空格,选择owner之后点击Confirm即可

image-20260126165048681

2.6 预授权接入的方式

获得密钥

使用以下命令为用户id为1的用户创建一个有效期1小时的预授权密钥

1
$ headscale preauthkeys create -u 1 -e 1h

headplane获取预授权密钥

登陆后点击Add Device Generate Pre-auth Key

image-20260127091045705

image-20260127091257019

根据需求选择用户及时间

Reuseable为密钥是否可以重复使用

Ephemeral为客户端登录后在登出就会被移除设备,在登陆需要重新认证

image-20260127091423110

linux和windows

获得密钥后在原来的登陆命令后拼接上一个空格在拼接(linux和windows)

1
--authkey=获得的密钥

则登陆命名就变为 注意相关信息替换成自己的。

1
$ tailscale up --login-server=http://<HEADSCALE_PUB_ENDPOINT>:8080 --accept-routes=true --accept-dns=false --authkey=获得的密钥

ios和安卓

在输入自定义服务器后不要管弹出的网页关掉,返回tailscale,按找之前步骤找到如下界面即可点击 Use an auth key

image-20260127083952178

把获得的authkey填写点击Add account即可

image-20260127084119104

3 headplane 安装

headplane 为headscale的管理前端

个人使用起来比headscale-admin、headscale-ui更为方便、headscale-admin 编译后有bug需要调整源码重新编译使用,再此只介绍headplane

headplane 有两种运行方式 一种是docker运行一种是编译后运行

两种运行方式选择

若是比较新的系统则可以直接选择编译运行的方式,前提是GCC版本要大于2.17,也可以使用docker 运行,国内下载镜像速度慢酌情考虑docker

若为centos7 等比较古早的版本无法直接编译运行 需要使用docker 容器运行

不想使用官方的 固定访问路径/admin ,需要自己编译或者自己打包docker 镜像

修改访问路径

在项目根目录下找到react-router.config.ts vite.config.ts``vitest.config.ts三个文件把里面的 /admin 修改为 /你想要的名称

配置文件运行宿主机上

路径/etc/headplane/config.yaml

需要修改的配置headscale.url headscale.config_path 按照实际情况配置server.cookie_secure 该配置若无ssl需要配置为false 否则无法正常登陆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Configuration for the Headplane server and web application
server:
host: "0.0.0.0"
port: 3000
base_url: "http://localhost:3000"
cookie_secret: "<change_me_to_something_secure!>"
cookie_secure: true
cookie_max_age: 86400 # 1 day in seconds
data_path: "/var/lib/headplane"

headscale:
url: "https://XXXX.XXX.XX.XX"
config_path: "/etc/headscale/config.yaml"
config_strict: true
integration:
agent:
enabled: false
pre_authkey: "<your-preauth-key>"
docker:
enabled: false
container_label: "me.tale.headplane.target=headscale"
socket: "unix:///var/run/docker.sock"

kubernetes:
enabled: false
validate_manifest: true

pod_name: "headscale"

proc:
enabled: false

3.1 docker运行

自己打包镜像

从官方headplaned的github仓库克隆下主线代码

进行docker构建 前提(已经安装完golang和nodejs及pnpm)

先修改Dockerfile文件 添加golang的国内镜像

1
2
3
4
FROM --platform=$BUILDPLATFORM golang:1.25.1 AS go-base
ENV GOPROXY=https://goproxy.cn,direct #添加
ENV GOSUMDB=sum.golang.google.cn #添加

进入克隆下的项目根目录 构建镜像

1
$ docker build --build-arg IMAGE_TAG=0.6.1  -t headplane-custom:0.6.1 .

确认:

1
$ docker images | grep headplane

导出为 tar 包: 文件很大可以自己压缩,本人懒得压缩(该步骤针对于服务器GCC版本低无法在服务器上构建镜像)

1
$ docker save headplane-custom:0.6.1 -o headplane-custom-0.6.1.tar

把文件拷贝到服务器上(该步骤针对于服务器GCC版本低无法在服务器上构建镜像)

目标机器导入镜像

1
$ docker load -i headplane-custom-0.6.1.tar

验证:

1
$ docker images | grep headplane

该种方式的的compose 文件为

1
2
3
4
5
6
7
8
9
10
11
12
services:
headplane:
image: headplane-custom:0.6.1
container_name: headplane1
restart: unless-stopped
ports:
- '3000:3000'
volumes:
- '/etc/headplane/config1.yaml:/etc/headplane/config.yaml:ro'
- '/var/lib/headplane-data:/var/lib/headplane'
- '/etc/headscale/config.yaml:/etc/headscale/config.yaml:ro'

官方镜像

用 Docker 运行 Headplane 非常简单,只需应用一个 compose 文件:

1
2
3
4
5
6
7
8
9
10
11
services:
headplane:
image: ghcr.io/tale/headplane:latest
container_name: headplane
restart: unless-stopped
ports:
- '3000:3000'
volumes:
- '/etc/headplane/config1.yaml:/etc/headplane/config.yaml:ro'
- '/var/lib/headplane-data:/var/lib/headplane'
- '/etc/headscale/config.yaml:/etc/headscale/config.yaml:ro'

直接使用运行即可 file.yaml替换成自己compse文件名

1
$ docker compse -f file.yaml up -d

注意把docker切换成国内的源

3.2 自己编译运行

默认nodejs相关环境安装完毕

1
2
3
4
$ git clone https://github.com/tale/headplane.git
$ cd headplane
$ pnpm install
$ pnpm build

配置service文件

路径/etc/systemd/system/headplane.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[Unit]
Description=Headplane Service
After=network.target # (or headscale.service if it runs via systemd)
Requires=network.target # (or headscale.service if it runs via systemd)
StartLimitIntervalSec=0

[Service]
Type=simple
User=your-username
WorkingDirectory=/path/to/your/cloned/headplane #headplane项目根目录
ExecStart=/usr/bin/node /path/to/your/cloned/headplane/build/server/index.js #自己替换路径
Restart=on-failure
RestartSec=5s

# Uncomment and set if using a custom config path
# Environment=HEADPLANE_CONFIG_PATH=/path/to/your/config.yaml

[Install]
WantedBy=multi-user.target

运行指令

1
2
$ systemctl daemon-reload
$ systemctl start headplane && systemctl enable headplane

3.3 headplane登陆管理控制台

在浏览器中输入地址http://你的域名:你的端口/你编译headplane时修改的名或者官方用的用admin,如若启用ssl则需要使用https://

根据提示使用

1
$ headscale apikeys create

创建密钥,密钥有效期默认90天 输入后点击signin即可

image-20260127082319744

登陆成功的页面,右上角用户那点击会显示剩余密钥可用时间。

image-20260127082921626

4 certbot构建证书配置ssl https 访问

前提安装完成nginx,有一个备案的域名 或 可用域名

个人倾向于使用Let’s Encrypt申请免费证书,设置好自动续期即可

服务器需要访问公网一个可以解析的域名本文以example.com为例

Certbot 是由 Electronic Frontier Foundation (EFF) 提供的一个开源工具,用于自动化从 Let’s Encrypt 获取和管理 SSL 证书。Certbot 会自动为你处理证书申请、安装和续期等过程。

使用linux snap 包管理工具安装Certbot,支持snap后可以使用如下命令安装Certbot

1
2
$ sudo snap install --classic certbot #安装Certbot
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot #创建一个符号链接,确保可以执行certbot命令(相当于快捷方式)

也可用自带的yum或者dnf或apt安装

4.1 证书申请,申请单域名

泛域名认证较为复杂需要域名提供商的域名解析api暂不提供改方式

nginx 配置 一定要放80端口aaa.xxxxx.com解析到服务器

1
2
3
4
5
6
7
8
9
10
11
server {
listen 80;
server_name aaa.xxxxx.com;
# ✅ Let’s Encrypt HTTP-01
location ^~ /.well-known/acme-challenge/ {
root /var/www/certbot;
default_type text/plain;
try_files $uri =404;
}
}

申请证书

1
2
3
4
5
6
7
8
9
10
$ certbot certonly --cert-name my-headscale-cert -d aaa.xxxxx.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log

How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Spin up a temporary webserver (standalone)
2: Place files in webroot directory (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1 选择1认证方式

基本能申请成功,证书路径在

/etc/letsencrypt/live/my-headscale-cert 文件下,该文件夹下文件为软连接用此即可

证书续期

首先,你可以手动测试续期是否正常:

1
sudo certbot renew --dry-run

如果没有报错,可以继续配置自动续期任务:

1
sudo crontab -e

在打开的编辑器中添加

1
2
3
#每10天执行一次自动续期任务凌晨三点
0 3 */10 * * /usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"

4.2 nginx 的ssl配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
server {
listen 443 ssl http2;
#listen 443;
server_name headscale.antaixin.com.cn;
ssl_certificate /etc/letsencrypt/live/my-headscale-cert/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/my-headscale-cert/privkey.pem;
#headscale-admin-Cx267c56Tcer 为自己编译的headplane路径
location /headscale-admin-Cx267c56Tcer {
proxy_pass http://localhost:3000;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}
location / {
proxy_pass http://127.0.0.1:16888;
# 必须的头
proxy_set_header Host $host;
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 https;
# WebSocket 支持(tailscale 必需)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 超时设置(避免 DERP / control 超时)
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}


5 DERP的部署

derp需要自己编译目前需要强制域名ssl ,可以参考Tailscale 基础教程:部署私有 DERP 中继服务器 · 云原生实验室修改源码进行ip部署

第一种方式获取

1
$ go install tailscale.com/cmd/derper@latest

第二种方式获取

GitHub - tailscale/tailscale: The easiest, most secure way to use WireGuard and 2FA.

从tailscale的仓库中拉取代码

进入cmd/derper目录下运行

1
$ go build .

把编译好的derper二进制文件复制到/usr/local/bin目录下

1
$ cp derper /usr/local/bin/derper

编辑service文件

路径/etc/systemd/system/derper.service hostname 替换成自己域名,–a尽量使用443端口其余配置尽量不要动

关键配置说明--verify-clients=true 这个为客户端需要认证防止DERP被白嫖的关键设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[Unit]
Description=Tailscale DERP Server
After=network.target

[Service]
ExecStart=/usr/bin/derper --hostname=aaa.xxxx.cn \
--certmode=manual \
--certdir=/etc/derper \
--a=:8443 \
--stun=true \
--stun-port=3478 \
--http-port=-1 \
--verify-clients=true
Restart=always
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target

把第4部申请的证书做软连接供derper使用 ,因此可以与headscale 管理使用同一个域名 –certdir即为证书路径 ,derper只接收路径不接受文件 软连接的名一定和域名相同

1
2
$ ln -s /etc/letsencrypt/archive/my-headscale-cert/fullchain1.pem /etc/derper/aaa.xxxx.cn.crt 
$ ln -s /etc/letsencrypt/archive/my-headscale-cert/privkey1.pem /etc/derper/aaa.xxxx.cn.key

运行以下指令

1
2
$ systemctl daemon-reload
$ systemctl start derper && systemctl enable derper

配置到headscale

有以文件的防止配置

配置路径为/etc/headscale/derp.yaml

regioncoderegionname两个可以自定义命名 derpport为开放的端口

1
2
3
4
5
6
7
8
9
10
11
12
13
regions:
900:
regionid: 900
regioncode: ahk
regionname: A Hongkong
nodes:
- name: 900a
regionid: 900
hostname: aaa.xxxx.cn
stunport: 3478
stunonly: false
derpport: 8443

headscale配置修改,为了防止连接tailscale的derp 建议修改成以下

1
2
3
4
5
#urls: []
# - https://controlplane.tailscale.com/derpmap/default

paths:
- /etc/headscale/derp.yaml

重启headscale服务

服务器开放端口

443 tcp

8443 tcp

3478 udp

DERP防止被别人白嫖

在启动参数中添加 --verify-clients=true

DERP的服务器安装 tailscale 作为认证客户端使用

DERP服务器的tailscale登陆命令

1
2
3
4
5
6
7
8
9
$ tailscale up \
--login-server=https://aaaa.xxxx.com \
--accept-dns=false \
--accept-routes=false \
--advertise-exit-node=false \
--netfilter-mode=off \
--shields-up=true \
--advertise-tags="tag:tailscale-verify-server" \
--authkey=9222a6a96247a6ce4a30dbd8ae0c4e9738ebd2a3327750d7

关键参数解释

--netfilter-mode=off不插 iptables防止服务器无法访问外网 不动 FORWARD / OUTPUT

--shields-up=true 不影响服务器原有网络, 防止局域网内其他主机访问

--accept-routes=false 不接受路由防止局域网其他主机通过内网ip访问服务器

6 打通内网

内网中转服务器目前只在linux系统上实验成功,windows暂未实验成

在这台 Linux 主机 (例如 OpenWrt) 上,需要开启内核的 IP 转发功能

1
2
3
4
$ echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/ipforwarding.conf
$ echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/ipforwarding.conf # 如果需要 IPv6 路由
$ sudo sysctl -p /etc/sysctl.d/ipforwarding.conf

在需要转发的内网主机上宣告路由,如果之前已运行,可以加上 --reset 参数重新配置,如果您有多个局域网段需要宣告,可以用逗号分隔,例如 --advertise-routes=192.168.1.0/24,10.0.0.0/8

假设内网ip为192.168.1.X 子网为255.555.255.0 即24位子网掩码计算,子网掩码需要转换为二进制

1
2
3
# 将 <HEADSCALE_PUB_ENDPOINT> 替换为您的 Headscale 服务器地址
$ sudo tailscale up --login-server=http://<HEADSCALE_PUB_ENDPOINT>:8080 --accept-routes=true --accept-dns=false --advertise-routes=192.168.1.0/24 --reset

headscale 服务器启用宣告的路由设置

如果使用 Headscale 命令行操作,可以先找到路由节点的 ID 或名称

1
2
3
4
$ headscale nodes list-routes 
# ID | Hostname | Approved | Available | Serving (Primary)
# 2 | 222222111 | | 192.168.1.0/24 |

查看需要启用的节点id路由是否在 Approved

若不在 以2号为例 进行允许

1
$ headscale nodes approve-routes --identifier 2 --routes 192.168.124.0/24

验证

1
2
3
$ headscale nodes list-routes 
# ID | Hostname | Approved | Available | Serving (Primary)
# 2 | 222222111 | 192.168.1.0/24 | 192.168.1.0/24 | 192.168.1.0/24

headplane操作

选择有蓝色 Subnets字样的节点按下图操作

image-20260127094659973

按照如下操作即可 可以看到Subnets上的感叹号没了

image-20260127094817134

可能出现的坑点

--accept-routes=true 若在内网内其他机器也登陆的tailscale 则其他机器的改选项一定要设置为false 否则可能会在成内网其他机器的路由表混乱,导致无法通过内网ip来访问登陆tailscale的主机

7 判断是直连还是经过DERP

在终端机上 使用tailscal ping 另一台终端机 若结果不含 DERP则为直连

image-20260127101334893

iperf测速 受限于公网的上传和下载,跨服务商也会有差距。能通的话基本不会有太大问题。除非网络提供商锁P2P传输。

image-20260127101027343

image-20260127101424933

非直连自己的DERP测速 受限于公网带宽 经过路由中转后速度也会降

79770d1fb8334bb7825a1c8f9a07c38c

8 参考文章

Tailscale 基础教程:Headscale 的部署方法和使用教程 · 云原生实验室

Tailscale 基础教程:部署私有 DERP 中继服务器 · 云原生实验室

使用 Let’s Encrypt 免费申请泛域名 SSL 证书,并实现自动续期 - 平元兄 - 博客园

至此部署完成!有问题欢迎联系邮箱 wzy9212@163.com

  • 标题: Headscale搭建-前端、服务、自定义derp
  • 作者: WangZeyu
  • 创建于 : 2026-01-26 14:47:08
  • 更新于 : 2026-01-27 10:34:13
  • 链接: https://wangzeyu92.github.io/2026/01/26/Headscale搭建-前端、服务、自定义derp/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。