nginx通过共存http/https两个server块实现部分路径走http、核心页面强制https:http server中用location精准放行/public/、/healthz、/legacy/等路径,其余一律301跳转;https server正常响应全部路径。

Nginx 实现“部分路径走 HTTP,核心页面强制 HTTPS”,本质是按 location 匹配做协议分流 + 条件重定向,而非全局跳转。关键在于:不依赖 server { listen 80 } 整体重定向,而是让 HTTP 和 HTTPS 两个 server 块共存,并在 HTTP server 中对特定路径放行,其余路径 301 跳转到 HTTPS。
下面分三块讲清楚怎么做:
HTTP server 中精准控制哪些路径可明文访问
只允许明确指定的非敏感资源走 HTTP,比如公开静态资源、健康检查接口、旧版兼容入口等。其他所有请求一律跳转。
配置示例(放在 http { ... } 内):
server {
listen 80;
server_name example.com;
# ✅ 明确放行:/public/ 下所有静态资源(图片、js、css)
location ^~ /public/ {
root /usr/share/nginx/html;
expires 1h;
add_header Cache-Control "public, immutable";
}
# ✅ 明确放行:/healthz 健康检查(供监控系统调用)
location = /healthz {
return 200 "OK";
add_header Content-Type text/plain;
}
# ✅ 明确放行:/legacy/ 开头的旧版页面(如遗留嵌入式 iframe)
location ^~ /legacy/ {
proxy_pass http://backend_legacy;
proxy_set_header Host $host;
}
# ❌ 其余所有请求:301 强制跳转到 HTTPS 对应路径
location / {
return 301 https://$host$request_uri;
}
}
HTTPS server 正常提供全部服务
这个块处理加密流量,无需额外判断协议,直接响应所有路径(包括上面放行的 /public/ 等,也走 HTTPS 更安全,但 HTTP 放行只是“兼容性冗余”):
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 所有路径都正常处理(含/public/、/healthz等)
location / {
root /usr/share/nginx/html;
index index.html;
}
# 可单独优化 API 路径
location ^~ /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
注意事项与常见坑
-
location ^~ /public/必须写在location /之前 —— Nginx 按顺序匹配,否则会被兜底规则拦截。 - 不要用
if ($request_uri ~ ^/public/) { ... }做判断 ——if在 location 外使用易出错,且性能差;优先用location前缀匹配。 - 避免在 HTTP server 中 proxy_pass 到 HTTPS 后端 —— 这会造成双重加密开销和证书校验问题;HTTP server 只该代理给纯 HTTP 服务(如 legacy backend)。
- 如果后端本身要求 HTTPS(比如 API),那
/api/就不该放在 HTTP server 里,必须走 HTTPS server 的proxy_pass https://...,并配置proxy_ssl_verify off(仅测试)或proxy_ssl_trusted_certificate(生产)。 - 浏览器 HSTS 头(
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains")一旦启用,会强制后续所有请求走 HTTPS —— 若你真需要长期保留某些 HTTP 路径,不能加 HSTS,否则用户首次访问过 HTTPS 后,浏览器将拒绝加载任何 HTTP 子路径。
不复杂但容易忽略。











