Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/40-deployment/production-registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@

`production.yml` 只接受精确 current-main SHA。`verify` 执行仓库检查和容器构建,不修改远程资源。`deploy` 在受保护 production 环境中,重新核验 main 后对已配置 app 向前迁移、配置数据库和单桶 S3 凭据、发布同一镜像,并验证 Heroku app origin。它不自动导入 D1、不改变域名、不创建示例数据,也不删除旧资源。

production 环境需要 `HEROKU_APP_NAME`、`S3_ENDPOINT_URL`、`S3_BUCKET`、`DOCUMENTATION_ORIGIN_TEMPLATE` variables,以及 `HEROKU_API_KEY`、`MIGRATION_DATABASE_URL`、`DATABASE_URL`、`AWS_ACCESS_KEY_ID`、`AWS_SECRET_ACCESS_KEY` secrets。文档模板必须指向已经配置 wildcard DNS/TLS 的专用内容 origin。生产当前使用 `https://registry-docs-{snapshot}.inkcre.dev`;每个不可变快照拥有独立 origin,并由 `*.inkcre.dev` DNS catch-all 与证书承载。服务只接受符合该模板的内容 host,其他落入 catch-allhost 返回 421。内容域与管理站同属 `inkcre.dev`,因此部署接受作者 HTML/JS 可能接收或干扰父域 Cookie 的风险;`inkcre.dev` 下的服务不得设置可发送到内容域的敏感父域 Cookie。首次配置保持既有 R2 桶,S3 token 仅授予该桶的对象读写。`MIGRATION_DATABASE_URL` 使用 `registry_owner`,仅交给迁移容器与可信角色配置命令;`DATABASE_URL` 使用同一数据库的普通 `registry_app` 角色和独立密码。迁移创建该角色及业务表授权,控制器设置密码后以 `web=1:eco` 启动应用。owner 连接与平台控制 token 不进入运行服务配置。数据库连接属于独立 Registry 项目,不复用 core-py 的数据库或发布生命周期。
production 环境需要 `HEROKU_APP_NAME`、`S3_ENDPOINT_URL`、`S3_BUCKET`、`DOCUMENTATION_ORIGIN_TEMPLATE` variables,以及 `HEROKU_API_KEY`、`MIGRATION_DATABASE_URL`、`DATABASE_URL`、`AWS_ACCESS_KEY_ID`、`AWS_SECRET_ACCESS_KEY` secrets。文档模板必须指向已经配置 wildcard DNS/TLS 的专用内容 origin。生产当前使用 `https://registry-docs-{snapshot}.inkcre.dev`;每个不可变快照拥有独立 origin。为复用免费 TLS,DNS 与证书使用范围更宽的 `*.inkcre.dev`,而不是只能匹配这类文档 hostname 的多层 wildcard。这个 catch-all 只负责把请求送达 Registry;应用仍按 `DOCUMENTATION_ORIGIN_TEMPLATE` 精确解析 Host,其他落入 wildcardhostname 返回 421。DNS 解析成功或 TLS 握手成功都不代表该 Host 是文档 origin。内容域与管理站同属 `inkcre.dev`,因此部署接受作者 HTML/JS 可能接收或干扰父域 Cookie 的风险;`inkcre.dev` 下的服务不得设置可发送到内容域的敏感父域 Cookie。首次配置保持既有 R2 桶,S3 token 仅授予该桶的对象读写。`MIGRATION_DATABASE_URL` 使用 `registry_owner`,仅交给迁移容器与可信角色配置命令;`DATABASE_URL` 使用同一数据库的普通 `registry_app` 角色和独立密码。迁移创建该角色及业务表授权,控制器设置密码后以 `web=1:eco` 启动应用。owner 连接与平台控制 token 不进入运行服务配置。数据库连接属于独立 Registry 项目,不复用 core-py 的数据库或发布生命周期。

Heroku 交付为 Uvicorn 设置 `FORWARDED_ALLOW_IPS=*`,由平台 HTTP 入口提供外部请求协议,补斜杠跳转保持 HTTPS。转发头不参与 namespace 授权或身份判断;认证仍由 publisher credential 决定。部署 smoke 同时检查 `/simple` 跳转到该 origin 的 HTTPS `/simple/`。

## 生产资源与 TLS

Registry 使用 Heroku app `inkcre-ext-reg-production`,其默认 origin 为 `https://inkcre-ext-reg-production-a6bbc8ada2d2.herokuapp.com`;web formation 为一个 Eco dyno。Neon 项目为 `wandering-base-13707928`,数据库 `registry` 位于根分支 `br-muddy-term-aw4iive7`。R2 使用原有私有桶 `inkcre-extension-registry-production-v2`。PR 分支从固定空 `preview-base` 创建,生产导入不改变这个基础分支。

Cloudflare zone `inkcre.dev` 中的 `registry.inkcre.dev` 使用代理 CNAME,目标为 Heroku 为该域名分配的 `classical-mapusaurus-sbqqxbde9bay1zrkw4vh1zhp.herokudns.com`。这个 hostname 的 Configuration Rule 设置 `ssl=strict`,Single Redirect Rule 将 HTTP 以 308 转向 HTTPS,并保留路径和查询参数;不修改其他 hostname 的 TLS 配置。
Cloudflare zone `inkcre.dev` 中的 `registry.inkcre.dev` 使用代理 CNAME,目标为 Heroku 为该域名分配的 `classical-mapusaurus-sbqqxbde9bay1zrkw4vh1zhp.herokudns.com`。这个 hostname 的 Configuration Rule 设置 `ssl=strict`,Single Redirect Rule 将 HTTP 以 308 转向 HTTPS,并保留路径和查询参数;不修改其他 hostname 的 TLS 配置。文档内容使用 DNS-only CNAME `*.inkcre.dev`,指向 Heroku 分配的 `thawing-opossum-dgyx69y8psreeea1hcg8r0k0.herokudns.com`。精确的 `app`、`design`、`registry` 等记录优先于 wildcard;新增子域不得依赖 wildcard 的 Registry 421 响应作为正式路由。

Registry 的 Cache Rule 对此 hostname 设置 `cache=true`、`edge_ttl.mode=bypass_by_default`、`browser_ttl.mode=respect_origin`、`origin_cache_control=true` 与 `respect_strong_etags=true`。页面和 API 的 `no-store` 禁止缓存;文件的 `public, no-cache` 要求边缘和浏览器每次回源重验证,不覆盖为固定 TTL。这样 release 的可读状态仍由应用在每次请求中检查,ETag 匹配时返回 304,边缘复用已经验证的字节。Cloudflare 默认 Browser Cache TTL 会把部分静态后缀改成四小时缓存,不能沿用这个默认值。切换后按 hostname 清除 Registry 缓存,不清除整个 zone。

Heroku SNI endpoint `gallimimus-68400` 绑定了仅覆盖 `registry.inkcre.dev` 的 Cloudflare Origin CA 证书,到期时间为 **2041-09-09 06:29 UTC**。公开客户端校验 Cloudflare 边缘证书,Cloudflare 校验 Heroku 的 Origin CA 证书;Heroku 默认域名仍使用平台的公开证书。此 app 不启用 ACM。Origin CA 不自动续期或发送到期通知,运维应在到期前签发新证书、用 `heroku certs:update` 替换并核验域名映射;私钥只保存在受限恢复目录与 Heroku 证书存储。保持 DNS 代理开启,关闭代理会将 Origin CA 证书直接暴露给不信任它的浏览器。参见 [Cloudflare Origin CA](https://developers.cloudflare.com/ssl/origin-configuration/origin-ca/) 与 [Heroku SSL](https://devcenter.heroku.com/articles/ssl)。
Heroku ACM 已为 `registry.inkcre.dev` 与 `*.inkcre.dev` 分别签发公开受信任证书。内容 wildcard 必须保持 DNS only,才能让 Heroku 验证并续期;若改为 Cloudflare proxy,必须先提供另一条可验证且由浏览器信任的完整 TLS 路径,不能让旧的 Cloudflare Origin CA 证书直接面向客户端。`registry.inkcre.dev` 仍可保持代理,因为其 Heroku origin 也有 ACM 证书。域名增删后运行 `heroku certs:auto --wait`,并分别验证合法但不存在的 snapshot Host 返回 404、非模板 Host 返回 421。参见 [Heroku ACM](https://devcenter.heroku.com/articles/automated-certificate-management) 与 [Heroku SSL](https://devcenter.heroku.com/articles/ssl)。

## 首次切换

Expand Down
Loading