剪藏#剪藏#天印 Skyforge

(运维)Tailscale 私有化部署方案——基于 Docker 编排与 Headscale 的全链路指南

2026 年 3 月 17 日1 分钟
分享Twitter / XTelegram微博
(运维)Tailscale 私有化部署方案——基于 Docker 编排与 Headscale 的全链路指南 封面

前言:构建自主可控的“大内网”

在混合办公与家庭私有云盛行的今天,如何打通各个住所、公司与移动端的网络,成为了运维爱好者关注的焦点。相比于依赖公网端口映射的 FRP 方案,VPN(虚拟专用网络) 技术更侧重于网络层的互连,能够实现双向通信与 IP 级互连,安全性更高 。

在众多 VPN 协议中,WireGuard凭借其高性能与极简的内核级实现,成为了目前最先进的选择。然而,原生 WireGuard 配置繁琐,且缺乏中心化的管理面板 。

为此,我们采用了 Tailscale 协议体系,并通过私有化部署 **Tailscale的中继服务器(DERP)以及控制服务器(Headscale),构建一套完全自主、免费且高性能的异地组网方案 **。

(一):部署条件

1.拥有一台带有公网IP的云服务器(2mbps+带宽速率)(1)对于drep服务需要放通一个tcp和一个udp端口,我这里选择10700/tcp,10800/udp。(2)对于headscale服务(包括webui界面)需要放通两个tcp端口,我这里选择9090和9091。PS:drep服务器和headscale服务器可以放在同一个云服务器上。端口 协议 方向 用途
80, 443 TCP 入站 Web 服务、API 接入 (OpenResty、nginx服务)
9090 TCP 入站 WebUI 访问 (如果不配置域名反代)
9091 TCP 入站 仅限调试用
10800 UDP 入站/出站 DERP STUN 服务 (位于 DERP 节点服务器)
10700 TCP 入站 DERP HTTPS 通道 (位于 DERP 节点服务器) 2.持有一个域名(国内需备案)(1)阿里云等域名服务提供厂商都可以,通常10块钱上下一个。(2)国内云服务器使用域名需要备案,如果你是香港或国外的云服务器通常不需要备案。

3.安装docker和docker compose

这里推荐github上非常火的一键换源项目:Linuxmirror,这个项目可以帮我们一键安装和更新docker的镜像源(国内云服务器推荐使用国内镜像源或者会使用魔法也可以直接使用docker hub镜像源):

JAVASCRIPT
#安装docker和换源
bash <(curl -sSL https://linuxmirrors.cn/docker.sh) 
#安装dockercompose组件
sudo apt install -y docker-compose-plugin 

(二):部署项目1.1 headscale的项目目录结构

JAVASCRIPT
/opt/headscale/
├── docker-compose.yaml       # 容器编排文件
├── data/                     # [自动生成] 数据库与密钥存储目录
└── config/                   # 配置文件目录(需手动准备)
    ├── config.yaml           # 主配置文件
    └── derp.yaml             # 自定义 DERP 节点映射表

1.2 域名用途

核心服务 (API) hd.example.com 客户端连接、注册使用的核心地址 (走 HTTPS)
Web 管理面板 ui.example.com 图形化管理界面 (可选,或通过端口访问)
内网基础域名 net.example.com MagicDNS 分配给内网设备的后缀 (建议使用子域名以免冲突)

1.3 docker-compose.yaml配置/opt/headscale/docker-compose.yaml

JAVASCRIPT
version'3.9'
services:
  headscale:
    image: headscale/headscale:latest
    container_name: headscale
    restart: unless-stopped
    command: serve
    volumes:
      - ./config:/etc/headscale
      - ./data:/var/lib/headscale
    ports:
      # 宿主机 9091 映射到容器 8080 (API端口)
      - "9091:8080" 
      # 宿主机 9090 映射到容器 9090 (Metrics端口,可选)
      - "9092:9090"
  headscale-ui:
    image: ghcr.io/gurucomputing/headscale-ui:latest
    container_name: headscale-ui
    restart: unless-stopped
    environment:
      - HTTP_PORT=80
    ports:
      # 宿主机 9090 映射到容器 80 (Web UI端口)
      # OpenResty 反代目标端口(如果给UI单独域名):9090
      - "9090:80"

1.4 config.yaml的配置/opt/headscale/config/config.yaml

JAVASCRIPT
server_url: https://hd.example.com
# 监听所有IP的8080端口(容器内部端口)
listen_addr: 0.0.0.0:8080
# 监控地址
metrics_listen_addr: 0.0.0.0:9090
# gRPC 配置 (通常不需要改动)
grpc_listen_addr: 0.0.0.0:50443
grpc_allow_insecure: false
# 密钥路径 (容器内路径,保持默认)
private_key_path: /var/lib/headscale/private.key
noise:
  private_key_path: /var/lib/headscale/noise_private.key
# IP段分配
prefixes:
  v4: 100.64.0.0/10
  v6: fd7a:115c:a1e0::/48
allocation: sequential
# DERP 配置
derp:
  server:
    # 核心修改:关闭内置DERP,因为您有独立的DERP服务器
    enabled: false 
    region_id: 999
    region_code"headscale"
    region_name"Headscale Embedded DERP"
    stun_listen_addr"0.0.0.0:3478"
  # 屏蔽官方DERP列表,使用纯净私有环境(可选)
  urls: []
  paths:
    - /etc/headscale/derp.yaml
  auto_update_enabled: false
  update_frequency: 24h
# 禁用更新检查
disable_check_updates: true
ephemeral_node_inactivity_timeout: 30m
# 数据库配置
database:
  type: sqlite
  debug: false
  sqlite:
    path: /var/lib/headscale/db.sqlite
    write_ahead_log: true
    wal_autocheckpoint: 1000

# 外部NGINX处理 TLS,容器内部只走 HTTP
acme_url: https://acme-v02.api.letsencrypt.org/directory
acme_email: ""
tls_letsencrypt_hostname: ""
tls_letsencrypt_cache_dir: /var/lib/headscale/cache
tls_letsencrypt_challenge_type: HTTP-01
tls_letsencrypt_listen: ":http"
tls_cert_path: "" 
tls_key_path: ""
# 日志
log:
  level: info
  format: text
# 策略模式
policy:
  mode: file
  path""
# DNS 配置
dns:
  magic_dns: true
  base_domain: ts.net
  # nameservers配置
  nameservers:
    global:
      - 223.5.5.5
      - 223.6.6.6
  search_domains: []
  extra_records: []
unix_socket: /var/run/headscale/headscale.sock
unix_socket_permission: "0770"
logtail:
  enabled: false
randomize_client_port: false

1.5 derp.yaml的配置/opt/headscale/config/derp.yamlPS:关于derp的配置下面会讲。

JAVASCRIPT
regions:
  901:
    regionid901
    regioncode: derp1_code
    regionname: derp1
    nodes:
      - name: bz1
        regionid901
        hostname: derp1.example.com
        derpport10700
        stunport10800
        stunonlyfalse
  902:
    regionid902
    regioncode: drep2_code
    regionname: drep2
    nodes:
      - name: ali1
        regionid902
        hostname: derp2.example.com
        derpport10700   
        stunport10800 
        stunonlyfalse

1.6 反向代理配置

因为我的方案将TLS等加密认证都分配给了外部的nginx(用的是1panel面板的openresty)。

使用openresty配置反向代理:

Notion image

修改hd.example.com域名的反向代理配置文件:hd.example.com域名一定要修改成自己的域名

JAVASCRIPT
server {
    listen 80;
    listen 443 ssl;
    server_name hd.example.com;
    index index.php index.html index.htm default.php default.htm default.html;
    access_log /www/sites/hd.example.com/log/access.log main;
    error_log /www/sites/hd.example.com/log/error.log;

    location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md) {
        return 404;
    }
    location ^~ /.well-known/acme-challenge {
        allow all;
        root /usr/share/nginx/html;
    }
    if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
        return 403;
    }

    root /www/sites/hd.example.com/index;
    http2 on;

    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }

    ssl_certificate /www/sites/hd.example.com/ssl/fullchain.pem;
    ssl_certificate_key /www/sites/hd.example.com/ssl/privkey.pem;
    ssl_protocols TLSv1.3 TLSv1.2;
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    error_page 497 https://$host$request_uri;
    proxy_set_header X-Forwarded-Proto https;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

    location / {
        proxy_pass http://127.0.0.1:9091;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header 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;

        add_header 'Access-Control-A
JAVASCRIPT
llow-Origin' '*' always;
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

        if ($request_method = 'OPTIONS') {
            return 204;
        }
    }
}

如果使用Nginx或者NPM做反向代理的可以将我的配置文件甩给AI询问方法即可。

1.7 运行容器编排在/opt/headscale这个路径下运行:

JAVASCRIPT
cd /opt/headscale
docker compose up -d

在查看docker是否运行成功

JAVASCRIPT
docker ps -n2

Notion image

在使用docker logs验证headscale容器内是否正常

JAVASCRIPT
docker logs headscale

Notion image

看到监听端口信息后可以确定容器正常运行1.8 登录配置headscale(1)浏览器地址输入hdui.example.com(你自己的网址)

Notion image

看到这里就说明headscale部署成功了(2)去服务器中输入命令

JAVASCRIPT
docker exec headscale headscale apikeys create --expiration 9999d

得到一个密钥信息(一定要保存好)

Notion image

(3)点击图片右侧settings按钮保存headscale服务器信息

Notion image

之后进入到User view界面,点击+New User

Notion image

名称自定义,例如admin,创建好后点击对勾

Notion image

这样用户就创建好了。到目前为止,Headscale服务器+Headscale的WebUI我们就搭建完成了,接下来搭建DERP服务器。2.1 DERP服务的项目目录结构

JAVASCRIPT
/opt/derp/
├── docker-compose.yaml       # 下方的编排文件
└── certs/                    # 证书存放目录
    ├── fullchain.pem         # 域名证书公钥
    └── privkey.pem           # 域名证书私钥

如果没有申请TLS证书,可以忽略掉存放证书的certs,建议还是使用1panel申请TLS证书用于HTTPS加密。我这里以使用HTTPS加密的配置为例。2.2 上传证书并配置docker-compose.yaml申请好的证书下载证书文件,解压后可以获得两个文件

JAVASCRIPT
fullchain.pem
privkey.pem

将这个两个文件一同上传到certs目录下。编辑/opt/derp下的docker-compose.yaml文件

JAVASCRIPT
version'3.8'
services:
  derper:
    image: hausen1012/ip_derper
    container_name: derper
    restart: always
    ports:
      - "10700:10700"      # DERP 端口 (TCP)
      - "10800:10800/udp"  # STUN 端口 (UDP)
    volumes:
      # 将当前目录下的证书映射为容器内识别的格式 (文件名需对应域名)
      - ./certs/fullchain.pem:/app/certs/derp.example.com.crt:ro
      - ./certs/privkey.pem:/app/certs/derp.example.com.key:ro
    command: >
      /app/derper 
      -hostname example.com 
      -a :10700 
      -stun-port 10800
      -http-port -1 
      -certmode manual 
      -certdir /app/certs

2.3 运行容器编排在/opt/headscale这个路径下运行:

JAVASCRIPT
cd /opt/headscale
docker compose up -d

在查看docker是否运行成功

JAVASCRIPT
docker ps -n1

登录https://drep.example.com:10700

Notion image

如果没有配置证书的话输入http://derp.example.com:10700

Notion image

看到这个两个页面都代表DERP服务器已经正常启动成功了不要忘记将/headscale/config/derp.yaml中的域名替换为你自己的域名(三):配置Tailscale客户端1.下载tailscale客户端下载网址https://tailscale.com/download注意:这个下载网址有时候需要科学上网。

Notion image

2.配置tailscale客户端,我以Windows客户端为例(其他系统客户端配置流程都一样)

Notion image

这样表示tailscale安装成功了(1) win+R 输入CMD进入命令提示符输入

JAVASCRIPT
tailscale up --login-server=https://hd.example.uno

Notion image

(2)看到出现这串网址后,复制网址到浏览器打开后:(3)再次回到hdui.example.com

Notion image

回到配置tailscale的客户端后发现

Notion image

(4)检测tailscale是否正常工作

JAVASCRIPT
tailscale staus      #检测你的tailscale状态
tailscale netcheck   #检测tailscale的网络情况 

Notion image

这样整套的服务DERP中继+Tailscale客户端+headscale服务端就完成了,至于可不可以走p2p连接主要取决于你客户端所在网络的NAT类型和支不支持UDP打洞,但是中继服务器已经搭建完成。

最后将整个组网的流程图放到下方(由于不专业可能有错误或表达不清晰,欢迎指正修改)

Notion image

Notion image

Notion image

原文地址: https://mp.weixin.qq.com/s?__biz=MzY5MjA5NjQ4OQ==&mid=2247483689&idx=1&sn=673d22d8cb5bd862123bbf794a1ffe31&chksm=f5bca8d6917f7cf1775bdc0109cf3608608fa03daafc0807c79aee770da0af0dd76fe1f83b62&mpshare=1&scene=1&srcid=03171QcJ8EXmOaZqLlCeNCEY&sharer_shareinfo=a50764cd26536699683bcc7b0073ff55&sharer_shareinfo_first=a50764cd26536699683bcc7b0073ff55#rd

相关文章