homepage v2.7.0 Docker Compose 部署指南

用 Docker Compose 在单台 Ubuntu 22.04 服务器上部署 homepage v2.7.0 自托管仪表盘,完成配置目录持久化、HOMEPAGE_ALLOWED_HOSTS 主机白名单、v2.0 内置密码登录门控(含 CSRF 登录全链路实测)与 Caddy HTTPS 反向代理接入,实现「启动即健康、配置即生效、公网形态有边界防护」的 0→1 部署。

homepage自托管仪表盘2026/10/25

homepage v2.7.0 Docker Compose 部署指南

‍‍​​‌​> 目标:用 Docker Compose 在单台 Ubuntu 22.04 服务器上部署 homepage v2.7.0 自托管仪表盘,完成配置目录持久化、HOMEPAGE_ALLOWED_HOSTS 主机白名单、v2.0 内置密码登录门控(含 CSRF 登录全链路实测)与 HTTPS 反向代理接入,实现「启动即健康、配置即生效、公网形态有边界防护」的 0→1 部署。本文全部命令与回显已在 Docker Engine 29.9.2(Compose v5.6.1)环境实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04(x86_64)
  • Docker Engine:29.9.2,Docker Compose 插件 v5.6.1
  • homepage 版本:v2.7.0(2026-10-23 发布,官方镜像 ghcr.io/gethomepage/homepage,应用本体为 Next.js 16.4.1,实测日志可见)
  • 反向代理镜像:caddy:2-alpine(Caddy 2,用于第十章 HTTPS 接入)
  • 端口规划:homepage 宿主端口 8129(应用端口 3000);Caddy HTTPS 宿主端口 8130。生产环境可按需改为 3000 或由反代直接占用 80/443,改宿主端口时必须同步修改 HOMEPAGE_ALLOWED_HOSTS(见第十二章常见问题 1)
  • 域名规划:homepage.example.com,本地验证环境在服务器 /etc/hosts 加入解析即可,生产环境配置 DNS A 记录
  • 编排目录:/opt/homepage/(示例路径,含 docker-compose.yml 与 config/ 配置子目录)
  • 独立网络:homepage-net(bridge,网段 10.89.58.0/24)

二、镜像选型说明

homepage 官方只发布单一镜像,选型要点集中在仓库地址与标签策略两点。以下标签清单于 2026-10-25 通过 ghcr.io registry API(/v2/gethomepage/homepage/tags/list)实查,共 211 个标签:

标签含义适用场景
v2.7.0精确版本标签,与 GitHub Release 一一对应生产推荐,升级可控,回显可复现
v2.7浮动小版本标签,跟随 v2.7.x 最新补丁想自动拿安全补丁
v2浮动主版本标签,跟随 v2.x 最新版想自动拿新功能(行为可能变化)
latest滚动最新(含 v3 时代后的新大版本)仅测试/尝鲜,不建议生产
main / nightly主分支 / 每夜构建开发调试专用

💡 说明:本文全部使用 v2.7.0 精确标签。镜像内应用以非 root 能力运行(支持 PUID/PGID 降权,见第六章环境变量表),数据目录为 /app/config,服务监听 0.0.0.0:3000,内置健康检查(每 10 秒探测一次 /api/healthcheck,实测 docker compose ps 状态为 healthy)。

三、前置条件

  1. 服务器已安装 Docker Engine 与 Compose 插件,验证:
docker version --format 'Engine {{.Server.Version}}'

实测输出:

Engine 29.9.2
docker compose version

实测输出:

Docker Compose version v5.6.1
  1. 域名解析就绪:生产环境为 homepage.example.com 配置 DNS A 记录;本地验证环境在服务器 /etc/hosts 中加入:
127.0.0.1 homepage.example.com

⚠️ HOMEPAGE_ALLOWED_HOSTS(见第六章)按「访问时浏览器地址栏里的 主机:端口」精确匹配。本文实测同时使用 homepage.example.com:8129(HTTP 直连)与 homepage.example.com:8130(HTTPS 反代)两种访问形态,两者都要在白名单里,缺一个对应形态就会报 Host 校验失败(排障实录见第十二章常见问题 1)。

  1. 配置目录已存在:homepage 启动时会把初始示例配置写入挂载的配置目录,但挂载源目录本身必须先创建,否则会以空目录覆盖启动报错:
mkdir -p /opt/homepage/config

四、部署步骤

本章按「创建网络 → 编写编排文件 → 启动 → 验证」的顺序完成 0→1 部署。预期结果:服务健康运行(healthy),健康检查端点返回 up,浏览器打开登录页/仪表盘正常。

4.1 创建独立网络

为整套栈创建独立 bridge 网络并显式指定网段,避免与其他业务网段冲突:

docker network create -d bridge --subnet 10.89.58.0/24 homepage-net

实测输出:

6b70f2682c085ac9b9a92680ebd183c27618a8686f60ff999b58be56a81187d7

💡 说明:显式 --subnet 便于后续把同网段内的被监测服务(如第十章反代)统一接入。若网段与现有网络冲突,换一个空闲 /24 即可,同时同步修改编排文件。

4.2 编写编排文件

在 /opt/homepage/ 下创建 docker-compose.yml。本文演示开启 v2.0 内置密码登录门控,签名密钥 HOMEPAGE_AUTH_SECRET 属于系统级密钥,按规范通过 .env 文件注入而非明文写进编排文件:

cd /opt/homepage
echo "HOMEPAGE_AUTH_SECRET=$(openssl rand -base64 32)" >> .env

docker-compose.yml 全文:

name: homepage-v2.7.0-stack

services:
  homepage:
    image: ghcr.io/gethomepage/homepage:v2.7.0
    container_name: homepage-v2.7.0-web
    ports:
      - "8129:3000"
    volumes:
      - /opt/homepage/config:/app/config
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      HOMEPAGE_ALLOWED_HOSTS: homepage.example.com:8129,homepage.example.com:8130,192.168.146.128:8129,localhost:3000,127.0.0.1:3000
      HOMEPAGE_AUTH_ENABLED: "true"
      HOMEPAGE_AUTH_SECRET: ${HOMEPAGE_AUTH_SECRET}
      HOMEPAGE_AUTH_PASSWORD: q1w2e3r4
      HOMEPAGE_EXTERNAL_URL: http://homepage.example.com:8129
    restart: unless-stopped
    networks:
      - homepage-net

networks:
  homepage-net:
    external: true

逐项说明:

  • image:锁定 v2.7.0 精确标签(理由见第二章);
  • ports:宿主 8129 → 应用 3000,生产可改 "3000:3000";
  • volumes 第一项:配置目录持久化(见第五章);第二项:只读挂载 Docker socket,用于容器状态/统计集成,不需要 Docker 集成可整行删掉(更安全的 socket proxy 接入方式见《homepage v2.7.0 配置参数详解》);
  • HOMEPAGE_ALLOWED_HOSTS:主机白名单,逗号分隔、不带空格;localhost:3000 与 127.0.0.1:3000 恒定内置可不写,本文为完整展示仍写入;192.168.146.128:8129 演示「服务器 IP 直连」形态,按实际 IP 替换;
  • HOMEPAGE_AUTH_ENABLED:开启 v2.0 登录门控;不开则仪表盘匿名可看(仅建议纯内网形态);
  • HOMEPAGE_AUTH_SECRET:会话签名密钥,至少 32 字符,来自 .env 注入;
  • HOMEPAGE_AUTH_PASSWORD:演示密码 q1w2e3r4;提供 OIDC 变量时该项自动失效(OIDC 对接见《homepage v2.7.0 配置参数详解》);
  • HOMEPAGE_EXTERNAL_URL:对外访问的绝对地址,用于 Cookie 作用域判定;HTTPS 部署请写 https:// 以便 Cookie 标记 Secure;
  • restart 与 networks:随宿主机自启、加入独立网络。

4.3 启动

docker compose up -d

实测输出:

 Container homepage-v2.7.0-web Creating 
 Container homepage-v2.7.0-web Created 
 Container homepage-v2.7.0-web Starting 
 Container homepage-v2.7.0-web Started 

💡 说明:homepage-net 在 4.1 已显式创建并声明 external: true,因此 compose 输出里不会出现网络创建行;若把网络定义改成非 external,首次 up 时会自动创建 homepage-v2.7.0-stack_homepage-net。

4.4 启动验证

第 1 步:等健康检查转绿(镜像内置健康检查,启动后约 20 秒内转 healthy):

docker compose ps

实测输出(输出节选,实测首尾):

NAME                  IMAGE                                 COMMAND                  SERVICE    CREATED          STATUS                    PORTS
homepage-v2.7.0-web   ghcr.io/gethomepage/homepage:v2.7.0   "docker-entrypoint.s…"   homepage   13 seconds ago   Up 12 seconds (healthy)   0.0.0.0:8129->3000/tcp, [::]:8129->3000/tcp

第 2 步:看启动日志,确认配置骨架已生成、无报错:

docker compose logs homepage

实测输出(输出节选,实测首尾):

homepage-v2.7.0-web  | Skipping ownership changes for /app/config
homepage-v2.7.0-web  | ▲ Next.js 16.4.1
homepage-v2.7.0-web  | - Local:         http://[::1]:3000
homepage-v2.7.0-web  | - Network:       http://[::]:3000
homepage-v2.7.0-web  | ✓ Ready in 0ms
homepage-v2.7.0-web  | settings.yaml was copied to the config folder
homepage-v2.7.0-web  | [2026-10-25T02:01:37.374Z] info: kubernetes.yaml was copied to the config folder

💡 说明:homepage 首次收到访问请求时才会把缺失的配置骨架(services.yaml、bookmarks.yaml、widgets.yaml、docker.yaml)逐个写入配置目录,日志形如 info: services.yaml was copied to the config folder。骨架只是注释示例,直接覆盖成自己的内容即可,改完保存即生效,多数配置无需重启(docker.yaml 例外,需 docker compose restart homepage)。

第 3 步:健康检查端点(该端点免认证,专供探活):

curl -s http://homepage.example.com:8129/api/healthcheck

实测输出:

up

第 4 步:登录门控实测。开启 HOMEPAGE_AUTH_ENABLED=true 后,未登录访问一律被重定向到登录页:

curl -s -o /dev/null -w "未登录访问首页: HTTP %{http_code}, redirect=%{redirect_url}\n" http://homepage.example.com:8129/

实测输出:

未登录访问首页: HTTP 307, redirect=http://homepage.example.com:8129/auth/signin?callbackUrl=%2F

用 curl 走一遍完整登录流(先取 CSRF Token,再提交密码,再带会话 Cookie 访问):

curl -s -c cookies.txt http://homepage.example.com:8129/api/auth/csrf

实测输出(输出节选,实测首尾):

{"csrfToken":"b55805eab606fb58...(32 位随机串)..."}
curl -s -b cookies.txt -c cookies.txt -o /dev/null \
  -w "登录回调: HTTP %{http_code}, redirect=%{redirect_url}\n" \
  -X POST http://homepage.example.com:8129/api/auth/callback/credentials \
  -d "csrfToken=<上一步的值>&password=q1w2e3r4"

实测输出:

登录回调: HTTP 302, redirect=http://homepage.example.com:8129/
curl -s -b cookies.txt -o /dev/null -w "登录后访问首页: HTTP %{http_code}\n" http://homepage.example.com:8129/

实测输出:

登录后访问首页: HTTP 200

浏览器访问 http://homepage.example.com:8129 即见登录页,输入密码 q1w2e3r4 进入仪表盘(首次进入为官方示例配置的界面,按《homepage v2.7.0 配置参数详解》改成自己的内容)。

第 5 步:错误密码行为(顺带验证失败日志,可对接 fail2ban/CrowdSec):

curl -s -b cookies_bad.txt -o /dev/null \
  -w "错误密码回调: HTTP %{http_code}, redirect=%{redirect_url}\n" \
  -X POST http://homepage.example.com:8129/api/auth/callback/credentials \
  -d "csrfToken=<同上取值>&password=wrongpass"

实测输出:

错误密码回调: HTTP 302, redirect=http://homepage.example.com:8129/api/auth/error?error=CredentialsSignin&provider=credentials
docker compose logs homepage | grep "sign-in"

实测输出:

homepage-v2.7.0-web  | [2026-10-25T02:06:12.368Z] warn: <nextauth> Failed password sign-in attempt

⚠️ homepage 应用层对密码尝试不做限速,公网部署应在反代层对 /api/auth/callback/credentials 的 POST 限速;上述 warn 日志即官方推荐的 fail2ban 过滤来源。

五、数据持久化说明

homepage 的全部持久化状态就是一个配置目录(/app/config),没有数据库、没有隐藏状态:

内容位置说明
全部 YAML 配置/app/config/*.yamlsettings/services/bookmarks/widgets/docker/kubernetes,见《homepage v2.7.0 配置参数详解》
变量注入文件/app/config/*.txt 等HOMEPAGE_FILE_XXX 指向的密钥/凭据文件(若有)
运行日志/app/config/logs/应用日志文件形态,与 stdout 并行

验证持久化:停止并删除服务后重新启动,配置原样保留:

docker compose down && docker compose up -d

实测输出:

 Container homepage-v2.7.0-web Stopping 
 Container homepage-v2.7.0-web Stopped 
 Container homepage-v2.7.0-web Removing 
 Container homepage-v2.7.0-web Removed 
 Container homepage-v2.7.0-web Creating 
 Container homepage-v2.7.0-web Created 
 Container homepage-v2.7.0-web Starting 
 Container homepage-v2.7.0-web Started 

重新登录访问,所有配置内容不变。备份与迁移只需打包 /opt/homepage/config 一个目录,实操步骤见《homepage v2.7.0 日常运维手册》。

六、环境变量表

环境变量必填默认说明
HOMEPAGE_ALLOWED_HOSTS是(v1.0 起)无逗号分隔的允许访问主机列表(主机:端口 精确匹配);localhost:3000、127.0.0.1:3000 恒定内置;设为 * 可关闭校验但官方不建议
HOMEPAGE_AUTH_ENABLED否falsev2.0 登录门控开关,true 后所有页面与 /api 路由需登录(/api/healthcheck 与 /api/config/custom.css 豁免)
HOMEPAGE_AUTH_SECRET门控开启时必填无会话签名密钥,≥32 字符,openssl rand -base64 32 生成;属系统级密钥,建议 .env 注入
HOMEPAGE_AUTH_PASSWORD门控开启且无 OIDC 时必填无登录密码;提供 OIDC 变量后失效
HOMEPAGE_EXTERNAL_URL门控开启时建议无对外访问绝对地址(含协议与端口);HTTPS 部署写 https:// 使 Cookie 带 Secure
HOMEPAGE_OIDC_ISSUER / _CLIENT_ID / _CLIENT_SECRET否无OIDC 登录三件套,任一提供即覆盖密码登录
HOMEPAGE_OIDC_SCOPE否openid email profileOIDC 请求的 scope
HOMEPAGE_OIDC_AUTO_LOGIN否falsetrue 时未登录直接跳转 IdP(逃生口:/auth/signin?autologin=0)
PUID / PGID否root以非 root 用户运行时的宿主 UID/GID,挂载卷需保证对应属主可写
HOMEPAGE_VAR_XXX否无变量注入:值替换配置文件中的 {{HOMEPAGE_VAR_XXX}} 占位符
HOMEPAGE_FILE_XXX否无文件注入:值为容器内文件路径,文件内容替换 {{HOMEPAGE_FILE_XXX}} 占位符

七、配置参数说明

部署侧只涉及三个参数组,页面级配置全部在 YAML 文件里(独立成篇):

  1. 端口与网络:ports 宿主端口任意,但改动后必须同步 HOMEPAGE_ALLOWED_HOSTS 与 HOMEPAGE_EXTERNAL_URL;
  2. 访问控制:HOMEPAGE_ALLOWED_HOSTS(防 Host 混淆攻击的入口白名单)+ 登录门控族(第六章)+ 反代边界(第十章),三层依次为「入口校验 → 应用认证 → 边界防护」;
  3. Docker 集成:挂载 socket(root 运行)或改用 socket proxy(非 root 可用),对应配置文件 docker.yaml 的两种写法见《homepage v2.7.0 配置参数详解》。

八、配置文件挂载

首次启动后的配置目录(ls /opt/homepage/config):

bookmarks.yaml
docker.yaml
kubernetes.yaml
logs
settings.yaml
services.yaml
widgets.yaml
  • 只有 settings.yaml、kubernetes.yaml 在启动时生成,其余四个在首次页面访问时生成骨架(4.4 第 2 步日志可见);
  • 配置文件保存即生效(服务/书签/信息组件/全局设置均为请求时读取),仅 docker.yaml 修改后需重启;
  • 本地图标目录:自定义图标挂到 /app/public/icons(编排文件加一行 - /opt/homepage/icons:/app/public/icons),服务里用 icon: /icons/my-icon.png 引用,新增图标后需重启。

九、等价 docker run

不使用 Compose 时,等价的启动命令(先 mkdir -p /opt/homepage/config,密钥以 -e 直接注入):

docker run -d \
  --name homepage \
  --restart unless-stopped \
  -p 8129:3000 \
  -v /opt/homepage/config:/app/config \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -e HOMEPAGE_ALLOWED_HOSTS=homepage.example.com:8129,localhost:3000,127.0.0.1:3000 \
  -e HOMEPAGE_AUTH_ENABLED=true \
  -e HOMEPAGE_AUTH_SECRET=$(openssl rand -base64 32) \
  -e HOMEPAGE_AUTH_PASSWORD=q1w2e3r4 \
  -e HOMEPAGE_EXTERNAL_URL=http://homepage.example.com:8129 \
  ghcr.io/gethomepage/homepage:v2.7.0

验证方式与 4.4 相同(docker compose ps 换成 docker ps + curl /api/healthcheck 返回 up)。生产环境建议仍用 Compose,升级与回滚操作面更小。

十、HTTPS 反向代理接入(Caddy)

homepage 本身只提供 HTTP 服务(应用端口 3000),HTTPS 形态由反向代理补齐。本章用 Caddy 2 为仪表盘加一层 TLS 网关:Caddy 对本地域名自动签发内部 CA 证书,无需手动申请;homepage 侧唯一要做的,是把反代访问形态的 主机:端口 加进 HOMEPAGE_ALLOWED_HOSTS——第四章编排文件里已包含 homepage.example.com:8130,直接可用。

💡 技术拓展:反代 TLS 证书的获取方式不止自签一种——

方式原理适用场景
自签(internal CA)反代自带 CA 签发,浏览器不信任需手动确认内网/本地验证环境,无公网解析
ACME 自动签发Let's Encrypt/ZeroSSL 按域名验证后签发受信证书有公网解析的真域名,零维护
手动导入证书商业/组织 CA 颁发的证书文件挂载给反代企业内已购证书、无法开放 80/443 验证

本文域名 homepage.example.com 仅为本地验证环境(无公网解析),采用 Caddy tls internal 自签方案。

10.1 Caddy 编排文件

在 /opt/homepage/caddy/ 下创建 docker-compose.yml(与主栈共用 4.1 创建的 homepage-net 网络):

name: homepage-caddy-proxy

services:
  caddy:
    image: caddy:2-alpine
    container_name: homepage-caddy-https
    ports:
      - "8130:8130"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
    networks:
      - homepage-net
    restart: unless-stopped

volumes:
  caddy-data:

networks:
  homepage-net:
    external: true

逐项说明:

  • ports:宿主 8130 → Caddy 8130,改端口需同步 Caddyfile 站点地址与 HOMEPAGE_ALLOWED_HOSTS;
  • volumes 第一项:Caddyfile 只读挂载进配置路径;第二项 caddy-data 具名卷存放证书与私钥,重启后不重新签发;
  • networks:声明 external: true 复用已有网络,反代与 homepage 同网,可按容器名直连。

10.2 Caddyfile

{
  admin off
}

https://homepage.example.com:8130 {
  tls internal
  reverse_proxy homepage-v2.7.0-web:3000
}

逐项说明:

  • admin off:关闭 Caddy 本地管理接口(默认监听 2019,本场景用不到,关掉减少暴露面);
  • 站点地址写完整 https://主机:端口,与白名单条目 homepage.example.com:8130 一一对应;
  • tls internal:启用 Caddy 内部 CA 自签(技术拓展见上);
  • reverse_proxy 目标写 homepage-v2.7.0-web:3000——即第四章编排里的 container_name + 应用端口,同一 user-defined 网络内可直接解析容器名,不要写死重启后会变的内网 IP。

10.3 启动与验证

cd /opt/homepage/caddy
docker compose up -d

实测输出:

 Container homepage-caddy-https Creating 
 Container homepage-caddy-https Created 
 Container homepage-caddy-https Starting 
 Container homepage-caddy-https Started 

验证 1:服务状态:

docker compose ps

实测输出:

NAME                   IMAGE            COMMAND                  SERVICE   CREATED         STATUS         PORTS
homepage-caddy-https   caddy:2-alpine   "caddy run --config …"   caddy     6 seconds ago   Up 5 seconds   80/tcp, 443/tcp, 2019/tcp, 443/udp, 0.0.0.0:8130->8130/tcp, [::]:8130->8130/tcp

验证 2:免认证探针走 HTTPS(自签证书用 -k 跳过校验):

curl -sk https://homepage.example.com:8130/api/healthcheck

实测输出:

up

验证 3:未登录访问 HTTPS 首页,同样被登录门控拦截,说明门控在反代形态下不受影响:

curl -sk -o /dev/null -w "HTTPS 首页: HTTP %{http_code}\n" https://homepage.example.com:8130/

实测输出:

HTTPS 首页: HTTP 307

验证 4:确认证书确由 Caddy 内部 CA 签发。浏览器首次访问会出现「证书不受信任」提示,属自签预期行为:

curl -skv https://homepage.example.com:8130/ 2>&1 | grep -E 'issuer:|SSL connection'

实测输出(输出节选,实测首尾):

* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / X25519 / id-ecPublicKey
*  issuer: CN=Caddy Local Authority - ECC Intermediate

⚠️ 换用真域名且已有公网解析时:删去 tls internal 一行,Caddy 默认通过 ACME 自动签发受信任证书(需 80/443 可达或 DNS 验证);同时把 HOMEPAGE_EXTERNAL_URL 改为 https:// 形态,登录 Cookie 才会带 Secure 标记。

至此部署收尾:HTTP 直连(8129)与 HTTPS 反代(8130)两种访问形态均可用,且都处于登录门控保护之下。上线后的日常巡检、备份与升级操作见《homepage v2.7.0 日常运维手册》。

十一、常用运维命令

# 查看服务状态(healthy 即正常)
docker compose ps

实测输出(输出节选,实测首尾):

NAME                  IMAGE                                 STATUS                    PORTS
homepage-v2.7.0-web   ghcr.io/gethomepage/homepage:v2.7.0   Up 12 seconds (healthy)   0.0.0.0:8129->3000/tcp, [::]:8129->3000/tcp
# 跟踪运行日志(配置加载、Host 校验、登录失败都在这里)
docker compose logs -f homepage

实测输出(输出节选,实测首尾):

homepage-v2.7.0-web  | [2026-10-25T02:01:37.374Z] info: kubernetes.yaml was copied to the config folder
homepage-v2.7.0-web  | [2026-10-25T02:02:21.692Z] info: bookmarks.yaml was copied to the config folder
# 应用层健康检查(免认证探活端点)
curl -s http://homepage.example.com:8129/api/healthcheck

实测输出:

up
# 修改配置后重启(docker.yaml 变更或镜像升级时)
docker compose restart homepage

实测输出:

 Container homepage  Started
# 停止 / 清理编排(external 网络不受影响)
docker compose down

实测输出:

 Container homepage-v2.7.0-web Stopping 
 Container homepage-v2.7.0-web Stopped 
 Container homepage-v2.7.0-web Removing 
 Container homepage-v2.7.0-web Removed 

十二、常见问题

Q1:页面能打开但所有 widget 无数据,日志报 Host validation failed?

这是 v1.0 之后最高频问题:访问用的 主机:端口 不在 HOMEPAGE_ALLOWED_HOSTS 里。注意内置白名单只包含 localhost:3000 与 127.0.0.1:3000,宿主端口一旦不是 3000,连本机直连也会被拒。实测复现(宿主端口 8129 直连):

curl -s http://127.0.0.1:8129/api/healthcheck

实测输出:

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

日志原文:

homepage-v2.7.0-web  | [2026-10-25T02:27:37.868Z] error: Host validation failed for: 127.0.0.1:8129. Hint: Set the HOMEPAGE_ALLOWED_HOSTS environment variable to allow requests from this host / port.

解决方案:把日志里 Host validation failed for: 后面的完整串(含端口)原样加进 HOMEPAGE_ALLOWED_HOSTS(逗号分隔、不带空格),docker compose up -d 重建后复测。实测把 homepage.example.com:8130(HTTPS 反代形态)补进白名单后,同一探针立即恢复:

curl -sk https://homepage.example.com:8130/api/healthcheck

实测输出:

up

注意同一域名走 8129 直连与 8130 反代是两个白名单条目。

Q2:HOMEPAGE_FILE_XXX 指向的文件报 500?

变量注入的文件路径是容器内路径,文件必须放在挂载进 /app/config 的目录里。实测把密钥文件误放在宿主机编排目录(未挂载)时,页面直接 500,日志核心报错:

homepage-v2.7.0-web  | Error: ENOENT: no such file or directory, open '/app/config/secret_key.txt'
homepage-v2.7.0-web  |   code: 'ENOENT',

解决方案:把文件放进 /opt/homepage/config/(即容器内 /app/config/),重启后恢复。

Q3:改了 services.yaml 之后仪表盘空白?

先看日志是否 YAML 解析失败。实测在 services.yaml 末尾追加一行未闭合的 坏行: [未闭合 后,页面 HTTP 仍 200 但服务区块消失,/api/services 返回 [],日志给出精确行列号:

homepage-v2.7.0-web  | [2026-10-25T02:07:56.195Z] error: Failed to load services.yaml, please check for errors
homepage-v2.7.0-web  | [2026-10-25T02:07:56.196Z] error: YAMLException: deficient indentation (26:1)

按日志里的行列号修正缩进即可;homepage 对坏配置的容错是「跳过该文件、页面不崩」,所以要用日志而不是页面状态判断配置健康。

Q4:服务一直 restarting 或 unhealthy?

依次检查:① docker compose logs homepage 看启动日志有无 panic/ENOENT;② 配置目录属主与 PUID/PGID 是否匹配(镜像启动脚本会对 /app/config 做 chown,若挂载卷只读会失败);③ 端口冲突(ss -ltnp | grep 8129);④ 健康检查走容器内 127.0.0.1:3000,与 HOMEPAGE_ALLOWED_HOSTS 无关,unhealthy 说明应用本体没起来,先解决日志里的报错再谈白名单。

Q5:升级后页面打不开/Host 报错?

升级(docker compose pull && docker compose up -d,完整升级/回滚流程见《homepage v2.7.0 日常运维手册》)后若访问方式变了(如新加了 HTTPS 反代),回顾 Q1;若想临时全局放行排查问题,可设 HOMEPAGE_ALLOWED_HOSTS=*,但仅限内网排障,公网严禁。

十三、参考链接