Wildcard & exact rules
*.myapp.test matches the apex and any depth of subdomain, dnsmasq-style — or pin an exact host.test. IPv4 and/or IPv6 targets, per-rule TTL, enable toggles.
Point *.myapp.test at 172.30.0.3 and
every hostname under it resolves — api.myapp.test,
db.myapp.test, anything — with zero per-host bookkeeping.
A tiny DNS server on loopback, wired into the resolver your OS already runs.
localdns add '*.myapp.test' 172.30.0.3 ✓ rule added *.myapp.test → 172.30.0.3 dig +short api.myapp.test 172.30.0.3 dig +short db.myapp.test 172.30.0.3 dig +short tenant-42.myapp.test 172.30.0.3 # one rule. every hostname under it. no /etc/hosts edits, ever.
the unprivileged loopback port it answers on
no analytics or tracking SDKs — nothing phones home
same rules, same UI, on macOS, Windows & Linux
the desktop installer — small, fast, no runtime
/etc/hosts and a full dnsmasq setup.Hosts files can't do wildcards. dnsmasq can, but wiring it into the resolver your OS already runs is a fight over port 53. LocalDNS is the missing piece.
Every service under *.myapp.test means another line to add — and another edit every time a container or worktree spins up.
# /etc/hosts 172.30.0.3 api.myapp.test 172.30.0.3 db.myapp.test 172.30.0.3 cache.myapp.test 172.30.0.3 auth.myapp.test 172.30.0.3 tenant-1.myapp.test 172.30.0.3 tenant-2.myapp.test # …and one more, forever, by hand
A single wildcard collapses all of them. New subdomains just work — no edit, no restart, no sudo loop.
# LocalDNS rule *.myapp.test → 172.30.0.3 # api.myapp.test ✓ resolves # db.myapp.test ✓ resolves # anything.myapp.test ✓ resolves # # every app on your machine — browsers, # curl, your IDE — sees it. not just dig.
Wildcard rules, live diagnostics, and system integration that cooperates with your existing DNS instead of fighting it.
*.myapp.test matches the apex and any depth of subdomain, dnsmasq-style — or pin an exact host.test. IPv4 and/or IPv6 targets, per-rule TTL, enable toggles.
Organize rules into groups with one-switch enable, and flip whole sets on or off. A master switch parks the whole server without deleting a thing.
A live query log with the answer, outcome (NXDOMAIN/NODATA) and latency for every lookup — plus a one-click self-test that fires a real query at the server.
Scans your hosts file and suggests the wildcard rules that collapse groups of entries. It never modifies /etc/hosts — your existing manager keeps owning it.
Lives quietly with a live status orb, recent-queries glance and a master switch — no Dock icon needed. Always one click away, idle cost near the noise floor.
Change a rule or the port and LocalDNS re-registers the affected zones with the system resolver for you. On headless Linux, localdns serve hot-reloads on a file watch.
The same design everywhere: a loopback-only DNS server, plus a small, auditable, per-OS mechanism that only registers zones — so no root process runs routinely, and LocalDNS never touches resolver state it didn't create.
Type a pattern like *.myapp.test and a target address. Rules live in a portable rules.json with an identical schema on every OS — copy it between machines.
An embedded DNS server binds 127.0.0.1 only and answers your zones with A/AAAA records. It's unreachable from the network — verify it yourself with dig @127.0.0.1 -p 15353.
LocalDNS registers the zone through the mechanism your OS already provides, so every app — browsers, curl, your IDE — resolves your names. Ownership is always explicit and reversible.
| OS | Zone registration | Server binds | Privilege model |
|---|---|---|---|
| macOS | /etc/resolver/<zone> files — the native Apple mechanism |
127.0.0.1:15353 |
One visible sudo command once, then a sandboxed security-scoped grant. No daemon. |
| Windows | NRPT rules tagged Comment=LocalDNS |
127.65.43.53:53 + 127.0.0.1:15353 |
A demand-start localdns-helper service — self-stops after 120 s idle. Installed once. |
| Linux | systemd-resolved routing domains on a dedicated localdns0 link |
127.0.0.1:15353 |
Hardened localdns-agentd — CAP_NET_ADMIN only, polkit-gated. Survives reboots. |
Anything foreign covering one of your zones is reported as Managed elsewhere and left alone. “Unregister All” — or uninstalling — removes every trace.
/etc/hosts?Hosts files can't do wildcards. Ten services under *.myapp.test mean ten lines to maintain — and another edit every time a service appears. LocalDNS collapses them to one rule and never touches your hosts file.
dnsmasq is excellent — but wiring it into a modern OS means winning a fight over port 53 and reconfiguring NetworkManager or resolved. LocalDNS cooperates with the resolver instead: your VPN's DNS, mDNS and split-horizon setups keep working.
resolved routes zones to DNS servers but can't answer *.zone → address itself. LocalDNS is the missing answering half, attached exactly the way resolved wants it.
LocalDNS collects nothing, transmits nothing, and talks to no server. This isn't a privacy policy promise you have to take on faith — it's how the software is built.
The embedded server pins its listener to 127.0.0.1, so it can't receive packets from — or send answers to — any other machine. The query log is a 200-entry in-memory ring buffer, never written to disk, cleared on quit. Read the full Privacy Policy.
The entire codebase — macOS app, Windows/Linux apps, and the CLI — is open source. On Windows and Linux it's simply free; on the Mac App Store, buying it funds development of all three.
Native SwiftUI app — sandboxed, notarized, auto-updating. Paid on the App Store; it funds every platform.
/etc/resolver integrationNSIS installer with the demand-start helper service. Full feature parity with the Mac app.
.deb / .rpm / .AppImage — plus the localdns CLI for headless boxes.
localdns add … && localdns serveNo. The embedded server binds the loopback interface only and answers exclusively the zones you configure. Everything else on your machine resolves exactly as before, through your normal system resolver. LocalDNS has no analytics, no telemetry, and talks to no server of its own.
No — and deliberately so. LocalDNS is authoritative only for your dev zones. It doesn't forward, cache, or do recursive resolution. Your VPN's DNS, mDNS, and corporate split-horizon setups keep working untouched, because the per-OS split-DNS mechanisms route only your zones to LocalDNS.
Writing /etc/resolver needs a privilege a sandboxed App Store app can't obtain on its own. So — like other hosts-file managers on the App Store — LocalDNS shows you one command to run yourself (with a copy button); your password is never seen by the app. You then grant the folder once in an open panel. After that, everything is automatic. Without the command, the server still runs and answers on 127.0.0.1:15353 — macOS just won't route system lookups to it yet.
No root process runs routinely. On macOS there's no daemon at all — just a user-granted folder ACL. On Windows the helper is demand-start and self-stops after 120 s idle. On Linux the agent is capability-restricted to CAP_NET_ADMIN and polkit-gated. Every privileged step is a one-time, visible consent.
Identical code. The Mac App Store build adds Apple's signing, notarization, sandboxing and automatic updates. Until it ships, an unsigned developer build is on GitHub Releases (right-click → Open). On Windows and Linux, the Releases builds are the real thing and free.
Yes. Rules live in a rules.json with a byte-identical schema across macOS, Windows and Linux — copy it between machines and it just works. The GUI and the localdns CLI share the same file.
Yes — the macOS app, the Windows/Linux app, and the CLI are all open source. You can read exactly what it does, build it yourself, and verify the privacy claims against the code. Browse the repository →
One rule, infinite hostnames — on the OS you already use, with the privacy guarantees built into the code.