WSの小屋

Nginx 配置详解:反向代理、负载均衡与安全加固

Nginx 是生产环境最常用的 Web 服务器和反向代理。但很多人的 Nginx 配置只停留在「能用」——没有性能调优、没有安全加固、没有正确的 HTTPS 配置。本文从真实生产环境出发,覆盖 Nginx 配置的核心场景。

反向代理配置

基础反向代理

server {
    listen 80;
    server_name example.com www.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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;
    }
}

WebSocket 代理

Node.js / Nuxt 项目中用了 WebSocket(如 HMR、实时通知),需要额外配置:

location /ws {
    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_read_timeout 86400;  # WebSocket 长连接超时
}

SSE(Server-Sent Events)代理

location /api/stream {
    proxy_pass http://127.0.0.1:3000;
    proxy_buffering off;           # 关闭缓冲,否则 SSE 会被攒着一起发
    proxy_cache off;
    proxy_set_header Connection '';
    proxy_http_version 1.1;
    chunked_transfer_encoding on;
}

静态文件 + API 代理混合

server {
    listen 80;
    server_name example.com;
    root /var/www/html;

    # SPA 前端:所有未匹配的路由回退到 index.html
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 静态资源:直接由 Nginx 处理(比 Node.js 快几倍)
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?|ttf)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # API 请求:代理到后端
    location /api/ {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # 上传文件大小限制
    client_max_body_size 50m;
}

负载均衡

基础负载均衡

upstream backend {
    # 默认轮询(round-robin)
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
    server 192.168.1.12:3000;
}

加权负载均衡

upstream backend {
    server 192.168.1.10:3000 weight=3;  # 性能强的机器权重高
    server 192.168.1.11:3000 weight=2;
    server 192.168.1.12:3000 weight=1;
}

最少连接数(适合请求耗时差异大的场景)

upstream backend {
    least_conn;
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
}

IP Hash(会话保持)

upstream backend {
    ip_hash;  # 同一 IP 总是分配到同一服务器
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;
}

健康检查与故障转移

upstream backend {
    server 192.168.1.10:3000 max_fails=3 fail_timeout=30s;
    server 192.168.1.11:3000 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:3000 backup;  # 备用,前面都挂了才启用
}
  • max_fails=3:30 秒内失败 3 次则标记为不可用
  • fail_timeout=30s:标记不可用后 30 秒内不再尝试
  • backup:备用服务器

HTTPS 配置

现代 HTTPS 配置

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;

    # SSL 证书
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # 只使用 TLS 1.2 和 1.3
    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;

    # 会话缓存(减少 TLS 握手开销)
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    # HSTS:强制浏览器后续都走 HTTPS
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
}

# HTTP 跳转 HTTPS
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

使用 Certbot 自动管理 Let's Encrypt 证书

# 安装 certbot
sudo apt install certbot python3-certbot-nginx

# 自动获取并配置证书
sudo certbot --nginx -d example.com -d www.example.com

# 自动续期(certbot 会自动添加 cron)
sudo certbot renew --dry-run

安全加固

隐藏版本号

# nginx.conf
server_tokens off;  # 不在响应头和错误页暴露 Nginx 版本

请求速率限制

# 定义限流区域
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;

server {
    # API 限流:平均 10 req/s,突发 20
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        proxy_pass http://backend;
    }

    # 登录接口更严格:1 req/s
    location /api/login {
        limit_req zone=login burst=5 nodelay;
        proxy_pass http://backend;
    }
}

并发连接数限制

limit_conn_zone $binary_remote_addr zone=conn:10m;

server {
    limit_conn conn 10;  # 每个 IP 最多 10 个并发连接
}

安全响应头

server {
    # 防止点击劫持
    add_header X-Frame-Options "SAMEORIGIN" always;

    # XSS 保护
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # CSP 策略
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.example.com;" always;

    # Referrer 策略
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # 权限策略
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
}

禁止访问敏感文件

location ~ /\.(git|env|htaccess) {
    deny all;
    return 404;
}

location ~ /\.(sql|bak|log|conf)$ {
    deny all;
    return 404;
}

性能优化

Gzip 压缩

gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript
           application/javascript application/json
           application/xml application/rss+xml
           application/atom+xml image/svg+xml;

Brotli 压缩(比 Gzip 压缩率更高)

# 需要 nginx brotli 模块
brotli on;
brotli_comp_level 4;
brotli_types text/plain text/css application/javascript application/json image/svg+xml;

缓冲区调优

# 代理缓冲区
proxy_buffer_size 16k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;

# 客户端缓冲区
client_body_buffer_size 16k;
client_header_buffer_size 4k;
large_client_header_buffers 4 8k;

日志优化(生产环境减少 IO)

# 只记录错误和关键请求
access_log /var/log/nginx/access.log combined buffer=32k flush=5s;

# 静态资源不记日志
location ~* \.(js|css|png|jpg|svg)$ {
    access_log off;
}

常用配置模板

Nuxt 3 SSR 部署

server {
    listen 80;
    server_name example.com;

    # Nuxt SSR
    location / {
        proxy_pass http://127.0.0.1:3000;
        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;

        # SSR 需要长连接超时
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
    }

    # Nuxt 静态资源(_nuxt/ 目录下的文件带 hash,可长期缓存)
    location /_nuxt/ {
        proxy_pass http://127.0.0.1:3000;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # HMR WebSocket(仅开发环境需要)
    location /_loading/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

灰度发布

# 利用 cookie 进行灰度分流
upstream stable {
    server 192.168.1.10:3000;
}

upstream canary {
    server 192.168.1.20:3000;  # 新版本
}

map $cookie_version $upstream_pool {
    default stable;
    canary canary;
}

server {
    location / {
        proxy_pass http://$upstream_pool;
    }
}

配置检查与重载

# 检查配置语法
sudo nginx -t

# 重载配置(不中断服务)
sudo nginx -s reload

# 查看当前连接数
nginx -V 2>&1 | grep -o with-http_stub_status_module
# 如果有 stub_status 模块,可以开启状态页检查连接数

总结

Nginx 配置的三个层次:

  1. 能用:反向代理 + HTTPS → 覆盖 80% 场景
  2. 好用:负载均衡 + 缓存 + Gzip → 性能提升
  3. 安全:限流 + 安全头 + 隐藏版本号 → 抵御常见攻击

建议把本文的配置模板保存下来,每次部署新项目时基于模板修改,避免从零开始。定期用 Mozilla SSL Config Generator 检查 SSL 配置是否跟上最新安全标准。

Comments | 0条评论