新版 headscale 移除了部分設定鍵,搭配 watchtower 自動更新 :latest 導致容器啟動即 FATAL、無限重啟,所有節點離線。 - config.yaml: 註解 randomize_client_port(FATAL)與 ephemeral_node_inactivity_timeout(已改名) - docker-compose.yml: image 釘到 v0.29.0,停止破壞性自動升級 - OPERATIONS.md / CLAUDE.md: 補上故障排除與升級注意事項 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8.0 KiB
8.0 KiB
Headscale 操作手冊
節點管理
查看節點狀態
# 列出所有節點
headscale nodes list
# JSON 格式輸出(含標籤)
headscale nodes list --output json | jq '.[] | {id, name, tags: .forced_tags}'
# 查看節點路由
headscale nodes list-routes
節點操作
# 重新命名節點
headscale nodes rename --identifier 2 iphone-15-pro-max
headscale nodes rename --identifier 4 ip-192-168-42-102
# 刪除節點
headscale nodes delete --identifier 6
headscale nodes delete --identifier 6 --force
節點標籤管理
# 給節點加上 server 或 mobile 標籤
headscale nodes tag --identifier 4 --tags tag:server # ct102
headscale nodes tag --identifier 9 --tags tag:server # 15-macbook-pro
headscale nodes tag --identifier 12 --tags tag:server # ip-192-168-88-82
headscale nodes tag --identifier 2 --tags tag:mobile # iphone-15-pro-max
headscale nodes tag --identifier 5 --tags tag:mobile # apple-tv-bedroom
# 移除所有標籤
headscale nodes tag --identifier 13 --tags ""
路由管理
# 批准路由(讓節點提供路由給其他節點)
headscale nodes approve-routes --identifier 4 --routes 0.0.0.0/0,192.168.42.0/24,::/0
headscale nodes approve-routes --identifier 5 --routes 192.168.42.0/24
金鑰管理
預授權金鑰(Pre-auth Keys)
# 產生 10 年期預授權金鑰
headscale preauthkeys create \
--user 1 \
--reusable \
--ephemeral=false \
--expiration 87600h
# 短期金鑰(24 小時)
headscale preauthkeys create --user 1 --reusable --ephemeral=false --expiration 24h
# 列出預授權金鑰
headscale preauthkeys list --user 1
API 金鑰管理
# 列出 API 金鑰
headscale apikeys list
# 撤銷 API 金鑰
headscale apikeys revoke <KEY_ID>
# 使用腳本創建 API 金鑰
./create_headscale_api_key.sh
使用者管理
# 查看所有使用者
headscale users list
# 重新命名使用者(namespace)
headscale users rename --identifier 1 --new-name mainnet
設備連接流程
完整流程
- 產生預授權金鑰
headscale preauthkeys create \
--user 1 \
--reusable \
--ephemeral=false \
--expiration 87600h
- 設備連接
tailscale up --login-server https://headscale.lotimmy.com --auth-key <金鑰>
- 註冊節點
headscale nodes register --user mainnet --key <設備返回的金鑰>
- 配置標籤和路由
# 添加標籤
headscale nodes tag --identifier <id> --tags tag:server
# 批准路由(如果需要)
headscale nodes approve-routes --identifier <id> --routes 0.0.0.0/0,::/0
Exit Node 配置
作為 Exit Node
tailscale up --reset \
--login-server https://headscale.lotimmy.com \
--advertise-exit-node \
--advertise-routes=192.168.42.0/24 \
--accept-routes=false
使用 Exit Node
# 指定 Exit Node
tailscale up --exit-node=<節點名稱或 IP>
# 使用特定節點的路由
tailscale up --exit-node=<節點名稱> --accept-routes
備份與還原
自動備份
# 執行自動備份
./headscale_backup_and_restore.sh
手動備份
# 停止服務
make down
# 建立備份
tar czvf headscale_backup_$(date +%Y%m%d_%H%M%S).tar.gz .
# 重新啟動服務
make up
備份驗證
備份腳本會自動:
- 停止服務
- 建立壓縮檔
- 計算資料庫 MD5 檢查碼
- 重啟服務
- 複製到遠端備份伺服器
- 驗證遠端備份完整性
日誌監控
服務日誌
# 查看 Tail 日誌
make logs
# 進入容器檢查
make exec
# 實時監控
make logs -f
API 健康檢查
# API 檢查腳本
./api_user_request.sh
# 手動檢查 API
curl -s https://headscale.lotimmy.com:8080/v1/metrics | head -n 10
系統監控
# 查看 Docker 事件
docker events --filter name=headscale
# 檢查容器資源使用
docker stats headscale
網路測試
內部連通性測試
# 測試內部節點連通性
tailscale ping 100.64.0.4
tailscale ping <節點名稱>
# 查看 tailnet 網路狀態
tailscale status
# 測試路由
tailscale ping <內網 IP>
DNS 測試
# 測試 MagicDNS
nslookup <節點名稱>.internal.lotimmy.com
# 測試自訂 DNS
dig @1.1.1.1 example.com
故障排除
常見問題
升級後容器無限重啟、所有節點離線(設定鍵被移除)
症狀:所有 tailscale/headscale 節點突然全部連不上;docker ps 顯示 headscale 一直 restarting(RestartCount 持續飆高)。
原因:本服務使用 headscale/headscale:latest 並開啟 watchtower 自動更新,新版可能移除舊設定鍵,使容器一啟動就 FATAL 而陷入重啟迴圈。已知案例:
randomize_client_port(頂層)— FATAL,已移除,改到 policy 檔設定"randomizeClientPort": true。ephemeral_node_inactivity_timeout— WARN,改名為node.ephemeral.inactivity_timeout。
診斷:
docker inspect headscale --format 'Status={{.State.Status}} RestartCount={{.RestartCount}}'
docker logs --tail 20 headscale # 找 FATAL 那行,會指出是哪個設定鍵
修復:依日誌把被移除的鍵在 config/config.yaml 註解掉(或依新版語法遷移),再重建容器:
docker-compose up -d --force-recreate
docker inspect headscale --format '{{.State.Status}} {{.RestartCount}}' # 應為 running / 0
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/health # 應為 200
根治建議:把 image 釘到固定版本(如 headscale/headscale:v0.26.0),或移除 watchtower 標籤改為手動升級,避免破壞性更新自動套用(見「日常維護」)。
設備無法連接
- 檢查服務狀態
make ps
make logs
- 檢查預授權金鑰
headscale preauthkeys list --user 1
- 檢查防火牆
# 檢查端口
netstat -tlnp | grep 8080
netstat -tlnp | grep 9090
netstat -tlnp | grep 50443
節點顯示離線
- 檢查 WireGuard 連接
wg show
- 重啟節點
tailscale down
tailscale up
- 檢查系統日誌
journalctl -u tailscale -f
路由無法使用
- 確認節點標籤
headscale nodes list --output json | jq '.[] | {id, name, tags: .forced_tags}'
- 確認路由批准
headscale nodes list-routes
- 檢查 ACL 政策
headscale policy check
DNS 問題
- 檢查 MagicDNS
nslookup <節點名稱>.internal.lotimmy.com
- 檢查 DNS 伺服器
curl -s https://dns.nextdns.io/health
- 重啟 DNS 服務
systemctl restart systemd-resolved
緊急處理
服務無法啟動
# 檢查配置檔案
headscale config check
# 檢查 Docker 日誌
make logs
# 清理 Docker 資源
make clean
make up
資料庫損壞
- 停止服務
make down
- 從備份還原
# 恢復備份檔案
tar xzvf headscale_backup_xxxx.tar.gz
# 重新啟動
make up
- 驗證資料
headscale nodes list
日常維護
每日檢查清單
- 檢查服務狀態:
make ps - 查看日誌錯誤:
make logs - 檢查連接節點數:
headscale nodes list | wc -l - 執行 API 檢查:
./api_user_request.sh - 檢查備份狀態(如果設定自動)
每週維護
- 備份驗證測試
- 檢查磁碟空間
- 更新 Docker 映像:
docker pull headscale/headscale:latest⚠️ 升級前先看 CHANGELOG 的 BREAKING 段落,確認沒有被移除的設定鍵;建議釘版本而非用
:latest自動更新(參見「故障排除 → 升級後容器無限重啟」)。 - 檢查系統資源使用
- 清理舊的日誌檔案
每月維護
- 更新系統軟體
- 重新審核 API 金鑰
- 測試災難還原流程
- 更新 ACL 政策
- 檢查安全性設定