家用服务器状态页想给家人看?Homepage 仪表盘整理服务入口,再用 cpolar 安全开放临时访问
2026/7/15 14:57:15 网站建设 项目流程

家用服务器状态页想给家人看?Homepage 仪表盘整理服务入口,再用 cpolar 安全开放临时访问

一台旧笔记本或 NUC 刷了 Linux,上面跑了 Jellyfin 看电影、Immich 存照片、Navidrome 听歌、Calibre-Web 看书、Gitea 写笔记、FreshRSS 看订阅。服务越来越多,家人每次想用某个功能都得来问"那个看电影的叫什么来着?IP 多少?端口多少?"

服务一多,入口就散。每个人记几个 IP+端口不现实,尤其家人不是技术人员。

Homepage(gethomepage.dev)就是干这个的:一个轻量 Docker 仪表盘,把你所有自托管服务整理成卡片、分组、带图标和运行状态。家庭内网打开浏览器就能看到全部入口。

而 cpolar 解决的场景是——家人出门在外,或者过年回老家,想看一眼家里的相册或读一本书,怎么安全访问?用 cpolar 开一个短时 HTTPS 地址,只暴露 Homepage 导航页,不暴露每个服务的管理端口和后端数据库。

本文完整跑通 Homepage 仪表盘 + cpolar 临时开放入口,从部署、配置到安全边界一步到位。

适用场景

这套组合适用的具体场景:

  • 内网跑了 5 个以上 Docker 服务,家人记不住每个服务的 IP 和端口号,需要一个导航页统一入口。
  • 家庭小主机上有照片、音乐、电子书、影视等服务,家人出差或旅游时想临时远程看一张照片或听一首歌。
  • 不想在路由器上做端口映射,不想用 DDNS,只想在需要的时候给一段 HTTPS 网址,用完后回收。
  • 不想把每个服务都暴露到公网,只需要暴露一个导航页,由家人自己决定点进哪个服务。
  • 过年回老家,想给父母展示家里 NAS 上存的照片和视频,不想折腾 VPN 或路由器配置。

核心原则:Homepage 只做导航面板,不做登录后台;cpolar 只暴露导航前台,不暴露后端管理端口、Docker Socket、SSH 或数据库。

最终效果

部署完成后,内网得到:

入口用途是否给家人
http://192.168.x.x:3000Homepage 仪表盘,展示所有服务卡片和运行状态内网直接访问
http://192.168.x.x:3000/adminHomepage 后台配置面板(默认关闭,需先开启)不开放
https://xxxx.cpolar.topcpolar 隧道 HTTPS 地址,映射到 Homepage 前台只在需要时给

家人打开浏览器输入https://xxxx.cpolar.top,看到的是一个干净的服务导航页,上面有:

  • "相册"卡片,点进去是 Immich 界面
  • "电影"卡片,点进去是 Jellyfin 界面
  • "音乐"卡片,点进去是 Navidrome 界面
  • "书库"卡片,点进去是 Calibre-Web 界面
  • "RSS 订阅"卡片,点进去是 FreshRSS 界面

每个卡片显示服务在线状态;下线时卡片灰色,不影响其他卡片使用。

环境准备

本文以一台 Linux 机器演示。macOS 和 Windows WSL2 的命令基本一致,只需把包管理器从 apt 换成 brew / chocolatey。

前置条件:

  • Linux 机器 / Windows WSL2(Ubuntu 22.04、Debian 12 或以上)
  • Docker 和 Docker Compose(>= v2.0)
  • 内网已有至少 2~3 个 Web 服务在运行(Jellyfin、Immich、Navidrome 等任选,没有也无妨,Homepage 空跑一样能展示分组模板)
  • 已注册 cpolar 账号并拿到 authtoken(cpolar 官网注册,免费套餐够用)
  • 一个浏览器(Chrome / Edge / Firefox 均可)

确认基础环境正常:

docker --version docker compose version cpolar version

如果还没有 cpolar,安装并登录:

curl -L https://www.cpolar.com/static/downloads/install-release-cpolar.sh | sudo bash cpolar authtoken <你的token>

cpolar 安装后先确保能正常启动隧道,后面会用到。

Docker 启动 Homepage 仪表盘

创建一个专用目录,存放 Homepage 的配置和数据:

mkdir -p ~/homepage && cd ~/homepage

新建docker-compose.yml

cat > docker-compose.yml <<'EOF' services: homepage: image: ghcr.io/gethomepage/homepage:latest container_name: homepage restart: unless-stopped ports: - "3000:3000" volumes: - ./config:/app/config - /var/run/docker.sock:/var/run/docker.sock:ro environment: - PUID=1000 - PGID=1000 labels: - "homepage.group=Infrastructure" - "homepage.name=Homepage" - "homepage.icon=homepage" - "homepage.href=http://localhost:3000" - "homepage.description=Dashboard" EOF

启动容器:

docker compose up -d

查看日志确认启动正常:

docker compose logs -f

看到Listening on port 3000或类似日志后,打开浏览器访问http://localhost:3000。这时候看到的默认页面是一个空白仪表盘,因为还没有配 services.yaml。

注意:挂载/var/run/docker.sock:ro是为了让 Homepage 自动发现本机运行中的 Docker 容器,并在卡片上显示在线/下线状态。如果不想给这个权限,可以去掉这一行,之后手动配置每个服务的 URL。

配置服务入口、分组和图标

Homepage 的核心配置在~/homepage/config/下。需要创建以下文件:

文件用途
services.yaml服务卡片列表
widgets.yaml小组件(天气、日期、资源监控等)
settings.yaml全局配置(布局、主题、语言等)

先创建services.yaml。下面以家庭常见服务为例做分组展示:

cat > config/services.yaml <<'EOF' --- # 分组:媒体中心 - Media: - Immich: icon: https://cdn.jsdelivr.net/npm/simple-icons@v13/icons/immich.svg href: http://192.168.1.100:2283 description: 家庭照片管理 server: local container: immich-server - Jellyfin: icon: https://cdn.jsdelivr.net/npm/simple-icons@v13/icons/jellyfin.svg href: http://192.168.1.100:8096 description: 电影和电视剧 server: local container: jellyfin - Navidrome: icon: https://cdn.jsdelivr.net/npm/simple-icons@v13/icons/navidrome.svg href: http://192.168.1.100:4533 description: 音乐流媒体 server: local container: navidrome # 分组:阅读与内容 - Reading: - Calibre-Web: icon: https://cdn.jsdelivr.net/npm/simple-icons@v13/icons/calibreweb.svg href: http://192.168.1.100:8083 description: 电子书库 server: local container: calibre-web - FreshRSS: icon: https://cdn.jsdelivr.net/npm/simple-icons@v13/icons/freshrss.svg href: http://192.168.1.100:8080 description: RSS 阅读器 server: local container: freshrss # 分组:开发与工具 - Utilities: - Gitea: icon: https://cdn.jsdelivr.net/npm/simple-icons@v13/icons/gitea.svg href: http://192.168.1.100:3001 description: Git 仓库 server: local container: gitea - Uptime Kuma: icon: https://cdn.jsdelivr.net/npm/simple-icons@v13/icons/uptimekuma.svg href: http://192.168.1.100:3002 description: 服务监控 server: local container: uptime-kuma EOF

再配置widgets.yaml,在顶部显示日期、天气和系统资源:

cat > config/widgets.yaml <<'EOF' --- - greeting: text_size: xl text: "{{HOSTNAME}} 家庭服务" - search: provider: google target: _blank - resources: cpu: true memory: true disk: / cputemp: true uptime: true - datetime: text_size: md format: dateStyle: long timeStyle: short hour12: false - weather: # 替换成你的城市编码,openweathermap 免费注册获取 API key # 不配置天气也不会影响其他功能 # city: Beijing # apiKey: your_openweather_api_key EOF

配置settings.yaml

cat > config/settings.yaml <<'EOF' --- providers: openweather: # 留空或填 API key apiKey: "" layout: Media: style: row columns: 3 Reading: style: row columns: 3 Utilities: style: row columns: 3 title: "家庭服务导航" headerStyle: boxed hideVersion: true useEqualHeights: true EOF

全部写入后重启 Homepage 使配置生效:

docker compose restart

等 10 秒左右,刷新http://localhost:3000,应该能看到分组的服务卡片。每个卡片显示图标、名称、描述,并标注服务在线状态(绿色圆点=在线,灰色=离线)。

配置技巧

  • 如果某个容器的容器名(container 字段)不匹配,状态会一直显示灰色。可以去掉 container 字段,只保留 href,卡片照常可点击。
  • 图标用 simple-icons 的 CDN 链接,格式:https://cdn.jsdelivr.net/npm/simple-icons@v13/icons/<英文名>.svg。Homepage 也支持直接用 emoji 或自定义 base64 SVG。
  • 分组名可以随意改,services.yaml 里- GroupName:就是分组标题行。
  • 如果不想显示某个卡片的状态指示灯,去掉servercontainer字段即可。
可选:让 Homepage 自动发现 Docker 容器

前面 docker-compose.yml 挂载了/var/run/docker.sock,Homepage 自动扫描本机运行的 Docker 容器。

但自动发现的卡片只有标题(容器名),没有分组、图标和描述。如果要细化,还是要手动在 services.yaml 里写。自动发现作为补充,在服务页底部列出尚未整理的新容器。

如果想用自动发现,不必额外配置。重启后如果看到有未分类的卡片,说明自动发现生效。

可选:后台管理面板

Homepage 默认不启用 admin 面板。如果需要登录后管理配置,编辑config/settings.yaml添加:

showStats: true

然后在 docker-compose.yml 的 environment 里加上认证信息。但本文场景下,不开启 admin 面板——家人只需要看导航页,不需要看到后台。管理员直接在服务器上用vi编辑config/services.yaml即可。

用 cpolar 临时 HTTPS 给家人分享

内网 Homepage 跑通后,家人出门在外时怎么访问?

cpolar 在服务器上创建一个隧道,把内网的 Homepage 端口映射成公网 HTTPS 地址,家人打开浏览器输入这个地址就能看到仪表盘。

先启动一个临时隧道,只映射 Homepage 的 3000 端口:

cpolar http 3000

成功输出类似:

Forwarding http://xxxx.cpolar.top -> http://localhost:3000 Forwarding https://xxxx.cpolar.top -> http://localhost:3000

https://xxxx.cpolar.top发给家人,手机或电脑浏览器直接打开就能看到和家里内网一样的仪表盘页面。

如果想把隧道放在后台运行,不受当前终端影响,用 systemd 管理:

cpolar authtoken <你的token> # 编辑 /etc/systemd/system/cpolar.service sudo tee /etc/systemd/system/cpolar.service > /dev/null <<'EOF' [Unit] Description=cpolar tunnel for Homepage After=network.target Wants=network.target [Service] Type=simple ExecStart=/usr/local/bin/cpolar http 3000 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl start cpolar sudo systemctl enable cpolar # 可选:开机自启

用 systemd 方式启动后,每次只想临时开放时,手动执行sudo systemctl start cpolar;用完执行sudo systemctl stop cpolar。不需要的时候不要开自启。

查看当前隧道分配的地址:

sudo journalctl -u cpolar -n 20 --no-pager

在日志中找到Forwarding https://...那一行,那就是家人要用的地址。

安全边界(用完即关)

Homepage + cpolar 的安全风险主要在"导航页暴露了内网哪些服务"。以下是每一步的安全操作清单:

操作一:只分配前台端口,不暴露后台端口

cpolar 只映射 3000 端口(Homepage),不映射 Jellyfin 的 8096、Immich 的 2283 等。家人通过 Homepage 的导航卡片点击,浏览器会走内网地址,如果在外网访问会因为地址是内网 IP 而打不开——这是设计意图。家人真正需要的是从 Homepage 上看到有哪些服务可用,然后自己选一个,通过 cpolar 或路由器端口映射单独开放那个服务的临时入口。如果只给家人看相册,单独用另一条 cpolar 隧道暴露 Immich 端口,而不是把所有服务全打开。

如果一定要在外面也能访问内网服务,有两个办法:

  1. 多隧道模式:为每个需要外网访问的服务启动独立 cpolar 隧道,分别给出不同地址。
  2. 透传方案:Homepage 的 href 写成反向代理路径(如http://192.168.1.100:3000/jellyfin),且前端反代统一走 3000 端口。

本文使用第 1 种——每服务独立隧道,用完即关,精细控制暴露面。

操作二:cpolar 隧道用完立即关闭

# 如果前台启动,Ctrl+C 直接关闭 # 如果 systemd 启动 sudo systemctl stop cpolar sudo systemctl disable cpolar # 确认隧道已关闭 cpolar status

输出应显示无活跃隧道或已断开。

操作三:不在导航页放置管理链接

services.yaml 里不要写 Portainer、SSH Web 终端、Docker Socket 等管理工具的入口。家人用不到管理功能,反而会增加暴露风险。

操作四:避免导航页泄漏内网 IP

services.yaml 中的 href 写内网 IP 没问题(家人点击后如果在内网环境,正常跳转;如果在 cpolar 外网环境,点进去会跳转到内网地址导致打不开,但这不会泄漏更多信息)。如果在意地址泄漏,可以把 href 写成模糊名称或不写。

操作五:定期清理不用的服务卡片

家庭服务会增减更替。不用的卡片删除后重启 Homepage,保持导航页干净。减少暴露面意味着减少家人点错的风险。

# 修改 services.yaml 后 docker compose restart

操作六:日志检查

# 查看 Homepage 访问日志 docker compose logs homepage --tail 50 # 查看 cpolar 连接记录 sudo journalctl -u cpolar -n 30 --no-pager

查看是否有异常 IP 多次扫描非正常路径。免费套餐的 cpolar 日志保留有限,但足够排查高频访问。

常见问题 / 排错

Q1:启动后访问 localhost:3000 显示白屏

原因:Homepage 需要先加载配置文件和资源,首次启动浏览器页面短暂空白。等 30 秒后刷新。

如果持续白屏,查看容器日志:

docker compose logs homepage

常见错误:配置文件 YAML 缩进错误(Homepage 对缩进非常敏感)、容器网络不通、无法访问 icon 的 CDN 地址。可以先用无配置模式测试:

mv config/services.yaml config/services.yaml.bak docker compose restart

此时访问localhost:3000应显示空仪表盘。如果空仪表盘正常,说明问题在 services.yaml 的格式或内容上。

Q2:服务卡片一直显示灰色离线

排查方向如下:

  • container填写的容器名与 Docker 实际容器名不一致。用docker ps查看真实容器名。
  • server写的是local,但 Homepage 容器和要检测的服务容器不在同一个 Docker 网络上。如果服务容器没在 homepage 的 docker-compose.yml 的networks里,状态检测会失败。
  • 如果不是 Docker 容器(比如宿主机直接跑的进程),去掉servercontainer字段,卡片变为无状态模式。

Q3:图标不显示

检查 services.yaml 中的 icon URL 是否可访问。Homepage 默认从 CDN 或者icons/目录加载图标。以下解决方法:

  • 确认 simple-icons CDN 地址有没有写错(区分大小写,如jellyfin不是Jellyfin)。
  • 换用 emoji 图标:icon: emoji-📺,格式是emoji-后接 emoji 字符。
  • 把 SVG 文件下载到本地放在config/icons/目录下,然后icon: /icons/jellyfin.svg
  • 如果内网访问 CDN 慢,可以自建图标反向代理或全部改用 emoji。

Q4:cpolar 隧道启动后,浏览器访问显示 "502 Bad Gateway"

原因:cpolar 无法连接内网 3000 端口。

检查步骤:

# 确认 Homepage 容器在运行 docker ps | grep homepage # 确认端口映射正常 curl -I http://localhost:3000 # 从宿主机之外的另一台设备确认 curl -I http://192.168.1.100:3000

如果内网访问正常但 cpolar 显示 502,检查防火墙是否阻止了回环连接。

Q5:配置修改后不生效

Homepage 不会热加载配置文件的改动。修改 services.yaml / widgets.yaml / settings.yaml 后需要重启:

docker compose restart

如果想使用 Homepage 的 admin 面板在线编辑(家庭场景用不到),需要在 settings.yaml 里开启enablePasswordProtection: true并配置环境变量。更安全的方式还是在服务器上用 vi 改完重启。

Q6:cpolar 免费套餐的速率限制

cpolar 免费套餐有每月流量和速度限制。如果家人大量浏览照片或串流视频,cpolar 隧道会跑满流量后断开。解决方案:

  • 只通过 cpolar 访问 Homepage 导航页,实际照片/视频流量走其他隧道或 VPN。
  • 流量到上限后升级套餐,或等次月恢复。
  • 用完隧道后及时关闭,避免后台跑满免费额度。

最后

Homepage 解决的是"服务入口太散"的问题,cpolar 解决的是"临时安全远程访问"的问题。两者配合,不改变内网服务部署方式,不引入 VPN,不调路由器,只需 Docker 一行启动和 cpolar 一行命令。

需要时开隧道,用完关隧道,管理边界清晰。家人打开手机浏览器就能看到家里的服务导航页——相册、书库、音乐、电影卡片一目了然,和在家里操作一样。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询