Files
headscale/OPERATIONS.md
2026-06-21 13:56:52 +08:00

459 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```
**命名規約**:Linux 節點統一用 `ip-<內網IP>`(點改連字號),例如內網 `192.168.42.105``ip-192-168-42-105`。改名只動 headscale 的 `givenName`(`tailscale status` 顯示的名字);節點自報的 `name`(hostname)不受影響。
#### 用 HTTP API 改名(容器不在本機時)
當 headscale 容器不在當前機器、無法 `docker exec` 時,改用公開端點的 API。需要一把有效 API key(過期會回 `401`):
```bash
# 在 headscale 主機產生臨時 key
docker exec headscale headscale apikeys create --expiration 1h
# 查節點 ID(givenName 即顯示名)
curl -s -H "Authorization: Bearer <API_KEY>" \
https://headscale.lotimmy.com/api/v1/node \
| jq '.nodes[] | {id, givenName, name}'
# 改名:POST /api/v1/node/{id}/rename/{newName},成功回 HTTP 200
curl -s -X POST -H "Authorization: Bearer <API_KEY>" \
https://headscale.lotimmy.com/api/v1/node/45/rename/ip-192-168-42-105
```
### 節點標籤管理
```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 <KEY_ID>
# 使用腳本創建 API 金鑰
./create_headscale_api_key.sh
```
## 使用者管理
```bash
# 查看所有使用者
headscale users list
# 重新命名使用者namespace
headscale users rename --identifier 1 --new-name mainnet
```
## ACL 政策管理
政策檔:`config/policy.hujson`(容器內 `/etc/headscale/policy.hujson`),由 `config.yaml``policy.mode: file` + `policy.path` 啟用。
```bash
# 驗證語法(套用前務必先跑)
docker exec headscale headscale policy check --file /etc/headscale/policy.hujson
# 查看目前生效的政策
docker exec headscale headscale policy get
# 修改後套用file 模式於啟動時讀取,需重啟)
make restart
```
> ⚠️ 啟用 policy 後,`acls` 是唯一授權來源。`policy.hujson` 須保留 allow-all`accept * -> *:*`)才能維持全互通,否則節點立即斷線。修改後務必確認 `headscale nodes list` 仍 online 且能 `tailscale ping`。
### Taildrive節點間檔案分享
權限由 policy 控制:`nodeAttrs` 授予 `drive:share` / `drive:access``grants``tailscale.com/cap/drive` 指定 share 範圍與讀寫權限(`rw` / `ro`)。需 headscale v0.29.0+。
```bash
# 分享端Linux/macOS/Windows
tailscale drive share <分享名稱> /要分享的/目錄
tailscale drive list
tailscale drive unshare <分享名稱>
# 存取端Linux 掛 WebDAV
# http://100.100.100.100:8080/<tailnet>/<peer-name>/<分享名稱>
# 確認能力已下發到節點
docker exec tailscale tailscale debug netmap | grep -i drive
```
## 設備連接流程
### 完整流程
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 <id> --tags tag:server
# 批准路由(如果需要)
headscale nodes approve-routes --identifier <id> --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 政策
- [ ] 檢查安全性設定