Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Ubuntu DNS Configuration Guide

By Kokil Thapa | Last reviewed: September 2026

Broken DNS on an Ubuntu server wastes hours before you even touch application code. This Ubuntu DNS Configuration Guide walks through how name resolution actually works on Ubuntu 22.04 and 24.04, from Linux system administration basics to production fixes. You will configure client DNS with Netplan, tune systemd-resolved, and set up local caching when outbound lookups slow down deploys. The steps below match what I use on real VPS and EC2 hosts running Laravel, Nginx, and MySQL.

How does DNS resolution work on Ubuntu Server?

When an app calls gethostbyname(), the request passes through the glibc resolver. That resolver reads /etc/resolv.conf and forwards queries to upstream nameservers. On Ubuntu Desktop and Server since 18.04, systemd-resolved usually owns that file as a symlink.

Netplan writes network YAML into backend configs. NetworkManager or systemd-networkd applies them. DNS servers you define in Netplan end up inside resolved's runtime state. A common mistake is editing /etc/resolv.conf by hand while resolved is active. Your change disappears on reboot or the next network event.

Before changing anything, capture the current state. Run these commands and save the output:

ls -l /etc/resolv.conf
resolvectl status
cat /etc/netplan/*.yaml
systemctl is-active systemd-resolved

On a typical Ubuntu server setup, you will see /etc/resolv.conf pointing at 127.0.0.53. That stub listener is resolved acting as a local forwarding proxy. Upstream servers live in resolved's configuration, not always in the stub file itself.

Ubuntu DNS Resolution FlowApplicationcurl, PHP, MySQLglibc/etc/resolv.confsystemd-resolved127.0.0.53 stubUpstream1.1.1.1, 8.8.8.8Configuration SourcesNetplan YAML/etc/netplan/*.yamlresolved.confGlobal DNS overrideDHCP leaseCloud provider DNSsystemd-resolved merges and serves 127.0.0.53
Ubuntu DNS configuration flow: apps read resolv.conf, systemd-resolved forwards to upstream servers defined in Netplan or resolved.conf

Which DNS components matter on Ubuntu?

Four pieces interact on most servers. Netplan defines interface-level nameservers. systemd-resolved aggregates them and handles caching. systemd-networkd or NetworkManager applies link settings. Cloud-init may inject DNS on first boot for AWS, DigitalOcean, or Hetzner images.

Know your renderer before editing YAML. Run netplan get on Ubuntu 24.04 or inspect networkd vs NetworkManager in the Netplan file header.

How do you configure DNS with Netplan on Ubuntu?

Netplan is the default network configuration layer on Ubuntu Server. Static DNS belongs in your Netplan YAML under the interface that carries default routes. This is the first place I check when a Ubuntu network configuration change breaks outbound API calls after a reboot.

Example for a single NIC with static IP and public resolvers:

# /etc/netplan/01-netcfg.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: false
      addresses:
        - 203.0.113.10/24
      routes:
        - to: default
          via: 203.0.113.1
      nameservers:
        addresses:
          - 1.1.1.1
          - 8.8.8.8
        search:
          - internal.example.com

Apply and verify in order:

  1. Validate syntax: sudo netplan generate
  2. Apply live: sudo netplan apply
  3. Check resolved picked up servers: resolvectl status eth0
  4. Test lookup: dig @127.0.0.53 example.com +short

For DHCP interfaces, you can override provider DNS. Set dhcp4-overrides: use-dns: false and supply your own nameservers block. AWS and some Nepali hosting panels push their resolvers through DHCP. Those work until you migrate the VM and the old resolver IP stops responding.

On production Laravel hosts I prefer Cloudflare (1.1.1.1, 1.0.0.1) or the hypervisor's internal resolver when it exists. Google Public DNS (8.8.8.8) is fine for general use. Match your domain and hosting provider's docs when they supply private resolvers for internal zones.

What Netplan mistakes break DNS?

Wrong YAML indentation is the top failure. nameservers must sit under the interface, not under network root. A second issue is mixing NetworkManager and networkd renderers across files. Third, forgetting sudo netplan apply after edit leaves old DNS in memory.

Always keep a serial console or out-of-band path open when changing DNS on remote servers. Lock yourself out once and you will never skip that step again.

How do you configure systemd-resolved on Ubuntu?

systemd-resolved is the default local DNS stub resolver on Ubuntu. It supports per-link DNS, LLMNR, DNSSEC validation, and conditional forwarding. The main config file is /etc/systemd/resolved.conf. Official behaviour is documented in the systemd-resolved manual.

Global fallback DNS when Netplan does not set servers:

# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1 9.9.9.9
FallbackDNS=8.8.8.8
Domains=~.
DNSSEC=allow-downgrade
Cache=yes
DNSStubListener=yes

Restart and flush after edits:

sudo systemctl restart systemd-resolved
sudo resolvectl flush-caches
resolvectl statistics

The Domains=~. syntax marks a routing-only domain. Combined with per-link settings it enables split DNS. Internal hostnames resolve through a private nameserver while public domains use Cloudflare or Google.

Split DNS with systemd-resolvedsystemd-resolved127.0.0.53Public domainsexample.com, github.comPrivate domains*.internal.local1.1.1.1Cloudflare DNS10.0.0.2Office dnsmasqDomains= directive routes queries to the correct upstream
Split DNS in this Ubuntu DNS configuration guide: systemd-resolved routes public and private zones to different upstream resolvers

When should you disable the stub listener?

Some stacks want direct control of /etc/resolv.conf. Docker, custom dnsmasq, or legacy BIND clients on the same host may conflict with the stub at 127.0.0.53. Set DNSStubListener=no, restart resolved, then replace the symlink:

sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

Only do this when you understand the trade-off. You lose local caching on the stub unless another daemon provides it. Document the change in your runbook so the next upgrade does not revert it silently.

Should you use dnsmasq or BIND for local DNS on Ubuntu?

Most web servers only need client-side DNS, not a full authoritative server. dnsmasq fits caching and local development hostnames. BIND9 fits when you host your own zones. The table below compares typical use cases on Ubuntu 22.04 and 24.04.

ApproachBest forComplexityUbuntu integration
systemd-resolved onlyDefault VPS, single serverLowBuilt-in, Netplan-driven
dnsmasq cacheHeavy outbound lookups, dev /etc/hostsMediumDisable stub or bind to 127.0.0.1
BIND9 authoritativePrivate zone hosting, lab DNSHighSeparate service, ufw rules
Cloud provider DNSRoute 53, Cloudflare, internal VPCLowVia DHCP or static Netplan

Install and configure dnsmasq as a lightweight cache:

sudo apt update
sudo apt install dnsmasq
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
# /etc/dnsmasq.conf
port=53
domain-needed
bogus-priv
no-resolv
server=1.1.1.1
server=8.8.8.8
cache-size=1000
listen-address=127.0.0.1
sudo ln -sf /run/dnsmasq/resolv.conf /etc/resolv.conf
sudo systemctl enable --now dnsmasq

I rarely run BIND on app servers. When a client needs internal zone control, we put BIND on a dedicated host and point app servers at it through Netplan. Keep authoritative DNS off your Nginx application box unless you have a clear reason.

For quick local hostname testing during a travel booking platform deploy, /etc/hosts plus resolved caching is enough. Use the regex tester to validate any automation scripts that parse dig output.

How do you troubleshoot DNS problems on Ubuntu?

DNS failures show up as slow page loads, failed Git pulls, broken payment webhooks, and queue workers that cannot reach SMTP or API endpoints. Treat symptoms as resolver problems until proven otherwise.

Run this diagnostic sequence:

  1. ping -c2 1.1.1.1 — confirms routing, not DNS
  2. dig example.com — tests default resolver path
  3. dig @1.1.1.1 example.com — bypasses local stack
  4. resolvectl query example.com — shows which interface and server answered
  5. sudo tcpdump -i any port 53 — catches silent drops or wrong target

If direct queries to 1.1.1.1 work but default lookups fail, the bug is local. Check Netplan, resolved, or a stale resolv.conf symlink. If both fail, inspect UFW firewall rules. Outbound UDP and TCP port 53 must be allowed unless you force DNS over TLS on port 853.

Intermittent failures often trace to IPv6. An AAAA record exists but the path to the v6 resolver is broken. Test with dig AAAA example.com and try resolvectl dns eth0 with v4-only servers. Netplan accepts v6 nameservers like 2606:4700:4700::1111 when your network supports them.

DNS Troubleshooting Decision TreeApp cannot resolve hostPing IP works?Fix routing firstdig @1.1.1.1 OK?Fix local resolverCheck firewallReview Netplan, resolved.conf, resolv.conf symlinkThen flush cache and retest
DNS troubleshooting workflow for Ubuntu servers: isolate network, upstream, and local resolver layers before editing config

How do DNS issues affect web applications?

Laravel queue workers cache DNS at the PHP process level on long runs. A resolver change mid-flight may not apply until you restart PHP-FPM or Supervisor. I've seen webhook retries pile up because outbound DNS to a payment gateway timed out after a bad Netplan edit.

MySQL replication and remote backups fail the same way. The error looks like a database problem. Always run dig db-replica.internal before chasing SQL grants. Pair DNS checks with your server monitoring alerts so MTTR stays low.

How do you harden DNS on production Ubuntu web servers?

DNS is part of your attack surface. Cache poisoning and resolver hijacks still happen on unsecured networks. Basic hardening costs little on a typical Rs 3,000–5,000/month VPS (~USD 22–37).

  • Prefer trusted upstream resolvers you control or well-known public anycast DNS
  • Enable DNSSEC=allow-downgrade or stricter when your upstream supports it
  • Block inbound port 53 on public interfaces unless you run authoritative BIND
  • Audit /etc/hosts for unexpected entries during security hardening
  • Log resolver changes in version control alongside Netplan files

On shared EC2 hosts running multiple legal-tech sites, we keep identical Netplan DNS blocks across sister deployments. That consistency simplified troubleshooting when one resolver IP changed after a provider migration. The same approach applies to hardened Ubuntu web servers running PHP 8.4 or 8.5 with Laravel 12 or 13.

Consider DNS over TLS for privacy-sensitive workloads. systemd-resolved supports DNSOverTLS=opportunistic in resolved.conf. Cloudflare and Quad9 provide the required hostname validation. This is optional for most brochure and eCommerce sites but worth enabling for admin panels handling client documents.

Production DNS Hardening LayersLayer 1: Trusted upstream DNSNetplan nameservers + resolved.conf fallbackLayer 2: Local resolver controlsystemd-resolved stub, cache flush policyLayer 3: UFW firewallBlock inbound port 53Layer 4: Monitoringdig checks in cron
Production DNS hardening on Ubuntu: trusted upstream, controlled local resolver, firewall, and monitoring

What belongs in your DNS runbook?

Store Netplan YAML in git. Note which resolver each environment uses. Document the flush command after deploy. Add a weekly cron that logs dig +short google.com to syslog. When you follow backup strategies, include /etc/netplan/ and /etc/systemd/resolved.conf in your config backups.

For multi-server setups, align DNS with your deployment pipeline. A Symfony or Laravel deploy that hits external APIs during composer install will fail fast if DNS is wrong on the CI runner or target host. Fix resolver config before debugging Composer timeouts.

Ubuntu Netplan reference material lives in the official Netplan documentation. Cross-check field names when upgrading from 22.04 to 24.04 because renderer defaults shifted slightly on cloud images.

Key Takeaways

  • Set DNS in Netplan nameservers, apply with netplan apply, and verify through resolvectl status.
  • Do not hand-edit /etc/resolv.conf when systemd-resolved manages the stub at 127.0.0.53.
  • Use dig @1.1.1.1 vs dig example.com to separate upstream outages from local misconfiguration.
  • Choose dnsmasq for caching or dev hostnames; reserve BIND for dedicated authoritative zones.
  • Back up Netplan and resolved.conf, allow outbound port 53 in UFW, and restart PHP-FPM after resolver changes on long-lived workers.
  • Flush caches with resolvectl flush-caches after every DNS config change before retesting applications.

People Also Ask

Where is DNS configured on Ubuntu 24.04?

Primary client DNS lives in /etc/netplan/*.yaml under each interface's nameservers key. systemd-resolved reads those settings and exposes the stub resolver at 127.0.0.53. Global overrides go in /etc/systemd/resolved.conf.

Why does /etc/resolv.conf keep resetting on Ubuntu?

It is often a symlink managed by systemd-resolved. Manual edits get overwritten on reboot or network restart. Change Netplan or resolved.conf instead, or disable the stub listener if another DNS daemon owns port 53.

What are the best DNS servers for Ubuntu VPS hosts?

Cloudflare (1.1.1.1), Quad9 (9.9.9.9), and Google (8.8.8.8) are reliable defaults. Use your cloud provider's internal resolver when the docs recommend it for lower latency inside the VPC.

How do I test DNS after changing Netplan?

Run sudo netplan apply, then resolvectl status, resolvectl flush-caches, and dig example.com +trace. Confirm both forward and reverse paths if your app depends on PTR records for mail or API allowlists.

Ship reliable DNS before your next deploy

Correct Ubuntu DNS configuration is boring work until the moment it saves a launch. Set nameservers in Netplan, let systemd-resolved handle the stub, validate with dig and resolvectl, and document every change. That baseline keeps Laravel apps, WordPress shops, and API integrations online when upstream networks shift. If you want hands-on help auditing resolver setup across production hosts, contact us or review our support and maintenance and web development services. For related reading, see the fail2ban guide, MySQL install walkthrough, and TLS configuration for Nginx. This Ubuntu DNS Configuration Guide is the foundation those stacks assume you already have right.

Frequently Asked Questions

Primary client DNS lives in /etc/netplan/.yaml under each interface's nameservers key. systemd-resolved reads those settings and exposes the stub resolver at 127.0.0.53. Global overrides go in /etc/systemd/resolved.conf.

It is often a symlink managed by systemd-resolved. Manual edits get overwritten on reboot or network restart. Change Netplan or resolved.conf instead, or disable the stub listener if another DNS daemon owns port 53.

Cloudflare (1.1.1.1), Quad9 (9.9.9.9), and Google (8.8.8.8) are reliable defaults. Use your cloud provider's internal resolver when the docs recommend it for lower latency inside the VPC.

Put static DNS under the interface that carries your default route in /etc/netplan/.yaml, inside a nameservers block with addresses and optional search domains. Validate with sudo netplan generate, apply with sudo netplan apply, then confirm systemd-resolved picked up the servers via resolvectl status on that interface. Test with dig @127.0.0.53 example.com +short. On DHCP interfaces, set dhcp4-overrides use-dns false and supply your own nameservers when provider defaults are unreliable after migrations.

Wrong YAML indentation is the top failure; nameservers must sit under the interface, not under the network root. Mixing NetworkManager and networkd renderers across Netplan files causes inconsistent application. Forgetting sudo netplan apply leaves old DNS active in memory even after you edit the file. Always keep serial console or out-of-band access open when changing DNS on remote servers, because a bad edit can lock you out until you revert from console.

When an application calls gethostbyname(), the glibc resolver reads /etc/resolv.conf and forwards queries upstream. On modern Ubuntu, that file usually points at 127.0.0.53, where systemd-resolved acts as a local forwarding proxy. Netplan writes network YAML that NetworkManager or systemd-networkd applies; nameservers you define there end up in resolved's runtime state. Cloud-init may also inject DNS on first boot on AWS, DigitalOcean, or Hetzner images. Capture ls -l /etc/resolv.conf, resolvectl status, and cat /etc/netplan/*.yaml before changing anything.

Edit /etc/systemd/resolved.conf under the Resolve section to set global DNS, FallbackDNS, Domains, DNSSEC, Cache, and DNSStubListener options when Netplan does not supply servers. The Domains tilde-dot syntax marks a routing-only domain and enables split DNS routing. After edits, restart with sudo systemctl restart systemd-resolved, flush caches with sudo resolvectl flush-caches, and review resolver activity with resolvectl statistics. On a typical server, resolved aggregates per-link DNS from Netplan rather than requiring heavy manual tuning.

Split DNS sends internal hostnames to a private nameserver while public domains use Cloudflare, Google, or another public resolver. On Ubuntu, systemd-resolved handles this through per-link DNS from Netplan combined with Domains routing in /etc/systemd/resolved.conf. Internal zones resolve through your private resolver; everything else goes to public upstreams. This matters when Laravel apps, queue workers, or MySQL replication depend on internal hostnames like db-replica.internal that do not exist on the public internet.

Disable the stub listener when Docker, custom dnsmasq, or legacy BIND clients on the same host conflict with resolved listening on 127.0.0.53. Set DNSStubListener=no in resolved.conf, restart resolved, then point /etc/resolv.conf at /run/systemd/resolve/resolv.conf or your replacement daemon's file. Only do this when you understand the trade-off: you lose local caching on the stub unless another daemon provides it. Document the change in your runbook so the next upgrade does not revert it silently.

Most web servers only need client-side DNS, not a full authoritative server. systemd-resolved alone suits default VPS setups with low complexity. dnsmasq fits heavy outbound lookups, caching, and local development hostnames; install it, point upstream server directives at trusted resolvers, and bind listen-address to 127.0.0.1. BIND9 fits private zone hosting on a dedicated host, not on your Nginx application box. For quick local hostname testing during deploys, /etc/hosts plus resolved caching is often enough without running BIND on app servers.

Start with ping -c2 1.1.1.1 to confirm routing, not DNS. Run dig example.com for the default resolver path and dig @1.1.1.1 example.com to bypass the local stack. Use resolvectl query example.com to see which interface and server answered. If direct upstream queries work but defaults fail, check Netplan, resolved, or a stale resolv.conf symlink. If both fail, inspect UFW rules because outbound UDP and TCP port 53 must be allowed. Intermittent failures often trace to broken IPv6 paths when AAAA records exist but v6 resolvers are unreachable.

DNS failures show up as slow page loads, failed Git pulls, broken payment webhooks, and queue workers that cannot reach SMTP or API endpoints. Laravel queue workers cache DNS at the PHP process level on long runs, so a resolver change mid-flight may not apply until you restart PHP-FPM or Supervisor. MySQL replication and remote backups fail with errors that look like database problems; run dig against the replica hostname before chasing SQL grants. I've seen webhook retries pile up after a bad Netplan edit timed out outbound DNS to a payment gateway.

Prefer trusted upstream resolvers you control or well-known public anycast DNS like Cloudflare and Quad9. Enable DNSSEC allow-downgrade or stricter settings when upstream supports it. Block inbound port 53 on public interfaces unless you run authoritative BIND. Audit /etc/hosts for unexpected entries during security hardening. Log resolver changes in version control alongside Netplan files. Consider DNSOverTLS opportunistic in resolved.conf for privacy-sensitive admin panels. Basic hardening costs little on a typical Rs 3,000 to 5,000 per month VPS around USD 22 to 37.

Run sudo netplan apply, then resolvectl status to confirm the interface picked up new nameservers. Flush caches with resolvectl flush-caches before retesting so stale answers do not mask the change. Test forward lookups with dig example.com and dig @127.0.0.53 example.com +short. Use dig example.com +trace for deeper path validation. Confirm both forward and reverse paths if your app depends on PTR records for mail or API allowlists. Compare dig @1.1.1.1 against the default path to separate upstream outages from local misconfiguration.

Store Netplan YAML in git and note which resolver each environment uses. Document the flush command after every deploy: resolvectl flush-caches. Add a weekly cron that logs dig +short google.com to syslog for early failure detection. Include /etc/netplan/ and /etc/systemd/resolved.conf in config backups alongside your normal backup strategy. Align DNS across multi-server setups so sister deployments share identical Netplan DNS blocks, which simplifies troubleshooting when a provider migration changes resolver IPs. Fix resolver config before debugging Composer timeouts on Symfony or Laravel deploys that hit external APIs.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: