回到所有文章

在 Linux Server 建置 Token Monitor Hub 與 systemd 背景服務

將 Token Monitor 部署到常駐 Linux 主機,設定 Hub、headless agent 與 systemd user service,集中查看多台裝置的 AI 工具用量。

在 Linux Server 建置 Token Monitor Hub 與 systemd 背景服務

文件日期:2026-08-13
適用情境:以一台持續開機的 Linux Server 作為 Token Monitor Hub,並讓沒有桌面介面的 Linux 主機以 headless agent 回報 Codex 等工具的用量。
本文以 Ubuntu/Debian 類系統與一般使用者帳號為例;所有路徑請換成自己的實際位置。

Token Monitor 是一個本機優先的 AI 工具用量監控器。它可讀取 Codex、Claude Code、Cursor、OpenCode 等工具留在本機的紀錄;在多裝置模式下,每台裝置只處理自己的資料,再將彙整結果送往 Hub。Hub 會把最新的彙整狀態推送給已連線的桌面 widget。

這篇文章建立的架構如下:

Linux agent(讀取 ~/.codex 等本機資料) ──┐
桌面 Token Monitor widget ─────────────────┼──> Token Monitor Hub ──> 所有已連線 widget
其他裝置的 agent/widget ──────────────────┘

Token Monitor 不會把 prompt、回應內容或原始程式碼同步到 Hub;同步的是用量彙整資料。仍請把 Hub 與 shared secret 視為內部服務來保護。

先決定哪些主機需要跑什麼

Hub 與 agent 的角色不同:

  • Hub:集中接收與彙整資料;適合放在持續開機、網路穩定的主機上。
  • Headless agent:掃描「該台主機、該登入帳號」的本機紀錄並上傳到 Hub。
  • 桌面 widget:已有 Token Monitor 桌面程式的裝置不必另外跑 agent;在設定頁選擇 Connect to a hub 即可自動回報。

因此,若這台 Linux Server 只用來提供 Hub,只需要建立 Hub service;若它自己也執行 Codex CLI,則再建立 agent service。agent 預設可追蹤所有支援的工具;本文示範只追蹤 Codex。

1. 準備 Node.js 與專案

Token Monitor 原始碼建置需要 Node.js 22.13 以上。先確認版本,再以要執行 service 的同一個帳號下載與安裝專案:

node --version
git clone https://github.com/Javis603/token-monitor.git ~/TokenMonitor/token-monitor
cd ~/TokenMonitor/token-monitor
npm install
cp .env.example .env

node --version 低於需求,先升級 Node.js 後再進行。使用 nvm 沒有問題,但後面的 service 必須明確使用 nvm 安裝的 Node 路徑;systemd 不會讀取互動 shell 的 .bashrc.zshrc

在專案根目錄建立一組 shared secret:

openssl rand -hex 32
nano .env

至少填入:

# Hub 與所有連線裝置都要使用完全相同的值。
TOKEN_MONITOR_SECRET=請貼上剛產生的隨機字串

# 僅當本機也要作為 agent 上傳資料時才需要。
TOKEN_MONITOR_HUB_URL=http://127.0.0.1:17321
TOKEN_MONITOR_DEVICE_ID=linux-server-01
TOKEN_MONITOR_CLIENTS=codex

TOKEN_MONITOR_DEVICE_ID 可省略,預設會使用主機名稱。TOKEN_MONITOR_CLIENTS 也可省略以追蹤所有支援工具;設為 codex 則可減少不需要的掃描。完整可用的環境變數以專案的 .env.example 為準。

.env 包含 secret,請勿提交至 Git,也不要把它貼到 issue、聊天室或截圖中。

2. 先以前景模式驗證 Hub

啟動 Hub:

cd ~/TokenMonitor/token-monitor
npm run hub

另開一個 shell,在同一台主機測試 health endpoint:

curl http://127.0.0.1:17321/api/health

確認回應正常後,按 Ctrl+C 停止前景程序。接著在桌面版 Token Monitor 的 Settings → Multi-device Sync → Connect to a hub,填入 Hub 的可達 URL 與同一組 secret。

若透過 Tailscale、ZeroTier 或公司內網連線,填入該網路上的網址,例如 http://100.x.y.z:17321。不要使用 127.0.0.1,因為它只代表「目前這台」電腦。

3. 將 Hub 設為 systemd user service

先查出 service 需要的實際 Node/npm 路徑:

command -v node
command -v npm

下列範例假設 nvm 的 Node 24 位於 /home/icebird/.nvm/versions/node/v24.15.0/bin,專案放在 /home/icebird/TokenMonitor/token-monitor。請按自己的帳號、Node 版本與專案路徑調整:

mkdir -p ~/.config/systemd/user
nano ~/.config/systemd/user/token-monitor-hub.service
[Unit]
Description=Token Monitor Hub
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=/home/icebird/TokenMonitor/token-monitor
Environment=NODE_ENV=production
Environment=PATH=/home/icebird/.nvm/versions/node/v24.15.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/home/icebird/.nvm/versions/node/v24.15.0/bin/npm run hub
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target

啟用並立刻啟動:

systemctl --user daemon-reload
systemctl --user enable --now token-monitor-hub
systemctl --user status token-monitor-hub

--user service 預設會隨使用者 session 結束而停止。讓它在 SSH 登出後及重新開機後仍可執行:

sudo loginctl enable-linger "$USER"

查看即時日誌:

journalctl --user -u token-monitor-hub -f

4. 讓 Linux 主機也回報自己的 Codex 用量(選用)

若這台 server 的同一個使用者帳號會執行 Codex CLI,agent 才能讀到其 ~/.codex/ 內的 session 紀錄。先以前景模式確認能連上 Hub:

cd ~/TokenMonitor/token-monitor
npm run agent

成功後建立 agent service:

nano ~/.config/systemd/user/token-monitor-agent.service
[Unit]
Description=Token Monitor headless agent
After=network-online.target token-monitor-hub.service
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=/home/icebird/TokenMonitor/token-monitor
Environment=NODE_ENV=production
Environment=PATH=/home/icebird/.nvm/versions/node/v24.15.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/home/icebird/.nvm/versions/node/v24.15.0/bin/npm run agent
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target

套用設定:

systemctl --user daemon-reload
systemctl --user enable --now token-monitor-agent
systemctl --user status token-monitor-agent
journalctl --user -u token-monitor-agent -f

若 agent 位於另一台主機,將那台機器 .envTOKEN_MONITOR_HUB_URL 改成 Hub 的內網或 overlay-network URL,並填入相同的 TOKEN_MONITOR_SECRET;agent service 其他設定相同。不要在 agent 主機執行 npm run hub,除非它也要作為一個獨立 Hub。

5. nvm 與 systemd 使用錯誤 Node 版本的排查

常見症狀是 service 的 ExecStart 指向 nvm 的 npm,但日誌仍顯示舊版系統 Node,例如 Node.js v18.x,並伴隨相依套件載入失敗。

原因是 npm 的啟動流程仍會從 PATH 尋找 node,而 systemd 不會載入你的 nvm shell 設定。解法就是 service 同時指定:

  1. ExecStart 使用 nvm 目錄中的絕對 npm 路徑。
  2. Environment=PATH=... 並把同一個 nvm bin 目錄放在最前面。

修改 unit 後必須重新載入並重啟:

systemctl --user daemon-reload
systemctl --user restart token-monitor-agent
journalctl --user -u token-monitor-agent -n 50 --no-pager

確認日誌中不再出現舊版 Node。若專案不使用 nvm,則把範例中的 nvm 路徑換成 command -v npm 的實際結果,並讓 PATH 優先找到同一套 Node。

6. 網路與維運建議

  • 優先使用內網、Tailscale 或 ZeroTier。 這通常比直接公開 TCP port 17321 安全且易於管理。
  • 若必須跨公開網路連線,請放在 Nginx 或 Caddy 等 reverse proxy 後方,以 HTTPS、嚴格防火牆規則及強 secret 保護;不要直接把 Hub port 裸露到網際網路。
  • Hub、agent 與每個同步 widget 的 TOKEN_MONITOR_SECRET 必須一致。更換 secret 時,所有客戶端都要同步更新。
  • 升級時先停止 service,更新程式與相依套件,再啟動:
cd ~/TokenMonitor/token-monitor
systemctl --user stop token-monitor-hub token-monitor-agent
git pull
npm install
systemctl --user start token-monitor-hub token-monitor-agent
  • 定期以 systemctl --user statusjournalctl --user -u <service> 檢查狀態;若有可用性監控系統,也可以定期查詢 /api/health

完成檢查表

  • Hub service 顯示 active (running)
  • curl http://127.0.0.1:17321/api/health 回應正常。
  • 每台同步裝置的 Hub URL 正確,且使用相同 shared secret。
  • 需要回報 Linux 本機用量的主機,agent service 顯示 active (running)
  • SSH 登出與主機重新啟動後,service 仍會自動恢復。

官方設定細節可參考 ConfigurationToken Monitor README