My self-hosted site works everywhere except at home (NAT loopback and split DNS)
Your home server is reachable from mobile data and from friends' houses, but not from your own Wi-Fi. Why that happens, how to confirm it in two minutes, and the two fixes: split DNS (best) or NAT loopback.
You set up a home server (Home Assistant, Nextcloud, Jellyfin, a camera NVR, a website) and pointed a domain like home.example.com at your home’s public IP with a port forward. Your phone on mobile data opens it. A friend opens it. But on your own Wi-Fi it times out, or opens the router’s login page instead.
Nothing is broken on the server. Your router doesn’t know how to “turn around” traffic that leaves your network and is aimed straight back at itself.
Why it happens
From outside, the path is simple: visitor → your public IP → router port forward → server.
From inside, your laptop looks up home.example.com, gets your public IP, and sends traffic to the router’s outside address. The router has to rewrite it and send it back in. That trick is called NAT loopback, NAT reflection or hairpin NAT. Many home routers don’t do it, do it badly, or answer with their own admin page. Netgate’s pfSense documentation adds that when the client and server sit on the same network, the server replies directly. The client is expecting a reply from the public IP, so it drops the connection.
Confirm it in two minutes
-
On the home Wi-Fi, look up the name:
- Windows:
nslookup home.example.com - Mac/Linux:
dig +short home.example.com
If it returns your public IP (check it at any “what is my IP” site), a loop problem is very likely. Also check for an IPv6 answer (
nslookup -type=AAAA home.example.comordig +short AAAA home.example.com). Devices prefer IPv6 when they have it, which can send them somewhere else entirely. - Windows:
-
Open the server by its local IP and port (e.g.
http://192.168.1.20:8123). If that works, the server is fine and only the name path is broken. -
Turn Wi-Fi off on your phone and open the domain on mobile data. If it works there and not at home, this guide probably fits. Firewall rules, Wi-Fi “client isolation” and IPv6 differences can cause similar symptoms, so check those if the fixes below don’t help.
Fix 1 (best): split DNS
Make your home network answer home.example.com with the local IP of whatever serves that name to the outside world. If you use a reverse proxy (Caddy, Nginx Proxy Manager, Traefik), that’s the proxy’s IP and port 443, not the app’s own port. Give that machine a fixed (reserved) IP so the record stays right. The rest of the internet keeps getting the public IP. Traffic then goes straight across the LAN. It’s faster too, because it never touches the router’s NAT. pfSense’s docs call this “the best practice to allow local clients to access local resources” and describe NAT reflection as a hack.
Where to add the local record (pick whatever you already run):
- Router with local DNS overrides (UniFi, OPNsense, pfSense, many ASUS/MikroTik): add a host override or local DNS record:
home.example.com → 192.168.1.20. - Pi-hole: Local DNS › DNS Records.
- AdGuard Home: Filters › DNS rewrites.
Then make sure your devices actually use that DNS server:
- Your router’s DHCP must hand out the Pi-hole/AdGuard/router IP as the DNS server, for IPv6 as well as IPv4 if your network has IPv6. Don’t add a public resolver (like 8.8.8.8) as a “secondary”. Devices use it at random and get the public answer.
- If the domain has a public AAAA (IPv6) record, add a local IPv6 override too, or devices may skip your IPv4 one.
- Browser “secure DNS” (DNS over HTTPS), phone “Private DNS”, iCloud Private Relay or a VPN can skip your home DNS completely. If one device still fails, check these first.
- Flush caches after the change: Windows
ipconfig /flushdns, macOSsudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder. Browsers keep their own cache, so restart the browser too. Then run the lookup from step 1 again to confirm the local answer. - Test the real HTTPS path against the local IP without changing any settings:
A normal response (not a certificate error) means split DNS will work.curl -I --resolve home.example.com:443:192.168.1.20 https://home.example.com/
HTTPS keeps working, if the certificate is one browsers trust. A certificate is issued for the name, not the IP, so a Let’s Encrypt certificate for home.example.com is valid by either address. A Cloudflare Origin CA certificate is not trusted by browsers: it only works behind Cloudflare’s proxy. If that’s what your server has, local visitors will get a certificate warning. Switch the server to Let’s Encrypt (Caddy does this automatically) before using split DNS.
The one catch: split DNS only changes the address, not the port. If outsiders use port 8443 that the router forwards to 443 inside, a local client given the local IP will still try 8443. Either use the same port inside and out, or put a reverse proxy on the server listening on the outside port.
Fix 2: turn on NAT loopback
If your router has it, the setting is called NAT loopback, NAT reflection, hairpin NAT or “NAT redirection”. Turn it on, and the router handles the U-turn. On some routers it’s a per-rule tick box on each port forward. When the client and server are on the same network, the router also has to rewrite the source address (pfSense documents this). Home routers with a simple on/off switch usually handle that for you. It’s simpler than split DNS, but every local request now goes through the router, and many ISP-supplied routers don’t have it at all.
Fix 3 (no router access): a hosts-file entry
For one or two computers, map the name yourself:
- Windows: add
192.168.1.20 home.example.comtoC:\Windows\System32\drivers\etc\hosts(edit Notepad as administrator). - Mac/Linux: add the same line to
/etc/hostswithsudo.
Stop if: the device is a laptop that leaves the house. With a hosts entry it will keep trying the local IP while you’re out, and the site will fail away from home. Remove the line, or use split DNS instead.
Behind Cloudflare’s proxy (orange cloud)?
If the record is proxied, outside lookups return Cloudflare’s IPs, not yours. Loopback isn’t involved, so if that fails at home, the problem is elsewhere (firewall rules, the origin certificate).
Think before adding split DNS here. Going direct skips everything Cloudflare does in front of your server: its certificate (see the Origin CA note above), its firewall rules, and any Cloudflare Access login you set up. Inside your home the app would then be protected only by its own login. If your server only accepts connections from Cloudflare’s addresses, direct access will simply be refused. Usually the right move is to leave a proxied site going through Cloudflare. See Point a Cloudflare domain at Netlify with HTTPS and Caddy reverse proxy for a home lab.
Sources
- NAT Reflection — by Netgate pfSense Documentation
- Can Split DNS Fix a Self-Hosted App That Fails Only Inside Your Home? — by ZimaSpace support
- Hairpin NAT vs split-DNS — by adamnet.works community