gdnsd on Ubuntu 24.04 on Azure User Guide
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
gdnsduser (gdnsd.service) -
A DNS endpoint on
0.0.0.0:53and[::]:53over 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
multifoplugin as the dynamic recordlb.example.cloudimg.invalid, which needs no external database -
The
geoipplugin compiled in and ready for geographic load balancing once you supply your own MaxMind database -
The whole configuration in readable text,
/etc/gdnsd/configplus zone files, that you version control and reload with a single command -
Local only administration over the
gdnsdctlcontrol 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
-
Open the cloudimg gdnsd on Ubuntu 24.04 LTS offer in the Azure Marketplace and select Get It Now, then Create.
-
Choose your subscription, resource group and region, and a VM size. A
Standard_B2sis a comfortable starting point for an authoritative name server. -
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.
-
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.

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.

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.

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.

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
gdnsdctlcontrol 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.