nginxreal-ip

What are the differences in obtaining the user's real IP in nginx?


Two nginxs, one for reverse proxy and one for backend application.

Configuration is as follows.

user -- https --> nginx reverse proxy -- http --> nginx (backend application)

Reverse proxy nginx configure:

http {

    # http block
    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;
    
    server {
        
        # server block
        proxy_set_header X-Real-IP        $remote_addr;
        proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
        
        location /  {
            # location block 
            proxy_set_header X-Real-IP       $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://jwjx.example.com;         
        }
    }
}

nginx (backend application) configure:

http {

    set_real_ip_from 202.192.xxx.0/26;
    set_real_ip_from 2001:192:xxx:8fa1::/64;
    real_ip_header X-Forwarded-For;
    #real_ip_recursive on;

    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log main;

}

Question: When the "proxy_set_header X-Real-IP $remote_addr" and "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;" are configured in the "http block" or "server block", the backend nginx access log cannot capture the user's real IP.

202.192.xxx.1- - [23/May/2025:22:00:11 +0800] "GET /nginxtest/ HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36 EdgA/136.0.0.0" "-"
202.192.xxx.1- - [23/May/2025:22:00:34 +0800] "GET /nginxtest/index.html HTTP/1.1" 200 13 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36 EdgA/136.0.0.0" "-"
202.192.xxx.1- - [23/May/2025:22:02:15 +0800] "GET /nginxtest/index.html HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36 EdgA/136.0.0.0" "-"
202.192.xxx.1- - [23/May/2025:22:02:17 +0800] "GET /nginxtest/index.html HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36 EdgA/136.0.0.0" "-"

However, when configured in the "location block", it can capture the user's real IP.

241a:452:dd19:23b1::1 - - [23/May/2025:22:12:04 +0800] "GET /nginxtest/index.html HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36 EdgA/136.0.0.0" "241a:452:dd19:23b1::1"
241a:452:dd19:23b1::1 - - [23/May/2025:22:12:05 +0800] "GET /nginxtest/index.html HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36 EdgA/136.0.0.0" "241a:452:dd19:23b1::1"
241a:453:dd8d:774b::1 - - [24/May/2025:18:11:01 +0800] "GET /nginxtest/ HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36 EdgA/136.0.0.0" "241a:453:dd8d:774b::1"
241a:453:dd8d:774b::1 - - [24/May/2025:18:11:03 +0800] "GET /nginxtest/ HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36 EdgA/136.0.0.0" "241a:453:dd8d:774b::1"
180.169.28.55 - - [24/May/2025:18:11:44 +0800] "GET /nginxtest/ HTTP/1.1" 200 13 "https://jwjx.example.com//nginxtest" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36" "180.169.28.55"
240e:469:dd8d:774b::1 - - [24/May/2025:20:57:39 +0800] "GET /nginxtest/index.html HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36 EdgA/136.0.0.0" "240e:469:dd8d:774b::1"
240e:469:dd8d:774b::1 - - [24/May/2025:20:57:40 +0800] "GET /nginxtest/index.html HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36 EdgA/136.0.0.0" "240e:469:dd8d:774b::1"

Why? which best?


Solution

  • The reason your backend NGINX cannot capture the user's real IP when proxy_set_header is set in the http or serverblock is because these settings can be overridden or ignored by the location block. To ensure headers are sent correctly, set them inside the location block.

    //Reverse Proxy NGINX:
    location / {
        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_pass http://backend_server;
    }
    
    // Backend NGINX:
    http {
        set_real_ip_from 202.192.xxx.0/26;
        set_real_ip_from 2001:192:xxx:8fa1::/64;
        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
    
        log_format main '$remote_addr - - [$time_local] "$request" $status '
                        '"$http_user_agent" "$http_x_forwarded_for"';
        access_log /var/log/nginx/access.log main;
    }