# Headscale 操作手冊 ## 節點管理 ### 查看節點狀態 ```bash # 列出所有節點 headscale nodes list # JSON 格式輸出(含標籤) headscale nodes list --output json | jq '.[] | {id, name, tags: .forced_tags}' # 查看節點路由 headscale nodes list-routes ``` ### 節點操作 ```bash # 重新命名節點 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 ``` ### 節點標籤管理 ```bash # 給節點加上 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 "" ``` ### 路由管理 ```bash # 批准路由(讓節點提供路由給其他節點) 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) ```bash # 產生 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 金鑰管理 ```bash # 列出 API 金鑰 headscale apikeys list # 撤銷 API 金鑰 headscale apikeys revoke # 使用腳本創建 API 金鑰 ./create_headscale_api_key.sh ``` ## 使用者管理 ```bash # 查看所有使用者 headscale users list # 重新命名使用者(namespace) headscale users rename --identifier 1 --new-name mainnet ``` ## 設備連接流程 ### 完整流程 1. **產生預授權金鑰** ```bash headscale preauthkeys create \ --user 1 \ --reusable \ --ephemeral=false \ --expiration 87600h ``` 2. **設備連接** ```bash tailscale up --login-server https://headscale.lotimmy.com --auth-key <金鑰> ``` 3. **註冊節點** ```bash headscale nodes register --user mainnet --key <設備返回的金鑰> ``` 3. **配置標籤和路由** ```bash # 添加標籤 headscale nodes tag --identifier --tags tag:server # 批准路由(如果需要) headscale nodes approve-routes --identifier --routes 0.0.0.0/0,::/0 ``` ## Exit Node 配置 ### 作為 Exit Node ```bash tailscale up --reset \ --login-server https://headscale.lotimmy.com \ --advertise-exit-node \ --advertise-routes=192.168.42.0/24 \ --accept-routes=false ``` ### 使用 Exit Node ```bash # 指定 Exit Node tailscale up --exit-node=<節點名稱或 IP> # 使用特定節點的路由 tailscale up --exit-node=<節點名稱> --accept-routes ``` ## 備份與還原 ### 自動備份 ```bash # 執行自動備份 ./headscale_backup_and_restore.sh ``` ### 手動備份 ```bash # 停止服務 make down # 建立備份 tar czvf headscale_backup_$(date +%Y%m%d_%H%M%S).tar.gz . # 重新啟動服務 make up ``` ### 備份驗證 備份腳本會自動: 1. 停止服務 2. 建立壓縮檔 3. 計算資料庫 MD5 檢查碼 4. 重啟服務 5. 複製到遠端備份伺服器 6. 驗證遠端備份完整性 ## 日誌監控 ### 服務日誌 ```bash # 查看 Tail 日誌 make logs # 進入容器檢查 make exec # 實時監控 make logs -f ``` ### API 健康檢查 ```bash # API 檢查腳本 ./api_user_request.sh # 手動檢查 API curl -s https://headscale.lotimmy.com:8080/v1/metrics | head -n 10 ``` ### 系統監控 ```bash # 查看 Docker 事件 docker events --filter name=headscale # 檢查容器資源使用 docker stats headscale ``` ## 網路測試 ### 內部連通性測試 ```bash # 測試內部節點連通性 tailscale ping 100.64.0.4 tailscale ping <節點名稱> # 查看 tailnet 網路狀態 tailscale status # 測試路由 tailscale ping <內網 IP> ``` ### DNS 測試 ```bash # 測試 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`。 **診斷**: ```bash docker inspect headscale --format 'Status={{.State.Status}} RestartCount={{.RestartCount}}' docker logs --tail 20 headscale # 找 FATAL 那行,會指出是哪個設定鍵 ``` **修復**:依日誌把被移除的鍵在 `config/config.yaml` 註解掉(或依新版語法遷移),再重建容器: ```bash 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 標籤改為手動升級,避免破壞性更新自動套用(見「日常維護」)。 #### 設備無法連接 1. **檢查服務狀態** ```bash make ps make logs ``` 2. **檢查預授權金鑰** ```bash headscale preauthkeys list --user 1 ``` 3. **檢查防火牆** ```bash # 檢查端口 netstat -tlnp | grep 8080 netstat -tlnp | grep 9090 netstat -tlnp | grep 50443 ``` #### 節點顯示離線 1. **檢查 WireGuard 連接** ```bash wg show ``` 2. **重啟節點** ```bash tailscale down tailscale up ``` 3. **檢查系統日誌** ```bash journalctl -u tailscale -f ``` #### 路由無法使用 1. **確認節點標籤** ```bash headscale nodes list --output json | jq '.[] | {id, name, tags: .forced_tags}' ``` 2. **確認路由批准** ```bash headscale nodes list-routes ``` 3. **檢查 ACL 政策** ```bash headscale policy check ``` #### DNS 問題 1. **檢查 MagicDNS** ```bash nslookup <節點名稱>.internal.lotimmy.com ``` 2. **檢查 DNS 伺服器** ```bash curl -s https://dns.nextdns.io/health ``` 3. **重啟 DNS 服務** ```bash systemctl restart systemd-resolved ``` ### 緊急處理 #### 服務無法啟動 ```bash # 檢查配置檔案 headscale config check # 檢查 Docker 日誌 make logs # 清理 Docker 資源 make clean make up ``` #### 資料庫損壞 1. **停止服務** ```bash make down ``` 2. **從備份還原** ```bash # 恢復備份檔案 tar xzvf headscale_backup_xxxx.tar.gz # 重新啟動 make up ``` 3. **驗證資料** ```bash headscale nodes list ``` ## 日常維護 ### 每日檢查清單 - [ ] 檢查服務狀態:`make ps` - [ ] 查看日誌錯誤:`make logs` - [ ] 檢查連接節點數:`headscale nodes list | wc -l` - [ ] 執行 API 檢查:`./api_user_request.sh` - [ ] 檢查備份狀態(如果設定自動) ### 每週維護 - [ ] 備份驗證測試 - [ ] 檢查磁碟空間 - [ ] 更新 Docker 映像:`docker pull headscale/headscale:latest` > ⚠️ 升級前先看 [CHANGELOG](https://github.com/juanfont/headscale/blob/main/CHANGELOG.md) 的 BREAKING 段落,確認沒有被移除的設定鍵;建議釘版本而非用 `:latest` 自動更新(參見「故障排除 → 升級後容器無限重啟」)。 - [ ] 檢查系統資源使用 - [ ] 清理舊的日誌檔案 ### 每月維護 - [ ] 更新系統軟體 - [ ] 重新審核 API 金鑰 - [ ] 測試災難還原流程 - [ ] 更新 ACL 政策 - [ ] 檢查安全性設定