DNS is infuriating to me. It exists in the uncanny valley of technologies where on paper I know a decent amount about it, but in reality I just flounder aimlessly and ultimately end up in an IRC channel somewhere spilling my woes to any (seemingly mystically intelligent) kind soul who will help me debug my issues. This does not pair well with trying to host your own server in your living room.
I had all my DNS issues tidied up enough to forget about them (the ideal state of affairs for DNS in my opinion) while I was living in Ireland and my ISP by default gave out static IPv4 addresses, or if not, changed them so infrequently that I didn't experience a change in over a year. However, with a new ISP in Berlin, I had quite a different experience. After congratulating myself on the quality of the infrastructure-as-code I had developed, so that even after 5 months of downtime, I could just plug in my server again, connect it to the WiFi, and it was back online, I went to bed happy. The following morning, however, I woke up to find that my IP address had changed overnight. I gave the DNS provider a call, and they informed me that a static IP address can easily be provided, but it will cost an additional ten euro per month. They reassign IP addresses every 24 hours too, just to be annoying about it. This means you can't rely on a rarely updating dynamic IP address either.
I felt personally attacked at the thought of paying for a static IP address, and for some inexplicable reason, I didn't want to use existing Dynamic DNS solutions. Maybe some vague notion of not wanting another external resource that I'd have to pay for or could break due to a misconfiguration, but most likely it was just stubbornness. Enter DIYnDNS! A simple Python script that will check if my IP address has changed in the last N minutes, and if so, connect to Cloudflare, update my DNS records to point at the new IP address, then go back to sleep until it notices the IP address has changed again.
This is all pretty straightforward, but there are a few nice aspects and things I learned along the way.
- First of all, this is all packaged up in a nice and small Docker container, which allows me to also make a simple
docker-compose
file to allow it to be installed with ease on any reverse proxy setup likeCaddy
orTraefik
. - Secondly, it uses a plain
.ini
file for configuration, which I never understood why people used before. I think I'll be using.ini
files for my configuration in future Python projects, primarily due to the inbuiltconfigparser
library and how easy it was to use. - Thirdly, there's a watchtower container defined in the
docker-compose
file too, which will automatically update thediyndns
container whenever there's a new image pushed to docker hub. - Finally, this container is updated on every push to the repository's
main
branch using some straightforward Github Actions CI.
The fact that all of this is possible with just some glorified configuration files and one easy to throw together python script is amazing to me. I really feel like anyone who isn't on the boat of self-hosting simple services, and understanding even the basics of how to put together a full CI/CD system like this, is missing out.
Finally, there are a good few areas that need to be improved. For starters, I should be able to configure the cron
from the config file somehow, but I had horrific trials trying to get the crontab
to respect env vars, follow my PATH
etc. Best solution for this is likely to put it in a systemd
service file, or else some baked in Python threading tool. I also think my usage of configparser
could be better. I want to explore the library more so I can use it for other projects in the near future.
Thank you for reading, and please get in touch if you have any comments, advice, or suggestions. My next post will be about the hassle I had and the effort I put in to try getting this setup working with Namecheap, my original DNS provider. It was significantly more involved than this and ultimately was ridiculous enough that I moved my DNS to Cloudflare!