# Firebase Hosting 自定义域名 SSL：配置与状态排查

> Firebase Hosting 绑定自定义域名并自动签发 SSL 证书：TXT 验证和 A 记录、CAA 放行 letsencrypt.org 与 pki.goog，以及 Needs setup、Pending 等状态的处理。

Source: https://ssl.sh/zh/guides/firebase-hosting-custom-domain-ssl/
Last updated: 2026-11-10

Firebase Hosting 会为你连接的每个自定义域名自动签发并续期 SSL 证书，除了 DNS 之外没有任何要配置的东西。流程是：用 TXT 记录证明域名所有权，把 A 记录指向 Hosting，Firebase 在 24 小时内把证书部署到全球 CDN，通常几小时就好。它使用的 CA 是 Let's Encrypt 和 Google Trust Services，所以如果设了限制较严的 CAA，两家都要放行。

步骤和菜单名称以 Firebase Hosting 官方文档为准（截至 2026 年 11 月），示例域名为 `example.com`。

## 速查表

| 问题 | Firebase Hosting 的做法 |
|---|---|
| 自动证书的 CA | Hosting 的 CA：Let's Encrypt 和 Google Trust Services |
| 所有权验证 | 根域名上的 `TXT` 记录，需永久保留 |
| 根域名和 `www` | 按向导显示的 IP 添加 `A`（及向导要求的 `AAAA`）记录 |
| CAA 要放行 | `letsencrypt.org` 和 `pki.goog` |
| 通配符域名 | 文档未介绍；逐个连接主机名，建议每个根域名下不超过 20 个子域名 |
| 上传自有证书 | 文档未提供 |
| 续期 | 自动，文档原话是按需重新签发（reprovisions SSL certs, as needed） |
| 多久生效 | A 记录指向 Hosting 后最多 24 小时 |

这里的步骤适用于 Firebase Hosting，Firebase App Hosting 的自定义域名流程不同。

## 国内访问说明

Firebase 是 Google 的服务，从中国大陆通常无法稳定访问，`web.app`、`firebaseapp.com` 和绑定到 Hosting 的自定义域名都可能打不开，这个问题不是证书能解决的。网站要给国内用户用，或者需要 ICP 备案的，建议用阿里云、腾讯云等国内云的静态托管加 CDN，HTTPS 配置见 [阿里云 CDN 配置 HTTPS](https://ssl.sh/zh/guides/aliyun-cdn-https/) 或 [腾讯云 CDN 配置 HTTPS](https://ssl.sh/zh/guides/tencent-cloud-cdn-https/)。

## 第一步：打开连接域名向导

在项目的 **Hosting** 页面点 Add custom domain（有多个站点的，先在目标站点上点 View），输入 `example.com`。可以勾选把请求重定向到另一个域名，让 `example.com` 和 `www.example.com` 显示同样的内容；第二个名字要作为单独的自定义域名再加一次。一个自定义域名只能连接到一个 Hosting 站点。

## 第二步：用 TXT 记录验证所有权

向导要求验证根域名时，在根域名（主机记录填 `@` 或留空）上加一条它给出的 TXT 记录。验证了根域名，就等于证明了对它所有子域名的所有权。高级设置（Advanced Setup）里这条记录的格式是 `hosting-site=[site_id]`。

这条 TXT 记录要永久保留。Firebase 用它证明所有权，并授权自己为站点分配和续期证书。在阿里云解析、DNSPod 添加后，给它最多 24 小时生效，再点 **Verify**。如果这时报错，说明记录还没生效或者值填错了。

## 第三步：把域名指向 Hosting

还没有流量的新域名选 Quick Setup；正在别处提供服务、需要零停机迁移的域名选 Advanced Setup。

**Quick Setup（快速设置）。** 按向导给出的记录为每个主机名添加。文档里的示例是：

```dns
example.com.      3600  IN  A  199.36.158.100
www.example.com.  3600  IN  A  199.36.158.100
```

以你的向导实际显示的值为准，不要照抄示例。然后删除所有指向其他服务商的 `A`、`CNAME` 记录，`AAAA` 记录也要删；快速设置的说明写得很清楚，这些记录只要还在，Firebase 就签不出证书。

**Advanced Setup（高级设置）。** 先把证书准备好，再切流量：

1. 添加所有权 TXT 记录；如果 Hosting 发现已有 CAA 会挡住签发，向导还会给出一对 CAA 记录。
2. 完成 ACME 验证，二选一：在 `_acme-challenge` 名字上加 TXT 记录，或者把指定的文本文件上传到现有网站的指定路径。
3. 证书签好后，把旧记录换成 Hosting 的 A/AAAA 记录。状态变成 **Connected** 之前，旧服务商会继续提供服务。

如果 CA 因为某种原因没能验证通过，Hosting 会重新生成一组验证值给你。

## 第四步：检查 CAA 记录

没有 CAA 记录就没有限制。有的话，两家 CA 都放行：

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

用 [CAA 检测工具](https://ssl.sh/zh/tools/caa-checker/) 或 `dig CAA example.com +short` 查看当前生效的策略。

## 验证

状态变成 Connected 后，域名返回 Let's Encrypt 或 Google Trust Services 签发的证书。用 [SSL 证书检查](https://ssl.sh/zh/tools/ssl-checker/) 从外部检查：

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

也可以直接看证书内容：

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

Firebase 会把你的域名作为 FirebaseApp SSL 证书的一个 SAN 名称，所以 SAN 列表里可能有你之外的其他名字，这是正常的。签发期间可能短暂看到不含你域名的证书，证书准备好后会自动恢复。

## 自动续期

Firebase 文档写明，Hosting 会按需自动为自定义域名重新签发 SSL 证书。要让它一直正常工作，需要两点：所有权 TXT 记录一直保留，A 记录一直指向 Hosting。另外，如果改 CAA 时去掉了 `letsencrypt.org` 或 `pki.goog`，之后的证书也可能签不下来。公开证书的最长有效期 2027 年 3 月 15 日起是 100 天，2029 年 3 月 15 日起是 47 天，续期会越来越频繁，建议用 [ssl.sh 监控](https://ssl.sh/zh/monitor/)（开发中） 盯着域名。

## 按状态排查

Needs setup 多半是 A 记录还没生效，Pending 多半是 CAA、验证 token 或子域名数量的问题。Firebase 文档为自定义域名列出了这几种状态：

- **Needs setup**：大多数情况是 A 记录还没从域名服务商传播到 Firebase Hosting。超过 24 小时的话，检查记录是否确实指向了 Hosting。少数情况（多见于高级设置）是 SSL 证书验证失败，验证用的 token（DNS TXT 记录或上传的文件）已经失效，点域名的 View，按新 token 重新配置。
- **Pending**：域名配置正确，但 Hosting 还没签出证书。Firebase 列了三个原因：
  - CAA 记录太严：放行 `letsencrypt.org` 和 `pki.goog`，见 [CAA 记录阻止签发](https://ssl.sh/zh/errors/caa-record-prevents-issuance/)。
  - 验证码失效：高级设置迁移失败后 token 已失效，点 **View** 用新 token。
  - 子域名太多：因为证书签发数量限制，Firebase 建议一个根域名下不超过 20 个子域名。
- **Minting Certificate**：证书正在生成，等着就行。
- **Connected**：DNS 正确且证书已就绪，网站已经在你的域名上提供服务。

状态还没到 **Connected** 时浏览器提示证书和域名不匹配（[NET::ERR_CERT_COMMON_NAME_INVALID](https://ssl.sh/zh/errors/net-err-cert-common-name-invalid/)），只是签发还没完成。可以用 Google Admin Toolbox 的 Dig 或本地 `dig` 确认记录是否已经更新。
