在 Ubuntu 上用 Let’s Encrypt 为 Apache 配置 HTTPS

讲清如何在 Ubuntu 22.04、24.04、26.04 上为 Apache 安装 Certbot、签发 Let’s Encrypt 证书、加固 TLS 配置并验证自动续期。

阅读时长: 9 分钟
共 4204字
作者: eimoon.com

在 Ubuntu 上用 Let’s Encrypt 为 Apache 配置 HTTPS

Apache 开启 HTTPS 的标准做法已经很明确:在 Ubuntu 上安装 Certbot,确认 Apache 虚拟主机配置正确,开放 80/443 端口,执行 sudo certbot --apache 申请证书,然后补上 TLS 与 HTTP 安全头加固,最后验证自动续期是否正常。

适用环境:

  • Ubuntu 22.04 LTS
  • Ubuntu 24.04 LTS
  • Ubuntu 26.04 LTS
  • Apache 2.4
  • 使用独立虚拟主机文件,而不是只依赖默认站点

如果目标只是“让浏览器不报不安全”,做到证书签发即可;如果目标是生产环境可长期运行,还需要处理续期、协议版本、OCSP stapling 和 HSTS。

Let’s Encrypt 和 Certbot 到底解决了什么问题?

结论:Let’s Encrypt 负责签发免费的 DV TLS 证书,Certbot 负责和 ACME 接口交互、完成域名控制校验、写入 Apache 配置并安排自动续期。

一个典型流程是这样的:

  1. 浏览器访问 https://your_domain
  2. Apache 从 /etc/letsencrypt/live/your_domain/ 读取证书并返回
  3. 首次申请证书时,Certbot 通过 Apache 插件或临时挑战文件,在 80 端口 上完成域名控制校验
  4. ACME 校验通过后签发证书
  5. systemd timer 定期执行 certbot renew,在证书过期前自动续期

有两个边界条件必须先说清:

  • 默认的 HTTP-01 验证依赖 80 端口可从公网访问
  • Let’s Encrypt 不保存你的私钥,私钥只在服务器本地保存

证书默认有效期是 90 天,Certbot 通常会在距离过期 30 天以内 开始尝试续期。

开始前需要满足哪些条件?

结论:证书签发失败,大多数不是 Certbot 本身的问题,而是 DNS、虚拟主机、80 端口三者之一没准备好。

准备项如下:

  • 一台 Ubuntu 22.04 / 24.04 / 26.04 LTS 服务器
  • 一个非 root 的 sudo 用户
  • 已注册域名
  • your_domainwww.your_domain 的 DNS A 记录指向服务器公网 IP
  • 已安装 Apache
  • 已创建虚拟主机文件,例如:
    • /etc/apache2/sites-available/your_domain.conf
  • 可选但推荐:启用 UFW

如果 DNS 还没生效,或者域名指向的不是当前服务器,后面执行 certbot --apache 基本一定失败。

如何先确认环境没有跑偏?

结论:先验证系统版本、Apache 版本、OpenSSL 版本和 Apache 运行状态,可以省掉不少排错时间。

检查 Ubuntu 版本:

lsb_release -ds

期望输出之一:

  • Ubuntu 22.04.x LTS
  • Ubuntu 24.04.x LTS
  • Ubuntu 26.04.x LTS

检查 Apache 版本:

apache2 -v

示例输出首行可能是:

Server version: Apache/2.4.58 (Ubuntu)

不同 LTS 版本的默认仓库 Apache 版本大致如下:

Ubuntu LTS 代号 默认仓库 Apache 版本(约)
22.04 Jammy 2.4.52 或更新
24.04 Noble 2.4.58 或更新
26.04 Resolute 2.4.x,以 apache2 -v 实际输出为准

检查 OpenSSL:

openssl version

当前 Ubuntu 22.04 及以上一般都是 OpenSSL 3.x,足够支持 TLS 1.2 / 1.3。

确认 Apache 已运行:

sudo systemctl is-active apache2

期望结果:

active

如果 Apache 还没安装,这一步先不要往下跳。

在 Ubuntu 上应该怎样安装 Certbot?

结论:Ubuntu 22.04、24.04、26.04 上优先使用 snap 版 Certbot,不要继续沿用老的 apt install certbot 路径。

先更新包并安装 snapd

sudo apt update
sudo apt install snapd -y

安装并刷新 snap 核心运行时:

sudo snap install core
sudo snap refresh core

移除旧的 apt 版 Certbot,避免命令指向错误二进制:

sudo apt remove certbot python3-certbot-apache 2>/dev/null || true

安装 snap 版 Certbot:

sudo snap install --classic certbot

建立软链接,确保命令可直接使用:

sudo ln -sf /snap/bin/certbot /usr/bin/certbot

检查版本:

certbot --version

检查插件:

sudo certbot plugins

输出里应当能看到 apache 插件。

再确认 snap 和续期定时器状态:

snap list certbot
systemctl list-timers --all | grep -i certbot

在 snap 安装场景下,常见定时器名是:

  • snap.certbot.renew.timer

Ubuntu 26.04 有额外差异吗?

结论:没有本质差异,路径和工具链基本一致。

这些路径和命令仍然成立:

  • /etc/apache2/
  • a2ensite
  • apachectl configtest
  • UFW Apache Full
  • 证书目录 /etc/letsencrypt/

如果发现 certbot 调到错误版本,直接检查:

which -a certbot

正确目标通常应当包含:

/snap/bin/certbot
/usr/bin/certbot

并且 /usr/bin/certbot 应软链接到 /snap/bin/certbot

Apache 虚拟主机需要满足什么条件?

结论:ServerNameServerAlias 必须正确,Certbot 才能识别要为哪些域名签证书。

编辑站点配置:

sudo nano /etc/apache2/sites-available/your_domain.conf

确保 VirtualHost *:80 里至少有这两行:

ServerName your_domain
ServerAlias www.your_domain

然后启用站点和 SSL 模块:

sudo a2ensite your_domain.conf
sudo a2enmod ssl
sudo systemctl reload apache2

每次改完配置都先做语法检查:

sudo apachectl configtest

期望输出:

Syntax OK

确认无误后再重载:

sudo systemctl reload apache2

如果这里写错域名,后续最典型的问题就是:

  • 域名不出现在 Certbot 可选列表里
  • 申请到了错误的证书
  • 某个站点被并入另一个证书

多站点环境里,建议按站点逐个执行 certbot --apache,而不是一次性“全选所有域名”。

防火墙应该怎么放行?

结论:如果 UFW 已启用,应使用 Apache Full,并且 80 端口不要在启用 HTTPS 后关闭

先查看当前规则:

sudo ufw status

如果当前只允许了 Apache,继续执行:

sudo ufw allow 'Apache Full'

如果纯 Apache 规则已经冗余,可以删除:

sudo ufw delete allow 'Apache'

再次确认:

sudo ufw status

常见 UFW profile 对比如下:

UFW profile 端口 用途
Apache 80/tcp 只开 HTTP
Apache Full 80/tcp, 443/tcp 同时开 HTTP 和 HTTPS
Apache (v6) / Apache Full (v6) IPv6 对应端口 双栈主机

HTTP-01 续期依赖 80 端口。即使网站已经全站跳转 HTTPS,也不要把 80 关掉,除非改用 DNS-01 等别的验证方式。

怎样正式申请 Let’s Encrypt 证书?

结论:Apache 场景最省事的方式就是直接执行 sudo certbot --apache

运行命令:

sudo certbot --apache

过程中会依次要求:

  1. 输入接收续期和安全通知的邮箱
  2. 同意订阅者协议
  3. 选择是否订阅邮件列表
  4. 选择需要包含在证书中的域名,例如:
    • your_domain
    • www.your_domain

成功后,典型输出类似这样:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/your_domain/privkey.pem
This certificate expires on YYYY-MM-DD.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

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

完成后可直接访问:

  • https://your_domain
  • https://www.your_domain

浏览器应当显示受信任锁标识。

证书文件保存在哪里?

结论:日常最常用的是 fullchain.pemprivkey.pem,其他文件主要用于排障和理解证书结构。

路径 用途
/etc/letsencrypt/live/your_domain/fullchain.pem 证书加中间证书链,Apache 的 SSLCertificateFile 常用它
/etc/letsencrypt/live/your_domain/privkey.pem 私钥,Apache 的 SSLCertificateKeyFile 使用它
/etc/letsencrypt/live/your_domain/cert.pem 仅域名证书
/etc/letsencrypt/live/your_domain/chain.pem 中间证书链
/etc/letsencrypt/live/your_domain/README Certbot 说明文件
/etc/letsencrypt/renewal/your_domain.conf 当前证书的续期配置

需要注意:

  • live/ 下通常是符号链接
  • 续期后链接目标会更新
  • 不要手工改这些证书文件内容

只申请到证书够不够?

结论:不够。Certbot 解决了“有 HTTPS”,但没有自动完成“TLS 配置足够稳妥”。

至少要做三件事:

  1. 禁用旧协议
  2. 开启 OCSP stapling
  3. 增加 HSTS 和常见安全头

如何加固 TLS 协议和密码套件?

结论:生产环境至少保留 TLS 1.2 和 TLS 1.3,禁用 TLS 1.0 / 1.1。

先启用 headers 模块:

sudo a2enmod headers

编辑 SSL 模块配置:

sudo nano /etc/apache2/mods-available/ssl.conf

加入或更新以下内容:

# Allow TLS 1.2 and 1.3 only. Drop SSLv3, TLS 1.0, and TLS 1.1.
SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1

# Prefer modern AEAD ciphers. Apache negotiates the best match with clients.
SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384

# Let the client pick the cipher order (recommended for TLS 1.3).
SSLHonorCipherOrder     off

# OCSP stapling: Apache attaches revocation status to the handshake.
SSLUseStapling          on
SSLStaplingCache        "shmcb:${APACHE_RUN_DIR}/ssl_stapling(32768)"

协议支持情况可概括为:

协议 Ubuntu 22.04/24.04/26.04 上的 Apache 2.4 说明
TLS 1.3 支持 现代客户端默认优先
TLS 1.2 支持 生产环境最低建议
TLS 1.1 及以下 应禁用 维持较好安全评级所必需

如果还要兼容极老旧客户端,这套配置可能过严;但对公开网站和 API,禁用 TLS 1.1 及以下通常是合理默认值。

HSTS 和安全响应头要不要配?

结论:要配,但 HSTS 要确认自己真的准备好全站 HTTPS 后再上。

编辑 Certbot 生成的 SSL 虚拟主机文件,文件名通常类似:

sudo nano /etc/apache2/sites-available/your_domain-le-ssl.conf

<VirtualHost *:443> 中加入:

# Tell browsers to use HTTPS for one year, including subdomains.
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

# Reduce MIME sniffing attacks.
Header always set X-Content-Type-Options "nosniff"

# Limit embedding in frames (adjust if you need iframes).
Header always set X-Frame-Options "SAMEORIGIN"

然后检查并重载:

sudo apachectl configtest
sudo systemctl reload apache2

这几项的实际作用分别是:

  • Strict-Transport-Security:浏览器后续强制走 HTTPS
  • X-Content-Type-Options: nosniff:减少 MIME 嗅探带来的风险
  • X-Frame-Options: SAMEORIGIN:限制页面被其他站点 iframe 嵌入

HSTS 的限制条件也很明确:

  • 如果某些子域名还没准备好 HTTPS,includeSubDomains 可能带来可用性问题
  • 配了长 max-age 后,浏览器缓存期间不容易撤回

如果基础设施还在调整阶段,可以先不用 HSTS,或者缩短 max-age 做灰度验证。

自动续期怎么确认是真的可用?

结论:不要假设 Certbot 会自动续期;必须手工验证 timer 和 dry-run。

先检查定时器状态:

sudo systemctl status snap.certbot.renew.timer

如果这个单元不存在,再试:

sudo systemctl status certbot.timer

列出所有 Certbot 相关定时器:

systemctl list-timers | grep -i certbot

执行模拟续期:

sudo certbot renew --dry-run

成功时通常会看到:

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

这一步非常关键。因为真正的生产事故往往不是“第一次签不下来”,而是“三个月后悄悄过期”。

续期失败时优先查什么?

结论:先看日志,再查 80 端口和 DNS,最后再怀疑 Apache 配置。

日志文件:

sudo less /var/log/letsencrypt/letsencrypt.log

优先检查这几项:

  1. 80 端口是否仍能从公网访问
  2. UFW 和云防火墙是否同时放行
  3. DNS 是否仍指向当前服务器
  4. Apache 是否能正确响应 /.well-known/acme-challenge/

修复后重新测试:

sudo certbot renew --dry-run

不要只依赖证书到期邮件提醒。生产环境应有独立监控。

常见故障分别怎么处理?

结论:大部分问题都能归类到域名校验失败、Apache 配置异常、限额命中、错误的 Certbot 安装来源这几类。

域名校验失败怎么办?

先检查 DNS:

dig +short your_domain A

返回结果应与服务器公网 IP 一致。

如果报错里出现 503unauthorized,通常意味着:

  • 域名虽已解析,但请求没有正确到达这个 Apache 站点
  • Apache 临时 challenge 路径返回了错误状态
  • 80 端口被拦截
  • 反向代理或上游 WAF 干扰了验证请求

这种场景里,重点检查:

  • ServerName / ServerAlias
  • UFW 规则
  • 云防火墙规则
  • 域名指向是否正确

Certbot 运行时 Apache 插件报错怎么办?

先检查当前二进制来源:

which -a certbot

如果仍在使用老的 apt 版,容易碰到插件解析异常,尤其是涉及复杂 Include 配置时。建议移除 apt 版 Certbot,统一切回 snap 版。

同时执行:

sudo apachectl configtest

确保 Apache 配置本身没有语法错误。

多个站点时,为什么新域名没出现在列表里?

先确认两点:

  • 该站点 .conf 文件已经存在
  • 已执行 a2ensite 启用,并且 Apache 已 reload

还要确认配置里确实有:

ServerName your_domain
ServerAlias www.your_domain

如果虚拟主机未启用,或者域名声明不完整,Certbot 不会把它识别成可申请目标。

命中了 Let’s Encrypt 限额怎么办?

Let’s Encrypt 有速率限制。一个明确的限制是:

  • 每个注册域每周最多 50 张证书

排查阶段不要反复真签,可以使用 staging 环境:

sudo certbot --apache --staging

注意:

  • staging 证书不被浏览器信任
  • 只适合测试流程,不适合正式上线

防火墙为什么会影响已经上线的网站续期?

因为默认续期仍走 HTTP-01,而 HTTP-01 依赖 80 端口。很多人上线后只保留 443,结果三个月后证书续不上。

默认方案下,至少要保留:

  • 80/tcp
  • 443/tcp

Let’s Encrypt 和付费 CA 应该怎么选?

结论:绝大多数公开网站、API、个人项目、内部公开服务,Let’s Encrypt 已经足够;只有在需要 OV/EV、合规材料或厂商支持时,才值得考虑付费 CA。

维度 Let’s Encrypt 付费 CA
成本 免费 按年付费或订阅
验证类型 DV DV / OV / EV
证书有效期 90 天,依赖自动续期 通常 1 年
泛域名 支持,需 DNS-01 支持,通常配套支持更完善
支持方式 社区文档与论坛 厂商 SLA、电话或工单支持
适用场景 公网站点、API、homelab 企业品牌展示、遗留政策要求、特定合规场景

选择标准并不复杂:

适合 Let’s Encrypt 的情况:

  • 能控制服务器
  • 能接受自动续期
  • 只需要标准 DV HTTPS

适合付费 CA 的情况:

  • 组织要求 OV/EV
  • 有审计或采购流程要求
  • 需要供应商支持合同

一份可直接执行的最小操作清单是什么?

结论:如果环境已准备好,按下面顺序走即可。

lsb_release -ds
apache2 -v
openssl version
sudo systemctl is-active apache2

sudo apt update
sudo apt install snapd -y
sudo snap install core
sudo snap refresh core
sudo apt remove certbot python3-certbot-apache 2>/dev/null || true
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot
certbot --version
sudo certbot plugins

sudo nano /etc/apache2/sites-available/your_domain.conf
sudo a2ensite your_domain.conf
sudo a2enmod ssl
sudo apachectl configtest
sudo systemctl reload apache2

sudo ufw allow 'Apache Full'
sudo ufw delete allow 'Apache'
sudo ufw status

sudo certbot --apache

sudo a2enmod headers
sudo nano /etc/apache2/mods-available/ssl.conf
sudo nano /etc/apache2/sites-available/your_domain-le-ssl.conf
sudo apachectl configtest
sudo systemctl reload apache2

sudo systemctl status snap.certbot.renew.timer
systemctl list-timers | grep -i certbot
sudo certbot renew --dry-run

上线后还应该再做什么?

结论:至少做两件事,外部验证和持续监控。

建议补充:

  • 用 SSL Labs Server Test 对域名做一次外部检测
  • 给证书过期时间接入监控系统
  • 配置变更前先跑 apachectl configtest
  • 保留配置备份,避免 Certbot 修改后难以回滚

如果只是快速搭一个站点,做到证书签发和自动续期即可;如果是生产环境,TLS 配置与续期监控不能省。

关于

关注我获取更多资讯

月球基地博客公众号二维码,扫码关注获取更多 AI 与编程资讯
📢 公众号
月球基地博客作者个人微信二维码,扫码交流 AI 与编程话题
💬 个人号
使用 Hugo 构建
主题 StackJimmy 设计