Apache SSL/HTTPS 配置 #

SSL/TLS 基础 #

什么是 SSL/TLS? #

text
┌─────────────────────────────────────────────────────────────┐
│                    SSL/TLS 概念                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  SSL (Secure Sockets Layer)                                 │
│  TLS (Transport Layer Security)                             │
│                                                             │
│  作用:                                                     │
│  ├── 加密:保护数据传输安全                                 │
│  ├── 认证:验证服务器身份                                   │
│  └── 完整性:防止数据篡改                                   │
│                                                             │
│  HTTPS = HTTP + TLS                                         │
│                                                             │
│  工作流程:                                                 │
│  1. 客户端发起 HTTPS 请求                                   │
│  2. 服务器返回 SSL 证书                                     │
│  3. 客户端验证证书                                          │
│  4. 协商加密密钥                                            │
│  5. 建立加密通道                                            │
│  6. 安全传输数据                                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

证书类型 #

text
┌─────────────────────────────────────────────────────────────┐
│                    SSL 证书类型                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  按验证级别:                                               │
│  ├── DV (Domain Validation)    域名验证,快速签发          │
│  ├── OV (Organization Validation) 组织验证,显示公司名     │
│  └── EV (Extended Validation)  扩展验证,最高信任级别      │
│                                                             │
│  按覆盖范围:                                               │
│  ├── 单域名证书               保护一个域名                 │
│  ├── 多域名证书               保护多个域名                 │
│  └── 通配符证书               保护主域名及所有子域名       │
│                                                             │
│  证书颁发机构:                                             │
│  ├── Let's Encrypt           免费自动签发                  │
│  ├── DigiCert                商业证书                      │
│  ├── Comodo                  商业证书                      │
│  └── GeoTrust                商业证书                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

启用 SSL 模块 #

加载必要模块 #

bash
# Ubuntu/Debian
sudo a2enmod ssl
sudo a2enmod socache_shmcb
sudo systemctl restart apache2

# CentOS/RHEL
# 在配置文件中取消注释
# LoadModule ssl_module modules/mod_ssl.so
sudo systemctl restart httpd

启用默认 SSL 站点 #

bash
# Ubuntu/Debian
sudo a2ensite default-ssl
sudo systemctl reload apache2

获取 SSL 证书 #

使用 Let’s Encrypt(推荐) #

bash
# 安装 Certbot
# Ubuntu/Debian
sudo apt install certbot python3-certbot-apache

# CentOS/RHEL
sudo yum install certbot python3-certbot-apache

# 自动获取并配置证书
sudo certbot --apache -d example.com -d www.example.com

# 仅获取证书
sudo certbot certonly --apache -d example.com

# 测试续期
sudo certbot renew --dry-run

# 自动续期(Cron)
# 0 0 * * * certbot renew --quiet

手动配置证书 #

bash
# 证书文件位置(Let's Encrypt)
/etc/letsencrypt/live/example.com/fullchain.pem    # 证书链
/etc/letsencrypt/live/example.com/privkey.pem      # 私钥

# 自签名证书(仅测试用)
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/ssl/private/apache-selfsigned.key \
  -out /etc/ssl/certs/apache-selfsigned.crt

SSL 虚拟主机配置 #

基础 HTTPS 配置 #

apache
# ============================================
# 基础 HTTPS 配置
# ============================================

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/html
    
    # 启用 SSL
    SSLEngine on
    
    # 证书文件
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    
    # 证书链(如果需要)
    SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
    
    # 目录配置
    <Directory /var/www/html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    
    # 日志
    ErrorLog ${APACHE_LOG_DIR}/ssl-error.log
    CustomLog ${APACHE_LOG_DIR}/ssl-access.log combined
</VirtualHost>

HTTP 到 HTTPS 重定向 #

apache
# ============================================
# HTTP 重定向到 HTTPS
# ============================================

# 方法 1:使用 Redirect
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    Redirect permanent / https://example.com/
</VirtualHost>

# 方法 2:使用 Rewrite
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>

# 方法 3:统一到 www
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    
    RewriteEngine On
    RewriteCond %{HTTPS} off [OR]
    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteRule ^(.*)$ https://www.example.com/$1 [L,R=301]
</VirtualHost>

完整 HTTPS 配置 #

apache
# ============================================
# 完整 HTTPS 配置
# ============================================

# HTTP 重定向
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>

# HTTPS 配置
<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/html
    
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    
    # SSL 协议
    SSLProtocol all -SSLv2 -SSLv3
    
    # 加密套件
    SSLCipherSuite HIGH:!aNULL:!MD5:!3DES
    
    # 优先使用服务器加密套件
    SSLHonorCipherOrder on
    
    # HSTS
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
    
    <Directory /var/www/html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    
    ErrorLog ${APACHE_LOG_DIR}/ssl-error.log
    CustomLog ${APACHE_LOG_DIR}/ssl-access.log combined
</VirtualHost>

SSL 高级配置 #

SSL 协议配置 #

apache
# ============================================
# SSL 协议配置
# ============================================

# 推荐配置(仅 TLS 1.2 和 1.3)
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1

# 或明确指定
SSLProtocol -all +TLSv1.2 +TLSv1.3

# 全局配置(在 apache2.conf 或 httpd.conf)
<IfModule mod_ssl.c>
    SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
</IfModule>

加密套件配置 #

apache
# ============================================
# 加密套件配置
# ============================================

# 推荐配置
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 on

# 禁用不安全加密
SSLCipherSuite HIGH:!aNULL:!MD5:!3DES:!RC4:!EXP

HSTS 配置 #

apache
# ============================================
# HSTS (HTTP Strict Transport Security)
# ============================================

# 基础 HSTS
Header always set Strict-Transport-Security "max-age=31536000"

# 包含子域名
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

# 包含预加载
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

# 注意:preload 需要提交到 hstspreload.org

OCSP Stapling #

apache
# ============================================
# OCSP Stapling
# ============================================

# 启用 OCSP Stapling
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off

# 全局配置
SSLStaplingCache shmcb:/var/run/ocsp(128000)

# 在虚拟主机中
<VirtualHost *:443>
    ServerName example.com
    
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/example.com.crt
    SSLCertificateKeyFile /etc/ssl/private/example.com.key
    
    SSLUseStapling on
</VirtualHost>

SSL 会话配置 #

apache
# ============================================
# SSL 会话配置
# ============================================

# 会话缓存
SSLSessionCache shmcb:/var/run/ssl_scache(512000)
SSLSessionCacheTimeout 300

# 会话票据
SSLSessionTickets off

# 全局配置
<IfModule mod_ssl.c>
    SSLSessionCache shmcb:/var/run/ssl_scache(512000)
    SSLSessionCacheTimeout 300
    SSLSessionTickets off
</IfModule>

安全头配置 #

完整安全头 #

apache
# ============================================
# 安全响应头配置
# ============================================

# 加载 headers 模块
LoadModule headers_module modules/mod_headers.so

<IfModule mod_headers.c>
    # HSTS
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
    
    # 防止点击劫持
    Header always set X-Frame-Options "SAMEORIGIN"
    
    # 防止 MIME 类型嗅探
    Header always set X-Content-Type-Options "nosniff"
    
    # XSS 保护
    Header always set X-XSS-Protection "1; mode=block"
    
    # Referrer 策略
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    
    # 内容安全策略
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
    
    # 权限策略
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
    
    # 禁用缓存敏感页面
    <FilesMatch "\.(html|php)$">
        Header set Cache-Control "no-cache, no-store, must-revalidate"
        Header set Pragma "no-cache"
        Header set Expires 0
    </FilesMatch>
</IfModule>

SSL 测试与验证 #

测试 SSL 配置 #

bash
# 测试 SSL 配置
sudo apachectl configtest

# 查看 SSL 配置
sudo apache2ctl -M | grep ssl

# 使用 openssl 测试
openssl s_client -connect example.com:443

# 测试证书
openssl s_client -connect example.com:443 -servername example.com

# 查看证书详情
openssl x509 -in /etc/ssl/certs/example.com.crt -text -noout

# 测试 SSL 协议
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3

在线测试工具 #

text
┌─────────────────────────────────────────────────────────────┐
│                    SSL 测试工具                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  SSL Labs:                                                 │
│  https://www.ssllabs.com/ssltest/                          │
│  最权威的 SSL 配置测试                                      │
│                                                             │
│  SSL Checker:                                              │
│  https://www.sslshopper.com/ssl-checker.html               │
│  快速检查证书状态                                           │
│                                                             │
│  Security Headers:                                         │
│  https://securityheaders.com/                              │
│  检查安全响应头                                             │
│                                                             │
│  HSTS Preload:                                             │
│  https://hstspreload.org/                                  │
│  提交 HSTS 预加载                                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

证书续期 #

Let’s Encrypt 自动续期 #

bash
# 测试续期
sudo certbot renew --dry-run

# 手动续期
sudo certbot renew

# 续期后重载 Apache
sudo certbot renew --post-hook "systemctl reload apache2"

# 设置自动续期(systemd timer)
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer

Cron 自动续期 #

bash
# 编辑 crontab
sudo crontab -e

# 添加以下内容(每天检查两次)
0 0,12 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload apache2"

常见问题 #

证书链问题 #

apache
# 如果浏览器提示证书不受信任,可能需要配置证书链

# 方法 1:使用 fullchain
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem

# 方法 2:单独配置证书链
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

混合内容问题 #

apache
# 强制 HTTPS 资源
<IfModule mod_headers.c>
    Header always set Content-Security-Policy "upgrade-insecure-requests"
</IfModule>

多域名证书 #

apache
# 多域名配置
<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    ServerAlias api.example.com
    
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>

下一步 #

掌握了 SSL/HTTPS 配置后,继续学习 访问控制,了解如何配置 Apache 的访问控制和安全策略!

最后更新:2026-03-29