阿里云域名+Ubuntu服务器Let‘s Encrypt免费HTTPS证书完整配置指南

发布时间:2026/9/16 3:55:24
阿里云域名+Ubuntu服务器Let‘s Encrypt免费HTTPS证书完整配置指南 1. 先拆清楚需求免费证书的适用边界与整套方案的选型逻辑1.1 Lets Encrypt 到底是什么Lets Encrypt 是 ISRGInternet Security Research Group运营的一个免费证书颁发机构它的核心特点是证书签发、续期全部自动化走的是 ACME 协议。2016 年正式上线之后个人网站、小项目、测试环境全面普及现在几乎成了免费 HTTPS的代名词。它的证书有效期固定在 90 天和阿里云那个一年期的免费 DigiCert 证书完全不同。90 天看起来很短其实是设计选择短周期证书就算私钥泄露影响面也有限同时强制倒逼证书持有人把续期这个过程自动化。所以 Lets Encrypt 从诞生起就假设你会用脚本或定时器去续期而不是像传统证书那样到期前手动换一次。在 Ubuntu 服务器上跑这套通常的形态是Certbot 作为客户端向 Lets Encrypt 申请证书签发完成后写到/etc/letsencrypt/live/目录Nginx 直接引用这个路径然后由 systemd 定时器每天检查一次证书是否临近过期该续就续续完自动 reload web server。整个过程跑通之后你基本不会再碰证书相关的事情。1.2 哪些场景适合免费证书哪些场景建议买付费我先说结论个人博客、小微企业官网、API 服务、内部系统外网入口、开发测试环境Lets Encrypt 完全够用而且是首选。我自己一台 Ubuntu 机器上挂了博客、几个 API 接口还有给移动端调用的后端服务跑了三年多没有任何问题。但有两类场景我会劝你买付费证书。第一种是银行、支付、政务类强合规业务或者对证书签发成功率有极高要求的核心生产链路这类场景需要的是 OV/EV 证书的品牌背书以及背后有专人可找的商业支持。第二种是你自己没法保证 80/443 端口稳定开放、域名解析经常变动或者服务器网络环境特殊比如某些机房对 ACME 验证请求有阻断这时候付费证书的宽容度更高省下的排查时间可能比证书本身值钱。做一个简单的对比对比项Lets Encrypt阿里云免费证书1年付费 OV 证书价格免费免费几百到几千不等有效期90 天1 年1-2 年续期方式全自动手动申请部署手动或自动签发速度秒级几分钟到几小时1 到 5 个工作日地址栏企业名不显示不显示OV/EV 显示适合场景个人站/API/测试临时项目/简易 HTTPS品牌展示/合规要求1.3 整套方案的技术链路整个方案可以拆成四层域名层、服务器层、Web 服务层、证书生命周期管理层。域名在阿里云注册DNS 解析也托管在阿里云Ubuntu 服务器上跑着 NginxCertbot 负责和 Lets Encrypt 交互systemd timer 负责定时触发续期。每一层出问题都会导致 HTTPS 不正常但每层的问题表现不一样域名解析错了证书根本没发下来服务器防火墙没放行 80验证请求进不来Nginx 配置错了证书装上去也不生效定时器没跑证书到期会突然暴雷。动手之前先把下面这几项准备好一个在阿里云注册的域名并且已经完成实名认证一台 Ubuntu 服务器20.04 或 22.04 都行有 root 权限服务器上已经装好 Nginx并且 80 端口能通过公网访问确认服务器安全组/防火墙放行了 80 和 443先用 SSH 登录服务器确认能顺畅访问外网最后一条容易被忽略。Certbot 签发和续期的过程中需要向 Lets Encrypt 的 ACME 服务器发起 HTTPS 请求如果服务器出不了外网或者 DNS 解析有污染签发会直接失败。遇到这类情况先排查网络。2. 域名解析配置最容易翻车也最容易被忽视的前置步骤2.1 阿里云控制台添加 A 记录的操作细节很多人觉得域名解析是简单事随手填个 IP 就完事。实际上 Lets Encrypt 的 HTTP-01 验证链路完全依赖域名能正确解析到你的服务器解析这一步错了后面所有操作都是白费功夫。以阿里云控制台为例登录阿里云域名控制台打开对应域名的解析设置点击添加记录记录类型选 A主机记录按需填主域名或www子域名也可以填api、blog这类自定义二级域名记录值填你服务器的公网 IP确认没有填内网 IPTTL 默认 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.1或8.8.8.8做交叉验证。注意一个问题dig 查到的结果只能说明你所在网络环境看到的记录Lets Encrypt 的验证服务器在海外它的 DNS 视角可能和你不一样。海外 DNS 生效通常比国内慢一些尤其是刚添加的解析记录建议至少等 5 到 10 分钟再签发证书。我记得有一次帮朋友签发证书连续报 DNS problem: NXDOMAIN就是因为解析刚添加还没传播完等了十分钟再跑就成功了。2.3 换了解析服务商Lets Encrypt 证书要重新申请吗这是高频问题也是这次要重点说清楚的一个场景。核心结论Lets Encrypt 证书绑定的是域名不绑定任何 DNS 服务商。证书签发和续期时Lets Encrypt 不会去检查你的域名用的是哪家 NS它只关心两件事一是通过 DNS 查询把域名解析到了哪个 IP二是通过这个 IP 能否访问到对应网站目录下的验证文件。所以如果只是把 DNS 解析从阿里云迁到其他服务商只要新服务商那边把 A 记录原样配好且解析结果不变已经签发的证书完全不需要动续期也不受影响。真正要做的是三件事迁移前把 TTL 暂时调小比如调到 300 秒加快迁移后的解析生效速度在新服务商处完整配置 A 记录、CNAME 记录不要漏迁移完成后跑一次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 而用 webrootCertbot 支持多种验证方式最常见的三种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 上最省事的安装方式是直接用 aptsudo 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 adminexample.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 程序、老版本浏览器会报证书链不完整、无法验证证书有效性。因为 Lets 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/。这个目录是 Lets 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这两个老协议漏洞多Lets 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 nginxnginx -t一定要先跑它能检查出证书路径写错、配置文件语法错误等低级问题。配置检查通过后再 reload不要直接 restartreload 不会中断现有连接。4.2 验证证书链是否完整配置完成后先用命令行验证从公网视角看证书到底正不正常curl -vI https://example.com 21 | grep -i subject\|issuer\|expire这会显示服务器返回的证书主体subject和签发者issuer。如果 issuer 是R10或R11这类 Lets 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)才是标准意义上的验证通过。浏览器访问时地址栏出现小锁、点击证书信息能看到 Lets Encrypt 的签发机构也说明接入成功。4.3 HSTS 要不要开以及什么时候开HSTSStrict-Transport-Security是告诉浏览器以后这个域名只允许用 HTTPS 访问的响应头配置方式是add_header Strict-Transport-Security max-age31536000; includeSubDomains always;我的建议是刚接入 HTTPS 时不要立刻加这个头。因为一旦浏览器记住了 HSTS 策略它在一段时间内会强制跳转 HTTPS如果期间你的证书出问题比如没续期成功、私钥丢失用户会直接无法访问而且浏览器上的报错没法一键跳过。稳妥的做法是先用 301 重定向跑一个月确认自动续期稳定后再加 HSTS并且 max-age 从一开始的 300 慢慢加长而不是一上来就一年。4.4 在线检测工具命令行验证通过后还可以用在线检测工具做第三方视角的检查。SSL Labsssllabs.com/ssltest.html和国内的 myssl.com 都能检测证书链、TLS 协议、加密套件、是否支持 OCSP Stapling。其中有一个常见的检测结果需要关注如果提示证书链不完整十有八九是 Nginx 配置里用了cert.pem而不是fullchain.pem如果提示不支持的协议或加密套件过弱那就是ssl_protocols或ssl_ciphers配置需要调整。5. 自动续期90 天有效期的正确玩法5.1 续期机制原理Lets Encrypt 的证书有效期是 90 天但 Certbot 的续期逻辑不是到期前一刻才操作。它读取/etc/letsencrypt/renewal/目录下的配置文件检查每张证书的到期时间如果距离到期不足 30 天才会真正执行续期否则直接跳过。也就是说你配置好定时任务之后每天都会运行一次certbot renew检查但大多数时候它什么都不做只有证书进入续期窗口期才会发起新的签发请求。这种机制的巧妙之处在于它天然容错。假设某次续期因为临时网络问题失败了第二天定时任务再跑还会继续尝试只要在 30 天窗口期内成功一次就行不需要你手动干预。5.2 系统自带的 certbot.timer 还是 cronUbuntu 下通过 apt 安装 certbot 后系统通常会自动创建两个 systemd 单元certbot.service和certbot.timer。timer 负责定时触发 service默认每天执行两次并且带有随机延迟避免所有服务器同时向 Lets 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-rundry-run 会连接 Lets Encrypt 的测试环境真实执行一次签发流程的演练但不会覆盖你现有的正式证书。它验证的是服务器和 ACME 服务端通信是否正常、域名解析是否正确、webroot 目录是否可写、80 端口是否可达。如果 dry-run 显示成功说明即使你将来完全不管自动续期也能正常完成。我见过太多人配置完证书后就把定时任务扔在那里半年后网站突然打不开一查是证书过期了再一查是 cron 根本没有执行或者执行报错。所以我的习惯是配置完当天先看一次 dry-run之后每个月手动跑一次 dry-run 并查看/var/log/letsencrypt/letsencrypt.log的日志输出。5.5 续期失败常见原因排查续期失败的原因通常集中在以下几类按出现频率排序域名解析被改或失效。上了新的 DNS 服务商但 A 记录没配全或者原服务商记录删了但某个地区 DNS 缓存还在返回旧 IPACME 验证时找不到正确服务器签发失败80 端口不可达。服务器安全组、云防火墙、ufw 三层的任何一层拦截了 80 端口的入站请求验证文件传不回去webroot 路径错误。续期配置里记录的 webroot 路径和实际网站目录不一致或者目录被重命名/删除验证文件生成后无法通过 URL 访问验证文件被重定向。Nginx 的 80 端口配置把/.well-known/acme-challenge/也 301 跳转到了 HTTPS导致验证请求走到 443如果 443 的证书刚好又是过期的就会形成死循环磁盘空间不足。/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续期很可能失败。原因是Lets Encrypt 续期时访问的是域名当前解析到的 IP如果你在新服务器上没有部署对应的 webroot 验证目录验证请求到了新服务器却找不到文件自然会失败。我踩过一次这样的坑。当时帮客户把网站从一台旧机器迁移到新的云服务器按照常规动作先在阿里云控制台改了 A 记录然后设了定时续期任务以为万事大吉。结果一个月后客户反馈网站证书过期我查看日志才发现迁移后从未成功续期过因为新服务器上只有网站代码和证书文件没有保留.well-known/目录的处理逻辑。正确的迁移顺序应该是在新服务器上安装好 Nginx把旧服务器的证书目录、站点配置原样复制过来在新服务器上的 Nginx 配置里预留location ^~ /.well-known/acme-challenge/和对应的 root 目录改解析之前先在新服务器上测试这几项是否就绪修改 A 记录后等解析稳定立刻执行sudo certbot renew --dry-rundry-run 成功后再切换流量或者直接改完解析后观察一段时间所以我现在的建议是把webroot 目录和 acme-challenge 配置当作服务器基础环境的一部分和 Nginx、SSH 同等对待迁移时第一优先级恢复而不是最后才想起来。6.2 ISRG Root X1 与老 JDK 的信任链问题这套方案里有一个隐藏的兼容性问题说来也是容易踩的深坑老版本的 Java 程序、老系统的 HTTPS 请求可能不信任 Lets Encrypt 的证书。原因在于 Lets Encrypt 的信任链演化。早年间它的证书由 DST Root CA X3 交叉签名而 DST Root CA X3 在很多老系统的根证书库里一直存在所以兼容面很广。后来 Lets Encrypt 转向自家根证书 ISRG Root X1 直接签发不再依赖 DST Root CA X3 的交叉签名。2024 年交叉签名的中间证书彻底下线后如果你的运行环境内置根证书库里没有 ISRG Root X1调用 HTTPS 接口时就会直接报PKIX path building failed或SSLHandshakeException。具体到 Java 环境Oracle JDK 8u101 及之后的版本基本内置了 ISRG Root X1JDK 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但这里要提醒一句手动导入根证书只解决 Lets 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 阿里云免费证书、Lets Encrypt、付费证书怎么选最后给一个选型上的个人看法。如果你只是想快速给一个小站加上 HTTPS并且不介意每年手动申请一次阿里云那个一年期免费证书也够用。但它的缺点很明显有效期一年意味着每年都要重复申请、下载、部署而且只支持到单域名或有限的子域名泛域名支持有限。如果你愿意把配置 HTTPS这件事彻底自动化我强烈推荐 Lets Encrypt。它的 90 天有效期看似频繁实际上配合 systemd timer 和 deploy-hook 之后你在这件事上花费的时间是零。跑通一次配置两年内你只需要在换服务器、改解析这种大动作时回头看一眼。付费证书适合的是对信任要求更高的场景具体怎么选回到这篇开头那个表对照自己的业务类型就好。对绝大多数个人开发者和中小企业来说Lets Encrypt 是一套性价比极高、且经过大规模验证的方案。我自己的体会是配置 HTTPS 这件事门槛不在命令本身而在理解验证链路。你把域名解析、80 端口、webroot 目录、续期 hook这条链路理清楚了不管换 DNS 服务商、换服务器、还是升级系统都不会慌。如果这篇文章能帮你避免我在迁移服务器时踩过的那个证书过期坑就算值了。