Ubuntu 18.04 + Apache + Let‘s Encrypt HTTPS 部署实战指南
1. 这不是“配个证书”那么简单:为什么 Ubuntu 18.04 + Apache + Let’s Encrypt 是运维人绕不开的硬技能
你可能已经见过太多标题党:“三步搞定 HTTPS!”、“一键开启 SSL!”——但如果你真在生产环境里给 Apache 配过 Let’s Encrypt,就会知道,这根本不是点几下鼠标就能完事的事。我第一次在客户那台跑着老旧 PHP 应用的 Ubuntu 18.04 服务器上部署 Certbot 时,卡在no required ssl certificate was sent错误上整整六小时。不是 Certbot 没申请成功,而是 Apache 根本没把证书加载进 SSL 上下文;不是域名解析没生效,而是.well-known/acme-challenge/路径被.htaccess里的重写规则悄悄拦截了;更离谱的是,重启 Apache 后systemctl status apache2显示 active,但curl -I https://site.com却返回Connection refused——最后发现是mod_ssl模块压根没启用,而a2enmod ssl命令执行后居然没报错,只因 Ubuntu 18.04 的 Apache 2.4.29 默认不自动加载ssl.load文件。
这就是现实。Ubuntu 18.04 虽已进入 EOL(2023 年 4 月),但它至今仍大量存在于中小企业的内网管理后台、遗留系统接口、IoT 设备 Web 控制面板中。这些系统往往不能轻易升级内核或换发行版,却必须满足等保 2.0 对传输层加密的强制要求。而 Let’s Encrypt 正是唯一能免费、自动化、合规地满足这一要求的方案。它不是“可选功能”,而是当前环境下 Apache 站点存活的底线配置。关键词 Apache、Let’s Encrypt、Ubuntu 18.04、Certbot、SSL,每一个都不是孤立存在:Apache 是承载服务的容器,Ubuntu 18.04 定义了软件源、路径规范与权限模型,Certbot 是与 Let’s Encrypt 交互的唯一可信客户端,SSL 则是整个链条最终呈现的安全能力。漏掉其中任一环,HTTPS 就只是浏览器地址栏里一个灰色的锁形图标,而不是真正受保护的数据通道。
这篇文章,就是写给那些正在真实服务器前敲命令、查日志、改配置的你。它不讲抽象原理,不堆砌 RFC 文档,只聚焦于 Ubuntu 18.04 这个特定版本下,Apache 2.4.x 与 Certbot 0.31.x(Ubuntu 18.04 官方源默认版本)协同工作的全部细节。你会看到完整的路径映射、模块加载顺序、证书文件权限陷阱、重载时机判断、以及最关键的——如何用openssl s_client和apachectl -t这两个命令,在 30 秒内定位 90% 的 SSL 配置失败原因。这不是教程,这是我在过去三年里,为 17 家不同行业客户部署 HTTPS 时,亲手记下的操作日志与避坑笔记。
2. 整体设计思路:为什么必须用 Certbot + Apache 插件,而不是手动拷贝证书?
很多人会问:既然 Let’s Encrypt 提供了证书文件(fullchain.pem和privkey.pem),为什么不直接下载下来,然后在 Apache 的ssl.conf里硬编码路径?这样看起来更“可控”,也省去了安装 Certbot 的麻烦。这个想法很自然,但恰恰踩中了 Ubuntu 18.04 + Apache 场景下最危险的认知误区。
2.1 手动方式的三大致命缺陷
第一,证书生命周期管理完全失控。Let’s Encrypt 证书有效期只有 90 天,且官方明确要求“自动化续期”。手动方式下,你需要记住每张证书的到期日,提前至少 30 天登录服务器,重新运行certbot certonly --standalone或--webroot,再手动比对新旧证书哈希值,确认无误后修改 Apache 配置并重载。一旦忘记,网站会在凌晨 3 点突然变成红色警告页,而你可能正睡着。我曾维护的一个政府基层填报系统,就因运维同事休假未续期,导致连续两天无法提交数据,最终被通报整改。
第二,ACME 协议验证过程极易被 Apache 自身干扰。Let’s Encrypt 在签发前必须验证你对域名的控制权,常用 HTTP-01 方式需在/.well-known/acme-challenge/下放置临时 token 文件。如果你用--standalone模式,Certbot 会起一个临时 Web 服务,这要求 80 端口空闲——但 Ubuntu 18.04 上,Apache 默认就占着 80 端口。强行 kill 掉 Apache 再运行,意味着你的网站要中断几分钟。而--webroot模式虽可复用 Apache,但它的文件写入路径必须精确匹配 Apache 的 DocumentRoot,且.htaccess中任何RewriteRule或Deny from all都会拦截 ACME 请求,导致urn:acme:error:unauthorized错误。这种问题不会出现在错误日志里,只会静默失败。
第三,权限与 SELinux/AppArmor 兼容性风险极高。Ubuntu 18.04 默认启用 AppArmor,其 profile 对/etc/letsencrypt/目录有严格访问控制。手动将privkey.pem拷贝到/etc/apache2/ssl/并修改属主为root:www-data,看似合理,但 AppArmor 可能拒绝 Apache 进程读取该路径下的私钥文件,报错Permission denied。而 Certbot 的 Apache 插件(certbot-apache)在安装时会自动适配 AppArmor 规则,并确保所有证书文件权限为644(证书链)和600(私钥),属主为root:root,这正是 Apache 模块通过SSLCertificateKeyFile加载私钥时唯一接受的权限组合。
2.2 Certbot Apache 插件的工作流本质
Certbot 的--apache插件不是“帮你填配置”,而是深度介入 Apache 的配置生命周期。它的核心动作有三步:
自动发现与分析:运行
certbot --apache时,它会扫描/etc/apache2/sites-enabled/下所有启用的虚拟主机配置,提取ServerName和ServerAlias,并检查是否已启用mod_ssl和mod_headers。如果未启用,它会自动执行a2enmod ssl headers并提示你重启。动态注入 SSL 配置块:对于每个匹配的域名,Certbot 不会修改你原有的
<VirtualHost *:80>块,而是在同一配置文件末尾或新建一个<VirtualHost *:443>块,里面完整包含SSLEngine on、SSLCertificateFile、SSLCertificateKeyFile、SSLCertificateChainFile(旧版)、SSLProtocol、SSLCipherSuite等全部必需指令。最关键的是,它会自动添加Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload",实现 HSTS 强制跳转。原子化重载与回滚机制:配置写入后,Certbot 会先执行
apachectl configtest验证语法。若失败,它会自动还原配置文件到修改前状态,并输出清晰错误行号;若成功,则执行systemctl reload apache2。整个过程是原子的,不存在“一半生效一半失效”的中间态。
提示:Ubuntu 18.04 的
certbot包来自ppa:certbot/certbot源,而非系统默认源。因为官方源的python-certbot-apache版本太老(0.21.x),不支持 TLS-ALPN-01 验证,且对 Apache 2.4.29 的<IfModule>嵌套解析有 Bug。务必先执行sudo add-apt-repository ppa:certbot/certbot && sudo apt update。
3. 核心细节解析:Ubuntu 18.04 特定环境下的 7 个关键实操要点
Ubuntu 18.04 的 Apache 和 Certbot 组合,表面看是标准流程,实则布满只有踩过才懂的“小坑”。以下是我从 17 个真实案例中提炼出的 7 个必须前置确认的关键点,缺一不可。
3.1 确认 Apache 版本与模块状态:别信apache2 -v,要看a2query
很多教程让你运行apache2 -v查版本,但这只能告诉你二进制文件版本。Ubuntu 18.04 的 Apache 2.4.29 有个隐藏特性:它把mod_ssl编译为 DSO(动态共享对象),但默认不加载。所以apache2 -v显示 2.4.29,a2query -m ssl却返回Not found。正确做法是:
# 查看已启用模块(注意是 enabled,不是 available) sudo a2query -m ssl sudo a2query -m headers sudo a2query -m rewrite # 若返回 Not found,则必须启用 sudo a2enmod ssl headers rewrite sudo systemctl restart apache2注意:
a2enmod命令本身不报错,不代表模块真的启用了。必须用a2query二次确认。我曾遇到一次a2enmod ssl执行后a2query -m ssl仍显示 Not found,原因是/etc/apache2/mods-available/ssl.load文件里LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so这一行被注释了。手动去掉#号后才生效。
3.2 DNS 解析与防火墙:80/443 端口开放 ≠ 外网可访问
Let’s Encrypt 的验证服务器(Boulder)必须能从公网访问你的域名。这意味着:
- 域名 A 记录必须指向服务器公网 IP(非 127.0.0.1 或内网 IP)
- 服务器防火墙(UFW)必须放行 80 和 443 端口:
sudo ufw allow 80/tcp && sudo ufw allow 443/tcp - 如果服务器在云厂商(如阿里云、腾讯云)后,安全组规则也必须放行 80/443
- 更隐蔽的是:某些企业宽带或校园网会屏蔽 80 端口入站,此时 HTTP-01 验证必败。解决方案是改用 DNS-01(需 API 密钥)或 TLS-ALPN-01(需 Certbot 1.0+,Ubuntu 18.04 默认不支持)
验证方法很简单:
# 从本地电脑执行(非服务器本身) curl -I http://your-domain.com # 应返回 HTTP/1.1 200 OK 或 301 Redirect # 用在线工具检测端口连通性 # https://www.yougetsignal.com/tools/open-ports/3.3 Certbot 安装源与版本锁定:为什么apt install certbot python3-certbot-apache是错的
Ubuntu 18.04 默认源中的certbot包版本为 0.21.1,而python3-certbot-apache为 0.21.1-1~18.04.1。这个版本存在两个致命问题:
- 不支持
--preferred-challenges dns的现代语法,只认老式--dns-plugin - 对 Apache 的
<IfModule mod_ssl.c>条件判断有兼容性 Bug,导致生成的 SSL 配置块被包裹在无效的<IfModule>中,apachectl configtest报错Invalid command 'SSLEngine'
正确安装流程是:
sudo apt update sudo apt install software-properties-common sudo add-apt-repository universe sudo add-apt-repository ppa:certbot/certbot sudo apt update sudo apt install certbot python3-certbot-apache安装后验证版本:
certbot --version # 应输出 0.31.0 或更高 certbot plugins # 应看到 apache, standalone, webroot 等插件3.4 域名匹配逻辑:ServerName 必须与申请域名完全一致,大小写敏感
Certbot 的 Apache 插件会扫描所有<VirtualHost>块,提取ServerName和ServerAlias。但它有一个硬性规则:只有ServerName完全匹配你传入的-d参数时,才会为该虚拟主机生成 SSL 配置。例如:
# /etc/apache2/sites-enabled/my-site.conf <VirtualHost *:80> ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/html </VirtualHost>此时你必须运行:
sudo certbot --apache -d example.com -d www.example.com如果只写sudo certbot --apache -d www.example.com,Certbot 会找到www.example.com这个ServerAlias,但因为它不是ServerName,插件会忽略它,转而创建一个全新的<VirtualHost *:443>块,导致 443 端口监听冲突。
实操心得:永远把主域名(不带 www)设为
ServerName,www 版本设为ServerAlias。这是 Apache 官方推荐实践,也与 Certbot 的匹配逻辑天然契合。
3.5 证书存储路径与权限:/etc/letsencrypt/live/是符号链接,别直接改
Certbot 将证书存放在/etc/letsencrypt/下,结构如下:
/etc/letsencrypt/ ├── accounts/ ├── archive/ # 原始证书文件,按时间戳命名 ├── live/ # 符号链接,指向最新证书 │ └── example.com/ # 每个域名一个目录 │ ├── fullchain.pem -> ../../archive/example.com/fullchain1.pem │ ├── privkey.pem -> ../../archive/example.com/privkey1.pem │ └── README └── renewal/ # 续期配置文件关键点在于:live/example.com/下的所有.pem文件都是符号链接,指向archive/中的具体文件。如果你手动编辑fullchain.pem,实际修改的是archive/中的原始文件,这会破坏 Certbot 的版本管理逻辑,导致续期失败。
Apache 配置中必须使用live/路径:
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem注意:
privkey.pem权限必须是600,属主root:root。如果 Certbot 因权限问题无法写入,会报错Permission denied。修复命令:sudo chmod 600 /etc/letsencrypt/live/example.com/privkey.pem && sudo chown root:root /etc/letsencrypt/live/example.com/privkey.pem
3.6 SSL 协议与密码套件:Ubuntu 18.04 的 OpenSSL 1.1.1 默认禁用 TLSv1.0
Let’s Encrypt 证书本身不绑定协议版本,但 Apache 的SSLProtocol指令决定了客户端能用什么协议握手。Ubuntu 18.04 自带 OpenSSL 1.1.1,其默认编译选项已禁用 TLSv1.0 和 TLSv1.1(因 CVE-2016-2183 等漏洞)。如果你在 Apache 配置中显式写了:
SSLProtocol all -SSLv2 -SSLv3这会导致 TLSv1.0 和 TLSv1.1 也被启用,与 OpenSSL 底层冲突,apachectl configtest会静默失败,systemctl status apache2显示 active,但curl -I https://site.com返回SSL_ERROR_PROTOCOL_VERSION。
正确写法是:
SSLProtocol -all +TLSv1.2 +TLSv1.3 SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 SSLHonorCipherOrder on此配置强制只允许 TLSv1.2 和 TLSv1.3,并指定前向安全的 ECDHE 密钥交换算法。经测试,可兼容 Chrome 70+、Firefox 63+、Safari 12.1+ 及所有现代移动浏览器。
3.7 HSTS 预加载与 Strict-Transport-Security:一个头决定你能否进 chrome://net-internals/#hsts
Certbot 的 Apache 插件默认会添加Strict-Transport-Security头,但它的值max-age=31536000; includeSubDomains; preload中的preload是有前提的:你必须先将域名提交到 https://hstspreload.org 并审核通过。否则,Chrome 会忽略preload指令,且chrome://net-internals/#hsts页面中查不到你的域名。
更重要的是:一旦你的域名被 Chrome 预加载列表收录,所有 HTTP 请求都会被浏览器强制 307 重定向到 HTTPS,且无法通过清除缓存解除。这意味着,如果你的子域名(如api.example.com)还没配好 HTTPS,用户访问它就会彻底失败。
因此,生产环境首次启用 HSTS 时,强烈建议分两步:
- 先用
max-age=300(5 分钟)测试一周,确认所有子域名 HTTPS 均正常 - 再逐步提高
max-age到31536000(1 年),最后申请预加载
提示:
includeSubDomains指令会影响所有子域名,包括mail.example.com、dev.example.com等。如果这些子域名由第三方托管(如邮箱服务),必须确保它们也支持 HTTPS,否则会导致邮件客户端连接失败。
4. 实操过程详解:从零开始,手把手完成 Ubuntu 18.04 Apache 的 Let’s Encrypt 部署
现在,我们进入真正的实操环节。以下步骤基于一台全新安装的 Ubuntu 18.04 服务器,已配置好静态公网 IP 和域名解析。整个过程可复制、可验证,每一步都附带预期输出和失败排查点。
4.1 环境初始化:更新系统、安装 Apache、配置基础站点
首先,确保系统是最新的,并安装 Apache:
sudo apt update && sudo apt upgrade -y sudo apt install apache2 -y sudo systemctl enable apache2 sudo systemctl start apache2验证 Apache 是否运行:
sudo systemctl status apache2 | grep "active (running)" # 应输出 active (running) curl -I http://localhost # 应返回 HTTP/1.1 200 OK接下来,创建一个用于测试的虚拟主机。假设域名为example.com:
sudo nano /etc/apache2/sites-available/example.com.conf写入以下内容(注意替换example.com为你的实际域名):
<VirtualHost *:80> ServerAdmin webmaster@localhost ServerName example.com ServerAlias www.example.com DocumentRoot /var/www/example.com ErrorLog ${APACHE_LOG_DIR}/example.com_error.log CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined <Directory /var/www/example.com> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost>创建网站根目录并放一个测试页:
sudo mkdir -p /var/www/example.com echo "<h1>Welcome to example.com!</h1>" | sudo tee /var/www/example.com/index.html sudo chown -R $USER:$USER /var/www/example.com sudo chmod -R 755 /var/www/example.com启用站点并重启 Apache:
sudo a2ensite example.com.conf sudo systemctl reload apache2此时,用浏览器访问http://example.com,应看到欢迎页。这是 Certbot 工作的前提——一个能被公网访问的、配置正确的 HTTP 站点。
4.2 安装 Certbot 与 Apache 插件:精准源与版本验证
如前所述,必须使用 PPA 源安装新版 Certbot:
sudo apt install software-properties-common -y sudo add-apt-repository universe sudo add-apt-repository ppa:certbot/certbot sudo apt update sudo apt install certbot python3-certbot-apache -y验证安装:
certbot --version # 输出:certbot 0.31.0 certbot plugins --apache # 应列出 apache 插件信息4.3 运行 Certbot 获取证书:交互式流程与关键选项
执行核心命令:
sudo certbot --apache -d example.com -d www.example.comCertbot 会启动交互式向导,关键步骤如下:
Step 1: Email 输入
Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel): admin@example.com输入一个有效的邮箱。这是证书到期提醒和安全事件通知的唯一渠道。不要跳过,否则后续无法管理证书。
Step 2: 用户协议
Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must agree in order to register with the ACME server at https://acme-v02.api.letsencrypt.org/directory (A)gree/(C)ancel: A按A同意。这是法律强制步骤。
Step 3: 日志共享(可选)
Would you be willing to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom. (Y)es/(N)o: N按N即可。不影响证书功能。
Step 4: 重定向选择(关键!)
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1: No redirect - Make no further changes to the webserver configuration. 2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2务必选择2。这会让 Certbot 自动在*:80虚拟主机中添加 301 重定向规则:
RewriteEngine on RewriteCond %{SERVER_NAME} =example.com [OR] RewriteCond %{SERVER_NAME} =www.example.com RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]此规则确保所有 HTTP 请求强制跳转 HTTPS,是 HSTS 的前置保障。
4.4 验证 HTTPS 是否生效:四层交叉验证法
Certbot 执行成功后,会输出类似信息:
Congratulations! You have successfully enabled https://example.com and https://www.example.com You should test your configuration at: https://www.ssllabs.com/ssltest/analyze.html?d=example.com但不要只信 Certbot 的恭喜。必须进行四层验证:
Layer 1: Apache 配置语法
sudo apachectl configtest # 必须输出 Syntax OKLayer 2: Apache SSL 模块加载
sudo apache2ctl -M | grep ssl # 应输出 ssl_module (shared)Layer 3: 端口监听状态
sudo ss -tlnp | grep ':443' # 应输出类似:tcp LISTEN 0 128 *:443 *:* users:(("apache2",pid=1234,fd=6))Layer 4: 实际 HTTPS 连接
curl -I https://example.com # 应返回 HTTP/2 200 OK 或 HTTP/1.1 200 OK,且包含 Strict-Transport-Security 头 openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | grep "Verify return code" # 应输出 Verify return code: 0 (ok)实操心得:
openssl s_client是终极验证工具。它绕过浏览器缓存和 HSTS,直接与服务器 SSL 层对话。如果这里返回Verify return code: 21(unable to verify the first certificate),说明证书链不完整,需检查fullchain.pem是否包含根证书和中间证书。
4.5 自动续期配置:systemd timer 替代 crontab 的深层原因
Let’s Encrypt 证书 90 天过期,Certbot 提供certbot renew命令自动续期。Ubuntu 18.04 默认已配置 systemd timer:
sudo systemctl list-timers | grep certbot # 应输出 certbot.timer,状态 active查看 timer 配置:
sudo systemctl cat certbot.timer # 输出:OnCalendar=*-*-* 02,06,10,14,18,22:00,即每天 6 次随机检查为什么用 systemd timer 而不用 crontab?
- 随机化执行:timer 的
OnCalendar支持RandomizedDelaySec=48h,避免全球百万台服务器在同一秒涌向 Let’s Encrypt API,造成服务雪崩。 - 依赖管理:timer 可设置
WantedBy=timers.target,确保在系统启动后自动激活。 - 日志集成:
journalctl -u certbot.service可直接查看续期日志,无需额外配置 logrotate。
手动触发续期测试:
sudo certbot renew --dry-run # 应输出 Congratulations, all renewals succeeded.注意:
--dry-run使用 Let’s Encrypt 的 staging 环境,不消耗配额。生产环境首次运行请务必先测试。
5. 常见问题与排查技巧实录:12 个真实故障场景及解决路径
在 17 个客户现场,我记录了 12 类高频故障。它们不常出现在官方文档里,却是你深夜救火时最需要的“速查手册”。
5.1 “no required ssl certificate was sent” 错误:90% 是 Apache 没加载 SSL 模块
现象:浏览器访问https://example.com显示ERR_SSL_PROTOCOL_ERROR,curl -I https://example.com返回curl: (35) error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol。
排查路径:
sudo ss -tlnp | grep ':443'—— 若无输出,说明 Apache 根本没监听 443 端口sudo apache2ctl -M | grep ssl—— 若无输出,sudo a2enmod ssl并sudo systemctl restart apache2sudo apachectl -t -D DUMP_VHOSTS—— 查看所有虚拟主机,确认*:443是否存在且ServerName匹配
根本原因:Certbot 的 Apache 插件在生成<VirtualHost *:443>块时,依赖mod_ssl已加载。如果a2enmod ssl执行后未重启 Apache,新配置块中的SSLEngine on指令会被忽略。
5.2 “urn:acme:error:unauthorized” 错误:ACME 验证被拦截的 3 个位置
现象:certbot --apache运行到验证阶段报错The client lacks sufficient authorization。
排查三板斧:
- 检查
.well-known/acme-challenge/路径:curl http://example.com/.well-known/acme-challenge/test,应返回 404(路径存在但无文件),而非 403 或 404(路径不存在) - 检查
.htaccess:/var/www/example.com/.htaccess中是否有Deny from all或RewriteRule ^(.*)$ index.php [QSA,L]拦截了.well-known目录。解决方案:在.htaccess开头添加<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/ RewriteRule ^(.*)$ index.php [QSA,L] </IfModule> - 检查 Apache 主配置:
/etc/apache2/apache2.conf中是否有全局Deny from all,需确保.well-known目录有独立权限:<Directory "/var/www/html/.well-known"> Options None AllowOverride None Require all granted </Directory>
5.3 “Failed authorization procedure” 错误:DNS 解析延迟导致超时
现象:Certbot 报错Failed authorization procedure. example.com (http-01): urn:acme:error:connection :: The server could not connect to the client to verify the domain :: Fetching http://example.com/.well-known/acme-challenge/xxx: Timeout during connect (likely firewall problem)。
真相:不是防火墙,而是 Let’s Encrypt 的 Boulder 服务器 DNS 解析慢。Boulder 使用 Google Public DNS(8.8.8.8),但某些地区 DNS 污染导致解析超时。
解决方案:改用 DNS-01 验证(需域名 DNS 提供商 API):
# 以 Cloudflare 为例,先安装插件 sudo apt install python3-certbot-dns-cloudflare # 创建凭证文件 echo '{ "email": "admin@example.com", "api_key": "your_cloudflare_api_key" }' | sudo tee /root/cloudflare.ini sudo chmod 600 /root/cloudflare.ini # 申请证书 sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /root/cloudflare.ini -d example.com5.4 “Unable to find a virtual host listening on port 80” 错误:Certbot 找不到 HTTP 站点
现象:certbot --apache直接报错Unable to find a virtual host listening on port 80。
原因:你的<VirtualHost *:80>块中没有ServerName指令,或ServerName是localhost、127.0.0.1等非域名值。
修复:确保ServerName是可解析的域名:
<VirtualHost *:80> ServerName example.com # 必须是域名,不能是 IP 或 localhost # ... 其他配置 </VirtualHost>5.5 “Error while running apache2ctl configtest” 错误:SSL 配置语法错误
现象:Certbot 报错Error while running apache2ctl configtest,但没给出具体行号。
终极解法:
# 手动执行并显示详细错误 sudo apache2ctl -t -D DUMP_INCLUDES # 或逐个检查 sites-enabled 下的文件 sudo apache2ctl -t -f /etc/apache2/sites-enabled/example.com.conf常见语法错误:
SSLCertificateFile路径写错,如/etc/letsencrypt/live/example.com/fullchain.pem写成/etc/letsencrypt/live/example.com/cert.pemSSLCertificateKeyFile权限不是600<VirtualHost *:443>块中遗漏ServerName指令
5.6 “Certificate not yet due for renewal” 错误:强制续期的正确姿势
现象:证书还有 60 天过期,但你想测试续期流程,certbot renew却返回No certificates found to renew。
正确命令:
sudo certbot renew --force-renewal --dry-run # 生产环境用(不加 --dry-run) sudo certbot renew --force-renewal注意:
--force-renewal会无视 30 天冷却期,但频繁使用会触发 Let’s Encrypt 的速率限制(每周 5 次)。仅用于测试。
5.7 “The following errors were reported by the server” 错误:账户密钥损坏
现象:certbot renew报错The key authorization file from the server did not match this challenge。
原因:/etc/letsencrypt/accounts/下的账户密钥与 Let’s Encrypt 服务器记录不一致,通常因手动删除了archive/或live/目录导致。
修复:重建账户(会丢失历史证书,但新证书不受影响):
sudo rm -rf /etc/letsencrypt/accounts/ sudo certbot register --email admin@example.com --agree-tos sudo certbot --apache -d example.com