Docs/ 基础设施/ 自定义域名

自定义域名

为应用绑定您自己的域名。sh0 通过 Caddy 进行路由,并在首次访问时获取 HTTPS 证书。

添加域名

一个域名只绑定到一个应用。添加后路由会立即推送到 Caddy;sh0 不会等待 DNS 生效。

  1. 在控制面板中打开应用。
  2. 进入 Domains & SSL 选项卡。
  3. 点击 Add Domain,在 Domain Name 中输入名称,例如 api.example.com。
  4. 点击 Add Domain 确认。选项卡随后会显示需要创建的 DNS 记录(类型 A,值为服务器 IP)。

在命令行中,sh0 domains <app> add|list|remove 完成相同操作。remove 接受域名或其 ID,除非指定 --yes,否则会要求确认:

Terminal
$ sh0 domains my-api add api.example.com
[ok] Added domain api.example.com to my-api

$ sh0 domains my-api remove api.example.com --yes
[ok] Removed api.example.com from my-api

DNS 配置

在 DNS 服务商处,用 A 记录将名称指向运行 sh0 的服务器公网 IP。控制面板在 DNS Configuration 下显示该 IP,并提供复制按钮。

DNS
api.example.com.   A   <your server IP>

对于子域名,指向另一个已解析到该服务器的名称的 CNAME 同样可行:关键是请求能通过 80 和 443 端口到达这台机器。

Warning
对于您自行管理的域名,sh0 不会查询 DNS。域名列表中的 DNS 指示并不是检查结果:唯一可靠的信号是 SSL Status 变为 Active。

HTTPS 证书

由 sh0 管理的反向代理 Caddy 通过 ACME 获取证书(Let's Encrypt,ZeroSSL 作为备用)。无需任何配置,但以下行为值得了解:

  • 按需签发。证书在该名称的首次 HTTPS 握手时申请,而不是在添加域名时。在有人访问 https://api.example.com 之前,状态保持 Pending。
  • 只为 sh0 路由的名称签发。签发前 Caddy 会询问 sh0 是否有路由使用该名称;TLS 握手中出现的其他名称一律拒绝,因此无人能让您的服务器为任意名称申请证书。
  • HTTP 跳转 HTTPS。Caddy 会将 HTTP 请求重定向到 HTTPS。
  • 续期。Caddy 会在证书到期前自动续期。

当有域名处于待定状态时,Domains & SSL 选项卡每 10 秒重新读取一次状态。通过 API,待定的域名带有 ssl_pending_reason 字段说明原因,例如:“No TLS handshake for this name has reached this server yet: certificates are issued on demand at the first visit. Check that DNS points here, then open the site once over HTTPS.”

位于 CDN 之后(Cloudflare 代理)

当 CDN 在服务器前终止 TLS 时(例如开启橙色云朵的 Cloudflare),HTTP-01 验证请求会停在 CDN,证书可能永远无法签发。有三种解决办法:

  • 仅 DNS(灰色云朵):最简单,Caddy 直接面对访客。
  • DNS-01 验证(按域名设置):Caddy 通过 Cloudflare API 写入 TXT 记录来证明所有权,而不是通过 HTTP 应答。
  • 自定义证书,例如 Cloudflare 源站证书,按下文所述上传。

DNS-01 需要带 Cloudflare 模块的 Caddy(sudo sh0 install-dns-caddy,然后重启 sh0),并在控制面板设置中配置具有 Zone:DNS:Edit 权限的 Cloudflare API 令牌。它按域名启用,且只能通过 API:控制面板目前没有相应的开关。在没有该模块的服务器上,调用会被拒绝(真实响应):

Terminal
$ sudo sh0 install-dns-caddy        # then restart sh0
$ curl -X PUT https://panel.example.com/api/v1/apps/<app-id>/domains/<domain-id>/tls-challenge \
    -H "Authorization: Bearer $SH0_TOKEN" -H "Content-Type: application/json" \
    -d '{"challenge":"dns-01"}'
{"error":{"code":"VALIDATION_ERROR","message":"This server's Caddy carries no DNS provider module, so DNS-01 cannot be used. Run `sh0 install-dns-caddy` and restart sh0; until then this domain would keep HTTP-01 and the setting would be a lie."}}

未配置令牌,或域名不在令牌所控制的区域内时,sh0 同样会拒绝 DNS-01:在那里验证永远无法完成。"challenge":"http-01" 可切换回默认方式。

自定义证书

若要使用您自己的证书颁发机构签发的证书而非 ACME,请使用同一选项卡中的 SSL Certificates 部分:

  1. 可以 Generate CSR(私钥在服务器上生成并保存),再将 CSR 提交给您的 CA;或者 Upload Certificate,以 PEM 格式提供证书及其私钥,如 CA 提供了中间证书链也一并提交。
  2. 签名证书上传后,将该域名切换为 Use Custom SSL。
  3. Use Auto SSL 可恢复自动证书。删除证书也会让使用它的域名回到自动模式。自定义证书的续期需由您自行处理。

规则与限制

  • 不支持通配符。*.example.com 会被拒绝(“Domain labels must contain only alphanumeric characters and hyphens”)。请逐个添加子域名。
  • worker 不能绑定域名。worker 类型的应用不提供 HTTP 端口,请先将其改为 web 类型。
  • 一个名称只属于一处。已绑定到文件存储实例的名称会被拒绝。
  • 规范化。名称在保存前会去除空白并转为小写;每个标签 1 到 63 个字符,只能包含字母、数字和连字符。
  • 权限。添加、删除域名或更改其验证方式,需要在应用所属项目上拥有 developer 角色。

故障排查

如果 SSL Status 一直是 Pending:

  • 读取 GET /api/v1/apps/<id>/domains 中的 ssl_pending_reason:它说明 sh0 看到的原因。
  • 确认该名称解析到服务器的公网 IP(dig +short)。
  • 确认服务器前的所有防火墙(包括云服务商的防火墙)都开放了 80 和 443 端口。
  • 通过 HTTPS 打开一次站点:没有首次握手就不会申请证书。
  • 位于 CDN 之后时,请使用上述三种办法之一。
Terminal
$ dig +short api.example.com
$ curl -I http://api.example.com