Roll out your own DNS server on Hashicorp Nomad with Bind9

3 min to read.

Welcome to my latest blog post, where I give you a deep dive into the world of DNS servers and show you how to set up your own DNS server on an Ubuntu system using Nomad and Bind9. This guide will allow you to host a customised domain and take control of your network communications.

Why have your own DNS server?

The Domain Name System (DNS) is an essential part of any network, as it allows domain names to be assigned to IP addresses. Setting up your own DNS server not only offers more control, but also enables customisation according to individual requirements.

Create Nomad job and task

To get started, we create a Nomad job with a group and a task. You can customise the names to suit your needs. Here is the basic code you can use as a starting point:

ini
# Benutzerdefinierte Parameter
variable "domain_name" {
  description = "Deine eigene Domain, die gehostet werden soll"
}

variable "network_ip_range" {
  description = "IP-Bereich deines Heimnetzwerks"
}

variable "dns_ip" {
  description = "IP-Adresse des DNS-Servers"
}

variable "email_address" {
  description = "Deine Kontakt-E-Mail-Adresse ohne @-Zeichen, stattdessen ein '.'"
}

job "dns" {
  group "dns-server" {

    network {
      port "dns" {
        static = 53
        to     = 53
      }
    }

    service {
      name = "bind9"
    }

    task "bind9" {
      driver = "docker"

      config {
        image = "ubuntu/bind9"

        ports = ["dns"]

        mounts {
          type   = "bind"
          target = "/etc/bind"
          source = "etc/bind"

          readonly = false
          bind_options {
            propagation = "rshared"
          }
        }
      }

      env {
        TZ         = "UTC"
        BIND9_USER = "root"
      }

      template {
        data          = <<EFF
acl internal {
    ${var.network_ip_range}/24;
    127.0.0.1;
    localhost;
};

options {
  forwarders {
    8.8.8.8;
    1.1.1.1;
  };
  allow-query { internal; };
  recursion yes;
  
  dnssec-validation auto;
};

include "/etc/bind/${var.domain_name}.conf";
        EFF
        destination   = "/etc/bind/named.conf"
        change_mode   = "signal"
        change_signal = "SIGINT"
      }

      template {
        data          = <<EFF
zone "${var.domain_name}" IN {
  type master;
  file "/etc/bind/${var.domain_name}.zone";
};
              EFF
        destination   = "/etc/bind/${var.domain_name}.conf"
        change_mode   = "signal"
        change_signal = "SIGINT"
      }

      template {
        data        = <<EFF
$TTL 2d

$ORIGIN ${var.domain_name}.

@               IN      SOA     ns.${var.domain_name}.   ${var.email_address}. (
                                1691399727
                                12h
                                15m
                                3w
                                2h
                                )

                IN      NS      ns.${var.domain_name}.

ns              IN      A       ${var.dns_ip}
              EFF
        destination = "/etc/bind/${var.domain_name}.zone"
        change_mode = "script"
        change_script {
          command = "service"
          args = [
            "named",
            "reload",
            "${var.domain_name}"
          ]
          timeout       = "5s"
          fail_on_error = false
        }
      }
    }
  }
}

Save this file as your-dns-job.nomad.
You can now customise the parameters such as domain_name, network_ip_range, dns_ip and email_address for email_address it is important that the @ is replaced by a dot in order to successfully host your own domain. Simply follow the comments and adjust the values according to your configuration.

Description of the script:

This script uses Nomad and Bind9 to automate the setup of a DNS server on an Ubuntu system. Here are the steps that the script performs:

  1. network configuration:
  • Sets a static port (53) for DNS communication.
  • You can customise the network mode as needed (e.g., "bridge").
  1. bind9 docker container:
  • Uses the official ubuntu/bind9 Docker container.
  • Binds required ports and mounts the bind directory for configurations.
  1. environment variables:
  • Sets various environment variables, such as the time zone (TZ) and the user (BIND9_USER).

4 Bind9 configuration:

  • Creates the main configuration file (named.conf) considering your individual domain.
  1. zone configuration:
  • Defines the zone of your domain and refers to the associated zone file.
  1. zone file:
  • Creates a zone file with basic DNS records, including the name server (ns) and the IP address of your DNS server.
  1. service reload:
  • Refreshes the DNS server service to apply the new configurations.

Create the parameter file and roll out to Nomad

Next, create a parameter file (e.g. dns_params.hcl) in which you define the specific values for your configuration. Here is an example:

ini
domain_name      = "deine-domain.de"
network_ip_range = "192.168.1.0"
dns_ip           = "192.168.1.2"
email_address    = "admin@deine-domain.de"

Execute the Nomad job with the parameter file:

bash
nomad job run -var-file=dns_params.hcl dein-dns-job.nomad

Allow incoming DNS traffic on port 53:

bash
sudo ufw allow 53

Edit the file /etc/resolv.conf and add the IP address of your DNS server:

ini
nameserver 192.168.1.2

Check the DNS configuration by performing a test:

bash
nslookup deine-domain.de 192.168.1.2

You should receive a successful DNS resolution.

With these steps, your DNS server on Ubuntu should be correctly configured and ready to use. Note that you will need to adjust the IP addresses and domain names mentioned according to your actual configuration. Good luck hosting your own domain!