2847 字
14 分钟
家庭服务器的服务清单:监控、密码库与密钥管理

家庭服务器最容易犯的错,是把“能跑”当成“能运维”。服务装上了、页面能打开,不代表它安全、可恢复、出了问题知道去哪看。我的做法是先定边界:公网只留一个入口,服务默认绑私有地址;然后补三件事——看得见(监控)、管得住(凭据管理)、恢复得了(备份)。

这篇文章不列流水账,而是按这三件事介绍现在这套服务是怎么组织的,重点讲 Beszel 和两种凭据管理:一种管人的密码,一种管机器的密钥。

1. 拓扑:只把入口放到公网#

整体是“一台家用主机 + 一台小 VPS”的结构:

公网
│
Cloudflare(DNS / TLS / Tunnel / Access)
│
VPS(Nginx,公网 HTTPS)
│ WireGuard 私网
家用主机(服务只绑私有地址)

家用主机在 NAT 后面,不开放路由器端口转发;VPS 是唯一的公网入口,负责 TLS 终止和按域名反向代理;Cloudflare 负责 DNS、Tunnel 和边缘认证;两台机器之间用 WireGuard 私网连接。动态服务的请求路径是:

浏览器 → Cloudflare → Tunnel → VPS Nginx → WireGuard → 家用主机

服务本身只监听私有地址。公网域名由 Nginx 按 Host 转发,Access 按域名分别配置,应用自己再做一层登录。这样一来,家庭公网 IP 不暴露,路由器上不需要开洞,TLS 只在边缘处理,入口少、审计面也小。

代价是链路变长:Cloudflare、Tunnel、VPS、WireGuard 任何一环出问题,公网访问都会断。这也是为什么同一个局域网里还要有一条直连入口——那是下一篇文章的内容。

2. 服务地图#

按职责分层,比按容器名罗列更有用:

层组件作用暴露方式
公网入口Cloudflare DNS / TLS / Tunnel / Access域名、证书、隧道、边缘认证公网
边缘反代VPS Nginx按域名转发到私网服务公网 HTTPS
私网WireGuard连接 VPS 与家用主机仅隧道
监控Beszel主机与容器指标Access + 应用登录
密码库Vaultwarden人的密码应用登录 + 2FA
密钥sops + age机器的密钥无网络入口
对象存储MinIO图片、资料只读或受限
照片Immich照片库应用登录
备份定时任务 / 手动数据恢复本机 + 离线

服务不是越多越好。每加一个,至少要能回答四个问题:数据放在哪、谁能访问、怎么备份、怎么回滚。答不上来的,先别加。

3. Beszel:先让状态可见#

Beszel 是一个轻量监控面板,由 Hub 和 Agent 两部分组成。Agent 跑在主机上,负责采集;Hub 存历史数据并提供 Web 界面。这里的 Agent 用 host 网络,通过 unix socket 和 Hub 通信,只读挂载 Docker socket,所以除了 CPU、内存、磁盘、网络,还能看到容器状态。数据落在 SQLite 里,不需要额外数据库。

它解决的是“现在是否正常、趋势有没有变化”:

  • 磁盘是不是快满了,内存有没有持续上涨;
  • 哪个容器在反复重启,网络流量有没有异常;
  • 升级或重建之后,指标有没有恢复。

反向代理有一个必须注意的点:Beszel 的实时指标走 WebSocket。Nginx 要转发 Upgrade、关闭响应缓冲、放长超时,否则页面能打开,数字却不动。这类“看起来正常、实际没数据”的状态,比直接报错更难发现。

日常用法很朴素:每天扫一眼面板;发现异常再去看 docker ps、journalctl 和服务自己的健康检查。容器 Up 不等于健康,端口在监听也不等于业务可用;监控只是线索,不是结论。单主机场景下,Beszel 足够轻,不需要为了监控再上一套 Prometheus + Grafana;告警目前是下一步,先把“看得见”做好。

Beszel 的数据是 SQLite,备份时按 SQLite 的方式做(在线备份或先停服务),不要直接拷运行中的文件。它的重要性低于密码库和照片,但配置和历史趋势有价值,升级前备份一下不亏。

4. 第一种密码管理:人用的密码库#

人用的密码放在 Vaultwarden 里。它是 Bitwarden 服务端的兼容实现,Web、手机、桌面客户端都能用,数据存在本机的 SQLite 里。

安全模型要分两层看:

  • 密码库本身是端到端加密的。 服务器存的是密文;即使主机被攻破,攻击者拿到的也不是明文密码。
  • 登录接口和账号元数据仍然暴露。 主密码、2FA、注册开关、管理面板,这些决定的是“别人能不能登进来”。

所以这里用了主密码 + TOTP/WebAuthn,关闭注册,关闭 /admin,只保留必要的登录入口。没有套 Cloudflare Access,原因和照片服务类似:手机和桌面客户端无法完成浏览器 SSO,套上 Access 反而会把正常客户端挡在外面。补偿手段是把应用自身的认证做扎实,并持续关注 Vaultwarden 的 CVE。

备份是每日一次:对 SQLite 做在线快照,连同附件和密钥材料一起打包,用 age 加密后保留一段时间。这里有两个恢复前提:主密码不能丢,age 私钥也不能丢。前者丢了,密码库打不开;后者丢了,加密备份解不开。主密码丢失无法恢复,这是这类工具的固有代价。

选择自建的代价是可用性和备份都要自己负责;收益是数据在手里,客户端生态也成熟。对个人使用来说,这个交换是划算的,但前提是备份真的能恢复,而不是只存在一个从没验证过的 tar 包。

5. 第二种密码管理:机器用的密钥#

机器的密钥不放在密码库里,而是用 sops + age 管理。

做法是:加密后的 env 文件进 git,键名保持明文,值用 age 加密;部署时用脚本解密,渲染成权限 600 的 .env;服务启动只读这个 .env,不依赖任何常驻的密钥服务。这样断网、重启、密钥服务没起来,都不影响业务启动。

为什么不直接用 Vaultwarden?因为机器的密钥需要的是另一套东西:

  • 部署脚本要能非交互地取值,不能等人打开网页点确认;
  • 密钥要跟配置一起版本化,能看历史、能回滚;
  • 服务启动时不能被一个外部服务卡住。

sops + age 的日常操作是“改加密源 → 渲染 → 重建”:

Terminal window
# 改加密源(值在编辑器里临时解密)
./scripts/secrets.sh edit <node> <service>
# 渲染成线上 .env(权限 600)
./scripts/secrets.sh render <node> <service>
# 检查加密源和线上 .env 是否漂移
./scripts/secrets.sh status <node> <service>

改完要重建容器才会重新读 env_file;回滚时从 git 里找旧密文,checkout 后重新渲染。age 私钥必须离线保存,丢了加密源就再也解不开;公钥可以入库。SSH 私钥、Cloudflare Token、磁盘恢复密钥不纳入这套机制,各自单独离线管理。

安全上的硬规则:.env 权限 600;加密源之外不出现明文;密钥不进 compose 字面量、不进 docker run 参数、不进命令行历史、不进聊天记录。渲染前会把旧 .env 备份到本地,避免改错之后没有退路。

6. 为什么分成两套#

把两套放在一起对比,分工很清楚:

维度Vaultwardensops + age
使用者人服务、部署脚本
交互方式Web / 手机 / 桌面,手动CLI,部署时非交互
主要威胁账号被盗、登录接口被撞仓库泄露、主机文件泄露
恢复依赖主密码 + 2FA + 备份age 私钥 + git 历史
适合放什么个人账号、Wi-Fi、网站密码数据库口令、API Key、服务间凭据

人的密码要“随时能取、跨设备同步、有 2FA”;机器的密钥要“版本化、可审计、启动时自动注入”。硬塞进一套,体验和安全性都会变差:把数据库口令放进密码库,部署时要人工取值;把个人密码放进加密 env,又失去了客户端的便利。

两套系统有一个交叉点:age 私钥的离线副本可以放进密码库,同时再留一份 U 盘或异机副本;而密码库的备份本身又用 age 加密。它们互相备份,但运行时互不依赖。这个关系要写清楚,否则真出事时很容易发现“备份的钥匙在备份里”。

7. 备份与恢复#

现在的备份策略按数据重要性分层:

数据方式恢复要点
密码库每日 age 加密打包主密码 + age 私钥
BeszelSQLite 复制低优先级,配置和历史
dsh / Paseo 状态停服务后打包会话、profile、凭据
配置与密钥git + 加密 secrets仓库 + age 私钥
对象存储 / 照片镜像 / dump数据目录 + 数据库一致

原则只有几条:加密、留离线副本、定期做恢复演练、不要直接复制运行中的数据库文件。SQLite 要用在线备份接口或先停服务;Postgres 用 dump,不要拷数据目录。恢复顺序也固定:先主机和网络,再 age 私钥,再渲染 .env,再恢复数据,最后起服务并验证。

单主机是单点,没有高可用;备份是这套系统里唯一“反脆弱”的部分。它不需要很复杂,但必须真的能恢复。

8. 边界与取舍#

这套结构有几个明确的取舍:

  • 没有高可用。 主机、VPS、Tunnel、家庭网络和电力,任何一环出问题都会影响服务。个人环境可以接受,但要知道边界在哪。
  • Access 和应用认证是两层,不互相替代。 Access 挡在边缘,应用认证挡在服务门口;局域网入口会绕过 Access,所以应用认证必须一直在。
  • 明文 HTTP 只用于可信局域网。 公网必须 TLS;局域网直连的便利性,是用“信任这个网络”换来的。
  • 监控不是万能。 Beszel 看趋势,日志看原因,健康检查看端到端;三者不能互相替代。
  • 升级要保守。 镜像固定 digest 或明确 tag,升级前备份,先看 release notes,保留回滚路径。家庭服务没有值班同学,出问题时能退回去比“升到最新”重要。

9. 小结#

服务清单可以很长,但运维只需要回答三个问题:状态看得见吗、凭据管得住吗、数据恢复得了吗。Beszel 解决第一个,Vaultwarden 和 sops + age 解决第二个,备份和恢复演练解决第三个。

把这三点做好之后,再加服务就只是加一个目录、一组配置和一条备份,而不是每次都在赌自己记得住。

相关阅读#

家庭服务器的服务清单:监控、密码库与密钥管理
https://blog.xqcherry.top/posts/operations/homelab-services-beszel-and-secrets/
作者
xqcherry
发布于
2026-11-07
许可协议
CC BY-NC-SA 4.0