CoreDNS on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of CoreDNS on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. CoreDNS is a fast, flexible, plugin based DNS server and a CNCF graduated project, best known as the default DNS server for Kubernetes. It is a single self contained Go binary whose entire behaviour is defined by a plain text Corefile, so you compose exactly the DNS pipeline you need from a chain of plugins rather than wiring together several daemons.
The image installs CoreDNS 1.14.6 from the official prebuilt release tarball, run under systemd as an unprivileged coredns user with just the CAP_NET_BIND_SERVICE capability so it can bind the standard privileged DNS port. CoreDNS answers DNS on port 53 over both UDP and TCP, publishes Prometheus metrics on port 9153, and exposes a loopback health endpoint on port 8080. There is no web interface and no database: the Corefile (/etc/coredns/Corefile) plus a zone file are the whole configuration.
Secure by default — not an open resolver. A naively deployed public resolver can be abused for DNS amplification attacks. This image avoids that: the shipped Corefile has two server blocks. An authoritative block serves the demonstration zone cloudimg.internal with the authoritative answer flag on all interfaces, and a recursive cache and forward block whose acl plugin allows recursion only from the local host and answers every other source with REFUSED. On the first boot of every VM the instance IP is baked into the demo zone so DNS answers immediately. CoreDNS has no login, so no shared or default credential of any kind ships in the image.
What is included:
-
CoreDNS 1.14.6 from the official prebuilt release binary, run under systemd as the unprivileged
corednsuser (coredns.service) -
A DNS endpoint on
0.0.0.0:53(UDP and TCP), a Prometheus metrics endpoint on:9153, and a health endpoint on:8080 -
An authoritative demonstration zone
cloudimg.internal, served with the AA flag on all interfaces, whose records point at this instance's IP (baked in on first boot) -
A recursive cache and forward resolver restricted by the
aclplugin to loopback only, so the image is not an open resolver until you deliberately open it to your trusted subnets -
The whole configuration in one readable file,
/etc/coredns/Corefile, that you version control and reload with a single command -
The systemd-resolved stub listener disabled so CoreDNS owns port 53 cleanly, while the OS keeps resolving names through the upstream resolver list
Prerequisites
-
Active Azure subscription, SSH public key, VNet + subnet in target region
-
Subscription to the CoreDNS listing on Azure Marketplace
-
Network Security Group rules allowing TCP 22 (admin), UDP 53 and TCP 53 (DNS) from the clients that will query the server, and optionally TCP 9153 from your monitoring network for metrics
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is ample for a small authoritative server or a departmental resolver. CoreDNS is extremely light; larger sizes are only needed for very high query volumes.
Step 1: Deploy from the Azure Portal
Search CoreDNS in Marketplace, select the cloudimg publisher, and click Create. Configure the Network Security Group to allow UDP 53 and TCP 53 from the clients that will query the server, and TCP 22 for administration. If you host public authoritative zones, 53 must be reachable from the internet; if you run a recursive resolver for your own networks, keep 53 restricted to your internal subnets.
Step 2: Deploy from the Azure CLI
RG="dns-prod"; LOCATION="eastus"; VM_NAME="coredns1"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/coredns-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
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 this VM's IP, renders the demonstration zone /etc/coredns/zones/db.cloudimg.internal from the shipped template (baking the IP into the demo, www and ns1 records and setting a fresh SOA serial), writes the informational note /root/coredns-info.txt, and starts coredns. This completes within seconds. SSH in as azureuser and read the note:
sudo cat /root/coredns-info.txt
The note records the demo zone name, the demo record, this VM's IP, the metrics URL, and the paths to the Corefile and zone file. CoreDNS has no password, so the note holds no secret.
Step 4: Confirm the service is running
coredns.service is active, coredns -version reports 1.14.6, and ss confirms it is listening on :53 for DNS (UDP and TCP), :9153 for metrics and :8080 for health.
systemctl is-active coredns.service
/opt/coredns/coredns -version
sudo ss -tulnp | grep -E ':53 |:9153 |:8080 '

Step 5: Query the authoritative demo zone
The demonstration zone cloudimg.internal is served authoritatively. Query its SOA and the demo A record on the loopback address. The answer carries the aa (authoritative answer) flag, and demo.cloudimg.internal resolves to this VM's IP. DNS over TCP works too, which is what zone transfers and large responses use.
dig +noall +answer @127.0.0.1 SOA cloudimg.internal
dig @127.0.0.1 A demo.cloudimg.internal
dig +tcp +short @127.0.0.1 A www.cloudimg.internal
In the second command, look for flags: qr aa rd in the header — the aa flag confirms CoreDNS is answering authoritatively for this zone rather than recursing.

Step 6: Prometheus metrics and health
CoreDNS exposes a Prometheus metrics endpoint on port 9153 (every server, plugin and response code is a labelled series) and a plain health endpoint on port 8080 that returns OK while the server is up. Point your Prometheus scraper at :9153 and your load balancer or uptime monitor at :8080/health.
curl -s http://127.0.0.1:9153/metrics | grep '^coredns_' | head
curl -s http://127.0.0.1:8080/health; echo

Step 7: Confirm the image is not an open resolver
This is the security posture that matters for a public DNS server. The default .:53 block forwards and caches recursive queries, but its acl plugin allows recursion only from loopback and answers every other source with REFUSED. Read the acl block, then send a recursive query from this VM's own non loopback address and confirm it is refused.
sudo grep -A3 'acl {' /etc/coredns/Corefile
IP=$(hostname -I | awk '{print $1}')
dig @"$IP" A probe.invalid | grep -E 'status:'
The recursive query from the non loopback source returns status: REFUSED, proving the image cannot be abused for DNS amplification out of the box. Authoritative answers for cloudimg.internal are still served to everyone (Step 5) — only recursion is restricted.

Step 8: Serve your own authoritative zone
You add authoritative zones by dropping a zone file into /etc/coredns/zones and adding a matching server block to the Corefile. The example below uses <your-domain> as a placeholder for a domain you own. Create the zone file, add the block, and reload.
# 1) create a zone file for <your-domain> in /etc/coredns/zones/db.<your-domain>
# (use the shipped db.cloudimg.internal.template as a starting point)
# 2) add a server block to /etc/coredns/Corefile:
# <your-domain>:53 {
# file /etc/coredns/zones/db.<your-domain>
# log
# errors
# }
# 3) apply the change:
sudo systemctl reload coredns
CoreDNS validates the Corefile on reload; if there is a syntax error it keeps serving the previous configuration. To publish the zone on the internet, point your registrar's NS records at this instance's public IP.
Step 9: Open recursion to your trusted networks
To let your own clients use the VM as a recursive resolver, add their subnets to the acl allow net line in the default .:53 block, then restart. Keep the list to networks you control — never open recursion to the whole internet.
# edit /etc/coredns/Corefile and extend the acl allow line in the .:53 block, e.g.
# allow net 127.0.0.0/8 ::1/128 10.0.0.0/8 192.168.0.0/16
sudo systemctl restart coredns
The upstreams used for forwarding are Quad9 (9.9.9.9) and its secondary (149.112.112.112); change the forward line in the Corefile if you prefer different resolvers or want DNS over TLS upstreams.
Step 10: Review the configuration and info note
Everything CoreDNS does is in the Corefile, and the per instance details are in the info note. Both are readable with sudo.
sudo cat /etc/coredns/Corefile
sudo cat /root/coredns-info.txt
The info note is 0600 root:root and holds no secret — CoreDNS has no login. It simply records the demo zone, this VM's IP and the metrics URL for convenience.
Step 11: Security recommendations
-
Restrict the NSG to your use case. For an internal recursive resolver, allow UDP 53 and TCP 53 only from your client subnets. For public authoritative zones, 53 must be internet reachable, but keep recursion loopback only (or scoped by the acl) so the server is never an open resolver.
-
Keep the acl tight. Only add subnets you control to the
allow netline. An overly broad allow list turns the server back into an open resolver. -
Restrict the metrics port. Port 9153 exposes query statistics. Open TCP 9153 only to your monitoring network, not the public internet.
-
Enable DNSSEC or DNS over TLS as needed. CoreDNS ships the
dnssec,tlsand forwardtls://plugins; enable them in the Corefile for signed zones and encrypted upstreams. -
Keep the OS patched. Unattended security upgrades remain enabled on the running VM.
Step 12: Support and Licensing
CoreDNS is an open source project distributed under the Apache License 2.0. This cloudimg image bundles the unmodified official CoreDNS release binary. cloudimg provides the packaging, the systemd hardening, the secure by default Corefile and acl posture, the per instance demo zone automation, the paired deploy guide, and 24/7 support with a guaranteed 24 hour response SLA.
cloudimg is not affiliated with or endorsed by the CoreDNS project or the CNCF. CoreDNS is a mark of its respective owner and is used here only to identify the software.
Deploy on Azure
Find CoreDNS 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.