Homepage 完整教學 2026:自架儀表板、widget 與 Docker 整合

Homepage(gethomepage)是一套 GPL-3.0、GitHub 33,478 星的自架服務儀表板,把散落在十幾個 port 的自架服務收成一頁,內建 165 種 service widget 與 14 種 info widget,能直接顯示 Uptime Kuma、Beszel、Jellyfin 的即時狀態。本文用 Docker Compose 實際跑起 v2.7.0,附完整 YAML 設定、繁中介面、Docker 整合、MCP 端點,以及兩個實測踩到的坑:HOMEPAGE_ALLOWED_HOSTS 回 400、YAML 縮排錯讓 widget 無聲消失。

  • Dennis
  • 10 分鐘閱讀
Homepage 完整教學 2026:自架儀表板、widget 與 Docker 整合

Homepage(gethomepage/homepage)是一套 GPL-3.0 授權、GitHub 33,478 星的自架儀表板:一個 Docker 容器、五個 YAML 檔,就能把 Uptime Kuma、Jellyfin、Paperless、Beszel 這些散在十幾個 port 的服務收成一頁,還能在卡片上直接顯示即時狀態。 本文用 v2.7.0 實測安裝,附繁體中文介面設定、Docker 整合、MCP 端點,以及兩個會讓你卡半小時的坑。

為什麼需要一個「首頁」

自架玩半年之後,你一定遇過這個畫面:瀏覽器書籤列有 20 個分頁,Portainer 在 9443、Uptime Kuma 在 3001、Jellyfin 在 8096、Paperless 在 8000、Beszel 在 8090,還有一堆你上個月才架好、現在已經忘了 port 的服務。

沒有儀表板的痛點Homepage 怎麼解
記不住 port 與網域一頁列出所有服務,點卡片就進去
不知道服務現在活著沒有卡片上直接顯示 running/健康狀態、API 回傳的即時數字
每次都要一個一個登入確認widget 幫你抓狀態、佇列數、下載速度、資源用量
新加的服務沒人知道用 Docker label 自動發現,容器起來就自動出現在儀表板
首頁想要好看一點12 種主題色、多種卡片樣式、背景圖、PWA 支援

它跟 Uptime Kuma、Grafana 的定位完全不同:那兩套回答「有沒有壞」,Homepage 回答「東西在哪、現在怎樣」。三者可以並存,Homepage 當門面,監控系統當後台。

一表看懂:規格與現況

項目內容
專案gethomepage/homepage
GitHub 星數33,478(2026-11-01 以 GitHub API 查詢)
Fork 數2,159
授權GPL-3.0
建立時間2022-08-24
最新版本v2.7.0(2026-10-23 發布)
技術棧Next.js(容器內為 16.4.1)+ Node.js
服務整合(widget)官方文件收錄 165 種 service widget(docs/widgets/services/ 檔案數)
資訊整合(info widget)14 種(資源、搜尋、日期、天氣、股市、Kubernetes…)
容器記憶體實測閒置時 158.7 MiB(docker stats,本機單一容器)
設定方式五個 YAML 檔(settings/services/widgets/bookmarks/docker)
介面語言內建 zh-Hant(繁體中文)
額外能力Docker 自動發現、Kubernetes、Proxmox、MCP 端點、custom.css/js

一句話定位:它是「自架服務的門面」,不是監控系統、不是反向代理、也不是密碼管理器。

Docker Compose 安裝(官方樣板+繁中設定)

官方 Docker 安裝頁的 compose 只有 9 行,這裡直接沿用並補上一個容易漏掉的環境變數:

services:
  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage
    ports:
      - 3000:3000
    volumes:
      - /path/to/config:/app/config        # 本機設定目錄,要先建好
      - /var/run/docker.sock:/var/run/docker.sock:ro   # 選用:Docker 整合
    environment:
      HOMEPAGE_ALLOWED_HOSTS: gethomepage.dev   # 必要,可含 port
    restart: unless-stopped

啟動:

mkdir -p /opt/homepage/config
docker compose up -d
docker logs -f homepage      # 看到 Ready 就可以開 http://你的IP:3000

實測(本機 Docker 29.2.1/Compose v5.1.0):容器啟動約 3 秒進入 healthy,首頁回應 HTTP 200、HTML 約 66 KB,/api/healthcheck 回 up。第一次啟動時 Homepage 會自動把缺少的 kubernetes.yaml 補進設定目錄,日誌會印 kubernetes.yaml was copied to the config folder——不是錯誤,不用理它。

Homepage 儀表板實際畫面:繁體中文介面、四組服務、Docker 整合顯示「健康」、Uptime Kuma widget 因目標未啟動而顯示 API 錯誤

上面這張是本機實測畫面:介面已是繁體中文,頂部資源列顯示 CPU/記憶體/磁碟/開機時間,右下角版本 v2.7.0 (2e5f101, 2026年10月23日)。「本頁容器」卡片右上角的綠色「健康」標籤來自 Docker 整合;Uptime Kuma 那張紅色的「API 錯誤 資訊」則是因為測試機上沒有跑 3001 埠的服務——這正好示範了 widget 失敗時的樣子,後面會教你怎麼查。

五個設定檔的分工

Homepage 的設定全部在 /app/config 底下,各檔職責分明:

檔案負責什麼內容形式
settings.yaml站名、語言、主題、版面配置、是否讓搜尋引擎索引單一 mapping
services.yaml服務分組與服務卡片(href、icon、description、Docker 對應、widget)最外層是陣列
widgets.yaml頁面上方的資訊列(資源、搜尋、日期、天氣)陣列
bookmarks.yaml書籤區(純連結,不帶狀態)陣列
docker.yamlDocker 連線設定(socket 或 HTTP API)mapping
kubernetes.yamlKubernetes 整合(沒有用就留空或別放)mapping

⚠️ 最常見的低級錯誤:services.yaml、widgets.yaml、bookmarks.yaml 的外層是陣列(每行以 - 開頭),settings.yaml、docker.yaml 是單一 mapping(不用 -)。兩種格式互換就會整頁空白。

實測設定:繁中、四組服務、資訊列

settings.yaml(實測可用):

title: 龍潭機房 Dashboard
description: 自架服務總覽
language: zh-Hant        # 繁體中文;zh-CN 會被自動對應成 zh-Hans
theme: dark
color: slate
headerStyle: clean
disableIndexing: true    # 不讓搜尋引擎索引
target: _blank

layout:
  監控與通知:
    style: row
    columns: 4
  多媒體:
    style: row
    columns: 3

services.yaml 片段(實測可用,注意縮排:group → service → 屬性 各進兩格):

- 監控與通知:
    - Uptime Kuma:
        icon: uptime-kuma.png
        href: http://127.0.0.1:3001/
        description: 站台存活監控
        siteMonitor: http://127.0.0.1:3001/
        widget:
          type: uptimekuma
          url: http://127.0.0.1:3001
          slug: main
    - Beszel:
        icon: beszel.png
        href: http://127.0.0.1:8090/
        description: 主機資源監控

widgets.yaml(頁面上方那一排):

- resources:
    cpu: true
    memory: true
    disk: /
    uptime: true
    cpus: true

- search:
    provider: duckduckgo
    target: _blank

- greeting:
    text_size: xl
    text: 龍潭機房

- datetime:
    text_size: xl
    format:
      dateStyle: long
      timeStyle: short
      hour12: false

改完存檔不用重啟,重整瀏覽器就會生效(Homepage 每次請求都會重讀設定)。要驗證設定有沒有被讀進去,不用開瀏覽器:

curl -s http://127.0.0.1:3000/api/services | head -c 500
curl -s http://127.0.0.1:3000/api/widgets  | head -c 300

這兩個端點會回傳解析後的 JSON,服務名稱、icon、description、widget 清單全在裡面。設定有問題時,這裡比畫面更容易看出來(下一節會用到)。

Docker 整合:卡片上直接看容器狀態

這是最值得開的功能。兩個步驟:

第一步,把 socket 掛進容器(唯讀),並在 docker.yaml 指定:

my-docker:
  socket: /var/run/docker.sock

第二步,在服務裡指定 server 與 container:

    - 本頁容器:
        icon: homepage.png
        href: http://127.0.0.1:3999/
        server: my-docker
        container: hp-test

驗證方式(實測輸出):

$ curl -s "http://127.0.0.1:3999/api/docker/statuses?server=my-docker"
{"statuses":{"hp-test":{"status":"running","health":"healthy"}}}

畫面就會出現綠色「健康」標籤,點標籤展開還能看到 CPU/記憶體/網路用量。

安全提醒:把 /var/run/docker.sock 掛進容器等於給容器「看你 Docker 的能力」。官方文件明確建議用 socket proxy 取代直掛:

  dockerproxy:
    image: ghcr.io/tecnativa/docker-socket-proxy:latest
    environment:
      - CONTAINERS=1
      - SERVICES=1
      - POST=0        # 禁止任何寫入操作
    ports:
      - 127.0.0.1:2375:2375
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro

然後 docker.yaml 改成 host: dockerproxy / port: 2375 即可。直掛 socket 時官方也提醒:容器必須以 root 執行。

自動發現:用 Docker label 就不用寫 services.yaml

  emby:
    image: lscr.io/linuxserver/emby:latest
    labels:
      - homepage.group=Media
      - homepage.name=Emby
      - homepage.icon=emby.png
      - homepage.href=http://emby.home/
      - homepage.description=Media server

容器一起來就自動出現在儀表板,連 server/container 都不用填。注意:用 Docker Swarm 時要改寫在 deploy.labels 底下。

兩個實測踩到的坑(會讓你懷疑人生)

坑一:HOMEPAGE_ALLOWED_HOSTS 沒設好 → 整站 400

Homepage 會驗證請求的 Host 標頭,不符就回:

HTTP 400
{"error":"Host validation failed. See logs for more details."}

容器日誌同時給提示:

error: Host validation failed for: evil.example.com.
Hint: Set the HOMEPAGE_ALLOWED_HOSTS environment variable to allow requests from this host / port.

重點在**「host / port 要完全一致」。實測時只把 localhost:3998 放進白名單,結果用 127.0.0.1:3998 連線一樣被擋——因為那被視為不同主機名。所以正式環境要把所有會被用來連線的形式**都列進去:

environment:
  HOMEPAGE_ALLOWED_HOSTS: "home.example.com,192.168.1.10:3000,localhost:3000,127.0.0.1:3000"

這也是為什麼很多人「本機可以開、從別台電腦連就 400」——不是防火牆,是白名單。反向代理後面記得放對外網域那一個。

坑二:YAML 縮排錯一格 → widget 無聲消失,不會報錯

實測把 widget 的位置寫錯(少一格縮排),結果:

  • 頁面沒有錯誤訊息,服務卡片正常出現
  • 但卡片上沒有 widget,看起來就像「這個服務不支援 widget」

用 API 一看就知道:

$ curl -s .../api/services
[{"name":"監控","services":[{"name":"Uptime Kuma","href":"...","widgets":[]}]}]

widgets 是空陣列——它被 YAML 解析成「另一個鍵」,而不是 widget 設定。更麻煩的是 Homepage 內建的 MCP 驗證工具也只驗 YAML 語法,這種「語法合法、結構錯誤」的情況會回 {"valid": true}。

現象可能原因怎麼查
整頁空白外層該用陣列的檔案寫成 mapping(或反之)curl /api/services 看有沒有 JSON
服務出現但沒有 widget縮排層級錯、widget: 與 icon: 不同層檢查 widgets 是否為空陣列
卡片顯示紅色「API 錯誤」widget 連不到目標服務或金鑰錯docker logs homepage 會印出實際打的 URL
Docker 狀態不出現沒掛 socket、docker.yaml 沒設、server 名字不符日誌出現 connect ENOENT /var/run/docker.sock
整站 400HOMEPAGE_ALLOWED_HOSTS 沒含這個 host:port日誌有 Host validation failed
圖示空白icon 名稱不在 dashboard-icons 清單,或容器沒有外網改用 mdi-*/si-* 前綴或本地 /icons/x.png

實測 widget 失敗時日誌長這樣(順帶揭露 widget 的實際呼叫路徑):

error: <httpProxy> Error calling http://127.0.0.1:3001/api//main...
Error: connect ECONNREFUSED 127.0.0.1:3001

前端則是 HTTP 500 加上 ECONNREFUSED 的錯誤物件。想讓使用者不要看到紅色錯誤框,可以在 settings.yaml 設 hideErrors: true 或單一 widget 設 hideErrors: true——但除錯階段千萬不要開,它會把唯一的線索藏起來。

進階:讓 AI 幫你改設定(MCP 端點)

v2.x 之後 Homepage 內建一個輕量的 MCP(Model Context Protocol)端點,預設關閉。啟用方式:

environment:
  HOMEPAGE_MCP_ENABLED: "true"
  HOMEPAGE_MCP_TOKEN: "用 openssl rand -base64 32 產生的 32 字元以上字串"

端點在 /api/mcp。實測結果:

$ curl -s http://127.0.0.1:3999/api/mcp \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $TOKEN" \
    -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '.result.tools[].name'
list_config_files
read_config_file
validate_config_file
write_config_file
add_service
add_info_widget
homepage_docs

七個工具、沒有 token 一律 401 Unauthorized。預設唯讀:呼叫 write_config_file 會回 Writing is disabled. Set HOMEPAGE_MCP_ALLOW_WRITE=true to enable MCP config edits.;要寫入必須另外開 HOMEPAGE_MCP_ALLOW_WRITE=true,而且寫入前會驗 YAML 語法(實測用 tab 縮排會回 tab characters must not be used in indentation (2:1) 並附行列位置)。

但請注意風險:官方文件寫得很明白——這個 token 等於「讀取所有設定的服務憑證」的權限,開啟寫入後還能改 custom.js(會在每個瀏覽器裡執行)。所以:只在內網開、務必配 TLS 與反向代理、token 至少 32 字元。MCP 官方也說 Claude Desktop 的「Add custom connector」不適用(它走 OAuth、無法帶自訂標頭),要改用 mcp-remote 加 X-Homepage-MCP-Token。

安全與治理檢查清單

項目建議做法
對外曝露預設只聽內網,要對外一律走反向代理+驗證(Authelia/Cloudflare Access)
搜尋引擎disableIndexing: true(實測會讓 /robots.txt 變成 Disallow: /)
Docker socket優先 socket proxy;直掛也要 :ro,並理解容器需 root
敏感值用 HOMEPAGE_VAR_XXX 環境變數+設定檔寫 {{HOMEPAGE_VAR_XXX}},別把 API key 寫進 YAML
檔案權限用 PUID/PGID 以非 root 執行,並確認 config 目錄擁有者正確
MCP預設關閉;要開就配 token+TLS,寫入權限另外評估
更新官方建議看 release notes 再升版;本教學用 v2.7.0 固定 tag 較好追

金鑰不要寫死在 YAML,做法是:

# services.yaml
        widget:
          type: jellyfin
          url: http://jellyfin:8096
          key: "{{HOMEPAGE_VAR_JELLYFIN_KEY}}"
# compose
environment:
  HOMEPAGE_VAR_JELLYFIN_KEY: "你的金鑰"

已知限制/沒做的事

誠實列出這篇的邊界,避免讀者以為什麼都驗過了:

  • 沒有實測 165 種 widget:只實測了 uptimekuma(失敗情境)與 Docker 狀態 API,其餘 widget 的參數請以官方文件為準。
  • 沒有接真實的 Jellyfin/Paperless 等後端:截圖中的服務是「連不到」的示範,紅色錯誤框就是實測證據;這些整合的實際數字沒有驗證。
  • 沒有測試 Kubernetes、Proxmox 整合:只確認 kubernetes.yaml 會被自動建立、相關端點存在。
  • 記憶體 158.7 MiB 是閒置值:docker stats 單次取樣,掛上大量 widget 後會更高。
  • 沒有做 Nginx/Traefik/Cloudflare Tunnel 的反向代理實測:只提醒 HOMEPAGE_ALLOWED_HOSTS 要放對外網域;這部分請搭配本站的反向代理教學。
  • STAR 數與版本會變:以 2026-11-01 查詢與 v2.7.0 為準。
  • MCP 端點只測了 tools/list、read_config_file、validate_config_file、write_config_file(被拒):沒有實測 add_service 寫入成功的情境。

誰適合、誰不需要

你的情況建議
有 5 個以上自架服務、常忘記 port非常適合,設定 30 分鐘內完成
想要一頁顯示服務健康狀態適合,但別取代 Uptime Kuma(告警仍要靠它)
只有 1~2 個服務不需要,瀏覽器書籤就好
想找「有登入驗證的入口」Homepage 有自己的 auth(HOMEPAGE_AUTH_ENABLED),但多數人會直接放反向代理後面
需要多節點、多使用者權限不適合,它不是 CMDB 也不是監控平台

站內延伸閱讀


本文基於 2026-11-01 的 gethomepage/homepage v2.7.0 實機測試;文中沒有聯盟連結,也不構成任何商業推薦。

📬 訂閱 most.tw 電子報

每週精選 AI 工具教學與技術乾貨,直接送到你的信箱。免費、隨時可退訂。

訂閱即表示同意收到 most.tw 電子報,隨時可一鍵退訂。

💬 有問題想討論?加 LINE 聯絡我

歡迎透過 LINE 官方帳號直接留言,我會盡快回覆你的問題。

加入 LINE 好友