# 域名与证书

Raise 的全部服务入口均基于基础域名 `BASE_DOMAIN` 的子域名进行路由与访问。在公网环境下，网关自动通过 Let's Encrypt 申请与续期证书；在内网环境下，网关使用内置 CA 为所有站点签发证书。组织还可以将自己的域名绑定到工作台或站点，在 DNS 中校验 TXT 记录后按需签发证书。

## 谁能用

不同角色在域名与证书管理中的分工与权限如下：

| 角色 / 人员 | 权限与职责说明 |
|---|---|
| 部署运维人员 | 决定基础域名 `BASE_DOMAIN`、TLS 证书模式（`--tls`）、配置 DNS 解析，以及是否分发与导入网关内置根证书。 |
| 平台运营（`platform.ops`） | 负责平台运营，不配置租户的自定义域名（自定义域名由各组织自主管理）。 |
| 组织管理员（`tenant.admin`） | 在「我的组织」→「企业设置」→「域名」中设置「组织的地址」，以及绑定、验证和释放自定义域名。 |
| 组织审计员（`tenant.auditor`） | 拥有只读查看权限，可以查看「域名」页面中的配置，但不能修改「组织的地址」或绑定自定义域名。 |
| 无权限成员 | 进入「域名」管理页会被权限拦截。若在工作台外部直接通过浏览器访问 `https://organization.apps.{base}`，会看到提示「请从工作台打开」。 |

## 怎么打开

你可以通过以下方式进入对应的域名配置与访问入口：

1. **部署配置入口**：
   - 在主机上执行安装脚本时，通过 `./setup-host.sh --domain <域名>` 指定基础域名。
   - 在环境配置文件 `.env` 中设置 `BASE_DOMAIN` 环境变量。
2. **组织域名管理入口**：
   - 登录 [工作台](/guide/workspace)，在左侧打开「我的组织」→「企业设置」→「域名」（必须嵌入在工作台中打开）。
   - 从 [站点](/apps/site) 应用跳转：在站点管理中携带参数 `?target=site:{id}` 打开本页面，系统会自动预选对应的站点。
3. **平台主要公开访问地址**：
   - 工作台统一门户：`https://app.{base}`。
   - 组织专属工作台（若已设置「组织的地址」）：`https://{租户slug}.{base}`。
   - 绑定的自定义域名：`https://{自定义域名}`。
   - 站点预览地址：`https://{slug}.{租户}.sites.{base}`。
4. **运维管理网访问入口**：
   - 平台运维服务默认监听 8443 端口（通过 `OPS_BIND` 配置），通过 SSH 隧道转发至本地后访问：`https://ops.{base}:8443`。

## 界面一览

### 平台子域名规划

Raise 网关根据访问的主机名将流量分发至对应的后端服务。

公网服务端口（80 端口 与 443 端口）：

| 主机名 | 服务用途 |
|---|---|
| `app.{base}` | 工作台门户 |
| `id.{base}` | 身份中心（Zitadel）与可选自建登录页 |
| `api.{base}` | 开放 API（Agent 相关请求转到 kwork-agent） |
| `dev.{base}` | 开放平台与开发者门户 |
| `docs.{base}` | 本手册（公开，不用登录；地址可用 `KWORK_DOCS_URL` 改） |
| `files.{base}` | 预签名文件上传与下载服务（`FILES_UPSTREAM`，私有化部署默认为 SeaweedFS） |
| `apply.{base}` | 助手草稿隔离审阅页 |
| `cdn.{base}` | ISV 联邦静态资源托管 |
| `bi.{base}` | Superset 数据分析服务（analytics） |
| `collab.{base}` | 协同办公与协作服务（collab profile） |
| `organization.apps.{base}` | 「我的组织」管理应用 |
| `{app}.apps.{base}` | 各官方与 ISV 应用（例如 `wiki`、`doc`、`storage`、`hr` 等） |
| `*.apps.{base}` | 其它已上架的应用系统 |
| `*.*.sites.{base}` | 站点预览服务 |
| 裸自定义域名（按需 `https://`） | 已通过验证的组织专属工作台或公开站点 |

运维网服务端口（8443 端口，由 `OPS_BIND` 控制）：

| 主机名 | 服务用途 |
|---|---|
| `ops.{base}` | 平台运营台 |
| `grafana.ops.{base}` | Grafana 监控大盘 |
| `prometheus.ops.{base}` | Prometheus 监控指标采集 |
| `alertmanager.ops.{base}` | Alertmanager 监控告警 |
| `temporal.ops.{base}` | Temporal 分布式工作流控制台 |
| `langfuse.ops.{base}` | Langfuse 模型调用追踪看板 |
| `llm.ops.{base}` | Bifrost 模型网关界面（供应商与密钥只读） |
| `bao.ops.{base}` | OpenBao 密钥凭据管理 |
| `bi.ops.{base}` | Superset 运营单点登录（SSO） |
| `seaweedfs.ops.{base}` / `filer.ops.{base}` | SeaweedFS 对象存储与文件系统管理 |
| `caddy.ops.{base}` | Caddy 网关管理接口（只读 GET） |

> **提示**
>
> 在 Kubernetes 环境中使用 Helm 部署时，请按照安装提示将泛域名 `*.{baseDomain}` 以及核心子域名 `id.`、`api.`、`app.`、`dev.`、`docs.` 的 DNS 解析均指向网关服务（gateway Service）。

### 组织应用「域名」管理页

组织管理员在工作台内进入「我的组织」→「企业设置」→「域名」，页面包含以下部分：

- **页头**：显示页面标题「域名」。拥有写权限时右侧提供「添加域名」。
- **「组织的地址」区块**：
  - 字段标签为「名称」，用于设置组织在平台泛域名 `*.{base}` 下的专属短名。
  - 尚未设置时按钮为「设置」；已有地址时按钮为「改名」。改名会弹出确认：旧地址立即失效，用它保存的书签和分享的链接将打不开。
  - 保存成功后弹出提示「已改为……」并显示修改后的完整主机名；若名称已被占用，提示「这个名字已经有人用了」。
- **「自己的域名」列表**：
  - 空态标题「还没有自定义域名」，说明「添加后需在 DNS 放一条 TXT 记录验证归属。」。许可未包含时提示「当前许可不包含自定义域名」「请联系平台运营方开通。」。
  - **域名卡片徽章**：每个域名卡片展示域名名称与状态徽章（「待验证」或「已验证」）。若用途为站点，卡片上额外展示徽章「站点」并跟随对应的站点编号。
  - **待验证卡片**：展示说明「添加下面的 TXT 记录后点“检查验证”……」。卡片中列出可一键复制的「类型」、「主机记录」与「记录值」，并提供操作按钮「检查验证」。点击后若验证成功弹出提示「……已验证」；若尚未查到 DNS 记录，提示「还没有查到 TXT 记录。DNS 生效可能需要几分钟。」。
  - **已验证卡片**：展示「验证于」时间戳，以及可直接点击访问的「访问地址」（`https://{domain}`）。
  - **释放操作**：每个域名卡片提供「释放域名」按钮。点击后弹出确认弹窗「释放……？」，弹窗说明「释放后域名不再指向你的工作台，可重新添加。」，确认按钮为「释放」。

## 常用操作

### 部署时配置基础域名与证书

根据部署网络环境的不同，选择对应的基础域名与证书配置方式：

#### 方式一：公网环境部署（Let's Encrypt 证书）

1. 在 DNS 服务商处添加泛域名解析记录：将 `*.work.example.com` 的 A 记录指向服务器公网 IP。
2. 确保服务器的 80 端口 与 443 端口 在公网防火墙和安全组中处于放行状态。
3. 在服务器执行初始化安装脚本，指定基础域名（默认启用 `--tls acme`）：
   ```bash
   ./setup-host.sh --domain work.example.com --tls acme
   ```
   或在 `.env` 文件中配置 `BASE_DOMAIN=work.example.com` 与联系邮箱 `ACME_EMAIL`。
4. 启动后，网关会自动向 Let's Encrypt 申请公网证书并自动维护续期。

#### 方式二：内网环境部署（内置 CA 证书）

1. 在内网 DNS 服务器上将 `*.work.corp` 解析到网关服务器的内网 IP。
2. 在服务器执行初始化安装脚本，指定内部证书模式：
   ```bash
   ./setup-host.sh --domain work.corp --tls internal
   ```
   （或在配置中设置 `CADDY_GLOBAL_OPTIONS=local_certs`）。
3. 部署启动后，网关会使用内置 CA 为所有站点自动签发证书。
4. 导出并信任网关根证书：将服务器上的证书文件 `deploy/compose/state/gateway-root-ca.crt` 复制到需要访问系统的各客户端电脑中并导入受信任根证书库：
   - macOS 系统终端导入命令：
     ```bash
     sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain deploy/compose/state/gateway-root-ca.crt
     ```
   - 若客户端使用 Firefox 浏览器，需单独在 Firefox 设置中手动导入该证书。
5. 导入完成后重启浏览器。

#### 方式三：本地快速试用（auto 模式与 hosts）

1. 执行安装脚本并指定 auto 模式：
   ```bash
   ./setup-host.sh --domain auto
   ```
   系统将自动使用 `<ip>.sslip.io` 作为域名，并启用网关内置 CA 签发证书。
2. 若仅需在本机上测试访问，可在命令后添加 `--hosts` 参数。脚本会自动向当前机器的 `/etc/hosts` 写入域名解析。
> **注意**
>
>    `--hosts` 参数只修改执行脚本的本机。局域网内的其它电脑如果需要访问，仍必须配置内网 DNS 或在其各自电脑的 hosts 文件中添加解析。

### 排查部署时的证书错误

1. **公网 ACME（Let's Encrypt）证书错误**：
   - 检查 DNS 解析是否生效，确认域名解析的 IP 是否与当前服务器公网 IP 一致。
   - 检查服务器 80 端口 是否对公网开放（Let's Encrypt 进行 HTTP-01 校验必须能够访问 80 端口）。
   - 查看网关容器日志，搜索 acme 相关的错误日志：
     ```bash
     docker compose logs gateway | grep -i acme
     ```
2. **内网内置 CA 证书错误**：
   - 检查客户端设备是否已将 `deploy/compose/state/gateway-root-ca.crt` 正确添加到受信任根证书颁发机构。
   - 导入证书后，必须彻底重启浏览器。

### 设置组织的地址

1. 登录 [工作台](/guide/workspace)，在左侧打开「我的组织」→「企业设置」→「域名」。
2. 定位到「组织的地址」区块。
3. 在「名称」输入框中填写希望使用的短名，系统会自动进行规范化。
4. 点击「设置」或「改名」：
   - 若已有地址，确认弹窗会说明旧地址立即失效，用它保存的书签和分享的链接将打不开。
   - 若设置成功，弹出提示「已改为……」并显示修改后的完整主机名。组织成员后续可通过 `https://{slug}.{base}` 打开专属工作台。
   - 若短名已被其它组织占用，界面提示「这个名字已经有人用了」。

> **注意**
>
> 通过专属组织地址访问时，身份服务的登录回调地址需要已登记该地址。系统重启 kwork 服务时会自动补齐登记。若登录回调未登记，系统日志会记录无法识别该地址。

### 绑定自定义域名（工作台或站点）

1. **办理域名备案**：若部署在中国大陆机房且面向公众开放，需通过云厂商办理 ICP 备案手续。平台本身不检查域名备案状态。
2. **进入域名页面并添加**：在 [工作台](/guide/workspace) 中依次打开「我的组织」→「企业设置」→「域名」，点击「添加域名」。
3. **填写域名与用途**：
   | 字段 | 必填 | 说明 |
   |---|---|---|
   | 「域名」 | 是 | 填写完整的自定义域名（例如 `work.example.com`）。不能使用平台基础域名自身的名字。一个自定义域名只属于一个组织。 |
   | 「用途」 | 是 | 选择「打开工作台（员工登录用的地址）」或「托管一个站点（营销页面，访客无需登录）」。工作台用途 CNAME 指向 `app.{base}`；站点用途指向 `sites.{base}`（具体以页面展示为准），并需填写「站点编号」。用途添加后不能修改。 |
4. **在 DNS 服务商处添加解析记录**：
   - **TXT 归属验证记录**：
     - 主机记录：`_kwork-challenge.{域名}`
     - 记录类型：`TXT`
     - 记录值：填写页面上显示的验证值（格式为 `kwork-verify=…`）
   - **CNAME 访问解析记录**：
     - 主机记录：`{域名}`（二级域名如 `work`，注意根域名通常不支持 CNAME）
     - 记录类型：`CNAME`
     - 记录值：按照页面给出的目标填写。工作台用途指向 `app.{base}`；站点用途指向 `sites.{base}`（或部署配置 `KWORK_SITES_HOST` 指定的目标）。
5. **在界面执行归属验证**：
   - 回到域名卡片，点击「检查验证」按钮。
   - 若系统检测到 DNS 记录匹配，弹出提示「……已验证」，状态更新为「已验证」，并显示「验证于」时间与「访问地址」。
   - 若尚未查到 DNS 记录，弹出提示「还没有查到 TXT 记录。DNS 生效可能需要几分钟。」，请等待几分钟后再次点击。国内 DNS 生效可能需要十几分钟。
6. **首次访问与证书按需签发**：
   - 自定义域名验证通过后，网关不会预先签发证书。
   - 只有在**第一次有人通过浏览器实际访问该域名**时，网关才会向 Let's Encrypt 触发证书申请流程。
   - 首次访问过程需等待数秒签发证书，首次打开稍慢属于正常情况。

> **提示**
>
> 根域名通常受 DNS 规范限制无法直接配置 CNAME 记录。如需使用根域名，请在 DNS 服务商处使用 ALIAS 记录、ANAME 记录，或改用带前缀的二级域名（如 `www.`）。

### 释放自定义域名与变更用途

1. 自定义域名的用途在添加后无法直接修改。如需更改用途，必须先释放域名后再重新添加。
2. 在「域名」页面找到目标域名的卡片，点击「释放域名」按钮。
3. 弹出确认弹窗「释放……？」，界面说明「释放后域名不再指向你的工作台，可重新添加。」。
4. 点击「释放」确认操作。释放完成后域名不再与当前组织关联。
5. 重新点击「添加域名」，输入域名并选择新的用途，并同步更新 DNS 服务商处的 CNAME 记录指向。

### 配置微信公众号与 JS-SDK 域名

1. 若在 [站点](/apps/site) 应用中使用了微信 JS-SDK，需在微信公众平台配置域名白名单。
2. 登录微信公众平台，在设置中登记 JS 接口安全域名与网页授权域名。
> **注意**
>
>    微信公众平台只认租户配置的正式自定义域名，微信不认平台的预览域名（`*.*.sites.{base}`）。单个微信公众号最多登记 20 个 域名，登记时填入纯域名，不包含协议头。
3. 从微信公众平台下载 txt 格式的校验文件，将其上传至对应站点的「根文件」中完成验证。

### 访问运维管理后台

1. 运维后台（`ops.{base}` 等）默认监听 8443 端口（通过 `OPS_BIND` 配置）。出于安全考虑，不要对公网直接放行 8443 端口。
2. 推荐通过 SSH 建立本地端口转发隧道访问：
   ```bash
   ssh -L 8443:127.0.0.1:8443 root@<主机>
   ```
3. 在本地操作电脑的 hosts 文件中添加映射记录：
   ```text
   127.0.0.1 ops.work.example.com
   ```
4. 在本地浏览器中打开 `https://ops.work.example.com:8443`。
5. 也可以在部署时通过 `--ops-bind <内网 IP>` 将运维网服务绑定至内网 IP，通过内网网络直接访问。

## 状态说明

### 自定义域名生命周期状态

```
添加域名 ───> 待验证 ───[ 点击「检查验证」通过 ]───> 已验证 ───[ 点击「释放域名」]───> 已释放（从列表移除）
```

| 状态名称 | 状态徽章 | 说明 | 可用操作 |
|---|---|---|---|
| 待验证 | 「待验证」 | 域名已添加到组织，正在等待管理员配置 DNS 的 TXT 记录并执行验证。此时域名未生效。 | 复制 DNS 验证信息（「类型」「主机记录」「记录值」）、点击「检查验证」、点击「释放域名」 |
| 已验证 | 「已验证」 | DNS TXT 记录校验成功，域名已成功绑定到组织。首次被访客访问时，网关自动按需向 Let's Encrypt 申请证书。 | 点击「访问地址」访问、点击「释放域名」 |

### 证书流控与自动续期状态

- **按需签发与频率控制**：网关对按需证书签发设有安全流控保护。单主机每 60 分钟 最多批准 6 次 申请（`KWORK_TLS_ASK_PER_HOST`），全局每 60 分钟 最多批准 300 次 申请（`KWORK_TLS_ASK_GLOBAL`），流控时间窗口为 60 分钟（`KWORK_TLS_ASK_WINDOW_MIN`）。配置为 `-1` 时不限制频率。配置了 Redis 时在所有副本间合计计算。当请求被限流时，网关系统日志中会记录 `certificate approvals limited`。
- **自动续期机制**：对于公网 Let's Encrypt 证书，当证书到期时间小于 14 天 时，网关服务（Caddy）会在后台自动执行证书续期。你可以在网关日志中通过 `obtain` 和 `renew` 关键字查看签发与续期记录。

## 让助手帮你做

在组织管理层面，助手可以协助组织管理员查询和管理自定义域名；但在底层基础设施部署层面，没有助手支持。助手不能修改平台基础域名 `BASE_DOMAIN`、不能签发平台证书，也不能修改网关的 Caddyfile 配置文件。

你可以向助手发送如下指令或咨询：
> 查看当前组织已绑定的自定义域名
> 帮我检查自定义域名的验证状态
> 域名 TXT 校验记录的主机记录和值是什么？
> 组织最多可以绑定几个站点域名？

> **注意**
>
> 部署运维操作（如修改基础域名、切换 TLS 模式、导入根证书）涉及基础设施安全与底层路由，必须由部署人员在服务器终端手动配置执行，助手无法代为操作。

## 设置

平台域名与证书相关的环境配置项如下：

| 配置项 | 作用说明 | 默认值 | 修改方式与权限 |
|---|---|---|---|
| `BASE_DOMAIN` | 平台基础域名，所有平台子域名均基于该域名构建 | 安装时必填 | 部署运维人员在部署配置中修改（修改后需重新签发证书并重新执行初始化 bootstrap） |
| `KWORK_BASE_DOMAIN` | kwork 后端进程读取的基础域名环境变量 | compose 中配置为 `$BASE_DOMAIN` | 部署运维人员在部署配置中修改 |
| `KWORK_SITES_HOST` | 站点自定义域名 CNAME 解析的目标主机地址 | `sites.{base}` | 部署运维人员可配置，用于将站点流量指到特定接入前置 |
| `KWORK_SITE_DOMAIN_CAP` | 单个组织最多允许添加的站点域名数量上限（包含未校验的域名） | `10` | 部署运维人员在部署配置中调整 |
| `KWORK_TLS_ASK_PER_HOST` | 单个主机名在时间窗口内允许批准的按需证书签发请求上限（设为 `-1` 表示不限） | `6` | 部署运维人员在部署配置中调整 |
| `KWORK_TLS_ASK_GLOBAL` | 全局所有主机在时间窗口内允许批准的按需证书签发请求总上限（设为 `-1` 表示不限） | `300` | 部署运维人员在部署配置中调整 |
| `KWORK_TLS_ASK_WINDOW_MIN` | 按需证书批准流控的时间窗口时长（单位：分钟） | `60` | 部署运维人员在部署配置中调整 |
| `CADDY_GLOBAL_OPTIONS` | 网关全局选项，设为 `local_certs` 时所有站点强制使用网关内置 CA 签发证书 | 空（默认使用 ACME 公网证书） | 部署运维人员通过 `--tls internal` 或在配置中设定 |
| `OPS_TLS` | 运维管理入口（`*.ops`）的证书签发模式 | `internal` | 部署运维人员在部署配置中调整 |
| `ACME_EMAIL` | Let's Encrypt 证书账户登记邮箱 | `ops@{domain}` | 部署运维人员在部署配置中设定 |

> **提示**
>
> 组织租户侧在界面中没有独立的「设置项」开关，域名配置与绑定本身即为生效的配置项。

## 注意事项

- **站点域名数量配额**：单个组织最多添加 `KWORK_SITE_DOMAIN_CAP`（系统默认 10 个）站点域名，该数量配额包含处于「待验证」状态的域名。
- **域名全局唯一归属**：一个自定义域名在全平台只能属于一个组织，不支持多个组织重复添加同一域名。
- **禁止使用平台基础域名**：组织不能使用平台基础域名（`BASE_DOMAIN`）下的任意主机名作为自定义域名。
- **根域名解析限制**：大部分 DNS 服务商的规范不允许对根域名设置 CNAME 记录。如需将根域名解析到平台或站点，需使用支持 ALIAS 或 ANAME 记录的 DNS 服务商，或改用二级域名（如 `www.`）。
- **DNS 生效网络延迟**：国内 DNS 服务商解析生效通常需要数分钟至十几分钟。若点击「检查验证」未查到 TXT 记录，系统会提示警告，请等待生效后再次校验。
- **按需证书流控限制**：网关对按需证书签发设置了频率上限。默认单主机每 60 分钟 最多 6 次，全局每 60 分钟 最多 300 次（配置了 Redis 时在所有副本间合计计算）。触发限流时日志会记录 `certificate approvals limited`。
- **首次访问延迟**：自定义域名验证通过后并不预先申请证书，只有当首个真实访问请求到达时才向 Let's Encrypt 触发申请（耗时数秒），首次打开页面稍慢属于正常情况。
- **内置 CA 信任要求**：在内网使用 `--tls internal` 部署时，必须将网关根证书导入并信任在每台用户电脑中，否则浏览器会拦截并提示证书错误。
- **Kubernetes 网关多副本存储要求**：在 Helm 部署环境下，网关默认配置为 1 副本，证书保存在持久卷（PVC）中（卸载应用时保留）。若需要运行网关多副本，存储卷必须支持 `ReadWriteMany`（多节点读写共享）。
- **证书自动续期阈值**：Caddy 会在证书到期前少于 14 天 时自动在后台执行续期。可在网关日志中排查 `obtain` 或 `renew` 记录。
- **品牌展示与缓存**：登录页和工作台会根据访问的域名展示对应的组织[品牌](/admin/brand)。品牌配置更新后有约 30 秒 的刷新缓存。
- **支付回调地址要求**：线上支付回调地址格式为 `https://app.{域名}/api/pay/notify/…`，生产环境下基础域名必须公网可达，否则外部支付网关无法完成回调通知。
- **文件直传地址**：浏览器端直接上传和下载走 `files.{base}` 或组织自带存储中配置的「浏览器访问地址」。

## 目前不支持

- 平台不提供域名备案引导流程，不自动检查域名的 ICP 备案状态（中国大陆公网业务需自行向云厂商办理备案）。
- 仓库不提供针对服务域名的外部主动拨测功能（外部探活地址为 `https://app.{base}/brand.json`）。

## 常见问题

#### 为什么添加并验证了自定义域名后，首次通过浏览器打开时感觉加载很慢？
因为 Raise 对自定义域名采用按需签发证书机制。在组织后台通过 DNS 验证后，网关并不会立即向证书机构申请证书；只有在第一次有访客通过 HTTPS 访问该域名时，网关才会向 Let's Encrypt 动态申请并载入证书。整个申请与握手过程通常需要数秒，因此首次打开时会有短暂等待，证书签发完成后后续访问将恢复正常速度。

#### 在内网或私有化环境中部署，为什么打开页面时浏览器提示证书不安全或连接不私密？
在内网环境下部署时（指定了 `--tls internal`），网关使用内置 CA 为服务站点签发证书。客户端操作系统的受信任根证书库中默认不包含此 CA。你需要从服务器下载 `deploy/compose/state/gateway-root-ca.crt` 根证书文件，并将其导入安装到用户的电脑受信任根证书颁发机构中（macOS 用户可使用 `sudo security add-trusted-cert …` 命令，Firefox 用户需在浏览器自带设置中导入）。导入完成后重启浏览器即可消除警告。

#### 为什么在组织设置中点击「检查验证」提示「还没有查到 TXT 记录。DNS 生效可能需要几分钟。」？
这是因为 DNS 服务商的记录广播和生效存在网络延迟，通常需要几分钟至十几分钟。请核对在 DNS 服务商处添加的记录类型是否为 TXT、主机记录是否为 `_kwork-challenge.{域名}`，以及记录值是否与界面给出的 `kwork-verify=…` 完整一致。确认无误后，稍候几分钟再次点击「检查验证」。

#### 为什么无法直接将组织的根域名（如 `example.com`）作为自定义域名通过 CNAME 解析？
根据域名系统（DNS）的标准规范，根域名（Zone Apex）通常必须包含 NS、SOA 等记录，因此大多数 DNS 解析服务商禁止为根域名直接设置 CNAME 记录。如果需要使用根域名，你可以选择支持 ALIAS 记录或 ANAME 记录的 DNS 服务商（将其扁平化解析），或者改用带前缀的二级域名（例如 `work.example.com` 或 `www.example.com`）进行 CNAME 解析。

#### 为什么运维管理后台（8443 端口）无法直接从公网打开？如何正确访问？
运维管理后台（`ops.{base}` 等）默认监听 8443 端口，出于集群安全性考量，生产环境下禁止直接对公网放行 8443 端口。访问运维后台的推荐方式是通过 SSH 建立本地端口转发隧道：在本地执行 `ssh -L 8443:127.0.0.1:8443 root@<主机>`，并在本地 hosts 文件中添加 `127.0.0.1 ops.work.example.com`，然后在浏览器中访问 `https://ops.work.example.com:8443`。此外，也可以在部署时通过 `--ops-bind` 将端口绑定到内网 IP 供内部网络访问。
