Divesting of docker, updating Namecheap DDNS
1168  words. Read time: 5 Minutes, 18 Seconds
2025-06-18 19:00 +0000
So there I was, on my long ride across the state for a visit to the office, no shit.
I was about 4 hours in, and sick of audio books and streaming my Soundcloud playlist. I wanted to get onto Jellyfin and stream some music from home that I didn’t have saved to my phone or flash drive that I keep in the car. But I couldn’t connect. I tried to connect to my VPN, and connect “locally” to Jellyfin (pro tip: setup local DNS records in Pihole/Unbound to your existing domains, so you can access your services the same way whether you’re home or abroad). It still didn’t work.
I have AT&T fiber, so I checked in the app quickly and all seemed well from outside to the ISP-provided router. I called my wife, she said the internet was working ok at home. I walked her through rebooting both the ISP router and our own, for good measure. Still no music, no blog (if you were trying to access this site ~1 week ago, my apologies), no nothing. I continued my trip, and just lived without. There’s only so much I can do from far away, and I had a full 10 hour day planned out at work with minimal time for sleep as it was.
When I got home I was prepared for the kids to assault me at the door with questions about their Minecraft/Terraria/CounterStrike issues. But surprisingly I was able to make it to the bedroom unmolested.
I poked and prodded a little after getting on the home wifi, and found the issue within 5 minutes. My DNS record at my host, Namecheap, was incorrect. At some point AT&T pushed a firmware update to their BG300 router, and assigned me a new IP. I had been using a small docker container to update every 10 minutes, but it had stopped working. If you’re using joshuamorris3/namecheap-ddns-update, maybe stop using it. It hasn’t been updated in over 4 years. Although in its defense, it did work flawlessly for like 3 years straight.
And yes, I tried to restart the docker container. Prune and re-pull the image. Etc.
Ok, shut up, guy. Let’s actually fix this.
First, I’m deleting this docker garbage. I don’t need a multiple MB piece of software to do what ubuntu server can do with zero overhead, besides less than 64k of additions to two plaintext files.
My plan is to:
- Delete the current (broken) solution
- Get it to update with (these instructions from Namecheap)[https://www.namecheap.com/support/knowledgebase/article.aspx/29/11/how-to-dynamically-update-the-hosts-ip-with-an-https-request/] in the browser
- Do the same, with curl
- Create a bash script
- Run that script every 10 minutes with cron
Get rid of docker solution
I mean, this isn’t difficult. If you ran the docker command once manually, stop it. Then prune it. If you used docker compose, stop it, and then delete the compose file. Pretty simple.
Get it to work in the browser
I tried it out on my laptop, running Linux Mint and Firefox browser, and was met with this error.
I painstakingly typed it all again, verbatim, into the chrome browser on my phone and it worked. So I guess firefox just does something a little differently. Oh well. We know the command works.
Making it work with curl
If you didn’t look at the instructions above, Namecheap wants this:
https://dynamicdns.park-your-domain.com/update?host=[host]&domain=[domain_name]&password=[ddns_password]&ip=[your_ip]
Default host is ‘@’, ‘*’ if you’re using a wildcard, or your subdomain if you’re doig it that way.
If you’re doing the record updating from a machine in the same local network, you don’t have to include the IP address explicitly. They will pull that auto-magically from their nginx/apache logs or whatever.
Again, if you didn’t read the instructions above yet, for the password field, they want your DDNS password, not your account password that you use to log into the Namecheap website. I know someone is going to do it…
Go to Namecheap, login, choose your domain, go to “manage”, and “advanced DNS settings” to find your DDNS password.
Curl wants it in this format.
$curl -G -d host=@ -d domain=fitib.us -d password=some_hex_string https://dynamicdns.park-your-domain.com/update
On the instruction page linked above, they clarify that in the browser it should be fine, but you will run into issues trying to do a POST command. They want all of it up front with a single GET request. So the -G forces curl to do that. Thanks to Daniel Stenberg and this post explaining the old magic of curl to us relatively youngins.
And you will add each variable with its own -d flag. Curl will append them all appropriately to the actual URL at the end to match what Namecheap needs.
This command worked just fine and gives me a response like this:
<?xml version="1.0" encoding="utf-16"?>
<interface-response>
<Command>SETDNSHOST</Command>
<Language>eng</Language>
<IP>108.222.51.159</IP>
<ErrCount>0</ErrCount>
<errors />
<ResponseCount>0</ResponseCount>
<responses />
<Done>true</Done>
<debug><![CDATA[]]></debug>
</interface-response>[1]- Done
Bash script
Now, we can finally make the bash script. We could just paste in what we have here, but I’d like to use variables in the script file that are on their own lines and easier to keep up with. If necessary, I can copy this file and easily modify it for something else in the future. Plus, my eyes aren’t as great as they used to be, and if I have to page through something in terminal with no word wrap, I’m sure to miss something. This format mitigates the risk of me fat fingering something.
!#/bin/sh
HOSTNAME=@
DOMAIN=fitib.us
PASSWORD=some_hex_string
curl -G -d host=$HOSTNAME -d domain=$DOMAIN -d password=$PASSWORD https://dynamicdns.park-your-domain.com/update
If you are needing to determine your public IP and send it in the request for some reason, use this instead.
!#/bin/sh
HOSTNAME=@
DOMAIN=fitib.us
PASSWORD=some_hex_string
IP='curl -s ipecho.net/plain'
curl -G -d host=$HOSTNAME -d domain=$DOMAIN -d password=$PASSWORD ip=$IP https://dynamicdns.park-your-domain.com/update
Make it executable and test is out if you want
$chmod +x namecheap-ddns-updater.sh
$bash namecheap-ddns-updater.sh
Add it as a cron job
$crontab -e
The first time you do this, it will ask which text editor you want to use.
Then add a line on your cron config file.
*/10 * * * * [your file path]/namecheap-ddns-updater.sh
Here’s a quick intro to crontab, for those that need it.
The end
That’s it! Now you can update Namecheap DDNS without having to rely on someone maintaining a docker image.
Make sure this is somewhere that will always come back up if you lose power. I have this on Proxmox in a VM for my essentials that manage my home network. I.e. Omada controller, Network UPS Tool, etc. So this is literally the first VM that I’ll get back if something goes wrong.
Theoretically, I could lose power when gone, and NUT would fail to gracefully shut down my cluster. I’d lose power in a bad way, and have to wait for fsck on boot (for a 8TB x2 mirrored ZFS pool, which isn’t a quick process). So I should really migrate this over to the Pi that’s running Pihole/Unbound. That thing will hard reboot a hundred times and not have problems. But I’m not that paranoid (yet).