事情本身不复杂,线索都在日志里。CentOS 7.9 上用 acme.sh 给站点签证书,首次签发成功,三个月后续期一直停在 pending,日志里是 invalid response from http,访问 /.well-known 被 301 到了 https。
第一反应是「80 端口上的默认 server 抢走了域名的请求,落到另一个站点根目录」,验证下来不成立。
原因不止一个,得分开看。nginx 里配了全站 301 跳 https,续期请求也被一起跳走,验证端不跟随跳转。少数情况下是nginx 的 location 匹配把 .well-known 目录也交给了 PHP 处理。
另外,证书签发方式选的是 standalone,但 80 端口正被 nginx 占着。
手工复现验证路径的返回
curl -sI http://www.example.com/.well-known/acme-challenge/test
然后在 nginx 里给该路径单独放行
printf 'location ^~ /.well-known/acme-challenge/ { root /var/www/letsencrypt; }\n' > /etc/nginx/conf.d/acme.conf && nginx -t && nginx -s reload
随后改回 webroot 方式续期
acme.sh --issue -d www.example.com -w /var/www/letsencrypt --force
等前面都确认过,再确认续期任务已写入
crontab -l | grep acme && acme.sh --list
怎么算真的好了,看的是同一批现象。curl 该路径返回 200 且内容是验证串,acme.sh –renew 输出 Cert success,acme.sh –list 里的续期时间变成三个月后。
这里还有个坑。全站跳 https 的模板最容易踩这个坑,验证路径要放在跳转规则之前;用 DNS 方式签发可以绕开 80 端口,但要能改解析记录。同一份配置在测试环境跑通,不代表线上没事,两边的默认值经常不一样。
