# Fly.io 自定义域名证书：fly certs、DNS 与报错

> 用 fly certs add 给 Fly.io 应用绑定自定义域名：A/AAAA 和 CNAME 怎么选、DNS-01 通配符、CAA 放行 Let's Encrypt、导入自有证书，以及验证卡住的排查。

Source: https://ssl.sh/zh/guides/fly-io-custom-domain-certificate/
Last updated: 2026-11-10

Fly.io 会为你用 `fly certs add` 添加的每个自定义域名签发 Let's Encrypt 证书，并负责续期。A/AAAA 或 CNAME 记录指向应用后，它会自动通过 TLS-ALPN 或 HTTP-01 完成验证；通配符证书要额外加一条 `_acme-challenge` CNAME 走 DNS-01。你也可以用 `fly certs import` 导入自己的证书。费用方面，每个组织前 10 张单域名证书免费，之后每张每月 0.10 美元；通配符证书每张每月 1 美元。

步骤和菜单名称以 Fly.io 官方文档为准（截至 2026 年 11 月）。应用名 `my-app` 和域名 `example.com` 是示例。

## 速查表

| 问题 | Fly.io 的做法 |
|---|---|
| 自动证书的 CA | Let's Encrypt |
| 验证方式 | TLS-ALPN（首选）、HTTP-01、DNS-01 |
| 根域名 `example.com` | 推荐 `A` 和 `AAAA` 指向应用 IP |
| `www` 和其他子域名 | `CNAME` 指向应用专属的 `fly.dev` 目标地址 |
| CAA 要放行 | `letsencrypt.org` |
| 通配符证书 | 支持，DNS-01（`_acme-challenge` CNAME），每月 1 美元 |
| 上传自有证书 | 支持，`fly certs import` |
| 证书状态 | `active`、`pending_validation`、`pending_ownership` |

## 国内访问说明

从中国大陆访问部署在 Fly.io 上的应用，延迟和稳定性都没有保证，不同运营商、不同时段差别很大，这些问题和证书本身无关。国内用户为主或需要 ICP 备案的业务，建议部署在阿里云、腾讯云等国内云上，证书参考 [阿里云 SSL 证书](https://ssl.sh/zh/guides/aliyun-ssl-certificate/) 或 [acme.sh 用阿里云 DNS/DNSPod 签证书](https://ssl.sh/zh/guides/acme-sh-dnspod-aliyun-dns/)。

## 第一步：把域名加到应用

每个要用 HTTPS 的主机名都要用 `fly certs add` 单独添加一次，通配符也一样：

```bash
fly certs add example.com -a my-app
fly certs add www.example.com -a my-app
fly certs add "*.example.com" -a my-app   # 通配符要加引号，避免被 shell 展开
```

每条命令都会打印适合你情况的 DNS 配置选项，之后可以用 `fly certs setup example.com` 再看一遍，控制台的 **Certificates** 页面也有同样的信息。

应用还没有公网 IPv4 和 IPv6 地址的话，先分配推荐的地址（需要精细控制时还有 `fly ips allocate-v4`、`fly ips allocate-v6`）：

```bash
fly ips allocate -a my-app
fly ips list -a my-app
```

## 第二步：添加 DNS 记录

Fly.io 签发或续期证书前，必须通过以下至少一种方式验证域名：指向应用的 `AAAA` 记录、`_acme-challenge` 的 CNAME 记录，或 `_fly-ownership` 的 TXT 记录。

| 名字 | 类型 | 记录值 |
|---|---|---|
| `example.com` | `A` | `fly certs setup` 显示的 IPv4 地址 |
| `example.com` | `AAAA` | 应用的 IPv6 地址 |
| `www.example.com` | `CNAME` | `fly certs setup` 显示的专属目标地址 |

大多数情况 Fly.io 推荐 A 和 AAAA。根域名上除非服务商支持 CNAME 拉平（ANAME/ALIAS），否则就用 A/AAAA；CNAME 适合子域名，也适合 IP 多或以后可能变动的应用。在阿里云解析、DNSPod 里，主机记录分别填 `@` 和 `www`。

还有两种可选记录用于特殊情况：

- **`_acme-challenge` CNAME**：走 DNS-01 验证，通配符证书必须用；想在切流量之前先拿到证书时也可以用。
- **`_fly-ownership` TXT**：域名在 CDN 或代理后面、要导入自有证书、或者不想用 IPv6 时，用它证明所有权。多个值可以写在同一条 TXT 记录里，用分号隔开。

## 第三步：检查 CAA 记录

域名设了 CAA 的话，必须放行 Let's Encrypt：

```dns
example.com.  3600  IN  CAA  0 issue "letsencrypt.org"
```

用 [CAA 检测工具](https://ssl.sh/zh/tools/caa-checker/) 确认。CAA 里只写了别家 CA（比如 `digicert.com`），签发会直接失败。

## 第四步：查看验证进度

DNS 记录生效后，用 `fly certs check` 触发重新检查，用 `fly certs list` 看所有证书的状态：

```bash
fly certs check example.com -a my-app
fly certs list -a my-app
```

`fly certs check` 会重新检查 DNS 和验证状态。Machines API 里的证书状态和 CLI 一致：`active` 表示已签发，`pending_validation` 表示验证还没完成，`pending_ownership` 表示还没证明所有权；返回结果里还可能带 `validation_errors` 和 `rate_limited_until`（频率限制解除时间）。

## 导入自有证书

`fly certs import` 上传 PEM 格式的完整证书链和私钥，导入的证书要自己续期：

```bash
fly certs import example.com --fullchain fullchain.pem --private-key private-key.pem -a my-app
```

在 `AAAA` 记录或 `_fly-ownership` TXT 记录证明所有权之前，状态可能是 `pending_ownership`。同一个主机名上自有证书和 Fly 托管证书可以共存：优先使用自有证书，Let's Encrypt 证书作为备用。Fly.io 的自动续期只针对它托管的 Let's Encrypt 证书，导入的证书要你自己在到期前替换。只想删除其中一种，用 `fly certs remove example.com --custom` 或 `--acme`。

## 验证

证书状态变成 `active` 后，域名返回 Let's Encrypt 签发的证书（导入的证书除外）。用 [SSL 证书检查](https://ssl.sh/zh/tools/ssl-checker/) 检查，或运行：

```bash
curl ssl.sh/example.com
```

确认 Fly Proxy 返回的证书：

```bash
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -issuer -subject -ext subjectAltName -dates
```

托管证书的颁发者是 Let's Encrypt，导入证书则显示你所用的 CA。

## 续期

Fly.io 托管的证书由它负责续期，文档说明续期不计入 Let's Encrypt“每个注册域名的证书数”限制。续期需要和首次签发一样的验证，所以 `AAAA` 记录、`_acme-challenge` CNAME 或 `_fly-ownership` TXT 要一直保留。导入的证书归你管，而公开证书有效期在不断缩短：现在最长 200 天，2027 年 3 月 15 日起 100 天，2029 年 3 月 15 日起 47 天。两种证书都建议用 [ssl.sh 监控](https://ssl.sh/zh/monitor/)（开发中） 盯着。

## 常见问题排查

**签发或验证卡住、失败。** Fly.io 首先提示检查 Let's Encrypt 的频率限制：

- 每个注册域名每周 50 张证书；
- 重复证书每周 5 张；
- 每个主机名每小时最多 5 次验证失败。

Fly.io 没法帮你重置，只能等时间窗口过去。用 Let's Debug 测一下域名，能发现 DNS、名称服务器、CAA、网络等问题；调试时不要反复删除再添加证书。详见 [Let's Encrypt 频率限制](https://ssl.sh/zh/errors/lets-encrypt-rate-limit/)。

**套了 Cloudflare。** 开着橙色云代理时，加一条 `_fly-ownership` TXT 记录，Fly.io 就能通过代理用 HTTP-01 签证书；Cloudflare 的 SSL 模式设成 Full 或 Full (Strict)，Flexible 会造成重定向循环。DNS-01 证书会和 Cloudflare Universal SSL 冲突，因为 Universal SSL 会自动插入在控制台里看不到的 `_acme-challenge` TXT 记录。还签不下来，就导入 Cloudflare Origin Certificate，并用同一条 TXT 记录验证所有权。

**CAA 报错。** 加上 `0 issue "letsencrypt.org"`，见 [CAA 记录阻止签发](https://ssl.sh/zh/errors/caa-record-prevents-issuance/)。

**浏览器里证书不对。** 运行 `fly certs list` 检查：可能这个主机名没加到应用里，或者有冲突的 DNS 记录把部分访客带去了别处。
