I recently ran into a DNS problem that looked like a WordPress or reverse-proxy failure: the VM hosting my automation tools could reach the network, but resolving the public name for my own blog was inconsistent. The cause was split-horizon DNS: internal clients were receiving a local answer for the www name, while the zone apex still returned SERVFAIL.
The fix was not to change WordPress. I verified the DNS path, documented the router’s local override, and kept the reverse proxy responsible for HTTPS rather than trying to make every client bypass DNS.
1. Separate DNS from application connectivity
First I check whether the name resolves at all. A successful network route or TCP connection does not prove that DNS, TLS, or WordPress is healthy.
getent ahostsv4 www.<site-domain>
getent ahostsv4 <site-domain>
resolvectl status
ip route
curl -k -I --max-time 10 https://www.<site-domain>/
On the affected VM, the www name resolved to the internal reverse-proxy address and HTTPS returned 200. That told me the application path was working. The remaining problem was the difference between the www record and the zone apex.
2. Query the DNS server directly
I use dig to see the status code, answer, and server that responded. This is more useful than looking only at the result of a browser request.
dig +time=2 +tries=1 www.<site-domain> A
dig +time=2 +tries=1 <site-domain> A
dig +time=2 +tries=1 <site-domain> CNAME
The useful fields are:
NOERRORwith an answer means the resolver found a usable record.SERVFAILmeans the resolver could not complete the lookup. It is not the same as “the host does not exist.”- The
SERVERline identifies which resolver actually answered the query. - A
CNAMEshows the next name that must also resolve. A broken target can make the original lookup fail.
In my case, the internal resolver returned a local CNAME for www and an internal address for the proxy target. The apex lookup returned SERVFAIL. That combination explained why the browser worked with the full www name while tools using the bare domain failed.
3. Check the resolver path and search domains
Linux systems commonly use the systemd-resolved stub listener. I check the effective configuration instead of editing /etc/resolv.conf blindly.
resolvectl status
resolvectl query www.<site-domain>
resolvectl query <site-domain>
readlink -f /etc/resolv.conf
cat /etc/resolv.conf
A search domain can also change what an unqualified name means. I use fully qualified names while troubleshooting, including the trailing dot when I want to avoid search-list processing:
dig +time=2 +tries=1 www.<site-domain>.
dig +time=2 +tries=1 <site-domain>.
If the fully qualified query fails in the same way, the issue is in the zone or resolver path rather than a shell search-domain expansion.
4. Verify the router’s local DNS override
My router provides the internal DNS override. The public name is deliberately mapped to the local reverse proxy for clients on the LAN. This is the split-horizon part: internal and external clients can receive different answers for the same public name.
I verify the override in the router’s DNS or host-record configuration:
# Use the router's actual management UI or API, then verify from the VM:
dig @<router-dns-address> www.<site-domain> A
dig @<router-dns-address> <site-domain> A
The important detail is consistency. If the site is intended to work at both the apex and www, both names need deliberate records. If only www is supported, I make that canonical URL clear and redirect the apex at the reverse proxy or public DNS provider.
5. Keep Nginx Proxy Manager focused on HTTP and TLS
Nginx Proxy Manager does not fix a missing DNS record. It receives a request after the client has resolved the hostname. I check the proxy host configuration and certificate separately:
curl -k -I --max-time 10 https://www.<site-domain>/
curl -k -I --max-time 10 https://<site-domain>/
# From a client that uses the intended address, test the Host header:
curl -k -I --resolve www.<site-domain>:443:<proxy-address> https://www.<site-domain>/
The --resolve test is useful because it bypasses normal DNS while preserving the HTTPS hostname and SNI. If this works but a normal request fails, DNS is still the first place to look. If it fails too, then I investigate the proxy host, certificate, upstream service, or WordPress response.
6. Flush caches only after correcting the record
After changing the router record, I clear the resolver cache on the client and repeat the same queries. Flushing a cache before correcting the authoritative or local record only makes the old answer disappear temporarily.
sudo resolvectl flush-caches
resolvectl statistics
dig +time=2 +tries=1 www.<site-domain> A
curl -k -I --max-time 10 https://www.<site-domain>/
Browsers and applications may maintain their own DNS cache, so I also restart the affected application or browser when the command-line results are correct but the application still uses the old answer.
7. The troubleshooting checklist
- Check the exact hostname with
getentanddig. - Record the DNS status, answer, CNAME target, and responding resolver.
- Compare the apex and
wwwnames instead of assuming they are equivalent. - Verify the router’s internal override and the public record independently.
- Test HTTPS with
curl, including--resolvewhen isolating DNS. - Flush caches only after the DNS configuration is correct.
The practical lesson is that a reverse proxy cannot compensate for an incomplete DNS design. Once I treated DNS, TLS, proxy routing, and WordPress as separate layers, the SERVFAIL was straightforward to isolate without changing the blog application.