Moving from AWS Route53 to Gandi LiveDNS

Looking for ways to simplify my setup, I recently switched the DNS zones for my domains from AWS Route53 to Gandi LiveDNS. I already have my domains registered at Gandi and use a VPS of another provider, so I can reduce my dependence on Amazon and save a small amount of money.

I use two kinds of automation working on DNS records: my zones are defined and managed via OpenTofu, and my servers use Let’s Encrypt DNS validation for its wildcard certificates. I don’t use any advanced features of Route53: if not for the temporary records added by certbot, my zones would be completely static (with changes only when I update my email setup or add/remove subdomains for websites).

Both tools have extensions interacting with Gandi: there is a Gandi provider for OpenTofu and a certbot plugin. (I checked that, and the IPv6 support, before deciding to use Gandi’s DNS. Otherwise I’d look for other DNS services with certbot support.)

The migration process itself was different than I expected: I had to switch NS records for the domain while providing a zone file, instead of enabling LiveDNS and then building a new zone before switching the domain to it. (Gandi also allows starting with a default zone which is useful only when using their other services for Web hosting and email.) So I needed a zone file export via the cli53 tool (which I already knew and used a long time before to compare zones when dealing with automation). The zone file required at least removing Amazon NS records before being imported.

The OpenTofu migration was easy: I configured the provider using a personal access token for the Gandi API, copied my files defining the records for Route53, and ran some find and replace to rename resource types and their fields. There are OpenTofu records for domains and records, so this is mostly the same as before.

I imported the records from LiveDNS into OpenTofu via its import command. I had to look in the provider’s source code for the syntax of import IDs: these are fqdn/record/type, e.g. tofu import gandi_livedns_record.example_com_mta_sts_txt example.com/_mta-sts/TXT would make the example_com_mta_sts_txt record in its configuration handle the existing _mta-sts.example.com TXT record. (With my resources being organized around record types often with for_each accessing subdomain names for a host, I generated the import commands by running tofu plan and transforming the text informing about resources to be added.)

Gandi LiveDNS requires relative DNS names, with @ for the root domain, and has different quoting for TXT records, while Route53 uses fully-qualified domain names. So I adjusted all of these until tofu plan informed of no changes to perform.

I tested the migration via the usual tools, getting some records via host and querying at least one website checking email-related records (which were the one most likely to break, being long TXT records affected by the difference in quoting between Route53 and LiveDNS).

The certbot plugin was trickier. As Gandi recently replaced its API keys by personal access tokens, the plugin required an update which was not yet in Debian Stable. So I had to backport it.

I needed to regenerate the certificates to be sure it works, running sudo /usr/bin/certbot --verbose --authenticator dns-gandi --dns-gandi-credentials /etc/letsencrypt/gandi/gandi.ini renew --force-renewal.

I’m not fully satisfied with personal access tokens: they require manual rotation, so I get the pre-Let’s Encrypt issue of requiring at least a yearly manual action to keep TLS working. The token also gives all domain-related permissions. A computer running a Web server for one domain should not be able to e.g. change records of other domains. I could solve this by using the certbot-dns-standalone plugin, delegating only a zone specific to ACME verification for the given domain, but I can do that later.

Then I deleted the Route53 zones via OpenTofu. It took a long time.

Several days later, all my services work, at least as well as they need to for hobbyist purposes. Now I need to research object storage providers to replace the only service my AWS account still bills for.