Dynamic DNS filtering for NGINX

James Young · December 11, 2013

Nginx is something that I’ve really come to appreciate since I moved my blog across to my own server.  However, it’s lacking a really great feature that I would love to have - the ability to dynamically update rules through DNS resolution.  I don’t have a static IP address for my home Internet connection, but I do use dynamic DNS.

In its default configuration, Nginx can’t do this (largely for performance reasons).  There are modules available for Nginx for this (like this), but I didn’t want to use one because there isn’t a whole lot of point.  So I made my own.

Nginx configurations revolve around include files.  What if we had a scripted process that generates an include file based on a DNS resolve and then reloads Nginx?  That’s exactly what I did.

Firstly, let’s assume the dynamic DNS record of your home connection is myhome.local .  Make a script in /etc/cron.daily or /etc/cron.hourly (depending how often you want nginx to reload, don’t do it too often);

#!/bin/bash
host myhome.local | grep "has address" | sed 's/.*has address //' | awk '{print "allow\t\t" $1 ";\t\t# Home IP" }' > /etc/nginx/conf.d/homeip.inc
service nginx reload > /dev/null 2>&1

Now, when that script runs, a file will be created at /etc/nginx/conf.d/homeip.inc that looks like this;

allow           192.168.1.1;                # Home IP

From there, it’s a simple matter to make an Nginx rule to let things coming from that IP through, for example;

location /zomgitworks {
    include /etc/nginx/conf.d/homeip.inc;
    deny all;

    alias /var/www/html/zomgitworks;
}

And now when you call http://yournginxbox/zomgitworks, you will get a 200 OK and content when you’re on your home IP, or a 403 Forbidden if you’re not.  Notably, if the DNS name doesn’t resolve for some reason, the generated file is blank so it does the right thing anyway (it just denies all access).

Of course, if your home IP changes, the rule will break until the next time the cron job runs.  You can run it yourself, of course.  So this won’t be suitable for things that change IP a lot (you should use the module for that), but it should be fine for things that change IP infrequently.

Twitter, Facebook