前言
为什么选用tailscale?
- 笔者有异地组网需求,目前尝试过frp stcp做穿透、wireguard组网,经过一段时间的使用,稍微总结一下:使用frp用stcp发布服务,客户端连接,确实是个很好的办法,但是配置终究太麻烦,需要安装客户端、在添加了穿透之后每个客户端需要独立配置等等;wireguard可能是当下最好的组网技术,低占用、linux内核级支持、配置简单(wireguard-ui),这些都是它的优点,可是有一个十分致命的点,它是中心化的,流量都需要过一遍server进行转发,这无异于极大的增加了服务器的带宽压力且增加了流量的延迟。经过这一段时间的查阅资料,发现了tailscale这个基于wireguard的项目,他的工作原理可以通过官网进行查看,与此同时又发现了headscale这个对tailscale server的开源实现。
- 这里可能有人就要问了,为什么在tailscale官方免费提供了3用户100台设备连接、提供acl、p2p、sso的情况下,要选择自建headscale呢,当然是为了固定IP,毕竟随机分配的地址可太难受了。
- 如果您觉得tailscale官方提供的设备数量足够你使用且无自定义ip的需求,那么你仍然可以使用tailscale官方提供的服务,但仍建议您自建一个derp(tailscale中继服务器),因为官方未在大陆地区提供derp服务,存在人数较多及访问延迟较高的情况。
服务器占用的端口列表
说明:此处占用端口列表为docker容器映射到本地的端口,你也可以使用docker启动一个nginx,这样子就不用占用服务器本地的端口了,本文采用物理机安装nginx进行反代的方式。
端口类型 |
实际对外端口号 |
容器端口号 |
需要反代 |
用途 |
所属服务 |
TCP |
58080 |
8080 |
需要 |
headscale server |
headscale |
TCP |
57070 |
7070 |
需要 |
headscale web ui |
headscale |
TCP |
56060 |
6060 |
需要 |
headscale derp |
derp server |
UDP |
3478 |
3478 |
不需要 |
headscale derp stun |
derp server |
前提条件
- 你需要一台具备公网IP的服务器和该服务器防火墙修改权限
- 一个域名且带有SSL证书(可以使用acme.sh申请免费证书),需要占用两个子域
- 一些基础的计算机网络知识 注意:请将本文全文所涉及到的域名:hs.example.com(headscale-server及ui)、hsderp.example.com(中继)修改为自己的域名,后续将不再另行说明。
- 本文将使用docker compose的方式安装headscale、derp、headscale-ui。
安装docker
注意:该项内容来源于清华大学开源软件镜像站
Docker 提供了一个自动配置与安装的脚本,支持 Debian、RHEL、SUSE 系列及衍生系统的安装。 以下内容假定 您为 root 用户,或有 sudo 权限,或知道 root 密码; 您系统上有 curl 或 wget
export DOWNLOAD_URL="https://mirrors.tuna.tsinghua.edu.cn/docker-ce"
# 如您使用 curl
curl -fsSL https://get.docker.com/ | sh
# 如您使用 wget
wget -O- https://get.docker.com/ | sh
docker compose文件
本文中compose文件仅部署headscale、headscale-ui、derp、client,请按需进行修改。
注意,要提前配置好config.yaml和derp.yaml,并放入headscale/config文件夹内,同时因derp更新不及时,这里采取了手动构建方式,需将derp.Dockerfile放入dockerfiles文件夹内。可以去GitHUB的代码仓下载config-example.yaml和derp-example.yaml,内容见0x04配置文件部分。
# docker-compose.yaml
version: '3.9'
networks:
private:
driver: bridge
ipam:
config:
- subnet: 172.20.200.0/24
services:
server:
image: headscale/headscale:v0.23.0-alpha12
container_name: headscale-server
networks:
- private
volumes:
- ./headscale/config:/etc/headscale
- ./headscale/data:/var/lib/headscale
- ./headscale/run:/var/run/headscale
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
ports:
- "58080:8080"
command: serve
restart: unless-stopped
depends_on:
- derp
webui:
image: ghcr.io/gurucomputing/headscale-ui
container_name: headscale-ui
networks:
- private
environment:
HTTP_PORT: 7070
ports:
- "57070:7070"
volumes:
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
restart: unless-stopped
derp:
build:
context: ./dockerfiles
dockerfile: derp.Dockerfile
container_name: headscale-derp
networks:
- private
environment:
DERP_DOMAIN: hs.example.com
DERP_ADDR: :6060
DERP_CERT_MODE: letsencrypt
DERP_VERIFY_CLIENTS: true
ports:
- "56060:6060" # derp port, TCP
- "3478:3478/udp" # STUN port, UDP
volumes:
- ./tailscale:/var/run/tailscale
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
restart: unless-stopped
client:
image: tailscale/tailscale:stable
container_name: tailscale-client
network_mode: "host"
privileged: true
environment:
TS_EXTRA_ARGS: --netfilter-mode = off
volumes:
- ./tailscale:/var/run/tailscale
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
- /var/lib:/var/lib
- /dev/net/tun:/dev/net/tun
cap_add:
- net_admin
- sys_module
command: tailscaled
restart: unless-stopped
请将derp.Dockerfile放入docker-compose.yaml同级的dockerfiles文件夹内
# derp.Dockerfile
FROM golang:latest AS builder
WORKDIR /app
# https://tailscale.com/kb/1118/custom-derp-servers/
RUN go env -w GOPROXY=https://goproxy.io,direct
RUN go install tailscale.com/cmd/derper@latest
FROM ubuntu
WORKDIR /app
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y --no-install-recommends apt-utils && \
apt-get install -y ca-certificates && \
mkdir /app/certs
ENV DERP_DOMAIN=your-hostname.com
ENV DERP_CERT_MODE=letsencrypt
ENV DERP_CERT_DIR=/app/certs
ENV DERP_ADDR=:443
ENV DERP_STUN=true
ENV DERP_STUN_PORT=3478
ENV DERP_HTTP_PORT=80
ENV DERP_VERIFY_CLIENTS=false
ENV DERP_VERIFY_CLIENT_URL=""
COPY --from=builder /go/bin/derper .
CMD /app/derper --hostname=$DERP_DOMAIN \
--certmode=$DERP_CERT_MODE \
--certdir=$DERP_CERT_DIR \
--a=$DERP_ADDR \
--stun=$DERP_STUN \
--stun-port=$DERP_STUN_PORT \
--http-port=$DERP_HTTP_PORT \
--verify-clients=$DERP_VERIFY_CLIENTS \
--verify-client-url=$DERP_VERIFY_CLIENT_URL
服务器配置
config.yaml
server_url: https://hs.example.cn
listen_addr: 0.0.0.0:8080
metrics_listen_addr: 0.0.0.0:9090
grpc_listen_addr: 0.0.0.0:50443
noise:
private_key_path: ./noise_private.key
prefixes:
v6: fd7a:115c:a1e0::/48
v4: 100.100.0.0/16
allocation: sequential
derp:
paths:
- /etc/headscale/derp.yaml
database:
type: sqlite
sqlite:
path: /var/lib/headscale/db.sqlite
write_ahead_log: true
derp.yaml
regions:
999:
regionid: 999
regioncode: cnsz
regionname: China Tencent Cloud
nodes:
- name: my-derp
regionid: 999
hostname: hsderp.example.cn
stunport: 3478
stunonly: false
derpport: 443
nginx配置文件
注意,为了便于笔者管理,以下给出的nginx配置文件仅为proxy相关conf,请自行在域名配置文件里incloud,相关语法:include /www/hsderp.example.cn/proxy/*.conf 。您也可以根自己喜好直接写入网站配置内。
headscale-server和derp正常进行反代就行了,ui端因为跨域的原因,需要在同一个域里。如您按照本文提供的内容进行创建的话,那么你可以直接使用此nginx配置,否则请自行修改相应端口。
- hsderp.example.com反代设置 hsderp.conf
location ^~ / {
proxy_pass http://127.0.0.1:56060;
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 X-Cache $upstream_cache_status;
add_header Strict-Transport-Security "max-age=31536000";
}
- hs.example.com反代设置 hs.conf
location ^~ / {
proxy_pass http://127.0.0.1:58080;
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 X-Cache $upstream_cache_status;
add_header Strict-Transport-Security "max-age=31536000";
add_header Cache-Control no-cache;
}
web.conf
location ^~ /web {
proxy_pass http://127.0.0.1:57070;
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 X-Cache $upstream_cache_status;
add_header Strict-Transport-Security "max-age=31536000";
add_header Cache-Control no-cache;
}
至此,您在浏览器中打开https://hs.example.com/web及https://haderp.example.com均可看到相关页面
headscale-ui配置
- 为了便捷控制,首先生成api key供headscale-ui进行控制 ,其中-e参数后面指定的是该apikey的过期时间,这里设置为720天 docker exec headscale-server headscale apikeys create -e 720d
- ui端配置 2.1 打开ui端页面 2.2 点击”Settings” 2.3 添加”Headscale URL”,本例为https://hs.example.com 2.4 将刚才生成的api key粘贴进“Headscale API Key”中 2.5 点击“Test Server Settings”,出现绿色对号后UI端就可以通过ui控制服务端了 2.6 进入“User View”,点击“+New User”,添加一个用户 2.7 为该用户生成一个Preauth Key,供客户端连接使用。为了便捷性,最好设置为“Reusable”,并“Active”,如所示
客户端连接
客户端可以在tailscale官网进行下载及查看使用文档。 如您docker-compose文件中将derp部分的DERP_VERIFY_CLIENTS设置为了true,这代表您开启了客户端验证,如关闭则您的derp可被所有人使用。开启后需要对docker的client进行配置,参考linux客户端,如下为使用docker exec配置示例
docker exec -it tailscale-client tailscale up --netfilter-mode=off --login-server=https://hs.example.com --auth-key=YOUR AUTH KEY
linux客户端
- 使用官方脚本安装tailscale客户端 curl -fsSL https://tailscale.com/install.sh | sh
- 连接服务器 注意:以下命令二选一即可,有关路由转发描述见0x08 路由转发
# 需路由转发
tailscale up --netfilter-mode=off \
--accept-routes \
--advertise-routes=192.168.0.0/24 \
--login-server=https://hs.example.com \
--auth-key=YOUR AUTH KEY
# 不需路由转发
tailscale up --netfilter-mode=off \
--login-server=https://hs.example.com \
--auth-key=YOUR AUTH KEY
windows客户端
- 在官网下载并安装客户端后,首次需打开cmd或powershell,输入以下命令进行连接
tailscale up -netfilter-mode=off -login-server=https://hs.example.com -auth-key=YOUR AUTH KEY
IOS客户端
- 您需要使用非中国大陆地区APP Store账号进行下载并安装tailscale。本文不提供相关教程,请自行搜索美区、港区APPLE ID注册教程。
- 安装后点击右上角头像,在弹出“Accounts”窗口,点击右上角三个点,并选择“Use a custom coordination server”
- 输入您的域名https://hs.example.com点击“Login in”
- 复制弹窗的以mkey:xxxx开头的key
- 浏览器打开headscale-ui,点击“Device view”,并点击“New Device”
- 将步骤4中复制的key粘贴到“Device Key”中,并选择对应用户,点后面的勾。
其他客户端
因笔者设备原因,android/macos等平台不做其他描述,手动添加设备的教程同IOS客户端中第3步以后所示。
路由转发
路由转发为接受路由转发,当你启动tailscale时加了--accept-routes参数之后,您启动命令中advertise-routes需要附带您当前设备能够访问的子网,这将会被通告出去。
举个例子,家中网段为192.168.0.0/24,设备A的ip地址为192.168.0.1,当开启路由转发后,从手机等设备访问192.168.0.0/24这个网段将通过设备A进行转发,可以直接联通家中所有局域网。
如您在0x07 客户端连接中的linux客户端教程中使用了路由转发功能,需要额外进行配置
# eth@if78为出口网卡名,tailscale0为tailscale网卡名,需根据实际修改
iptables -I FORWARD -i eth@if78 -j ACCEPT
iptables -I FORWARD -o eth0@if78 -j ACCEPT
iptables -t nat -I POSTROUTING -o eth0@if78 -j MASQUERADE
iptables -I FORWARD -i tailscale0 -j ACCEPT
iptables -I FORWARD -o tailscale0 -j ACCEPT
iptables -t nat -I POSTROUTING -o tailscale0 -j MASQUERADE
sysctl -w net.ipv4.ip_forward=1