SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-07

Ubuntu 24.04 安装 Apache Certbot:跳过 Snap

Ubuntu 24.04 的 apt 已提供 Certbot 2.9.0,无需安装 Snap。一条命令为 Apache 申请 Let's Encrypt 证书,并说明 ServerName 缺失、80 端口或 DNS 配置错误时的确切报错。

构建内容

在 Ubuntu 24.04 上配置 Apache 站点,使其通过 HTTPS 提供服务,并使用由 Certbot 签发的免费、受浏览器信任的 Let's Encrypt 证书。证书由您无需再次关注的 systemd 计时器自动续期。实际执行的命令只有一行。所有问题都会在执行这行命令之前发生:没有 ServerName 的 vhost、提供商防火墙关闭了 80 端口、DNS 仍指向旧服务器。因此,本指南的大部分内容都用于检查前置条件,并列出每种错误配置会输出的确切错误字符串。

有两点范围说明。如果您的 Web 服务器是 nginx,流程基本相同,但插件和配置不同,请改用 nginx 版本的本指南。如果您要保护的服务仅供内部使用,例如私有地址上的管理面板或无人访问的预发布服务器,则完全不需要证书颁发机构;自签名证书所需配置更少,并且可以离线使用。

前置条件,以及 Certbot 运行前失败的三种情况

  • Apache 已通过普通 HTTP 提供网站。 Certbot 的 Apache 插件会修改现有网站配置,不会创建网站。如果您使用的是全新 VPS,请先完成 Ubuntu 24.04 上的 LAMP 堆栈,然后再回来;本指南补充的正是其中缺失的 TLS 章节。
  • 拥有一个公共域名,并在 VPS 地址上配置了 A 记录。 Let's Encrypt 的 HTTP-01 挑战要求其验证服务器从互联网连接到您的服务器:没有端口转发的 NAT 家庭实验室无法使用,不能使用 .local 名称,也不能使用裸 IP 地址。dig +short example.com 必须返回您的 VPS 地址;如果您在过去一小时内修改过 DNS,请等待旧记录的 TTL 过期后再申请。
  • 如果存在 AAAA 记录,该记录必须正确。 发布 AAAA 记录后,Let's Encrypt 会优先使用 IPv6,因此过期或错误的 AAAA 记录会导致验证失败,即使您在笔记本上通过 IPv4 访问 curl 仍然正常。请发布正确的 AAAA 记录,或者完全不要发布 AAAA 记录。

必须在 ufw 服务商的网络防火墙中开放 80 和 443 端口。大多数托管面板都有第二层防火墙,操作系统无法看到它。HTTP-01 只能通过 80 端口验证;不能只运行 443。

sudo ufw allow "Apache Full"
sudo ufw status

完成这些准备后,整个过程只需 15 分钟,其中 10 分钟用于阅读。

Snap 还是 apt Certbot?在 24.04 上,apt 已经完全够用

Certbot 多年前转向 snap 分发有充分理由:发行版软件包长期不更新。Ubuntu 20.04 提供的是 Certbot 0.40,之后一直没有升级,项目维护者也不愿继续排查五年前的旧问题。在 24.04 上,这个理由已经不存在了。软件源提供 Certbot 2.9.0,这是当前版本,unattended-upgrades 也会持续为其提供补丁。对于这个操作系统,我建议使用 apt。这样无需运行 snapd daemon,Apache 插件会在同一次事务中安装,续期定时器也会按 Debian 的常规方式集成到 systemd。

sudo apt update
sudo apt install -y certbot python3-certbot-apache
certbot --version

正确结果是:certbot 2.9.0python3-certbot-apache 软件包负责读取和修改 Apache 配置。缺少它时,certbot --apache 会因 The requested apache plugin does not appear to be installed 而失败。

在以下两种情况下,snap 仍然是更合适的选择:您希望在最新 Certbot 发布当天就使用它,或者需要某个仅通过 snap 分发的 DNS 插件(certbot-dns-* 提供商插件中有多个属于这种情况)。如果选择这种方式:

sudo apt remove -y certbot python3-certbot-apache
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

无论选择哪种方式,都不要同时运行两种安装。两套安装会争用 /etc/letsencrypt 上的续期调度器,您的 shell 在 PATH 中找到的 certbot 可能并不拥有您的证书。上面的 apt remove 行不是可有可无的装饰。

Certbot 要修改的 vhost 必须已经存在,ServerName 是关键

certbot --apache 会查找端口 80 上的虚拟主机。如果其 ServerNameServerAlias 与您提供的每个 -d 域名匹配,certbot --apache 就会通过该虚拟主机验证域名控制权,然后为该 vhost 写入一个 SSL 副本。如果没有匹配的 ServerName,就无法匹配;而 Ubuntu 自带的默认 000-default.conf 中,ServerName 默认处于注释状态。这一行注释是本指南中那条大型命令失败的最常见原因。

因此,在操作 Certbot 之前,先为站点配置正确的基于名称的 vhost。创建 /etc/apache2/sites-available/example.com.conf

<VirtualHost *:80>
    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
</VirtualHost>

启用该配置,并确认 Apache 能解析它,同时会将该域名路由到此 vhost:

sudo a2ensite example.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
sudo apache2ctl -S

configtest 必须输出 Syntax OK。如果同时输出 AH00558: apache2: Could not reliably determine the server's fully qualified domain name,这表示全局 ServerName 存在警告,并非您的 vhost 有问题。在这里可以忽略该警告,并通过 echo "ServerName $(hostname -f)" | sudo tee /etc/apache2/conf-available/servername.conf && sudo a2enconf servername && sudo systemctl reload apache2 将其静默。

-S 的输出才是需要检查的内容。您应看到类似 port 80 namevhost example.com (/etc/apache2/sites-enabled/example.com.conf:1) 的行,并在其下方看到 alias www.example.com。Apache 报告的是它实际读取的 sites-enabled 符号链接,而不是您在 sites-available 中编辑的文件。如果端口 80 下没有列出 example.com,Certbot 也无法找到它。

签发证书:certbot --apache

sudo certbot --apache -d example.com -d www.example.com

首次运行时会询问3项内容:电子邮件地址(用于您的 ACME 账户和接收 CA 的紧急通知;Let's Encrypt 不再发送到期警告,因此您需要自行监控续期)、是否同意 Let's Encrypt 条款,以及是否允许将您的电子邮件地址共享给 EFF。现在不会再询问是否重定向:从 Certbot 2.0 开始,Apache 安装程序默认将 HTTP 重定向到 HTTPS,这正是您需要的行为。如果确实需要继续通过纯 HTTP 提供内容,请传入 --no-redirect

成功时会显示以下内容。请仔细阅读,不要略过:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2026-10-14.

Deploying certificate
Successfully deployed certificate for example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Successfully deployed certificate for www.example.com to /etc/apache2/sites-available/example.com-le-ssl.conf
Congratulations! You have successfully enabled HTTPS on https://example.com and https://www.example.com

在这条消息背后,Certbot 完成了4项操作:如果 Apache 尚未启用 ssl 模块,则启用该模块;写入 example.com-le-ssl.conf,即在 *:443 上创建原始虚拟主机的副本,并加入 SSLEngine on 和证书路径;启用该配置;最后在原始的80端口虚拟主机中加入 RewriteRule 块,将所有请求通过301重定向到 HTTPS。原始虚拟主机文件会被修改,而不是替换;SSL 配置副本会与其并列保存,您可以查看其中新增的每一行。

证书实际存放的位置,以及为什么绝不能复制它

所有文件都位于 /etc/letsencrypt/live/example.com/ 下:fullchain.pem(证书及中间证书链,服务器应指向此文件)、privkey.pem(私钥,仅 root 可读取),以及供需要分别使用这些内容的软件使用的 cert.pemchain.pem。这些文件都是指向 /etc/letsencrypt/archive/ 的符号链接。这个间接层就是续期机制:续期会将新文件写入 archive/,然后重新指向这些符号链接。让其他软件指向 live/ 中的路径,它们就能自动使用续期后的文件;如果将文件复制到其他位置,90 天后就会造成服务中断。

另一个值得了解的文件是 /etc/letsencrypt/renewal/example.com.conf。它记录了证书的签发方式、authenticator = apacheinstaller = apache 以及域名,因此续期时可以无人值守地重复整个流程,包括随后重新加载 Apache。

续期任务已安排,先验证,不要重复创建

Let's Encrypt 证书默认有效期为 90 天,apt 软件包已安装所需机制:一个 systemd timer,每天在随机时间运行 Certbot 两次,为距离到期不足 30 天的证书续期。不要再添加 cron 任务;第二个调度器只会增加日志噪声,并带来触发速率限制的风险。

systemctl list-timers certbot.timer
sudo certbot renew --dry-run

第一条命令用于确认 timer 已处于活动状态,并显示未来 24 小时内的某个 NEXT 时间。该任务每天运行两次,并带有随机延迟,因此具体执行时间会刻意保持不确定(使用 snap 安装时,timer 则是 snap.certbot.renew.timer)。dry run 会在 Let's Encrypt 的 staging 环境中完整演练续期流程:执行真实挑战,但不会签发证书,也不会消耗速率限制额度。成功结果最后应显示:

Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)

如果 dry run 失败,那么约 60 天后的实际续期也会以同样方式失败。现在就修复问题,因为当前证书仍处于完整有效期内。最常见的原因是签发证书后添加了防火墙规则,再次关闭了端口 80。

使用 curl 验证,以及浏览器锁形图标应显示的内容

curl -sI http://example.com | head -n 3
curl -I https://example.com
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -issuer -dates

第一个命令应返回 HTTP/1.1 301 Moved Permanently,并带有 Location: https://example.com/ 标头。这就是 Certbot 安装的重定向。第二个命令应返回 HTTP/1.1 200 OK,且 curl 不应报告 TLS 问题。第三个命令会打印签发者、包含短 CN(例如 R12E7)的 O = Let's Encrypt 行,以及大约在 90 天后到期的 notAfter。在浏览器中,您会看到锁形图标,点击它后应显示相同的签发者。如果 curl 正常工作,但浏览器发出警告,那么您看到的几乎肯定是缓存页面或错误的主机名,而不是证书问题。

多个站点:使用一个 SAN 证书,还是每个站点使用一个证书

两种方式都可以,续期方式也相同。对于同一台服务器上彼此无关的站点,每个站点分别运行一次签发命令。每个站点都会在 live/ 下拥有自己的目录和续期配置,其中一个域名出现问题时,不会阻止其他域名续期。这是我的默认做法。

对于包含多个名称的单个站点,将这些名称放入同一个 SAN 证书。一个证书最多可以包含 100 个名称。上文已经通过 example.comwww.example.com 完成了此操作。之后如果要向现有证书添加名称,请指定证书名称,并提供新的完整名称列表,重新签发证书:

sudo certbot --apache --cert-name example.com -d example.com -d www.example.com -d blog.example.com

Certbot 会检测到域名集合发生变化,要求您确认扩展,然后原地替换证书,仍使用相同的 live/ 路径,因此无需修改其他内容。请注意,这个列表会替换原列表,而不是追加:如果从该命令中省略 www,新证书会静默移除该名称。

通配符证书需要 DNS-01,但通常不需要通配符证书

HTTP-01 无法签发 *.example.com;在 Web 服务器上放置文件只能证明您控制了一个主机名,不能证明您控制了整个命名空间。通配符证书需要 DNS-01 challenge:Certbot 会在 _acme-challenge.example.com 设置 TXT 记录。实际操作中,这意味着使用带有 DNS 服务商 API 凭据的 certbot-dns-* 插件,或者在每次续期时手动编辑 TXT 记录并使用 --manual(非常繁琐,不要以此为方案)。从 TXT 记录的工作方式,到配置可无人值守续期的插件,完整步骤请参阅 使用 Certbot 通过 DNS-01 申请通配符证书。坦率地说:如果您已知有四个子域名,列出这四个域名的 SAN 证书比通配符证书更简单,而且不需要将 DNS API 密钥存放在服务器上。

故障模式及其对应的报错字符串

Certbot 因 Apache 配置损坏而无法启动。

The apache plugin is not working; there may be problems with your existing configuration.
The error was: MisconfigurationError('Error while running apache2ctl configtest.\n\nAction \'configtest\' failed.\nThe Apache error log may have more information.\n\nAH00526: Syntax error on line 12 of /etc/apache2/sites-enabled/example.com.conf')

插件会先运行 configtest,然后才执行其他操作。如果 Apache 本身存在问题,插件会立即退出。\ns 是字面内容,因为 Certbot 会输出异常的 repr。手动运行 sudo apache2ctl configtest。它会显示文件名和行号。常见原因包括手动编辑时的拼写错误、SSLCertificateFile指向已不存在的路径,或引用了但未启用的模块。修复问题,直到命令输出 Syntax OK,然后重新运行 Certbot。

没有 vhost 与该域名匹配。

Unable to find a virtual host listening on port 80 which is currently the only challenge port.

这是前文提到的缺少 ServerName 问题,会在签发证书时被捕获。Certbot 搜索了所有已启用的 80 端口 vhost,查找与您的 -d 匹配的 ServerName/ServerAlias,但没有找到。sudo apache2ctl -S 会显示 Apache 实际将请求路由到哪里。将 ServerName 行添加到正确的 vhost,重新加载配置后再试。另一种类似情况是验证请求到达了错误的 vhost。由于其他站点接收了请求,挑战响应返回 Invalid response ... 404。诊断方法相同,使用的工具也相同:apache2ctl -S

验证超时。

Certbot failed to authenticate some domains (authenticator: apache).
...
Detail: ...: Timeout during connect (likely firewall problem)

Let's Encrypt 无法在 DNS 公布的地址上打开到 80 端口的 TCP 连接。按可能性从高到低,原因包括:服务商的网络防火墙(与 ufw 分开,在托管面板中配置);ufw 规则只允许 443 或只允许 SSH;DNS 仍指向之前的服务器;以及过期的 AAAA 记录问题,即 Let's Encrypt 的服务器尝试使用 IPv6,而您的服务器只通过 IPv4 响应。请从 VPS 外部测试:在笔记本电脑上运行 curl -I http://example.com,即可复现验证器看到的结果。

反复重试,最终触发了速率限制。

Error creating new order :: too many failed authorizations recently: see https://letsencrypt.org/docs/rate-limits/

Let's Encrypt 允许每个账户对每个主机名每小时进行 5 次失败验证。自 2025 年速率限制调整后,该限制采用可恢复的令牌桶机制,大约每 12 分钟恢复 1 次重试额度。对损坏的防火墙反复重试会迅速耗尽额度。等待可以解决问题,但真正的修复方法是改变操作方式:每次失败后,都使用 staging 环境进行调试,直到验证成功。

sudo certbot certonly --apache --dry-run -d example.com -d www.example.com

注意 certonly:只有 certonlyrenew 子命令接受 --dry-run,直接使用 certbot --apache --dry-run 则会拒绝运行,并提示 --dry-run currently only works with the 'certonly' or 'renew' subcommands。dry run 会在 staging 环境中执行验证。该环境具有更宽松的限制,并且不会签发真实证书,因此您可以在其中反复失败。只有 staging 验证通过后,才重新运行实际命令。其他限制包括每个注册域每周最多 50 张证书,以及每周最多 5 次相同名称集合的重复申请。只有脚本循环重新申请证书时,才可能触及这些限制。

HTTPS 启用后,请记住,证书保护的是传输,而不是服务器本身:22 端口仍可能全天遭受密码猜测。下一步自然是结合 在 Ubuntu 24.04 上配置 Fail2ban,继续用约 30 分钟完成加固。

FAQ

对于 Ubuntu 24.04 上的 Apache,应通过 snap 还是 apt 安装 Certbot?

使用 apt。Ubuntu 24.04 提供 Certbot 2.9.0,已足以支持本指南中的所有内容,可通过 unattended-upgrades 获取安全补丁,并且不需要 snapd。只有在需要立即使用最新版本,或需要仅以 snap 形式提供的 DNS 插件时,才选择 snap。如果切换,请先执行 apt remove certbot python3-certbot-apache,避免两个续期调度器同时运行。

为什么 Certbot 提示“无法找到监听端口 80 的虚拟主机”?

因为没有启用的端口 80 虚拟主机包含与您通过 -d 传入的域名匹配的 ServerNameServerAlias。Ubuntu 的默认虚拟主机将 ServerName 注释掉了。运行 sudo apache2ctl -S,找到或创建应负责该域名的虚拟主机,添加 ServerName example.com,重新加载 Apache,然后再次运行 Certbot。

如何修复“连接超时(可能是防火墙问题)”?

Let's Encrypt 无法通过 DNS 发布的地址访问端口 80。检查服务商控制面板级别的网络防火墙以及 ufw,确认 dig +short example.com 返回此 VPS,并删除或修正过期的 AAAA 记录。只要存在 IPv6 地址,验证就会优先使用 IPv6。使用 curl -I http://example.com 从服务器外部确认修复结果,然后在正式签发前使用 sudo certbot certonly --apache --dry-run -d example.com 进行演练。

Certbot 会在 Ubuntu 24.04 上自动续期证书吗?

会。apt 软件包会安装 certbot.timer,这是一个 systemd 定时器,每天运行两次,并为距离到期不超过 30 天的证书续期,随后重新加载 Apache;snap 使用 snap.certbot.renew.timer 执行相同的任务。使用 systemctl list-timers certbot.timer 验证,并通过 sudo certbot renew --dry-run 进行演练。不要在此基础上再添加自己的 cron 任务。

如何使用 Certbot 和 Apache 获取通配符证书?

通配符证书需要 DNS-01 challenge:Certbot 必须在 _acme-challenge.example.com 处创建 TXT 记录。这需要使用带有 DNS 服务商 API 凭据的 certbot-dns-* 插件;--manual 方案则要求每次续期时手动编辑 TXT 记录。如果只有少量已知子域名,直接明确列出这些域名的 SAN 证书更简单,也能避免将 DNS API 密钥放在服务器上。