Homer Dashboard 完整部署与优化:Docker 配置、CORS 健康检查、Proxmox 集成
我的 NAS Dashboard 折腾过好几轮了。Homepage 太复杂,Glance 太素,最后落到了 Homer—— 一个单 HTML 文件就能跑的轻量 Dashboard,配置用 YAML,图标用 Font Awesome,热加载不用重启。
但默认的 Docker 配置有几个坑,健康检查(Ping)也因为浏览器 CORS 策略全挂。踩完一遍坑后记录这篇,下次重建直接抄。
环境:fnOS(<NAS_IP>),Docker Compose,Homer v26.04.2(b4bz/homer)。
Docker Compose 优化
Homer 的官方示例 docker-compose.yml 有几个小问题,长期跑建议改掉:
services: homer: image: b4bz/homer container_name: homer restart: unless-stopped # 尊重手动停止 volumes: - ./www/assets:/www/assets ports: - 8888:8080 deploy: resources: limits: memory: 128M cpus: "0.5" logging:6 collapsed lines
driver: json-file options: max-size: "10m" max-file: "3" security_opt: - no-new-privileges:true| 改动 | 原因 |
|---|---|
always → unless-stopped | NAS 维护时手动 stop 不会被 daemon 拉起 |
移除 INIT_ASSETS=1 | 非首次部署,避免覆盖自定义主题文件 |
移除 user: 1000:1000 | 消除 root-owned 文件权限冲突 |
| 添加资源限制 | 128MB 内存 / 0.5 CPU,防止异常耗光资源 |
| 添加日志轮转 | 10MB × 3 文件,避免日志撑满磁盘 |
| 添加安全加固 | no-new-privileges:true 禁止容器内提权 |
CORS 健康检查代理
这是整个配置里最折腾的部分。
Homer 的 Ping 组件通过浏览器向目标服务发 HEAD 请求来检测状态。问题在于:Homer 页面跑在 <NAS_IP>:8888,目标服务在 <NAS_IP>:xxxx。不同端口 = 不同源,浏览器直接拦截跨域请求。结果就是所有服务全部显示 offline,Ping 组件成了摆设。
解决思路:在 NAS 上跑一个轻量 Python 代理(端口 8889),浏览器请求发给代理,代理转发给目标并附加 CORS 头。
浏览器 → Homer(:8888) → CORS代理(:8889) → 各服务端口 ↑ 直连导航 ↑ 健康检查(加 CORS 头)代理代码
app.py 核心逻辑:
from http.server import HTTPServer, BaseHTTPRequestHandlerfrom socketserver import ThreadingMixInimport urllib.requestimport ssl
class ThreadingServer(ThreadingMixIn, HTTPServer): """多线程处理并发请求"""
class ProxyHandler(BaseHTTPRequestHandler): def do_GET(self): target_url = self.path.split('?url=', 1)[-1] ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE # Proxmox 自签名证书
17 collapsed lines
req = urllib.request.Request(target_url) # 透传 Authorization 头(Proxmox API 需要) auth = self.headers.get('Authorization') if auth: req.add_header('Authorization', auth)
try: with urllib.request.urlopen(req, timeout=10, context=ctx) as resp: self.send_response(200) except Exception: self.send_response(502)
self.send_header('Access-Control-Allow-Origin', '*') self.end_headers()
server = ThreadingServer(('0.0.0.0', 8889), ProxyHandler)server.serve_forever()踩坑记录
-
单线程排队:Python
http.server默认单线程,12 个 Ping 同时请求导致排队超时。ThreadingMixIn解决。 -
fnOS 防火墙:
<NAS_IP>外部访问被拦,只有127.0.0.1能通。NAS 本机服务的健康检查 URL 统一用127.0.0.1。 -
HEAD 不支持:飞牛终端 (5122)、OpenList (5255) 等服务返回 405。代理内部 HEAD 自动转 GET。
-
超时不够:Ping 默认 2 秒,云端服务(尤其海外)来不及。
timeout: 10000。
端点格式速查
# NAS 本机服务(代理用 127.0.0.1)endpoint: "http://<NAS_IP>:8889/?url=http://127.0.0.1:10880"
# 其他物理机服务endpoint: "http://<NAS_IP>:8889/?url=http://<N8N_HOST_IP>:5678"
# 云端 HTTPS 服务endpoint: "http://<NAS_IP>:8889/?url=https://marxchou.com"Proxmox 监控集成
Homer 内置 Proxmox 类型支持,可以直接展示节点 CPU / 内存使用率。不过有个小坑:认证方式要用 api_token 而不是 username/password。
- name: Proxmox(监控) type: Proxmox url: https://<PVE_HOST_IP>:8006 endpoint: http://<NAS_IP>:8889/?url=https://<PVE_HOST_IP>:8006 node: zcpve api_token: PVEAPIToken=root@pam!homer=<secret> warning_value: 50 danger_value: 80 updateIntervalMs: 30000由于 Proxmox 使用自签名 SSL 证书,代理端必须忽略证书验证(ssl.CERT_NONE),同时透传 Authorization 头。不然 API Token 认证过不去。
配置文件结构
Homer 支持多页面,我把服务按位置分了三页:
| 文件 | 页面 | 内容 |
|---|---|---|
config.yml | 主页 (Nas) | 本地 NAS 服务 |
localhost.yml | #localhost | 局域网其他设备 + Proxmox |
cloud-server.yml | #cloud-server | 公网云端服务 |
服务条目模板:
# 本地服务- name: "Gogs" icon: "fa-brands fa-git-alt" subtitle: "轻量级 Git 服务 · :10880" tag: "dev" url: "http://<NAS_IP>:10880" endpoint: "http://<NAS_IP>:8889/?url=http://127.0.0.1:10880" type: "Ping"
# 云端服务(注意 timeout)- name: "MarxChou" icon: "fa-solid fa-feather" subtitle: "个人博客" tag: "blog" url: "https://marxchou.com"5 collapsed lines
endpoint: "http://<NAS_IP>:8889/?url=https://marxchou.com" successCodes: [200, 301, 302, 308, 401, 403] timeout: 10000 updateIntervalMs: 60000 type: "Ping"NAS 上目前监控了 18 个服务:Gogs、Rustpad、Syncthing、Linkwarden、Wallos、Tiny Tiny RSS、RSSHub、Donetick、Linkding 等。
排障速查
服务显示 offline:
curl "http://localhost:8889/?url=http://127.0.0.1:PORT"— 测试代理可达性ss -tlnp | grep PORT— 确认目标端口在监听docker ps -a --filter name=xxx— 确认容器在跑docker logs homer-health | grep PORT— 查看代理日志curl http://localhost:8888/assets/config.yml— 确认配置被正确加载
代理挂了:
cd /vol1/1000/docker/homer-healthdocker compose down && docker compose up -d --build添加新服务: 在对应 yml 里加条目 → Homer 热加载,无需重启。导航 URL 用 <NAS_IP>:PORT,健康检查用 127.0.0.1:PORT。
云端服务误报 offline: 默认 Ping 超时 2 秒不够。加 timeout: 10000,顺手加 updateIntervalMs: 60000 还能解决 “Invalid registration parameters” 警告。
文件清单
/vol1/1000/docker/├── homer/│ ├── docker-compose.yml # Homer 主容器│ └── www/assets/│ ├── config.yml # NAS 主页配置│ ├── localhost.yml # 局域网服务 + Proxmox│ ├── cloud-server.yml # 云端服务│ └── catppuccin-macchiato.css # 主题└── homer-health/ ├── docker-compose.yml # CORS 代理容器 ├── Dockerfile └── app.py # 代理核心代码总结
Homer 本身很简单:一个 HTML 文件加一个 YAML 配置就能跑。但要让健康检查真正工作,CORS 代理是绕不过去的。Python 几行代码的事,不过单线程、HEAD 不支持这些坑踩过才知道。
Dashboard 这种东西,折腾的乐趣大于实用价值。但每天打开浏览器看到一排绿灯,心情确实好一点。