阿里云域名+Ubuntu服务器Let‘s Encrypt免费HTTPS证书完整配置指南
2026/9/16 3:55:20 网站建设 项目流程

1. 先拆清楚需求:免费证书的适用边界与整套方案的选型逻辑

1.1 Let's Encrypt 到底是什么

Let's Encrypt 是 ISRG(Internet Security Research Group)运营的一个免费证书颁发机构,它的核心特点是证书签发、续期全部自动化,走的是 ACME 协议。2016 年正式上线之后,个人网站、小项目、测试环境全面普及,现在几乎成了"免费 HTTPS"的代名词。

它的证书有效期固定在 90 天,和阿里云那个一年期的免费 DigiCert 证书完全不同。90 天看起来很短,其实是设计选择:短周期证书就算私钥泄露,影响面也有限;同时强制倒逼证书持有人把"续期"这个过程自动化。所以 Let's Encrypt 从诞生起就假设你会用脚本或定时器去续期,而不是像传统证书那样到期前手动换一次。

在 Ubuntu 服务器上跑这套,通常的形态是:Certbot 作为客户端向 Let's Encrypt 申请证书,签发完成后写到/etc/letsencrypt/live/目录,Nginx 直接引用这个路径;然后由 systemd 定时器每天检查一次证书是否临近过期,该续就续,续完自动 reload web server。整个过程跑通之后,你基本不会再碰证书相关的事情。

1.2 哪些场景适合免费证书,哪些场景建议买付费

我先说结论:个人博客、小微企业官网、API 服务、内部系统外网入口、开发测试环境,Let's Encrypt 完全够用,而且是首选。我自己一台 Ubuntu 机器上挂了博客、几个 API 接口,还有给移动端调用的后端服务,跑了三年多没有任何问题。

但有两类场景我会劝你买付费证书。第一种是银行、支付、政务类强合规业务,或者对"证书签发成功率"有极高要求的核心生产链路,这类场景需要的是 OV/EV 证书的品牌背书,以及背后有专人可找的商业支持。第二种是你自己没法保证 80/443 端口稳定开放、域名解析经常变动,或者服务器网络环境特殊(比如某些机房对 ACME 验证请求有阻断),这时候付费证书的"宽容度"更高,省下的排查时间可能比证书本身值钱。

做一个简单的对比:

对比项Let's Encrypt阿里云免费证书(1年)付费 OV 证书
价格免费免费几百到几千不等
有效期90 天1 年1-2 年
续期方式全自动手动申请部署手动或自动
签发速度秒级几分钟到几小时1 到 5 个工作日
地址栏企业名不显示不显示OV/EV 显示
适合场景个人站/API/测试临时项目/简易 HTTPS品牌展示/合规要求

1.3 整套方案的技术链路

整个方案可以拆成四层:域名层、服务器层、Web 服务层、证书生命周期管理层。

域名在阿里云注册,DNS 解析也托管在阿里云;Ubuntu 服务器上跑着 Nginx;Certbot 负责和 Let's Encrypt 交互;systemd timer 负责定时触发续期。每一层出问题都会导致 HTTPS 不正常,但每层的问题表现不一样:域名解析错了,证书根本没发下来;服务器防火墙没放行 80,验证请求进不来;Nginx 配置错了,证书装上去也不生效;定时器没跑,证书到期会突然暴雷。

动手之前,先把下面这几项准备好:

  • 一个在阿里云注册的域名,并且已经完成实名认证
  • 一台 Ubuntu 服务器(20.04 或 22.04 都行),有 root 权限
  • 服务器上已经装好 Nginx,并且 80 端口能通过公网访问
  • 确认服务器安全组/防火墙放行了 80 和 443
  • 先用 SSH 登录服务器,确认能顺畅访问外网

最后一条容易被忽略。Certbot 签发和续期的过程中需要向 Let's Encrypt 的 ACME 服务器发起 HTTPS 请求,如果服务器出不了外网,或者 DNS 解析有污染,签发会直接失败。遇到这类情况先排查网络。

2. 域名解析配置:最容易翻车也最容易被忽视的前置步骤

2.1 阿里云控制台添加 A 记录的操作细节

很多人觉得域名解析是简单事,随手填个 IP 就完事。实际上 Let's Encrypt 的 HTTP-01 验证链路完全依赖"域名能正确解析到你的服务器",解析这一步错了,后面所有操作都是白费功夫。

以阿里云控制台为例:

  1. 登录阿里云域名控制台,打开对应域名的"解析设置"
  2. 点击"添加记录"
  3. 记录类型选 A,主机记录按需填@(主域名)或www(子域名),也可以填apiblog这类自定义二级域名
  4. 记录值填你服务器的公网 IP,确认没有填内网 IP
  5. TTL 默认 600 秒就行,不需要调太短

这里有一个经验:如果你打算用一张证书同时覆盖多个子域名,比如 example.com 和 www.example.com 一起用,那就需要在解析里同时添加@www两条 A 记录,指向同一台服务器。Certbot 签发时可以用多个-d参数把这些域名放到一张证书的 SAN 列表里,浏览器访问任何一个都能校验通过。

2.2 验证解析是否真正生效

添加完记录不要直接开搞,先验证一下。最常用的命令是:

dig +short example.com dig +short www.example.com

返回你的服务器公网 IP 就说明当前网络环境下的递归 DNS 已经能看到这条记录了。如果本机用的 DNS 有缓存,可能不会立刻生效,可以换个 DNS 查询:

nslookup example.com 223.5.5.5

这里223.5.5.5是阿里云的公共 DNS,也可以换成1.1.1.18.8.8.8做交叉验证。注意一个问题:dig 查到的结果只能说明"你所在网络环境"看到的记录,Let's Encrypt 的验证服务器在海外,它的 DNS 视角可能和你不一样。海外 DNS 生效通常比国内慢一些,尤其是刚添加的解析记录,建议至少等 5 到 10 分钟再签发证书。我记得有一次帮朋友签发证书,连续报 "DNS problem: NXDOMAIN",就是因为解析刚添加还没传播完,等了十分钟再跑就成功了。

2.3 换了解析服务商,Let's Encrypt 证书要重新申请吗

这是高频问题,也是这次要重点说清楚的一个场景。

核心结论:Let's Encrypt 证书绑定的是域名,不绑定任何 DNS 服务商。证书签发和续期时,Let's Encrypt 不会去检查你的域名用的是哪家 NS,它只关心两件事:一是通过 DNS 查询把域名解析到了哪个 IP,二是通过这个 IP 能否访问到对应网站目录下的验证文件。

所以,如果只是把 DNS 解析从阿里云迁到其他服务商,只要新服务商那边把 A 记录原样配好,且解析结果不变,已经签发的证书完全不需要动,续期也不受影响。真正要做的是三件事:

  1. 迁移前把 TTL 暂时调小(比如调到 300 秒),加快迁移后的解析生效速度
  2. 在新服务商处完整配置 A 记录、CNAME 记录,不要漏
  3. 迁移完成后跑一次sudo certbot renew --dry-run,验证续期链路依然通畅

如果迁移之后发现续期失败,不要先去折腾证书,第一时间查新服务商的解析记录是不是有遗漏,或者旧服务商的记录删除后某个地区的 DNS 还在返回旧 IP。

2.4 一张证书覆盖多个域名时的解析规划

我的建议是:尽量把需要 HTTPS 的域名都集中到一台服务器上,用一张 SAN 证书统一覆盖。比如 example.com、www.example.com、api.example.com 三个域名,解析全部指向同一台 Ubuntu 服务器,签发时用:

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

这样做的好处是续期时一次搞定,不用为每个域名单独维护一张证书和一套定时任务。缺点也有:如果其中一个域名解析出问题,续期可能会失败,导致整张证书无法续期。所以我通常建议基础好的用户这么做,如果你是第一次配置,还是先从单域名起步,跑顺了再扩展。

3. 签发证书:用 Certbot 的 webroot 模式拿到第一张证书

3.1 为什么不用 standalone 而用 webroot

Certbot 支持多种验证方式,最常见的三种:standalone、webroot、DNS-01。

standalone 模式需要 Certbot 自己监听 80 端口来响应验证请求,这就要求你的 Nginx 先停下来,否则端口被占用会报错。对一台正在运行的服务来说,为了签发证书停服务是不可接受的。

webroot 模式则是让 Certbot 在指定目录下生成一个临时验证文件,Nginx 依然正常运行,验证请求来了通过静态文件响应。整个过程中业务完全不中断,这是它成为最主流方式的原因。

DNS-01 模式需要去 DNS 服务商处添加一条 TXT 记录来证明域名所有权。它的好处是可以在没有 80 端口的情况下签发证书,也可以签发通配符证书(*.example.com),但操作步骤繁琐,每次续期都要动态改 DNS 记录,除非你的场景特殊,否则我建议先用 webroot。

3.2 Ubuntu 下安装 Certbot 的两种方式

Ubuntu 22.04 上最省事的安装方式是直接用 apt:

sudo apt update sudo apt install certbot python3-certbot-nginx

这里我特意安装了python3-certbot-nginx插件。很多人对这个插件有顾虑,因为它会自动修改 Nginx 配置文件。我的做法是:装上插件,但签发时用certonly模式只签发证书,不动 Nginx 配置;配置我自己手动改,这样对服务器有完全的控制权,插件的主要作用只是保证依赖齐全。

如果你用的 Ubuntu 版本较新,也可以用 snap 方式安装,snap 会自动更新 Certbot 版本,适合那些希望客户端始终处于新版的人。但我个人在服务器上倾向于 apt,因为服务器环境追求的是稳定,而不是频繁更新。

3.3 签发命令逐参数拆解

假设网站根目录是/var/www/example,我们要签一张同时包含 example.com 和 www.example.com 的证书:

sudo certbot certonly \ --webroot \ -w /var/www/example \ -d example.com \ -d www.example.com \ --email admin@example.com \ --agree-tos \ --no-eff-email

每个参数的含义:

  • certonly:只获取证书,不修改任何 Web 服务器配置文件
  • --webroot:使用 webroot 验证方式
  • -w:指定网站根目录,验证文件会被放在该目录下的.well-known/acme-challenge/
  • -d:声明要申请证书的域名,可以重复多次
  • --email:用于接收证书过期提醒和紧急通知
  • --agree-tos:同意 ACME 服务条款
  • --no-eff-email:不订阅 EFF 的推广邮件,不想天天收营销邮件就加上

第一次执行时会提示确认 IP 和条款,确认后几秒钟就会看到Successfully received certificate的提示。证书文件会写到/etc/letsencrypt/live/example.com/目录下。

如果这条命令在 DNS 解析刚生效还没稳定时执行,有可能报 DNS 相关的错误,重新执行一遍即可。

3.4 证书文件与配置文件的含义

签发成功后在/etc/letsencrypt/live/example.com/下会看到四个文件:

文件用途
cert.pem域名证书本身,不含中间证书
chain.pem中间证书链
fullchain.pemcert.pem加上chain.pem的合并文件
privkey.pem私钥,一定要保护好

Nginx 配置里ssl_certificate必须指向fullchain.pem,而不是cert.pem。这是个非常常见的坑:如果你只填了cert.pem,大多数浏览器能正常访问,但部分移动端 App、Java 程序、老版本浏览器会报证书链不完整、无法验证证书有效性。因为 Let's Encrypt 给的是叶证书,客户端需要中间证书才能把信任链追溯到根证书,fullchain.pem就是把中间证书一起打包,省去了客户端自己寻找的过程。

3.5 私钥权限与服务账号的关系

live/目录下的私钥默认权限是 600,属主是 root。Nginx 的 master 进程以 root 启动,可以读取私钥,然后再把 worker 进程降权到www-data,所以正常情况下 Nginx 使用/etc/letsencrypt/...路径没有权限问题。

但有一种情况需要注意:如果你不是用 Nginx 或 Apache,而是自己写的 Python/Node 服务直接监听 443,服务以普通用户身份启动,可能读不了 root 的私钥。解决方案有两个:一个是用setfacl给指定用户单独授权,另一个是把证书和私钥复制到应用自己的目录并设置属主。但复制出去会带来新问题:自动续期后新证书不会同步到复制目录,需要额外写 hook 脚本来处理。我的建议是能直接让服务使用/etc/letsencrypt/live/路径就尽量直接使用,省掉同步的麻烦。

4. 接入 Nginx:配置示例与全链路验证方法

4.1 server 块配置示例

假设域名是 example.com,网站根目录是/var/www/example,我在/etc/nginx/sites-available/example里写这样的配置:

server { listen 80; server_name example.com www.example.com; location ^~ /.well-known/acme-challenge/ { root /var/www/example; } location / { return 301 https://$host$request_uri; } } server { listen 443 ssl http2; server_name example.com www.example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; root /var/www/example; index index.html; location / { try_files $uri $uri/ =404; } }

有几个细节我单独说明。

第一个是location ^~ /.well-known/acme-challenge/。这个目录是 Let's Encrypt 验证请求访问的路径,必须能直接通过 HTTP 访问到,不能强制跳转到 HTTPS。因为 ACME 验证时访问的地址是http://example.com/.well-known/acme-challenge/xxx,如果这个请求被 301 跳转到 HTTPS,部分情况下仍然能通过,但为了稳妥,我习惯把它单独放行,在 80 端口的配置里明确允许这个路径不要做重定向。

第二个是ssl_protocols TLSv1.2 TLSv1.3。没必要再开 TLSv1.0 和 TLSv1.1,这两个老协议漏洞多,Let's Encrypt 也早已不支持如此老的 TLS 版本作为 ACME 通道。现在主流客户端都支持 TLS 1.2 以上,放心关掉。

第三个是 Nginx 版本的差异。Ubuntu 22.04 自带的 Nginx 1.18 用的是listen 443 ssl http2;这种写法;如果你的 Nginx 是 1.25.1 以上的新版本,推荐把 http2 拆出来写成listen 443 ssl; http2 on;。我先按最常见的老写法给示例,防止直接复制后语法报错。

写完配置后依次执行:

sudo nginx -t sudo systemctl reload nginx

nginx -t一定要先跑,它能检查出证书路径写错、配置文件语法错误等低级问题。配置检查通过后再 reload,不要直接 restart,reload 不会中断现有连接。

4.2 验证证书链是否完整

配置完成后,先用命令行验证从公网视角看证书到底正不正常:

curl -vI https://example.com 2>&1 | grep -i "subject\|issuer\|expire"

这会显示服务器返回的证书主体(subject)和签发者(issuer)。如果 issuer 是R10R11这类 Let's Encrypt 的中间证书,说明证书链是完整的。

更严格的检查方式是用 openssl 直接做一次 TLS 握手,看证书的签发情况:

echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -issuer -subject -dates

注意两个细节:一是-servername参数必须带,否则 SNI 没有指定,服务器可能返回默认证书;二是输出里看到Verify return code: 0 (ok)才是标准意义上的验证通过。

浏览器访问时地址栏出现小锁、点击证书信息能看到 Let's Encrypt 的签发机构,也说明接入成功。

4.3 HSTS 要不要开,以及什么时候开

HSTS(Strict-Transport-Security)是告诉浏览器"以后这个域名只允许用 HTTPS 访问"的响应头,配置方式是:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

我的建议是:刚接入 HTTPS 时不要立刻加这个头。因为一旦浏览器记住了 HSTS 策略,它在一段时间内会强制跳转 HTTPS,如果期间你的证书出问题(比如没续期成功、私钥丢失),用户会直接无法访问,而且浏览器上的报错没法一键跳过。稳妥的做法是先用 301 重定向跑一个月,确认自动续期稳定后再加 HSTS,并且 max-age 从一开始的 300 慢慢加长,而不是一上来就一年。

4.4 在线检测工具

命令行验证通过后,还可以用在线检测工具做第三方视角的检查。SSL Labs(ssllabs.com/ssltest.html)和国内的 myssl.com 都能检测证书链、TLS 协议、加密套件、是否支持 OCSP Stapling。其中有一个常见的检测结果需要关注:如果提示"证书链不完整",十有八九是 Nginx 配置里用了cert.pem而不是fullchain.pem;如果提示"不支持的协议"或"加密套件过弱",那就是ssl_protocolsssl_ciphers配置需要调整。

5. 自动续期:90 天有效期的正确玩法

5.1 续期机制原理

Let's Encrypt 的证书有效期是 90 天,但 Certbot 的续期逻辑不是到期前一刻才操作。它读取/etc/letsencrypt/renewal/目录下的配置文件,检查每张证书的到期时间,如果距离到期不足 30 天才会真正执行续期,否则直接跳过。也就是说,你配置好定时任务之后,每天都会运行一次certbot renew检查,但大多数时候它什么都不做,只有证书进入续期窗口期才会发起新的签发请求。

这种机制的巧妙之处在于它天然容错。假设某次续期因为临时网络问题失败了,第二天定时任务再跑还会继续尝试,只要在 30 天窗口期内成功一次就行,不需要你手动干预。

5.2 系统自带的 certbot.timer 还是 cron

Ubuntu 下通过 apt 安装 certbot 后,系统通常会自动创建两个 systemd 单元:certbot.servicecertbot.timer。timer 负责定时触发 service,默认每天执行两次,并且带有随机延迟,避免所有服务器同时向 Let's Encrypt 发起请求造成高峰。

先检查 timer 是否存在:

systemctl list-timers certbot.timer systemctl status certbot.timer

如果输出显示active (waiting),说明系统定时器已经就绪,不需要再配置任何 cron。很多人不知道这一点,还会额外加一条 cron 任务,结果出现两个续期任务同时跑的情况,虽然不会有大问题,但属于多余的复杂度。

如果你的环境里没有自动生成 timer,或者你更习惯用 cron,可以这样写:

0 3 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"

凌晨 3 点执行,避开业务高峰。--quiet让 cron 只在有输出时才发通知,--deploy-hook在续期真正发生时才 reload Nginx。两种方式选一个就行,不要混用。

5.3 deploy-hook 比 post-hook 靠谱在哪里

续期成功后,新的证书需要让 Web 服务器重新加载才会生效。Certbot 提供了几种 hook:

  • --pre-hook:续期命令执行前运行
  • --post-hook:续期命令执行后运行,无论是否真正续期都会执行
  • --renew-hook:证书实际被续期后才运行
  • --deploy-hook:和 renew-hook 类似的机制,在每个成功续期的证书对应的部署阶段执行

很多人习惯用 post-hook 来 reload Nginx,这是有问题的。因为 Certbot 在你手动执行certbot renew时也会调用 post-hook,即使所有证书都还有 60 天才到期,什么都没续,它照样会 reload 一次 Nginx。对一台承载大量连接的服务器来说,无意义的 reload 虽然影响小,但完全不必要。

正确做法是把 reload 动作挂到 deploy-hook 或 renew-hook 上。比如:

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

也可以把 hook 写进续期配置文件/etc/letsencrypt/renewal/example.com.conf中:

renew_hook = systemctl reload nginx

这样写的好处是,即使以后用 cron 或 timer 触发certbot renew时没有手动带参数,配置里的 hook 也会生效,不用每次在命令行重复声明。

5.4 dry-run 是续期排障的第一工具

配置好续期任务后,务必要跑一次模拟操作确认整个链路是通的:

sudo certbot renew --dry-run

dry-run 会连接 Let's Encrypt 的测试环境,真实执行一次签发流程的演练,但不会覆盖你现有的正式证书。它验证的是:服务器和 ACME 服务端通信是否正常、域名解析是否正确、webroot 目录是否可写、80 端口是否可达。如果 dry-run 显示成功,说明即使你将来完全不管,自动续期也能正常完成。

我见过太多人配置完证书后就把定时任务扔在那里,半年后网站突然打不开,一查是证书过期了,再一查是 cron 根本没有执行或者执行报错。所以我的习惯是:配置完当天先看一次 dry-run,之后每个月手动跑一次 dry-run 并查看/var/log/letsencrypt/letsencrypt.log的日志输出。

5.5 续期失败常见原因排查

续期失败的原因通常集中在以下几类,按出现频率排序:

  1. 域名解析被改或失效。上了新的 DNS 服务商但 A 记录没配全,或者原服务商记录删了但某个地区 DNS 缓存还在返回旧 IP,ACME 验证时找不到正确服务器,签发失败
  2. 80 端口不可达。服务器安全组、云防火墙、ufw 三层的任何一层拦截了 80 端口的入站请求,验证文件传不回去
  3. webroot 路径错误。续期配置里记录的 webroot 路径和实际网站目录不一致,或者目录被重命名/删除,验证文件生成后无法通过 URL 访问
  4. 验证文件被重定向。Nginx 的 80 端口配置把/.well-known/acme-challenge/也 301 跳转到了 HTTPS,导致验证请求走到 443,如果 443 的证书刚好又是过期的,就会形成死循环
  5. 磁盘空间不足。/var/lib/letsencrypt/etc/letsencrypt所在分区满了,新证书写不进去

排查顺序建议是:先看日志sudo tail -n 50 /var/log/letsencrypt/letsencrypt.log,日志会明确告诉你验证时访问的具体 URL 和失败原因;然后在服务器本地执行curl http://example.com/.well-known/acme-challenge/test,看是否能返回文件内容;最后再检查端口、防火墙和解析记录。日志里明确写着Invalid response from http://example.com/.well-known/acme-challenge/xxx这类信息时,基本可以确定是访问路径的问题,而不是证书本身的问题。

6. 我实际踩过的坑:迁移、根证书、巡检清单

6.1 换 IP 或迁移服务器时,证书失效的处理

这是比换 DNS 服务商更棘手的情况。前面说了换 DNS 服务商不影响证书,但如果域名解析的 A 记录从旧服务器 IP 换到了新服务器 IP,续期很可能失败。原因是:Let's Encrypt 续期时访问的是"域名当前解析到的 IP",如果你在新服务器上没有部署对应的 webroot 验证目录,验证请求到了新服务器却找不到文件,自然会失败。

我踩过一次这样的坑。当时帮客户把网站从一台旧机器迁移到新的云服务器,按照常规动作先在阿里云控制台改了 A 记录,然后设了定时续期任务,以为万事大吉。结果一个月后客户反馈网站证书过期,我查看日志才发现迁移后从未成功续期过,因为新服务器上只有网站代码和证书文件,没有保留.well-known/目录的处理逻辑。

正确的迁移顺序应该是:

  1. 在新服务器上安装好 Nginx,把旧服务器的证书目录、站点配置原样复制过来
  2. 在新服务器上的 Nginx 配置里预留location ^~ /.well-known/acme-challenge/和对应的 root 目录
  3. 改解析之前,先在新服务器上测试这几项是否就绪
  4. 修改 A 记录后,等解析稳定,立刻执行sudo certbot renew --dry-run
  5. dry-run 成功后再切换流量,或者直接改完解析后观察一段时间

所以我现在的建议是:把"webroot 目录和 acme-challenge 配置"当作服务器基础环境的一部分,和 Nginx、SSH 同等对待,迁移时第一优先级恢复,而不是最后才想起来。

6.2 ISRG Root X1 与老 JDK 的信任链问题

这套方案里有一个隐藏的兼容性问题,说来也是容易踩的深坑:老版本的 Java 程序、老系统的 HTTPS 请求,可能不信任 Let's Encrypt 的证书。

原因在于 Let's Encrypt 的信任链演化。早年间它的证书由 DST Root CA X3 交叉签名,而 DST Root CA X3 在很多老系统的根证书库里一直存在,所以兼容面很广。后来 Let's Encrypt 转向自家根证书 ISRG Root X1 直接签发,不再依赖 DST Root CA X3 的交叉签名。2024 年交叉签名的中间证书彻底下线后,如果你的运行环境内置根证书库里没有 ISRG Root X1,调用 HTTPS 接口时就会直接报PKIX path building failedSSLHandshakeException

具体到 Java 环境,Oracle JDK 8u101 及之后的版本基本内置了 ISRG Root X1,JDK 7 的部分更新版本也补充了,但更老的 JDK、某些魔改版、还有一些基于旧根证书库构建的中间件,都不在安全范围内。如果你要问我最低能支持到哪个版本,网上能查到的参考信息普遍指向 JDK 8u101 这条线,但我的建议是生产环境直接用较新的 JDK 8 小版本或 JDK 11/17,而不是卡在临界版本上赌运气。

如果你没法升级 JDK,另一个方向是把 ISRG Root X1 的根证书手动导入到 Java 的cacerts信任库,命令大致是:

sudo keytool -import -trustcacerts -alias isrgrootx1 \ -file /path/to/isrg-root-x1.pem \ -keystore $JAVA_HOME/lib/security/cacerts

但这里要提醒一句:手动导入根证书只解决 Let's Encrypt 一个证书机构的问题,以后其他机构的根证书变更你还要继续手动维护。从长期看,升级运行时才是根治方案。

6.3 到期巡检:养成每月看一眼的习惯

自动续期不是永不犯错,巡检习惯还是要有的。我给自己定了一个很轻量的巡检清单,每个月执行一次,耗时不到一分钟:

# 查看所有已签发的证书和到期时间 sudo certbot certificates # 查看定时器是否正常 systemctl status certbot.timer # 查看最近一次续期日志 sudo tail -n 20 /var/log/letsencrypt/letsencrypt.log # 在线检查证书到期时间 echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -enddate

如果证书距离到期少于 14 天,说明自动续期可能出了问题,不要再等了,立刻手动跑sudo certbot renew --force-renewal排查。如果证书距离到期超过 45 天,说明一切正常,关掉终端该干嘛干嘛。

另外一个小建议是给证书加一层外部监控。最简单的方式是使用提供"免费证书到期提醒"的服务,或者自己写一个脚本调用外部 API 检测;也可以利用 certbot 的续期 hook 在续期失败时发通知。我的习惯是配合钉钉机器人和 systemd timer 的日志,把证书状态和服务器报警统一到一个渠道里,但具体方案每个人偏好不同,这里不展开。

6.4 阿里云免费证书、Let's Encrypt、付费证书怎么选

最后给一个选型上的个人看法。如果你只是想快速给一个小站加上 HTTPS,并且不介意每年手动申请一次,阿里云那个一年期免费证书也够用。但它的缺点很明显:有效期一年意味着每年都要重复申请、下载、部署;而且只支持到单域名或有限的子域名,泛域名支持有限。

如果你愿意把"配置 HTTPS"这件事彻底自动化,我强烈推荐 Let's Encrypt。它的 90 天有效期看似频繁,实际上配合 systemd timer 和 deploy-hook 之后,你在这件事上花费的时间是零。跑通一次配置,两年内你只需要在换服务器、改解析这种大动作时回头看一眼。

付费证书适合的是对信任要求更高的场景,具体怎么选,回到这篇开头那个表对照自己的业务类型就好。对绝大多数个人开发者和中小企业来说,Let's Encrypt 是一套性价比极高、且经过大规模验证的方案。

我自己的体会是:配置 HTTPS 这件事,门槛不在命令本身,而在理解验证链路。你把"域名解析、80 端口、webroot 目录、续期 hook"这条链路理清楚了,不管换 DNS 服务商、换服务器、还是升级系统,都不会慌。如果这篇文章能帮你避免我在迁移服务器时踩过的那个证书过期坑,就算值了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询