
Apache HTTP Server 仍然是最广泛使用的 Web 服务器之一,特别是在 VPS 上运行的 LAMP 堆栈中。在 Apache 上安装 SSL 需要启用 mod_ssl 并配置合适的 HTTPS VirtualHost。本指南涵盖商业 SSL 证书和通过 Certbot Apache 插件的免费 Let's Encrypt 证书。
前置条件:已安装 Apache(apache2)的 Ubuntu 20.04/22.04 VPS、DNS A 记录指向您服务器 IP 的域名,以及 root 或 sudo 访问权限。
第 1 部分 — 首先需要的东西
验证 Apache 正在运行:
sudo systemctl status apache2
在 UFW 中打开端口 80 和 443:
sudo ufw allow 80 sudo ufw allow 443 sudo ufw status
确认您的域名解析到服务器 IP:
dig example.com +short
第 2 部分 — 在 Apache 上启用 mod_ssl
Ubuntu 的 Apache 在提供 HTTPS 之前需要显式启用 mod_ssl:
# 启用 mod_ssl 和 mod_rewrite(用于重定向) sudo a2enmod ssl sudo a2enmod rewrite # 重启 Apache 使模块生效 sudo systemctl restart apache2
验证 mod_ssl 是否已激活:
apache2ctl -M | grep ssl
您应该在输出中看到 ssl_module (shared)。
第 3 部分 — 在 Apache 上安装商业 SSL 证书
从您的 CA 收到证书文件后,遵循以下步骤:
3.1 放置证书文件
# 为 SSL 文件创建安全目录 sudo mkdir -p /etc/apache2/ssl/example.com # 复制证书和密钥文件 sudo cp your_domain.crt /etc/apache2/ssl/example.com/certificate.crt sudo cp your_private.key /etc/apache2/ssl/example.com/private.key # 如果 CA 提供了中间证书 sudo cp intermediate.crt /etc/apache2/ssl/example.com/ca_bundle.crt # 设置安全权限 sudo chmod 600 /etc/apache2/ssl/example.com/private.key sudo chmod 644 /etc/apache2/ssl/example.com/certificate.crt
3.2 创建 HTTPS VirtualHost
sudo nano /etc/apache2/sites-available/example.com-ssl.conf
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/example.com/certificate.crt
SSLCertificateKeyFile /etc/apache2/ssl/example.com/private.key
# 仅当您有中间证书时才包含此项
SSLCertificateChainFile /etc/apache2/ssl/example.com/ca_bundle.crt
<Directory /var/www/example.com>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example.com-ssl-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-ssl-access.log combined
</VirtualHost># 启用新网站
sudo a2ensite example.com-ssl.conf
sudo apache2ctl configtest
sudo systemctl reload apache2第 4 部分 — 使用 Certbot Apache 插件安装 Let's Encrypt
Certbot 的 Apache 插件自动管理所有内容,包括 VirtualHost 修改:
# 安装 Certbot 和 Apache 插件 sudo apt update sudo apt install certbot python3-certbot-apache -y # 为您的域获取证书 sudo certbot --apache -d example.com -d www.example.com
Certbot 会提示:
- 用于过期通知的电子邮件地址。
- 同意《服务条款》。
- 是否将所有 HTTP 流量重定向到 HTTPS(建议:是)。
提示:--apache 插件会自动编辑您的 VirtualHost、添加所需的 SSL 指令并配置重定向 — 无需手动配置更改。
第 5 部分 — 手动配置 VirtualHost 和 HTTP→HTTPS 重定向
要自己控制重定向而不让 Certbot 修改您的配置,编辑 port-80 VirtualHost:
sudo nano /etc/apache2/sites-available/example.com.conf
# Port-80 VirtualHost: 将所有流量重定向到 HTTPS <VirtualHost *:80> ServerName example.com ServerAlias www.example.com # 301 永久重定向 Redirect permanent / https://example.com/ </VirtualHost> # 替代方案:使用 mod_rewrite 获得更灵活性 <VirtualHost *:80> ServerName example.com ServerAlias www.example.com RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L] </VirtualHost>
⚠️ 注意:仅在确认您的 HTTPS VirtualHost 正常工作后才启用重定向。在 HTTPS 上线前启用 Redirect permanent 将导致所有访问者立即出错。
第 6 部分 — 测试配置并重新加载
重新加载前始终测试您的 Apache 配置:
# 验证 Apache 配置语法 sudo apache2ctl configtest # 如果语法 OK,重新加载 Apache sudo systemctl reload apache2 # 使用 curl 测试 HTTPS curl -I https://example.com # 用 openssl 验证证书详情 echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
有效的 apache2ctl configtest 输出以 Syntax OK 结尾。如果出现错误,请仔细阅读消息并在重新加载前修复。
测试 Let's Encrypt 的自动续期
# 干运行:测试续期而不实际续期
sudo certbot renew --dry-run自动续期:Certbot 会自动注册 systemd 定时器。用 systemctl list-timers | grep certbot 检查。证书会在过期前 30 天自动续期。
通过 Certbot Apache 插件使用 Let's Encrypt — 完整演练
Let's Encrypt 是一个免费 SSL 提供商,发行有效期为 90 天且可自动续期的 DV(域验证)证书。Certbot Apache 插件对初学者最友好,因为它为您编辑 VirtualHost,所以您几乎不需要自己触及配置。以下是从开始到结束的完整过程。
# 1) 更新包列表并安装 Certbot + Apache 插件 sudo apt update sudo apt install certbot python3-certbot-apache -y # 2) 确认 Apache 有一个 port-80 VirtualHost,其 ServerName 与您的域匹配 # Certbot 读取 ServerName/ServerAlias 来了解要为哪个域颁发证书 sudo apache2ctl -S # 3) 请求证书并让 Certbot 自动编辑 VirtualHost sudo certbot --apache -d example.com -d www.example.com # 4) 仅获取证书,不让 Certbot 触及您的配置(手动 VirtualHost) sudo certbot certonly --apache -d example.com -d www.example.com
当您运行 certbot --apache 时,它会要求您提供过期通知的电子邮件地址、要求您接受《服务条款》,并让您选择是否将 HTTP 重定向到 HTTPS(选择 Redirect)。Certbot 然后会自动在 sites-available 中创建一个 example.com-le-ssl.conf 文件,证书文件存储在 /etc/letsencrypt/live/example.com/ 下。
Let's Encrypt 文件位置:fullchain.pem(证书 + 链合并)、privkey.pem(私钥),加上 cert.pem 和 chain.pem — 都在 /etc/letsencrypt/live/example.com/ 内。Certbot 会为您在 VirtualHost 中引用 fullchain.pem 和 privkey.pem。
手动配置 Port-443 VirtualHost(SSLCertificateFile / Key / Chain)
对于商业 SSL 证书 — 或如果您想完全控制 Let's Encrypt 配置 — 创建一个 port-443 VirtualHost 并将其指向所有三个证书部分:域证书、私钥和链(中间)证书。
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com
SSLEngine on
# 域证书 (.crt 或 cert.pem)
SSLCertificateFile /etc/apache2/ssl/example.com/certificate.crt
# 生成 CSR 时使用的私钥 (.key 或 privkey.pem)
SSLCertificateKeyFile /etc/apache2/ssl/example.com/private.key
# CA 的中间/链证书 (.ca-bundle 或 chain.pem)
SSLCertificateChainFile /etc/apache2/ssl/example.com/ca_bundle.crt
# 建议:仅允许 TLS 1.2+ 并禁用不安全的遗留协议
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder on
<Directory /var/www/example.com>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example.com-ssl-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-ssl-access.log combined
</VirtualHost>在 Apache 2.4.8 及更高版本中,您可以将证书和链打包到单个文件中,仅使用 SSLCertificateFile(不需要 SSLCertificateChainFile),但如上所示保持文件分离更易于读取和维护。下表总结了关键指令及其匹配的文件。
| 指令 | 使用的文件 | 说明 |
|---|---|---|
SSLCertificateFile |
certificate.crt / fullchain.pem |
CA 颁发的域证书 |
SSLCertificateKeyFile |
private.key / privkey.pem |
与 CSR 配对的私钥;chmod 600 |
SSLCertificateChainFile |
ca_bundle.crt / chain.pem |
CA 中间证书(避免移动设备上的链错误) |
强制 HTTPS 重定向 + 在 Apache 上启用 HSTS(.htaccess / VirtualHost)
安装 SSL 后,您应该强制每个请求使用 HTTPS 并启用 HSTS(HTTP 严格传输安全)来告诉浏览器此域只能通过 HTTPS 访问。您可以在 VirtualHost 级别或 .htaccess 文件中执行此操作。
选项 1 — 在 port-80 VirtualHost 中重定向
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
# 301 永久重定向到 HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>选项 2 — 在 .htaccess 中强制 HTTPS(适用于共享 DocumentRoot)
# 将此放在您 DocumentRoot 的 .htaccess 中(需要 AllowOverride All)
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]选项 3 — 启用 HSTS 头
将 HSTS 头添加到 port-443 VirtualHost(首先用 sudo a2enmod headers 启用 mod_headers):
# 在 VirtualHost *:443 内部,在 SSL 设置之后
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"⚠️ HSTS 注意:一旦浏览器缓存 HSTS,它会在整个 max-age 周期内强制 HTTPS。如果您的 SSL 过期或破裂,访问者将完全被锁定。仅在确信 HTTPS 稳定且能正确自动续期后才启用 HSTS,不要在完全准备好前添加 preload。
启用 mod_ssl、用 apachectl configtest 测试、续期和常见问题
在每次重新加载前,验证语法并确认所需的模块已启用。最常见的验证命令是:
# 启用所需的模块(ssl、rewrite、headers) sudo a2enmod ssl rewrite headers # 重新加载前始终验证配置语法 sudo apachectl configtest # equivalent to apache2ctl configtest # 如果您得到 Syntax OK,重新加载以应用配置 sudo systemctl reload apache2 # 干运行 Let's Encrypt 续期(没有真正的续期) sudo certbot renew --dry-run # 检查所有证书的过期日期 sudo certbot certificates
常见问题和修复
- ERR_SSL_PROTOCOL_ERROR / 无法访问 HTTPS:通常
mod_ssl未启用或防火墙中端口 443 关闭 — 用apache2ctl -M | grep ssl和sudo ufw allow 443检查。 - 浏览器警告"不安全"尽管安装了证书:
SSLCertificateChainFile经常缺失,导致证书链不完整(特别是在移动设备上)— 添加完整的中间证书。 - configtest 报告"密钥值不匹配":私钥与证书不匹配。比较模数:
openssl x509 -noout -modulus -in cert.crt | openssl md5对比openssl rsa -noout -modulus -in private.key | openssl md5— 它们必须匹配。 - 重定向循环(ERR_TOO_MANY_REDIRECTS):当代理/CDN 在上游终止 SSL 而您仍然强制 HTTPS 时发生 — 使用
RewriteCond %{HTTP:X-Forwarded-Proto} !https而不是%{HTTPS} off。 - certbot 续期失败:通常端口 80 关闭或 port-80 VirtualHost 缺失,所以 HTTP-01 质询失败 — 保持端口 80 开放以便续期完成。
常见问题(FAQ)
Let's Encrypt 真的免费吗,它与付费 SSL 证书有何不同?
Let's Encrypt 100% 免费且为 DV(仅验证域所有权),有效期 90 天并可自动续期 — 适合一般网站。付费 SSL 增加 OV/EV 选项以验证组织身份,加上保修和 CA 支持。AsiaGB 同时提供免费 Let's Encrypt 和付费 DV SSL,起价 1,000 泰铢/年(含安装支持)。
我在 Apache 上安装了 SSL,但网站仍显示"不安全" — 为什么?
最常见的原因是混合内容(通过 http:// 加载的图像或脚本)、缺少 SSLCertificateChainFile 导致证书链不完整,或未强制重定向到 HTTPS。检查浏览器控制台中的混合内容并添加完整的中间证书。
安装 SSL 后应该重启还是重新加载 Apache?
使用 sudo systemctl reload apache2 — 它重新加载配置而不中断活动连接。仅在首次启用或禁用模块(如 mod_ssl)时使用 restart,且总是先运行 configtest。
Certbot 真的会自动续期 Let's Encrypt 吗,还是需要自己的 cron 任务?
现代 Certbot 会自动安装 systemd 定时器,不需要手动 cron。用 systemctl list-timers | grep certbot 验证,用 sudo certbot renew --dry-run 测试。只要端口 80 保持开放,证书会在过期前 30 天自动续期。
Apache 上的 SSL — 设置清单
- 安装 Apache 并启用 mod_ssl 和 mod_rewrite。
- 确认 DNS A 记录指向您的服务器 IP。
- 使用权限 644/600 存储证书和密钥文件。
- 使用正确的 SSLCertificateFile 指令创建 HTTPS VirtualHost。
- 添加 port-80 VirtualHost 将 HTTP 重定向到 HTTPS。
- 重新加载前始终运行
apache2ctl configtest。 - 用
curl -I和openssl s_client验证。 - 对于 Let's Encrypt:用
--dry-run测试续期。