459 lines
10 KiB
Markdown
459 lines
10 KiB
Markdown
# 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 政策
|
||
- [ ] 檢查安全性設定 |