Gd
Networking Azure

gdnsd on Ubuntu 24.04 on Azure User Guide

| Product: gdnsd 3.8.3 on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of gdnsd on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. gdnsd is a fast, lightweight authoritative only DNS server, a single compiled daemon that publishes the DNS records for the domains you own and answers queries for those zones directly from memory. It is well known for weighted, health checked and geographic load balancing answers. It is not a recursive resolver: it never resolves names on behalf of clients.

The image builds gdnsd 3.8.3 from the official upstream source release (checksum verified) and runs it under systemd as an unprivileged gdnsd user with just the CAP_NET_BIND_SERVICE capability, so it can bind the standard privileged DNS port without running as root. gdnsd answers DNS on port 53 over both UDP and TCP across all interfaces. There is no web interface and no database: the configuration file (/etc/gdnsd/config) plus plain text zone files in /etc/gdnsd/zones are the whole configuration. Administration is performed locally with the gdnsdctl tool over a private unix control socket that is not reachable over the network.

Secure by default — authoritative only. A naively deployed public resolver can be abused for DNS amplification attacks. gdnsd avoids this entirely because it is authoritative only: it answers only for the zones you configure and it never recurses, so any query for a name outside your zones is answered REFUSED. gdnsd also does not serve zone transfers, so an AXFR request from an unauthorised client cannot dump your zone. On the first boot of every VM the instance IP is baked into a demonstration zone so DNS answers immediately. gdnsd has no login, so no shared or default credential of any kind ships in the image.

What is included:

  • gdnsd 3.8.3 built from the official upstream source release, run under systemd as the unprivileged gdnsd user (gdnsd.service)

  • A DNS endpoint on 0.0.0.0:53 and [::]:53 over both UDP and TCP

  • An authoritative demonstration zone example.cloudimg.invalid, served with the authoritative answer (AA) flag, whose records point at this instance's IP (baked in on first boot)

  • A working weighted and multi address failover resource served through gdnsd's multifo plugin as the dynamic record lb.example.cloudimg.invalid, which needs no external database

  • The geoip plugin compiled in and ready for geographic load balancing once you supply your own MaxMind database

  • The whole configuration in readable text, /etc/gdnsd/config plus zone files, that you version control and reload with a single command

  • Local only administration over the gdnsdctl control socket, with the systemd-resolved stub listener disabled so gdnsd owns port 53 cleanly while the OS keeps resolving names through the upstream resolver list

Prerequisites

  • An Azure subscription with permission to deploy virtual machines

  • A resource group and virtual network, or let the portal create them during deployment

  • A network security group that allows inbound UDP and TCP port 53 from the clients that will query your name server, and TCP port 22 from your management address for SSH

  • To serve a real domain, the ability to set the domain's NS delegation at your registrar to point at this instance

Step 1: Deploy from the Azure Portal

  1. Open the cloudimg gdnsd on Ubuntu 24.04 LTS offer in the Azure Marketplace and select Get It Now, then Create.

  2. Choose your subscription, resource group and region, and a VM size. A Standard_B2s is a comfortable starting point for an authoritative name server.

  3. Under Networking, attach or create a network security group that allows inbound UDP 53 and TCP 53 from your clients and TCP 22 from your management address.

  4. Review and create. When the deployment finishes, note the VM's public IP address.

Step 2: Deploy from the Azure CLI

az group create --name gdnsd-rg --location eastus

az vm create \
  --resource-group gdnsd-rg \
  --name gdnsd-vm \
  --image <cloudimg-gdnsd-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

az vm open-port --resource-group gdnsd-rg --name gdnsd-vm --port 53 --priority 1001

Replace <cloudimg-gdnsd-image-urn> with the image reference from your Marketplace subscription. The az vm open-port command opens port 53 in the VM's network security group. Open it for both UDP and TCP to the client ranges that will query your server.

Step 3: First boot

On the first boot of each VM a one shot service, gdnsd-firstboot.service, resolves the instance's IP address, renders the demonstration zone example.cloudimg.invalid with that IP, writes an informational note to /root/gdnsd-info.txt, and then systemd starts gdnsd. gdnsd has no login, so this note holds no secret. First boot completes within a few seconds of the VM becoming reachable.

Step 4: Confirm the service is running

SSH to the VM and confirm gdnsd is active and owns port 53 over both UDP and TCP:

systemctl is-active gdnsd.service
gdnsd --version
ss -tuln | grep ':53 '

You should see the service reported as active, gdnsd reporting version 3.8.3, and listeners bound on port 53 for both UDP and TCP on IPv4 and IPv6.

The gdnsd service reports active, gdnsd reports version 3.8.3, and ss shows the server listening on port 53 for DNS over both UDP and TCP on all interfaces for IPv4 and IPv6

Step 5: Query the authoritative demo zone

Query the demonstration zone on the loopback interface. gdnsd answers authoritatively, so the response header carries the aa (authoritative answer) flag:

dig @127.0.0.1 example.cloudimg.invalid SOA +short
dig @127.0.0.1 example.cloudimg.invalid NS +short
dig @127.0.0.1 demo.example.cloudimg.invalid A

The SOA and NS queries return the zone's start of authority and name server records, and the demo record returns an A record pointing at this instance's IP. Note flags: ... aa in the header of the demo answer, which confirms the answer is authoritative.

dig returns the SOA and NS for the authoritative demo zone example.cloudimg.invalid, and a query for demo.example.cloudimg.invalid returns an A record with the header flags including aa, the authoritative answer flag, resolving to the instance IP address

Step 6: Weighted failover and runtime statistics

The image ships a working weighted, all active failover resource served through gdnsd's multifo plugin as the dynamic record lb.example.cloudimg.invalid. It returns a mapped set of addresses and needs no external database. Runtime statistics are read locally with gdnsdctl over the control socket:

dig @127.0.0.1 lb.example.cloudimg.invalid A +short
sudo gdnsdctl stats

The lb query returns the mapped address set from the multifo resource, and gdnsdctl stats prints JSON runtime statistics gathered over the private control socket. The control socket is a local unix socket at /run/gdnsd/control.sock; it is not reachable over the network.

dig for lb.example.cloudimg.invalid returns the mapped multi address set from the multifo weighted failover resource, and gdnsdctl stats prints JSON runtime statistics read over the local control socket

Step 7: Confirm the server is authoritative only

gdnsd never recurses. Confirm that a query for a name outside your zones is answered REFUSED, and that a zone transfer request from an unauthorised client is refused, by querying the instance on its routable address:

IP=$(hostname -I | awk '{print $1}')
dig @"$IP" www.example.com A | grep -E 'status:'
dig @"$IP" example.cloudimg.invalid AXFR | tail -3

The out of zone query returns status: REFUSED, proving the server is not an open resolver and cannot be used as a DNS amplification vector, and the AXFR request reports Transfer failed, proving zone transfers are not served to unauthorised clients.

A query for the out of zone name www.example.com returns a header with status REFUSED, and an AXFR zone transfer request reports Transfer failed, proving gdnsd is authoritative only, is not an open resolver, and does not serve zone transfers to unauthorised clients

Step 8: Serve your own authoritative zone

gdnsd derives each zone's name from its file name in /etc/gdnsd/zones, so serving a new zone is a matter of dropping in a zone file named after the zone. Create a zone file for your domain and reload:

sudo tee /etc/gdnsd/zones/<your-domain> >/dev/null <<'ZONE'
$TTL 3600
@   SOA ns1 hostmaster (
    1       ; serial
    7200        ; refresh
    3600        ; retry
    1209600     ; expire
    3600        ; ncache
)
@   NS  ns1
ns1 A   203.0.113.10
@   A   203.0.113.10
www A   203.0.113.10
ZONE
sudo gdnsdctl reload-zones

Replace <your-domain> with your domain name (for example example.com) and the addresses with your own. gdnsdctl reload-zones reloads the zones with no downtime. Then delegate the domain at your registrar by setting its NS records to point at this instance.

Step 9: Weighted and geographic load balancing

gdnsd is well known for returning different answers based on weight, health and client geography. The shipped multifo resource in /etc/gdnsd/config gives you all active failover out of the box:

sudo cat /etc/gdnsd/config

To weight backends unevenly, use the weighted plugin; to fail over based on health checks, attach a service_types monitor to the resource; and for geographic answers, enable the compiled in geoip plugin. Because MaxMind licenses its GeoIP databases directly to each end user, this image does not ship a MaxMind database. Download your own MaxMind database, accept MaxMind's terms with MaxMind, place the .mmdb file on the VM, and reference it from a geoip resource in the configuration. cloudimg support can help you design weighted, health checked and geographic resources for your traffic.

Step 10: Review the configuration and info note

sudo cat /etc/gdnsd/config
sudo cat /root/gdnsd-info.txt
ls -l /etc/gdnsd/zones

The configuration file is the single source of truth for options and plugin resources, the zones directory holds one file per zone, and the info note summarises this instance. The note holds no secret because gdnsd has no login.

Step 11: Security recommendations

  • Open port 53 only to the clients that need it. Authoritative servers for a public domain must accept queries from the internet, but you can still restrict management access. Keep TCP 22 limited to your management address.

  • Keep it authoritative only. This image never recurses, which is what makes it safe to expose publicly. Do not add forwarding or recursion; if you need a resolver for your own clients, run a separate recursive resolver.

  • Administer locally. The gdnsdctl control socket is a local unix socket and is not exposed on the network. Manage the server over SSH.

  • Run more than one name server. For production, delegate your domain to at least two authoritative servers in different locations, each running this image, so your DNS survives the loss of any single instance.

  • Keep the OS patched. The image ships fully patched with unattended security updates enabled so it keeps receiving fixes.

Step 12: Support and Licensing

gdnsd is free software published under the GNU General Public License version 3 (GPL-3.0). This image builds gdnsd from the official upstream source release. gdnsd is a trademark of its respective owner, and MaxMind, GeoIP and GeoLite are trademarks of MaxMind, Inc. cloudimg is not affiliated with, endorsed by, or sponsored by the gdnsd project or MaxMind, Inc.; all product names are used for identification only.

cloudimg provides 24/7 technical support for this product by email (support@cloudimg.co.uk) and live chat, covering deployment and first boot configuration, zone design, weighted and multi address failover, geographic load balancing with your own MaxMind database, high availability name server design, registrar delegation, version upgrades, performance tuning and troubleshooting. Critical issues receive a one hour average response time.