Tailscale 生态全私有化部署
部署 Headscale
首先还是使用 1Panel 作为部署平台。此处省略其安装部分,直接开始正文。1Panel 应用仅需安装 OpenResty 用于反代。
直接打开 1Panel 的容器编排,使用docker-compose
一键部署。
version: '3.5'
services:
headscale:
image: headscale/headscale:latest
container_name: headscale
network_mode: bridge
volumes:
- ./config:/etc/headscale/
ports:
- "127.0.0.1:4000:4000"
restart: always
command: headscale serve
这时容器会不停的重启,这是因为缺少一个config.yaml
与db.sqlite
数据库文件。先暂时将 Headscale 容器停止。
cd /opt/1panel/docker/compose/headscale
mkdir -p ./config
touch ./config/db.sqlite
wget -O ./config/config.yaml https://raw.githubusercontent.com/juanfont/headscale/main/config-example.yaml
然后,我们打开/opt/1panel/docker/compose/headscale/config
文件夹下的config.yaml
,对其内容进行个性化修改。
此处我将server_url
字段值改为 Headscale 服务的域名https://nat.moe.ceo:443
,将listen_addr
字段值改为0.0.0.0:4000
,将metrics_listen_addr
字段值改为0.0.0.0:9090
,将grpc_listen_addr
字段值改为0.0.0.0:50443
。(重要的是server_url
与listen_addr
字段值)
server_url
字段是服务所使用的域名。listen_addr
字段是设定程序监听绑定给服务的端口。由于443端口我需要和其他服务同时使用,所以使用 OpenResty 反代服务域名到程序监听的端口4000上,且为了安全和管理,我部署容器几乎都采用的是443反代到本地端口说,没有将容器端口直接暴露到公网。metrics_listen_addr
字段是用于设定/metrics
端点的端口。其作用是访问/metrics
端点可以查看服务 Headscale 的运行情况。grpc_listen_addr
字段是设定服务 Headscale 的远程 CLI 调试。注意如果你需要使用 CLI,请一定还要把grpc_allow_insecure
值改为true
。虽然我修改了metrics_listen_addr
与grpc_listen_addr
字段,但其实docker-compose
中我并没有将其映射出去,实在是平时用不上,有需要的可以自行映射出去。Headscale 自带的stun
服务也是一样。
根据个人需求可以将ip_prefixes
改为想要用于分配的 IP 网段。具体其他详细参数可以参考配置文件的注释内容与 Tailscale 官方文档进行修改。需要注意的是如果是阿里云的服务器,可能会有一定问题,此处不做讲解,可以查看其他作者的博文进行解决。
如对 dns 有需求的也可以修改dns_config
字段下的nameservers
部分内容。默认的1.1.1.1
与8.8.8.8
也是可行的。
将配置文件config.yaml
修改完成后重启 Headscale 容器。
进入网站管理页面,添加 Headscale 服务的域名,网站类型是静态网站,切记不是反向代理。代理地址127.0.0.1:4000
我们后续再设置。再前往证书页面为此域名申请一个免费的证书。最好切回网站管理页面,为 Headscale 服务的域名开启 HTTPS 支持。
此时还未完成所有步骤,我们需要对 Headscale 的反向代理进行修改。然后还需要为它配置一个 WebUI 界面,方便我们后续的使用。
在 Releases 中下载 headscale-ui 压缩包将其上传到 1Panel 设置的域名的文件夹内。如我设置的域名是nat.moe.ceo
,则在 1Panel 中打开文件夹/opt/1panel/apps/openresty/openresty/www/sites/nat.moe.ceo/index
,上传完headscale-ui.zip
,将其解压出来会得到一个web
文件夹,其里面就是 headscale-ui 的静态文件代码。
我们返回 1Panel 的网站管理页面,对我们设置的域名进行调整。首先创建一个反向代理,指定根路径反代到127.0.0.1:4000
,我们设定的listen_addr
字段端口上。然后点击创建的反代的源文选项,我们需要对其进行修改。在反代的配置内容后面加入以下代码:
location /web {
alias /www/sites/nat.moe.ceo/index/web;
index index.html;
}
需要注意的是alias
部分的内容需要根据你的实际域名路径进行修改。
此时我们可以访问几个路径看看是否成功的启动了服务。如/windows
子路径查看 Windows 端的配置方法、/apple
子路径查看 macOS 与 IOS 端的配置方法。同样可以访问/web
路径看看 WenUI 是否正常。
我们此处就需要生成一个apikey
用来管理 Headscale 服务了。你可以选择直接在 1Panel 中进入容器终端或者选择 SSH 连上服务器通过docker exec -it headscale /bin/sh
命令进入容器终端。
我们输入headscale apikeys create -e 3650d
命令用来生成一个时长365天有效期的密钥。其实直接执行docker exec headscale headscale apikeys create -e 3650d
也行。
此时可以访问/web
进入 WebUI 中,Headscale URL 处填入服务域名(如我则填写https://nat.moe.ceo
),Headscale API Key 处填入上面得到的密钥。点击 Test Server Setting 对密钥进行连接测试。连接成功会旁边显示绿色小勾。此时就可以在 User View 与 Device View 中查看设备与用户情况了。
客户端配置
现在我们需要在 User View 中创建一个用户,设置完用户名,创建用户成功后还需要为其设置一个身份密钥 Preauth Keys 用于和服务端进行连接。为了方便可以勾选上 Reusable 生成一个可以重复使用的 KEY,且把有效期拉长点。需要知道的是前面终端生成的apikeys
是管理服务的密钥,这里提供 WebUI 生成的是连接这个用户组网用的auth key
密钥。
# 创建用户
headscale namespaces create default
# 创建对应用户的authkey
headscale preauthkeys create -e 24h --user default
至于怎么连接可以查看官方仓库juanfont/headscale: An open source, self-hosted implementation of the Tailscale control server (github.com)查看具体内容,也可以通过前面说过的访问对应子路径查看。
这里以 Android 的为例,可以下载官方客户端后,在客户端设置中选择使用自建服务器,填入服务域名即可。连接后会跳转访问自建的服务网页,页面说会有一个命令与说明,我们将命令进入到headscale
容器内执行即可,其中NAMESPACE
要改为实际的创建的用户名。命令类似于:
headscale nodes register --user default --key SOME_HEX_VALUE
最新的 Android 客户端可以直接使用auth key
进行登录了。我们拿创建用户的时候生成的身份密钥 Preauth Keys 填入其中连接就行了。新版本更加方便简洁。不仅可以通过 Android 客户端使用auth key
进行登录,同样可以在 WebUI 的 Device View 中使用跳转后给予的命令的SOME_HEX_VALUE
值拿到 Device Key 处填入实现组网登录。
至于 Windows 端就直接终端命令吧。如下:
tailscale up --login-server=https://nat.moe.ceo --authkey=877f98d30e7df9f6f760266864220a935eaad6c33dda22ac
其中的auth key
值是我随便打的,将login-server
与authkey
值改为自己实际上使用与生成的即可。
一切连接完成后,我们就可以通过WebUI看到Device View中出现的新设备了。
客户端常用命令扩展
# 显示组网状态
tailscale status
# 显示网络状态
tailscale netcheck
# 提供出口节点
tailscale up --advertise-exit-node
# 启用子网路由
tailscale up --advertise-routes=192.168.1.0/24
# 接受子网路由
tailscale up --accept-routes
# 断开并且退出
tailscale down
关于客户端命令可以查看 Tailscale 的官网的官方文档。关于 Headscale 的 config 具体配置可以查看注释与官方代码仓库。
部署 DERP
此处还是使用docker-compose
一键化部署,且依旧会出现重启问题,先停止,修改完再启动即可。
version: '3.5'
services:
derper:
image: fredliang/derper
container_name: derper
network_mode: bridge
volumes:
- ./certs:/app/certs
- /opt/1panel/docker/compose/tailscaled/tailscale:/var/run/tailscale
ports:
- "3477:3477"
- "3478:3478/udp"
restart: always
environment:
- DERP_CERT_MODE=manual
- DERP_ADDR=:3477
- DERP_VERIFY_CLIENTS=true
- DERP_DOMAIN=nat.moe.ceo
首先需要知道的是否需要启用DERP_VERIFY_CLIENTS
,启用后自建的 DERP 就仅只能自己使用,不会被其他人扫到你自建的中继节点然后白嫖。上述给予的docker-compose
案例是启用了此功能的。
如需此功能请先在 DERP 服务器上运行 Tailscale 的客户端。我依旧选择 Docker 容器化部署。
version: '3.5'
services:
tailscaled:
container_name: tailscaled
image: tailscale/tailscale
network_mode: host
privileged: true
restart: always
cap_add:
- net_admin
- sys_module
volumes:
- ./lib/:/var/lib/
- /dev/net/tun:/dev/net/tun
- ./tailscale:/var/run/tailscale
command: sh -c "mkdir -p /var/run/tailscale && ln -s /tmp/tailscaled.sock /var/run/tailscale/tailscaled.sock && tailscaled"
由于我的 DERP 与 Headscale 处于同一个服务器,所以我的 Headscale 自带的stun
就没有启用,直接使用 DERP 上的即可。
且我为 DERP 分配的域名也是 Headscale 的域名。因为官方 DERP 方案走的是443端口,我授予的域名443端口还反代着 Headscale 服务,所以采用的是单独的端口。
此处我讲解一下 DERP 的容器compose
参数情况。3477端口是 DERP 服务端口,可以在环境变量environment
中修改DERP_ADDR
值进行调整,需要注意的是填写值的前面有一个:
符号。3478端口是stun
服务的端口,需要注意走的是udp
,不要写错了,且有防火墙的,需要注意放行情况。如果不需要stun
服务,环境变量中加入DERP_STUN
值为false
即可,默认是true
。certs路径的映射是用来存放derp服务域名的 TLS 证书的。环境变量中的DERP_CERT_MODE
可以设置证书设定方式,可选manual
与letsencrypt
,但是如果是letsencrypt
则derp服务使用443端口。因为我并没有让 DERP 使用443端口,且我给予的域名的443反代给了 Headscale 在使用。故此我选择手动,填写manual
模式。需要注意的是DERP_DOMAIN
值是一定要填写的,我填写的是 Headscale 服务的域名。毕竟在同一个服务器上跑,懒得再单独给一个域名了。且我都单独给域名了,不如443反代。
如果你不需要启用 DERP 的身份验证,公开 DERP 服务的话,那tailscale
与derp
容器的/var/run/tailscale
目录是不需要映射的。这个目录映射的作用是使用其目录中的tailscaled.sock
用于身份验证。
至于certs
的证书,由于我是为 DERP 授予的 Headscale 服务域名,所以直接将/opt/1panel/apps/openresty/openresty/www/sites/nat.moe.ceo/ssl/
目录中的证书COPY到/opt/1panel/docker/compose/derper/certs/
下即可。需要注意的是一定要修改证书与密钥文件名字。证书密钥文件名一定要是nat.moe.ceo.crt
与nat.moe.ceo.key
。即授予 DERP 的域名为文件名。
为了方便可以写一个定时任务,将证书定时同步到目录下即可。如下:
cp /opt/1panel/apps/openresty/openresty/www/sites/nat.moe.ceo/ssl/fullchain.pem /opt/1panel/docker/compose/derper/certs/nat.moe.ceo.crt
cp /opt/1panel/apps/openresty/openresty/www/sites/nat.moe.ceo/ssl/privkey.pem /opt/1panel/docker/compose/derper/certs/nat.moe.ceo.key
证书文件弄好后就可以正常启动derp
容器了。
如果是443端口复用、自动化生成证书且开启身份验证,则docker-compose
与nginx
反代如下:
version: '3.5'
services:
derper:
image: fredliang/derper
container_name: derper
network_mode: bridge
volumes:
- ./certs:/app/certs
- /opt/1panel/docker/compose/tailscaled/tailscale:/var/run/tailscale
ports:
- "127.0.0.1:3477:443"
- "3478:3478/udp"
restart: always
environment:
- DERP_CERT_MODE=letsencrypt
- DERP_ADDR=:443
- DERP_VERIFY_CLIENTS=true
- DERP_DOMAIN=demo.moe.ceo
location ^~ / {
proxy_pass http://127.0.0.1:3477;
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 REMOTE-HOST $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
add_header Cache-Control no-cache;
proxy_ssl_server_name off;
如果是非443端口且开启身份验证,则docker-compose
代如下:
version: '3.5'
services:
derper:
image: fredliang/derper
container_name: derper
network_mode: bridge
volumes:
- ./certs:/app/certs
- /opt/1panel/docker/compose/tailscaled/tailscale:/var/run/tailscale
ports:
- "3477:3477"
- "3478:3478/udp"
restart: always
environment:
- DERP_CERT_MODE=manual
- DERP_ADDR=:3477
- DERP_VERIFY_CLIENTS=true
- DERP_DOMAIN=demo.moe.ceo
如果是非443端口且不开启身份验证,则docker-compose
代如下:
version: '3.5'
services:
derper:
image: fredliang/derper
container_name: derper
network_mode: bridge
volumes:
- ./certs:/app/certs
ports:
- "3477:3477"
- "3478:3478/udp"
restart: always
environment:
- DERP_CERT_MODE=manual
- DERP_ADDR=:3477
- DERP_VERIFY_CLIENTS=false
- DERP_DOMAIN=demo.moe.ceo
如果是使用 Tailscale 的官方平台,则登录 Tailscale 进入 Access Controls 界面。为配置内容增加以下部分:
"derpMap": {
// OmitDefaultRegions 用来忽略官方的中继节点,一般自建后就看不上官方小水管了
"OmitDefaultRegions": false,
"Regions": {
// 这里的 901 从 900 开始随便取数字
"900": {
// RegionID 和上面的相等
"RegionID": 900,
// RegionCode 简洁名字
"RegionCode": "NAT",
// RegionName 注释名字
"RegionName": "nat.moe.ceo",
"Nodes": [
{
// Name 保持 1不动
"Name": "1",
// 这个也和 RegionID 一样
"RegionID": 900,
// 域名
"HostName": "nat.moe.ceo",
// 端口号
"DERPPort": 3477,
},
],
},
},
},
当然我们使用的是 Headscale 私有端,必然要讲解一下 Headscale 上怎么配置。
Headscale 是可以通过两种方式来配置自定义 DERP 的。分别是在线 URL,通过JSON
方式与本地YAML
文件方式。Tailscale 官方使用的是前者。
我们可以打开 Headscale 的config.yaml
文件。其中有关于derp
配置的部分。其中有官方urls
案例。毕竟 Headscale 是可以使用 Tailscale 官方公开的 DERP 节点的。其次就是derp.yaml
文件路径的设置,把注释取消掉,在对应路径创建文件。
按照我docker-compose
的目录映射来看,直接在config
目录内创建derp.yaml
文件即可。我的案例如下:
# /etc/headscale/derp.yaml
regions:
900:
regionid: 900
regioncode: NAT
regionname: nat.moe.ceo
nodes:
- name: 1
regionid: 900
hostname: nat.moe.ceo
ipv4: xx.xx.xx.xx
stunport: 3478
stunonly: false
derpport: 3477
具体的参数看意思也知道了。至于 Headscale 配置文件中derp
部分的其他内容请自行看注释。