本文约 6,502 字,预计阅读 17 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:不装证书,浏览器直接给你标红
现在的浏览器对 HTTP 站点的态度已经非常明确:Chrome 在地址栏显示”不安全”,表单输入框会提示”此连接不安全”;百度和 Google 都把 HTTPS 作为排名信号之一;更实际的问题是,如果你的站点要做微信分享、接入支付、使用 Service Worker 或者 getUserMedia,全部要求 HTTPS 环境。
好消息是证书本身已经免费——Let’s Encrypt 提供 90 天有效期的免费 DV 证书,配合 acme.sh 可以全自动续期,一次配置永久免维护。麻烦的部分在细节:验证方式选错导致签发失败、续期时 Nginx 没重载导致证书过期、强制 HTTPS 后后台重定向循环、混合内容(Mixed Content)导致小绿锁不显示。
原理分析:证书验证的是”域名控制权”而非”身份”
证书类型。 按验证强度分三类:
| 类型 | 全称 | 验证内容 | 签发时间 | 适用场景 | 价格 |
|---|---|---|---|---|---|
| DV | Domain Validation | 只验证域名控制权 | 几分钟 | 博客、个人站、绝大多数企业站 | 免费 |
| OV | Organization Validation | 验证组织真实性 | 3–7 工作日 | 企业官网、需要展示主体信息 | 数百至数千元/年 |
| EV | Extended Validation | 严格验证组织与法律实体 | 1–2 周 | 金融、电商、支付 | 数千元/年 |
对绝大多数 WordPress 站点,免费 DV 证书完全够用。 DV 和 OV/EV 的加密强度是一样的,区别只在于证书里是否包含企业信息以及审核严格程度。
两种验证方式的区别。
- HTTP-01 验证: ACME 服务器要求你在
http://域名/.well-known/acme-challenge/下放一个特定文件,能访问到就证明你控制该域名。优点是全自动;缺点是必须开放 80 端口,且泛域名证书不支持这种方式。 - DNS-01 验证: ACME 服务器要求你在 DNS 里添加一条
_acme-challenge的 TXT 记录。优点是支持泛域名证书(*.mimangfei.com)、不需要开放任何端口、服务器在内网也行;缺点是需要 DNS 服务商提供 API 密钥来自动添加记录。
为什么必须自动续期。 Let’s Encrypt 证书有效期 90 天,到期后浏览器会显示”您的连接不是私密连接”,访客基本会直接关掉。人工续期三年必然忘一次,所以自动续期不是可选项而是必选项。
证书链与中间证书。 部署时需要配置的是 fullchain.pem(站点证书 + 中间证书)而不是 cert.pem(仅站点证书)。只配 cert.pem 会导致部分浏览器(尤其是 Android 和旧版 Java 客户端)报 NET::ERR_CERT_AUTHORITY_INVALID,而桌面 Chrome 却正常——因为 Chrome 会用 AIA 扩展自动补全中间证书,其他客户端不一定会。
保姆级实操:用 acme.sh 申请并自动续期
步骤 1:安装 acme.sh 并设置默认 CA。
# 安装(邮箱用于到期提醒)
curl https://get.acme.sh | sh -s email=admin@mimangfei.com
source ~/.bashrc
# 切换默认 CA 为 Let's Encrypt(acme.sh 默认已改为 ZeroSSL,也可保持默认)
acme.sh --set-default-ca --server letsencrypt
步骤 2A:HTTP-01 方式签发(有 80 端口、单域名)。
# 用 Nginx 模式,acme.sh 会自动改配置再还原
acme.sh --issue -d mimangfei.com -d www.mimangfei.com --nginx
# 或者用 standalone 模式(需临时停掉占用 80 端口的服务)
acme.sh --issue -d mimangfei.com --standalone
步骤 2B:DNS-01 方式签发(推荐,支持泛域名)。 以 DNSPod(腾讯云)为例,先在控制台创建 API 密钥:
export DP_Id="你的API_ID"
export DP_Key="你的API_Token"
# 签发泛域名证书,包含根域与二级通配
acme.sh --issue --dns dns_dp -d mimangfei.com -d '*.mimangfei.com'
# 阿里云用 dns_ali,Cloudflare 用 dns_cf,完整列表见 acme.sh 的 dnsapi 目录
API 密钥会被 acme.sh 保存在 ~/.acme.sh/account.conf 里,续期时自动读取,不要把这个文件提交到代码仓库。
步骤 3:安装证书到指定目录并配置自动重载。 不要直接引用 ~/.acme.sh/ 下的文件(该目录结构可能变动),用 --install-cert 安装到固定路径:
mkdir -p /etc/nginx/ssl/mimangfei.com
acme.sh --install-cert -d mimangfei.com \
--key-file /etc/nginx/ssl/mimangfei.com/key.pem \
--fullchain-file /etc/nginx/ssl/mimangfei.com/fullchain.pem \
--reloadcmd "systemctl reload nginx"
--reloadcmd 是关键:acme.sh 会自动创建 crontab 任务,每天检查到期时间,续期成功后执行这条命令让 Nginx 加载新证书。
步骤 4:配置 Nginx 的 HTTPS 与强制跳转。
# HTTP 全部 301 跳转到 HTTPS(保留 ACME 验证路径不走跳转)
server {
listen 80;
server_name mimangfei.com www.mimangfei.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://www.mimangfei.com$request_uri;
}
}
server {
listen 443 ssl;
http2 on;
server_name mimangfei.com;
ssl_certificate /etc/nginx/ssl/mimangfei.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/mimangfei.com/key.pem;
return 301 https://www.mimangfei.com$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name www.mimangfei.com;
root /var/www/html;
index index.php index.html;
ssl_certificate /etc/nginx/ssl/mimangfei.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/mimangfei.com/key.pem;
# 会话复用,减少 TLS 握手开销
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# HSTS:告诉浏览器以后只走 HTTPS(确认长期用 HTTPS 再开启)
add_header Strict-Transport-Security "max-age=31536000" always;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
# 关键:让 WordPress 知道前端是 HTTPS,否则会出现重定向循环
fastcgi_param HTTPS on;
}
}
步骤 5:修改 WordPress 站点地址。 后台「设置 → 常规」把 WordPress 地址(URL)和站点地址(URL)改成 https:// 开头。如果后台进不去,用 wp-config.php 强制:
// wp-config.php:在 "/* 好了!请停止编辑 */" 之前加入
define( 'WP_HOME', 'https://www.mimangfei.com' );
define( 'WP_SITEURL', 'https://www.mimangfei.com' );
// 反向代理/CDN 场景下必须加,否则后台重定向循环
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) {
$_SERVER['HTTPS'] = 'on';
}
步骤 6:批量修复历史内容里的 HTTP 链接(混合内容)。 地址栏不显示锁图标,通常是因为页面里还引用了 http:// 的图片或脚本。用 WP-CLI 全站替换:
# 先干跑预览,确认影响范围
wp search-replace 'http://www.mimangfei.com' 'https://www.mimangfei.com' --dry-run --precise
# 确认无误后执行(--precise 使用 PHP 序列化安全替换,避免破坏插件设置)
wp search-replace 'http://www.mimangfei.com' 'https://www.mimangfei.com' --precise
# 只替换文章内容里的链接,不动设置项
wp search-replace 'http://' 'https://' wp_posts --precise
步骤 7:验证配置并做在线检测。
# 检查证书有效期与证书链
echo | openssl s_client -connect www.mimangfei.com:443 -servername www.mimangfei.com 2>/dev/null \
| openssl x509 -noout -dates -subject -issuer
# 确认自动续期任务存在
crontab -l | grep acme
# 手动测试续期流程(加 --force 强制,确认无误后再靠自动任务)
acme.sh --renew -d mimangfei.com --force
# 检查 301 跳转是否正确
curl -I http://www.mimangfei.com
最后用 SSL Labs 的在线检测(ssllabs.com/ssltest)确认评级达到 A,重点看证书链是否完整(”Chain issues: None”)。
常见踩坑
- 只配了 cert.pem 没配 fullchain.pem。 桌面浏览器正常、部分手机报证书不可信,排查方向就是证书链不完整。
- CDN 后面配置 HTTPS 导致重定向循环。 WordPress 收到的是 HTTP 请求,又跳回 HTTPS,无限循环。解决办法是上面的
$_SERVER['HTTPS'] = 'on'片段,或者让 CDN 回源也走 HTTPS。 - 80 端口被防火墙挡住导致 HTTP-01 验证失败。 报错
urn:ietf:params:acme:error:connection。要么临时放行,要么改用 DNS-01。 - 没加
--reloadcmd,证书续期了但 Nginx 没加载。 表现为”证书文件是新的,浏览器还是报过期”。systemctl reload nginx必须加上。 - 开了 HSTS 又想回退到 HTTP。 HSTS 的 max-age 有效期内浏览器强制走 HTTPS,无法绕过。没想清楚之前不要开 HSTS。
- Let’s Encrypt 的速率限制。 同一域名每周最多签发 50 张证书,同一注册域名每周 5 张(
Renewal Exempt)。调试阶段狂点会触发too many certificates already issued,此时要用--staging测试环境。 - 案例:一次证书过期导致全站不可访问。 客户的证书是半年前用 certbot 手动申请的,配置的 cron 任务写的是
certbot renew --quiet,但因为安装时用的是 snap,cron 里的 PATH 找不到 certbot 可执行文件,任务静默失败。证书过期当天,全站访问显示NET::ERR_CERT_DATE_INVALID,流量当天掉了 90%。处理方式是紧急用certbot certonly --nginx重签,然后改用systemctl list-timers | grep certbot确认 systemd timer 处于 active 状态。教训:配完自动续期必须验证一次——用certbot renew --dry-run或acme.sh --renew --force跑一遍,并且配置到期前 20 天的邮件/短信提醒作为第二道防线。
总结
SSL 配置的正确顺序是:选验证方式(有 80 端口用 HTTP-01,要泛域名用 DNS-01)→ 签发 → 安装到固定目录并配 reloadcmd → 配置 Nginx 443 与 301 跳转 → 改 WordPress 站点地址 → WP-CLI 批量替换历史链接 → 验证证书链与自动任务。判断标准:SSL Labs 评级 A、证书链完整、crontab 里有 acme 任务、所有页面无混合内容警告。证书配好之后,下一步是 网站监控与告警搭建,把证书到期也纳入告警项;安全方面还可以配合 网站上线安全基线配置 中的 HSTS 与安全头一起配置。
