Tailscale是一种虚拟组网工具,基于WireGuard。能够把安装了Tailscale服务的机器,都连接到同一个局域网。局域网中的每台设备会自动分配IP,设备可以通过IP实现相互访问,除了延迟,与物理本地局域网相同。
Tailscale会优先使用中继服务器,保证最快可连接,之后尝试P2P连接,即两台设备之间数据不经过中继服务器直接连接。P2P连接成功之后,两台设备直接的延迟取决于两地距离,带宽取决于两地网络带宽上线,不再收中继服务器带宽约束。P2P连接中断时,自动fallback回中继服务器连接,优先保证可访问,其次优化连接速度。
Tailscale本身是一款商业软件,free版本支持3个用户和100个设备组网,但是中继服务器不在国内,在P2P连接失败后,网络延迟较大。可以通过自建中继节点接入官方控制器解决,其次,官方控制器在设备首次接入网络时,都需要使用相同的Google、微软账号登录,比较麻烦,因此选择使用Tailscale的开源替代版本Headscale。
安全方面,Tailscale网络之间的流量使用WireGuard协议传输,中继节点无法解密流量,外部设备需要进行授权才能加入网络,因此安全性较高。
组网成功并且两台设备之间可以通过P2P直连,延迟可以在个位数毫秒内。
网络拓扑
组网后网络拓扑如下,网络中每台设备会分配一个tailscale网络IP
搭建需求
- 至少需要两台服务器,一台部署控制器,多台部署中继节点
- 至少需要两个域名,一台指向控制器,另一台指向各个中继节点
- 域名强制使用HTTPS,如果不使用Caddy等工具,需要手动上传、更新SSL证书,如果证书到期服务将无法使用
- 控制器需要使用80、443端口,中继节点可自定义端口,但不使用443端口时,可能会与Clash冲突导致无法连接到中继节点
使用软件
GitHub – GoodiesHQ/headscale-admin: Admin Web Interface for juanfont/headscale
GitHub – fredliang44/derper-docker: tailscale‘s selfhosted derp-server docker image
安装前
创建Docker网络
docker network create headscale-network
服务端-1-控制器Headscale
安装位置/root/headscale
创建配置文件夹、数据文件夹、docker-compose文件
mkdir container-config container-data
touch docker-compose.yml
version: '3'
services:
headscale:
container_name: headscale
image: headscale/headscale:latest
restart: unless-stopped
volumes:
- ./container-config:/etc/headscale
- ./container-data:/var/lib/headscale
entrypoint: headscale serve
networks:
headscale-network:
networks:
headscale-network:
external: true
在container-config
下创建配置文件config.yaml
先使用官方提供的配置文件模板,后续会对该文件进行修改
server_url: http://127.0.0.1:8080
配置文件第13行,需要改成指向服务器的域名
配置文件第19行,需要改成0.0.0.0:8080否则外部网络无法连接
此时文件目录如下所示
/root/headscale
├── container-config
│ └── config.yaml
├── container-data
└── docker-compose.yml
启动Headsale服务
docker compose up -d
服务端-1-Headsale管理面板
安装目录/root/headscale-admin
使用docker-compose
运行
version: '3'
services:
headscale-admin:
image: goodieshq/headscale-admin:latest
container_name: headscale-admin
ports:
- 8000:80
networks:
- headscale-network
networks:
headscale-network:
external: true
启动容器
docker compose up -d
目录结构如下
/root/headscale-admin/
└── docker-compose.yml
服务端-1-Caddy反代服务
Headscale强制要求HTTPS,此处使用Caddy是为了自动申请更新域名证书,可根据需要更换Nginx
安装目录/root/caddy
创建目录、配置文件
mkdir container-config container-data
touch docker-compose.yml
services:
caddy:
image: caddy:latest
container_name: caddy
restart: always
networks:
headscale-network:
stdin_open: true
tty: true
volumes:
- ./container-data:/data
- ./container-config:/config
- /etc/localtime:/etc/localtime:ro
ports:
- 80:80
- 443:443
entrypoint: /usr/bin/caddy run --adapter caddyfile --config /config/Caddyfile
networks:
headscale-network:
external: true
在container-config
下创建配置文件Caddyfile
,自行更换example.com
为服务器使用域名
https://example.com {
reverse_proxy /admin/* http://headscale-admin
reverse_proxy * http://headscale:8080
}
此时目录结构如下
/root/caddy
├── container-config
│ └── Caddyfile
├── container-data
└── docker-compose.yml
验证是否安装成功
访问以下地址https://<font style="color:rgb(55, 53, 47);">example.com/windows</font>
,能正常访问说明以上步骤正确
管理面板配置
访问地址[https://example.com/admin/](https://headscale2.vio.vin/admin/settings/)
进入管理面板,注意此处需要有最后的/
创建默认用户
docker exec headscale headscale users create default
获取用户加入节点时的key
docker exec headscale headscale preauthkeys create --user default
生成API密钥
docker exec headscale headscale apikey create
在管理面板填入API密钥,点击保存即可认证成功
注意:此处的Legacy API (Headscale < 0.23)
选项需要关掉,如果失败可以打开控制台日志进行排错,浏览器中打开F12即可
- Users:用于创建不同用户,不同用户之间可以隔离也可互相访问
- Nodes:管理已加入Tailscale网络的设备,可以删除设备
- Deploy:用于生成客户端加入Tailscale网络的指令,按照下图设置即可
服务端-2-中继节点Derper
中继节点作为客户端加入Tailscale网络
- 此处是为了使用
DERP_VERIFY_CLIENTS=true
的功能更,用于中继节点授权,防止节点被公网其他用户使用
curl -fsSL https://tailscale.com/install.sh | sh
安装之后使用查看状态确保程序为active状态
systemctl status tailscaled.service
之后使用使用上一步生成的指令加入tailscale网络
tailscale up --login-server=https://headscale2.vio.vin --authkey=e228e7ddcc424e4a5eb4bec397ee493aa03f383fb608e804 --accept-dns=false --accept-routes
安装目录/root/derp
第15行,此处的域名应该使用节点域名,不可与Headscale域名相同
第10行,映射端口需要开启udp
version: '3'
services:
derper:
image: fredliang/derper
container_name: derper
restart: always
ports:
- 443:443
- 34789:3478/udp
volumes:
- ./certs:/app/certs
- /var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock
environment:
- DERP_DOMAIN=example.com
- DERP_VERIFY_CLIENTS=true
此时目录结构如下
/root/derp
└── docker-compose.yml
启动容器
docker compose up -d
访问derp域名确认已在运行
节点加入Headscale
在/root/headscale/container-config
下创建derp.yaml
文件
regions:
902:
regionid: 902
regioncode: chd
regionname: HK Claw
nodes:
- name: 902a
regionid: 902
hostname: derp-hk.vio.vin
stunport: 34789
stunonly: false
derpport: 443
此处的902为节点id,stunport为udp端口,derpport为derp HTTPS端口,其余按照上述自行填写
修改/root/headscale/container-config/config.yaml
注释掉114行,不需要tailscale官方的中继服务器
修改124、125行,指定derp.yaml文件地址
---
# List of externally available DERP maps encoded in JSON
urls:
# - https://controlplane.tailscale.com/derpmap/default
# Locally available DERP map files encoded in YAML
#
# This option is mostly interesting for people hosting
# their own DERP servers:
# https://tailscale.com/kb/1118/custom-derp-servers/
#
# paths:
# - /etc/headscale/derp-example.yaml
paths:
- /etc/headscale/derp.yaml
# If enabled, a worker will be set up to periodically
# refresh the given sources and update the derpmap
# will be set up.
auto_update_enabled: true
# How often should we check for DERP updates?
update_frequency: 24h
用户使用
下载tailscale软件并自行安装
打开CMD窗口,输入headscale管理面板中生成的命令,当显示Tailscale Connected时说明已经连接成功
点击Network devices可查看当前网络中的其他设备,点击可复制设备IP地址
高级功能
Subnet Routers
文档
Subnet routers · Tailscale Docs
按照上述示例配置后,每个设备需要在客户端单独运行tailscale才能加入tailscale网络,加入网络之后才能互相访问,如果需要加入网络的设备较多,此方法不够简单。
是否有什么办法可以将一个ip段或者一个局域网的设备全部拉入tailscale网络中呢,通过Subnet Routers可以实现。不适用Subnet Routers时,只能实现点对点互联,只有使用Subnet Routers才能实现真正的VPN功能。
假设网络拓扑为公司局域网ip段为192.168.31.0/24,将该局域网中任意一个设备的启动命令修改为
tailscale up --accept-routes=true --accept-dns=false --advertise-routes=192.168.31.0/24 --advertise-exit-node
该设备加入tailscale之后,会以该设备网为中继节点,访问局域网内其他设备,此处需要对防火墙出入站规则进行相应配置,tailscale启动后会创建一个tailscale0虚拟网卡,需要对此网卡关闭防火墙,允许出入站。
注意:
- 此处非常不建议使用192.168的网络前缀,容易与客户端网络发生冲突,建议改为10.XX.XX.0网段。
- 开启Subnet Routers功能的节点设备需要开启IP转发功能,具体参考以下文档。
Subnet routers · Tailscale Docs
Exit node
在上述启动命令中有一个参数--advertise-exit-node
,该参数意味将该设备作为整个网络的出口节点,网络中所有设备访问互联网时,不会直接进行访问,所有流量会被转发到该设备,由该设备代理网络流量实现访问,该功能类似与传统意义的VPN,该功能并不是默认的,客户端需要手动设置才能使用Exit node功能。
Exit nodes (route all traffic) · Tailscale Docs
Access Control
默认情况下,同一个局域网内的设备互相可以访问,如果需要对该局域网下的设备进行分组隔离,可以使用tags功能,给加入网络的所有设备打上tag之后,可以通过acl设置设备之间的单向-双向访问,除tag之外,也支持对设备进行分组控制。首先需要修改配置文件,定义tag,此处以json配置文件为示例,自建Headscale需要以yaml为配置文件。
创建Tags
此处的"tag:home-pc"
,代表一个tag,后的中括号制定了谁可以使用这个tag,此处简单设置为管理员可以使用tag。
{
"tagOwners": {
"tag:home-pc": ["autogroup:admin"],
"tag:home-server": ["autogroup:admin"],
"tag:work-pc": ["autogroup:admin"],
"tag:game-server": ["autogroup:admin"],
"tag:game-player": ["autogroup:admin"],
"tag:relay-node": ["autogroup:admin"],
},
}
访问控制
默认设置为{"action": "accept", "src": ["*"], "dst": ["*:*"]}
所有设备之间可相互访问,如需自行控制需要删除这一行。
- acls中包含多个访问规则
- action个reject代表接收或拒绝连接。
- src表示连接源,后可配置tag或group,格式为,示例
["tag:game-player"]
- dst表示连接目的地,格式为:<端口号>,示例
["tag:game-server:*", "tag:game-server:8080", "tag:game-server:8000:9000"],
- tag:game-server:*所有端口均可访问
- tag:game-server:8080只允许访问8080端口
- tag:game-server:8000:9000允许访问的端口范围为8000-9000
"acls": [
// Allow all connections.
// Comment this section out if you want to define specific restrictions.
// {"action": "accept", "src": ["*"], "dst": ["*:*"]},
{
"action": "accept",
"src": ["tag:game-player"],
"dst": ["tag:game-server:*"],
},
{
"action": "accept",
"src": ["tag:game-server"],
"dst": ["tag:game-player:*"],
},
{
"action": "accept",
"src": ["tag:work-pc"],
"dst": ["*:*"],
},
{
"action": "accept",
"src": ["tag:home-pc"],
"dst": ["*:*"],
},
],
更多配置可以查看官方文档以其其他文档。
Group devices with tags · Tailscale Docs
IPV6
启用IPV6可以提高直连几率,减少中继服务器流量负载,IPV6访问需要中继节点和客户端同时支持IPV6,且必须是240开头的公网IP地址。
其他
无人值守模式
开启次配置,tailscale将在设备开机时自动允许
不加入Subnet
如果遇到IP地址冲突,客户端可以暂时关闭subnet routers,关闭如下配置即可
排错
在客户端使用指令tailscale netcheck
可以查看中继服务器状态
tailscale netcheck
使用tailscale status
可查看当前客户端是否连接到tailscale网络,同时可查看网络中其他设备IP
如果遇到Subnet Router无法访问,需要按照此文档开启ip转发
Subnet routers · Tailscale Docs
0