Operations 20 min read

Unlock Nginx Power: Load Balancing, Static Serving, Logging, Security & Gray Release Guide

This article walks you through practical Nginx configurations covering reverse‑proxy load balancing, static resource handling, cache control, version hiding, JSON‑formatted logging, rate‑limiting, IP restrictions, gray‑release traffic splitting, security headers and DNS anti‑spoofing, with ready‑to‑use code examples.

Lin is Dream
Lin is Dream
Lin is Dream
Unlock Nginx Power: Load Balancing, Static Serving, Logging, Security & Gray Release Guide

1. Load Balancing

Nginx performs reverse proxy, rate limiting, and load balancing through .conf files. Below is a basic single‑node proxy configuration (only forwards to one Tomcat instance) and a production‑grade upstream with weighted round‑robin and fail‑over settings.

server {
    listen 80;
    location /testapi/ {
        proxy_pass http://178.168.1.10:9120/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Real-Port $remote_port;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size 8M;
        client_body_buffer_size 128k;
        proxy_connect_timeout 10s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

upstream openserver-api {
    server 127.0.0.1:8900 weight=100 max_fails=10 fail_timeout=15s;
    server 127.0.0.1:8901 weight=100 max_fails=10 fail_timeout=15s;
}

server {
    listen 80;
    location /test-api/ {
        proxy_pass http://openserver-api/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Real-Port $remote_port;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size 8M;
        client_body_buffer_size 128k;
        proxy_connect_timeout 10s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

The weighted strategy distributes requests evenly; if a node returns 500 ten times within 15 seconds, it is automatically taken out of rotation.

2. Static Resource Access

For modern Vue front‑end projects, map a URL path to the compiled dist directory using alias and try_files to serve the correct file or fallback to index.html.

server {
    listen 80;
    server_name example.com;
    location /page/ {
        alias /home/user/web/page/dist/;
        try_files $uri $uri/ /page/index.html;
    }
}

alias vs. root : alias replaces the matched part of the request path directly, while root appends the request URI to the defined root directory.

3. Hide Version Number

Expose only the server name without version information to avoid revealing vulnerable versions.

Nginx version hiding
Nginx version hiding
# Disable version in HTTP block
server_tokens off;

# Override fastcgi_params to hide version
fastcgi_param SERVER_SOFTWARE nginx;

4. Log Management

Configure automatic log rotation and JSON formatting for easier aggregation (e.g., ELK, Flume).

# JSON log format
log_format json '{"remote_addr":"$remote_addr","connection":"$connection","connection_requests":"$connection_requests","remote_user":"$remote_user","time_local":"$time_local","request_length":"$request_length","request":"$request","status":"$status","request_time":"$request_time","upstream_response_time":"$upstream_response_time","body_bytes_sent":"$body_bytes_sent","content_length":"$content_length","http_x_forwarded_for":"$http_x_forwarded_for","upstream_addr":"$upstream_addr","http_referer":"$http_referer","http_user_agent":"$http_user_agent"}';

http {
    access_log /var/log/nginx/access.log json;
    # other http settings …
}

# Example JSON log entry
{"remote_addr":"180.101.49.58","connection":"3","connection_requests":"1","remote_user":"-","time_local":"18/Jan/2025:08:02:38 +0000","request_length":"1237","request":"POST /api/queryList HTTP/1.1","status":"200","request_time":"0.112","upstream_response_time":"0.111","body_bytes_sent":"1574","content_length":"2","http_x_forwarded_for":"-","upstream_addr":"180.101.49.58:18105","http_referer":"http://example.com:18105/query/?token=erwerwer&activityId=werwer&level=100","http_user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"}

5. Gray Release

Use Nginx weight‑based upstreams to gradually shift traffic between versions for safe deployments.

# Example gray‑release upstream
upstream openserver-api {
    server 127.0.0.1:8900 weight=80;  # old version
    server 127.0.0.1:8901 weight=20;  # new version
}

server {
    listen 80;
    location /api/ {
        proxy_pass http://openserver-api/;
    }
}

6. Extension Modules

6.1 Rate Limiting (IP based)

# Limit requests per IP to 10 per minute
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/m;
server {
    location / {
        limit_req zone=one burst=5 nodelay;
        # other config …
    }
}

6.2 IP Access Control

# Allow specific IPs, deny the rest
allow 192.168.1.1;
allow 203.0.113.2;
deny all;

IP lists can be moved to an external file and included:

# In main server block
include /nginx/conf/limitip.conf;
# limitip.conf example
deny 192.168.1.100;
deny 203.0.113.50;

6.3 Country‑Based Access (allow only China)

geo $allowed_country {
    default 0;      # deny all by default
    101.0.0.0/8 1; # China IP ranges (example)
    103.0.0.0/8 1;
    106.0.0.0/8 1;
    # …add more CIDR blocks as needed
}

server {
    listen 80;
    location / {
        if ($allowed_country = 0) { return 403; }
        # normal processing …
    }
}

6.4 Security Headers

location / {
    add_header Cache-Control "no-cache, no-store, must-revalidate";
    add_header Pragma "no-cache";
    add_header Expires 0;
    add_header X-Frame-Options DENY;
    add_header X-Xss-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";
    add_header Content-Security-Policy "default-src 'self';" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header Access-Control-Allow-Origin "*";
    add_header X-Download-Options "noopen";
}

6.5 DNS Spoofing Prevention

Define a default server that catches unmatched hostnames or direct IP access and returns the non‑standard 444 status to close the connection.

server {
    listen 80 default_server;
    server_name _;
    return 444; # close connection without response
}

Q&A

Q1: Difference between remote_addr and http_x_forwarded_for ?

A: remote_addr is the IP address of the immediate TCP peer (the last proxy or client). It cannot be forged because a TCP handshake is required. http_x_forwarded_for is an HTTP header that records the full chain of client IPs as the request passes through multiple proxies, with each proxy appending its remote_addr. The last entry in X‑Forwarded‑For is the original client IP; the final proxy’s IP is available via remote_addr.

Q2: Why does Nginx sometimes return 502 or fail to connect?

Common causes include expired domain certificates, missing ICP备案 (in China), or upstream servers being temporarily unavailable. Adding max_fails, fail_timeout, and keepalive settings, as well as checking TCP state (e.g., TIME_WAIT, ESTABLISHED) helps diagnose and mitigate the issue.

Q3: How to handle high‑traffic load testing failures?

Ensure proper upstream timeout settings ( proxy_http_version 1.1), increase keepalive connections, and verify that the kernel’s network parameters are not too low, which could cause packet loss under heavy load.

All the above configurations constitute a comprehensive Nginx cheat‑sheet for production environments.

Load BalancingConfigurationloggingsecurityNginx
Lin is Dream
Written by

Lin is Dream

Sharing Java developer knowledge, practical articles, and continuous insights into computer engineering.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.