Geofencing with Nginx and MaxMind’s GeoIP Database

Today I ran into an interesting problem that required me to geofence traffic from certain parts of the world. I knew about MaxMind’s GeoIP database and I also knew about the Nginx geoip module (ngx_http_geoip_module) so I had a starting point. What I wanted to do was drive traffic from selected countries to a static landing page to reduce the load on the dynamic infrastructure. After purchasing the GeoIP database I immediately uploaded it to my web server and then started building out my Nginx config file.

The first thing was to include the GeoIP database in the HTTP section of the Nginx master config file:

http {
    ...
    geoip_country  /path/to/GeoIP.dat;
    ...
}

Next up was to create a mapping for the countries that I wanted to geofence (in this example I’m geofencing India and China):

http {
    ...
    geoip_country  /path/to/GeoIP.dat;

    map $geoip_country_code $mapping {
        default     default;
        CN          fenced;
        IN          fenced;
    }
    ...
}

After creating the mappings we need to build a rudimentary config that proxies the incoming request to the appropriate backends. The important part here is that the mapping variable is used in the upstream names:

server {

    listen          80;
    server_name     example.com;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_pass http://$mapping.server;
    }
}

upstream fenced.server {
    server  127.0.0.1:9002;
}

upstream default.server {
    server  127.0.0.1:9001;
}

Finally all that is needed is to build out the configs for the ports we are listening on:


server {
    listen          9001;
    server_name     127.0.0.1;

    root    /path/to/webroot;
    index   index.html index.htm;

    location / {
        add_header X-Geo $geoip_country_code;
        add_header X-Geo3 $geoip_country_code3;
        add_header X-IP $remote_addr;

        try_files $uri $uri/ /index.html;
    }

}


server {
    listen          9002;
    server_name     127.0.0.1;

    root    /path/to/fenced;
    index   index.html index.htm;

    location / {
        add_header X-Geo $geoip_country_code;
        add_header X-Geo3 $geoip_country_code3;
        add_header X-IP $remote_addr;

        try_files $uri $uri/ /index.html;
    }

}

And thats it. Obviously the configs require a lot of work to get them to production ready however that is how I went about building a basic geofencing solution. I’d love to see other people’s solutions as I had trouble finding other examples online.

Leave a Reply

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