Reachable by IP but Not by Name: Debugging DNS on a Home LAN
You open http://192.168.1.10:8080 and Nextcloud loads fine. You open https://cloud.example.com from the same sofa and it times out, or says the server cannot be found. From your phone on mobile data, the name works perfectly.
The service is fine. Something between your device and the answer for that name is wrong, and there are only a handful of candidates. Here they are, roughly in order of how often they bite.
First, find out what the name resolves to
Everything else depends on this one answer. Ask the resolver your machine actually uses, then compare it with what the outside world sees.
getent hosts cloud.example.com
dig +short cloud.example.com
dig +short cloud.example.com @1.1.1.1
Quick detour on why there are two tools. dig talks straight to a DNS server and ignores /etc/nsswitch.conf. getent hosts goes through the C library, so it also sees /etc/hosts, mDNS and anything else configured. Applications use the second path. If dig works and getent does not, the fault is in the host configuration, not the DNS server.
On a systemd-resolved machine, resolvectl query cloud.example.com is better still, because it names the link and server that answered.
Read the answer, then pick the branch
- No answer at all: your LAN resolver is refusing, filtering or not forwarding. See the rebinding section.
- Your public IP: the name works, but your router will not loop the traffic back. See hairpin NAT.
- The LAN IP on
digbut something else fromgetent: a stale/etc/hostsline, a search domain, or a different resolver in play. - A name ending in
.localthat fails: mDNS, covered below.
The name points at your public IP, and the router will not hairpin
This is the classic. Public DNS says cloud.example.com is 203.0.113.7, your router's WAN address. A device inside sends a packet to that address, and the router has to notice it is for itself, apply the port forward, and send it back out the LAN side to the server.
That is called hairpin NAT (or NAT loopback or reflection). Many routers do not do it, or do it badly. The server also sees a client on its own subnet, so replies may skip the router entirely, which breaks the connection. The robust fix is not to hairpin at all: make the name resolve to the private address when you are inside.
Split-horizon DNS: give the LAN its own answer
Run a resolver on the LAN that overrides just the names you host. Everything else still forwards upstream. With dnsmasq (also what OpenWrt uses), it is one line:
address=/cloud.example.com/192.168.1.10
With Unbound it takes two:
server:
local-zone: "cloud.example.com." redirect
local-data: "cloud.example.com. A 192.168.1.10"
Use redirect rather than static if you want subdomains to follow along. With static, any name you did not list under that zone returns NXDOMAIN, which is occasionally what you want and usually a surprise.
Then check your DHCP server hands out this resolver, not the ISP's, or the override is never consulted.
Rebinding protection eats the answer
Now the opposite problem. Your public DNS record points at a private address (a lot of people do this deliberately, so internal services get real names and real certificates). Your router sees a public name resolving to 192.168.x.x and drops it.
That is DNS rebinding protection, and it exists for a good reason: it stops a hostile website from pointing its own name at your router's admin page. It is on by default in OpenWrt's dnsmasq (rebind_protection) and in Unbound's private-address setting.
Allow your own domain rather than switching the protection off:
# dnsmasq
rebind-domain-ok=/example.com/
# unbound
server:
private-domain: "example.com"
The symptom is a clean "no such host" from the LAN resolver, while dig @1.1.1.1 returns the private IP happily. That mismatch is your tell.
Your browser is not asking your resolver
If getent and dig both give the right LAN address but the browser still fails, check its DNS settings. Firefox and Chromium can use DNS over HTTPS to a public provider, which skips your local overrides entirely and returns the public address.
Hang on, why does that matter for local names? Because the DoH provider has never heard of your address= line. It only knows what public DNS says. Firefox has a canary domain and some heuristics to back off on managed networks, but do not rely on them. Turn secure DNS off for that profile, or point it at a resolver you run.
.local names and mDNS
If the name ends in .local, unicast DNS is probably not involved. RFC 6762 reserves that suffix for multicast DNS, so lookups go to a multicast group on the local link, and a normal DNS server never sees them. Linux needs Avahi or systemd-resolved with mDNS enabled to answer or resolve them.
Multicast also does not cross subnets or VLANs without a reflector. If the server is on an IoT VLAN, nas.local will fail from your main network even though the IP works.
For a home network, RFC 8375 reserves home.arpa for exactly this job. It behaves like an ordinary DNS zone, which means your own resolver can serve it. You cannot get a public certificate for it, which is a fair reason to use a real domain you own instead.
IPv6 can quietly win
Last one. If the name has an AAAA record (public, perhaps from a DDNS update or a CDN) and your client has IPv6, it will try that first. The LAN override you wrote only returns an A record, so the client may prefer a public IPv6 address that your firewall does not forward.
Check with dig AAAA cloud.example.com. Either add a local AAAA answer, or have the resolver return an empty answer for AAAA on that name. In dnsmasq that is address=/cloud.example.com/:: alongside the A override, which returns a null AAAA for the name.
Check it worked
- Run
getent hosts cloud.example.comon a LAN client; it should print the private address. - Run
curl -v https://cloud.example.com; the connection line should show the same address. - Flush caches if it still looks wrong:
resolvectl flush-cacheson the client, and restart the router's DNS service. - From mobile data, confirm the name still resolves to the public address, so you have not broken remote access.
If certificates complain after the change, that is usually a good sign: you are now talking to the server directly, and it is presenting whatever certificate it has. A reverse proxy listening on the LAN IP with the right virtual host fixes that.