Victor Kropp

Take DNS under control with dnscontrol

I own a number of domains for my personal website, hobby projects, and, of course, those awesome side project ideas, which were never implemented. These domains are registered by two different registrars, hosted on multiple providers, and provide different services (e.g., mail, VPN, etc.) Managing and updating them manually every time is tedious and error-prone.

So I finally decided to automate it. I considered several options, including terraform, but ended up with a much simpler dedicated solution: dnscontrol. It features a simple DSL for DNS zones descriptions and provides integrations with many popular DNS registrars and hosting providers.

Getting started

DNSControl is also very user-friendly and extremely easy to start with. All you need is to set up credentials (API tokens) for all third-parties and invoke

dnscontrol get-zones --format=js --out=draft.js your-provider

dnscontrol infers your current setup by accessing provider’s API. Here’s a sample of draft configuration for this domain (some entries omitted for brevity):

D("kropp.name", REG_CHANGEME,
        DnsProvider(DSP_DO),
        DefaultTTL(3600),
        //NAMESERVER("ns1.digitalocean.com."),
        //NAMESERVER("ns2.digitalocean.com."),
        //NAMESERVER("ns3.digitalocean.com."),
        A("@", "165.227.134.122", TTL(1800)),
        MX("@", 10, "aspmx1.migadu.com."),
        MX("@", 20, "aspmx2.migadu.com."),
        CNAME("victor", "kropp.name.", TTL(1800)),
        CAA("@", "issue", "letsencrypt.org", CAA_CRITICAL),
        AAAA("@", "2a03:b0c0:3:d0::cd:1"),
END);

This is an (almost) usable configuration, I only needed to provide a registrar in the first line. And after that refactor the configuration to extract common parts, which are shared between domains.

Reusing configuration

For example, I use Migadu for all my mail. Email setup requires setting around 10 DNS entries nowadays, and it appeared that none of my domains had all of them. Now, I’m using a common function, which configures e-mail for the domain with all best practices applied:

var MAIL_TTL = TTL(14400);
var VERIFICATION_TTL = TTL(43200);

var MIGADU_MAIL = function(domain) {
  return [
    MX("@", 10, "aspmx1.migadu.com.", MAIL_TTL),
    MX("@", 20, "aspmx2.migadu.com.", MAIL_TTL),
    CNAME("key1._domainkey", "key1." + domain + "._domainkey.migadu.com.", VERIFICATION_TTL),
    CNAME("key2._domainkey", "key2." + domain + "._domainkey.migadu.com.", VERIFICATION_TTL),
    CNAME("key3._domainkey", "key3." + domain + "._domainkey.migadu.com.", VERIFICATION_TTL),
    TXT("@", "v=spf1 include:spf.migadu.com -all"),
    TXT("_dmarc", "v=DMARC1; p=quarantine;"),
    CNAME("autoconfig", "autoconfig.migadu.com."),
    SRV("_autodiscover._tcp", 0, 1, 443, "autodiscover.migadu.com."),
    SRV("_submissions._tcp", 0, 1, 465, "smtp.migadu.com."),
    SRV("_imaps._tcp", 0, 1, 993, "imap.migadu.com."),
    SRV("_pop3s._tcp", 0, 1, 995, "pop.migadu.com."),
  ]
}

And now setting up a new domain is a breeze!

Preview and apply changes

After you’ve finished, move draft.js to dnscontrol.js and run

dnscontrol preview

This command verifies the configuration and lists all potential changes. After you verify they are intended, run

dnscontrol push

to apply them.

That’s it.

Note on credentials

DNSControl uses creds.json file with the following content to access providers on your behalf.

{
  "digitalocean": {
    "TYPE": "DIGITALOCEAN",
    "token": "$DO_TOKEN"
  }
}

Although you can put all tokens right there, you cannot place the file under version control then. Instead, I use environment variables for sensitive tokens. This allows me to track this file. This is important because provider ids are used in dnsconfig.js, and it also provides changes history.

Now all my domains are under dnscontrol and their configuration is tracked with git. If the need arises to move them to another DNS provider, it would be a piece of cake.



This is post 11 of #100DaysToOffload

dns100DaysToOffload

Subscribe to all blog posts via RSS