AWS EC2 instance behind AWS ELB cannot get the real client's IP address

I am very new with nginx setting. My API application running in an EC2 instance which is automatically created by my AWS Elastic Beanstalk environment. The application ues Nginx and the instance is behind ELB load balancer (classic). Route 53 domain routes the traffic to the ELB.

I send the packet from Postman or Packet Sender to that domain, but can never receive response. After check the nginx error log, find that the client IP is displayed as 10.0.2.63, but not the IP address of my PC. My real IP address 149.15x.1xx.2xx. I guess 10.0.2.63 is the VPC IP address. Below is the nginx error log.

while reading PROXY protocol, client: 10.0.2.63, server: 0.0.0.0:80

To my understanding, because the client IP is VPC IP address, the EC2 instance cannot send the reply to the real client IP address(my PC's IP address), therefore, Postmand or Packet Sender receives empty response.

Does I understand correctly? How can I let the EC2 instance receive the real client IP address? Like below:

while reading PROXY protocol, client: 149.15x.1xx.2xx, server: 0.0.0.0:80

I don't know it is the problem with AWS ELB setting or nginx setting.

The nginx config in my EC2 instance is:

files:
/etc/nginx/conf.d/proxy.conf:
content: |
  client_max_body_size 500M;
  server_names_hash_bucket_size 128;

  upstream backend {
    server unix:///var/run/puma/my_app.sock;
  }

  server {
    listen 80 proxy_protocol;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    large_client_header_buffers 8 32k;

    set_real_ip_from 10.0.0.0/8;
    real_ip_header X-Forwarded-For;

    location / {
      proxy_http_version 1.1;
      proxy_set_header X-Real-IP $proxy_protocol_addr;
      proxy_set_header X-Forwarded-For $proxy_protocol_addr;
      proxy_set_header Host $http_host;
      proxy_set_header X-NginX-Proxy true;
      proxy_buffers 8 32k;
      proxy_buffer_size 64k;
      proxy_pass http://backend;
      proxy_redirect off;

      # Enables WebSocket support
      location /v1/cable {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade "websocket";
        proxy_set_header Connection "Upgrade";
        proxy_set_header X-Real-IP $proxy_protocol_addr;
        proxy_set_header X-Forwarded-For $proxy_protocol_addr;
      }
    }
  }

Solution 1:

You get the Client IP from the X-Forwarded-For header. This AWS Blog post gives you config for Apache and Nginx logs. Here's Nginx

http {
  ...
  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;
}

I use CloudFlare in front of my Nginx server. Here's how I replace the CloudFlare IP with the actual Client IP. You would replace "CF-Connecting-IP" with "X-Forwarded-For" and replace the IP CIDR to the CIDR of your VPC.

set_real_ip_from 173.245.48.0/20;
real_ip_header CF-Connecting-IP;