🏠 家庭实验室的四层架构:边缘 / 应用 / 云端 / 接入

9月 14, 2026·
BBBlllack
BBBlllack
· 2 分钟阅读时长

这篇是我这套家庭自托管集群的总览。它不是"买台服务器装个 Docker"的入门贴,而是为什么这样分层的复盘 —— 每一层都在解决上一层解决不了的问题。

一、动机:东西越堆越多,然后失控

一开始只是想把照片从手机里挪出来。于是有了一台小主机跑 Immich。后来想有个自己的网盘,又加了 OpenList。再后来要远程访问、要监控、要备份、要证书、要域名……

半年之后我发现:我不知道哪个服务跑在哪台机器上,也不知道某个端口是谁开的。

真正的问题不是"服务太少",而是缺少架构。于是我按职责把设备重新划成四层。

二、四层架构

                    ┌──────────────────────────────┐
   公网 ────────────▶│  接入层  光猫 / SD-WAN 组网    │
                    └──────────────┬───────────────┘
                                   │ 端口映射(增量式)
                    ┌──────────────▼───────────────┐
                    │  边缘层  1.50  Edge Box       │
                    │  nginx / 门户 / 防护 bouncer   │
                    │  代理客户端 / 流量统计         │
                    └──────────────┬───────────────┘
                                   │ 内网 TLS 反代
                    ┌──────────────▼───────────────┐
                    │  应用层  1.40  App Node       │
                    │  Docker: 照片库 / 网盘 / DNS   │
                    └──────────────────────────────┘

                    ┌──────────────────────────────┐
                    │  云端层  VPS(公网入口 / 中继) │
                    │  反向代理 / 穿透服务端 / 数据库 │
                    └──────────────────────────────┘

2.1 边缘层:所有入站流量的唯一入口

边缘盒是一台 ARM 小主机(4 核 / 1GB 级),它承担:

职责实现
Web 入口nginx,静态托管门户站与内部工具页
TLS 终止TrustAsia DV 证书,统一挂 home.***.cn
入侵防护CrowdSec bouncer(决策来自应用层的 LAPI)
出站代理本地 SOCKS5 + HTTP 代理,供内网其他主机借用
流量审计vnStat 按日/月统计双网卡
状态探针fcgiwrap + CGI,输出网卡地址等实时信息

为什么把入口单独拎出来? 因为它必须是唯一的。一旦有两个入口,你就有了两套证书、两套防火墙规则、两套日志,然后开始不一致。

2.2 应用层:只跑应用,不碰边界

应用节点的职责非常窄:跑容器。上面是 Docker 全家桶 —— 照片库(含 PostgreSQL + Redis)、网盘,以及 DDNS 客户端和 CrowdSec LAPI。

它的网络暴露策略是最小化:容器端口只监听内网,对外的 TLS 反代由边缘层做。这样即使某个应用出了 RCE,攻击者也只拿到一个没有公网身份的内网容器。

2.3 云端层:只有公网身份,不存隐私数据

云端那台 VPS 承担两类工作:

  1. 公网入口:反向代理 + 内网穿透服务端,把外部请求送回家里。
  2. 纯服务:递归 DNS、关系库、缓存、远程桌面中继 —— 这些"要么需要固定公网 IP,要么需要独立可用性"的东西。

一条硬规则:隐私数据(尤其照片)绝不上云。 云主机只放可重建的数据。

2.4 接入层:最不该被自动化碰的地方

光猫和 SD-WAN 盒子属于运营商/厂商资产,配置有整体替换的坑(改一条规则可能把整个映射表覆盖掉)。

所以这一层我只做两件事:只增不改(新增映射时严格走 add-only,改前导出、改后校验、失败回滚),以及记录下来(哪条映射对应哪个服务,写进文档而不是记在脑中)。

三、三条关键设计决策

3.1 域名必须统一

站点早期用过 aaa.site 和 bbb.site 两套域名,结果:

  • 证书要签两遍
  • 反代 server_name 要写两组
  • 文档要维护两份映射表
  • 其中一个域名忘了续费,被抢注后全站 canonical 指向了诈骗页

统一到一套域名后,证书、反代、DNS 记录全部收敛成一条线。

3.2 公网暴露面用"高位端口 + 域名"代替"IP + 默认端口"

有备案要求的网络环境下,80/443 上的未备案域名会被边缘劫持到一个阻断页。应对方式不是放弃,而是把 HTTPS 挪到高位端口,靠域名 + TLS 提供服务。代价是 URL 难看,收益是链路可控。

3.3 服务与数据分离

备份策略按层设计:

  • 边缘层:配置 + 证书,改动前必 cp -p 备份,带回滚路径
  • 应用层:数据库卷 + 对象存储目录,定期快照
  • 云端层:可重建,所以只需要配置即代码

四、可观测性:先能看见,才能优化

早期我靠"感觉"判断负载高低,后来改成本地采集 + 静态 JSON 热缓存:

采集进程(应用身份) → 写 /run 下的热缓存 → nginx 读文件返回

关键在于读写分离:HTTP 侧只读缓存,绝不触发采集。这样即使页面被脚本高频轮询,也不会把负载打上去 —— 再叠一层 limit_req 限流,正常用户完全无感。

五、踩过的坑

坑现象结论
限流区定义位置nginx 起不来limit_req_zone 只能在 http{} 内
include fastcgi_params所有 CGI 请求 404它会用 $document_root$fastcgi_script_name 覆盖 SCRIPT_FILENAME,必须手工列参数
光猫映射批量改映射表被整体替换必须 add-only 增量 + 校验 + 回滚
域名续费canonical 全指向诈骗站定期检查 whois 到期时间
容器端口直接对公网暴露面失控应用层端口只在内网可达

六、小结

这套架构的核心不是设备数量,而是分层带来的可推理性质:

  • 想改证书 → 只动边缘层
  • 想加服务 → 只动应用层
  • 想改公网路由 → 只动云端层
  • 想调接入 → 只动光猫,且只增不改

当你需要同时在心里维护超过三台机器的状态时,架构就不是奢侈品,而是必需品。