属于我们的Performance & Scalability系列
阅读完整指南Nginx 生产配置:SSL、缓存和安全性
Nginx 是生产 Web 服务器,可处理几乎所有高流量 Web 部署。如果配置得当,它可以提供 SSL 终止、高效的静态文件服务、WebSocket 代理、速率限制和安全标头 — 所有这些都在单个请求到达您的 Node.js 应用程序之前完成。如果配置不当,它就会成为瓶颈、安全责任或神秘的 Cloudflare 重定向循环的原因。
本指南涵盖了多应用 Node.js 部署的生产级 Nginx 配置:Next.js 前端、NestJS API 和 Docusaurus 文档 - 所有这些都在 Cloudflare 后面的同一服务器上运行。
要点
- 切勿将 www 和非 www 拆分为 Cloudflare 后面的单独服务器块 — 导致重定向循环
- 在
/etc/nginx/conf.d/中使用单个 Nginx 配置文件 — 不要在sites-enabled/中也使用符号链接X-XSS-Protection已弃用 — 使用 CSP 代替;X-Frame-Options: DENY仍然有效- 使用路径前缀时
proxy_pass必须包含尾部斜杠- 文本/* MIME 类型的 Gzip 压缩始终值得启用
- 速率限制需要在
http{}级别定义limit_req_zone,而不是server{}级别- Let's Encrypt 证书使用 Certbot 自动续订;添加一个 cron 作业以在续订后重新加载 Nginx
- WebSocket 代理需要特定标头:
Upgrade和Connection
目录结构
保持 Nginx 配置井井有条:
/etc/nginx/
nginx.conf — Main config (rarely touch this)
conf.d/
ecosire-production.conf — All your server blocks in ONE file
snippets/
ssl-params.snippet — SSL hardening (included by server blocks)
proxy-params.snippet — Common proxy headers
security-headers.snippet — Security headers
关键:将所有配置放入 conf.d/ecosire-production.conf 中。也不要将其添加到 sites-enabled/ — 这会导致 Nginx 处理配置两次,从而导致重复的 limit_req_zone 错误和意外行为。
速率限制区域
在配置中的 http{} 级别定义速率限制区域。它们不能在 server{} 块内定义:
# /etc/nginx/conf.d/ecosire-production.conf
# Must be at http{} level — these are in the main conf or conf.d root
limit_req_zone $binary_remote_addr zone=api_general:10m rate=60r/m;
limit_req_zone $binary_remote_addr zone=api_auth:10m rate=10r/m;
limit_req_zone $binary_remote_addr zone=api_public:10m rate=30r/m;
limit_req_zone $binary_remote_addr zone=static_files:10m rate=200r/m;
主应用程序服务器块
# Main web application — Next.js on port 3000
server {
listen 80;
listen [::]:80;
server_name ecosire.com www.ecosire.com;
# Cloudflare handles SSL termination — Nginx only sees HTTP
# (If direct SSL, add listen 443 ssl and certificate paths)
# Security headers
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# CSP — adjust based on your needs
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://js.stripe.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; frame-src https://js.stripe.com; connect-src 'self' https://api.ecosire.com;" always;
# Remove server version from responses
server_tokens off;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
image/svg+xml
font/woff2;
gzip_min_length 1024;
# ─── Static Files: Next.js build output ─────────────────────────
location /_next/static/ {
proxy_pass http://127.0.0.1:3000;
add_header Cache-Control "public, max-age=31536000, immutable";
# Files include content hash in filename — safe to cache forever
}
# ─── Public static assets ────────────────────────────────────────
location /assets/ {
proxy_pass http://127.0.0.1:3000;
add_header Cache-Control "public, max-age=86400"; # 1 day
}
# ─── Well-known files (no locale prefix) ─────────────────────────
location /.well-known/ {
proxy_pass http://127.0.0.1:3000;
add_header Cache-Control "public, max-age=86400";
}
# ─── App routes (rate limited) ───────────────────────────────────
location / {
limit_req zone=api_general burst=20 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
API 服务器块
# NestJS API — port 3001
server {
listen 80;
listen [::]:80;
server_name api.ecosire.com;
server_tokens off;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# CORS — handled by NestJS, but Nginx can add preflight response
# for performance (avoids reaching Node.js for OPTIONS)
location / {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin "https://ecosire.com";
add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
add_header Access-Control-Allow-Credentials "true";
add_header Access-Control-Max-Age 1728000;
add_header Content-Length 0;
return 204;
}
limit_req zone=api_general burst=30 nodelay;
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Stricter rate limits for auth endpoints
location ~ ^/api/auth/(login|exchange|callback) {
limit_req zone=api_auth burst=5 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Health check — no rate limiting
location /api/health {
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host $host;
access_log off; # Don't log health check spam
}
# Stripe webhook — needs raw body
location /api/billing/webhook {
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# No rate limiting on webhooks — Stripe IPs are trusted
# NestJS validates the Stripe signature
}
}
WebSocket 代理
如果您的应用程序使用 WebSockets(Socket.IO、NestJS WebSocket 网关),则代理配置需要特定标头:
# WebSocket upgrade handling
location /ws/ {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade"; # Capital U required
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# WebSocket connections can be long-lived
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
如果没有 Upgrade 和 Connection 标头,浏览器的 WebSocket 握手将失败并出现 426 Upgrade Required 或 101 Switching Protocols 错误。
直接 SSL(无需 Cloudflare)
如果不使用 Cloudflare,请直接在 Nginx 中处理 SSL 终止:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name ecosire.com;
ssl_certificate /etc/letsencrypt/live/ecosire.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ecosire.com/privkey.pem;
# SSL hardening
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# ... rest of server block
}
# HTTP to HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name ecosire.com www.ecosire.com;
return 301 https://ecosire.com$request_uri;
}
Cloudflare 特定配置
在 Cloudflare 后面,Nginx 只能看到 Cloudflare 的 IP。要保留真实的客户端 IP:
# Real IP from Cloudflare — add this in http{} or at top of server{}
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
real_ip_header CF-Connecting-IP;
另外:在使用 Cloudflare 时,永远不要将 www.ecosire.com 和 ecosire.com 拆分为单独的 Nginx 服务器块。 Cloudflare 在其边缘处理 www 重定向。如果您添加重定向到非 www 的 www 服务器块,并且 Cloudflare 也重定向 www,则会出现重定向循环 (ERR_TOO_MANY_REDIRECTS)。
日志配置
# Custom log format with useful fields
log_format json_combined escape=json
'{'
'"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"cf_ip":"$http_cf_connecting_ip",'
'"method":"$request_method",'
'"uri":"$request_uri",'
'"status":$status,'
'"body_bytes":$body_bytes_sent,'
'"response_time":$request_time,'
'"referrer":"$http_referer",'
'"user_agent":"$http_user_agent"'
'}';
access_log /var/log/nginx/ecosire-access.log json_combined;
error_log /var/log/nginx/ecosire-error.log warn;
测试您的配置
# Test syntax before applying
nginx -t
# Reload without downtime
nginx -s reload
# Check which config file is active
nginx -T | grep "configuration file"
# Test a specific server block
curl -I https://ecosire.com
curl -I https://api.ecosire.com/api/health
# Check security headers
curl -I https://ecosire.com | grep -E "X-Frame|X-Content|Referrer|Content-Security"
常见问题
我应该在新项目中使用 Nginx 还是 Caddy?
Caddy 的配置要简单得多——它自动处理 Let's Encrypt SSL,并且具有开箱即用的合理默认值。 Nginx 更强大,并且拥有更大的模块和文档生态系统。对于大多数新项目来说,Caddy 是更好的起点;如果您需要对 SSL、复杂的上游路由或 Nginx 特定模块进行细粒度控制,请切换到 Nginx。对于已安装 Nginx 的现有 Linux 服务器,请坚持使用 Nginx。
如何避免重复的 limit_req_zone 错误?
limit_req_zone 指令必须出现在 http{} 上下文级别,而不是出现在 server{} 块内。在包含多个配置文件的 Turborepo monorepo 部署中,请确保该指令在所有包含的文件中仅出现一次。如果您看到错误,请检查是否有 conf.d/app.conf 和 sites-enabled/ 符号链接指向同一文件。
如何为 Next.js ISR(增量静态再生)配置 Nginx?
Next.js 在内部处理 ISR——Nginx 只需要将所有请求代理到 Next.js,而不缓存响应。不要添加干扰 Next.js 的 ISR 缓存标头的 Cache-Control 标头。对于 /_next/static/ 中的静态资源,请添加 immutable 缓存标头,因为这些文件具有内容哈希名称。对于所有其他路由,让 Next.js 设置缓存标头。
启用 Cloudflare 后,为什么我的 SSL 分数会下降?
当 Cloudflare 处于代理模式时,SSL 实验室会测试 Cloudflare 的 SSL,而不是您的 SSL。将 Cloudflare 的 SSL 模式设置为“完全(严格)”以确保 Cloudflare 验证您的原始证书。在您的服务器上安装 Cloudflare Origin 证书 — 它免费且有效期为 15 年。您的 SSL Labs 分数将成为 Cloudflare 的分数(通常是 A+),这实际上是对典型的自配置 Nginx SSL 设置的改进。
如何在同一服务器上处理多个 Node.js 应用程序?
在不同的端口上运行每个应用程序(Next.js 在 3000 上运行,NestJS 在 3001 上运行,Docusaurus 在 3002 上运行等),并在 Nginx 配置中为每个子域添加一个服务器块。使用 PM2 管理所有 Node.js 进程。 Nginx 按子域(或路径前缀)路由到正确的端口。每个服务器块都可以有自己的速率限制、缓存和安全标头配置。
后续步骤
生产 Nginx 配置是一个动态文档 - 它随着应用程序需求的变化、流量模式的变化以及新的安全最佳实践的出现而不断发展。 ECOSIRE 在生产环境中运行 Nginx,为多个应用程序提供服务,处理 SSL 终止、速率限制以及跨所有域的 Cloudflare 集成。
无论您需要 DevOps 咨询、生产基础设施设置还是完整的部署架构设计,探索我们的服务 以了解我们如何提供帮助。
作者
ECOSIRE Research and Development Team
在 ECOSIRE 构建企业级数字产品。分享关于 Odoo 集成、电商自动化和 AI 驱动商业解决方案的洞见。
相关文章
API Rate Limiting: Patterns and Best Practices
Master API rate limiting with token bucket, sliding window, and fixed counter patterns. Protect your backend with NestJS throttler, Redis, and real-world configuration examples.
Cybersecurity Trends 2026-2027: Zero Trust, AI Threats, and Defense
The definitive guide to cybersecurity trends for 2026-2027—AI-powered attacks, zero trust implementation, supply chain security, and building resilient security programs.
Financial Services ERP Implementation: Regulatory and Security Requirements
A practitioner's guide to implementing ERP in regulated financial services firms, covering security controls, compliance validation, data governance, and phased rollout.
更多来自Performance & Scalability
k6 Load Testing: Stress-Test Your APIs Before Launch
Master k6 load testing for Node.js APIs. Covers virtual user ramp-ups, thresholds, scenarios, HTTP/2, WebSocket testing, Grafana dashboards, and CI integration patterns.
Odoo Performance Tuning: PostgreSQL and Server Optimization
Expert guide to Odoo 19 performance tuning. Covers PostgreSQL configuration, indexing, query optimization, Nginx caching, and server sizing for enterprise deployments.
Odoo vs Acumatica: Cloud ERP for Growing Businesses
Odoo vs Acumatica compared for 2026: unique pricing models, scalability, manufacturing depth, and which cloud ERP fits your growth trajectory.
Testing and Monitoring AI Agents in Production
A complete guide to testing and monitoring AI agents in production environments. Covers evaluation frameworks, observability, drift detection, and incident response for OpenClaw deployments.
Compliance Monitoring Agents with OpenClaw
Deploy OpenClaw AI agents for continuous compliance monitoring. Automate regulatory checks, policy enforcement, audit trail generation, and compliance reporting.
Optimizing AI Agent Costs: Token Usage and Caching
Practical strategies for reducing AI agent operational costs through token optimization, caching, model routing, and usage monitoring. Real savings from production OpenClaw deployments.