Here is the final polished article, now including a clean, complete “How to Remove Wildcard Domain Resolution” section. This version is publication-ready.


๐Ÿ“ How to Safely Set Up Wildcard Domain Resolution on Linux Without Breaking Your System

(Modern systemd-resolved + dnsmasq Split DNS Method)

Local development environments often need custom domains like:

http://myapp.test
http://api.test
http://backend.internal.test

But achieving wildcard resolution (i.e., *.test โ†’ 127.0.0.1) is tricky. Most tutorials break DNS by:

  • Overwriting /etc/resolv.conf
  • Disabling systemd-resolved
  • Hijacking port 53
  • Interfering with libvirt DNS
  • Using .local (reserved for mDNS)

This article walks you through the correct, safe, reversible approach that works on:

  • Arch Linux & Omarchy Linux
  • Fedora
  • Ubuntu
  • Manjaro
  • Any Linux using systemd-resolved

๐ŸŽฏ Goal

We want:

*.test โ†’ 127.0.0.1

WITHOUT breaking:

  • system DNS
  • VPN DNS
  • libvirt/QEMU DNS
  • systemd-resolved
  • Network connectivity

The solution must be:

  • wildcard-capable
  • isolated
  • non-conflicting
  • 100% reversible

๐Ÿ† The Best Method

Use dnsmasq on a separate port + systemd-resolved split DNS routing

This gives:

โœ” Full wildcard .test support โœ” No conflict with system services โœ” systemd-resolved remains fully functional โœ” No broken networking โœ” Fully reversible โœ” No changes to /etc/resolv.conf โœ” No touching port 53

This is how enterprise VPN clients and container systems (Podman, LXD, Kubernetes) implement split DNS.


๐Ÿ› ๏ธ Step 1 โ€” Create a dedicated dnsmasq instance on port 5353

Create config directory:

sudo mkdir -p /etc/dnsmasq.d-test
sudo nano /etc/dnsmasq.d-test/test.conf

Add:

# dnsmasq for .test wildcard resolution
port=5353
bind-interfaces
listen-address=127.0.0.1

# Wildcard domain rule
address=/.test/127.0.0.1

This ensures dnsmasq never conflicts with system services.


๐Ÿ› ๏ธ Step 2 โ€” Create a systemd service for this dnsmasq

sudo nano /etc/systemd/system/dnsmasq-test.service

Add:

[Unit]
Description=Dnsmasq Instance for .test Wildcard Resolution
After=network.target

[Service]
ExecStart=/usr/bin/dnsmasq --keep-in-foreground --conf-dir=/etc/dnsmasq.d-test
Restart=on-failure

[Install]
WantedBy=multi-user.target

Enable & start:

sudo systemctl daemon-reload
sudo systemctl enable --now dnsmasq-test

Test:

systemctl status dnsmasq-test

๐Ÿงช Step 3 โ€” Verify dnsmasq answers .test queries

dig @127.0.0.1 -p 5353 hello.test

Should return:

hello.test.  0  IN A  127.0.0.1

๐Ÿ› ๏ธ Step 4 โ€” Configure systemd-resolved split DNS

sudo mkdir -p /etc/systemd/resolved.conf.d
sudo nano /etc/systemd/resolved.conf.d/10-test-domain.conf

Add:

[Resolve]
DNS=127.0.0.1:5353
Domains=~test

Meaning:

  • Only .test domains go to dnsmasq-test
  • All other domains go through your normal DNS

Reload:

sudo systemctl restart systemd-resolved

๐Ÿงช Step 5 โ€” Test wildcard resolution

resolvectl query hello.test
resolvectl query anything.test
resolvectl query backend.internal.test

You should always get:

127.0.0.1

Test in browser:

http://myapp.test

This now resolves cleanly without modifying /etc/hosts.


๐Ÿค“ Why This Works (Deep Explanation)

systemd-resolved acts as the system DNS interceptor. When you add:

Domains=~test
DNS=127.0.0.1:5353

You instruct resolved to:

Forward ONLY .test queries to dnsmasq-test, and ignore upstream DNS servers for these queries.

dnsmasq-test uses:

address=/.test/127.0.0.1

So any .test domain โ€” regardless of subdomain depth โ€” returns 127.0.0.1.

This results in:

Domain Resolver Output
hello.test dnsmasq-test 127.0.0.1
api.backend.test dnsmasq-test 127.0.0.1
google.com upstream DNS real IP
archlinux.org upstream DNS real IP

No conflict. No breakage. No override of system functions.


๐Ÿ—‘๏ธ How to Completely Remove Wildcard .test Configuration

(100% rollback, safe)

1๏ธโƒฃ Remove dnsmasq-test config & disable service

sudo systemctl disable --now dnsmasq-test
sudo rm -r /etc/dnsmasq.d-test
sudo rm /etc/systemd/system/dnsmasq-test.service

Reload systemd:

sudo systemctl daemon-reload

2๏ธโƒฃ Remove split-DNS rule from systemd-resolved

sudo rm /etc/systemd/resolved.conf.d/10-test-domain.conf

Restart resolver:

sudo systemctl restart systemd-resolved

3๏ธโƒฃ Verify cleanup

resolvectl domain
resolvectl dns

Ensure .test no longer appears in routing.


4๏ธโƒฃ Test:

resolvectl query hello.test

Should now return:

Failed to resolve โ€ฆ

Wildcard setup removed successfully.


๐ŸŽ‰ Final Thoughts

This method is:

  • modern
  • robust
  • systemd-compatible
  • container-friendly
  • VPN-friendly
  • zero-conflict
  • wildcard-capable
  • fully reversible

It’s the safest way on modern Linux to get .test (or .dev, .lab, .localtest) wildcard DNS resolution โ€” perfect for:

  • Frappe
  • Docker
  • local microservices
  • FM (Frappe Manager)
  • web dev environments
  • custom proxies

If you want, I can also extend this article to cover:

โœ” Multiple wildcard domains (*.dev, *.localtest, *.sandbox) โœ” How to set up HTTPS for .test using mkcert โœ” Using CoreDNS instead of dnsmasq โœ” Using this setup with Docker Compose or FM

Just tell me what you want!