WordPress 配置 HTTPS:证书、混合内容与全站跳转
HTTPS 配完最常见的三种残留:浏览器地址栏的小锁出来了,但控制台一片红;首页跳到了 https,内页还是 http;后台能进,前台白屏。这三件事分别对应证书链、站点地址、混合内容,配置顺序错了就会反复。
证书选型:DV 够用,别为 EV 多花钱
域名验证型(DV)证书只验证域名归属,签发几分钟,免费的和付费的在浏览器里显示完全一样。组织验证型(OV)会核验企业工商信息,适合需要展示主体资质的场景,价格从几百到几千不等。扩展验证型(EV)现在主流浏览器已经不再显示绿色地址栏,性价比很低。
| 类型 | 验证内容 | 签发时间 | 适用场景 |
|---|---|---|---|
| 免费 DV(Let’s Encrypt) | 域名解析归属 | 1 到 5 分钟 | 绝大多数企业站、博客、展示站 |
| 付费 DV | 域名解析归属 | 10 分钟到 2 小时 | 需要一年期、不想折腾自动续签 |
| OV | 域名 + 企业营业执照 | 1 到 3 个工作日 | 金融、招投标、需提交资质的场景 |
| 泛域名 DV | 主域所有权 | 10 分钟 | 有 blog、shop、m 等多个子域 |
Let’s Encrypt 有效期 90 天,靠自动续签。宝塔面板在「网站 → 设置 → SSL → Let’s Encrypt」申请时会自动写续签任务,但要确认计划任务里的 ssl-renew 是启用状态——续签失败最常见的后果是某天早上全站证书过期,浏览器直接拦截。
验证方式有两种。文件验证要求 /.well-known/acme-challenge/ 这个目录能被公网访问,如果站点做了强制跳转或者 CDN 缓存了这个路径,验证会一直失败,这时改成 DNS 验证。泛域名证书只能用 DNS 验证,需要在域名解析里加一条 TXT 记录,加完等一两分钟再点验证,别急着重复提交,重复提交容易触发频率限制,一周内都签不下来。
Nginx 的 443 配置
宝塔用户点一下「强制 HTTPS」就能生成,但手工维护的机器要自己写。核心是四行:证书、私钥、协议版本、跳转。
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /www/server/panel/vhost/cert/example.com/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
root /www/wwwroot/example.com;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ .php$ {
include fastcgi_params;
fastcgi_pass unix:/tmp/php-cgi-74.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
两个细节。证书路径要用 fullchain.pem 而不是 cert.pem,否则部分安卓机和旧版 Java 客户端会报证书链不完整。协议版本只留 TLSv1.2 和 1.3,TLSv1.0/1.1 已经被主流浏览器标记为不安全,留着只会让安全扫描扣分。改完执行 nginx -t 再 reload,直接 reload 会在配置有语法错误时把整站搞挂。
站点地址改成 https:先改数据库,再改配置
只在浏览器里访问 https 不够,WordPress 内部还认为自己是 http,后台资源、编辑器、定时任务全都会生成 http 链接。要改的是 wp_options 表里的 siteurl 和 home 两个值,路径在「设置 → 常规 → WordPress 地址」和「站点地址」。
UPDATE wp_options SET option_value = 'https://www.example.com'
WHERE option_name IN ('siteurl', 'home');
表前缀不是 wp_ 的要换成实际前缀。执行前先备份数据库,改错了可以在 wp-config.php 里临时加两行救回来:
define('WP_HOME', 'https://www.example.com');
define('WP_SITEURL', 'https://www.example.com');
这两行优先级高于数据库,加了之后后台能进,再回去改数据库,改完删掉这两行。文章正文和自定义字段里还有大量硬编码的 http 链接,直接跑 SQL 替换会破坏序列化数据,必须用 wp search-replace 'http://www.example.com' 'https://www.example.com' --dry-run 先看影响范围,确认后再执行。搬家和换域名时这一套流程同样适用,细节见网站迁移。
后台还要单独强制。WordPress 允许前后台使用不同协议,如果只改了前台,登录页仍然是 http,密码就是明文传输。在 wp-config.php 里加 define('FORCE_SSL_ADMIN', true);,把这个口子堵上。多站点要在 wp-config.php 里同时定义 WP_HOME 和 WP_SITEURL,不能靠后台选项,因为多站点读的是网络设置。
混合内容:怎么找,怎么改
混合内容是指 HTTPS 页面里加载了 http 资源。浏览器对图片和音频是”降级显示”,对 JS 和 CSS 是直接拦截,表现出来就是样式丢失、轮播不动、统计代码不生效。
定位有三种办法,按效率排序:
- 浏览器 F12 打开控制台,筛选
Mixed Content,报错里会直接给出完整的 http 地址。 - 抓源码搜:
curl -s https://www.example.com/ | grep -o "http://[^"']*",一次能捞出一批。 - 数据库层面扫,用
wp search-replace的--dry-run模式,它会列出所有会被替换的位置和条数。
改的时候注意来源:主题选项里填的背景图地址、页眉页脚插入的统计代码、插件里配置的 CDN 域名,这三处是重灾区,改完数据库还得回去改配置,否则下次保存设置又被写回 http。实在改不动的第三方资源(比如老的统计脚本只提供 http),删掉换一个,不要用「不安全内容放行」的浏览器开关糊弄自己。
HSTS 要不要开
HSTS 通过响应头告诉浏览器「这个域名以后只走 HTTPS」,有效期由 max-age 决定。开了之后浏览器不再发http 请求,省一次 301 往返,也能防住 SSL 剥离攻击。
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
但它有个硬性代价:一旦下发,在 max-age 到期之前浏览器不会回退到 http。证书过期、配置出错、临时切回 http 调试,用户都只能看到错误页,没有绕过按钮。所以第一次开的时候把 max-age 设成 300 秒,确认全站和所有子域都能正常走 HTTPS,再逐步加到一年。带 includeSubDomains 和 preload 的更要谨慎,提交 preload 列表之后,移除要走几个月的流程。
判断能不能上 includeSubDomains 的标准很实际:把所有子域列出来,逐个访问一遍,包括 mail、ftp、测试环境、老项目遗留的二级域名。只要有一个还在 http,就不能加这个参数,否则那个子域会直接不可访问。内网系统用公网域名做子域的,尤其要检查。
全站 301:跳转要一次到位
跳转链越长,权重损耗越大。正确的做法是在 Nginx 层一次跳到最终地址,不要在 http 跳 https 之后再跳一次去掉 www。
server {
listen 80;
server_name example.com www.example.com;
return 301 https://www.example.com$request_uri;
}
这条规则同时处理了协议和域名,不管用户从哪个入口进来,一次就到终点。WordPress 后台的「站点地址」必须和这里的目标完全一致,否则会形成无限跳转,浏览器报 ERR_TOO_MANY_REDIRECTS。如果站点前面还有 CDN,跳转要在源站做,别在 CDN 上也配一份,两份规则打架时的表现是间歇性循环跳转,很难复现。
| 现象 | 原因 | 处理 |
|---|---|---|
| 小锁正常但样式全丢 | CSS、JS 仍是 http 地址 | 按混合内容三步定位并替换 |
| 内页跳回 http | 数据库 siteurl 未改,或固定链接缓存 | 改 options 表,重存一次固定链接 |
| ERR_TOO_MANY_REDIRECTS | Nginx 跳转目标与站点地址不一致 | 统一成同一个域名写法 |
| 部分手机提示证书无效 | 用了 cert.pem 而非 fullchain.pem | 换成完整链证书 |
收尾做三件事:用在线 SSL 检测跑一遍,确认证书链和协议版本没问题;把站点地图里的地址全部换成 https 并重新提交;观察一周 404 日志,看有没有遗漏的 http 内链。安全层面还可以顺手把后台登录强制走 HTTPS、关掉 xmlrpc.php,这些和安全加固是同一套动作。整套 SSL 配置的完整清单在SSL 配置那篇,遇到打不开的情况可以先看打不开排查,按顺序排除证书、端口和解析。