本指南将带你完成在 Apache HTTP Server 上使用 mod_ssl 安装 SSL 证书的全过程——从上传文件到加固 TLS 设置,再到排查常见错误。适用于来自 GetHTTPS、Certbot 或任何证书颁发机构的证书。
如果你还没有证书,5 分钟内免费获取一个。
前提条件
- Apache 2.4+ 已安装并在 HTTP(端口 80)上提供网站服务
- Root/sudo 访问权限
- 证书文件 — Apache 需要三个独立文件:
cert.pem— 你的证书(仅终端实体)privkey.pem— 你的私钥chain.pem— 中间证书颁发机构证书链
为什么需要三个文件? 不同于 Nginx(使用单个
fullchain.pem),Apache 传统上需要将证书和证书链分开存放。Apache 2.4.8+ 可以在SSLCertificateFile中使用fullchain.pem并省略SSLCertificateChainFile。格式详情 →
第一步:上传证书文件
# Create a secure directory
sudo mkdir -p /etc/ssl/gethttps
# Copy files to the server
sudo cp cert.pem chain.pem privkey.pem /etc/ssl/gethttps/
# Lock down the private key
sudo chmod 600 /etc/ssl/gethttps/privkey.pem
sudo chmod 644 /etc/ssl/gethttps/cert.pem /etc/ssl/gethttps/chain.pem
sudo chown root:root /etc/ssl/gethttps/*
如果通过 SCP 传输:
scp cert.pem chain.pem privkey.pem user@your-server:/tmp/
# On the server:
sudo mv /tmp/{cert,chain,privkey}.pem /etc/ssl/gethttps/
第二步:启用所需的 Apache 模块
# Debian/Ubuntu
sudo a2enmod ssl # Core SSL module
sudo a2enmod headers # For HSTS and security headers
sudo a2enmod rewrite # For HTTP→HTTPS redirect (if using .htaccess)
sudo systemctl restart apache2
# CentOS/RHEL/Amazon Linux
sudo yum install mod_ssl # Usually installs and enables in one step
sudo systemctl restart httpd
验证 mod_ssl 已加载:
apachectl -M | grep ssl
# Expected: ssl_module (shared)
第三步:配置 HTTPS VirtualHost
创建或编辑你网站的 SSL 配置。在 Debian/Ubuntu 上,通常位于 /etc/apache2/sites-available/yourdomain-ssl.conf:
# ─── HTTPS server ────────────────────────────
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
# Certificate files
SSLEngine on
SSLCertificateFile /etc/ssl/gethttps/cert.pem
SSLCertificateKeyFile /etc/ssl/gethttps/privkey.pem
SSLCertificateChainFile /etc/ssl/gethttps/chain.pem
# TLS protocol — only 1.2 and 1.3
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder off
SSLCompression off
# OCSP stapling (faster cert verification for clients)
SSLUseStapling on
SSLStaplingCache "shmcb:/var/run/apache2/ssl_stapling(128000)"
# Security headers
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
# Your site
DocumentRoot /var/www/html
<Directory /var/www/html>
AllowOverride All
</Directory>
</VirtualHost>
# ─── HTTP redirect ───────────────────────────
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
各指令说明:
| 指令 | 用途 |
|---|---|
SSLEngine on | 为此 VirtualHost 启用 SSL/TLS |
SSLCertificateFile | 证书路径 |
SSLCertificateKeyFile | 私钥路径 |
SSLCertificateChainFile | 中间证书颁发机构证书的路径 |
SSLProtocol | 仅允许 TLS 1.2/1.3 — 旧版本已弃用 |
SSLHonorCipherOrder off | 让客户端选择最佳加密套件 |
SSLCompression off | 防止 CRIME 攻击 |
SSLUseStapling | 服务器预取 OCSP 响应 |
Strict-Transport-Security | HSTS — 浏览器记住始终使用 HTTPS |
Redirect permanent | 301 重定向 HTTP → HTTPS |
第四步:启用站点并测试
# Debian/Ubuntu
sudo a2ensite yourdomain-ssl.conf
sudo apachectl configtest # Must say "Syntax OK"
sudo systemctl reload apache2
# CentOS/RHEL
sudo apachectl configtest
sudo systemctl reload httpd
如果 configtest 报告错误,它会告诉你确切的行号——在重新加载之前修复它。
第五步:验证
浏览器: 访问 https://yourdomain.com。点击锁头图标 → 验证签发者为”Let’s Encrypt”。
命令行:
echo | openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
在线工具: 使用 SSL Labs Server Test 进行综合评分。目标:A 或 A+。
Apache 与 Nginx:证书文件差异
| Apache | Nginx | |
|---|---|---|
| 证书 | SSLCertificateFile cert.pem | ssl_certificate fullchain.pem |
| 私钥 | SSLCertificateKeyFile privkey.pem | ssl_certificate_key privkey.pem |
| 证书链 | SSLCertificateChainFile chain.pem | 包含在 fullchain.pem 中 |
| 所需文件 | 3 个独立文件 | 2 个文件(证书链合并) |
Apache 2.4.8+ 也可以在 SSLCertificateFile 中使用合并的 fullchain.pem——这样就可以省略 SSLCertificateChainFile。
续签
当你的证书即将过期时(在此查看):
# Replace files
sudo cp new-cert.pem /etc/ssl/gethttps/cert.pem
sudo cp new-chain.pem /etc/ssl/gethttps/chain.pem
sudo cp new-privkey.pem /etc/ssl/gethttps/privkey.pem
# Reload (not restart) — zero downtime
sudo systemctl reload apache2 # Debian/Ubuntu
sudo systemctl reload httpd # CentOS/RHEL
故障排查
”AH02572: Failed to configure certificate” / 密钥不匹配
证书和私钥不对应。验证它们是否匹配:
# These two hashes must be identical
openssl x509 -noout -modulus -in /etc/ssl/gethttps/cert.pem | md5sum
openssl rsa -noout -modulus -in /etc/ssl/gethttps/privkey.pem | md5sum
如果不同,说明你使用了来自不同 GetHTTPS 会话的文件。请从同一会话重新下载。
“AH01909: server certificate does NOT include an ID”
你的 ServerName 与证书 SAN 字段中的任何域名都不匹配:
openssl x509 -noout -text -in /etc/ssl/gethttps/cert.pem | grep -A1 "Subject Alternative Name"
确保你的 Apache ServerName 与列出的 DNS 名称之一完全匹配。
浏览器显示”证书不受信任”
缺少中间证书链。验证 SSLCertificateChainFile 指向的是 chain.pem(中间证书),而不是 cert.pem。测试证书链:
echo | openssl s_client -connect yourdomain.com:443 2>/dev/null | grep "Verify return code"
# "Verify return code: 0 (ok)" = good
# "Verify return code: 21 (unable to verify)" = chain incomplete
“AH00526: Syntax error on line X”
Apache 配置语法错误。常见原因:
- 缺少
</VirtualHost>闭合标签 SSLCertificateChainFile拼写错误- Header 值缺少引号
- 文件路径不存在
HTTPS 正常但显示”不安全”
混合内容——你的页面通过 HTTP 加载了资源。打开 DevTools → Console → 修复 http:// 开头的 URL。
常见问题
可以使用 fullchain.pem 代替分开的 cert + chain 吗?
可以,在 Apache 2.4.8+ 上。使用 SSLCertificateFile /path/to/fullchain.pem 并完全移除 SSLCertificateChainFile 指令。在较旧版本的 Apache 上,你需要分开的文件。
如何检查我的 Apache 版本?
apachectl -v
# or
httpd -v
需要重启 Apache 还是仅重新加载?
重新加载(systemctl reload)就够了,且不会造成停机。重启(systemctl restart)会断开所有活动连接。证书更改时始终使用 reload。
Apache 能否为不同域名提供不同的证书?
可以。创建单独的 <VirtualHost *:443> 块,使用不同的 ServerName 和 SSLCertificate* 指令。Apache 使用 SNI(Server Name Indication)来选择正确的证书。
Apache 是否支持 ECDSA 证书?
支持。Apache 2.4+ 处理 ECDSA 的方式与 RSA 相同——相同的指令,相同的文件格式。GetHTTPS 默认生成 ECDSA P-256。
Apache 的 SSL 错误日志在哪里?
# Debian/Ubuntu
tail -f /var/log/apache2/error.log
# CentOS/RHEL
tail -f /var/log/httpd/ssl_error_log