BIND 9 (ISC BIND) on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of BIND 9 (ISC BIND) on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. BIND 9 is the internet's most widely deployed DNS software, maintained by Internet Systems Consortium (ISC). It is a full featured authoritative and (optionally) recursive DNS server with DNSSEC, zone management, and the rndc control channel.
The image installs the current stable ESV branch, BIND 9.20, from the official ISC packages (the ISC ppa:isc/bind repository), not the Ubuntu archive bind9 package. The Ubuntu 24.04 archive ships the 9.18 branch, which reached ISC upstream end of life in 2026; this image deliberately ships a supported, actively patched branch. Unattended security upgrades are configured to keep the 9.20 branch patched on your running VM.
Security by design — a non open resolver. An open recursive resolver (one that will recursively resolve arbitrary names for anyone on the internet) is a well known DNS amplification and reflection DDoS vector. This image ships as a pure authoritative server with recursion switched off, so no client, local or remote, can use it to recursively resolve external names: a recursive query for an external name such as google.com is answered with REFUSED. The configuration also sets version none (the BIND version is not leaked), disables zone transfers by default, and enables response rate limiting to blunt amplification abuse. You can enable recursion for your own trusted networks when you need it (see Step 9).
Security by design — a per instance control key. The rndc control key is the equivalent of a remote control password for the DNS server, so this image never ships a fixed control key. On the very first boot of every VM a fresh per instance rndc key is generated (hmac-sha256) and the control channel is bound to 127.0.0.1 port 953 only. The key details are written to /root/bind-credentials.txt (mode 0600, root only).
What is included:
-
BIND 9.20 (current stable ESV) from the official ISC packages, run under systemd as the unprivileged
binduser (named.service) -
Responsible non open resolver defaults:
recursion no,allow-recursion { none; },version none,allow-transfer { none; }, and response rate limiting -
One example authoritative zone (
example.internal) sodig @<server> www.example.internalresolves to10.0.0.20out of the box, plus a documented template for adding your own zones -
A per instance rndc control key generated on first boot, control channel bound to
127.0.0.1:953only, documented in/root/bind-credentials.txt(0600) -
Zone files, DNSSEC keys, and journals on a dedicated 20 GiB Azure data disk mounted at
/var/lib/bind, so authoritative data survives independently of the OS disk and the volume is independently resizable -
A tiny nginx on port
:80serving only an unauthenticated/healthzendpoint (HTTP 200) for Azure Load Balancer health probes — this is not a DNS management UI -
Ubuntu 24.04 LTS base with latest security patches applied at build time, and unattended security upgrades kept enabled (including the ISC repository)
-
Azure Linux Agent for seamless cloud integration and SSH key injection
-
24/7 cloudimg support with a guaranteed 24 hour response SLA
Prerequisites
-
Active Azure subscription, SSH public key, VNet + subnet in target region
-
Subscription to the BIND 9 listing on Azure Marketplace
-
Network Security Group rules allowing TCP 22 (admin) and both UDP and TCP 53 (DNS) from the clients that will query the server
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for a small authoritative server. Servers answering heavy query volumes should use Standard_D2s_v5 or larger.
Step 1: Deploy from the Azure Portal
Search BIND 9 in Marketplace, select the cloudimg publisher, and click Create. Configure the Network Security Group to allow UDP 53 and TCP 53 (DNS) from your client networks, and TCP 22 for administration. DNS uses UDP 53 for most queries and falls back to TCP 53 for large responses and zone transfers, so open both.
Step 2: Deploy from the Azure CLI
RG="dns-prod"; LOCATION="eastus"; VM_NAME="ns1"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/bind9-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$GALLERY_IMAGE_ID" \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values "$SSH_KEY" \
--public-ip-sku Standard
Open the DNS and admin ports on the VM's NSG:
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 53 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1002
Step 3: First boot
On first boot the image resolves the VM public IP, generates a fresh per instance rndc control key, verifies the responsible defaults, starts named, proves the example zone answers and that the server is not an open resolver, and writes /root/bind-credentials.txt. This completes within a minute. SSH in as azureuser and read the details:
sudo cat /root/bind-credentials.txt
Step 4: Confirm the services are running
named.service (the BIND daemon) and nginx.service (the health probe) are both active. rndc status reports the server up using the per instance control key, and ss confirms DNS is listening on :53 while the rndc control channel is bound to 127.0.0.1:953 only.
systemctl is-active named.service nginx.service
sudo rndc status

Step 5: Query the example authoritative zone
The image ships one example authoritative zone, example.internal, so a DNS round trip works immediately. Query it against the loopback address (or the VM public IP from a client). The aa flag in the header confirms an authoritative answer.
dig @127.0.0.1 www.example.internal
dig @127.0.0.1 example.internal SOA +short
dig @127.0.0.1 example.internal MX +short
dig @127.0.0.1 example.internal TXT +short

Step 6: Review the configuration and responsible defaults
The configuration lives in /etc/bind. named-checkconf validates the whole configuration (no output means valid). The options file locks the server down as a non open resolver.
named -v
sudo named-checkconf
grep -E 'recursion|allow-recursion|version|allow-transfer|responses-per-second' /etc/bind/named.conf.options

Step 7: Verify the server is not an open resolver
This is the key security property. A recursive query for an external name must be REFUSED. The per instance rndc key file is present with 0640 root:bind permissions, and the zone data lives on the dedicated data disk.
dig @127.0.0.1 google.com
sudo stat -c '%n %a %U:%G' /etc/bind/rndc.key
findmnt /var/lib/bind

Step 8: Add your own authoritative zone
Create a zone file on the data disk and register it in /etc/bind/named.conf.local. For example, to serve mycompany.example:
sudo tee /var/lib/bind/db.mycompany.example >/dev/null <<'ZONE'
$TTL 3600
@ IN SOA ns1.mycompany.example. admin.mycompany.example. (
2026071001 3600 900 604800 3600 )
@ IN NS ns1.mycompany.example.
ns1 IN A 203.0.113.10
www IN A 203.0.113.20
ZONE
sudo chown bind:bind /var/lib/bind/db.mycompany.example
Then add the zone to /etc/bind/named.conf.local (a commented template is already there), check, and reload:
sudo named-checkconf
sudo named-checkzone mycompany.example /var/lib/bind/db.mycompany.example
sudo rndc reload
Step 9: Enable recursion for your own networks (optional)
If you want this server to also act as a resolving (caching) DNS server for your own trusted clients, edit /etc/bind/named.conf.options and set:
recursion yes;
allow-recursion { localhost; localnets; 10.0.0.0/8; };
Replace 10.0.0.0/8 with your own trusted client ranges. Never use allow-recursion { any; }; — that turns the server back into an open resolver. Apply the change with sudo named-checkconf && sudo rndc reload.
Step 10: Manage named with rndc
The rndc control channel is keyed by the per instance key and bound to loopback. Common operations:
sudo rndc status
sudo rndc reload
sudo rndc reconfig
Step 11: Security recommendations
-
Restrict the NSG. Allow UDP and TCP 53 only from the client networks that need to query the server, and TCP 22 for administration only.
-
Keep recursion off unless you need it, and if you do enable it, scope
allow-recursionto your own networks (Step 9) — neverany. -
Add DNSSEC signing for production authoritative zones (
dnssec-policy) so resolvers can validate your answers. Keys are stored on the data disk under/var/lib/bind. -
Add secondary servers. For resilience, configure secondaries and scope
allow-transferto their addresses instead of{ none; }. -
Keep the OS and BIND patched. Unattended security upgrades remain enabled on the running VM, including the ISC repository for the 9.20 branch.
-
Back up
/var/lib/bind(the data disk) to preserve your zone files and DNSSEC keys.
Step 12: Support and Licensing
BIND 9 is developed by Internet Systems Consortium (ISC) and distributed under the Mozilla Public License 2.0 (MPL-2.0). This cloudimg image bundles the unmodified official ISC packages. cloudimg provides the packaging, the responsible non open resolver hardening, the per instance rndc key automation, the example zone, and 24/7 support with a guaranteed 24 hour response SLA.
cloudimg is not affiliated with or endorsed by Internet Systems Consortium (ISC). BIND is a mark of its respective owner and is used here only to identify the software.
Deploy on Azure
Find BIND 9 on Ubuntu 24.04 LTS on the Azure Marketplace, published by cloudimg. Deploy from the Portal or the Azure CLI as shown above.
Need Help?
Email support@cloudimg.co.uk for deployment help, configuration questions, or licensing enquiries.