强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Certbot 证书自动化教程 / 第 7 章:Apache 集成

第 7 章:Apache 集成

7.1 Apache 插件概述

Certbot 的 Apache 插件能够自动完成域名验证并修改 Apache 配置,实现 SSL/TLS 的一键部署。与 Nginx 插件类似,它能自动识别 Apache 虚拟主机配置并进行修改。

插件能力

功能说明
自动验证通过 Apache 响应 ACME HTTP-01 验证
自动配置 SSL修改虚拟主机配置,添加 SSL 指令
HTTPS 重定向自动添加 HTTP → HTTPS 重定向
模块管理自动启用必要的 SSL 模块
虚拟主机识别自动识别并匹配 server_name

所需 Apache 模块

模块用途启用命令
mod_sslSSL/TLS 支持a2enmod ssl
mod_rewriteURL 重写(HTTPS 重定向)a2enmod rewrite
mod_headers响应头操作(HSTS)a2enmod headers
mod_socache_shmcbOCSP Stapling 缓存a2enmod socache_shmcb

7.2 安装与基本使用

安装 Apache 插件

# Debian / Ubuntu
sudo apt update
sudo apt install -y apache2 python3-certbot-apache

# CentOS / RHEL / Fedora
sudo dnf install -y httpd python3-certbot-apache

# 启用必要模块
sudo a2enmod ssl rewrite headers socache_shmcb
sudo systemctl restart apache2

基本命令

# 为单个域名申请证书并自动配置 Apache
sudo certbot --apache -d example.com

# 为多个域名申请证书
sudo certbot --apache -d example.com -d www.example.com

# 交互式选择域名
sudo certbot --apache

# 仅获取证书,不修改 Apache 配置
sudo certbot certonly --apache -d example.com

执行过程

运行 certbot --apache 后,Certbot 会:

  1. 读取 Apache 配置文件,识别匹配的 VirtualHost
  2. 通过 Apache 响应 ACME HTTP-01 验证
  3. 申请证书
  4. 创建 SSL 虚拟主机配置
  5. 可选:添加 HTTP → HTTPS 重定向
  6. 测试 Apache 配置语法
  7. 重新加载 Apache

7.3 Apache 配置自动修改

修改前的配置

# /etc/apache2/sites-available/example.com.conf
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/html
    <Directory /var/www/html>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

修改后的配置

Certbot 会创建一个新的 SSL 虚拟主机:

# HTTP 虚拟主机(添加重定向)
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =example.com [OR]
    RewriteCond %{SERVER_NAME} =www.example.com
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

# 新增 HTTPS 虚拟主机
<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/html
    <Directory /var/www/html>
        AllowOverride All
        Require all granted
    </Directory>

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>

7.4 SSL 安全加固

Certbot 生成的 SSL 配置

/etc/letsencrypt/options-ssl-apache.conf 内容:

# OCSP Stapling
SSLUseStapling On
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache shmcb:/var/run/ocsp(128000)

# Session 配置
SSLSessionCache shmcb:/var/run/ssl_scache(512000)
SSLSessionCacheTimeout 300

# 协议和密码套件
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
SSLCompression off

增强安全配置

在 Certbot 生成配置的基础上,在 VirtualHost 中添加:

<VirtualHost *:443>
    ServerName example.com

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCACertificateFile /etc/letsencrypt/live/example.com/chain.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    # OCSP Stapling(如未在全局配置中启用)
    SSLUseStapling On
    SSLStaplingCache shmcb:/var/run/ocsp(128000)

    # 安全响应头
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    Header always set X-Frame-Options DENY
    Header always set X-Content-Type-Options nosniff
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
</VirtualHost>

启用 HSTS

# 在 SSL 虚拟主机中添加
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

警告: 启用 HSTS 后,浏览器会强制使用 HTTPS 访问。确保你的站点完全支持 HTTPS 后才启用,否则会导致用户无法访问。

HSTS 参数说明

参数说明建议值
max-age浏览器缓存 HSTS 的时间(秒)63072000(2 年)
includeSubDomains应用到所有子域名视情况而定
preload可加入浏览器预加载列表确认后启用

HSTS 预加载

申请加入浏览器 HSTS 预加载列表:

  1. 确保站点完全支持 HTTPS
  2. 设置 max-age 至少为 31536000(1 年)
  3. 包含 includeSubDomainspreload 指令
  4. 访问 hstspreload.org 提交申请

7.5 反向代理配置

Apache 反向代理到后端应用

<VirtualHost *:443>
    ServerName app.example.com

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/app.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/app.example.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    # 启用代理模块
    ProxyPreserveHost On
    ProxyPass / http://127.0.0.1:3000/
    ProxyPassReverse / http://127.0.0.1:3000/

    # WebSocket 支持
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /(.*) ws://127.0.0.1:3000/$1 [P,L]
</VirtualHost>

启用必要模块

sudo a2enmod proxy proxy_http proxy_wstunnel rewrite
sudo systemctl restart apache2

7.6 虚拟主机模板

标准 HTTPS 虚拟主机模板

# /etc/apache2/sites-available/example.com.conf

# HTTP 重定向
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    # ACME 验证路径
    Alias /.well-known/acme-challenge/ /var/www/certbot/.well-known/acme-challenge/
    <Directory "/var/www/certbot/.well-known/acme-challenge/">
        Options None
        AllowOverride None
        Require all granted
    </Directory>

    # 重定向到 HTTPS
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
    RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>

# HTTPS 站点
<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com

    # SSL 配置
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCACertificateFile /etc/letsencrypt/live/example.com/chain.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    # 安全头
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
    Header always set X-Content-Type-Options nosniff
    Header always set X-Frame-Options DENY

    # 文档根目录
    <Directory /var/www/example.com>
        AllowOverride All
        Require all granted
    </Directory>

    # 日志
    ErrorLog ${APACHE_LOG_DIR}/example.com_error.log
    CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined
</VirtualHost>

启用配置

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

7.7 多站点配置

场景:一台 Apache 托管多个 HTTPS 站点

# 为多个站点申请证书
sudo certbot --apache \
  -d site1.com -d www.site1.com \
  -d site2.com -d www.site2.com \
  -d api.site3.com
# 分别为每个站点申请
sudo certbot --apache -d site1.com -d www.site1.com
sudo certbot --apache -d site2.com -d www.site2.com
sudo certbot --apache -d api.site3.com

使用通配符证书

# 使用 DNS 验证申请通配符证书
sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
  -d example.com \
  -d "*.example.com"

# 手动配置多个虚拟主机使用同一个通配符证书
# /etc/apache2/sites-available/app.example.com.conf
<VirtualHost *:443>
    ServerName app.example.com
    DocumentRoot /var/www/app

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    <Directory /var/www/app>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

7.8 Let’s Encrypt 验证路径配置

确保 ACME 路径可访问

# 在 HTTP 虚拟主机中配置
<VirtualHost *:80>
    ServerName example.com

    # ACME 验证路径(HTTPS 重定向前)
    Alias /.well-known/acme-challenge/ /var/www/certbot/.well-known/acme-challenge/
    <Directory "/var/www/certbot/.well-known/acme-challenge/">
        Options None
        AllowOverride None
        Require all granted
    </Directory>

    # 非 ACME 请求重定向到 HTTPS
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
    RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>

7.9 常见问题排错

问题 1:模块未启用

AH00526: Syntax error on line XX of /etc/apache2/sites-enabled/...
Invalid command 'SSLEngine'

解决方案:

sudo a2enmod ssl
sudo systemctl restart apache2

问题 2:端口 443 未监听

no listening sockets available, shutting down

解决方案:

# 确认 Apache 配置中包含 443 端口监听
grep -r "Listen" /etc/apache2/ports.conf
# 应该有:
# Listen 80
# Listen 443

# 如果没有,编辑 ports.conf
sudo vim /etc/apache2/ports.conf
sudo systemctl restart apache2

问题 3:VirtualHost 不匹配

Certbot could not find a matching VirtualHost

解决方案:

# 检查 VirtualHost 配置
apache2ctl -S

# 确保 ServerName 与 -d 参数匹配
# 确保站点已启用
sudo a2ensite example.com.conf

问题 4:.htaccess 被忽略

解决方案:

<Directory /var/www/html>
    AllowOverride All
    Require all granted
</Directory>
sudo a2enmod rewrite
sudo systemctl restart apache2

7.10 Apache 与 Nginx 对比

特性ApacheNginx
Certbot 插件支持
配置风格XML (声明式)指令式
.htaccess 支持
事件驱动架构有限✅ 原生
内存占用较高较低
动态内容处理mod_php/mod_fcgid通过 FastCGI
Certbot 配置修改创建新 VirtualHost直接修改 server 块

7.11 最佳实践

  1. 使用 --apache 一键部署: 简单场景让 Certbot 自动处理
  2. 启用必要模块: sslrewriteheaderssocache_shmcb
  3. 配置 HSTS: 在确认 HTTPS 正常后逐步启用
  4. 使用 Include 复用配置: 将 SSL 参数放在独立文件中
  5. 定期检查配置语法: 使用 apache2ctl configtest
  6. 监控证书过期: 设置提醒或使用自动化监控

扩展阅读