使用Let‘s Encrypt与Certbot为Nginx网站免费配置HTTPS及自动续期

📅 2026/7/6 13:22:50 👁️ 阅读次数 📝 编程学习
使用Let‘s Encrypt与Certbot为Nginx网站免费配置HTTPS及自动续期

1. 项目概述:为什么你的网站必须上HTTPS?

最近在帮几个朋友部署个人博客和项目站点时,我发现一个挺普遍的现象:很多开发者,尤其是刚入行的朋友,对本地开发、后端逻辑、前端框架玩得很溜,但一到要把项目部署上线,面对“HTTPS”、“SSL证书”这些词就有点发怵,总觉得是运维的活儿,或者觉得申请证书很麻烦、很贵。结果就是,一个功能完善的项目,最后用一个“不安全”的HTTP协议裸奔在公网上。这就像你花大价钱装修了一套智能家居,结果大门用的还是老旧的挂锁,安全风险和心理上的不踏实感是实实在在的。

其实,给网站部署HTTPS,在今天已经不是什么高深技术或奢侈配置了。它更像是一种“基础设施”,是互联网应用的标配。从技术上讲,HTTPS就是在HTTP协议的基础上,加了一层SSL/TLS加密层。这个加密层主要干三件事:加密传输(防止数据在传输过程中被窃听)、身份验证(通过证书确认你访问的就是“真正的”那个网站,而不是钓鱼网站)、数据完整性保护(确保数据在传输过程中没有被篡改)。对于用户来说,最直观的感受就是浏览器地址栏里那个小锁图标,以及“https://”开头的网址。

那为什么非得用Let‘s Encrypt呢?简单说,因为它把这三件事里的“身份验证”环节,从一件昂贵、繁琐的行政流程,变成了一项免费、自动化的公共服务。在它出现之前,商业证书动辄每年几百上千元,申请流程还需要提交各种企业资质文件,对于个人开发者、小团队或者开源项目来说,是个不小的门槛。Let‘s Encrypt的出现,彻底改变了这个局面。它通过一套名为ACME的自动化协议,让你用几条命令就能完成域名验证、证书申请、安装和续期的全过程。现在,它已经为全球超过7亿个网站提供证书,成为了互联网基础安全设施中不可或缺的一环。

所以,无论你是要部署一个展示个人作品的技术博客,还是一个有用户登录、支付功能的小型应用,配置HTTPS都是上线前必须完成的关键一步。接下来,我就以一个典型的Nginx + Ubuntu Server环境为例,带你从头到尾走一遍用Let‘s Encrypt的Certbot工具,为你的域名配置HTTPS并设置自动续期的完整流程。我会把每个步骤背后的原理、可能遇到的坑以及我的实操心得都讲清楚,让你不仅能“照着做”,更能“懂得为什么这么做”。

2. 核心原理与工具选型:ACME协议与Certbot

在动手敲命令之前,我们有必要花几分钟了解一下背后的核心机制。这能帮助你在出问题时,知道该从哪里排查,而不是盲目地重试。

2.1 ACME协议:自动化证书管理的基石

Let‘s Encrypt实现免费和自动化的核心,是一个叫做ACME的协议。ACME全称是Automated Certificate Management Environment,你可以把它理解为一套标准化的“机器人流程”。它定义了证书颁发机构(CA,也就是Let‘s Encrypt)和你的服务器(ACME客户端)之间如何进行自动化的通信,以完成域名所有权验证、证书申请、签发和续期。

整个过程的核心挑战在于:如何向CA证明“你确实拥有这个域名”?ACME协议主要提供了两种验证方式:

  1. HTTP-01挑战:这是最常用、最直接的方式。CA服务器会给你一个随机的令牌(token)和一个对应的密钥指纹。你的ACME客户端需要在你的Web服务器上,创建一个特定的URL(例如http://你的域名/.well-known/acme-challenge/<token>),并将密钥指纹作为这个URL的访问内容。随后,Let‘s Encrypt的服务器会尝试通过HTTP访问这个URL。如果能成功获取到正确的密钥指纹,就证明你对该域名的Web服务有控制权,从而通过验证。
  2. DNS-01挑战:这种方式不依赖Web服务器。CA会给你一个特定的值,你需要在你域名的DNS解析商那里,为域名添加一条特定的TXT记录。Let‘s Encrypt的服务器会查询这条DNS记录,如果匹配,则通过验证。这种方式特别适合那些没有运行Web服务器(比如邮件服务器),或者Web服务器不方便临时配置的情况。

我们本次实操将主要使用HTTP-01挑战,因为它对大多数Web场景最友好,Certbot也能自动帮我们完成在Nginx上的临时配置。

2.2 为什么选择Certbot?

ACME协议是标准,而Certbot则是这个协议最流行、最成熟的客户端实现之一,由EFF(电子前哨基金会)维护。它就像一个全自动的证书管理机器人,优点非常明显:

  • 高度自动化:对于Nginx/Apache等主流Web服务器,Certbot可以自动检测配置、修改配置、安装证书、重载服务,几乎一键完成。
  • 生态友好:与Let‘s Encrypt服务端兼容性最好,文档也最全。
  • 续期无忧:内置的定时任务可以自动检查证书有效期(Let‘s Encrypt证书只有90天),并在到期前自动续期,彻底解放双手。

当然,除了Certbot,也有其他优秀的ACME客户端,比如:

  • acme.sh:一个纯Shell脚本编写的客户端,非常轻量,依赖极少,适合嵌入式设备或追求最小化安装的环境。
  • Caddy:一个现代化的Web服务器,其最大特色就是内置了ACME客户端,配置HTTPS只需一行代码。

对于绝大多数使用Nginx或Apache的Linux服务器环境,Certbot仍然是首选,它的自动化程度最高,社区支持也最广。

2.3 环境准备清单

在开始之前,请确保你已经准备好以下条件,这能避免很多后续的麻烦:

  1. 一台拥有公网IP的服务器:云服务器(如阿里云ECS、腾讯云CVM)或自有服务器均可。系统以Ubuntu 20.04/22.04 LTS或CentOS 7/8为例,本文命令以Ubuntu为准,CentOS会有少量差异(主要是包管理器yum和systemctl服务名)。
  2. 一个已解析的域名:你需要拥有一个域名(例如example.com),并且已经将该域名的A记录解析到你服务器的公网IP地址。重要:解析生效需要时间(TTL),通常几分钟到几小时不等,请务必提前操作并确认ping yourdomain.com能返回你的服务器IP。
  3. 服务器权限:你需要以root用户或具有sudo权限的用户登录服务器。
  4. 开放的80和443端口:Let‘s Encrypt的HTTP-01挑战需要通过80端口访问你的服务器。确保服务器的防火墙(如ufwiptables)和安全组(云服务器控制台设置)已经放行了**80(HTTP)443(HTTPS)**端口。
    # 以Ubuntu的ufw为例,检查并开放端口 sudo ufw status sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw reload
  5. 正在运行的Web服务器:我们以Nginx为例。你需要先安装并启动Nginx,确保通过HTTP能正常访问到你的网站(哪怕只是一个默认的欢迎页面)。这是因为Certbot在验证时需要能访问到你服务器上的特定临时文件。

实操心得:很多新手卡在第一步,就是因为域名解析没生效或者防火墙端口没开。一个简单的测试方法是:在本地电脑,用浏览器直接访问http://你的服务器公网IP,看看能否看到Nginx的默认页面;再访问http://你的域名,看是否显示同样的内容。如果IP通但域名不通,就是DNS问题;如果都不通,就是服务器Web服务或防火墙问题。

3. 逐步实操:从安装到配置自动化续期

假设你的域名是myawesome.site,服务器是全新的Ubuntu 22.04,已经完成了基础的系统更新。

3.1 步骤一:安装Nginx与Certbot

首先,我们安装Web服务器和证书管理工具。

# 更新软件包列表 sudo apt update # 安装Nginx sudo apt install nginx -y # 启动Nginx并设置开机自启 sudo systemctl start nginx sudo systemctl enable nginx # 安装Certbot及其Nginx插件 # snap是Ubuntu推荐的软件包管理方式,Certbot官方也推荐通过snap安装以获得最新版本和自动更新 sudo snap install --classic certbot # 创建软链接,方便直接使用certbot命令 sudo ln -s /snap/bin/certbot /usr/bin/certbot

安装完成后,可以先访问你的服务器IP或域名,应该能看到Nginx的欢迎页面,确认Web服务运行正常。

3.2 步骤二:使用Certbot获取并自动配置证书

这是最核心的一步。Certbot提供了--nginx参数,它能自动读取你Nginx中现有的虚拟主机(server block)配置,并交互式地帮你完成所有工作。

sudo certbot --nginx

运行这个命令后,你会进入一个交互式命令行界面:

  1. 输入邮箱:首先会提示你输入一个邮箱地址。这个邮箱用于接收证书到期前的续期提醒,以及Let‘s Encrypt的重要通知(如服务条款更新)。务必使用一个你能长期访问的有效邮箱
  2. 同意服务条款:输入A或直接回车同意。
  3. 订阅邮件(可选):询问是否愿意接收EFF的新闻邮件,根据个人意愿选择YN
  4. 选择域名:Certbot会自动扫描Nginx配置中发现的域名。它会列出所有找到的域名(比如myawesome.sitewww.myawesome.site),让你用空格键选择要为哪些域名申请证书。通常建议同时选中裸域名和www子域名。
  5. 自动配置:选择完毕后,Certbot会开始执行:
    • 联系Let‘s Encrypt的服务器,发起证书申请。
    • 自动为你的域名配置HTTP-01挑战(临时修改Nginx配置,在.well-known/acme-challenge/路径下提供验证文件)。
    • Let‘s Encrypt服务器访问该验证文件,确认域名控制权。
    • 验证通过后,下载生成的SSL证书和私钥,通常存放在/etc/letsencrypt/live/你的域名/目录下。
    • 自动修改你的Nginx配置文件,添加SSL相关的配置,并将HTTP(80端口)的请求重定向到HTTPS(443端口)。

整个过程如果顺利,最后你会看到类似这样的成功信息:

Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/myawesome.site/fullchain.pem /etc/letsencrypt/live/myawesome.site/privkey.pem Your certificate will expire on 2025-08-01. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew"

关键文件说明

  • fullchain.pem:这是你的证书链,包含你的站点证书和中间CA证书,Nginx配置中ssl_certificate指令指向它。
  • privkey.pem:这是你的私钥,必须严格保密,Nginx配置中ssl_certificate_key指令指向它。
  • cert.pemchain.pem:分别是你的站点证书和中间CA证书,通常直接使用fullchain.pem更省事。

此时,你的Nginx配置文件(通常是/etc/nginx/sites-available/default)已经被Certbot修改。它主要做了两件事:

  1. 在原有的80端口server块中,添加了return 301 https://$host$request_uri;这行,实现HTTP到HTTPS的强制跳转。
  2. 新增了一个监听443端口的server块,里面配置了ssl_certificatessl_certificate_key指向刚才生成的证书文件,并开启了SSL协议。

现在,你可以立即打开浏览器,访问https://myawesome.site,应该能看到小锁标志和“连接是安全的”提示。

3.3 步骤三:验证证书与自动续期配置

证书装好了,但事情还没完。Let‘s Encrypt的证书有效期只有90天,这是为了安全最佳实践(缩短密钥泄露后的影响时间)。手动续期是不可接受的,我们必须配置自动化。

幸运的是,Certbot在安装时已经为我们创建了一个系统定时任务(cron job或systemd timer)。你可以通过以下命令查看续期任务的状态:

# 查看Certbot的定时服务状态(systemd系统) sudo systemctl status certbot.timer # 或者列出系统的定时任务,查看是否有certbot renew sudo crontab -l | grep certbot

通常,这个定时任务会每天随机运行两次,但只有在证书到期前30天内,执行certbot renew命令时才会真正进行续期操作。你可以手动模拟续期测试,确保流程畅通:

# 使用 --dry-run 参数进行测试续期,不会真的申请新证书 sudo certbot renew --dry-run

如果看到 “The dry run was successful.” 的提示,说明你的自动续期配置完全正确,未来可以高枕无忧。

注意事项:自动续期成功的一个关键前提是,你的Web服务器在续期时,80或443端口必须能被Let‘s Encrypt的服务器访问到,以完成挑战验证。如果你的服务器防火墙策略后续有变更,一定要确保这一点。另外,续期操作会重新验证域名所有权,如果域名解析失效,续期也会失败。

3.4 步骤四:优化SSL/TLS配置(进阶)

Certbot提供的默认配置是安全的,但我们可以进一步优化,提升安全性和性能。编辑你的Nginx的SSL server块(通常在/etc/nginx/sites-available/default或独立的SSL配置文件中)。

找到类似下面的配置部分,我们可以进行增强:

server { listen 443 ssl http2; # 启用HTTP/2,提升性能 server_name myawesome.site www.myawesome.site; ssl_certificate /etc/letsencrypt/live/myawesome.site/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/myawesome.site/privkey.pem; # 以下是可选的优化配置 # 1. 启用更安全的SSL协议,禁用不安全的旧协议 ssl_protocols TLSv1.2 TLSv1.3; # 2. 配置优先使用的加密套件,提供前向安全性 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; # 3. 启用SSL会话缓存,减少TLS握手开销 ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # 4. 启用OCSP Stapling,提高TLS握手速度并增强隐私 ssl_stapling on; ssl_stapling_verify on; # 需要配置一个可用的DNS解析器,通常在nginx.conf的http块中已有 # resolver 8.8.8.8 8.8.4.4 valid=300s; # ... 你的其他配置(如root, index, location等) }

修改配置后,务必测试Nginx配置语法并重载服务:

sudo nginx -t # 测试配置,看到 `syntax is ok` 和 `test is successful` sudo systemctl reload nginx # 平滑重载配置,不影响在线服务

4. 常见问题与排查技巧实录

即使流程再自动化,在实际操作中还是会遇到各种“坑”。下面是我总结的几个最常见的问题及解决方法。

4.1 问题一:Certbot执行时报错 “Failed to connect to host for DVSNI challenge”

错误分析:这通常意味着Let‘s Encrypt的服务器无法通过HTTP(80端口)访问到你的服务器来完成域名验证。排查步骤

  1. 检查域名解析:在服务器上或使用dignslookup命令,确认你的域名是否正确解析到了服务器公网IP。ping yourdomain.com看IP是否正确。
  2. 检查防火墙:确保服务器本机的防火墙(如ufw)和云服务商的安全组规则都允许来自任意IP(0.0.0.0/0)的80端口入站流量。
    sudo ufw status verbose
  3. 检查Nginx是否运行并监听80端口
    sudo systemctl status nginx sudo netstat -tulpn | grep :80
    如果Nginx没运行,启动它。如果80端口被其他程序占用,需要解决冲突。
  4. 检查服务器是否在NAT或代理之后:如果你的服务器在一个内网,通过路由器端口映射或云负载均衡器对外提供服务,你需要确保80端口的映射是正确的,并且流量能到达运行Certbot的这台机器。

4.2 问题二:访问HTTPS网站显示“不安全”或证书错误

错误分析:浏览器提示不安全,可能的原因有几种。排查步骤

  1. 证书域名不匹配:确保证书是为当前访问的域名申请的。比如你为www.example.com申请了证书,但直接访问example.com就会报错。解决方法是在申请证书时同时选中两个域名,或者在Nginx配置中将裸域名重定向到www子域名(或反之)。
  2. 证书链不完整:极少数情况下,某些旧设备或中间代理可能无法自动获取中间证书。确保Nginx配置中ssl_certificate指向的是fullchain.pem(包含链),而不是cert.pem
  3. 系统时间不同步:HTTPS证书具有严格的有效期。如果服务器或客户端的时间偏差太大(比如超过几天),会被视为证书无效。使用date命令检查服务器时间,并用sudo timedatectl set-ntp true启用NTP时间同步。

4.3 问题三:自动续期(renew)失败

错误分析:这是最需要关注的问题,因为会导致证书过期,网站无法访问。排查步骤

  1. 手动测试续期:运行sudo certbot renew --dry-run查看具体报错信息。错误信息通常会明确指出原因,如验证失败、权限不足等。
  2. 检查验证路径可访问性:续期同样需要完成HTTP-01或DNS-01挑战。确保在续期时,.well-known/acme-challenge/这个临时目录能被外界通过HTTP访问到。有时因为网站配置了重写规则(如WordPress的固定链接),可能会意外拦截对这个路径的访问。你可以在续期测试期间,手动构造一个URL测试一下。
  3. 检查Certbot的定时任务:确认certbot renew命令被正确添加到cron或systemd timer中,并且有执行权限。可以查看日志:
    sudo journalctl -u certbot.service # 查看certbot服务日志 sudo grep certbot /var/log/syslog # 在syslog中搜索相关记录
  4. 证书文件权限问题/etc/letsencrypt/目录和其中的文件权限非常关键。不要随意修改其所有权或权限。如果因为误操作导致续期时无法读取私钥或写入新证书,也会失败。标准的权限应由root:root拥有。

4.4 问题四:Nginx配置SSL后重启报错

错误分析:修改Nginx配置后,执行nginx -t测试失败或systemctl reload nginx失败。排查步骤

  1. 仔细阅读错误信息:Nginx的错误提示通常很明确,会指出哪一行、哪个指令有问题。常见错误包括:语法错误(少分号、括号)、文件路径错误(证书或私钥文件不存在)、端口冲突等。
  2. 检查文件路径:确认ssl_certificatessl_certificate_key指令指向的.pem文件路径完全正确,且Nginx进程用户(通常是www-datanginx)有读取权限。
    sudo ls -la /etc/letsencrypt/live/yourdomain/ sudo nginx -T | grep ssl_certificate # 查看实际加载的配置
  3. 检查监听端口:确认没有其他程序占用了443端口。sudo netstat -tulpn | grep :443

4.5 多域名与通配符证书申请

如果你的一个站点有多个域名(例如主站、博客、API子域名),或者你想使用通配符证书(*.example.com),Certbot也能处理。

  • 多域名证书:在运行sudo certbot --nginx时,在选择域名的步骤,用空格键选中所有需要的域名即可。Certbot会生成一张包含所有选中域名的SAN(主题备用名称)证书。
  • 通配符证书:通配符证书(*.example.com)可以保护该域名下的所有子域名。重要:通配符证书必须使用DNS-01挑战方式,因为HTTP-01挑战无法证明你对所有子域名的控制权。申请命令类似:
    sudo certbot certonly --manual --preferred-challenges dns -d *.example.com -d example.com
    执行后,Certbot会提示你在DNS管理面板为_acme-challenge.example.com添加一条特定的TXT记录。添加并等待DNS生效(可能需要几分钟到几小时)后,回车继续。这种方式无法全自动,因为Certbot无法自动操作你的DNS提供商。但有些DNS提供商(如Cloudflare, AWS Route53)有API,可以通过Certbot的插件实现自动化,这需要额外配置。

5. 配置备份与监控告警

一切配置妥当后,还有两件重要的事:备份和监控。

配置备份:将/etc/letsencrypt/目录和你的Nginx站点配置文件定期备份,是良好的运维习惯。如果服务器需要迁移,这些文件是关键。

证书过期监控:虽然Certbot会自动续期,但总有意外(比如服务器宕机、网络故障、配置错误)。建议设置一个简单的监控,在证书到期前(比如14天)提醒你。有很多开源工具(如certbot本身有--renew-hook可以触发告警脚本),或者使用第三方监控服务(如UptimeRobot, Prometheus with blackbox_exporter)来定期检查你网站的证书有效期。

一个简单的Shell脚本检查示例,可以放入cron每周运行:

#!/bin/bash DOMAIN="myawesome.site" EXPIRY_DATE=$(echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2) EXPIRY_SECONDS=$(date -d "$EXPIRY_DATE" +%s) CURRENT_SECONDS=$(date +%s) DAYS_LEFT=$(( (EXPIRY_SECONDS - CURRENT_SECONDS) / 86400 )) if [ $DAYS_LEFT -lt 14 ]; then echo "警告: $DOMAIN 的SSL证书将在 $DAYS_LEFT 天后过期!" | mail -s "证书过期警告" your-email@example.com fi

最后,我想说的是,给网站部署HTTPS在今天已经是一项基本技能。通过Let‘s Encrypt和Certbot,这个过程变得极其简单且免费。花上半小时,按照上面的步骤操作一遍,你就能为你的网站筑起一道基础的安全防线,同时也能给用户更专业的印象。更重要的是,你理解了背后的ACME协议、证书验证原理和自动化续期机制,以后再遇到相关问题,你就能从容应对,而不是只能搜索“证书过期了怎么办”。