Nginx 强制 HTTPS 跳转,但保留 IP 直连(备案后最实用的一段配置)
域名备案通过后,第一件事通常是给 80 端口加 301 跳转,让所有访问都走 HTTPS。但很多人会踩一个坑:加了跳转以后,直接用服务器 IP 访问也跳到 HTTPS 了,而 IP 上没有对应证书,浏览器直接报错,调试和预览都很别扭。
这篇记录一个两全的配置法:域名强制 HTTPS,IP 直连继续走 HTTP。
原理
Nginx 是按 server_name 匹配请求的 Host 头的。所以我们可以:
- 一个 80 server 块,
server_name写域名 → 301 到 HTTPS - 原来的 80 default server(
server_name _)继续服务 → IP 访问走这里
因为我们原来的配置里 80 是 default_server + server_name _,域名请求虽然也会落到它,但只要新增一个 server_name 为域名的 80 块,Nginx 会优先按名字匹配,就把域名请求单独劫走做跳转。
配置
在站点配置里追加:
server {
listen 80;
listen [::]:80;
server_name www.example.com example.com;
return 301 https://$host$request_uri;
}
nginx -t && systemctl reload nginx 之后:
curl -I http://www.example.com/ # 301 -> https://www.example.com/
curl -I http://example.com/ # 301 -> https://example.com/
curl -I http://1.2.3.4/ # 200,IP 直连不受影响
为什么用 $host
$host是请求头里的 Host(不带端口),会跟随用户的访问域名- 如果你有多域名(www 和裸域),它会各自跳到自己,不用写死
- 不要用
$server_name,在某些代理场景下会跳错域名
几个细节
1. 80 块不要写 default_server
同一个端口只能有一个 default_server。新块只写 listen 80; 和 server_name,别加 default_server,否则会跟原来的冲突。
2. 跳转用 301 还是 308?
SEO 场景用 301(永久),浏览器和搜索引擎都会记住。POST 请求需要保方法的话才考虑 308,一般网站用 301 足够。
3. 跳转后 HSTS 可以加,但要谨慎
add_header Strict-Transport-Security "max-age=31536000" always;
加了以后浏览器会强制 HTTPS,包括子域名(如果带 includeSubDomains)。建议先跑一两周没报错再加。
4. 检查一下 HTTP 服务是否会被 CDN/云厂商拦
未备案的域名在国内云上访问 80 端口会被 302 到备案拦截页,这个跳转配置根本不会执行。先确认备案通过、域名能正常 200 再配跳转。
小结
强制 HTTPS 和 IP 直连并不冲突,核心就是让域名和 IP 走不同的 server 块。配置很短,但能省掉很多"IP 访问报证书错误"的调试麻烦。
需要建站/HTTPS 配置/服务器维护的,可以找我。