这次整理个人服务器,我最想解决的不是「再多跑几个服务」,而是把已经长出来的一堆服务重新放回清晰的边界里。
过去很多 HomeLab 的服务会自然堆在一起:博客、导航页、监控、面板、自研项目、机器人、Minecraft 私服,还有各种临时实验。它们一开始都只是「先跑起来」,时间久了之后,入口、域名、数据库、端口和备份策略就会互相缠在一起。出问题时很难判断是哪一层坏了,迁移时也很难只搬走其中一部分。
现在回头看,四月那版更像迁移草稿:先把 HK Main、Mac mini、代理节点和各个 Stack 的职责画出来。今天这版则更接近当前现场:哪些域名真的在用,哪些服务已经成为长期服务,哪些入口只是为了朋友访问或我自己维护而存在。
所以这套 framework 的目标很明确:公网入口统一,服务按职责拆分,敏感组件收回内网,静态内容尽量交给托管平台,真正需要长期运行、持久化或接入内网的服务再放到 Mac mini 上。
当前架构采用「Cloudflare 统一 DNS/访问层 + HK Main 公网入口 + Mac mini 本地核心服务」的模式。
flowchart LR
User["公网用户 / 朋友"] --> CF["Cloudflare DNS / CDN"]
CF --> Pages["Cloudflare Pages<br/>Astro Blog 等静态内容"]
CF --> HK["HK Main<br/>frps only"]
HK --> FRPC["Mac mini<br/>frpc"]
FRPC --> NPM["Nginx Proxy Manager"]
NPM --> Monitor["monitor-stack<br/>Komari"]
NPM --> Home["homepage-stack<br/>Homepage"]
NPM --> Private["private-services-stack<br/>Nextcloud / Vault"]
NPM --> VPN["vpn-stack<br/>VPN 下载与配置入口"]
Friends["可信朋友"] --> GameAccess["Tailscale 优先<br/>frp / 域名备用"]
GameAccess --> Games["game-stack<br/>Game Server"]
VPN --> Nodes["代理 / VPN 节点<br/>按需接入"]
这里的关键是把「入口」和「业务」拆开。
HK Main 只作为公网入口,负责运行 frps,不承载数据库、不放个人文件、不跑长期业务,也不和代理出口节点混用。真正的服务运行在本地 Mac mini 的 Orbstack 里,由 frpc 接入 HK Main,再交给 Nginx Proxy Manager(NPM)做域名分流和反向代理。
静态博客仍然适合放在 Cloudflare Pages 这类托管平台上;但当前的 homepage.shishishi3.com 已经不是单纯的静态主页,而是 HomeLab 的导航和状态入口,所以它作为长期服务放在 Mac mini 上。这样一来,静态发布面和内网服务面不会互相拖累。
Mac mini 是这套系统的核心宿主机。它没有公网 IP,主要负责运行长期服务、数据库、自研项目、机器人和游戏服务。所有容器按 Docker Compose Stack 拆分,每个 Stack 都有自己的配置目录、数据目录和网络边界。
HK Main 是唯一暴露在公网入口层的主机。它只运行 frps,接收来自 Cloudflare 后的 HTTP/HTTPS 流量,再通过 frp 转发到 Mac mini。这个节点的职责越少越好,因为它在公网侧,攻击面必须尽量小。
代理或 VPN 节点只承担网络出口和接入职责,不参与 Nextcloud、Homepage、Komari、游戏服等主业务服务,也不和 HK Main 混用。节点可以增减,但入口层和本地服务层不跟着晃。
这种拆分的好处是边界清楚:入口坏了查 HK Main,业务坏了查 Mac mini,文件同步坏了查 Nextcloud,监控异常看 Komari,游戏访问异常查 gs 和对应端口,不需要在同一台机器上翻一堆彼此无关的容器。
域名也按职责拆开。现在我不再把域名表写成「未来想跑什么」,而是直接按当前正在使用的入口来记。
shishishi3.com 用来承载面向我自己和可信访问者的常规 Web 服务:
| 子域名 | 服务 | 部署位置 |
|---|---|---|
komari.shishishi3.com | Komari 监控面板 | monitor-stack |
homepage.shishishi3.com | Homepage 导航与服务入口 | homepage-stack |
vpndl.shishishi3.com | VPN 下载、配置或说明入口 | vpn-stack |
gs.shishishi3.com | 游戏服务访问入口 | game-stack |
nc.shishishi3.com | Nextcloud 文件与同步服务 | private-services-stack |
v.shishishi3.com | Vault / 私密工具入口 | private-services-stack |
这一版比四月的规划更收敛:status、panel、bot、demo 这些名字先从文章里拿掉,不再用它们代表当前状态。需要时当然还可以重新加,但域名规划应该反映正在跑的服务,而不是把所有可能性都提前占住。
基础设施域名则继续保持低调,只用来指向 HK Main、frp、节点或内部管理入口。普通服务入口放在 shishishi3.com 下,基础设施入口不要和业务域名混在一起。排查 DNS、证书、Cloudflare 规则和 NPM 反代时,这条线越清楚越省事。
这套方案不把 Cloudflare Tunnel 作为主入口。Cloudflare 负责 DNS、CDN、WAF 和访问控制,真正需要回到本地的源站入口统一落到 HK Main。
Web 流量的路径大致是:
用户浏览器
-> Cloudflare
-> HK Main:80/443
-> frps
-> Mac mini frpc
-> NPM
-> Komari / Homepage / Nextcloud / Vault / VPN 入口等服务容器
端口转发采用 TCP 方式:
HK Main:80 -> frps:8080 -> Mac mini frpc -> NPM:80
HK Main:443 -> frps:8443 -> Mac mini frpc -> NPM:443
frps 只做转发,不在 HK Main 上处理业务请求。frpc 和 frps 之间启用 TLS 传输,NPM 负责域名分流、反向代理和证书管理。后端服务不直接向公网暴露端口,只加入 NPM 能访问到的 Docker 网络。
非 HTTP/HTTPS 服务不强行塞进 NPM。比如 gs.shishishi3.com 更像是游戏服务的友好入口标识,实际连接可以按游戏协议、端口和访问对象来决定:可信朋友优先走 Tailscale,无法安装客户端时再通过 frp 或受限端口作为备用入口。
Mac mini 上的服务按职责拆成几层。名字不需要追求漂亮,关键是看到目录就能知道它负责什么。
edge-stack 是入口层,包含 frpc 和 NPM。它负责把公网流量接入本地,并把不同域名转发到对应服务。NPM 管理后台默认只允许内网或 Tailscale 访问,不直接暴露到公网。
monitor-stack 放 Komari。监控系统看起来只是一个面板,但它承担的是「我是不是该起来看一眼」这种责任,所以要独立持久化,升级时也不要和其他服务绑在一起。
homepage-stack 放 Homepage。它是人的入口,不是机器入口:链接、分组、服务状态、常用管理地址都可以放这里。它可以暴露给自己使用,但不应该顺手把每个后台都直接暴露出去。
private-services-stack 放 Nextcloud 和 v.shishishi3.com 这类私密服务。这里的共同点不是技术栈,而是数据敏感:文件、同步数据、密码库或其他私人资料都要有明确的数据卷、备份计划和访问限制。
vpn-stack 放 vpndl.shishishi3.com 对应的下载、配置或说明入口。它不一定需要复杂,但它牵涉到接入方式,所以要和普通展示项目分开,避免随手改一个页面时影响别人连接。
game-stack 放 gs.shishishi3.com 背后的游戏服务。游戏服务不和 Web 反向代理混用;访问上优先 Tailscale,备用方案才是 frp 或受限端口。存档、模组和配置文件单独持久化并定期备份。
临时项目仍然可以有自己的 projects-stack,但它不再是这篇文章里的主角。当前这套架构的核心不是「我能展示多少 demo」,而是 Komari、Homepage、VPN 入口、游戏服务、Nextcloud 和私密服务这些已经在使用的东西要稳定。
拆分以后,每个 Stack 都可以独立启动、停止、备份和迁移。新增服务时,先判断它属于哪一层,再加入对应 Stack,而不是把所有容器继续扔进同一个平面里。
HK Main 的原则是「只做入口,不放业务」。它只开放 80、443、frps 控制端口和必要的高位转发端口;frps 使用强 Token,禁用默认管理端口;SSH 只允许密钥登录,禁止密码登录。
Mac mini 的原则是「服务分层,数据收口」。Orbstack 中按 Stack 拆分网络,数据库端口不映射到公网侧,NPM 管理后台不直接暴露公网,所有 .env、数据库密码、Token 和密钥文件都不提交到 Git。Nextcloud 和 Vault 这类服务尤其不能只满足于「页面能打开」,还要确认数据卷、备份和恢复路径。
Cloudflare 的原则是「域名分流,访问控制前置」。常规 Web 服务可以开启 CDN 和 WAF;面板类服务优先叠加 Cloudflare Access 或 IP 限制;证书尽量使用 DNS 验证或 Cloudflare Origin Certificate,避免 HTTP 验证被 frp 转发链路影响。
备份重点包括 Cloudflare Pages 项目配置、Astro Blog 源码仓库、Homepage 配置、Komari 数据、Nextcloud 数据和数据库、Vault 类服务的数据卷、VPN 配置入口、游戏存档和 NPM 配置。能恢复,才算真正部署完成。
现在这套东西已经不是单纯的迁移计划,所以后续维护也不应该从「启动所有容器」开始,而应该先把入口和数据边界理清楚。
第一步是盘点现有容器、镜像版本、端口映射、volume、数据库和配置文件,并完成一次可验证的备份。第二步在 Mac mini 上按 Stack 建立目录,每个 Stack 独立维护 compose.yml、.env 和 data/。
如果入口有变动,先检查 HK Main 的 frps、防火墙和必要端口,再验证 Mac mini 的 frpc 是否稳定连接。入口链路通了之后,再看 edge-stack 和 NPM,确认 npm-http、npm-https 转发注册成功,对应域名也命中了正确的 Proxy Host。
如果业务有变动,就按域名逐个验证:komari 看监控数据是否连续,homepage 看导航和状态卡片是否正确,vpndl 看下载和配置是否可用,gs 看游戏协议和端口是否通,nc 看文件同步和数据库状态,v 看登录、解锁和数据持久化。
最后检查 DNS、NPM 反代规则、备份任务和旧端口映射。确认新入口稳定后,再关闭旧容器或旧域名,不把所有风险堆到最后。
这套 framework 现在已经从四月的「准备重构」进入了「按当前服务持续维护」阶段。后续还需要补齐几类具体模板:
monitor-stack 的 compose.yml 和 Komari 备份说明。homepage-stack 的配置结构。private-services-stack 的 Nextcloud / Vault 备份与恢复流程。vpn-stack 的入口说明和访问控制清单。game-stack 的 compose.yml。等这些模板补齐后,这套框架就不只是一次重构记录,而是一套可以反复复用的个人服务器部署方式:新服务按层加入,旧服务按层迁移,出了问题也能沿着入口、业务、数据和网络边界逐层定位。