When implementing an Nginx reverse proxy configuration, many developers encounter situations where backend services only see 127.0.0.1 (localhost) as the client IP address instead of the actual remote client's IP. This is particularly problematic when:
- Implementing IP-based security controls
- Generating accurate access logs
- Implementing geo-based features
- Tracking user sessions
Based on the described infrastructure:
Client → Nginx Reverse Proxy (VM1) → Frontend (NG-Engine) → Backend (Spring/Java) → Data Servers (VM2-x)
Here's a fully corrected nginx.conf configuration that properly handles client IP propagation:
server {
listen 443 ssl;
server_name test-server;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
# Security headers
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" always;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
location / {
proxy_pass http://localhost:6789;
proxy_http_version 1.1;
# Essential IP forwarding headers
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;
# Connection upgrade headers if using WebSockets
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Additional recommended settings
proxy_redirect off;
proxy_buffers 8 16k;
proxy_buffer_size 32k;
proxy_read_timeout 90;
}
}
For Spring Boot applications, you need to configure the trust of proxy headers:
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto
server.tomcat.internal-proxies=10\\.10\\.10\\.15|127\\.0\\.0\\.1
server.forward-headers-strategy=framework
To verify the configuration works:
- Add logging in your backend service to print the X-Forwarded-For header
- Make a request through the proxy while monitoring both Nginx and backend logs
- Check that the client IP appears in both locations
For more complex scenarios with multiple proxy hops:
# In nginx.conf
real_ip_header X-Forwarded-For;
set_real_ip_from 10.10.10.0/24; # Your proxy IP range
set_real_ip_from 127.0.0.1;
This ensures Nginx will properly parse client IPs even when requests pass through multiple proxies.
- Verify Nginx has http_realip_module installed (nginx -V)
- Check for conflicting headers in upstream services
- Ensure no middleware is stripping headers between services
- Confirm your backend framework is configured to read forwarded headers
When working with multi-tier architectures involving reverse proxies, one of the most common challenges is maintaining the original client IP address throughout the request chain. Many developers encounter situations where their backend services only see the proxy server's IP (typically 127.0.0.1) instead of the actual client address.
In this particular setup, the request flows through several components:
- Client browser (external VM or remote desktop)
- Nginx reverse proxy (VM1)
- NgEngine frontend service (VM1)
- Java/Spring backend (VM1)
- Various data servers (VM2..x)
To properly pass the client IP through all layers, we need to ensure:
1. Nginx properly sets X-Forwarded-For header
2. The real_ip module is correctly configured
3. Downstream services properly interpret the forwarded headers
Here's the corrected nginx configuration that properly handles client IP forwarding:
server {
listen 443 ssl;
server_name test-server;
# SSL configuration omitted for brevity
location / {
proxy_pass http://localhost:6789;
proxy_http_version 1.1;
# Standard proxy headers
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;
# WebSocket support headers
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Important real_ip directives
real_ip_header X-Forwarded-For;
set_real_ip_from 127.0.0.1;
set_real_ip_from 10.10.10.0/24; # Your internal network range
}
}
Several important points to verify:
- The
real_ip
module must be compiled into Nginx (confirmed in yournginx -V
output) set_real_ip_from
must include all trusted proxy IPs- Downstream services must be configured to read the X-Forwarded-For header
For a Spring Boot application to properly use the forwarded headers, add this to your application.properties:
server.forward-headers-strategy=framework
server.tomcat.remoteip.remote-ip-header=x-forwarded-for
server.tomcat.remoteip.protocol-header=x-forwarded-proto
If you're still seeing 127.0.0.1, follow these debugging steps:
- Check Nginx access logs for the actual headers being sent
- Verify the request headers reaching your backend service
- Test with a simple endpoint that echoes back the headers
- Ensure no intermediate services are overwriting the headers