homepage v2.7.0 日常运维手册
面向已上线的 homepage v2.7.0 单机栈,覆盖日常巡检、配置目录备份与恢复演练、存活探针与登录失败监控、资源水位与日志轮转、版本升级与回滚(v2.6.0↔v2.7.0 双向实测)、Host 校验/只读挂载/端口占用等故障排查的完整运维闭环,全部命令与回显实测沉淀。
homepage v2.7.0 日常运维手册
目标:面向已按部署指南上线的 homepage v2.7.0 单机栈,给出「日常巡检 → 备份与恢复 → 监控告警 → 扩容缩容 → 升级与回滚 → 故障排查」的完整运维闭环,每个操作都附实测命令与真实回显。本文全部命令与回显已在 Docker Engine 29.9.2(Compose v5.6.1)环境实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04(x86_64),Docker Engine 29.9.2(Compose v5.6.1)
- homepage 版本:v2.7.0(官方镜像
ghcr.io/gethomepage/homepage,编排名homepage-v2.7.0-stack) - 编排目录:
/opt/homepage/(含docker-compose.yml与config/配置子目录);备份落盘目录:/var/backups/homepage/ - 访问形态:
http://homepage.example.com:8129(HTTP 直连,已开启密码门控,示例密码q1w2e3r4);https://homepage.example.com:8130(Caddy HTTPS 反代) - 网络规划:独立 bridge 网络
homepage-net(网段10.89.58.0/24) - 登录会话获取:
/api/validate等管理端点需登录态,本文统一用两步 curl(取 CSRF Token → 提交密码)拿到会话 Cookie 后再调用:
cd /opt/homepage
CSRF=$(curl -s -c cookies.txt http://homepage.example.com:8129/api/auth/csrf)
TOKEN=$(echo "$CSRF" | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
curl -s -b cookies.txt -c cookies.txt -o /dev/null -w "登录回调: HTTP %{http_code}\n" \
-X POST http://homepage.example.com:8129/api/auth/callback/credentials \
-d "csrfToken=$TOKEN&password=q1w2e3r4"
实测输出:
登录回调: HTTP 302
💡 说明:homepage v2.0 起所有页面与
/api路由默认受登录门控保护(免认证的只有探活端点/api/healthcheck),因此运维脚本凡是调用管理端点都要先带上会话 Cookie。cookies.txt含有效会话,不要提交进版本库。
二、日常巡检
日常巡检回答三个问题:服务活着吗、跑的是哪个版本、配置还健康吗。本章命令均可直接加入巡检脚本,预期结果逐项给出。
2.1 服务状态与版本巡检
先看服务状态(healthy 即健康检查通过)与当前运行的版本:
cd /opt/homepage
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 5 minutes ago Up 22 seconds (healthy) 0.0.0.0:8129->3000/tcp, [::]:8129->3000/tcp
docker compose images
实测输出:
CONTAINER REPOSITORY TAG PLATFORM IMAGE ID SIZE CREATED
homepage-v2.7.0-web ghcr.io/gethomepage/homepage v2.7.0 linux/amd64 19c5c0918445 376MB 36 hours ago
再扫一眼近期日志有没有异常关键字(error/Failed/EROFS 等):
docker compose logs --since 1h homepage
实测输出:
homepage-v2.7.0-web | /app/.next already owned by correct UID/GID or running as root, skipping chown
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 | ✓ Running next.config took 2ms
💡 说明:版本以
docker compose images的TAG列为准(当前v2.7.0,镜像 376MB),日志首行的▲ Next.js 16.4.1是应用本体的框架版本,两者口径不同。巡检基线:healthy+ 日志无error级输出即为正常。
2.2 应用健康与配置自检
健康检查走免认证探活端点,任何监控工具都能直接用:
curl -s http://homepage.example.com:8129/api/healthcheck
实测输出:
up
配置健康度用自检端点核对(需登录态,会话取法见第一章):
curl -s -b cookies.txt http://homepage.example.com:8129/api/validate
实测输出:
[]
💡 说明:
/api/validate返回全部配置文件的解析错误数组,空数组[]即所有 YAML 均可正常解析。homepage 对坏配置的容错是「跳过该文件、页面不崩」,所以配置健康必须靠这个端点而不是页面状态判断(坏 YAML 的完整排障实录见《homepage v2.7.0 配置参数详解》第八章)。
2.3 配置目录与日志体量巡检
homepage 全部持久化状态就是一个配置目录,体量巡检能提前发现异常增长:
du -sh /opt/homepage/config /opt/homepage/config/logs
实测输出:
44K /opt/homepage/config
8.0K /opt/homepage/config/logs
ls -lh /opt/homepage/config/logs/
实测输出:
total 4.0K
-rw-r--r-- 1 root root 3.5K Oct 25 11:21 homepage.log
💡 说明:纯配置形态的 homepage 配置目录只有几十 KB 量级(本环境 44K),日志文件单日增长也在 KB 级。若
du结果出现 MB/GB 级增长,优先排查是否有人把大文件(图标包、附件)放进了挂载目录,或日志因反复报错膨胀(轮转方案见 5.3 节)。
三、备份与恢复
homepage 没有数据库、没有隐藏状态,备份对象就是 /opt/homepage/config 一个目录,恢复也只在该目录上做文章。本章给出手动备份、完整恢复演练与定时备份三件套。
💡 技术拓展:配置目录备份的常见方式对比——
方式 原理 适用场景 tar 全量打包 一次性打包成单文件,便于异地传输与长期归档 低频变更的配置类目录(本文采用) rsync 增量同步 按差异同步到备份盘,占用小、可秒级恢复目录形态 大目录、高频增量 文件系统快照 LVM/ZFS 快照,一致性最好 有快照能力且要求时间点一致的存储 homepage 配置目录仅几十 KB 且变更低频,tar 打包最简单可控,本文实际采用 tar + 保留 7 天的定时清理。
3.1 手动备份
mkdir -p /var/backups/homepage
tar czf /var/backups/homepage/homepage-config-20261025-1115.tar.gz -C /opt/homepage config
ls -lh /var/backups/homepage/homepage-config-20261025-1115.tar.gz
实测输出:
-rw-r--r-- 1 root root 2.2K Oct 25 11:19 /var/backups/homepage/homepage-config-20261025-1115.tar.gz
备份前先核对包内容(-C /opt/homepage config 使包内路径统一为 config/,恢复时解到 /opt/homepage 即还原原位):
tar tzf /var/backups/homepage/homepage-config-20261025-1115.tar.gz
实测输出:
config/
config/proxmox.yaml
config/docker.yaml
config/kubernetes.yaml
config/bookmarks.yaml
config/services.yaml
config/secret_key.txt
config/widgets.yaml
config/settings.yaml
config/logs/
config/logs/homepage.log
💡 说明:备份无需停服务——tar 读取的是普通文件,homepage 配置低频变更,读到「半新半旧」的概率可忽略;要求严格一致时可在
docker compose stop后打包再start。注意包里除 5 个 YAML 外还有secret_key.txt(HOMEPAGE_FILE_*注入的凭据文件)与logs/,备份该目录即备份全部状态。
3.2 恢复演练(真实故障模拟)
模拟最坏情况——配置目录整体丢失,验证「全新骨架启动 → 备份恢复 → 配置还原」全链路:
第 1 步:停服务,把配置目录挪走模拟丢失:
cd /opt/homepage
docker compose down
mv config config.lost
实测输出:
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
第 2 步:空目录启动,观察骨架重建:
mkdir -p config
docker compose up -d
等健康检查转绿后验证——服务正常但已回到官方示例配置(自定义内容全部丢失):
curl -s http://homepage.example.com:8129/api/healthcheck
实测输出:
up
head -3 /opt/homepage/config/settings.yaml
实测输出:
---
# For configuration options and examples, please see:
# https://gethomepage.dev/configs/settings/
⚠️ 注意:骨架重建只会补回官方示例 YAML,自己放进配置目录的自定义文件(如
HOMEPAGE_FILE_*指向的凭据文件)不会凭空再生——这正是必须备份的原因。
第 3 步:清掉骨架,从备份恢复:
docker compose down
rm -rf /opt/homepage/config
tar xzf /var/backups/homepage/homepage-config-20261025-1115.tar.gz -C /opt/homepage
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 Starting
Container homepage-v2.7.0-web Started
第 4 步:验证配置原样还原——探针恢复后,用登录会话读取页面标题(该值来自 settings.yaml 里的 {{HOMEPAGE_VAR_DASHNAME}} 占位符渲染):
curl -s http://homepage.example.com:8129/api/healthcheck
实测输出:
up
curl -s -b cookies.txt http://homepage.example.com:8129/ | python3 -c "
import json,sys,re
m=re.search(r'<script id=\"__NEXT_DATA__\" type=\"application/json\">(.*?)</script>', sys.stdin.read(), re.S)
print('title:', json.loads(m.group(1))['props']['pageProps']['initialSettings'].get('title'))
"
实测输出:
title: 测试变量仪表盘
标题与丢失前一致,恢复闭环完成。清理演练残留:rm -rf /opt/homepage/config.lost。
3.3 定时备份
把 3.1 的打包动作固化为脚本 /opt/homepage/backup.sh(打包 → 只保留 7 天内的备份包):
#!/bin/bash
# homepage 配置目录定时备份:打包 + 7 天保留清理
set -e
BACKUP_DIR=/var/backups/homepage
STAMP=$(date +%Y%m%d-%H%M)
mkdir -p "$BACKUP_DIR"
tar czf "$BACKUP_DIR/homepage-config-$STAMP.tar.gz" -C /opt/homepage config
find "$BACKUP_DIR" -name 'homepage-config-*.tar.gz' -mtime +7 -delete
ls -lh "$BACKUP_DIR/homepage-config-$STAMP.tar.gz"
赋予执行权限并手动跑一次验证:
chmod +x /opt/homepage/backup.sh
bash /opt/homepage/backup.sh
实测输出:
-rw-r--r-- 1 root root 2.2K Oct 25 11:24 /var/backups/homepage/homepage-config-20261025-1124.tar.gz
备份目录中按天累积(旧包由脚本按 -mtime +7 自动清理):
ls -lh /var/backups/homepage/
实测输出:
-rw-r--r-- 1 root root 2.2K Oct 25 11:19 homepage-config-20261025-1115.tar.gz
-rw-r--r-- 1 root root 2.2K Oct 25 11:24 homepage-config-20261025-1124.tar.gz
写入 root 的 crontab,每天 03:10 执行(crontab -e 追加一行):
10 3 * * * /opt/homepage/backup.sh >> /var/log/homepage-backup.log 2>&1
⚠️ 注意:备份包只落在本机
/var/backups/homepage/,宿主机磁盘故障时备份会一起丢;生产环境应把该目录再同步到异地(rsync/对象存储均可,包仅 KB 级)。
四、监控告警
homepage 自身不提供指标端点,监控以「存活探针 + 日志事件」两条线组织:探针回答「挂没挂」,日志回答「有没有人撞门」。
💡 技术拓展:服务探针的三种常见方式对比——
方式 原理 适用场景 HTTP 探针 请求专用健康端点,校验状态码与响应体 有健康端点的 Web 服务(本文采用) ICMP 探针 ping 主机/IP,只测网络可达 不关心应用进程是否存活的粗粒度场景 进程探针 检查进程/端口监听存在 无健康端点的后台程序 homepage 内置免认证的
/api/healthcheck端点且返回体可断言(up),HTTP 探针能同时验证「进程在、端口通、应用可用」三层,本文实际采用。
4.1 存活探针
两种访问形态各挂一条 HTTP 探针(HTTPS 自签证书需 -k 跳过校验):
curl -s http://homepage.example.com:8129/api/healthcheck
curl -sk https://homepage.example.com:8130/api/healthcheck
实测输出:
up
up
两条探针分别覆盖「应用本体」与「HTTPS 反代链路」,任一返回非 up(或超时)即触发告警。建议探针间隔 30–60 秒;homepage 无缓存依赖,探针频率对服务端无压力。
4.2 登录失败监控
公网形态下最值得监控的应用层事件是密码撞门。先复现一次失败登录:
CSRF=$(curl -s -c cookies_bad.txt http://homepage.example.com:8129/api/auth/csrf)
TOKEN=$(echo "$CSRF" | python3 -c 'import json,sys;print(json.load(sys.stdin)["csrfToken"])')
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=$TOKEN&password=wrongpass"
实测输出:
错误密码回调: HTTP 302, redirect=http://homepage.example.com:8129/api/auth/error?error=CredentialsSignin&provider=credentials
应用日志留下固定格式的 warn 记录:
cd /opt/homepage
docker compose logs --since 5m homepage | grep -i "sign-in"
实测输出:
homepage-v2.7.0-web | [2026-10-25T03:21:03.361Z] warn: <nextauth> Failed password sign-in attempt
Failed password sign-in attempt 这一行就是监控与封禁的锚点:最小方案是定时 grep 该关键字超阈值即告警;正式方案是对接 fail2ban/CrowdSec,按源 IP 对 /api/auth/callback/credentials 的失败 POST 自动封禁(homepage 应用层不做限速,公网部署必须补上这层)。
五、扩容缩容
homepage 是无状态仪表盘:没有数据库、不做持久缓存,单实例资源占用极小。扩容缩容的重点因此不是「加机器」,而是摸清水位、管好日志体量、明确多实例的边界。
5.1 资源水位实测
docker stats --no-stream --format 'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}' homepage-v2.7.0-web homepage-caddy-https
实测输出:
NAME CPU % MEM USAGE / LIMIT NET I/O BLOCK I/O
homepage-v2.7.0-web 0.00% 106.7MiB / 23.42GiB 7.53kB / 3.32kB 295kB / 0B
homepage-caddy-https 0.00% 12.85MiB / 23.42GiB 10.3kB / 9.6kB 782kB / 246kB
💡 说明:空闲态 homepage 常驻内存约 107MiB(Next.js 应用基线),Caddy 约 13MiB,CPU 接近 0。加上页面渲染峰值,1GB 内存的小型服务器即可稳定承载;服务集成(widget 探针)增多时内存略有上浮,仍远够不着小机型瓶颈。缩容(降配)前跑一次
docker stats对照本节水位即可判断余量。
5.2 多实例边界
单机横向扩容 homepage 没有收益(无状态、无并发瓶颈),真正需要多实例的场景是「多机房各部署一套、各自看各自的服务面」。多实例时注意三点:HOMEPAGE_ALLOWED_HOSTS 与 HOMEPAGE_EXTERNAL_URL 按各自访问形态分别配置;Docker socket 只读挂载只反映本机服务,跨机服务改用 docker.yaml 的远程 HTTP/TLS 接入(见《homepage v2.7.0 配置参数详解》第七章);配置目录各自独立,不存在共享状态。
5.3 日志轮转
应用日志写在挂载目录内(/opt/homepage/config/logs/homepage.log),随运行时间增长。用 logrotate 治理,配置 /etc/logrotate.d/homepage:
/opt/homepage/config/logs/*.log {
weekly
maxsize 10M
rotate 8
missingok
notifempty
compress
delaycompress
copytruncate
dateext
}
逐项说明:weekly 每周轮转、maxsize 10M 超过 10MB 提前触发;rotate 8 保留 8 份;missingok/notifempty 日志缺失或为空时跳过不报错;compress+delaycompress 上上一轮的旧日志压缩(最近一份留原文,便于直接 grep);copytruncate 复制后截断原文件——应用持有日志文件句柄,不用 create 模式重建文件,避免句柄指向旧 inode 继续写入;dateext 用日期做轮转后缀。
先做语法与匹配检查(-d 为演练模式,不动文件):
logrotate -d /etc/logrotate.d/homepage
实测输出(输出节选,实测首尾):
reading config file /etc/logrotate.d/homepage
Reading state from file: /var/lib/logrotate/status
Allocating hash table for state file, size 64 entries
Creating new state
再强制轮转一次验证实际效果:
ls -lh /opt/homepage/config/logs/
logrotate -f /etc/logrotate.d/homepage
ls -lh /opt/homepage/config/logs/
实测输出:
total 4.0K
-rw-r--r-- 1 root root 3.8K Oct 25 11:21 homepage.log
total 4.0K
-rw-r--r-- 1 root root 0 Oct 25 11:24 homepage.log
-rw-r--r-- 1 root root 3.8K Oct 25 11:24 homepage.log-20261025
💡 说明:轮转后原文件被截断为 0 字节(应用句柄继续有效),历史内容存为
homepage.log-20261025;因配置了delaycompress,最近一份不压缩,下一轮才转.gz。该配置同样作用于排障期产生的日志备份。
六、升级与回滚
homepage 更新节奏快(近期基本每周一个 minor 版本),升级与回滚都必须是「改 tag → 拉镜像 → 重建」三步的低风险操作。版本基线:本文成稿时(2026-10-25)官方最新稳定版为 v2.7.0(2026-10-23 发布,以 GitHub Releases 页实查为准)。
6.1 升级标准流程
以实测的「v2.6.0 → v2.7.0 升级」演示完整流程(未来升级到更新版本时,只需替换目标 tag)。升级前先执行第三章备份。
第 1 步,编辑 /opt/homepage/docker-compose.yml,把 image 的 tag 换成目标版本:
image: ghcr.io/gethomepage/homepage:v2.7.0
第 2 步,拉取新版本镜像:
cd /opt/homepage
docker compose pull
实测输出:
Image ghcr.io/gethomepage/homepage:v2.7.0 Pulling
Image ghcr.io/gethomepage/homepage:v2.7.0 Pulled
第 3 步,滚动重建服务(compose 检测到镜像变化自动重建):
docker compose up -d
实测输出:
Container homepage-v2.7.0-web Recreated
Container homepage-v2.7.0-web Started
第 4 步,三重验证:版本确实切换、探针存活、配置无恙:
docker compose images
实测输出:
CONTAINER REPOSITORY TAG PLATFORM IMAGE ID SIZE CREATED
homepage-v2.7.0-web ghcr.io/gethomepage/homepage v2.7.0 linux/amd64 19c5c0918445 376MB 36 hours ago
curl -s http://homepage.example.com:8129/api/healthcheck
docker compose logs homepage | grep -m1 "Next.js"
实测输出:
up
homepage-v2.7.0-web | ▲ Next.js 16.4.1
⚠️ 注意:不要用
latest标签做升级通道——latest会跨大版本滚动(v2 → v3),行为变化不可控;升级一律锁定精确版本号(tag 策略对比见《homepage v2.7.0 Docker Compose 部署指南》第二章)。跨大版本升级前先读 Release Notes 的 Breaking Changes,并确认备份在手。
6.2 回滚演练
新版本异常时直接把 tag 换回旧版本重建即可。实测「v2.7.0 → v2.6.0」回滚:
cd /opt/homepage
# 编辑 docker-compose.yml,将 image tag 改回 v2.6.0 后执行:
docker compose up -d
实测输出:
Container homepage-v2.7.0-web Recreate
Container homepage-v2.7.0-web Recreated
Container homepage-v2.7.0-web Started
验证回滚结果与配置保留情况:
docker compose images
实测输出:
CONTAINER REPOSITORY TAG PLATFORM IMAGE ID SIZE CREATED
homepage-v2.7.0-web ghcr.io/gethomepage/homepage v2.6.0 linux/amd64 3e38fe788223 369MB 7 days ago
curl -s http://homepage.example.com:8129/api/healthcheck
docker compose logs homepage | grep -m1 "Next.js"
curl -s -b cookies.txt http://homepage.example.com:8129/ | python3 -c "
import json,sys,re
m=re.search(r'<script id=\"__NEXT_DATA__\" type=\"application/json\">(.*?)</script>', sys.stdin.read(), re.S)
print('title:', json.loads(m.group(1))['props']['pageProps']['initialSettings'].get('title'))
"
实测输出:
up
homepage-v2.7.0-web | ▲ Next.js 16.3.8
title: 测试变量仪表盘
💡 说明:v2.6.0 与 v2.7.0 之间配置完全互通(YAML 配置在两个版本间往返,标题、主题、服务分组原样保留)。这就是 3.1 节强调「全部状态=一个目录」的红利:版本回滚不涉及任何数据迁移。若确实回滚失败,还有 3.2 节的备份恢复兜底。
七、故障排查手册
本章沉淀运维期真实发生过的故障,按「现象 → 定位 → 解决」组织。排查通用入口永远是:docker compose ps 看状态 → docker compose logs homepage 看日志 → 按下述案例对号入座。
7.1 探针返回 Host validation failed
现象:/api/healthcheck 返回错误 JSON 而非 up。实测复现(用未被白名单收录的 127.0.0.1:8129 直连):
curl -s http://127.0.0.1:8129/api/healthcheck
实测输出:
{"error":"Host validation failed. See logs for more details."}
定位:日志给出被拒的完整 主机:端口 与修复提示:
docker compose logs --since 10m homepage | grep "Host validation"
实测输出:
homepage-v2.7.0-web | [2026-10-25T03:27:48.860Z] 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 重建后复测。注意内置白名单只有 localhost:3000 与 127.0.0.1:3000,宿主端口映射后「本机直连」也是新的白名单条目;同一域名走 8129 直连与 8130 反代是两个条目。
7.2 服务反复重启(Restarting),探针连接失败
现象:docker compose ps 状态在 Restarting 循环,探针连接被拒。实测复现(配置目录被误加只读挂载 :ro 且目录为空时):
docker compose up -d
等待数秒后查看状态与日志:
docker compose ps
实测输出:
NAME STATUS
homepage-v2.7.0-web Restarting (1) Less than a second ago
docker compose logs homepage
实测输出(输出节选,实测首尾):
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 | ✓ Running next.config took 1.3ms
homepage-v2.7.0-web | ❌ Failed to initialize required config: /app/config/settings.yaml
homepage-v2.7.0-web | Reason: EROFS: read-only file system, copyfile '/app/src/skeleton/settings.yaml' -> '/app/config/settings.yaml'
homepage-v2.7.0-web | Hint: Make /app/config writable or manually place the config file.
探针此时连接失败:
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://homepage.example.com:8129/
实测输出:
HTTP 000
定位:Restarting (1) 表示进程以非零码退出被反复拉起;日志 EROFS: read-only file system 指明启动时要把配置骨架复制进 /app/config,而该路径只读。解决:去掉挂载项里的 :ro 后缀(配置目录必须可写——homepage 会在其中写骨架、写日志),重建后恢复 healthy。若业务确实要求只读,必须手工预置全部配置文件并接受无法写日志的代价,不建议。
7.3 降权运行(PUID/PGID)与目录属主
现象:配置 PUID/PGID 以非 root 用户运行时,担心挂载目录属主不匹配导致启动失败。实测结论:homepage 启动脚本会自动把 /app/config 的属主修正为 PUID:PGID。实测把配置目录整体置为 root:root 后设置 PUID=1000/PGID=1000 启动,服务照常 healthy,目录属主被自动改写:
ls -ln /opt/homepage/config | head -4
实测输出:
total 36
-rw-r--r-- 1 1000 1000 289 Oct 25 10:03 bookmarks.yaml
-rw-r--r-- 1 1000 1000 42 Oct 25 10:03 docker.yaml
-rw-r--r-- 1 1000 1000 31 Oct 25 10:01 kubernetes.yaml
结论:属主不匹配无需人工干预,启动即自愈;但仍建议把挂载源目录属主预先 chown 成与 PUID/PGID 一致的值,避免依赖隐式改写。若还叠加了只读挂载则同 7.2 会直接崩溃。
7.4 端口占用核查
现象:docker compose up -d 报端口分配失败(port is already allocated)。定位用 ss 看宿主端口当前占用者:
ss -ltnp | grep 8129
实测输出(正常状态,homepage 栈自己占用):
LISTEN 0 4096 0.0.0.0:8129 0.0.0.0:* users:(("docker-proxy",pid=1576849,fd=8))
LISTEN 0 4096 [::]:8129 [::]* users:(("docker-proxy",pid=1576855,fd=8))
解决:占用者是 docker-proxy 说明已被本栈或另一套编排占用,先 docker compose ls 或逐栈 docker compose ps 找到占端口的编排停掉/改端口;改宿主端口后务必同步 HOMEPAGE_ALLOWED_HOSTS(见 7.1)与 HOMEPAGE_EXTERNAL_URL。
7.5 配置改坏后的排查路径
现象:改完 YAML 后服务区块消失、widget 无数据,但页面仍能打开。定位顺序:先跑配置自检端点拿精确错误(文件名、原因、行号),再看日志确认加载失败记录:
curl -s -b cookies.txt http://homepage.example.com:8129/api/validate
健康时返回 [];有错时返回形如 [{"name":"YAMLException","config":"services.yaml","reason":"deficient indentation","mark":{"line":25}}] 的错误数组,按 line 行号修缩进即可。homepage 对坏配置的容错是「跳过该文件、页面不崩」,判断配置健康必须用该端点或日志,不能只看页面。完整的坏 YAML 制造、复现与修复实录见《homepage v2.7.0 配置参数详解》第八章案例 4。
八、常见问题
Q1:备份时需要停服务吗?
不需要。备份对象是普通文件(几 KB 的 YAML 与日志),tar 直接读即可;要求严格时间点一致时再 docker compose stop → 打包 → start。恢复时则必须先 down——恢复是把文件覆盖回挂载目录,服务运行中覆盖会造成读写竞争。
Q2:升级或回滚会丢配置吗?
不会。配置全部在挂载目录中,镜像替换不触碰该目录。本文 6.1/6.2 两节在 v2.6.0 ↔ v2.7.0 之间双向演练,页面标题(占位符渲染值)与全部配置项原样保留。跨大版本升级(如未来 v3)先读 Release Notes 并备份,仍以「改精确 tag → pull → up -d」推进。
Q3:日常巡检应该盯哪几个指标?
四个:docker compose ps 为 healthy;/api/healthcheck 返回 up;/api/validate 返回 [];du -sh /opt/homepage/config 维持 KB 级基线。前两个回答「活着」,第三个回答「配置没改坏」,第四个回答「没有被塞进异常文件」。
Q4:HTTPS 访问浏览器提示证书不受信任?
这是 Caddy 自签方案的预期行为:本地验证域名没有公网解析,证书由 Caddy 内部 CA 签发,浏览器不信任属正常现象。生产换真域名后删掉 Caddyfile 里的 tls internal 一行即可自动签发受信证书(自签与 ACME 两种方式的取舍详见《homepage v2.7.0 Docker Compose 部署指南》第十章)。
九、参考链接
- 官方 Docker 安装文档(环境变量与认证门控权威说明):https://gethomepage.dev/installation/docker/
- Troubleshooting 官方排障指南:https://gethomepage.dev/troubleshooting/
- Configuration 目录(各 YAML 文件详解):https://gethomepage.dev/configs/
- GitHub Releases(版本发布清单,升级前实查最新稳定版):https://github.com/gethomepage/homepage/releases
- Caddy 文档(reverse_proxy 与 TLS 配置):https://caddyserver.com/docs/
- 本专栏同主题:《homepage 介绍与选型指南》、《homepage v2.7.0 Docker Compose 部署指南》、《homepage v2.7.0 配置参数详解》