安装服务端
创建headscale配置目录
1 2
| $ mkdir -p /etc/headscale/{data,certs} $ cd /etc/headscale
|
生成headscale配置文件
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
| $ cat >config.yaml<<EOF --- # 这个地址是告诉客户端需要访问的地址, 即使你需要在跑在 # 负载均衡器之后这个地址也必须写成负载均衡器的访问地址 server_url: http://35.241.79.221:8080
# Headscale 实际监听ip和端口 listen_addr: 0.0.0.0:8080
# 监控数据地址 metrics_listen_addr: 127.0.0.1:9090
# grpc 监听地址 grpc_listen_addr: 0.0.0.0:50443
# 是否允许不安全的 grpc 连接(非 TLS) grpc_allow_insecure: false
private_key_path: /var/lib/headscale/private.key noise: private_key_path: /var/lib/headscale/noise_private.key # 给vpn客户端分配的vpn网段 ip_prefixes: - 192.168.66.0/24 # 中继服务器相关配置 derp: server: enabled: false region_id: 999 region_code: "headscale" region_name: "Headscale Embedded DERP" stun_listen_addr: "0.0.0.0:3478" urls: paths: # 自定义的中继服务器配置文件,后面需要创建这个配置文件 - /etc/headscale/derp.yaml auto_update_enabled: true update_frequency: 24h disable_check_updates: false ephemeral_node_inactivity_timeout: 30m node_update_check_interval: 10s
# SQLite config db_type: sqlite3 db_path: /var/lib/headscale/db.sqlite
# acme自动生成ssl证书配置 acme_url: https://acme-v02.api.letsencrypt.org/directory acme_email: "" # 这里不使用自动前面证书,我自己网上生成。 tls_letsencrypt_hostname: "" tls_client_auth_mode: relaxed 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: format: text level: info acl_policy_path: "" dns_config: nameservers: # 给客户端分配dns服务器 - 114.114.114.114 domains: [] magic_dns: true base_domain: example.com unix_socket: /var/run/headscale.sock unix_socket_permission: "0770" logtail: enabled: false randomize_client_port: false EOF
|
创建中继服务器使用的证书目录及证书
1 2 3 4 5 6
| $ cd /etc/headscale
$ vim certs/derper.xxx.cn.key $ vim certs/derper.xxx.cn.crt
|
创建中继服务器配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| $ cd /etc/headscale $ cat >derp.yaml<<EOF regions: 900: regionid: 900 regioncode: thk regionname: aliyun SH nodes: - name: 900a regionid: 900 hostname: derper.xxx.cn ipv4: 35.241.xx.221 stunport: 3478 stunonly: false derpport: 8082 EOF
|
配置说明:
regions
是 YAML 中的对象,下面的每一个对象表示一个可用区,每个可用区里面可设置多个 DERP 节点,即 nodes
。
- 每个可用区的
regionid
不能重复。
- 每个
node
的 name
不能重复。
regionname
一般用来描述可用区,regioncode
一般设置成可用区的缩写。
ipv4
字段不是必须的,如果你的域名可以通过公网解析到你的 DERP 服务器地址,这里可以不填。如果你使用了一个二级域名,而这个域名你并没有在公共 DNS server 中添加相关的解析记录,那么这里就需要指定 IP(前提是你的证书包含了这个二级域名,这个很好支持,搞个泛域名证书就行了)。
stunonly: false
表示除了使用 STUN 服务,还可以使用 DERP 服务。
- 上面的配置中域名和 IP 部分我都打码了,你需要根据你的实际情况填写。
安装docker并生成docker-compose文件
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
| $ curl https://www.putianhui.cn/package/script/install_docker.sh | bash
$ wget https://github.com/docker/compose/releases $ cat > docker-compose.yaml<<EOF version: '3.9'
services: headscale: container_name: headscale image: headscale/headscale:0.16.4 ports: - '8080:8080' cap_add: - NET_ADMIN - NET_RAW - SYS_MODULE sysctls: - net.ipv4.ip_forward=1 - net.ipv6.conf.all.forwarding=1 restart: always volumes: - ./:/etc/headscale - ./data:/var/lib/headscale command: ['headscale', 'serve'] derper: container_name: derper image: fredliang/derper ports: - '8082:8082' - '3478:3478/udp' environment: - DERP_DOMAIN=derper.xxx.cn - DERP_CERT_MODE=manual - DERP_ADDR=:8082 - DERP_HTTP_PORT=-1 restart: always volumes: - ./certs:/app/certs volumes: config: data: EOF
|
启动
启动成功后注意防火墙放行如下端口
服务端常用命令
如果是docker运行的服务端就用 [docker exec headscale headscale ns list] 这样
namespcae相关
1 2 3 4 5 6 7 8 9 10 11
| $ headscale ns list
$ headscale ns create test-net
$ headscale namespace destroy default
$ headscale namespace rename default myspace
|
node相关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| $ headscale nodes list
$ headscale node ls -t
$ headscale -n default node ls
$ headscale node delete -i<ID>
$ headscale node tag -i=2 -t=tag:test
$ headscale nodes routes list -i 1
|
route相关
1 2 3 4 5
| $ headscale routes list -i=9
$ headscale routes enable -i=9 -r=192.168.10.0/24
|
preauthkeys相关
preauthkeys主要是方便客户端快速接入,创建了preauthkeys后客户端直接使用该key就可以直接加入namespace
1 2 3 4 5 6
|
$ headscale -n default preauthkeys list
$ headscale preauthkeys create -e 24h -n default
|
apikeys相关
apikeys是为了客户端和headscale做http鉴权用的,http请求的时候需要设置头部authorization值为固定的字符串”Bearer “加apikeys创建的key
1 2 3 4 5
| $ headscale apikeys create
$ headscale apikeys list -o=json
|
安装服务端管理UI(可选)

注意:
我这里用test-headscale.putianhui-local.com
域名作为ui的访问域名。
headscale服务端(默认使用8080端口)和headscal-ui需要部署在同一台主机上(使用nginx通过前面那个域名把前后端代理出去,解决跨域问题)
1、先将test-headscale.putianhui-local.com
域名解析到headscale服务端ip上。
2、申请test-headscale.putianhui-local.com
域名的ssl证书,可以在阿里云申请免费的,也可以看我这个文档去申请免费通配证书。
3、服务端安装nginx
1 2 3 4 5 6 7 8 9 10
| $ yum install -y nginx unzip && systemctl enable nginx && systemctl start nginx
$ mkdir -p /etc/nginx/cert
$ ll /etc/nginx/cert test-headscale_putianhui-local_com.key test-headscale_putianhui-local_com.pem
|
4、下载headscale-ui源码到本地。
1 2 3 4 5 6 7 8
| $ wget https://github.com/gurucomputing/headscale-ui/releases/download/2022.12.23.2-beta/headscale-ui.zip
$ unzip headscale-ui.zip && headscale-ui
$ mkdir -p /data/ && mv headscale-ui /data
|
5、创建headscale-ui的nginx配置文件
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
| $ vim /etc/nginx/conf.d/headscale-ui.conf map $http_upgrade $connection_upgrade { default keep-alive; 'websocket' upgrade; '' close; }
server { server_name test-headscale.putianhui-local.com;
location /web { alias /data/headscale-ui; index index.html; }
location / { proxy_pass http://localhost: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; }
listen 443 ssl; ssl_certificate cert/test-headscale_putianhui-local_com.pem; ssl_certificate_key cert/test-headscale_putianhui-local_com.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; ssl_prefer_server_ciphers on; }
server { if ($host = test-headscale.putianhui-local.com) { return 301 https://$host$request_uri; }
server_name test-headscale.putianhui-local.com; listen 80; return 404; }
|
测试nginx配置文件正确性并重载配置文件。
1 2 3 4 5
| $ nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
$ nginx -s reload
|
配置重载成功后就可以使用前面的域名https://test-headscale.putianhui-local.com/web
访问到headscale-ui了,如果无法访问请检查你服务器的80、443端口是否放开。
配置headscale-ui

在headscale服务端创建一个apiKey,后面的web页面访问需要用到
1 2
| $ docker exec headscale headscale apikeys create zX79yATj2w.DmfLc0oqBRjnQNiVhcVp_lwEJUIoPkLeQ2HUFhuxxxx
|

安装客户端
Linux 用户目前只需要使用以下命令安装即可:
1
| curl -fsSL https://tailscale.com/install.sh | sh
|
节点加入到服务端
1
| tailscale up --login-server http://35.241.79.221:8080 --advertise-routes=192.168.0.0/24 --accept-routes=true --accept-dns=false
|
关于选项设置:
--login-server
: 指定使用的中央服务器地址(必填)
--advertise-routes
: 向中央服务器报告当前客户端处于哪个内网网段下, 便于中央服务器让同内网设备直接内网直连(可选的)或者将其他设备指定流量路由到当前内网(可选)
--accept-routes
: 是否接受中央服务器下发的用于路由到其他客户端内网的路由规则(可选)
--accept-dns
: 是否使用中央服务器下发的 DNS 相关配置(可选, 推荐关闭)
执行加入命令完成后, tailscale
将会卡住, 并打印一个你的服务器访问地址; 浏览器访问该地址后将会得到一条命令
复制到浏览器访问显示的链接,然后浏览器会显示一条服务端执行的命令。
复制浏览器显示的命令,去服务端执行一下。
1 2 3 4 5 6
|
$ headscale ns create test-net
$ docker exec headscale headscale -n NAMESPACE nodes register --key 584b3fc394e9c8a310ac1c23122dfc03a16422674f38dfe2cac780cdb6cd1503
|
当服务端执行命令后,几秒钟客户端就自动退出一直卡住的界面了。
此时客户端就可以ping通对端集群内的客户端vpn-ip了。
上面步骤完成后只能客户端之间ping通客户端的vpn-ip,如果想ping对端客户端所在的内网其他主机,需要用下面命令开启路由功能.
1 2 3 4 5
|
$ headscale nodes list
$ headscale nodes routes list -i 1
|
此时就可以在一个客户端去ping对端内网的其他主机了。
客户端常用命令
1 2 3 4 5 6 7 8 9 10 11
| $ tailscale ip
$ tailscale status
$ tailscale netcheck
$ tailscale ping 192.168.66.1
|
自建私有中继服务器
中继服务器部署
1 2 3 4 5 6 7 8 9 10 11 12 13
| $ pwd /etc/headscale
$ mkdir certs
$ vim certs/derper.xxx.cn.key $ vim certs/derper.xxx.cn.crt
docker run -d --name derper -v /etc/headscale/certs:/app/certs -e DERP_DOMAIN=derper.xxx.cn -e DERP_CERT_MODE=manual -e DERP_ADDR=:8082 -e DERP_HTTP_PORT=-1 -p 8082:8082 -p 3478:3478/udp fredliang/derper
|
启动参数介绍
-d
:容器后台运行
--name
:指定容器名称
-v
:将宿主机/etc/headscale/certs
这个ssl证书目录挂载到容器中的/app/certs
证书目录。
-e DERP_DOMAIN
:指定你解析过来的二级域名
-e DERP_CERT_MODE
:ssl证书的模式使用自定义
-e DERP_ADDR
:自定义端口
配置headscale使用自定义中继服务器
1、在headscale的配置目录下创建一个中继服务器列表文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| $ cat >derp.yaml<<EOF regions: 900: regionid: 900 regioncode: thk regionname: aliyun SH nodes: - name: 900a regionid: 900 hostname: derper.xxx.cn ipv4: 35.241.xx.221 stunport: 3478 stunonly: false derpport: 8082 EOF
|
配置说明:
regions
是 YAML 中的对象,下面的每一个对象表示一个可用区,每个可用区里面可设置多个 DERP 节点,即 nodes
。
- 每个可用区的
regionid
不能重复。
- 每个
node
的 name
不能重复。
regionname
一般用来描述可用区,regioncode
一般设置成可用区的缩写。
ipv4
字段不是必须的,如果你的域名可以通过公网解析到你的 DERP 服务器地址,这里可以不填。如果你使用了一个二级域名,而这个域名你并没有在公共 DNS server 中添加相关的解析记录,那么这里就需要指定 IP(前提是你的证书包含了这个二级域名,这个很好支持,搞个泛域名证书就行了)。
stunonly: false
表示除了使用 STUN 服务,还可以使用 DERP 服务。
- 上面的配置中域名和 IP 部分我都打码了,你需要根据你的实际情况填写。
2、修改 Headscale 的配置文件,引用上面的自定义 DERP 配置文件。需要修改的配置项如下:
1 2 3 4 5 6 7 8 9 10 11 12
|
derp: urls: paths: - /etc/headscale/derp.yaml
|
修改完配置后,重启 headscale 服务
3、在 Tailscale 客户端上使用以下命令查看目前可以使用的 DERP 服务器
1 2 3 4 5 6 7 8 9 10 11
| $ tailscale netcheck Report: * UDP: true * IPv4: yes, 120.26.48.71:39855 * IPv6: no, but OS has support * MappingVariesByDestIP: * HairPinning: false * PortMapping: * Nearest DERP: aliyun SH * DERP latency: - thk: 33.9ms (aliyun SH)
|