Unbound
Overview
This guide covers the deployment and configuration of Unbound on Ubuntu 24.04 on Azure, using SecureAnyCloud Azure Marketplace images. Unbound is a fast, lean, validating, recursive, caching DNS resolver developed by NLnet Labs. It performs full recursive resolution for the clients it serves, validates every answer cryptographically with DNSSEC, and caches aggressively for low latency. A single plain-text configuration file drives it, with no database and no web console.
The image installs the maintained Unbound package from the Ubuntu 24.04 LTS archive, which is security-patched by the Ubuntu security team and kept current on your running VM by unattended upgrades.
Security by design: not an open resolver. An open recursive resolver is one that will recursively resolve arbitrary names for anyone on the internet. It is a well-known DNS amplification and reflection DDoS vector. Unbound listens on all interfaces, so it is useful inside your VNet. Its access-control policy allows recursion only from the local host and RFC1918 private ranges and refuses every public source.
A recursive query from a public address is answered with REFUSED, so this server can never be abused as an amplifier. Widen the policy to your own trusted subnets only when you need to (see Step 9), and never to 0.0.0.0/0.
Security by design: DNSSEC validation on. Unbound validates the DNSSEC signature chain on every recursive answer against the root trust anchor (/var/lib/unbound/root.key, kept current automatically via RFC 5011). A correctly signed name is returned with the AD (Authenticated Data) flag; a name whose signatures fail to validate is rejected with SERVFAIL rather than handed to your clients.
Security by design: no baked control credential. A DNS resolver has no admin login. The only management surface is unbound-control, and this image exposes it over a root-only unix socket (/run/unbound.ctl) rather than a network TLS port, so there is no control key or certificate baked into the image and nothing to rotate. Manage the resolver locally with sudo unbound-control.
What you get:
- Unbound (from the Ubuntu 24.04 LTS archive), run under systemd as the unprivileged
unbounduser under its AppArmor profile (unbound.service) - DNSSEC validation on against the root trust anchor, with
harden-dnssec-strippedand aggressive NSEC caching - A responsible
access-controlpolicy that keeps the resolver from being an open one: recursion for127.0.0.0/8,::1and the RFC1918 private ranges only, with0.0.0.0/0and::0/0refused unbound-controlon a root-only unix socket (/run/unbound.ctl), so no control credential ships in the image- Privacy and performance defaults:
qname-minimisation, prefetching, cache prefetch, and per-IP and per-domain rate limiting to blunt reflection abuse - Identity hardening:
hide-identityandhide-version, so the resolver does not leak its software version - Unattended security upgrades left enabled, so the resolver keeps receiving patches
Prerequisites
- An active Azure subscription, an SSH public key, and a VNet with a subnet in the target region
- A subscription to the Unbound 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 resolver
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for a small resolver. Resolvers serving heavy query volumes should use Standard_D2s_v5 or larger.
Deploy from the Azure Portal
Search the Marketplace for Unbound, select the SecureAnyCloud 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, so open both.
Deploy from the Azure CLI
Alternatively, deploy with the Azure CLI. Adjust the resource group, location and VM name for your environment:
RG="dns-prod"; LOCATION="eastus"; VM_NAME="resolver1" IMAGE_URN="sac1647283583153:unbound-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION"
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:unbound-ubuntu-24-04:default:latest
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$IMAGE_URN" \
--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 (open both UDP and TCP 53):
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 1002First boot
On first boot the image resolves the VM public IP for its documentation, confirms DNSSEC validation and the access-control policy that keeps it from being an open resolver are in place. It then starts Unbound, proves the resolver is up and controllable over the unix socket, and writes /root/unbound-credentials.txt. This completes within a minute. SSH in as azureuser and read the details:
sudo cat /root/unbound-credentials.txtConfirm the resolver is running
unbound.service is active and unbound-control status reports the server running with the validator module loaded (DNSSEC), using the root-only unix socket control channel. Check both:
systemctl is-active unbound.service
sudo unbound-control statusResolve a name with DNSSEC validation
Query a DNSSEC-signed name against the loopback address. The AD flag in the header confirms that the answer was cryptographically validated against the root trust anchor. A second identical query is served from cache, which shows as a much lower query time.
dig @127.0.0.1 +dnssec cloudflare.com dig @127.0.0.1 cloudflare.comConfirm DNSSEC rejects bad data
A name whose DNSSEC signatures deliberately fail to validate must be rejected with SERVFAIL rather than returned to clients. dnssec-failed.org is a well-known test domain with intentionally broken signatures. Query it, then validate the whole configuration with unbound-checkconf. No error output means the configuration is valid.
dig @127.0.0.1 dnssec-failed.org
sudo unbound-checkconfVerify it is not an open resolver
This is the key security property. The access-control policy in /etc/unbound/unbound.conf.d/00-sac.conf refuses 0.0.0.0/0 and ::0/0, and allows recursion only from the local host and the RFC1918 private ranges. No public source can use this server to recursively resolve arbitrary names. Check the policy and the query counters:
grep -E 'access-control|control-interface|control-use-cert' /etc/unbound/unbound.conf.d/00-sac.conf
sudo unbound-control stats_noreset | grep -E 'total.num.queries|total.num.cachehits'Point your clients at the resolver
From a VM inside the same VNet (an allowed private range), set the resolver's private IP as the nameserver, or test directly against the resolver:
dig @<vm-ip> +dnssec example.comTo make a Linux client use the resolver permanently, set the resolver's private IP as the DNS server on the client's network interface, through netplan or systemd-resolved.
Widen access-control to your own networks (optional)
By default, recursion is offered to the local host and the RFC1918 private ranges. To serve additional trusted client networks, add an access-control allow line to /etc/unbound/unbound.conf.d/00-sac.conf inside the server: block:
access-control: 203.0.113.0/24 allowReplace 203.0.113.0/24 with your own trusted client ranges. Never use access-control: 0.0.0.0/0 allow, because that turns the server back into an open resolver. Apply the change with:
sudo unbound-checkconf
sudo unbound-control reloadManage Unbound with unbound-control
The control channel is a root-only unix socket, so unbound-control works locally with no credential to manage. Common operations:
sudo unbound-control status
sudo unbound-control stats
sudo unbound-control reloadTo inspect or flush the cache:
sudo unbound-control dump_cache | head
sudo unbound-control flush_zone example.comSecurity recommendations
Restrict the NSG. Allow UDP and TCP 53 only from the client networks that need to query the resolver, and TCP 22 for administration only.
Keep recursion scoped. Widen access-control only to networks you trust (Step 9), and never to 0.0.0.0/0. Even with the NSG open, the access-control policy is your second layer of defence against open resolver abuse.
Leave DNSSEC validation on. It protects your clients from spoofed or tampered answers. The root trust anchor updates itself via RFC 5011.
Consider forwarders if required. If your environment mandates resolving through an upstream (for example a corporate resolver), configure a forward-zone. Recursive resolution directly to the authoritative servers is the more private default.
Keep the OS and Unbound patched. Unattended security upgrades remain enabled on the running VM.
Monitor with the statistics. unbound-control stats exposes query counts, cache hit ratio and validation failures for your monitoring system.
Support and licensing
Unbound is developed by NLnet Labs and distributed under the BSD 3-Clause license. This SecureAnyCloud image bundles the unmodified Ubuntu Unbound package. SecureAnyCloud provides the packaging, the hardening that keeps it from being an open resolver, the DNSSEC validation defaults, the root-only unix socket control channel, and 24/7 support with a guaranteed 24-hour response SLA.
SecureAnyCloud is not affiliated with or endorsed by NLnet Labs. Unbound is a mark of its respective owner and is used here only to identify the software.
Deploy on Azure
Find Unbound on Ubuntu 24.04 LTS on the Azure Marketplace, published by SecureAnyCloud. Deploy from the Portal or the Azure CLI as shown above.
Need help?
Email sales@secureanycloud.com for deployment help, configuration questions, or licensing enquiries.
Deploy on Azure
Launch Unbound DNS Resolver on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
This guide covers the deployment and configuration of Unbound on AWS, using SecureAnyCloud AWS Marketplace images. Unbound is a fast, lean, validating, recursive, caching DNS resolver developed by NLnet Labs. It performs full recursive resolution for the clients it serves, validates every answer cryptographically with DNSSEC, and caches aggressively for low latency. A single plain-text configuration file drives it, with no database and no web console.
The image installs the maintained Unbound 1.19.2 package from the Ubuntu 24.04 LTS archive, which is security-patched by the Ubuntu security team and kept current on your running instance by unattended upgrades. Point your own workloads, containers and office networks at it instead of a third-party public resolver, to keep your DNS traffic private and under your control.
Security by design: not an open resolver. An open recursive resolver is one that will recursively resolve arbitrary names for anyone on the internet. It is a well-known DNS amplification and reflection DDoS vector. Unbound listens on all interfaces, so it is useful inside your VPC. Its access-control policy allows recursion only from the local host and the RFC1918 private ranges and refuses every public source.
A recursive query from a public address is answered with REFUSED, so this server can never be abused as an amplifier. Widen the policy to your own trusted subnets only when you need to (Step 8), and never to 0.0.0.0/0.
Security by design: DNSSEC validation on. Unbound validates the DNSSEC signature chain on every recursive answer against the root trust anchor (/var/lib/unbound/root.key, kept current automatically via RFC 5011). A correctly signed name is returned with the AD (Authenticated Data) flag; a name whose signatures fail to validate is rejected with SERVFAIL rather than handed to your clients.
Security by design: no baked control credential. A DNS resolver has no admin login. The only management surface is unbound-control, and this image exposes it over a root-only unix socket (/run/unbound.ctl) rather than a network TLS port, so there is no control key or certificate baked into the image and nothing to rotate. Manage the resolver locally with sudo unbound-control.
What you get:
- Unbound 1.19.2 (from the Ubuntu 24.04 LTS archive), run under systemd as the unprivileged
unbounduser under its AppArmor profile (unbound.service) - DNSSEC validation on against the root trust anchor, with
harden-dnssec-strippedand aggressive NSEC caching - A responsible
access-controlpolicy that keeps the resolver from being an open one: recursion for127.0.0.0/8,::1and the RFC1918 private ranges only, with0.0.0.0/0and::0/0refused unbound-controlon a root-only unix socket (/run/unbound.ctl), so no control credential ships in the image- Privacy and performance defaults:
qname-minimisation, prefetching, cache prefetch, and per-IP and per-domain rate limiting to blunt reflection abuse - Identity hardening:
hide-identityandhide-version, so the resolver does not leak its software version - The systemd-resolved stub listener disabled, so Unbound owns port 53 cleanly while the OS keeps resolving names through the VPC upstream resolver
- Unattended security upgrades left enabled, so the resolver keeps receiving patches
Connecting to your instance
Connect over SSH on port 22 as the default login user for the AMI variant you launched. There is no application password to retrieve. You manage Unbound locally with sudo unbound-control over a root-only unix socket.
For the Ubuntu 24.04 variant, the SSH login user is ubuntu. This variant runs Unbound 1.19.2 from the Ubuntu 24.04 LTS archive.
Prerequisites
- An AWS account and an EC2 key pair in the target region
- A subscription to the Unbound listing on AWS Marketplace
- A security group allowing TCP 22 (administration) and both UDP 53 and TCP 53 (DNS) from the client networks that will query the resolver. DNS uses UDP 53 for most queries and falls back to TCP 53 for large responses, so open both.
Recommended instance type: m5.large (2 vCPU, 8 GB RAM) for a general resolver. Resolvers serving heavy query volumes can move to a larger m5 or c5 size.
Deploy from the AWS Console
In the EC2 console, choose Launch instance and select the SecureAnyCloud Unbound AMI. Pick an instance type (m5.large recommended), your key pair and subnet.
Attach a security group that allows UDP 53 and TCP 53 from your client networks, plus TCP 22 for administration. Then launch the instance.
Deploy from the AWS CLI
Replace the values in angle brackets with your own AMI ID, key pair, subnet and security group, then launch:
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <your-key-pair> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=unbound-resolver}]'The security group <security-group-id> must allow inbound UDP 53 and TCP 53 from your client networks and TCP 22 from your administrator network.
First boot
On first boot the image resolves the instance public IP for its documentation, confirms DNSSEC validation and the access-control policy that keeps it from being an open resolver are in place. It then starts Unbound, proves the resolver is up and controllable over the unix socket, and writes /root/unbound-credentials.txt. This completes within a minute. SSH in as ubuntu and read the details:
sudo cat /root/unbound-credentials.txtConfirm the resolver is running
unbound.service is active and unbound-control status reports the server running with the validator module loaded (DNSSEC), using the root-only unix socket control channel. Unbound listens on port 53 over both UDP and TCP on all interfaces. Check both:
systemctl is-active unbound.service
sudo unbound-control statusResolve a name with DNSSEC validation
Query a DNSSEC-signed name against the loopback address. The AD flag in the header confirms that the answer was cryptographically validated against the root trust anchor. A second identical query is served from cache, which shows as a much lower query time.
dig @127.0.0.1 +dnssec cloudflare.com dig @127.0.0.1 cloudflare.comConfirm DNSSEC rejects bad data
A name whose DNSSEC signatures deliberately fail to validate must be rejected with SERVFAIL rather than returned to clients. dnssec-failed.org is a well-known test domain with intentionally broken signatures. Query it, then validate the whole configuration with unbound-checkconf. No error output means the configuration is valid.
dig @127.0.0.1 dnssec-failed.org
sudo unbound-checkconfVerify it is not an open resolver
This is the key security property. The access-control policy in /etc/unbound/unbound.conf.d/00-sac.conf refuses 0.0.0.0/0 and ::0/0, and allows recursion only from the local host and the RFC1918 private ranges. No public source can use this server to recursively resolve arbitrary names.
The control channel is the root-only /run/unbound.ctl unix socket with control-use-cert: no, so no control credential ships in the image. Check the policy and the query counters:
grep -E 'access-control|control-interface|control-use-cert' /etc/unbound/unbound.conf.d/00-sac.conf
sudo unbound-control stats_noreset | grep -E 'total.num.queries=|total.num.cachehits='Widen access-control to your own networks (optional)
By default, recursion is offered to the local host and the RFC1918 private ranges. To serve additional trusted client networks, add an access-control allow line to /etc/unbound/unbound.conf.d/00-sac.conf inside the server: block:
access-control: 203.0.113.0/24 allowReplace 203.0.113.0/24 with your own trusted client ranges. Never use access-control: 0.0.0.0/0 allow, because that turns the server back into an open resolver. Apply the change with:
sudo unbound-checkconf
sudo unbound-control reloadPoint your clients at the resolver
From a host inside the same VPC (an allowed private range), point it at the resolver's private IP, or test directly against the resolver:
dig @<private-ip> +dnssec example.comTo make a Linux client use the resolver permanently, set the resolver's private IP as the DNS server on the client's network interface, through netplan or systemd-resolved.
Manage Unbound with unbound-control
The control channel is a root-only unix socket, so unbound-control works locally with no credential to manage. Common operations:
sudo unbound-control status
sudo unbound-control stats
sudo unbound-control reload
sudo unbound-control dump_cache | head
sudo unbound-control flush_zone example.comSecurity recommendations
Restrict the security group. Allow UDP and TCP 53 only from the client networks that need to query the resolver, and TCP 22 for administration only.
Keep recursion scoped. Widen access-control only to networks you trust (Step 8), and never to 0.0.0.0/0. Even with the security group open, the access-control policy is your second layer of defence against open resolver abuse.
Leave DNSSEC validation on. It protects your clients from spoofed or tampered answers. The root trust anchor updates itself via RFC 5011.
Consider forwarders if required. If your environment mandates resolving through an upstream (for example a corporate resolver), configure a forward-zone. Recursive resolution directly to the authoritative servers is the more private default.
Keep the OS and Unbound patched. Unattended security upgrades remain enabled on the running instance.
Monitor with the statistics. unbound-control stats exposes query counts, cache hit ratio and validation failures for your monitoring system.
Support and licensing
Unbound is developed by NLnet Labs and distributed under the BSD 3-Clause license. This SecureAnyCloud image bundles the unmodified Ubuntu Unbound package. SecureAnyCloud provides the packaging, the hardening that keeps it from being an open resolver, the DNSSEC validation defaults, the root-only unix socket control channel, and 24/7 support with a one-hour average response time for critical issues.
SecureAnyCloud is not affiliated with or endorsed by NLnet Labs. Unbound is a mark of its respective owner and is used here only to identify the software.
Need help?
Email sales@secureanycloud.com for deployment help, configuration questions, or licensing enquiries.
Deploy on AWS
Launch Unbound with 24/7 support from SecureAnyCloud.
View on Marketplace
Need help?
Our support team is available 24/7.
sales@secureanycloud.com