1. 项目概述为什么我们需要为网站获取HTTPS证书在今天的互联网上一个没有HTTPS的网站几乎等同于“不安全”的代名词。无论是浏览器地址栏里刺眼的“不安全”标识还是用户提交表单时对数据泄露的担忧都让HTTPS从一项“加分项”变成了“必需品”。你可能听说过Let‘s Encrypt这个提供免费SSL/TLS证书的公益机构它彻底改变了HTTPS的普及门槛。而“Get HTTPS for free”这个项目正是围绕Let’s Encrypt的ACME协议实现自动化证书申请、验证和续期的核心实践。简单来说这个过程就是让你的服务器向证书颁发机构CA这里是Let‘s Encrypt证明“嘿我确实拥有这个域名比如example.com的控制权。” 一旦证明成功CA就会签发一张属于你这个域名的证书。服务器安装这张证书后就能与用户的浏览器建立加密的HTTPS连接。整个证明“你拥有这个域名”的过程就叫做“域名验证”Domain Validation。而ACME协议主要定义了三种验证方式HTTP-01、DNS-01和TLS-ALPN-01通常被归为文件验证的一种高级形式但今天我们聚焦前两种和基础的HTTP文件验证。为什么需要了解这三种方式因为不同的服务器环境、网络架构和运维需求决定了哪种方式最适合你。用错了方法可能会让自动化流程卡壳甚至因为验证失败导致服务中断。接下来我们就深入拆解这三种验证方式的原理、适用场景和实操中的那些“坑”。2. 核心验证方式原理与场景对比在自动化证书管理过程中验证方式是核心枢纽。ACME协议的设计初衷是自动化因此验证过程也必须无需人工干预。三种验证方式本质上是提供了三条不同的“通道”让CA能够通过互联网访问到你指定的资源从而确认你对域名的控制权。2.1 HTTP-01 验证最直接的文件挑战原理拆解HTTP-01验证的原理非常直观。当你的客户端如Certbot向Let‘s Encrypt申请证书时CA会提供一个唯一的、随机的“令牌”token和一个对应的“密钥授权”key authorization。你的客户端需要在你所申请证书的域名例如www.example.com的Web服务器根目录下创建一个特定的文件。这个文件的访问路径是http://www.example.com/.well-known/acme-challenge/token文件的内容就是那个“密钥授权”字符串。随后CA的验证服务器会尝试通过HTTP注意是HTTP不是HTTPS协议访问这个URL。如果能成功访问到并且返回的内容完全匹配客户端预先计算好的“密钥授权”值那么验证就通过了。CA会认为“既然你能在这个域名对应的Web服务器上放置一个我能读取的特定文件那你肯定拥有这个域名的控制权至少是Web服务器的控制权。”适用场景与优缺点优点原理简单配置直观。对于大多数拥有标准Web服务器如Nginx, Apache的站点来说这是最快捷的方式。很多自动化工具如Certbot的Webroot插件默认或首选这种方式。缺点必须开放80端口CA的验证服务器只通过HTTP80端口访问。如果你的服务器防火墙屏蔽了80端口或者80端口被其他服务占用验证就会失败。依赖Web服务你的域名必须解析到一台正在运行且可公开访问的Web服务器。如果你只是在搭建一个API服务器、游戏服务器或其他非Web服务可能没有现成的Web服务来响应这个挑战。多服务器负载均衡场景复杂如果你的网站由多台Web服务器通过负载均衡器对外服务你需要确保这个特定的挑战文件能被同步到所有后端服务器或者通过负载均衡器策略确保CA的请求总能被路由到存放了该文件的服务器上。这增加了运维复杂度。内网或开发环境对于无法从公网直接访问的内网服务器或本地开发环境HTTP验证无法进行。注意很多人在配置Nginx或Apache时会忽略对.well-known目录的访问权限配置。如果该目录被禁止访问例如通过location ~ /\.规则拒绝了所有以点开头的隐藏目录验证必定失败。你需要显式地为这个路径配置允许访问的规则。2.2 DNS-01 验证最灵活的记录挑战原理拆解DNS-01验证将证明的场所从Web服务器转移到了DNS服务器。同样CA会提供一个“令牌”和“密钥授权”。但这次你的客户端需要计算这个“密钥授权”的SHA-256哈希值一个Base64 URL编码的字符串然后将这个哈希值作为一条特定的TXT记录添加到你的域名的DNS配置中。这条TXT记录的名称主机记录是_acme-challenge.你的域名。例如对于example.com记录名就是_acme-challenge.example.com。记录值就是那个计算出的哈希值。CA的验证服务器会查询DNS系统获取这条TXT记录的值。如果查询到的值与预期哈希值匹配验证即告成功。CA的逻辑是“既然你能在域名的权威DNS服务器上设置一条特定的TXT记录那你肯定拥有这个域名的DNS解析控制权。”适用场景与优缺点优点不依赖特定服务不需要Web服务器、邮件服务器或任何其他特定服务在运行。只要域名能正常解析验证就能进行。这对于非Web服务、负载均衡器VIP、邮件服务器MX记录指向的IP等场景是唯一选择。可签发通配符证书这是DNS-01验证独有的巨大优势。只有通过DNS验证Let‘s Encrypt才会为你签发通配符证书如*.example.com用于保护该域名下的所有子域名。适合复杂架构在多数据中心、混合云、CDN等复杂架构中管理DNS记录通常比同步Web服务器文件更简单、更中心化。内网环境友好即使服务器在内网只要其域名在公网DNS有解析哪怕解析到内网IP或通过NAT就可以完成验证。缺点需要API权限自动化流程要求你的客户端能通过脚本调用DNS服务商的API来动态添加和删除这条TXT记录。这意味着你需要从DNS服务商如Cloudflare,阿里云DNS, DNSPod等获取API密钥或Token并妥善保管。DNS传播延迟新增或修改DNS记录后全球DNS缓存刷新需要时间TTL。虽然Let‘s Encrypt的验证服务器会重试并等待但如果你的DNS服务商生效慢或者你设置的TTL过长可能导致验证超时失败。安全风险将DNS服务商的API密钥存放在申请证书的服务器上增加了密钥泄露的风险。一旦泄露攻击者可能篡改你的所有DNS记录。实操心得DNS API密钥管理绝对不要将API密钥硬编码在脚本或配置文件中。对于Certbot可以使用环境变量传递或者利用其--config-dir和--work-dir指定安全目录。更好的做法是使用支持“角色”或“细粒度权限”的DNS服务商如Cloudflare的API Token创建一个仅具有“编辑域名的TXT记录”权限的Token将风险降到最低。2.3 TLS-ALPN-01 验证基于端口443的挑战原理拆解TLS-ALPN-01是一种更“底层”的验证方式它发生在TLS握手阶段。当CA验证服务器连接到你的服务器的443端口HTTPS时会在TLS握手的“应用层协议协商”ALPN扩展中发送一个特殊的协议IDacme-tls/1。你的服务器需要配置为能识别这个协议ID并在握手过程中返回一个特定的“密钥授权”证书一个自签名的临时证书而不是通常的网站证书。这个临时证书的主题备用名称SAN包含一个特殊的域名其内容编码了验证信息。CA验证服务器通过解析这个临时证书来完成验证。由于整个过程发生在标准的TLS 443端口它不需要单独的HTTP服务也不依赖DNS记录。适用场景与优缺点优点仅需443端口对于只开放了443端口HTTPS的服务器非常友好无需额外开放80端口。验证效率高验证过程在TLS层完成通常比HTTP请求更快。缺点实现复杂需要在TLS握手层面进行拦截和响应对服务器软件如Nginx, Apache的版本和模块有要求。Certbot通过--preferred-challenges tls-alpn-01参数和对应的插件如certbot-nginx来支持但配置不如HTTP方式普遍。适用场景窄主要用于本身就在443端口提供TLS服务的场景。如果服务器没有配置任何TLS服务此方法无效。不支持通配符证书和HTTP-01一样TLS-ALPN-01也不能用于申请通配符证书。由于TLS-ALPN-01在实际中使用频率远低于HTTP和DNS方式且通常被Certbot等工具在后台自动选择用于续期当80端口不可用时我们接下来的实操将重点放在HTTP和DNS验证上。3. 实战演练使用Certbot配置两种主流验证方式理论讲完了我们上手操作。这里以最流行的ACME客户端Certbot为例演示在Ubuntu 22.04 Nginx环境下如何分别使用HTTP和DNS验证方式获取证书。3.1 环境准备与Certbot安装首先确保你的服务器系统是最新的并且已经安装了Nginx或其他Web服务器这里以Nginx为例。# 更新系统包列表 sudo apt update sudo apt upgrade -y # 安装Nginx (如果尚未安装) sudo apt install nginx -y # 安装Certbot和Nginx插件 sudo apt install certbot python3-certbot-nginx -y安装python3-certbot-nginx插件至关重要它允许Certbot自动读取和修改Nginx的配置文件来完成HTTP验证和证书安装。3.2 方式一HTTP-01验证实战单域名假设你的域名是blog.yourdomain.com并且已经解析到了这台服务器的公网IP。步骤1使用Certbot的Nginx插件自动获取并配置这是最简单的方式Certbot会自动处理所有事情修改Nginx配置以响应挑战获取证书并重写配置以启用HTTPS。sudo certbot --nginx -d blog.yourdomain.com执行这个命令后Certbot会交互式地询问你的邮箱用于接收续期提醒和紧急通知。询问你是否同意服务条款。询问你是否愿意分享你的邮箱以接收EFF的新闻可选。自动在Nginx配置中为blog.yourdomain.com添加一个临时的location块用于服务.well-known/acme-challenge/路径下的挑战文件。与Let‘s Encrypt通信触发验证。验证通过后下载证书和密钥。自动修改你的Nginx站点配置文件将HTTP重定向到HTTPS并配置SSL证书路径。整个过程几乎无需手动干预。完成后你的网站应该已经可以通过HTTPS访问了。步骤2手动验证与配置文件解读理解Certbot做了什么有助于故障排查。它主要修改了你的Nginx站点配置文件通常在/etc/nginx/sites-available/下。修改后的关键部分类似这样server { listen 80; server_name blog.yourdomain.com; # 这是Certbot自动添加的用于验证的location块 location ^~ /.well-known/acme-challenge/ { root /var/www/certbot; # 或默认的Web根目录 default_type text/plain; try_files $uri 404; } # 这是Certbot添加的重定向规则将HTTP流量重定向到HTTPS location / { return 301 https://$server_name$request_uri; } } server { listen 443 ssl; server_name blog.yourdomain.com; # 证书路径由Certbot自动设置 ssl_certificate /etc/letsencrypt/live/blog.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/blog.yourdomain.com/privkey.pem; # 其他SSL优化配置... # 你的网站主配置 root /var/www/html; index index.html; }常见问题排查验证失败连接被拒绝 (Connection refused)检查服务器80端口是否在防火墙如ufw, firewalld中开放以及是否被云服务商的安全组/网络ACL放行。使用sudo ufw status或sudo netstat -tulpn | grep :80检查。验证失败404 Not Found检查Nginx配置中.well-known/acme-challenge/的location块是否正确配置并且路径可读。确保没有其他全局规则如禁止访问隐藏目录的规则覆盖了它。验证失败403 Forbidden检查/var/www/certbot或你的Web根目录的权限确保Nginx进程用户通常是www-data有读取权限。3.3 方式二DNS-01验证实战以Cloudflare为例支持通配符假设你想为*.yourdomain.com和yourdomain.com申请一张通配符证书你的DNS托管在Cloudflare。步骤1获取Cloudflare API凭证登录Cloudflare控制台进入你的域名。点击右下角“获取您的API令牌”。点击“创建令牌”。选择“编辑区域DNS”模板。在“区域资源”中选择需要授权的域名例如yourdomain.com。点击“继续以显示摘要”然后“创建令牌”。请务必安全保存这个Token它只显示一次步骤2在服务器上配置Cloudflare API Token我们需要让Certbot能使用这个Token。创建一个配置文件来存储它sudo mkdir -p /etc/letsencrypt/.secrets/ sudo nano /etc/letsencrypt/.secrets/cloudflare.ini在文件中写入以下内容将your-cloudflare-api-token替换为刚才获取的真实Token# Cloudflare API token dns_cloudflare_api_token your-cloudflare-api-token然后设置严格的权限防止其他用户读取sudo chmod 600 /etc/letsencrypt/.secrets/cloudflare.ini步骤3安装Certbot的Cloudflare DNS插件Certbot需要通过插件来调用DNS API。# 对于Ubuntu/Debian可能需要先添加Certbot官方PPA以获取最新插件 sudo apt install python3-pip -y sudo pip3 install certbot-dns-cloudflare步骤4使用DNS验证申请通配符证书这次我们使用certonly命令并指定DNS插件和验证方式sudo certbot certonly \ --dns-cloudflare \ --dns-cloudflare-credentials /etc/letsencrypt/.secrets/cloudflare.ini \ --preferred-challenges dns-01 \ -d *.yourdomain.com \ -d yourdomain.com命令参数详解certonly仅获取证书不安装或修改Web服务器配置。--dns-cloudflare指定使用Cloudflare DNS插件。--dns-cloudflare-credentials指定包含API Token的凭证文件路径。--preferred-challenges dns-01强制使用DNS验证方式。-d指定要包含在证书中的域名。通配符域名*.yourdomain.com必须与根域名yourdomain.com一起指定才能申请到同时包含两者的通配符证书。步骤5手动配置Nginx使用证书证书获取成功后会存放在/etc/letsencrypt/live/yourdomain.com/目录下。你需要手动编辑Nginx配置来使用它们server { listen 443 ssl http2; server_name yourdomain.com www.yourdomain.com app.yourdomain.com; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; # 其他SSL配置... root /var/www/html; index index.html; } server { listen 80; server_name yourdomain.com www.yourdomain.com app.yourdomain.com; return 301 https://$host$request_uri; }DNS验证的坑与技巧TTL设置在申请证书前可以考虑将域名的TTL临时调低例如300秒以便DNS记录变更快速生效。申请完成后再调回。API权限最小化正如之前提到的使用仅具有编辑TXT记录权限的API Token。验证延迟如果遇到超时可以稍等几分钟再重试。Certbot在验证时会自动等待DNS传播。多域名管理对于管理大量域名的场景DNS验证的自动化优势明显但需要为每个DNS服务商配置对应的插件和凭证。4. 高级场景与自动化续期策略证书的有效期是90天自动化续期是免费HTTPS可持续的关键。4.1 自动化续期原理Certbot在安装时通常会创建一个systemd定时任务timer或cron job。在Ubuntu上你可以通过以下命令查看systemctl list-timers | grep certbot # 或查看cron sudo cat /etc/cron.d/certbot这个定时任务会定期例如每天两次运行certbot renew命令。renew命令会检查/etc/letsencrypt/live/目录下所有证书的到期时间如果距离到期不足30天它会自动尝试续期。续期时的验证续期使用的验证方式默认会沿用当初申请证书时成功的方式。例如你当初用HTTP验证申请的续期时Certbot会尝试再次使用HTTP验证。如果当初用DNS验证续期时也需要能调用DNS API。4.2 为DNS验证配置自动化续期对于HTTP验证只要Web服务器运行正常续期通常是自动的。但对于DNS验证由于涉及API调用需要确保续期时凭证文件可用。续期命令和申请时类似但更简单因为Certbot会读取之前的配置sudo certbot renew --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/.secrets/cloudflare.ini你可以手动运行这个命令测试续期--dry-run参数可以模拟续期而不真正操作sudo certbot renew --dry-run如果测试成功那么定时任务就会正常工作。4.3 复杂架构下的验证策略负载均衡器后方多台Web服务器方案A推荐在负载均衡器如HAProxy, Nginx, AWS ALB层面进行HTTP验证。将/.well-known/acme-challenge/路径的流量路由到一台专门用于证书管理的“认证服务器”或者使用负载均衡器本身的能力响应挑战如HAProxy的use_backend规则。方案B使用DNS验证。这是最干净的方法完全绕开了Web服务器层的复杂性。Docker容器环境可以使用certbot/certbot官方Docker镜像通过--webroot模式将宿主机的某个目录挂载到容器内作为Webroot同时这个目录也被Nginx容器挂载并配置对应location。这样Certbot容器写入的挑战文件Nginx容器可以读取。更现代的做法是使用traefik或caddy这类原生支持自动获取Let‘s Encrypt证书的反向代理/Web服务器。仅限内网访问的服务必须使用DNS验证。只要你的内网服务有一个在公网可解析的域名即使解析到内网IP或通过端口转发就可以完成验证。另一种方案是使用“DNS别名”CNAME验证。例如内网服务域名为internal.yourdomain.com你可以在公网DNS为其设置一个CNAME记录指向另一个你完全控制的、可进行HTTP验证的公网域名auth.yourdomain.com。然后申请证书时使用internal.yourdomain.com但验证在auth.yourdomain.com上进行。这需要ACME客户端支持如Certbot的--challenge-alias参数但此功能在部分客户端中可能不稳定或为实验性。5. 故障排查与安全加固指南即使流程清晰实操中仍会遇到各种问题。这里汇总一些典型故障和排查思路。5.1 常见错误与解决方案速查表错误现象可能原因排查步骤与解决方案连接被拒绝 (Connection refused)1. 服务器防火墙/安全组未开放80或443端口。2. Web服务Nginx/Apache未运行。3. 验证请求被本地防火墙规则拦截。1.sudo ufw allow 80/tcp和sudo ufw allow 443/tcp。2. 检查云服务商安全组规则。3.sudo systemctl status nginx确保服务运行。4. 检查iptables或nftables规则。超时 (Timeout)1. DNS解析问题CA服务器无法连接到你的域名。2. 网络路由问题或中间防火墙阻断。3. 服务器负载过高无响应。1. 使用dig或nslookup检查域名解析是否正确指向服务器IP。2. 从其他网络telnet yourdomain.com 80测试端口连通性。3. 检查服务器资源使用情况。验证失败404 Not Found1. Nginx/Apache配置中缺少或错误配置了.well-known路径。2. Web根目录路径错误或权限不足。3. 有全局配置如location ~ /\.阻止访问。1. 检查站点配置文件确认location ^~ /.well-known/acme-challenge/块存在且路径正确。2. 检查该路径的磁盘权限确保Web进程用户可读。3. 检查是否有冲突的location规则。DNS验证失败Invalid TXT record1. DNS API调用失败记录未成功添加。2. DNS记录值哈希计算或填写错误。3. DNS传播延迟CA查询时记录尚未生效。1. 检查Certbot日志确认API调用是否成功。2. 手动使用dig TXT _acme-challenge.yourdomain.com查询记录是否存在且值正确。3. 临时降低TTL等待几分钟后重试。证书续期失败1. 验证环境已改变如关闭了80端口DNS API密钥失效。2. 证书配置文件损坏。3. 达到了Let‘s Encrypt的速率限制。1. 运行sudo certbot renew --dry-run -v查看详细错误。2. 检查/etc/letsencrypt/renewal/yourdomain.com.conf配置文件。3. 访问https://letsencrypt.status.io/查看CA状态或检查是否触发每周域名5个/周或重复证书5个/周限制。5.2 安全最佳实践私钥保护Let‘s Encrypt签发的私钥默认保存在/etc/letsencrypt/archive/和/etc/letsencrypt/live/符号链接。确保这些目录的权限严格如700仅限root用户访问。最小权限原则对于DNS验证使用权限最低的API Token。对于HTTP验证确保Web服务器进程权限不被过度提升。监控与告警证书续期并非100%成功。务必设置监控检查证书到期时间。一个简单的方法是使用一个cron job定期检查并发送通知# 每周一检查一次如果证书剩余天数小于30天发送邮件需要配置mailutils echo 0 0 * * 1 root /usr/bin/certbot renew --quiet --no-self-upgrade systemctl reload nginx | sudo tee -a /etc/crontab # 或者使用脚本检查并告警 # remaining_days$(openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -noout -dates | grep -i after | cut -d -f2 | xargs -I {} date -d {} %s | awk {print int(($0 - systime())/86400)}) # if [ $remaining_days -lt 15 ]; then echo 证书即将过期; fi备份定期备份/etc/letsencrypt/目录。虽然证书可以重新申请但备份配置和账户密钥可以避免在服务器迁移时重新进行账户注册。禁用HTTP到HTTPS的重定向循环在配置Nginx重定向时确保挑战路径/.well-known/acme-challenge/不被重定向到HTTPS。这就是为什么在之前的配置示例中我们将挑战location块放在监听80端口的server块内并且放在重定向规则location /之前的原因。Nginx的location匹配有优先级^~前缀表示“如果匹配此规则则停止搜索更具体的规则”这确保了挑战文件能被HTTP访问。5.3 性能与可靠性考量OCSP装订Stapling在Nginx SSL配置中启用OCSP Stapling可以减少客户端验证证书吊销状态时的延迟提升HTTPS握手速度。ssl_stapling on; ssl_stapling_verify on; # 使用一个可用的DNS解析器 resolver 8.8.8.8 1.1.1.1 valid300s; resolver_timeout 5s;会话票据Session Tickets启用SSL会话票据允许客户端在短时间内重新连接时无需完全握手进一步提升性能。HSTS对于生产环境考虑添加HTTP严格传输安全头强制浏览器始终使用HTTPS访问你的网站。但请注意一旦启用在证书过期或配置错误时用户将无法绕过警告访问你的网站因此务必确保证书管理流程可靠后再启用。add_header Strict-Transport-Security max-age63072000; includeSubDomains; preload always;选择哪种验证方式没有绝对答案。对于个人博客、简单网站HTTP验证的便捷性是首选。当你需要管理多个子域名、架构复杂或服务非HTTP协议时DNS验证的灵活性无可替代。而TLS-ALPN-01则在特定端口限制场景下有用武之地。理解其原理结合自身环境做出选择并配以可靠的自动化续期和监控才能真正让“免费的HTTPS”成为网站稳定、安全的基石而不是一个需要时刻担心的运维负担。
Let‘s Encrypt HTTPS证书申请:HTTP与DNS验证方式详解与实战
发布时间:2026/7/1 22:25:18
1. 项目概述为什么我们需要为网站获取HTTPS证书在今天的互联网上一个没有HTTPS的网站几乎等同于“不安全”的代名词。无论是浏览器地址栏里刺眼的“不安全”标识还是用户提交表单时对数据泄露的担忧都让HTTPS从一项“加分项”变成了“必需品”。你可能听说过Let‘s Encrypt这个提供免费SSL/TLS证书的公益机构它彻底改变了HTTPS的普及门槛。而“Get HTTPS for free”这个项目正是围绕Let’s Encrypt的ACME协议实现自动化证书申请、验证和续期的核心实践。简单来说这个过程就是让你的服务器向证书颁发机构CA这里是Let‘s Encrypt证明“嘿我确实拥有这个域名比如example.com的控制权。” 一旦证明成功CA就会签发一张属于你这个域名的证书。服务器安装这张证书后就能与用户的浏览器建立加密的HTTPS连接。整个证明“你拥有这个域名”的过程就叫做“域名验证”Domain Validation。而ACME协议主要定义了三种验证方式HTTP-01、DNS-01和TLS-ALPN-01通常被归为文件验证的一种高级形式但今天我们聚焦前两种和基础的HTTP文件验证。为什么需要了解这三种方式因为不同的服务器环境、网络架构和运维需求决定了哪种方式最适合你。用错了方法可能会让自动化流程卡壳甚至因为验证失败导致服务中断。接下来我们就深入拆解这三种验证方式的原理、适用场景和实操中的那些“坑”。2. 核心验证方式原理与场景对比在自动化证书管理过程中验证方式是核心枢纽。ACME协议的设计初衷是自动化因此验证过程也必须无需人工干预。三种验证方式本质上是提供了三条不同的“通道”让CA能够通过互联网访问到你指定的资源从而确认你对域名的控制权。2.1 HTTP-01 验证最直接的文件挑战原理拆解HTTP-01验证的原理非常直观。当你的客户端如Certbot向Let‘s Encrypt申请证书时CA会提供一个唯一的、随机的“令牌”token和一个对应的“密钥授权”key authorization。你的客户端需要在你所申请证书的域名例如www.example.com的Web服务器根目录下创建一个特定的文件。这个文件的访问路径是http://www.example.com/.well-known/acme-challenge/token文件的内容就是那个“密钥授权”字符串。随后CA的验证服务器会尝试通过HTTP注意是HTTP不是HTTPS协议访问这个URL。如果能成功访问到并且返回的内容完全匹配客户端预先计算好的“密钥授权”值那么验证就通过了。CA会认为“既然你能在这个域名对应的Web服务器上放置一个我能读取的特定文件那你肯定拥有这个域名的控制权至少是Web服务器的控制权。”适用场景与优缺点优点原理简单配置直观。对于大多数拥有标准Web服务器如Nginx, Apache的站点来说这是最快捷的方式。很多自动化工具如Certbot的Webroot插件默认或首选这种方式。缺点必须开放80端口CA的验证服务器只通过HTTP80端口访问。如果你的服务器防火墙屏蔽了80端口或者80端口被其他服务占用验证就会失败。依赖Web服务你的域名必须解析到一台正在运行且可公开访问的Web服务器。如果你只是在搭建一个API服务器、游戏服务器或其他非Web服务可能没有现成的Web服务来响应这个挑战。多服务器负载均衡场景复杂如果你的网站由多台Web服务器通过负载均衡器对外服务你需要确保这个特定的挑战文件能被同步到所有后端服务器或者通过负载均衡器策略确保CA的请求总能被路由到存放了该文件的服务器上。这增加了运维复杂度。内网或开发环境对于无法从公网直接访问的内网服务器或本地开发环境HTTP验证无法进行。注意很多人在配置Nginx或Apache时会忽略对.well-known目录的访问权限配置。如果该目录被禁止访问例如通过location ~ /\.规则拒绝了所有以点开头的隐藏目录验证必定失败。你需要显式地为这个路径配置允许访问的规则。2.2 DNS-01 验证最灵活的记录挑战原理拆解DNS-01验证将证明的场所从Web服务器转移到了DNS服务器。同样CA会提供一个“令牌”和“密钥授权”。但这次你的客户端需要计算这个“密钥授权”的SHA-256哈希值一个Base64 URL编码的字符串然后将这个哈希值作为一条特定的TXT记录添加到你的域名的DNS配置中。这条TXT记录的名称主机记录是_acme-challenge.你的域名。例如对于example.com记录名就是_acme-challenge.example.com。记录值就是那个计算出的哈希值。CA的验证服务器会查询DNS系统获取这条TXT记录的值。如果查询到的值与预期哈希值匹配验证即告成功。CA的逻辑是“既然你能在域名的权威DNS服务器上设置一条特定的TXT记录那你肯定拥有这个域名的DNS解析控制权。”适用场景与优缺点优点不依赖特定服务不需要Web服务器、邮件服务器或任何其他特定服务在运行。只要域名能正常解析验证就能进行。这对于非Web服务、负载均衡器VIP、邮件服务器MX记录指向的IP等场景是唯一选择。可签发通配符证书这是DNS-01验证独有的巨大优势。只有通过DNS验证Let‘s Encrypt才会为你签发通配符证书如*.example.com用于保护该域名下的所有子域名。适合复杂架构在多数据中心、混合云、CDN等复杂架构中管理DNS记录通常比同步Web服务器文件更简单、更中心化。内网环境友好即使服务器在内网只要其域名在公网DNS有解析哪怕解析到内网IP或通过NAT就可以完成验证。缺点需要API权限自动化流程要求你的客户端能通过脚本调用DNS服务商的API来动态添加和删除这条TXT记录。这意味着你需要从DNS服务商如Cloudflare,阿里云DNS, DNSPod等获取API密钥或Token并妥善保管。DNS传播延迟新增或修改DNS记录后全球DNS缓存刷新需要时间TTL。虽然Let‘s Encrypt的验证服务器会重试并等待但如果你的DNS服务商生效慢或者你设置的TTL过长可能导致验证超时失败。安全风险将DNS服务商的API密钥存放在申请证书的服务器上增加了密钥泄露的风险。一旦泄露攻击者可能篡改你的所有DNS记录。实操心得DNS API密钥管理绝对不要将API密钥硬编码在脚本或配置文件中。对于Certbot可以使用环境变量传递或者利用其--config-dir和--work-dir指定安全目录。更好的做法是使用支持“角色”或“细粒度权限”的DNS服务商如Cloudflare的API Token创建一个仅具有“编辑域名的TXT记录”权限的Token将风险降到最低。2.3 TLS-ALPN-01 验证基于端口443的挑战原理拆解TLS-ALPN-01是一种更“底层”的验证方式它发生在TLS握手阶段。当CA验证服务器连接到你的服务器的443端口HTTPS时会在TLS握手的“应用层协议协商”ALPN扩展中发送一个特殊的协议IDacme-tls/1。你的服务器需要配置为能识别这个协议ID并在握手过程中返回一个特定的“密钥授权”证书一个自签名的临时证书而不是通常的网站证书。这个临时证书的主题备用名称SAN包含一个特殊的域名其内容编码了验证信息。CA验证服务器通过解析这个临时证书来完成验证。由于整个过程发生在标准的TLS 443端口它不需要单独的HTTP服务也不依赖DNS记录。适用场景与优缺点优点仅需443端口对于只开放了443端口HTTPS的服务器非常友好无需额外开放80端口。验证效率高验证过程在TLS层完成通常比HTTP请求更快。缺点实现复杂需要在TLS握手层面进行拦截和响应对服务器软件如Nginx, Apache的版本和模块有要求。Certbot通过--preferred-challenges tls-alpn-01参数和对应的插件如certbot-nginx来支持但配置不如HTTP方式普遍。适用场景窄主要用于本身就在443端口提供TLS服务的场景。如果服务器没有配置任何TLS服务此方法无效。不支持通配符证书和HTTP-01一样TLS-ALPN-01也不能用于申请通配符证书。由于TLS-ALPN-01在实际中使用频率远低于HTTP和DNS方式且通常被Certbot等工具在后台自动选择用于续期当80端口不可用时我们接下来的实操将重点放在HTTP和DNS验证上。3. 实战演练使用Certbot配置两种主流验证方式理论讲完了我们上手操作。这里以最流行的ACME客户端Certbot为例演示在Ubuntu 22.04 Nginx环境下如何分别使用HTTP和DNS验证方式获取证书。3.1 环境准备与Certbot安装首先确保你的服务器系统是最新的并且已经安装了Nginx或其他Web服务器这里以Nginx为例。# 更新系统包列表 sudo apt update sudo apt upgrade -y # 安装Nginx (如果尚未安装) sudo apt install nginx -y # 安装Certbot和Nginx插件 sudo apt install certbot python3-certbot-nginx -y安装python3-certbot-nginx插件至关重要它允许Certbot自动读取和修改Nginx的配置文件来完成HTTP验证和证书安装。3.2 方式一HTTP-01验证实战单域名假设你的域名是blog.yourdomain.com并且已经解析到了这台服务器的公网IP。步骤1使用Certbot的Nginx插件自动获取并配置这是最简单的方式Certbot会自动处理所有事情修改Nginx配置以响应挑战获取证书并重写配置以启用HTTPS。sudo certbot --nginx -d blog.yourdomain.com执行这个命令后Certbot会交互式地询问你的邮箱用于接收续期提醒和紧急通知。询问你是否同意服务条款。询问你是否愿意分享你的邮箱以接收EFF的新闻可选。自动在Nginx配置中为blog.yourdomain.com添加一个临时的location块用于服务.well-known/acme-challenge/路径下的挑战文件。与Let‘s Encrypt通信触发验证。验证通过后下载证书和密钥。自动修改你的Nginx站点配置文件将HTTP重定向到HTTPS并配置SSL证书路径。整个过程几乎无需手动干预。完成后你的网站应该已经可以通过HTTPS访问了。步骤2手动验证与配置文件解读理解Certbot做了什么有助于故障排查。它主要修改了你的Nginx站点配置文件通常在/etc/nginx/sites-available/下。修改后的关键部分类似这样server { listen 80; server_name blog.yourdomain.com; # 这是Certbot自动添加的用于验证的location块 location ^~ /.well-known/acme-challenge/ { root /var/www/certbot; # 或默认的Web根目录 default_type text/plain; try_files $uri 404; } # 这是Certbot添加的重定向规则将HTTP流量重定向到HTTPS location / { return 301 https://$server_name$request_uri; } } server { listen 443 ssl; server_name blog.yourdomain.com; # 证书路径由Certbot自动设置 ssl_certificate /etc/letsencrypt/live/blog.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/blog.yourdomain.com/privkey.pem; # 其他SSL优化配置... # 你的网站主配置 root /var/www/html; index index.html; }常见问题排查验证失败连接被拒绝 (Connection refused)检查服务器80端口是否在防火墙如ufw, firewalld中开放以及是否被云服务商的安全组/网络ACL放行。使用sudo ufw status或sudo netstat -tulpn | grep :80检查。验证失败404 Not Found检查Nginx配置中.well-known/acme-challenge/的location块是否正确配置并且路径可读。确保没有其他全局规则如禁止访问隐藏目录的规则覆盖了它。验证失败403 Forbidden检查/var/www/certbot或你的Web根目录的权限确保Nginx进程用户通常是www-data有读取权限。3.3 方式二DNS-01验证实战以Cloudflare为例支持通配符假设你想为*.yourdomain.com和yourdomain.com申请一张通配符证书你的DNS托管在Cloudflare。步骤1获取Cloudflare API凭证登录Cloudflare控制台进入你的域名。点击右下角“获取您的API令牌”。点击“创建令牌”。选择“编辑区域DNS”模板。在“区域资源”中选择需要授权的域名例如yourdomain.com。点击“继续以显示摘要”然后“创建令牌”。请务必安全保存这个Token它只显示一次步骤2在服务器上配置Cloudflare API Token我们需要让Certbot能使用这个Token。创建一个配置文件来存储它sudo mkdir -p /etc/letsencrypt/.secrets/ sudo nano /etc/letsencrypt/.secrets/cloudflare.ini在文件中写入以下内容将your-cloudflare-api-token替换为刚才获取的真实Token# Cloudflare API token dns_cloudflare_api_token your-cloudflare-api-token然后设置严格的权限防止其他用户读取sudo chmod 600 /etc/letsencrypt/.secrets/cloudflare.ini步骤3安装Certbot的Cloudflare DNS插件Certbot需要通过插件来调用DNS API。# 对于Ubuntu/Debian可能需要先添加Certbot官方PPA以获取最新插件 sudo apt install python3-pip -y sudo pip3 install certbot-dns-cloudflare步骤4使用DNS验证申请通配符证书这次我们使用certonly命令并指定DNS插件和验证方式sudo certbot certonly \ --dns-cloudflare \ --dns-cloudflare-credentials /etc/letsencrypt/.secrets/cloudflare.ini \ --preferred-challenges dns-01 \ -d *.yourdomain.com \ -d yourdomain.com命令参数详解certonly仅获取证书不安装或修改Web服务器配置。--dns-cloudflare指定使用Cloudflare DNS插件。--dns-cloudflare-credentials指定包含API Token的凭证文件路径。--preferred-challenges dns-01强制使用DNS验证方式。-d指定要包含在证书中的域名。通配符域名*.yourdomain.com必须与根域名yourdomain.com一起指定才能申请到同时包含两者的通配符证书。步骤5手动配置Nginx使用证书证书获取成功后会存放在/etc/letsencrypt/live/yourdomain.com/目录下。你需要手动编辑Nginx配置来使用它们server { listen 443 ssl http2; server_name yourdomain.com www.yourdomain.com app.yourdomain.com; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; # 其他SSL配置... root /var/www/html; index index.html; } server { listen 80; server_name yourdomain.com www.yourdomain.com app.yourdomain.com; return 301 https://$host$request_uri; }DNS验证的坑与技巧TTL设置在申请证书前可以考虑将域名的TTL临时调低例如300秒以便DNS记录变更快速生效。申请完成后再调回。API权限最小化正如之前提到的使用仅具有编辑TXT记录权限的API Token。验证延迟如果遇到超时可以稍等几分钟再重试。Certbot在验证时会自动等待DNS传播。多域名管理对于管理大量域名的场景DNS验证的自动化优势明显但需要为每个DNS服务商配置对应的插件和凭证。4. 高级场景与自动化续期策略证书的有效期是90天自动化续期是免费HTTPS可持续的关键。4.1 自动化续期原理Certbot在安装时通常会创建一个systemd定时任务timer或cron job。在Ubuntu上你可以通过以下命令查看systemctl list-timers | grep certbot # 或查看cron sudo cat /etc/cron.d/certbot这个定时任务会定期例如每天两次运行certbot renew命令。renew命令会检查/etc/letsencrypt/live/目录下所有证书的到期时间如果距离到期不足30天它会自动尝试续期。续期时的验证续期使用的验证方式默认会沿用当初申请证书时成功的方式。例如你当初用HTTP验证申请的续期时Certbot会尝试再次使用HTTP验证。如果当初用DNS验证续期时也需要能调用DNS API。4.2 为DNS验证配置自动化续期对于HTTP验证只要Web服务器运行正常续期通常是自动的。但对于DNS验证由于涉及API调用需要确保续期时凭证文件可用。续期命令和申请时类似但更简单因为Certbot会读取之前的配置sudo certbot renew --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/.secrets/cloudflare.ini你可以手动运行这个命令测试续期--dry-run参数可以模拟续期而不真正操作sudo certbot renew --dry-run如果测试成功那么定时任务就会正常工作。4.3 复杂架构下的验证策略负载均衡器后方多台Web服务器方案A推荐在负载均衡器如HAProxy, Nginx, AWS ALB层面进行HTTP验证。将/.well-known/acme-challenge/路径的流量路由到一台专门用于证书管理的“认证服务器”或者使用负载均衡器本身的能力响应挑战如HAProxy的use_backend规则。方案B使用DNS验证。这是最干净的方法完全绕开了Web服务器层的复杂性。Docker容器环境可以使用certbot/certbot官方Docker镜像通过--webroot模式将宿主机的某个目录挂载到容器内作为Webroot同时这个目录也被Nginx容器挂载并配置对应location。这样Certbot容器写入的挑战文件Nginx容器可以读取。更现代的做法是使用traefik或caddy这类原生支持自动获取Let‘s Encrypt证书的反向代理/Web服务器。仅限内网访问的服务必须使用DNS验证。只要你的内网服务有一个在公网可解析的域名即使解析到内网IP或通过端口转发就可以完成验证。另一种方案是使用“DNS别名”CNAME验证。例如内网服务域名为internal.yourdomain.com你可以在公网DNS为其设置一个CNAME记录指向另一个你完全控制的、可进行HTTP验证的公网域名auth.yourdomain.com。然后申请证书时使用internal.yourdomain.com但验证在auth.yourdomain.com上进行。这需要ACME客户端支持如Certbot的--challenge-alias参数但此功能在部分客户端中可能不稳定或为实验性。5. 故障排查与安全加固指南即使流程清晰实操中仍会遇到各种问题。这里汇总一些典型故障和排查思路。5.1 常见错误与解决方案速查表错误现象可能原因排查步骤与解决方案连接被拒绝 (Connection refused)1. 服务器防火墙/安全组未开放80或443端口。2. Web服务Nginx/Apache未运行。3. 验证请求被本地防火墙规则拦截。1.sudo ufw allow 80/tcp和sudo ufw allow 443/tcp。2. 检查云服务商安全组规则。3.sudo systemctl status nginx确保服务运行。4. 检查iptables或nftables规则。超时 (Timeout)1. DNS解析问题CA服务器无法连接到你的域名。2. 网络路由问题或中间防火墙阻断。3. 服务器负载过高无响应。1. 使用dig或nslookup检查域名解析是否正确指向服务器IP。2. 从其他网络telnet yourdomain.com 80测试端口连通性。3. 检查服务器资源使用情况。验证失败404 Not Found1. Nginx/Apache配置中缺少或错误配置了.well-known路径。2. Web根目录路径错误或权限不足。3. 有全局配置如location ~ /\.阻止访问。1. 检查站点配置文件确认location ^~ /.well-known/acme-challenge/块存在且路径正确。2. 检查该路径的磁盘权限确保Web进程用户可读。3. 检查是否有冲突的location规则。DNS验证失败Invalid TXT record1. DNS API调用失败记录未成功添加。2. DNS记录值哈希计算或填写错误。3. DNS传播延迟CA查询时记录尚未生效。1. 检查Certbot日志确认API调用是否成功。2. 手动使用dig TXT _acme-challenge.yourdomain.com查询记录是否存在且值正确。3. 临时降低TTL等待几分钟后重试。证书续期失败1. 验证环境已改变如关闭了80端口DNS API密钥失效。2. 证书配置文件损坏。3. 达到了Let‘s Encrypt的速率限制。1. 运行sudo certbot renew --dry-run -v查看详细错误。2. 检查/etc/letsencrypt/renewal/yourdomain.com.conf配置文件。3. 访问https://letsencrypt.status.io/查看CA状态或检查是否触发每周域名5个/周或重复证书5个/周限制。5.2 安全最佳实践私钥保护Let‘s Encrypt签发的私钥默认保存在/etc/letsencrypt/archive/和/etc/letsencrypt/live/符号链接。确保这些目录的权限严格如700仅限root用户访问。最小权限原则对于DNS验证使用权限最低的API Token。对于HTTP验证确保Web服务器进程权限不被过度提升。监控与告警证书续期并非100%成功。务必设置监控检查证书到期时间。一个简单的方法是使用一个cron job定期检查并发送通知# 每周一检查一次如果证书剩余天数小于30天发送邮件需要配置mailutils echo 0 0 * * 1 root /usr/bin/certbot renew --quiet --no-self-upgrade systemctl reload nginx | sudo tee -a /etc/crontab # 或者使用脚本检查并告警 # remaining_days$(openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -noout -dates | grep -i after | cut -d -f2 | xargs -I {} date -d {} %s | awk {print int(($0 - systime())/86400)}) # if [ $remaining_days -lt 15 ]; then echo 证书即将过期; fi备份定期备份/etc/letsencrypt/目录。虽然证书可以重新申请但备份配置和账户密钥可以避免在服务器迁移时重新进行账户注册。禁用HTTP到HTTPS的重定向循环在配置Nginx重定向时确保挑战路径/.well-known/acme-challenge/不被重定向到HTTPS。这就是为什么在之前的配置示例中我们将挑战location块放在监听80端口的server块内并且放在重定向规则location /之前的原因。Nginx的location匹配有优先级^~前缀表示“如果匹配此规则则停止搜索更具体的规则”这确保了挑战文件能被HTTP访问。5.3 性能与可靠性考量OCSP装订Stapling在Nginx SSL配置中启用OCSP Stapling可以减少客户端验证证书吊销状态时的延迟提升HTTPS握手速度。ssl_stapling on; ssl_stapling_verify on; # 使用一个可用的DNS解析器 resolver 8.8.8.8 1.1.1.1 valid300s; resolver_timeout 5s;会话票据Session Tickets启用SSL会话票据允许客户端在短时间内重新连接时无需完全握手进一步提升性能。HSTS对于生产环境考虑添加HTTP严格传输安全头强制浏览器始终使用HTTPS访问你的网站。但请注意一旦启用在证书过期或配置错误时用户将无法绕过警告访问你的网站因此务必确保证书管理流程可靠后再启用。add_header Strict-Transport-Security max-age63072000; includeSubDomains; preload always;选择哪种验证方式没有绝对答案。对于个人博客、简单网站HTTP验证的便捷性是首选。当你需要管理多个子域名、架构复杂或服务非HTTP协议时DNS验证的灵活性无可替代。而TLS-ALPN-01则在特定端口限制场景下有用武之地。理解其原理结合自身环境做出选择并配以可靠的自动化续期和监控才能真正让“免费的HTTPS”成为网站稳定、安全的基石而不是一个需要时刻担心的运维负担。