This Time Self-Hosted
dark mode light mode Search

In the land of dynamic DNS

In the previous post I talked about my home network and services, and I pointed out how I ended up writing some code while trying to work around lack of pure-IPv6 hosts in Let’s Encrypt. This is something I did post about on Google+, but that’s not really a reliable place to post this for future reference, so it’s time to write it down here.

Update 2021-12-20: obviously, that was a bad idea. But guess who had a backup of the posts available?

So this past couple of days I ended up implementing DNS updaters for both and Main reason why I’m doing this is that I’d like to have a provider that both allow me IPv6 dynamic DNS updates and dns-01 challenges for Let’s Encrypt. (As it turns out, actually should have both, but it does not allow you to define your custom sub-domain, like even though I have the “Pro” package.)

Thus I currently have a (not-yet-releasable) go repository with the updaters for those two services, even though Afraid does not really need one, and I indeed solved the problem there by using a single curl -6 call. I also have tested dns-01 challenge with lego and Gandi.

But at the end, before going to sleep, my impression is that I trust Afraid more than Gandi, even though it is not perfect (e.g. by default Afraid provides you a non-HTTPS endpoint.) Indeed, Afraid provides you with one token per host you want to update, and the token can only update that one host. So if your token gets in bad folks’ hands, they can at most hijack the one host.

But if a Gandi API key is leaked, or somehow manages to be accessible to an attacker… every domain and every zone is attackable. Because there is no other validation. That key, is a single string token that effectively sidesteps every other bit of authentication, including 2FA. I just deactivated my production key. I have working code, but I won’t use it.

I sure hope that the service owner at Afraid can tell me of an API to change TXT records on their side. I really would like to keep using them for my home services’. If that fails, I may take Hector’s advice and just build my own.

Me on Google+ — 2016-06-12 00:35:41+0000

In the post I referred to the fact that, up until around April this year, Let’s Encrypt did not support IPv6-only hosts, and since I only have DS-Lite connectivity at home, I wanted that. To be precise, it’s the http authentication that was not supported on IPv6, but the ACME protocol (which Let’s Encrypt designed and implements) supports another authentication method: dns-01, at least as a draft.

Since this is a DNS-based challenge, there is no involvement of IPv4 or IPv6 addresses altogether. Unfortunately, the original client, now called certbot, does not support this type of validation, among other things because it’s bloody complicated. On the bright side, lego (an alternative client written in Go), does support this validation, including a number of DNS provider code supported.

Unfortunately,, which is the dynamic host provider I started using for my home network, is not supported. The main reason is that its API do not allow creating TXT or CNAME records, which are needed for dns-01 validation. I did contact the owner hoping that a non-documented API was found, but I got no answer back.

Gandi, on the other hand, is supported, and is my main DNS provider, so I started looking into that direction. Unlike my previous provider (OVH), Gandi does not appear to provide you any support for delegating to a dynamic host system. So instead I looked for options around it, and I found that Gandi provides some APIs (which, after all, is what lego uses itself.)

I ended up writing two DNS updating tools for that; if nothing else because they are very similar, one for Gandi and one for (the one for was what I started with — at the time I thought that they didn’t have an endpoint to update IPv6 hosts, since the default endpoint was v4 only.) I got clearance to publish it and is now on GitHub, it can work as a framework for any other dynamic host provider, if you feel like writing one, it provides some basic helper methods to figure out the current IPv4 or IPv6 assigned to an interface — while this makes no sense behind NAT, it makes sense with DS-Lite.

But once I got it all up and running I realized something that should have been obvious from the start: Gandi’s API is not great for this use case at all. In the case of and OVH’s protocol, there is a per-host token, usually randomly generated, you deploy that to the host you want to keep up to date, and that’s it, nothing else can be done with that token: it’s a one-way update of the host.

Gandi’s API is designed to be an all-around provisioning API, so it allows executing any operation whatsoever with your token. Including registering or dropping domains, or dropping the whole zone or reconfiguring it. It’s a super-user access token. And it sidesteps the 2-factors authentication that you can set up on the Gandi. If you lose track of this API key, it’s game over.

So at the end of the day, I decided not to use this at all. But since I already wrote the tools, I thought it would be a good idea to leave it to the world. It was also a bit of a nice way for me to start writing some public Go code,

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.