背景
我家只有动态公网IP,并且做了DDNS,家里云虚拟出一台服务器(Ubuntu)部署了L2TP服务,所以在此之前,我一直通过L2TP/IPSec的方式回家,以便于我访问家里的资源。上述方式固然可行,但是慢慢显出弊端:时而链接不上、流量全回家绕一圈,不能灵活调整,速度受宽带上行限制等问题。于是推翻之前的建设,重新部署基于Headscale的异地组网服务。
准备
Headscale可以部署在有公网IP的VPS上,也可以部署在有动态公网IP的家宽上,但是不建议部署在没有公网IP的服务器上,本文采用部署在有动态公网IP的家宽中的服务器上。
本文Headscale的拓扑:
控制链路:外网设备(HTTPS) -> 家里公网IP:12345 -> 路由转发 -> Ubuntu Nginx 12345 (解密) -> Ubuntu Headscale 8080 (HTTP)
数据链路:外网设备 -> 建立P2P或DERP中转 -> Ubuntu (Tailscale Node) -> OpenWrt旁路由 -> 互联网正文
第一步:主路由端口映射 (Port Forwarding)
在你的主路由(10.0.0.1)后台进行设置:
外部端口:12345
内部IP:10.0.0.99 (Ubuntu服务器)
内部端口:12345
协议:TCP (如果Tailscale流量大,建议同时开启UDP映射,虽然Headscale控制流主要是TCP,但为了打洞顺畅,建议TCP+UDP)。
第二步:申请 SSL 证书 (适配 Nginx)
使用 acme.sh 申请证书,并配置它在证书更新后自动重载 Nginx
1.安装 acme.sh:
curl https://get.acme.sh | sh
source ~/.bashrc2.使用 DNS API 申请证书 (以 Cloudflare 为例,其他服务商类似):
export CF_Key="你的API Key"
export CF_Email="你的邮箱"
~/.acme.sh/acme.sh --issue --dns dns_cf -d home.example.com3.安装证书到 Nginx 目录:
先创建存放目录:
mkdir -p /etc/nginx/ssl执行安装命令(注意:这里的 reloadcmd 是关键,确保证书自动更新后 Nginx 会重载):
~/.acme.sh/acme.sh --install-cert -d home.example.com \
--key-file /etc/nginx/ssl/key.pem \
--fullchain-file /etc/nginx/ssl/cert.pem \
--reloadcmd "systemctl reload nginx"第三步:安装并配置 Nginx
1.安装 Nginx:
apt update
apt install nginx -y2.创建 Headscale 的 Nginx 配置:
创建文件 /etc/nginx/sites-available/headscale:
# 定义上游 Headscale 地址(Websocket 需要)
map $http_upgrade $connection_upgrade {
default keep-alive;
'websocket' upgrade;
'' close;
}
server {
# 监听 12345 端口,开启 SSL
listen 12345 ssl;
http2 on;
server_name home.example.com;
# SSL 证书路径
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# SSL 优化配置(可选,增强安全性)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
# 代理到本地 Headscale
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
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 X-Forwarded-Proto $scheme;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}3.启用配置并验证:
# 建立软链接启用站点
ln -s /etc/nginx/sites-available/headscale /etc/nginx/sites-enabled/
# 删除默认配置(如果占用了端口或导致冲突)
rm /etc/nginx/sites-enabled/default
# 检查语法是否正确
nginx -t如果看到 syntax is ok 和 test is successful,继续下一步。
4.重启 Nginx:
systemctl restart nginx第四步:验证
ss -tulnp | grep 55555
# 应该看到 nginx 在监听,而不是 headscale第五步:部署与配置 Headscale (Ubuntu)
1.下载并安装:
wget --output-document=/usr/local/bin/headscale \
https://github.com/juanfont/headscale/releases/download/v0.28.0/headscale_0.28.0_linux_amd64
chmod +x /usr/local/bin/headscale2.配置 Headscale:
mkdir -p /etc/headscale
mkdir -p /var/lib/headscale
touch /var/lib/headscale/db.sqlite
nano /etc/headscale/config.yamlconfig.yaml
# 外部访问地址
server_url: https://home.example.com:12345
# 监听地址 (配合 Nginx,只监听本地)
listen_addr: 127.0.0.1:8080
# 监控与GRPC地址 (保持默认即可)
metrics_listen_addr: 127.0.0.1:9090
grpc_listen_addr: 127.0.0.1:50443
grpc_allow_insecure: false
# 噪声协议私钥
noise:
private_key_path: /var/lib/headscale/noise_private.key
# IP 前缀
prefixes:
v4: 100.64.0.0/10
v6: fd7a:115c:a1e0::/48
# 数据库配置
database:
type: sqlite3
sqlite:
path: /var/lib/headscale/db.sqlite
write_ahead_log: true
# 日志配置
log:
level: info
format: text
# DNS 配置 (新版格式)
dns:
magic_dns: true
base_domain: example.com
nameservers:
global:
- 10.0.0.254 # DNS Server
- 223.5.5.5
search_domains: []
extra_records: []
# Unix Socket
unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
# OIDC 登录
oidc:
issuer: ""
client_id: ""
client_secret: ""
# 必须禁用内置 TLS
tls_letsencrypt_hostname: ""
tls_client_auth_mode: disabled
tls_cert_path: ""
tls_key_path: ""
derp:
server:
enabled: false
urls:
- https://controlplane.tailscale.com/derpmap/default
paths: []
auto_update_enabled: true
update_frequency: 24h3.创建 Systemd 服务:
vim /etc/systemd/system/headscale.service
[Unit]
Description=headscale controller
After=network.target
[Service]
WorkingDirectory=/etc/headscale
ExecStart=/usr/local/bin/headscale serve
Restart=always
RestartSec=3
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target4.启动服务:
systemctl enable headscale
systemctl start headscale
systemctl status headscale
# 验证端口监听
ss -tulnp | grep 123455.创建用户:
headscale users create myhome第六步:配置 Ubuntu 为出口节点 (Exit Node)
现在 Headscale 已经运行,我们需要在同一台机器 (10.0.0.99) 上安装 Tailscale 客户端,并让它把自己变成一个路由器。
1.开启内核转发 (IP Forwarding):
echo 'net.ipv4.ip_forward = 1' | tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.d/99-tailscale.conf
sysctl -p /etc/sysctl.d/99-tailscale.conf2.安装 Tailscale:
curl -fsSL https://tailscale.com/install.sh | sh3.接入 Headscale 并广播路由:
这是最关键的一步。需要告诉 Headscale:这台机器是一个出口节点,并且可以访问 10.0.0.0/24 网段。
tailscale up \
--login-server=https://home.example.com:12345 \
--advertise-routes=10.0.0.0/24 \
--advertise-exit-node \
--accept-routes此时终端会显示一个认证链接,访问链接,根据内容在服务器中批准。
4.在 Headscale 端查看已批准机器与路由:
headscale nodes list查看可用路由列表
headscale nodes list-routes开启可用路由
headscale nodes approve-routes -i 1 -r "0.0.0.0/0"
headscale nodes approve-routes -i 1 -r "::/0"当可用路由列表中Approved中有刚刚添加的,说明已生效
第七步:客户端连接
- iOS/Android:
在 App 的设置里找到Use Alternate Server或Login URL,填入: https://home.example.com:12345 - Windows:
管理员权限运行 CMD
tailscale login --login-server https://home.scxu.cc:55555 - macOS:
defaults write io.tailscale.ipn.macsys ControlURL https://home.example.com:12345



































































































































