生产环境
本页讲的是把实例投入生产:如何正确地把它放到反向代理之后、单实例不变量意味着什么,以及怎么做备份。Notarium 以单个容器部署——生产配置归结为下面三件事。
反向代理与转发头
在应用前面放一个反向代理(nginx、Caddy、Traefik)——由它终结 TLS,再代理到 Notarium 的端口。关键要求:代理必须转发描述外部地址的请求头。
反向代理必须发送 X-Forwarded-Host(或原样保留 Host)以及 X-Forwarded-Proto: https。否则,界面里经 cookie 认证的写操作会被当作跨源请求而拒绝——症状就是「看得到,却存不了」。转发 X-Forwarded-Proto 也是必需的:会话 cookie 要靠它才能拿到 Secure 标志。
原因在于:写操作上的 Origin 校验,要把请求来源与浏览器所看到的地址比对——而这个地址正是随转发头送达的。智能体通过 Bearer PAT 发起的调用不受此校验约束(它们不带 cookie,也就没有 CSRF 攻击面)。代理这一侧则必须用自己的值覆写转发头,而不是把客户端送来的原样放行。
如果你为智能体启用 OAuth 授权,在代理之后运行时请设置 PUBLIC_BASE_URL(例如 https://notes.example.com)——给 OAuth 元数据一个稳定的外部地址。不设置的话,地址会从转发头推导得出。参见配置。
信任客户端 IP
与地址相互独立的另一条轴,是客户端的真实 IP。有两项限额按它来计:登录尝试,以及放行新的 OAuth 客户端。在代理之后,所有请求都来自同一个地址,因此不做显式配置的话,这些限额就会按代理来计——也就是把所有人算成一个。
控制它的开关是 TRUST_PROXY:以逗号分隔的紧邻的上游代理 IP/CIDR 列表。
# .env —— 填入你自己的代理容器或主机地址
TRUST_PROXY=172.18.0.0/16
安全的默认做法是让这个变量保持不设置:这样 X-Forwarded-For 完全不参与限额计算,也就没法用请求头伪造别人的 IP。只有在你确切知道自己代理的地址时才去设置它,并且把列表控制得尽量窄。
布尔值、跳数、具名网段以及全地址网段(/0)会在启动时被拒绝。信任所有地址,就等于让任何客户端都能用请求头给自己指派一个 IP,从而绕过登录限额。
这项设置不影响 X-Forwarded-Host 与 X-Forwarded-Proto 的转发——它们是相互独立的轴,上一节的约定原样有效。
单实例不变量
Notarium 是为单个进程设计的。有两项认证状态保存在进程内存里:
- 登录限流——尝试次数计数器;
- SSE 套接字注册表——撤销访问权限时,正是靠它瞬间切断活动连接。
在负载均衡器后面跑多个实例、又没有共享存储时,这些机制就会失效:攻击者可以把限额在各实例上成倍放大,而在一个实例上撤销访问权限,也关不掉挂在另一个实例上的 SSE 连接。
这两项状态都保存在进程内存里,所以在负载均衡器后面跑多个实例、又没有共享存储时,这些机制无法工作。把元数据库迁移到 Postgres 能带来共享状态,但仅凭这一点还不足以支撑横向扩展。请保持单个实例。
备份
标准的备份方式是镜像的内置命令,而不是从外部复制文件:notarium backup 会打包出一个经过校验的 ZIP 并以流的形式输出,期间服务照常运行。
docker compose exec -T notarium backup > notarium-$(date -u +%Y%m%dT%H%M%SZ).zip
docker compose exec -T notarium backup verify < notarium-20260731.zip
校验属于常规任务的固定环节,而不是偶尔走一次过场:它什么都不改,却能赶在你真正需要这份归档之前就发现损坏。至于任务本身,光靠一次重定向是不够的——请照搬运维手册里的安全发布流程(临时文件 → 刷盘 → 原子硬链接):备份与恢复。那一页还讲了如何恢复到干净的数据卷,以及这条命令的适用边界。
meta.dbcp /data/meta.db,或者在服务运行时复制数据卷,都算不上备份:元数据库跑在 WAL 模式下,已提交的数据行可能还躺在 meta.db-wal 里,而逐个复制出来的文件也不构成同一时刻的快照。
备份里究竟包含什么,以及为什么:
| 内容 | 作用 |
|---|---|
/data/spaces | 你的 Markdown 文件——事实来源。 |
/data/meta.db | 元数据库(历史、用户、访问权限)——从文件无法恢复。 |
/data/jobs | 导入/导出任务的产物与上传文件。 |
/data/engine | 引擎的派生索引。不进归档:可从文件重建。 |
如果元数据库已迁移到 Postgres,或者笔记存放在数据根目录之外,内置命令会直接报错退出,而不是产出一个残缺的归档——这时请用你的服务商提供的标准工具备份数据库和挂载目录。元数据库究竟保存了哪些内容,参见数据库页面。