The unencrypted DNS problem
You notice your DNS queries are traveling in plain text across your local network. Or you want to route them through a privacy-focused provider like Cloudflare, Quad9, or NextDNS. You try editing /etc/resolv.conf and immediately hit a wall. The file is a symlink pointing to /run/systemd/resolve/stub-resolv.conf. Any manual change vanishes after a reboot or a network manager restart.
Fedora handles name resolution through systemd-resolved. The daemon sits between your applications and the actual DNS servers. It caches results, handles DNSSEC validation, and supports encrypted transport out of the box. You configure it through resolvectl or by editing its main configuration file. The process is straightforward once you understand where the runtime and persistent layers live.
Run resolvectl status before you change anything. See what the system is currently using.
How systemd-resolved actually works
Traditional Linux setups write nameserver addresses directly into /etc/resolv.conf. Fedora replaced that model with a stub resolver listening on 127.0.0.53. Applications talk to the stub. The stub forwards queries to systemd-resolved. The daemon then routes them to the configured upstream servers.
This architecture gives you a single place to enforce encryption. When you enable DNS over HTTPS or DNS over TLS, the stub resolver passes the query to the daemon. The daemon encrypts the payload, sends it to the provider, decrypts the response, and hands it back to your application. Your browser or package manager never sees the unencrypted wire format.
Think of it like a secure drop box. You hand your mail to the drop box. The drop box puts it in a locked container, drives it to the post office, and returns the reply. The mail carrier never reads the contents. systemd-resolved is the drop box. The upstream provider is the post office.
The daemon maintains two configuration layers. Runtime settings apply immediately and survive until the next reboot. Persistent settings live in /etc/systemd/resolved.conf and survive reboots. NetworkManager can also push DNS settings per-connection, which overrides the global file for that specific link. Always check which layer is winning when behavior looks inconsistent.
Check the active interface before you apply changes. Guessing the interface name breaks the routing.
Configure DNS over HTTPS
DNS over HTTPS wraps standard DNS queries inside HTTPS traffic. It uses port 443, which means it blends in with normal web browsing and bypasses most restrictive firewalls. Cloudflare, Google, and NextDNS all support it.
Here is how to check your active network interface and apply a DoH endpoint to it.
ip -br link show # list interfaces with their state and MAC addresses
sudo resolvectl dns enp3s0 https://cloudflare-dns.com/dns-query # set DoH for the active interface
sudo resolvectl domain enp3s0 ~. # route all queries through this interface
The ~. domain directive tells the resolver to send every query to this interface. Without it, the system only uses the DoH server for domains explicitly assigned to that interface. Replace enp3s0 with your actual interface name. Wireless interfaces usually start with wlp, ethernet with enp or eth.
The command above changes the runtime configuration. It takes effect immediately but does not survive a reboot. To make it permanent, you need to edit the persistent configuration file.
Here is how to write the persistent DoH configuration.
[Resolve]
DNS=1.1.1.1 1.0.0.1
Domains=~.
DNSOverHTTPS=https://cloudflare-dns.com/dns-query
FallbackDNS=8.8.8.8 8.8.4.4
Save this to /etc/systemd/resolved.conf. The [Resolve] section applies globally. The Domains=~. line ensures all queries route through the configured servers. FallbackDNS provides a safety net if the primary provider goes down. Files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Always edit /etc/. Never touch /usr/lib/.
After saving, reload the daemon to apply the persistent settings.
sudo systemctl reload systemd-resolved # apply config without dropping active connections
Reload the service, not restart it. Restarting drops the cache and breaks active queries.
Configure DNS over TLS
DNS over TLS uses a dedicated port, 853, and wraps queries in a TLS handshake. It is slightly faster than DoH because it avoids HTTP framing overhead. It also requires your firewall to allow outbound traffic on port 853. Some corporate or campus networks block non-standard ports, which makes DoT less reliable in restricted environments.
Here is how to switch an interface to DoT using Quad9 as the provider.
sudo resolvectl dns enp3s0 tls://dns.quad9.net # set DoT for the active interface
sudo resolvectl domain enp3s0 ~. # route all queries through this interface
The tls:// prefix tells systemd-resolved to negotiate a TLS connection before sending queries. The daemon validates the provider certificate against your system trust store. If the certificate chain is invalid, the query fails and falls back to unencrypted DNS unless you explicitly disable fallback.
To make DoT persistent, update /etc/systemd/resolved.conf with the following block.
[Resolve]
DNS=9.9.9.9 149.112.112.112
Domains=~.
DNSOverTLS=dns.quad9.net
FallbackDNS=1.1.1.1
The DNSOverTLS directive accepts hostnames or IP addresses. When you provide a hostname, the daemon verifies the TLS certificate matches that hostname. Reload the service after editing.
sudo systemctl reload systemd-resolved # apply config without dropping active connections
Reload the daemon after every config change. The runtime and persistent configs diverge if you skip this step.
Verify the configuration
You need to confirm that queries are actually traveling over the encrypted channel. resolvectl status shows the current state of every interface and the global resolver settings.
resolvectl status # display resolver state and active servers
Look for the DNS Servers and DNSSEC lines under your interface. If DoH or DoT is active, you will see DNSSEC: yes and the provider URL or hostname listed. The Current DNS Server line shows which upstream address the daemon is currently using.
Run a live query to watch the encryption in action.
resolvectl query example.com # send a test query and show resolution path
The output lists the answer, the server that responded, and the protocol used. If you see DoH or DoT in the response path, the encryption is working. If it says DNS, the query fell back to plain UDP/TCP.
Check the journal for resolver activity when something behaves strangely.
journalctl -xeu systemd-resolved.service # show recent resolver logs with context
The x flag adds explanatory text to priority messages. The e flag jumps to the end of the log. Most sysadmins type journalctl -xeu <unit> muscle-memory style. Read the actual error before guessing.
Common pitfalls and error patterns
The resolver will refuse to encrypt queries if the provider certificate is untrusted. You will see validation failures in the journal. The exact wording varies by provider, but the pattern is consistent.
systemd-resolved[1234]: Failed to resolve 'example.com': Invalid argument
systemd-resolved[1234]: DNSSEC validation failed for example.com: Insecure
Fedora ships with a curated CA trust store. If you are using a custom corporate proxy or a self-signed DoH endpoint, you must import the certificate into /etc/pki/ca-trust/source/anchors/ and run update-ca-trust. The resolver checks the system trust store, not the browser trust store.
Interface name changes break runtime configuration. If your laptop connects to Wi-Fi and Ethernet simultaneously, resolvectl dns only affects the interface you specify. Queries for domains not assigned to that interface will route through the other connection. Use the ~. domain directive to force global routing, or configure each interface explicitly.
DNSSEC and DoH/DoT interact closely. systemd-resolved validates DNSSEC signatures by default. If your chosen provider does not support DNSSEC, or if the validation chain breaks, the resolver may drop responses entirely. You can disable validation temporarily for testing by setting DNSSEC=no in /etc/systemd/resolved.conf. Re-enable it immediately after troubleshooting. Disabling DNSSEC on a production system removes a critical integrity check.
The resolv.conf symlink confusion causes the most support tickets. Applications that bypass the stub resolver and read /etc/resolv.conf directly will ignore your DoH/DoT settings. Most modern software respects the systemd stub. Legacy tools or containers might need explicit nameserver configuration. Check your application documentation if a specific program refuses to resolve.
Run resolvectl status first. Identify the active interface before you blame the provider.
When to use which transport
Use DNS over HTTPS when you need maximum firewall compatibility and want queries to blend with standard web traffic. Use DNS over TLS when you want lower latency and your network allows outbound port 853. Use plain DNS when you are on a trusted local network and want to avoid the overhead of encryption. Use the systemd stub resolver when you want automatic caching and DNSSEC validation without managing unbound or dnsmasq.
Pick the transport that matches your network constraints. Test it before you commit.