Wednesday, January 1, 2014

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?

Nginx web server does support if conditionalconfiguration. 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

0 comments:

Post a Comment