# Apache 配置 Let's Encrypt 免费证书：Certbot 教程

> 用 Certbot 给 Apache httpd 2.4 申请 Let's Encrypt 免费 SSL 证书，配置 443 虚拟主机、HTTP 跳转 HTTPS 和自动续期。

Source: https://ssl.sh/zh/guides/apache-lets-encrypt-certbot/
Last updated: 2026-11-10

Apache httpd 2.4 用 Certbot 的 Apache 插件配置 Let's Encrypt 证书：运行 `sudo certbot --apache`，Certbot 会为 `example.com` 和 `www.example.com` 签发证书、生成 443 虚拟主机、加上 HTTP 跳转，之后自动续期。适用于 Ubuntu 22.04/24.04、Debian 12/13 和 Rocky/AlmaLinux 9/10 等 RHEL 系发行版，Certbot 4.1 及以上。

## 前提条件

Let's Encrypt 需要从公网通过 80 端口访问你的服务器。

- 带 systemd 和 snapd 的 Linux 服务器，有 sudo 权限。
- 已安装 Apache 2.4，80 端口的虚拟主机能正常访问，`ServerName`/`ServerAlias` 和要申请的域名一致。
- `example.com`、`www.example.com` 的 A/AAAA 记录指向服务器，例如 `203.0.113.10`。
- 服务器在中国大陆的，域名需已 ICP 备案。
- 系统防火墙和云服务器安全组对所有来源放行 TCP 80、443。

```bash
dig +short example.com A
sudo ufw allow 'Apache Full'          # Debian/Ubuntu 用 ufw 时
sudo firewall-cmd --permanent --add-service=http --add-service=https && sudo firewall-cmd --reload   # CentOS/Rocky
```

## 第一步：启用 mod_ssl 并检查虚拟主机

没有 mod_ssl，Certbot 无法生成 443 虚拟主机。Debian/Ubuntu：

```bash
sudo a2enmod ssl headers
sudo systemctl reload apache2
```

CentOS、Rocky、AlmaLinux：

```bash
sudo dnf install mod_ssl
sudo systemctl reload httpd
```

80 端口的虚拟主机要明确写出域名：

```apache
# /etc/apache2/sites-available/example.com.conf
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com
</VirtualHost>
```

```bash
sudo a2ensite example.com.conf
sudo apachectl configtest && sudo systemctl reload apache2
```

## 第二步：安装 Certbot

snap 是官方推荐的安装方式，自带 Apache 插件：

```bash
sudo apt-get remove certbot     # CentOS/Rocky 用 sudo dnf remove certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
```

不能用 snap 的，按 certbot.eff.org 的 pip 说明把 `certbot certbot-apache` 装到 `/opt/certbot`。

## 第三步：申请证书并自动配置 Apache

一条 `certbot --apache` 命令完成验证、签发和 Apache 配置，证书要包含的域名都用 `-d` 写上：

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

Certbot 用 HTTP-01 验证域名，生成 SSL 虚拟主机，询问是否加 HTTP 跳转（选是），然后重载 Apache。邮箱可以不填，Let's Encrypt 从 2025 年 6 月 4 日起不再发到期提醒邮件。只想申请证书、不改配置的，用 `sudo certbot certonly --apache -d example.com -d www.example.com`。

## 第四步：检查 SSL 虚拟主机

Certbot 生成的 443 虚拟主机引用 `fullchain.pem` 和 `privkey.pem`。自己维护配置时，下面这份和 Certbot 生成的效果相同：

```apache
<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com

    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    Protocols h2 http/1.1
</VirtualHost>

SSLProtocol -all +TLSv1.2 +TLSv1.3

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    Redirect permanent / https://example.com/
</VirtualHost>
```

`Protocols h2` 需要 mod_http2（`sudo a2enmod http2`）。不要开启 `SSLUseStapling`，Let's Encrypt 证书里已经没有 OCSP 地址。检查并重载：

```bash
sudo apachectl configtest && sudo systemctl reload apache2
```

## 验证

配置正确时，证书颁发者是 Let's Encrypt，HTTP 请求返回指向 `https://` 的 Location 头。用 [SSL 证书检查](https://ssl.sh/zh/tools/ssl-checker/) 从外部检查，或在终端运行：

```bash
curl ssl.sh/example.com
```

在服务器上：

```bash
sudo certbot certificates
curl -sI http://example.com | grep -i '^location'
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates
```

## 自动续期

snap 自带的 systemd 定时器每天运行两次 `certbot renew`；Certbot 4.1 及以上按 Let's Encrypt 的 ARI 建议时间续期，没有 ARI 时在剩余三分之一有效期时续期。用 `--apache` 安装的证书续期后会自动重载 Apache。

```bash
systemctl list-timers | grep certbot
sudo certbot renew --dry-run
```

用 `certonly` 申请的证书要加重载钩子（Debian/Ubuntu 是 `apache2`，CentOS/Rocky 是 `httpd`）：

```bash
sudo certbot reconfigure --cert-name example.com --deploy-hook "systemctl reload apache2"
```

更多写法见 [Certbot 续期钩子](https://ssl.sh/zh/guides/certbot-renewal-hooks/)。2027 年 2 月 10 日 Let's Encrypt 默认证书改为 64 天，定时器照常工作，不用改配置。Let's Encrypt 不再发提醒邮件，建议加到 [ssl.sh 监控](https://ssl.sh/zh/monitor/)（开发中）。

## 常见问题排查

- **Invalid command 'SSLEngine'**：没加载 mod_ssl，运行 `sudo a2enmod ssl` 或安装 `mod_ssl`。
- **Unable to find a virtual host listening on port 80**：按第一步建好 `*:80` 虚拟主机，`ServerName` 要对得上。
- **Timeout during connect**：80 端口不通（安全组、运营商封端口、未备案）或解析错误，见 [certbot 连接超时](https://ssl.sh/zh/errors/certbot-timeout-during-connect/)。
- 浏览器报 **ERR_SSL_PROTOCOL_ERROR**：443 虚拟主机里没写 `SSLEngine on`，Apache 在 443 上返回明文 HTTP，见 [ERR_SSL_PROTOCOL_ERROR](https://ssl.sh/zh/errors/err-ssl-protocol-error/)。
- 浏览器正常、**curl 或 Java 报错**：证书链不完整，见 [缺少中间证书](https://ssl.sh/zh/errors/missing-intermediate-certificate/)。
- **www 访问提示证书域名不匹配**：证书里没有这个域名，见 [NET::ERR_CERT_COMMON_NAME_INVALID](https://ssl.sh/zh/errors/net-err-cert-common-name-invalid/)。
