Nginx as a Reverse Proxy & Web Server

Location matching, proxy_pass, HTTPS, gzip, rate limiting and buffering — the Nginx configs behind most production services.

BeginnerUpdated 2026-10-2855K views

Config file anatomy

Nginx config is a nested block tree: http wraps server (virtual hosts) wraps location (URI matching). Directives inherit downward, and location matching has a surprising precedence order.

main 上下文(nginx.conf)
└─ http {
     ├─ upstream api { server 10.0.0.5:8080; server 10.0.0.6:8080; }   ← 负载均衡组
     ├─ server {                ← 一个虚拟主机(一个域名/端口)
     │    listen 443 ssl http2;
     │    server_name api.example.com;
     │    ├─ location /  { proxy_pass http://api; }
     │    └─ location /static/ { root /var/www; expires 30d; }
     │  }
  }
Location modifierPriorityMeaning
= /uri1 最高精确匹配,匹配到立即停止
^~ /uri2前缀匹配命中后不再走正则
~ / ~* regex3正则(区分/不区分大小写),按在文件里的顺序
无修饰符 /uri4 最低最长前缀匹配
Regex locations are evaluated in the order they appear in the file, and the first win — this is why a careless ~ .*\.php location can hijack traffic you intended for a longer prefix match. Prefer ^~ for static paths.

Reverse proxy: the config you will reuse forever

server {
    listen 443 ssl http2;
    server_name api.example.com;

    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # 限流:按客户端 IP,每秒 10 个请求,突发 20 个排队
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

    location / {
        limit_req zone=api burst=20 nodelay;
        limit_req_status 429;

        proxy_pass http://api;                 # upstream 组
        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 3s;
        proxy_read_timeout    60s;
        proxy_send_timeout    60s;

        # 关闭缓冲,必须立刻收到的 SSE / 流式接口才需要
        # proxy_buffering off;
    }
}
For SSE / WebSocket / chunked streams you MUST set proxy_buffering off and Upgrade/Connection headers, otherwise Nginx buffers the whole response and the client hangs until timeout.
# WebSocket 升级
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}
# location 内:
proxy_set_header Upgrade    $http_upgrade;
proxy_set_header Connection $connection_upgrade;

Load balancing strategies

StrategyDirectivePick when
Round robin默认无状态服务,机器配置相近
Least connectionsleast_conn请求耗时差异大
IP haship_hash需要会话粘性(但应优先用无状态方案)
Consistent hash by keyhash $uri consistent缓存命中优先
Weightedserver x weight=3机器配置不同
upstream api {
    least_conn;
    server 10.0.0.5:8080 weight=3 max_fails=3 fail_timeout=10s;
    server 10.0.0.6:8080;
    server 10.0.0.7:8080 backup;     # 全挂了才启用
    keepalive 32;                    # 到上游的长连接池
}
Passive health checks (max_fails/fail_timeout) are default; the free nginx passive check can strand traffic to a slow node. If you need active checks or finer policy, look at HAProxy or nginx Plus.

Performance, compression and caching

http {
    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 5;
    gzip_types text/plain text/css application/json application/javascript
               text/xml application/xml image/svg+xml;
    gzip_vary on;

    # 客户端缓存 + 代理缓存(需要共享存储才能多副本一致)
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=apic:10m
                     max_size=1g inactive=30m use_temp_path=off;

    open_file_cache max=2000 inactive=20s;
    sendfile on;
    tcp_nopush on;
    keepalive_timeout 65;
}
  • gzip_comp_level above 5 wastes CPU for ~1% size gain; 4-5 is the sweet spot
  • Do NOT gzip images/video (already compressed) — CPU cost with negative gain
  • For static assets: cache-bust by versioned filenames (style.20261101a.css) + far-future Cache-Control
  • Verify config BEFORE reload: nginx -t, then nginx -s reload for zero-downtime
nginx -t              # 语法检查(reload 前必做)
nginx -s reload       # 平滑重载(SIGUSR1 式热生效)
nginx -s reopen      # 日志切割:mv 日志后重新打开文件句柄

Friends & Partners