安全头必须加在https的server块顶层(location外)并带always参数,不可放在upstream或location内;upstream只负责转发,安全加固须在server层完成,且需用proxy_hide_header屏蔽后端同名头。

Upstream 本身不处理安全响应头,它只负责转发请求和接收后端响应。真正加安全头的位置是 server 块——也就是 Nginx 作为反向代理对外输出响应的那一层。Upstream 的作用只是把后端内容“送过来”,安全加固必须在它之后、发给客户端之前完成。
安全头必须加在 server 块,不是 upstream 或 location 内
很多人误以为可以在 upstream 定义里加 header,或者写在 proxy_pass 所在的 location 块里。但实际生效位置只能是:HTTPS 的 server 块顶层(location 外),且必须带 always 参数。例如:
-
✅ 正确写法(server 块内、location 外):
add_header X-Content-Type-Options "nosniff" always;add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; -
❌ 错误写法:
写在upstream块里 → 无效;
写在location / { proxy_pass http://backend; }里 → 只对该 location 下 2xx 响应生效,且缺always时 404/502 等错误页不带头;
写在http块顶层 → 所有站点(含 HTTP)都继承,可能锁死子站或导致 CSP 白屏。
Upstream 配合安全加固的关键点
虽然 upstream 不加头,但它直接影响安全头是否能可靠生效:
-
确保后端不覆盖关键头:如果后端应用(如 PHP、Node.js)也输出
X-Frame-Options或Content-Security-Policy,Nginx 的add_header默认会被覆盖。解决方法是用proxy_hide_header主动屏蔽后端同名头:proxy_hide_header X-Frame-Options;proxy_hide_header Content-Security-Policy; -
错误响应也要防护:当 upstream 不可用(如 502 Bad Gateway)、超时或返回 4xx,这些响应同样需要安全头。只有
add_header ... always在 server 块中才能保证它们带上HSTS、CSP等——否则浏览器收不到 HSTS 就不会强制 HTTPS,CSP 报错日志也无法收集。 -
按 upstream 实际能力定制策略:比如 upstream 是静态文件服务,就不用配
script-src 'unsafe-inline';如果是管理后台,X-Frame-Options应设为DENY而非SAMEORIGIN;若 upstream 依赖 Google Fonts,则 CSP 中必须显式包含font-src fonts.gstatic.com。
常见组合配置示例
一个典型的代理型 server 块结构如下(含 upstream 和安全头):
- 先定义 upstream:
upstream api_backend { server 127.0.0.1:8000; keepalive 32; } - 再在对应 HTTPS server 块中:
listen 443 ssl;ssl_certificate ...;proxy_hide_header X-Frame-Options;proxy_hide_header X-XSS-Protection;add_header X-Content-Type-Options "nosniff" always;add_header X-Frame-Options "DENY" always;add_header Content-Security-Policy "default-src 'self'; frame-src 'none';" always; - 最后在 location 中调用:
location /api/ { proxy_pass http://api_backend; }











