Nginx proxy based IP whitelisting for your underlying service

Nginx is one of the most sought-after webservers when intended for reverse proxy or static content serving. Let’s see how we can use nginx to restrict IP addresses that can access underlying services when nginx is configured as a proxy.

Configuring the nginx conf file

The first part is to have a working nginx configuration file that we will be using for setting up a site. Please note that you could use your existing conf file if you have a domain already configured.

Creating the configuration file

A configuration file in the nginx will decide how incoming request for a particular domain/resource need to be handled. We can specify the domain to be used,  redirections and proxy settings in this file. This is where we will be specifying the IP whitelisting as well.

Following would be a typical configuration file:

server {

        listen 80;
        server_name api.example.com ,localhost;

        # Handler for the root location
        location / {

                proxy_set_header   X-Real-IP $remote_addr;
                proxy_set_header   Host      $host;
                proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Proto $scheme;
                proxy_set_header   X-Forwarded-Host $host;
                proxy_set_header   X-Forwarded-Server $host;
                proxy_pass         http://127.0.0.1:81;
                proxy_redirect     http://127.0.0.1:81 http://api.example.com;
        }

}

We can save the file as api.example.com.conf file under /etc/nginx/conf.d/ folder and when you restart the nginx configuration, it would pick up the .conf files and load.

Following things are done in the configuration file:

  • Listen to the 80 port
  • Handle the requests coming in for the api.example.com domain
  • We have one handler for the root location which proxies the requests to the service running in the localhost port 81.

Restricting the traffic from IP addresses

The above configuration as such does not have any restrictions and would allow traffic from all sources. Now if we want to restrict the source IP addresses or domain, we can update our configuration as below:

server {

        listen 80;
        server_name api.example.com ,localhost;

        # Handler for the root location
        location / {
                # The ip addresses to be allowed
                allow 123.123.123.123;
                allow 124.125.126.127;
                allow www.mydomain.com;
                allow api.mydomain.com;
             
                # Finally deny all other traffic
                deny all;         
                proxy_set_header   X-Real-IP $remote_addr;
                proxy_set_header   Host      $host;
                proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Proto $scheme;
                proxy_set_header   X-Forwarded-Host $host;
                proxy_set_header   X-Forwarded-Server $host;
                proxy_pass         http://127.0.0.1:81;
                proxy_redirect     http://127.0.0.1:81 http://api.example.com;
        }
}

As you can see in the above configuration, we have first specified the IP addresses and the domain names from which we would allow the traffic to hit the nginx proxy. At the end we have added deny all so that all other sources would be denied.

It is important to keep the deny all; after the allowed sources as otherwise deny would get precedece and would not consider the subsequent allowed sources

Restart the nginx once the configuration is done. That’s all we need to restrict the IP addresses accessing the proxied resources.

When you request a nginx resource from a non-whitelisted IP, you would receive the following response:

Please make sure that you only allow port 80 / 443 ( SSL ) traffic through your firewall. If your underlying service ( in the above config, port 81 )  is available to the public , there is no practical use for whitelisting the proxy redirection in nginx.

Creating a file with allowed sources

It is possible that you might have many sources to be configured and its difficult to manage in the same conf file. For ease of use, you could create a file containing all the sources and then include them in the conf file as below

First, create a file with whitelist sources. Lets name is mysources.whitelist and have it saved under /etc/nginx/app/mysources.whitelist

The following could be placed inside the mysources.whitelist file:

# The ip addresses to be allowed
allow 123.123.123.123;
allow 124.125.126.127;
allow www.mydomain.com;
allow api.mydomain.com;

Now you can update the configuration file as below to include the whitelist file :

server {

        listen 80;
        server_name api.example.com ,localhost;

        # Handler for the root location
        location / {
                # The ip addresses to be allowed             
                include /etc/nginx/app/mysources.whitelist;

                # Finally deny all other traffic
                deny all;         
                proxy_set_header   X-Real-IP $remote_addr;
                proxy_set_header   Host      $host;
                proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Proto $scheme;
                proxy_set_header   X-Forwarded-Host $host;
                proxy_set_header   X-Forwarded-Server $host;
                proxy_pass         http://127.0.0.1:81;
                proxy_redirect     http://127.0.0.1:81 http://api.example.com;
        }
}

This would include the rules that you have set in the mysources.whitelist file while loading the configuration. Now you only need to edit the single file for updating the allowed sources.

Please note that you still need to restart the nginx server to have the changes done to whitelist file to have effect.

Conclusion

There is no denying that nginx is pretty configurable and is being used more and more on servers as a reverse proxy. Though not a foolproof method, the IP whitelisting does provide the first line of defence when you want to have unwanted sources away from you underlying APIs.

The configuration described in this post is currently only handling HTTP traffic. You could check the following post on how to configure https with Letsencrypt SSL below:

Let me know if you have any queries or comments regarding the configuration in the comments section below.

regards
Microideation

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *