diff --git a/.gitignore b/.gitignore index 8d511a21..ecde3cc3 100644 --- a/.gitignore +++ b/.gitignore @@ -77,4 +77,6 @@ profile.cov .grok /.gomodcache/ *.mmdb -!internal/apps/agent/geoipdata/GeoLite2-Country.mmdb \ No newline at end of file +!internal/apps/agent/geoipdata/GeoLite2-Country.mmdb + +/.superpowers/ diff --git a/docs/config.ts b/docs/config.ts index 7eed9745..94f37c26 100644 --- a/docs/config.ts +++ b/docs/config.ts @@ -125,6 +125,7 @@ function sidebarDesign(): DefaultTheme.SidebarItem[] { items: [ { text: '产品边界', link: '' }, { text: '系统架构', link: 'architecture' }, + { text: 'Zone 与域名资源设计', link: 'zone-design' }, { text: 'Agent 与发布模型', link: 'agent-design' }, { text: '内网穿透隧道设计', link: 'tunnel-design' }, { text: 'WAF 设计', link: 'waf-design' }, @@ -135,4 +136,3 @@ function sidebarDesign(): DefaultTheme.SidebarItem[] { } ] } - diff --git a/docs/design/architecture.md b/docs/design/architecture.md index 8fce3d12..1284771c 100644 --- a/docs/design/architecture.md +++ b/docs/design/architecture.md @@ -139,7 +139,7 @@ OpenResty (Agent, TLS/WAF) 当前系统核心实体包括: -* **反代与配置**:`proxy_routes` (网站配置), `origins` (源站), `config_versions` (配置版本), `tls_certificates` (证书), `managed_domains` (托管域名). +* **反代与配置**:`zones` (根域管理边界), `zone_domains` (明确域名与证书/路由关联), `proxy_routes` (路由策略), `origins` (源站), `config_versions` (配置版本), `tls_certificates` (证书). 详见 [Zone 与域名资源设计](./zone-design.md)。 * **Pages 静态托管**:`pages_projects` (Pages项目), `pages_deployments` (不可变部署), `pages_deployment_files` (部署文件清单). * **节点与穿透**:`nodes` (节点), `tunnels` (隧道客户端), `node_system_profiles` (系统概况), `apply_logs` (应用日志). * **WAF 与安全**:`waf_rule_groups` (WAF规则组), `waf_ip_groups` (WAF IP组), `waf_rule_group_bindings` (网站WAF绑定). @@ -154,7 +154,7 @@ OpenResty (Agent, TLS/WAF) | 完整配置版本,而不是在线 patch | 让预览、激活、历史和回滚有稳定边界,保证节点状态一致 | | Agent 主动拉取 | Server 不需要 SSH 权限,降低安全风险;支持 HTTP 与 WebSocket 双协议灵活切换 | | 全局单激活版本 | 降低控制面复杂度,保证所有节点默认一致;提供一键秒级回滚的稳定机制 | -| 网站配置聚合多域名 | 支持单个业务站点共享站点级策略,同时支持按域名灵活绑定不同的 TLS 证书 | +| Zone 域名与路由策略分离 | Zone 提供根域入口与域名边界;路由仍可复用同一套站点级策略并按域名绑定证书 | | 内网穿透基于 frp 整合 | 复用成熟隧道协议,避免自研隧道引起稳定性风险;其 Vhost 机制天然适配反代路由 | | 运行时配置与控制库解耦 | 如 WAF 运行时只读取本地 JSON 规则包,配置变更通过差分广播或快速重载热生效 | @@ -167,6 +167,7 @@ OpenResty (Agent, TLS/WAF) 1. **[产品边界](./index.md)**:了解 OpenFlare 核心定位与不允许逾越的设计边界。 3. **[Agent 与发布模型](./agent-design.md)**:理解版本快照同步及失败回滚的安全兜底逻辑。 4. **细分领域设计**: + * Zone 与域名相关开发:阅读 [Zone 与域名资源设计](./zone-design.md)。 * 穿透相关开发:阅读 [内网穿透隧道设计](./tunnel-design.md)。 * WAF 相关开发:阅读 [WAF 设计](./waf-design.md)。 * Pages 托管开发:阅读 [Pages 静态托管设计](./pages-design.md)。 diff --git a/docs/design/index.md b/docs/design/index.md index 4014319d..78cf8b56 100644 --- a/docs/design/index.md +++ b/docs/design/index.md @@ -22,11 +22,12 @@ OpenFlare 适合需要统一管理多台 OpenResty 代理节点的团队,具 | 能力 | 说明 | 详细设计/使用指南 | | --- | --- | --- | | **反代配置管理** | 以网站规则(Proxy Route)为聚合边界,支持多域名与多上游负载均衡 | [新建反代配置](../guide/proxy-config.md) | +| **Zone 与域名管理** | 以可注册根域为管理入口,聚合明确域名、域名证书与反代路由 | [Zone 与域名资源设计](./zone-design.md) | | **配置版本控制** | 支持全局单一激活版本的预览、发布、不可变快照历史与秒级一键回滚 | [Agent 与发布模型](./agent-design.md) | | **WAF 安全防护** | 全局与自定义规则组,支持手动/自动/订阅型 IP 组,GeoIP 准入与 PoW CC 防护 | [WAF 设计](./waf-design.md) / [WAF 使用指南](../guide/waf-usage.md) | | **内网穿透** | 通过中继节点(Relay)与内网客户端(OpenFlared),反向穿透暴露内网 Web 服务 | [内网穿透设计](./tunnel-design.md) / [穿透使用指南](../guide/tunnel-usage.md) | | **Pages 静态托管** | 直接上传前端 zip 包,由边缘节点拉取并由 OpenResty 本地服务,支持 API 反代与 SPA Fallback | [Pages 静态托管设计](./pages-design.md) | -| **TLS 证书自动续期** | 绑定 managed_domains 并通过 ACME 协议向 Let's Encrypt 申请/续期证书 | [新建反代配置](../guide/proxy-config.md) | +| **TLS 证书自动续期** | 将证书显式绑定到 Zone 域名,并通过 ACME 协议向 Let's Encrypt 申请/续期证书 | [Zone 与域名资源设计](./zone-design.md) | | **多节点监控与观测** | 收集节点资源快照、健康事件,聚合请求指标与访问日志明细 | [系统架构](./architecture.md) | --- @@ -190,4 +191,3 @@ OpenFlare 已收敛为**单 monorepo**(Go 模块 `github.com/Rain-kl/Wavelet` * 发布、同步、回滚与 Agent 模型变化:更新 [Agent 与发布模型](./agent-design.md)。 * 部署方式变化:更新 [部署说明](../deployment/deployment.md) 与 README。 * 配置项变化:更新 [配置项参考](../reference/configuration.md)。 - diff --git a/docs/design/zone-design.md b/docs/design/zone-design.md new file mode 100644 index 00000000..f5ad2f13 --- /dev/null +++ b/docs/design/zone-design.md @@ -0,0 +1,95 @@ +# Zone 与域名资源设计 + +## 目标 + +将“网站”重构为以可注册根域为入口的 Zone 管理体验。`arctel.de` 之类的 Zone 是稳定的管理边界;用户通过稳定 ID 路径进入该 Zone,查看并维护其中明确声明的域名、域名所绑定的反代路由和证书,以及路由级 WAF、Pages 等能力。 + +本设计替代 `managed_domains` 的概念、表与 API。它不引入权威 DNS 解析记录管理。 + +## 范围与约束 + +* Zone 根域使用 Public Suffix List 解析,例如 `api.example.co.uk` 归属 `example.co.uk`。 +* URL 使用 ID:列表为 `/websites`,详情为 `/websites/:zoneId`;不使用域名作为 URL 参数。 +* Zone 域名必须是明确的 FQDN,禁止录入 `*.example.com`。TLS 证书可仍含通配符 SAN,并用于覆盖明确的 Zone 域名。 +* 一个 Zone 域名至多关联一条反代路由;一条反代路由可关联多个 Zone 域名,因而可跨 Zone 共享同一套上游、缓存、限流、WAF 与 Pages 配置。 +* 不新增 DNS 记录、边缘函数、预览子域或租户隔离能力。 + +## 核心模型 + +```mermaid +erDiagram + ZONES ||--o{ ZONE_DOMAINS : contains + PROXY_ROUTES ||--o{ ZONE_DOMAINS : serves + TLS_CERTIFICATES ||--o{ ZONE_DOMAINS : secures + PROXY_ROUTES ||--o{ WAF_RULE_GROUP_BINDINGS : applies + PAGES_PROJECTS ||--o{ PROXY_ROUTES : backs + + ZONES { + uint id PK + string domain UK + string remark + } + ZONE_DOMAINS { + uint id PK + uint zone_id + uint proxy_route_id + string domain UK + uint cert_id + string remark + } +``` + +### `of_zones` + +保存根域、备注、创建时间与更新时间。根域全局唯一且创建后不可原地修改;需要变更时新建 Zone 并迁移域名。删除 Zone 前必须先清空其 Zone 域名。 + +### `of_zone_domains` + +保存 `zone_id`、明确 `domain`、可空的 `proxy_route_id`、可空的 `cert_id`、备注及时间戳。`domain` 全局唯一;所有关系字段建立索引但不建立物理外键。`proxy_route_id` 允许为空,以承接已准备证书但尚未配置反代的历史域名。 + +`of_proxy_routes` 逐步移除 `domain`、`domains`、`cert_id`、`cert_ids` 与 `domain_cert_ids` 等冗余列。路由名称 `site_name` 成为稳定的人类可读标识,编译器从关联的 Zone 域名读取 server name 与证书。 + +## 业务与 API + +管理端新增 Zone 资源: + +* `GET/POST /api/v1/d/zones` +* `GET/POST /api/v1/d/zones/:id/update` +* `POST /api/v1/d/zones/:id/delete` +* `GET/POST /api/v1/d/zones/:id/domains` +* `POST /api/v1/d/zones/:id/domains/:domainID/update` +* `POST /api/v1/d/zones/:id/domains/:domainID/delete` +* `GET /api/v1/d/zones/:id/overview` + +反代路由的创建、更新请求改用 `zone_domain_ids`。服务端在事务中验证域名归属、全局唯一性和证书 SAN 覆盖;失败通过 `response.Abort*` 统一返回。删除已绑定路由的 Zone 域名必须先解除或删除该路由;删除仍有域名的 Zone 必须拒绝。 + +WAF、Pages、上游与发布版本仍属于 `proxy_routes`。Zone 概览只聚合展示其域名关联的路由状态,不复制或重新定义这些配置。 + +## 前端体验 + +`/websites` 只展示 Zone 根域,显示已配置域名数、路由数与状态,并提供搜索、创建和操作菜单。点击进入 `/websites/:zoneId`。 + +详情页包含: + +* 概览:域名、路由和有效证书统计;域名—路由—证书摘要;路由级 WAF 与 Pages 摘要。 +* 域名:明确 FQDN 的列表、证书选择和关联路由;不显示或接受通配符域名。 +* 路由:筛选到当前 Zone 的路由并链接到既有路由详情。 +* 证书:当前 Zone 域名实际引用的证书。 +* 设置:Zone 备注和受保护的删除操作。 + +新增路由时从 Zone 域名中选择;用户也可以先在 Zone 中登记域名,再绑定路由。全局反代路由入口保留,但改用同一套 Zone 域名选择器。 + +## 数据迁移 + +本次改造分两个发布阶段,以免 SQL 用错误的“末两段域名”规则处理多级公共后缀。 + +1. 使用 PostgreSQL 与 SQLite 同版本 Goose DDL 创建新表、索引;保留旧表和路由冗余列。 +2. 通过可显式执行、可重复运行的 Go 数据迁移使用 `publicsuffix.EffectiveTLDPlusOne`:从既有路由域名及 `managed_domains` 创建 Zone 和 Zone 域名,按旧 `domain_cert_ids` 的位置迁移证书;旧记录仅在没有路由时生成未绑定 Zone 域名。迁移报告必须列出无法解析或存在冲突的记录并中止,不静默丢弃。 +3. 新代码切换到 Zone 模型、完成配置编译与 UI 验证后,再在独立 Goose 迁移中删除 `of_managed_domains` 和旧冗余列。 + +## 验证 + +* 单元测试:Public Suffix List 分组、FQDN / 通配符拒绝、跨 Zone 路由、证书 SAN 覆盖、删除保护及迁移幂等性。 +* 集成测试:Zone、Zone 域名与路由 API 的成功与失败响应;现有路由迁移后生成相同 OpenResty 域名与证书配置。 +* 前端测试:Zone 列表、ID 路由、详情加载 / 错误 / 空状态、域名选择器与 API 负载。 +* 手动验证:迁移前后比较激活配置快照中的 `server_name` 和证书路径,发布后使用根域及各子域请求验证路由。 diff --git a/docs/superpowers/specs/2026-07-12-zone-domain-design.md b/docs/superpowers/specs/2026-07-12-zone-domain-design.md new file mode 100644 index 00000000..d1b9cd00 --- /dev/null +++ b/docs/superpowers/specs/2026-07-12-zone-domain-design.md @@ -0,0 +1,12 @@ +# Zone 域名重构规格 + +已确认的设计: + +* `/websites` 展示可注册根域 Zone;详情 URL 使用 `/websites/:zoneId`。 +* `managed_domains` 将被彻底替换为 `of_zones` 与 `of_zone_domains`。 +* Zone 域名是 `of_proxy_routes` 域名的规范化来源;一个域名至多连接一条路由,一条路由可含多个 Zone 的域名。 +* Zone 域名只允许明确 FQDN;允许把含 `*.example.com` SAN 的 TLS 证书绑定到明确域名,但不允许通配符域名记录。 +* 路由仍拥有上游、缓存、限流、WAF 与 Pages;Zone 只提供聚合管理和展示。 +* 迁移先建新表、用 Public Suffix List 回填和验证,再在后续独立发布中移除旧表及冗余列。 + +完整设计、API、迁移与验证策略见 [Zone 与域名资源设计](../../design/zone-design.md)。