How to Configure Nginx as Reverse Proxy with Specific Source IP Address for Backend Connections


2 views

When using Nginx as a reverse proxy with multiple backend services, we often need precise control over which source IP address Nginx uses when connecting to upstream servers. This becomes critical when:

  • Backend servers have IP-based whitelisting
  • Multiple services run on the same host with different IP requirements
  • Network policies require traffic to originate from specific IPs

The proxy_bind directive in Nginx allows you to specify exactly which local IP address should be used for outgoing connections to backend servers. Here's how to implement it:

location /integracao/ {
    proxy_bind A.A.A.A;
    proxy_pass http://X.X.X.X:9080/integracao/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

location /solr/ {
    proxy_bind B.B.B.B;
    proxy_pass http://Y.Y.Y.Y:8080/solr/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

Here's a full server block example demonstrating proper implementation:

server {
    listen 80;
    server_name example.com;

    # First backend service using IP A
    location /service1/ {
        proxy_bind 192.168.1.100;
        proxy_pass http://backend1:8080/;
        
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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_cache_bypass $http_upgrade;
    }

    # Second backend service using IP B
    location /service2/ {
        proxy_bind 192.168.1.101;
        proxy_pass http://backend2:9080/;
        
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

For more complex setups, you might need additional configuration:

# Using variables for dynamic IP selection
map $host $bind_ip {
    hostnames;
    default 192.168.1.100;
    service1.example.com 192.168.1.100;
    service2.example.com 192.168.1.101;
}

server {
    listen 80;
    server_name ~^(www\.)?(?.+)$;

    location / {
        proxy_bind $bind_ip;
        proxy_pass http://backend/$domain;
    }
}
  • Verify IP binding with tcpdump -i any host backend_ip
  • Check Nginx error logs for binding failures
  • Ensure the IP addresses are properly configured on the server
  • Test connectivity separately with curl --interface before Nginx configuration

When using multiple IP addresses:

  • Connection pooling is per IP-port combination
  • Monitor kernel connection tracking table size
  • Consider using proxy_connect_timeout and proxy_next_upstream for resilience

When working with Nginx as a reverse proxy, we often need to control which source IP address gets used when connecting to backend servers. This becomes critical when:

  • Backend servers have IP-based access restrictions
  • Multiple services require different source IPs for identification
  • Network policies enforce specific routing paths

The most straightforward solution is Nginx's proxy_bind directive. Here's how to implement it:

server {
    listen 80;
    server_name example.com;

    location /integracao/ {
        proxy_bind A.A.A.A;  # Replace with your actual IP
        proxy_pass http://X.X.X.X:9080/integracao/;
        
        # 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;
    }

    location /solr/ {
        proxy_bind B.B.B.B;  # Replace with your actual IP
        proxy_pass http://Y.Y.Y.Y:8080/solr/;
        
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

After implementing, verify the source IP with these methods:

# Method 1: Check Tomcat access logs
tail -f /path/to/tomcat/logs/access.log

# Method 2: Use tcpdump on backend server
sudo tcpdump -i eth0 'port 9080 or port 8080' -nn -v

For more complex setups with upstream blocks:

upstream tomcat_integracao {
    server X.X.X.X:9080;
}

upstream solr_server {
    server Y.Y.Y.Y:8080;
}

server {
    location /integracao/ {
        proxy_bind A.A.A.A;
        proxy_pass http://tomcat_integracao;
    }
    
    location /solr/ {
        proxy_bind B.B.B.B;
        proxy_pass http://solr_server;
    }
}
  • Ensure the IP addresses are properly assigned to your server's network interfaces
  • Check firewall rules to confirm outbound connections are allowed from these IPs
  • Verify that the backend servers are configured to accept connections from these specific IPs
  • Test connectivity manually using curl --interface before Nginx configuration

For systems where proxy_bind isn't available (older Nginx versions), consider using iptables:

# Mark packets for specific backend routing
iptables -t mangle -A OUTPUT -p tcp --dport 9080 -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -p tcp --dport 8080 -j MARK --set-mark 2

# Create routing tables for each marked connection
echo "100 integracao" >> /etc/iproute2/rt_tables
echo "200 solr" >> /etc/iproute2/rt_tables

# Add routing rules
ip rule add fwmark 1 table integracao
ip rule add fwmark 2 table solr

# Configure source IPs for each table
ip route add default via A.A.A.A dev eth0 table integracao
ip route add default via B.B.B.B dev eth0 table solr