This article explains how to configure NGINX and NGINX Plus to accept the PROXY protocol.

Table of Contents

Introduction

The PROXY protocol enables NGINX and NGINX Plus to receive client connection information passed through proxy servers and load balancers such as HAproxy and Amazon Elastic Load Balancer (ELB).

The information passed via the PROXY protocol is the client IP address, the proxy server IP address, and both port numbers. Knowing the originating IP address of a client may be useful for setting a particular language for a website, keeping a blacklist of IPs, or simply for logging and statistics purposes.

With the PROXY protocol, NGINX can learn the originating IP address from SSL, HTTP/2, SPDY, WebSocket, and TCP.

Using the PROXY protocol with SSL, HTTP/2, SPDY, and WebSocket

To make NGINX accept the PROXY protocol with SSL, HTTP/2, SPDY, and WebSocket, make the following changes on the http level:

    1. Configure NGINX to accept the PROXY protocol headers. Add the proxy_protocol parameter to the listen directive:
      server {
          listen 80   proxy_protocol;
          listen 443  ssl proxy_protocol;
          ...
      }
    2. In the set_real_ip_from directive, specify the IP address or the CIDR range of addresses of the TCP proxy or load balancer:
      server {
          ...
          set_real_ip_from 192.168.1.0/24;
          ...
      }
    3. In the real_ip_header directive, add the proxy_protocol parameter that will keep the client’s IP address and port number:
      server {
          ...
          real_ip_header proxy_protocol;
      }
    4. Pass the client IP address from NGINX to an upstream server with the proxy_set_header directive and the $proxy_protocol_addr variable:
      proxy_set_header X-Real-IP       $proxy_protocol_addr;
      proxy_set_header X-Forwarded-For $proxy_protocol_addr;
    5. Add the $proxy_protocol_addr variable to the log_format directive on the http level:
      http {
          ...
          log_format combined '$proxy_protocol_addr - $remote_user [$time_local] '
                              '"$request" $status $body_bytes_sent '
                              '"$http_referer" "$http_user_agent"';
      }

Using the PROXY protocol with a TCP Stream

NGINX can be configured to pass the PROXY protocol data for a TCP stream.
In the NGINX Plus configuration file, include the proxy_protocol directive in the server block on the stream level:

stream {
    server {
        listen 12345;
        proxy_pass example.com:12345;
        proxy_protocol on;
    }
}

Complete Example

http {
    log_format combined '$proxy_protocol_addr - $remote_user [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent"';
    ...

    server {
        server_name localhost;

        listen 80   proxy_protocol;
        listen 443  ssl proxy_protocol;

        ssl_certificate      /etc/nginx/ssl/public.example.com.pem;
        ssl_certificate_key  /etc/nginx/ssl/public.example.com.key;

        set_real_ip_from 192.168.1.0/24;
        real_ip_header   proxy_protocol;

        location /app/ {
            proxy_pass       http://backend1;
            proxy_set_header Host            $host;
            proxy_set_header X-Real-IP       $proxy_protocol_addr;
            proxy_set_header X-Forwarded-For $proxy_protocol_addr;
        }
    }
} 

stream {
...
    server {
        listen         12345;
        proxy_pass     example.com:12345;
        proxy_protocol on;
    }

}

The example assumes that there is a load balancer in front of NGINX, for example, Amazon ELB that balances all incoming HTTPS traffic. NGINX accepts the HTTPS traffic on port 443 (listen 443 ssl;), and accepts the client’s IP address passed from the load balancer via the PROXY protocol as well (the proxy_protocol parameter). The load balancer address is specified in the set_real_ip_from directive. The client’s IP address is passed in the proxy_protocol parameter from the real_ip_header directive.

NGINX terminates the HTTPS traffic (the ssl_certificate and ssl_certificate_key directives) and proxies the decrypted data to a backend server (proxy_pass http://backend1;) including the client’s IP address and port (the values of the proxy_set_header directives).

The proxy_protocol_addr variable specified in the log_format directive also passes the client’s IP address to the log.

A TCP server (the stream block) accepts the TCP traffic from the load balancer and passes it to the example.com server (the proxy_pass directive), and the proxy_protocol on; directive tells NGINX to pass the PROXY protocol data to the TCP server.