
把
sub.domain.com这条链路从 523 错误、systemd timer 到 Cloudflare SSL 模式全部摸了一遍,将踩坑记录分享出来。
背景与目标
导火索其实是:受够了阿里云那套三个月一到就得手动重做 SSL 的流程,所以决定自己接管证书链路,于是有了这次折腾:Ubuntu 22.04 云主机 + Cloudflare 橙云 + Nginx 源站 + Let’s Encrypt,希望彻底摆脱手工续期SSL证书的烦恼。
整体架构其实很简单:Cloudflare 负责 DNS 和边缘代理,Nginx 负责源站业务,证书则改由 certbot 托管。理论上这是一套被无数人验证过的组合,但真开干就知道细节坑有多少:DNS 云朵颜色、80 端口、systemd 定时器、Cloudflare SSL 模式……每一步都能把人劝退。
环境
- Ubuntu 22.04 LTS
- Cloudflare 代理(吃瓜名称叫“橙云”?)
- Nginx 提供服务
- DNS 托管在 Cloudflare
想要的效果
https://sub.domain.com稳定在线,后端自己管。- 源站证书用 Let’s Encrypt,自动续期。
- Cloudflare 继续挡在前面,并且有 CDN + 防护。
- 整条链路 端到端加密:浏览器 → Cloudflare → 源站。
听上去挺普通的需求,结果一脚踩进一堆坑。踩完才明白:越是“常见套路”,越容易想当然,很多默认设置都暗藏条件,比如 Cloudflare 的 52x 错误其实是源站问题、iptables/UFW 的默认策略其实不给新端口开门、certbot 早就把 cron 换成 timer 等等。
坑一:certbot 报 523,其实是 Cloudflare 找不到源站
现场命令
sudo certbot --nginx -d sub.domain.com
Invalid response from
http://sub.domain.com/.well-known/acme-challenge/xxx: 523
523 是 Cloudflare 的 “Origin is unreachable”。意思是:Let’s Encrypt 从 Cloudflare 转发过来,结果 Cloudflare 啥都没拿到。顺带一提,Cloudflare 的 52x 系列全是“我去叫后端结果扑了个空”,523 是 TCP 连不通,522 是超时,520/521 是源站直接挂——所以别一股脑儿怀疑 certbot,多半是自己主机的问题。
第一步可以先去 Cloudflare 面板看一下 DNS 记录是否是橙云、IP 有没有指错。如果你开了灰云(DNS only),Let’s Encrypt 会直接敲源站;但只要是橙云,验证流量就得先打到 Cloudflare,再由它去源站。
先验证 HTTP/HTTPS
直接浏览器测一遍:
https://sub.domain.com✅ 正常http://sub.domain.com❌ 523
说明 443 一切 OK,80 端口不正常!
如果没有浏览器环境,也可以临时 curl -I http://sub.domain.com,或者更狠一点 curl -I --resolve sub.domain.com:80:你的源站IP http://sub.domain.com,直接跳过 Cloudflare。命令行返回 301/200 说明源站没问题,直接 52x/超时则继续排查。
分层排查
-
谁抢着用了 80?
sudo ss -tlnp | grep ':80 '输出里干脆写着
apache2,原来我这台机子还留着 Apache。ss这一招很好用,能一眼看出监听端口对应的进程、PID、句柄,用来甄别历史残留服务再合适不过。sudo systemctl stop apache2 sudo systemctl disable apache2 sudo systemctl start nginx sudo systemctl enable nginxdisable这一步别偷懒,不然系统下次升级完 apache2 又会自己蹦起来,把 80 端口重新抢回去。 -
防火墙别忘了放行
sudo ufw status sudo ufw allow 80/tcp闭着 80 时 Cloudflare 当然还是够不着。
如果你用的不是 UFW 而是云厂商安全组/iptables,同理要在那一层放行。Cloudflare 虽然会缓存静态内容,但在申请证书过程里,它必须实时访问你的
.well-known路径,任何一层阻拦都会直接 523。 -
80 端口的 Nginx 配置要干净
server { listen 80; server_name _; # 也可以不手写 .well-known,交给 certbot --nginx 自动处理 location / { return 301 https://$host$request_uri; } }这一份是最省事的“兜底”server 块。certbot 会在你已有的 server 块中插入
.well-known/acme-challenge的 location,如果你只想保持一个全局 301,也完全没问题,它会帮你生成一个临时配置。只要 80 端口能返回 200/301,Let’s Encrypt 就能完成校验。 -
再跑一次 certbot
sudo certbot --nginx -d sub.domain.com这回顺利签证。
1.4 总结
- 523 绝大概率是 Cloudflare 打不到你,不要怪 certbot。
- Cloudflare 验证走 HTTP,80 端口得保证能用。
.well-known可以交给certbot --nginx,不用单独写 rewrite。
坑二:使用 systemd timer 自动续期,而不是用 cron
certbot 完事后会提示 “已经安排自动续期”。结果 crontab -l 空空如也,让人怀疑人生。Ubuntu 22.04 默认是 systemd timer。
systemctl list-timers | grep certbot
看到 certbot.timer 每 12 小时检查一次,跑 certbot renew。只有证书 30 天内到期才真正续。
如果想细究它的调度规则,可以 systemctl cat certbot.timer 看看配置,里面写着 OnCalendar=*-*-* 00,12:00:00,也就是每天两次。真正干活的是 certbot.service,默认运行 certbot -q renew,静默模式只在出错时打印日志。
想演习:
sudo certbot renew --dry-run
想盯日志:
systemctl status certbot.timer
journalctl -u certbot.service
搞清楚这些流程之后,自动续期就放心多了。
另外,certbot 支持 --deploy-hook。如果你源站后面还有额外的服务(比如 reload 某个容器、同步证书到别的机器),可以提前把脚本挂上去,renew 成功后自动执行一遍。
坑三:浏览器里看到的证书不是自己那张
先在源站确认证书
echo | openssl s_client -connect 127.0.0.1:443 -servername sub.domain.com 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
这条命令直接连 127.0.0.1,绕开 Cloudflare。要是这里还是旧证书,Nginx 配置没切对。
server {
listen 443 ssl http2;
server_name sub.domain.com;
ssl_certificate /etc/letsencrypt/live/sub.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sub.domain.com/privkey.pem;
# ...
}
改完:
sudo nginx -t
sudo systemctl reload nginx
为什么浏览器里还是另一张?
因为橙云挡着,浏览器连的是 Cloudflare,当然看到 Cloudflare 的边缘证书。想看源站那张就得先灰云(DNS only)。
Cloudflare 自带的通配符
Cloudflare 的 Universal Edge Certificate 默认涵盖 domain.com 和 *.domain.com,SAN 里写得明明白白。免费、省心,但私钥在 Cloudflare 手上,不能拿走。你也可以在 Cloudflare 面板申请“源站证书”(Origin Certificate),这是一张只用在 Cloudflare→源站链路的证书,最长有效期 15 年,不过它不被浏览器信任,适合不想折腾 certbot 的场景。
如果希望在浏览器里测试源站证书,又不想灰云,可以用 curl -I --resolve sub.domain.com:443:源站IP https://sub.domain.com 强制把域名解析到源站,确认链路没问题再打开橙云。
Cloudflare SSL 模式顺手梳一遍
位置:Cloudflare 控制台 → SSL/TLS → Overview。
- Flexible:前端 HTTPS,回源 HTTP。源站无证书也能跑,但中间明文,安全感为零。
- Full:两端都是 HTTPS,但 Cloudflare 不验证源站证书。自签、过期都照样连,容错高、安全性一般。
- Full (strict):两段 HTTPS 且严校证书。源站证书不对就弹 525/526。我最终选这个,图个安心,但续期一定要稳。
还有个细节:如果你的业务需要 WebSocket、gRPC 等长连接,最好直接用 Full/Full (strict)。Flexible 在这些协议上经常翻车,因为中间那段是 HTTP,连接升级会失败。总之,只有在“我就是没证书”这种情况才考虑 Flexible,否则别想太多,直接 Full (strict)。
主域在虚机、子域在自管服务器的搭配
- 边缘证书(Edge cert):Cloudflare 托管,对
domain.com+*.domain.com生效,自动续期,所有子域共享。 - 各自源站证书(Origin cert):
- 虚拟主机那份通常是 cPanel + AutoSSL 之类的东西管。
- 自管服务器这边用
Let's Encrypt + certbot。
- 两套体系统治不同层面,互不干涉。
- 如果主域也开
Full (strict),虚机上的证书也必须保持可用,否则照样 525/526。
实践下来比较顺的方式是:主域保持橙云,依赖虚机商的自动化;需要自定义业务逻辑的子域全部指向自建服务器,各自维护 certbot。Cloudflare 的“SSL for SaaS” 也能做到分域托管,但那是付费功能,普通用户还是分开管理更省心。
Checklist:上线/排障的小抄
申请/续期前
- DNS 已指到正确 IP,必要时先灰云(DNS only)。
- 80 / 443 都由 Nginx 接管,Apache 一律停掉。
- 防火墙、安全组放行 80、443。
- 可以
certbot certificates看看已有证书状态,确认路径没写错。 nginx -t应成为肌肉记忆,改配置别忘了过一遍。- 几个常用命令:
sudo certbot --nginx -d sub.domain.com
sudo systemctl list-timers | grep certbot
sudo certbot renew --dry-run
线上出问题时
-
浏览器报错是 Cloudflare 52x 还是源站 4xx/5xx?
-
先看源站证书:
echo | openssl s_client -connect 127.0.0.1:443 -servername sub.domain.com 2>/dev/null \ | openssl x509 -noout -subject -issuer -dates -
看 Cloudflare 的 SSL 模式(Flexible / Full / Full strict)。
-
查续期日志:
systemctl status certbot.timer journalctl -u certbot.service -
输出 Nginx 生效配置确认到底引用哪张证书:
sudo nginx -T -
仍旧没头绪?关闭橙云改 DNS only,看直接连源站会报什么,再根据 HTTP/HTTPS 提示继续排。
写在最后
- 523 不是 certbot 崩,而是 Cloudflare 找不到你家 80 端口。
- 自动续期交给
certbot.timer,别再去 cron 里找。 - 开橙云时浏览器看到的永远是 Cloudflare 的证书,别纠结。
- Full 和 Full (strict) 是容错 vs 安全的选择题,选严格模式就要保证续期流程没毛病。
- 主域、子域在不同环境没关系,记住边缘证书统一托管,各自源站各自续。
整个流程走完,回头看其实每个点都挺有逻辑。希望这篇“流水账”能帮你少踩几个坑,Nginx + certbot + Cloudflare 早日顺起来。
最后提醒一句:证书这玩意儿是个持续性工程,搭完不是结束。隔三差五盯一下 journalctl -u certbot.service、看看证书剩余天数、检查 Cloudflare 邮件通知,都是很划算的投入。别像我一样被 523/525 吓醒再来收拾烂摊子。
Ubuntu自签HTTPS证书避坑指南
1万+

被折叠的 条评论
为什么被折叠?



