基于 Ubuntu 自签永久免费 HTTPS 证书:一次帮你把坑踩个遍

Ubuntu自签HTTPS证书避坑指南

在这里插入图片描述

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

想要的效果

  1. https://sub.domain.com 稳定在线,后端自己管。
  2. 源站证书用 Let’s Encrypt,自动续期。
  3. Cloudflare 继续挡在前面,并且有 CDN + 防护。
  4. 整条链路 端到端加密:浏览器 → 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/超时则继续排查。

分层排查

  1. 谁抢着用了 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 nginx
    

    disable 这一步别偷懒,不然系统下次升级完 apache2 又会自己蹦起来,把 80 端口重新抢回去。

  2. 防火墙别忘了放行

    sudo ufw status
    sudo ufw allow 80/tcp
    

    闭着 80 时 Cloudflare 当然还是够不着。

    如果你用的不是 UFW 而是云厂商安全组/iptables,同理要在那一层放行。Cloudflare 虽然会缓存静态内容,但在申请证书过程里,它必须实时访问你的 .well-known 路径,任何一层阻拦都会直接 523。

  3. 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 就能完成校验。

  4. 再跑一次 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

线上出问题时

  1. 浏览器报错是 Cloudflare 52x 还是源站 4xx/5xx?

  2. 先看源站证书:

    echo | openssl s_client -connect 127.0.0.1:443 -servername sub.domain.com 2>/dev/null \
      | openssl x509 -noout -subject -issuer -dates
    
  3. 看 Cloudflare 的 SSL 模式(Flexible / Full / Full strict)。

  4. 查续期日志:

    systemctl status certbot.timer
    journalctl -u certbot.service
    
  5. 输出 Nginx 生效配置确认到底引用哪张证书:

    sudo nginx -T
    
  6. 仍旧没头绪?关闭橙云改 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 吓醒再来收拾烂摊子。

### Cloudflare SSL证书的申请、安装与配置 #### 云服务器上的SSL/TLS加密概述 为了保障网站的安全性和数据传输过程中的隐私保护,使用SSL/TLS协议来加密通信变得至关重要。Cloudflare提供了一种简单而有效的方法来获取并管理这些安全套接字层/传输层安全性(SSL/TLS)证书。 #### 获取免费的Universal SSL服务 当用户的域名指向通过Cloudflare DNS托管时,默认情况下会自动启用Universal SSL功能[^1]。这意味着无需额外操作即可享受由Cloudflare提供的基础级别的HTTPS支持。 对于那些希望进一步自定义其设置或拥有专用IP地址需求的企业级客户来说,则可以考虑购买更高级别的计划以获得增强型特性和服务质量承诺。 #### 设置页面规则实现强制重定向至HTTPS 为了让访问者始终能够通过安全连接浏览站点,在Cloudflare仪表板内创建一条新的Page Rule(页面规则),指定目标URL模式为`http://*.*/*`并将该请求永久性地301跳转到对应的https版本上[^2]。 ```bash # 创建一个新的页面规则 curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/pagerules" \ -H "Authorization: Bearer {your_api_token}" \ -d '{"targets":[{"target":"url","constraint":{"operator":"matches","value":"http://*.example.com/*"}}],"actions":[{"id":"always_use_https"}],"status":"active"}' ``` #### 自动化部署Let's Encrypt证书 如果用户已经在其他地方注册了自己的域名并且想要利用Cloudflare作为CDN加速器的同时也保持原有的SSL提供商关系的话,那么可以通过CF Workers脚本配合ACME客户端工具完成自动化更新流程[^3]。 ```javascript // Worker script to handle ACME challenges for Let's Encrypt certificates with Cloudflare API. addEventListener('fetch', event => { let url = new URL(event.request.url); if (url.pathname.startsWith('/.well-known/acme-challenge/')) { // Handle challenge response here... } else { return fetch(event.request); } }); ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员义拉冠

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值