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.ceolocation ^~ / {
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 可以根据自己喜好
"Name": "核心",
// 这个也和 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部分的其他内容请自行看注释。
此处为多地区多节点的官方平台配置案例:
"900": {
"RegionID": 900,
"RegionCode": "NAT",
"RegionName": "nat.moe.ceo",
"Nodes": [
{
"Name": "核心",
"RegionID": 900,
"HostName": "nat.moe.ceo",
"DERPPort": 3477,
},
],
},
"901": {
"RegionID": 901,
"RegionCode": "railgun",
"RegionName": "railgun.top",
"Nodes": [
{
"Name": "电磁炮",
"RegionID": 901,
"HostName": "railgun.top",
"DERPPort": 3477,
},
],
},此处为单地区多节点的官方平台配置案例:
"900": {
"RegionID": 900,
"RegionCode": "NekoPara",
"RegionName": "猫娘乐园",
"Nodes": [
{
"Name": "巧克力",
"RegionID": 900,
"HostName": "chocola.nekopara.moe",
"DERPPort": 3477,
},
{
"Name": "香草",
"RegionID": 900,
"HostName": "vanilla.nekopara.moe",
"DERPPort": 3477,
},
],
},