在 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 配置并安排自动续期。
一个典型流程是这样的:
- 浏览器访问
https://your_domain - Apache 从
/etc/letsencrypt/live/your_domain/读取证书并返回 - 首次申请证书时,Certbot 通过 Apache 插件或临时挑战文件,在 80 端口 上完成域名控制校验
- ACME 校验通过后签发证书
- 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_domain和www.your_domain的 DNSA记录指向服务器公网 IP- 已安装 Apache
- 已创建虚拟主机文件,例如:
/etc/apache2/sites-available/your_domain.conf
- 可选但推荐:启用 UFW
如果 DNS 还没生效,或者域名指向的不是当前服务器,后面执行 certbot --apache 基本一定失败。
如何先确认环境没有跑偏?
结论:先验证系统版本、Apache 版本、OpenSSL 版本和 Apache 运行状态,可以省掉不少排错时间。
检查 Ubuntu 版本:
lsb_release -ds
期望输出之一:
Ubuntu 22.04.x LTSUbuntu 24.04.x LTSUbuntu 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/a2ensiteapachectl configtest- UFW
Apache Full - 证书目录
/etc/letsencrypt/
如果发现 certbot 调到错误版本,直接检查:
which -a certbot
正确目标通常应当包含:
/snap/bin/certbot
/usr/bin/certbot
并且 /usr/bin/certbot 应软链接到 /snap/bin/certbot。
Apache 虚拟主机需要满足什么条件?
结论:ServerName 和 ServerAlias 必须正确,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
过程中会依次要求:
- 输入接收续期和安全通知的邮箱
- 同意订阅者协议
- 选择是否订阅邮件列表
- 选择需要包含在证书中的域名,例如:
your_domainwww.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_domainhttps://www.your_domain
浏览器应当显示受信任锁标识。
证书文件保存在哪里?
结论:日常最常用的是 fullchain.pem 和 privkey.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 配置足够稳妥”。
至少要做三件事:
- 禁用旧协议
- 开启 OCSP stapling
- 增加 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:浏览器后续强制走 HTTPSX-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
优先检查这几项:
- 80 端口是否仍能从公网访问
- UFW 和云防火墙是否同时放行
- DNS 是否仍指向当前服务器
- Apache 是否能正确响应
/.well-known/acme-challenge/
修复后重新测试:
sudo certbot renew --dry-run
不要只依赖证书到期邮件提醒。生产环境应有独立监控。
常见故障分别怎么处理?
结论:大部分问题都能归类到域名校验失败、Apache 配置异常、限额命中、错误的 Certbot 安装来源这几类。
域名校验失败怎么办?
先检查 DNS:
dig +short your_domain A
返回结果应与服务器公网 IP 一致。
如果报错里出现 503、unauthorized,通常意味着:
- 域名虽已解析,但请求没有正确到达这个 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/tcp443/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 配置与续期监控不能省。
关于
关注我获取更多资讯