SSL 证书签下来之后第一件事:让所有 HTTP 请求都跳到 HTTPS。否则浏览器地址栏出现「不安全」,SEO 排名也会被降权。Nginx 上配这个其实不复杂,但 90% 的人栽在「301 跳转规则写错」或「和 CDN 重复强制」上。
先确认证书就位
Let’s Encrypt、腾讯云免费 DV、Cloudflare Origin Certificate 任选一个都行,关键是:
- 证书包含主域名和 www 子域名(一张 SAN 多域名证书最方便)
- 私钥文件权限 600,属主 root
- 已经测过
openssl s_client -connect yourdomain.com:443能看到证书链
第一步:HTTPS server 块先写好
不要急着写跳转,先确保 443 端口能正常访问。Nginx 站点配置 /etc/nginx/sites-available/yourdomain.conf 加一段:
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
root /var/www/yourdomain;
index index.html index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}
关键点:
- listen 443 ssl http2:开启 HTTPS 2,Chrome 浏览器地址栏会有更快标志
- ssl_protocols TLSv1.2 TLSv1.3:禁用 TLSv1.0 / 1.1,老浏览器兼容性自己权衡
- add_header Strict-Transport-Security:HSTS,浏览器以后强制 HTTPS
- add_header X-Frame-Options / X-Content-Type-Options:基础安全头,顺手加上
第二步:写 HTTP → HTTPS 301 跳转
在同一个配置文件的 server { listen 80; } 块里加:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
# 关键:acme.sh 续签需要 80 端口的特定路径
location /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
}
# 其他全部跳 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
用 301 而不是 302——301 是永久跳转,浏览器会缓存、SEO 会把权重完全转过去;302 是临时跳转,每次都要重新请求,对 SEO 不友好。
第三步:测一下配置文件 + reload
sudo nginx -t # 测试配置语法,没问题才继续
sudo systemctl reload nginx
浏览器里访问 http://yourdomain.com,应该立刻跳到 https://yourdomain.com,地址栏有锁图标。
第四步:处理混合内容
页面已经 HTTPS 了,但里面嵌入的 http:// 图片、CSS、JS 还在走老路——这就是「混合内容」,浏览器会过滤甚至阻止。表现:锁图标没了、Network 里 Mixed Content 报错。
修法(按优先级):
- 数据库批量替换(WordPress):
UPDATE wp_posts SET post_content = REPLACE(post_content, 'http://yourdomain.com', 'https://yourdomain.com'); - 主题/插件里的硬编码 URL:用 Search & Replace 插件扫一遍
- CDN 资源:协议相对 URL(
//cdn.example.com/xxx.js)或显式 https - WordPress 自动替换:在 wp-config.php 加
define('WP_HOME', 'https://yourdomain.com');
第五步:开 HSTS(强烈建议)
HSTS 告诉浏览器:「这个域名以后只能用 HTTPS,连 HTTP 请求都不要发」。第一次访问之后浏览器就记住了,连明文请求都不会发出去,杜绝降级攻击。
Nginx 配置里已经加了 Strict-Transport-Security 头。访问 https://hstspreload.org/ 提交域名,加入浏览器预加载列表,Chrome / Firefox / Safari 一发布就生效。
第六步:CDN 用户的额外步骤
套了 Cloudflare / 阿里云 CDN 的朋友注意:
| CDN SSL 模式 | 含义 | 是否推荐 |
|---|---|---|
| Off | CDN 不加密 | ❌ 别用 |
| Flexible | CDN→用户 HTTPS,CDN→源站 HTTP | ⚠️ 会引起循环 |
| Full | 全程 HTTPS,自签证书也接受 | ✅ 可用 |
| Full (Strict) | 全程 HTTPS,校验证书合法性 | ✅ 强烈推荐 |
「ERR_TOO_MANY_REDIRECTS」九成就是这个 Flexible 模式引起的——CDN 用 HTTP 回源,源站又强制跳 HTTPS,请求来回死循环。改 Full 或 Full (Strict) 立刻好。
常见问题
Q:开了 HTTPS 后网站变慢了怎么办?
A:HTTPS 本身多 1 次 TLS 握手(100ms 左右),但启用 HTTP/2(listen 443 ssl http2)+ 会话复用(ssl_session_cache)能抵消掉大头。感觉明显变慢多半是网络问题不是 HTTPS 问题。
Q:Let’s Encrypt 证书怎么自动续签?
A:用 certbot 或 acme.sh 自动加 cron。certbot 默认会在 90 天剩余 30 天时自动续签,安装时勾选「Set up cron job」即可。续签日志在 /var/log/letsencrypt/。
Q:HSTS 开了之后还能改回 HTTP 吗?
A:能,但要等浏览器侧的 max-age 过期。安全起见,先确认 HTTPS 完全稳了再开 HSTS,不要一上来就 preload(preload 之后基本撤销要等几个月)。
按这六步把 Nginx 上的 HTTPS 强制跳转和混合内容处理完,地址栏就会一直显示锁图标了。如果哪一步卡住或者 reload 之后网站反而崩了,把 error.log 末尾几行贴到 fenij.com 留言,我帮你接着分析。