≡ Menu

Nginx: Redirect Backend Traffic Based Upon Client IP Address

I have four Apache backend servers in front of nginx reverse proxy server. How do I make sure nginx reverse proxy load balancer always send specific client IP address (say IP 1.2.3.4) request to http://apachereadwrite/ backend and rest to http://apachereadonly/ backend?

Tutorial details
DifficultyEasy (rss)
Root privilegesYes
RequirementsNone
Estimated completion time5m
Nginx web server does support if conditional configuration. You can redirect and/or select configuration depending on client ip address. In this case you need to use the variable called $remote_addr which can be used to retrieve information about the users ip address. This is useful if you want to give file upload capabilities to your own office IP address and read-only capabilities to the rest of the world based upon client IP address or vpn address:

      File upload is disabled on
        server {A,B,C} via php
           +------+  +-----+  +-----+  +-----+
           |      |  |     |  |     |  |     |
           |      |  |     |  |     |  |     |
 Backends  |  A   |  |  B  |  |  C  |  |  D  | File upload enabled
           |      |  |     |  |     |  |     | on server D via PHP
           |      |  |     |  |     |  |     |
           |      |  |     |  |     |  |     |
           +--+---+  +-+---+  +--+--+  +-+---+
              |        |         |       |
              |        |         |       |
              +--------+---------+-------+
                             |
                             |
                         +---+---+
                         |       |
                         |       |
                         |       |
                         |       |
                         |       |
                         |       |
                         +-------+
                       nginx reverse proxy server

Edit the file /etc/php.ini on server {A,B,C}, type:
# vi /etc/php.ini
Make the following changes to /etc/php.ini:

 
# Disallow uploading altogether this makes moving or injecting bad scripts/code onto your web server more difficult
file_uploads = Off
 
# Disallow treatment of file requests as fopen calls
allow_url_fopen = Off
allow_url_include = Off
 

Restart Apache server on {A,B,C}. Make sure file upload is enabled on server A by editing php.ini and setting the following entries:

 
file_uploads = On
upload_max_filesize=2M
post_max_size=4M
 

Nginx syntax

The syntax is as follows:

if ( $remote_addr ~* ip-address-here ) {
           proxy_pass http://YOUR-BACKEND-HERE;
}

First set default proxy_pass:

 
## Default backend is apachereadonly ##
proxy_pass  http://apachereadonly;
 

Check for client ip address:

 
## If IP is 1.2.3.4 send backend to apachereadwrite ##
if ( $remote_addr ~* 1.2.3.4 ) {
    proxy_pass http://apachereadwrite;
}
 

Examples

Edit nginx.conf file, enter:
# vi nginx.conf
Edit/append as follows:

 
   ## apachereadonly backend ##
   upstream apachereadonly  {
     server 10.10.11.10:8011; 
     server 10.10.11.11:8011; 
     server 10.10.11.12:8011; 
     ip_hash; 
   }
   ## apachereadwrite backend ##
  upstream apachereadwrite {
     server 10.10.11.13:8011;
 
   }
 
        ## config ##
        location / {
                proxy_set_header        Accept-Encoding   "";
                proxy_set_header        Host              $http_host;
                proxy_set_header        X-Forwarded-By    $server_addr:$server_port;
                proxy_set_header        X-Forwarded-For   $remote_addr;
                proxy_set_header        X-Forwarded-Proto $scheme;
                proxy_set_header        X-Real-IP         $remote_addr;
                ## default backend
                proxy_pass  http://apachereadonly;
                ## send traffic to apachereadwrite backend if ip is 1.2.3.4 ##
                if ( $remote_addr ~* 1.2.3.4 ) {
                        proxy_pass http://apachereadwrite;
                }
                proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        }
        ## rest of config ##
 

Save and close the file. Restart / reload nginx server:
# /etc/init.d/nginx reload
OR
# /usr/sbin/nginx -s reload

Tweet itFacebook itGoogle+ itPDF itFound an error/typo on this page?

{ 3 comments… add one }

  • Alexander Kuznetcov February 19, 2014, 11:12 am

    Other way is to use MAP module for switching backends for special remote addresses
    http://nginx.org/en/docs/http/ngx_http_map_module.html

    Example of configuration:

    ## apachereadonly backend ##
    upstream apachereadonly  {
      server 10.10.11.10:8011;
      server 10.10.11.11:8011;
      server 10.10.11.12:8011;
      ip_hash;
    }
    ## apachereadwrite backend ##
    upstream apachereadwrite {
      server 10.10.11.13:8011;
    }
    ## define default backend and backend for special remote addresses
    map $remote_addr $backend {
      default apachereadonly;
      1.2.3.4 apachereadwrite;
    }
    ## virtual host
    server {
      listen 80;
      server_name  example.com;
      # your configuration here
      location / {
        proxy_set_header        Accept-Encoding   "";
        proxy_set_header        Host              $http_host;
        proxy_set_header        X-Forwarded-By    $server_addr:$server_port;
        proxy_set_header        X-Forwarded-For   $remote_addr;
        proxy_set_header        X-Forwarded-Proto $scheme;
        proxy_set_header        X-Real-IP         $remote_addr;
        proxy_pass  http://$backend;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
      }
    }
    

Leave a Comment