跳到主内容
快讯直播
AI智模界
教程

SSL 证书申请失败或不生效的常见原因

报错现象

在申请或部署 SSL 证书时,常见几类报错:

1. ACME 客户端申请阶段:

```

Challenge failed for domain example.com

Timeout during connect (likely firewall problem)

Invalid response from http://example.com/.well-known/acme-challenge/xxx: 404

DNS problem: NXDOMAIN looking up A for example.com

Problem binding to port 80: Could not bind to IPv4 or IPv6

Too many failed authorizations recently

```

出现场景:运行 certbot、acme.sh 等客户端,选择 HTTP-01 或 DNS-01 验证后。

2. 浏览器访问阶段:

```

NET::ERR_CERT_COMMON_NAME_INVALID

NET::ERR_CERT_AUTHORITY_INVALID

您的连接不是私密连接

证书链不完整

```

出现场景:Nginx/Apache 配置了证书,但浏览器不信任,或部分客户端(Java、旧 Android、小程序)请求失败。

3. 自动续期失败:

cron 或 systemd timer 执行 certbot renew 后证书未更新,日志里出现 Attempting to renew cert ... produced an unexpected error

影响范围:网站被标记不安全、API 调用中断、移动端 WebView 无法加载、支付回调失败等。排查时先区分是“申请失败”还是“申请成功但不生效”。

可能原因

按出现概率从高到低:

1. 域名解析问题:A/AAAA 记录缺失、指向错误 IP、存在冲突的 CNAME、DNS 缓存未刷新、只有 A 记录但客户端走 IPv6 导致验证超时。

2. 验证方式与服务器实际配置不匹配:HTTP-01 要求 80 端口可从公网访问并返回指定内容;DNS-01 要求 TXT 记录正确传播;TLS-ALPN-01 要求 443 端口直达本机。

3. 80 端口被占用或防火墙/安全组未放行:Nginx、Apache、Docker 容器占用 80;云安全组、ufw、iptables 拦截。

4. 证书链不完整或部署文件用错:只部署了域名证书,缺少中间 CA;Nginx 把 ssl_certificate 指向 cert.pem 而不是 fullchain.pem

5. 自动续期配置失效:timer/cron 未启用、webroot 路径变化、DNS API 凭证过期、deploy hook 未重载服务、权限不足。

6. 触达 CA 速率限制或 CAA 记录限制:短时间内重复申请、CAA 只允许特定 CA。

7. 服务器时间偏差过大、SNI 配置错误、HTTP 强制跳转 HTTPS 干扰验证、CDN/WAF 回源拦截。

逐条排查与解决

1. 检查域名解析

先确认域名指向当前服务器的公网 IP。

```

dig +short A example.com

dig +short AAAA example.com

dig +short CNAME example.com

curl -4 ifconfig.me

curl -6 ifconfig.me

```

判断:A 记录应返回服务器公网 IPv4。如果返回 203.0.113.10 这类文档示例 IP,说明解析未生效或配错。若有 AAAA 记录但服务器没有 IPv6 地址,部分 CA 会优先走 IPv6 验证导致超时。可暂时删除 AAAA 记录,或给服务器配置 IPv6 并放行 80/443。

修改 DNS 后等待 TTL 过期,用公共解析器验证:

```

dig @8.8.8.8 +short A example.com

dig @1.1.1.1 +short A example.com

```

如果多个解析器结果不一致,说明传播未完成,等一段时间再申请。

2. 确认验证方式

HTTP-01 验证:CA 会访问 http://example.com/.well-known/acme-challenge/随机字符串。需要 80 端口开放,且 Web 服务器能返回文件内容。

用 webroot 模式示例:

```

sudo certbot certonly --webroot -w /var/www/html -d example.com

```

Nginx 中确保验证路径不被重写、不被跳转:

```

location ^~ /.well-known/acme-challenge/ {

root /var/www/html;

default_type "text/plain";

allow all;

}

```

手动放一个测试文件:

```

echo "hello-acme" | sudo tee /var/www/html/.well-known/acme-challenge/hello

curl -v http://example.com/.well-known/acme-challenge/hello

```

判断:返回 200 且内容为 hello-acme。若返回 301 到 HTTPS,需要让 HTTP 验证路径可访问,或改用 DNS-01。若返回 404,检查 root 路径和 location 是否匹配。若超时,回到第 3 条查端口和防火墙。

DNS-01 验证:CA 会查询 _acme-challenge.example.com 的 TXT 记录。

```

dig +short TXT _acme-challenge.example.com

dig @8.8.8.8 +short TXT _acme-challenge.example.com

```

判断:返回的 TXT 值应与客户端要求的一致。使用 DNS API 插件时,检查 API 凭证是否有权限修改 TXT 记录。若手动添加 TXT,注意不要多加引号或换行。

TLS-ALPN-01 验证:需要 443 端口直接到达本机,且没有 CDN 终止 TLS。判断:openssl s_client -connect example.com:443 -servername example.com 返回的证书是否为本机证书。

3. 检查 80 端口占用与防火墙

```

sudo ss -tlnp | grep ':80'

sudo lsof -i :80

sudo ss -tlnp | grep ':443'

```

如果 80 被 Nginx 占用,不要用 --standalone 硬抢端口。两种做法:

  • 用 webroot 模式,让 Nginx 继续监听 80。
  • 临时停掉 Nginx:

```

sudo systemctl stop nginx

sudo certbot certonly --standalone -d example.com

sudo systemctl start nginx

```

如果使用 Docker,检查端口映射:

```

docker ps --format '{{.Names}} {{.Ports}}'

```

防火墙检查:

```

sudo ufw status

sudo iptables -L -n

sudo firewall-cmd --list-all

```

云服务器还要在控制台安全组放行 80 和 443。判断:从外网执行 curl -v http://example.com,若连接超时,通常是安全组或防火墙拦截。

4. 检查证书链与部署文件

申请成功后,证书目录通常包含:

  • cert.pem:域名证书
  • chain.pem:中间 CA 证书
  • fullchain.pem:域名证书 + 中间 CA
  • privkey.pem:私钥

Nginx 应这样配置:

```

server {

listen 443 ssl;

server_name example.com;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

}

```

Apache 应这样配置:

```

SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem

SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

```

检查实际链:

```

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null

```

判断:输出中应有多个证书,末尾是根 CA 或中间 CA。如果只有一个证书,说明链不完整。再用:

```

openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt /etc/letsencrypt/live/example.com/fullchain.pem

```

返回 OK 表示链文件完整。浏览器正常但 Java 或旧 Android 报错,通常是链不完整或顺序错误。

5. 检查自动续期

查看定时任务是否启用:

```

systemctl list-timers | grep certbot

sudo crontab -l

```

执行演练:

```

sudo certbot renew --dry-run

```

查看日志:

```

sudo journalctl -u certbot.timer

sudo tail -n 100 /var/log/letsencrypt/letsencrypt.log

```

常见问题与处理:

  • webroot 路径变化:修改续期配置中的 --webroot-path
  • DNS API 凭证过期:更新凭证文件或环境变量。
  • 续期后服务未重载:加 deploy hook。

```

sudo certbot renew --deploy-hook "systemctl reload nginx"

```

手动强制续期测试(不要频繁执行,避免触发速率限制):

```

sudo certbot renew --force-renewal

```

判断:--dry-run 成功说明续期流程基本可用;若失败,按日志里的 challenge 类型回到第 1、2、3 条排查。

6. 检查速率限制与 CAA

```

dig +short CAA example.com

```

如果返回 0 issue "某个CA",而申请的不是该 CA,就会失败。需要修改 CAA 记录或改用允许的 CA。若报错包含 too many certificates already issuedtoo many failed authorizations,说明触发了 CA 的速率限制。等待限制窗口重置,或改用其他验证方式。具体限制以 CA 官方页面为准。

7. 检查服务器时间与 SNI

```

date -u

timedatectl status

```

时间偏差过大会导致 ACME 签名验证失败。启用 NTP:

```

sudo timedatectl set-ntp true

```

多域名或 SNI 场景,确认请求的域名匹配到正确 server 块:

```

openssl s_client -connect 127.0.0.1:443 -servername example.com </dev/null | openssl x509 -noout -subject -dates

```

判断:subject 中的 CN 或 SAN 应包含 example.com。若不包含,说明 Nginx/Apache 用了默认证书或错误证书。

都不管用时的兜底方案

1. 换验证方式。HTTP-01 反复失败时,改用 DNS-01;DNS-01 传播慢时,改用 HTTP-01。两种方式交叉验证,能快速定位是解析问题还是 Web 服务问题。

2. 换一台机器申请。在一台 80/443 干净的临时服务器上申请,成功后把 fullchain.pemprivkey.pem 拷贝到目标服务器。注意私钥权限设为 600

3. 使用手动模式。certbot certonly --manual 可以按提示手动添加 DNS TXT 记录,适合排查阶段。但手动模式默认不能自动续期,需要后续补自动化。

4. 换 ACME 客户端。不同客户端对验证流程、DNS API 支持不同,具体用法以官方文档当前版本为准。

5. 抓包确认请求是否到达。在服务器上执行:

```

sudo tcpdump -i any -n port 80 or port 443

```

然后重新申请,观察是否有来自 CA 的请求。若没有请求到达,问题在 DNS、防火墙或 CDN;若有请求但返回错误,问题在 Web 服务器配置。

6. 检查 CDN/WAF。如果域名接入了 CDN,确认回源是否放行 .well-known/acme-challenge/ 路径,或者临时把解析切到源站再申请。

7. 查看完整日志。ACME 客户端日志通常比屏幕输出更详细,重点看 challenge 类型、请求 URL、返回状态码。若仍无法判断,带上日志和域名信息联系 CA 支持。

如何预防再次发生

1. 域名解析保持稳定。给需要证书的域名固定 A 记录,A/AAAA 保持一致。变更解析前先确认新 IP 已能提供服务,TTL 不要设得过长。

2. 优先选适合自己环境的验证方式。服务器 80 端口稳定可达,用 HTTP-01;域名多、服务器分散、不想暴露 80,用 DNS-01。DNS API 凭证要最小权限并妥善保管。

3. 变更防火墙和安全组前先自检。用 curl 从外网访问验证路径,确认 80/443 可达。云安全组、主机防火墙、容器端口映射三处都要检查。

4. 始终部署 fullchain。Nginx 用 fullchain.pem,Apache 用 fullchain.pem。定期用 openssl s_client 检查证书链是否完整。

5. 自动续期要演练。配置 systemd timer 或 cron 后,执行 certbot renew --dry-run。加 deploy hook 自动重载 Nginx/Apache,避免证书更新了但服务仍用旧证书。

6. 设置到期提醒。即使有自动续期,也用监控工具检查证书剩余有效期。到期前 30 天、7 天分别告警。

7. 保留排查记录。记录域名、验证方式、使用的 ACME 客户端、证书路径、续期命令。下次出现类似报错时,能快速对照。

按照上面的顺序排查,多数 SSL 证书申请失败或不生效的问题都能定位。核心思路是:先确认域名解析到达正确的服务器,再确认验证方式对应的端口和路径可达,然后检查证书链和续期配置,再考虑 CA 限制和 CDN 等外部因素。

AI 生成本文由 AI 基于公开信息自动生成,仅供参考。