Some checks failed
docker-images / resolve-build-targets (push) Failing after 1s
docker-images / build-and-push (admin) (push) Has been cancelled
docker-images / submit-indexnow (push) Has been cancelled
docker-images / build-and-push (backend) (push) Has been cancelled
docker-images / build-and-push (frontend) (push) Has been cancelled
ui-regression / playwright-regression (push) Has been cancelled
6.3 KiB
6.3 KiB
Docker / 反代架构说明
本文记录当前项目在 tohka 这类宿主机上的推荐部署结构,以及为什么会同时出现:
- 宿主机层的 Caddy
admin容器内的 Nginx
1. 总体分层
推荐生产结构:
Internet
-> Host Caddy (:80 / :443)
-> frontend container (Astro SSR / Node :4321)
-> admin container (Nginx :80, 静态 SPA)
-> backend container (Loco.rs API :5150)
-> backend-worker container (Loco.rs worker / Redis queue)
职责划分:
- Host Caddy
- 统一接收公网流量
- 处理域名、HTTPS、证书续签
- 反向代理到各个内部容器
- frontend
- Astro SSR(Node) 应用
- 不是纯静态站,所以容器内直接运行 Node 服务即可
- admin
- React/Vite 打包后的纯静态 SPA
- 容器内使用 Nginx 提供静态文件
- 生产推荐前面接 TinyAuth / Pocket ID 做 SSO
- backend
- API、后台鉴权、审计、版本历史、订阅投递
- backend-worker
- 消费 Redis 队列
- 负责通知异步投递、失败重试、digest 任务触发后的实际发送
2. 为什么上层已经有 Caddy,admin 容器里还要 Nginx?
这两层并不冲突,职责不同:
- Caddy 是入口网关
- Nginx 是 admin 容器内部的静态文件服务器
也就是说:
Browser
-> Caddy
-> admin nginx
-> /usr/share/nginx/html
这样做的好处:
- admin 镜像本身自带可用的静态文件服务能力
- 宿主机层仍然保留统一的域名 / HTTPS / 路由管理
- admin 作为独立前端,可以单独构建、单独发布
2.2 为什么现在多了 backend-worker?
因为当前通知系统已经改成:
backend (web)
-> 写入 notification_deliveries
-> enqueue 到 Redis
backend-worker
-> 消费队列
-> 发送 email / webhook / discord / telegram / ntfy
如果只启动 backend 而没有 backend-worker,通知会入队但没人消费。
补充说明:
backend-worker目前主要消费 Redis 队列里的通知相关任务。- AI 索引重建会直接在
backend进程本地启动,这样创建任务后会立即进入执行,不再依赖独立 worker 消费。
2.1 推荐的后台认证链路
当前最推荐:
Browser
-> Caddy (import tinyauth)
-> TinyAuth
-> Pocket ID (OIDC)
-> admin nginx / backend API
关键点:
- admin 页面和它调用的
/api/*建议走 同一个受保护后台域名 - Caddy 使用
forward_auth - backend 开启
TERMI_ADMIN_TRUST_PROXY_AUTH=true - 生产推荐再配
TERMI_ADMIN_PROXY_SHARED_SECRET=<随机长字符串> - Caddy 在
/api/*反代到 backend 时补X-Termi-Proxy-Secret - backend 读取 TinyAuth 转发的
Remote-User / Remote-Email / Remote-Groups - 本地开发可以保留
TERMI_ADMIN_LOCAL_LOGIN_ENABLED=true
3. 为什么 frontend 不使用同样的 Nginx 模式?
因为当前 frontend 是 Astro SSR:
output: 'server'@astrojs/nodestandalone
它需要在请求期执行服务端逻辑,因此更适合:
Caddy -> frontend Node server
而不是先打成纯静态文件再由 Nginx 托管。
4. admin 容器内 Nginx 当前负责什么?
当前 admin/nginx.conf 主要负责:
- SPA fallback:
try_files ... /index.html assets/长缓存(hash 资源可immutable)index.html/runtime-config.js禁缓存,避免配置或入口文件陈旧gzip压缩- 基础安全响应头
/healthz健康检查入口
为什么 runtime-config.js 要禁缓存?
因为 admin 现在支持运行时环境变量注入,例如:
ADMIN_API_BASE_URLADMIN_FRONTEND_BASE_URL
容器启动时会生成 runtime-config.js。
如果它被强缓存,改完环境变量重启容器后,浏览器可能仍然读到旧地址。
5. 为什么没有在 admin 容器里启用 Brotli?
当前基础镜像是官方 nginx:alpine。
这个镜像默认不一定带 Brotli 模块,所以这里先启用通用的 gzip。
如果后续确实需要 Brotli,有两个常见做法:
- 让宿主机层的 Caddy 统一负责压缩
- 改用带 Brotli 模块的自定义 Nginx 镜像
对当前项目而言,优先让 宿主机 Caddy 做统一公网入口,admin 容器内部只负责稳妥地提供静态文件,是更简单的方案。
6. 推荐的 tohka 思路
如果 tohka 上已经有一个统一的大 Caddyfile,推荐继续保持:
- Caddy 统一暴露
80/443 frontend/admin/backend只走内网端口- 不把数据库 / Redis 直接暴露到公网
- backend 如果启用了代理 SSO,不要再把
:5150直接开放给公网
仓库里已经额外提供:
deploy/docker/compose.tohka.override.yml
用它叠加 compose.package.yml 后,会把:
frontend:4321admin:4322backend:5150
都只绑定到 127.0.0.1
7. 当前和配置相关的关键文件
- 宿主机入口反代:
tohka上的大 Caddyfile - admin 静态服务:
admin/nginx.conf - admin 镜像:
admin/Dockerfile - Caddy 参考模板:
deploy/caddy/Caddyfile.tohka.example - compose 示例:
deploy/docker/compose.package.yml - tohka override:
deploy/docker/compose.tohka.override.yml - OIDC / Pocket ID 落地:
deploy/docker/TOHKA_POCKET_ID.md - 运行时环境示例:
deploy/docker/.env.example
8. Caddy 路由推荐
默认更推荐:
blog.init.cool-> frontendadmin.blog.init.cool-> admin + backend(/api/*)api.blog.init.cool-> backend
这样最省心,也最不容易碰到路径前缀、资源基路径、Cookie Path 等问题。
如果一定要用:
init.cool/admininit.cool/api
也可以,但 admin 需要在构建时设置:
VITE_ADMIN_BASENAME=/admin
对应模板见:
deploy/caddy/Caddyfile.tohka.example
9. 备份 / 恢复入口
当前仓库内已经补了:
deploy/scripts/backup/backup-postgres.shdeploy/scripts/backup/backup-media.shdeploy/scripts/backup/restore-postgres.shdeploy/scripts/backup/restore-media.shdeploy/docker/BACKUP_AND_RECOVERY.md
建议把这些接进生产上的 cron / systemd timer,而不是只停留在仓库里。
10. 健康检查与启动顺序
当前推荐闭环:
- backend 启动时先自动跑 migration
- backend 提供
/healthz - frontend 提供
/healthz - admin 由 Nginx 提供
/healthz - compose 中 frontend / admin / backend-worker 都依赖 backend healthy