Skip to main content
Version: 1.0.0

Bind DNS on Aruba Cloud

Deploy BIND9 — the most widely deployed DNS server software — on Aruba Cloud using Terraform and cloud-init. BIND9 is configured as a caching recursive resolver with configurable upstream forwarders and built-in access control.

Provider version: arubacloud/arubacloud ~> 1.0 | Terraform: ≥ 1.9


Introduction​

BIND9 (Berkeley Internet Name Domain) is the reference implementation of the DNS protocol and the most commonly deployed authoritative and recursive DNS server. This example provisions a caching resolver with:

  • BIND9 installed from Ubuntu 22.04 official packages
  • Configured as a caching forwarder — queries are resolved via configurable upstream servers and cached locally
  • Access control via both the security group (dns_cidr) and BIND9's allow-query / allow-recursion ACL — double protection against open-resolver abuse
  • Port 53 (UDP + TCP) for DNS queries
  • systemd-resolved stub listener disabled so BIND9 can own port 53

Choosing between DNS servers: Use BIND9 when you need authoritative DNS hosting, complex zone management, or DNSSEC signing. For a simpler caching resolver, consider CoreDNS, Pi-hole, or AdGuard Home.


Architecture Overview​


Infrastructure Created​

ResourceName patternDescription
arubacloud_projectbind-prodProject container
arubacloud_vpcbind-prod-vpcVirtual Private Cloud
arubacloud_subnetbind-prod-subnetBasic subnet
arubacloud_securitygroupbind-prod-vm-sgSecurity group
arubacloud_securityrulebind-prod-vm-sshSSH ingress
arubacloud_securityrulebind-prod-vm-dns-tcpDNS TCP 53 ingress
arubacloud_securityrulebind-prod-vm-dns-udpDNS UDP 53 ingress
arubacloud_elasticipbind-prod-vm-eipVM public IP
arubacloud_blockstoragebind-prod-boot20 GB boot disk (Performance)
arubacloud_keypairbind-prod-keypairSSH public key
arubacloud_cloudserverbind-prod-vmCloudServer VM

Estimated Monthly Cost​

ResourceSpecEst. cost/mo
CloudServer VMCSO1A2 — 1 vCPU / 2 GB~€9
Boot disk20 GB Performance~€3
Elastic IP—~€3
Total~€15/mo

Requirements​

  • Terraform ≥ 1.9
  • ArubaCloud Terraform Provider ~> 1.0
  • An ArubaCloud account with OAuth2 API credentials
  • An SSH key pair

Variables​

Required​

VariableDescription
arubacloud_client_idArubaCloud OAuth2 client ID
arubacloud_client_secretArubaCloud OAuth2 client secret
ssh_public_keySSH public key content

Optional​

VariableDefaultDescription
app_name"bind"Short name used in all resource names
environment"prod"Environment label
location"ITBG-Bergamo"ArubaCloud region
zone"ITBG-1"Availability zone
billing_period"Hour""Hour" or "Month"
vm_flavor"CSO1A2"CloudServer flavor
vm_image"LU22-001"Boot disk image (Ubuntu 22.04 LTS)
vm_disk_size_gb20Boot disk size in GB
ssh_cidr"0.0.0.0/0"CIDR for SSH
dns_cidr"0.0.0.0/0"CIDR for DNS port 53 — always restrict
upstream_dns_1"1.1.1.1"Primary upstream resolver
upstream_dns_2"1.0.0.1"Secondary upstream resolver

Outputs​

OutputDescription
dns_serverDNS server IP address
vm_public_ipPublic IP address of the VM
ssh_commandSSH command to connect to the VM

Deployment Instructions​

1. Clone and navigate​

git clone https://github.com/arubacloud/terraform-arubacloud-examples.git
cd terraform-arubacloud-examples/bind-dns

2. Configure variables​

cp terraform.tfvars.example terraform.tfvars

Always restrict dns_cidr to prevent your server from being used as an open resolver:

dns_cidr = "10.8.0.0/24" # WireGuard tunnel CIDR
ssh_cidr = "203.0.113.42/32"

3. Deploy​

terraform init
terraform plan
terraform apply

Bootstrap takes approximately 1–2 minutes.

4. Test the deployment​

Run the checks below against the IP shown in terraform output -raw dns_server.

Port reachability — confirm port 53 is open on both transport protocols:

DNS=$(terraform output -raw dns_server)
nc -zv "$DNS" 53 # TCP
nc -zvu "$DNS" 53 # UDP

Expected output:

Connection to <ip> 53 port [tcp/domain] succeeded!
Connection to <ip> 53 port [udp/domain] succeeded!

DNS resolution — send a real query and verify you get an answer:

dig @"$DNS" google.com

A healthy response looks like:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, ...
;; ANSWER SECTION:
google.com. ... IN A 142.251.x.x
...
;; Query time: <low ms>
;; SERVER: <ip>#53

Key things to check: status: NOERROR, at least one record in the ANSWER SECTION, and a low query time (< 200 ms on the first hit, < 20 ms on a cached repeat).

IPv6 resolution:

dig @"$DNS" google.com AAAA

Repeat query (cache hit):

dig @"$DNS" google.com && dig @"$DNS" google.com

The second query time should drop significantly, confirming the cache is working.

5. Point clients​

Set the output IP as the DNS server on your VPN clients or network devices.


Customisation​

The BIND9 configuration is at /etc/bind/named.conf.options. Reload after changes:

sudo named-checkconf && sudo systemctl reload bind9

Add an authoritative zone​

Create a zone file and add it to /etc/bind/named.conf.local:

zone "example.internal" {
type master;
file "/etc/bind/db.example.internal";
};

Then create /etc/bind/db.example.internal:

$TTL 300
@ IN SOA ns1.example.internal. admin.example.internal. (
2024010101 ; Serial
3600 ; Refresh
1800 ; Retry
604800 ; Expire
300 ) ; Minimum TTL

@ IN NS ns1.example.internal.
ns1 IN A <vm-ip>
host1 IN A 10.0.0.1

Enable DNSSEC validation​

DNSSEC validation is already enabled (dnssec-validation auto). To also sign your own zones, install dnssec-tools and follow the BIND9 DNSSEC guide.


Troubleshooting​

BIND9 not responding​

sudo systemctl status bind9
sudo named-checkconf
sudo journalctl -u named -n 30
sudo ss -ulnp | grep :53
sudo ss -tlnp | grep :53

Port 53 in use after install​

sudo ss -ulnp sport = :53
grep DNSStubListener /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved && sudo systemctl restart bind9

Test from client​

See the full test suite in Deployment Instructions → Test the deployment. Quick one-liners:

dig @<vm-ip> google.com # A record
dig @<vm-ip> google.com AAAA # IPv6
nslookup google.com <vm-ip> # alternative resolver
nc -zv <vm-ip> 53 # TCP port check
nc -zvu <vm-ip> 53 # UDP port check

References​