Beszel 是一套 MIT 授權的開源伺服器監控,用「Hub + Agent」兩件元件做出主機 CPU/記憶體/磁碟/網路、Docker 容器、S.M.A.R.T. 硬碟健康與網路探測的長時間歷史圖表,外加可自訂門檻的告警。實測 Hub 容器閒置只吃約 11 MB 記憶體、映像檔 47.6 MB,適合那種「只想要一張看得懂的儀表板」而不是一整套觀測平台的場合。
為什麼還需要第三種監控工具
自架圈對監控的選擇長期卡在兩個極端:
| 痛點 | 實際狀況 |
|---|---|
| Uptime Kuma 只看「有沒有活」 | 網站掛了會通知,但「CPU 連續三小時 95%」「硬碟剩 8%」「某個容器記憶體一直漲」這類慢性問題它不管你 |
| Prometheus + Grafana 太重 | 要 node_exporter、cAdvisor、Prometheus、Grafana 四件以上,設定檔、retention、面板 JSON 都要自己顧;小專案常常裝完就放在那裡吃資源 |
| 雲端監控要月費 | 主機數量一多,基本方案很容易超過一台 VPS 的錢,而且 agent 會回傳內網資訊 |
| 只想看歷史趨勢 | 很多工具只給「即時」與「最近 1 小時」,要回答「上週改設定後記憶體有沒有降」就得另外拉資料 |
Beszel 的定位就在中間:一個容器 + 一支 agent,資料落在自己的機器,圖表預設就有歷史區間,告警用現成的通知服務(Shoutrrr URL),不用學 PromQL。
一表看懂:規格與實測數字
以下數據分兩類標明:官方標示(GitHub/官方文件)與 本文實測(2026-10-31,在一台 Docker 主機上以獨立容器跑起來量測)。
| 項目 | 內容 | 來源 |
|---|---|---|
| 授權 | MIT | 官方(GitHub API) |
| GitHub 星數 | 26,731 | 官方,2026-10-31 查詢 |
| 最新版本 | v0.21.1(2026-10-22 發布) | 官方 release |
| 語言 | Go(單一靜態執行檔) | 官方 |
| 架構 | Hub(PocketBase 後端)+ Agent | 官方文件 |
| Hub 映像檔 | 47.6 MB | 本文實測 docker images |
| Agent 映像檔 | 15.6 MB | 本文實測 docker images |
| Hub 閒置記憶體 | 11.2 MiB | 本文實測 docker stats |
| Agent 常駐記憶體 | 約 15.2 MB(RSS);執行檔 10.68 MB | 本文實測 ps |
| 健康檢查端點 | GET /api/health → {"message":"API is healthy.","code":200} | 本文實測 HTTP 200 |
| 資料存放 | 單一目錄 ./beszel_data(內含 PocketBase 資料庫) | 官方文件 |
需要說明的是:Agent 的記憶體數字來自直接執行官方 Linux 執行檔(v0.21.1,amd64),不是容器內量測;docker stats 對 network_mode: host 的容器會顯示 0B,這是 Docker 本身的顯示限制,不是 agent 不耗資源。
架構:兩個元件、三種連線方式
| 元件 | 角色 | 你在哪裡看到它 |
|---|---|---|
| Hub | 網頁儀表板與資料庫(PocketBase)。負責帳號、系統清單、警報規則、通知設定 | http://你的主機:8090(後台管理在 /_/) |
| Agent | 跑在被監控主機上,收集指標並回傳 | 沒有介面,只有 log |
Hub 與 Agent 之間有三種連線方式,選哪一種會影響防火牆設定:
| 方式 | 設定方式 | 適用場景 |
|---|---|---|
| Unix socket | Agent 的 LISTEN 指向共享 volume 裡的 socket 檔(Hub 與 Agent 同一台) | 單機自架,最省事、不開任何 port |
| WebSocket | Agent 設 HUB_URL + TOKEN,主動連回 Hub | 被監控主機在 NAT/防火牆後面,無法被連入 |
| SSH | Hub 主動連 Agent 的 45876 埠 | 內網多主機、已有 SSH 金鑰管理 |
其中 WebSocket 這條路是清理防火牆最有效的一招:Agent 往外連,Hub 不需要主動打進來。Hub 端可設 DISABLE_SSH=true,讓它不再對沒有 WebSocket 連線的系統反覆撥號。
安裝:官方 compose 原文照貼
官方提供三份 compose 範本(supplemental/docker/ 目錄下):hub 單獨、agent 單獨、同一台主機兩者一起。以下是最常見的「同一台主機」版本,內容與官方檔案一致,只把埠號與容器名改成實測時使用的值:
services:
beszel:
image: henrygd/beszel:latest
container_name: beszel
restart: unless-stopped
environment:
APP_URL: http://localhost:8090 # 改成你實際使用的網域或 IP:port
ports:
- 8090:8090
volumes:
- ./beszel_data:/beszel_data
- ./beszel_socket:/beszel_socket
beszel-agent:
image: henrygd/beszel-agent:latest
container_name: beszel-agent
restart: unless-stopped
network_mode: host
volumes:
- ./beszel_agent_data:/var/lib/beszel-agent
- ./beszel_socket:/beszel_socket
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
LISTEN: /beszel_socket/beszel.sock
HUB_URL: http://localhost:8090
TOKEN: <token> # 從 Hub 的「Add System」對話框取得
KEY: "<key>" # 同上
啟動前先驗語法,再跑起來:
docker compose config --quiet && echo OK
docker compose up -d
docker compose ps
實測啟動後的 Hub log 會印出三個位置,記下來會省下不少找路時間:
Server started at http://0.0.0.0:8090
├─ REST API: http://0.0.0.0:8090/api/
└─ Dashboard: http://0.0.0.0:8090/_/
/_/ 是 PocketBase 原生後台(資料表層級),/ 是 Beszel 自己的儀表板。多數操作在前者之外的前端完成,/_/ 只在需要直接看資料表或改使用者時用。
驗證服務真的活著:
curl -s http://localhost:8090/api/health
# {"message":"API is healthy.","code":200,"data":{}}
加入第一台主機(Hub 與 Agent 同機)
- 開
http://你的主機:8090,建立管理員帳號。 - 點右上角 Add System,Host/IP 填 socket 路徑
/beszel_socket/beszel.sock。 - 對話框會給你
KEY與TOKEN,貼回 compose 的環境變數,docker compose up -d重啟 agent。 - 表格上的系統狀態變成綠色,就代表資料開始進來。
這一步有一個容易誤解的錯誤訊息。若 agent 在還沒拿到 KEY 之前就啟動,log 會直接報:
Failed to load public keys: no key provided: must set -key flag, KEY env var, or KEY_FILE env var
這不是映像檔壞了,而是設計如此:KEY 一定要先在 Hub 端建立系統後才會產生,順序反了 agent 就起不來。遠端主機(WebSocket)情境也一樣,只是改成把 HUB_URL 指向 Hub 的公開位址、LISTEN 改成 45876。
另外,0.12.0 之後支援「通用權杖(universal token)」:在 Hub 的 /settings/tokens 建一組權杖,agent 端只帶 TOKEN 就能註冊,不必事先在 UI 建系統。大量部署時比一台一台點快很多。
它到底收哪些資料
| 類別 | 內容 |
|---|---|
| 主機 | CPU、記憶體(含 swap 與 ZFS ARC)、磁碟使用率、磁碟 I/O、網路流量、負載、溫度、風扇轉速 |
| 容器 | 每個 Docker/Podman 容器的狀態、CPU、記憶體、網路用量歷史 |
| 硬碟健康 | S.M.A.R.T. 屬性、eMMC 壽命、Linux mdraid 陣列狀態、硬碟故障通知 |
| ZFS | 池容量、使用率、健康狀態、I/O、scrub 進度、各 dataset 用量 |
| GPU | NVIDIA、AMD、Intel 的使用率與功耗(需對應映像或 collector 設定) |
| 網路探測 | ICMP/TCP/HTTP/DNS 的延遲與封包遺失(Agent 0.20.0 以上) |
Docker 容器資料要掛 /var/run/docker.sock(唯讀即可)。不想讓 Beszel 去查各 registry 有沒有新映像,可設 agent 的 DOCKER_IMAGE_CHECK=false;容器太多太雜,可用 EXCLUDE_CONTAINERS="test-*,*-staging" 這種 wildcard 規則排除。
告警:用 Shoutrrr URL,不用寫程式
Beszel 的通知不吃自訂 webhook JSON,而是用 Shoutrrr 的 URL schema。常用幾個:
| 服務 | URL 格式 |
|---|---|
| ntfy | ntfy://:存取權杖@你的ntfy主機/主題名 |
| Telegram | telegram://bot_token@telegram?chats=@頻道或chat_id |
| Discord | discord://token@id |
| Slack | slack://[botname@]token-a/token-b/token-c |
| Gotify | gotify://主機/token |
| 通用 HTTP | generic://example.com?template=json |
設定位置在 Settings → Notifications,警報門檻則在系統那一列的 alerts 面板逐項打開(CPU、記憶體、磁碟、溫度、頻寬、容器狀態等)。門檻是「超過就通知、回到門檻以下就自動解除」,不用自己寫狀態機。
以台灣最常見的組合來說,一條 ntfy://:tk_xxxx@ntfy.example.com/beszel 就能同時推到手機與桌面,自架 ntfy 的完整設定可以看站內另一篇教學(見文末延伸閱讀)。
反向的監控:heartbeat(死人開關)
如果 Beszel 主機自己掛了,它沒辦法通知你。Hub 支援 HEARTBEAT_URL:定期對外部服務(Healthchecks.io、BetterStack、Uptime Kuma 的 push 端點)發 ping,對方收不到就報警。用 POST 時還會附上狀態摘要:
{
"status": "error",
"systems": { "total": 5, "up": 3, "down": 1, "paused": 1, "pending": 0 },
"msg": "1 system(s) down: Production-DB"
}
這個設計很實用:等於用一個免費的外部服務,幫你的自架監控買保險。
網路監控:從每台主機的視角量延遲
0.20.0 之後,Agent 可以主動探測你指定的目標,全部在 Hub UI 設定(沒有 agent 環境變數):
| 協定 | 量什麼 | 逾時 | 算遺失的條件 |
|---|---|---|---|
icmp | echo 往返時間(IPv4/IPv6) | 3 秒 | 沒回應 |
tcp | 建立連線的時間(不含 DNS) | 3 秒 | 連不上或逾時 |
http | GET 到回應的時間 | 10 秒 | 失敗或狀態碼 ≥ 400 |
dns | 解析主機名的時間 | 3 秒 | 查不到 |
ICMP 需要 CAP_NET_RAW 或 root;容器內若削掉了 capabilities,要在 compose 補 cap_add: [NET_RAW]。tcp/http/dns 不需要特權。
實務上這一欄最好用的是「從不同機器看同一個服務」:例如從台北與東京兩台 VPS 同時打自家 API,延遲曲線分開畫,問題是線路還是服務立刻分得出來。
與同類方案的定位差異
| 工具 | 主要回答的問題 | 安裝元件數 | 歷史資料 | 適合誰 |
|---|---|---|---|---|
| Beszel | 這幾台機器的資源與容器用量隨時間怎麼變 | 2(Hub+Agent) | 內建,圖表可切時間區間 | 1~20 台自架主機、想一次看到全部 |
| Uptime Kuma | 這個服務現在活著嗎、多久沒回應 | 1 | 有(可用性為主) | 只要「掛了通知我」 |
| Netdata | 這台機器每一秒發生了什麼 | 1(每台) | 有,但存檔與長期保留要另外規劃 | 單機即時除錯 |
| Prometheus + Grafana | 任意指標的自訂查詢與長期儲存 | 4 以上 | 有,需規劃 retention | 指標要做為正式 SLO、已有團隊維護 |
| Beszel +(可選)Loki | 資源趨勢 + 日誌檢索 | 3 以上 | 分工明確 | 想要「數字與 log 對照」的自架者 |
一句話選法:要可用性通知選 Uptime Kuma;要資源趨勢與容器歷史選 Beszel;要自訂指標查詢與告警規則選 Prometheus 堆疊。
已知限制與本文沒做的事
這是本站產品文的固定段落,把驗證邊界講清楚:
- 本文實測到的:官方 compose 能直接啟動、Hub
/api/health回 200、Hub 閒置記憶體 11.2 MiB、映像檔大小、Agent 執行檔可啟動並偵測到磁碟與網路介面、未設 KEY 時的錯誤訊息。 - 本文沒有實際點完的:因為在無圖形介面的環境驗證,「Add System」對話框那一步沒有實際點擊,所以系統轉綠、容器統計曲線、S.M.A.R.T. 讀值、告警實際送達都沒有截圖級證據。這些步驟在官方文件中有完整說明,但請把它們當成「依官方文件轉述」而非實測結果。
- 沒有測到的規模:只驗證單機兩容器。數十台主機時的 Hub 負載、資料庫成長速度未測。
- 它不做的事:不收集日誌(沒有 log 搜尋,要日誌請搭 Loki 或同類方案)、不做分散式 tracing/APM、不是秒級即時面板(設計取向是資源趨勢,不是即時除錯)。
- 備份還是要自己顧:Hub 內建「自動備份到本機或 S3 相容儲存」的功能,但備份排程、還原演練屬於站主要自己負責的維運工作;
./beszel_data一定要備。 - 通知服務本身也要活著:告警是透過外部服務送出的,若 ntfy/Telegram 掛了,你不會知道系統掛了——所以 heartbeat 那條對外 ping 建議一起設。
誰適合、誰不需要
| 情境 | 建議 |
|---|---|
| 3~10 台 VPS/家用伺服器,想知道資源趨勢 | 適合,兩個容器就結束 |
| 想監控硬碟健康、提早換硬碟 | 適合,S.M.A.R.T. 與 eMMC 壽命都有 |
| 只需要網站 200 檢查 | 用 Uptime Kuma 就夠,Beszel 反而多一層 |
| 已經有 Prometheus + Grafana 在跑 | 不需要重複投資,除非想要更低維運成本的第二套視角 |
| 需要 log 搜尋與 trace | 不是它的工作,搭配 Loki/Tempo 類方案 |
| 團隊要正式 SLO 與 on-call 流程 | Prometheus 堆疊或商用方案更合適 |
怎麼開始
mkdir -p ~/beszel && cd ~/beszel
# 貼上上面的 compose(或官方 supplemental/docker/same-system/docker-compose.yml)
docker compose config --quiet && docker compose up -d
curl -s http://localhost:8090/api/health
三步就能看到儀表板。真正花時間的通常是告警門檻要不要設得合理——建議前兩週先只開「磁碟使用率」與「系統離線」兩條,等累積出自己的正常值區間,再開 CPU 與記憶體,避免一開始就被誤報淹沒。
站內延伸閱讀
- Uptime Kuma 完整教學 2026:自架網站可用性監控
- Grafana + Prometheus + Loki 自架監控堆疊完整教學
- ntfy 完整教學 2026:35K 星自架推播通知
- Docker Compose 完整教學 2026
參考來源
- Beszel 官方文件:What is Beszel?
- Beszel 官方文件:Getting Started
- Beszel 官方文件:Environment Variables
- Beszel 官方文件:Notifications(Shoutrrr)
- Beszel 官方文件:Network Monitoring
- GitHub:henrygd/beszel
利益揭露:本文無聯盟連結,也未接受 Beszel 專案任何形式的贊助。文中標示「實測」的數字皆為 2026-10-31 在單一 Docker 主機上量測所得,版本與數字以官方頁面當下顯示為準。
