This guide is maintained by Ops Error Atlas from a backend engineering perspective. It favors evidence, command output, and failure-layer separation over broad definitions or blind configuration changes.
How Ops Error Atlas reviews guideshost not found in upstream means Nginx could not resolve an upstream hostname when it needed that name. It commonly appears during config test, reload, container startup, or request handling with variable-based proxy targets.
The useful question is:
Did Nginx need this upstream name resolved at startup, reload time, or request time?
That timing matters because Nginx hostname resolution behavior depends on how the upstream is configured.
Common examples
You may see:
nginx: [emerg] host not found in upstream "api" in /etc/nginx/conf.d/default.conf:12
or:
no resolver defined to resolve api.internal
or a runtime upstream failure when a variable is used in proxy_pass.
These are related but not identical. One fails at startup or reload; another fails during request processing.
First inspect the exact config
Dump the effective config:
nginx -T
Find upstream references:
nginx -T | grep -nE 'upstream|proxy_pass|resolver'
Then test DNS from the same environment as Nginx:
getent hosts api
getent hosts api.internal
cat /etc/resolv.conf
If Nginx runs inside Docker or Kubernetes, run those commands inside the Nginx container or pod, not on the host.
Startup resolution vs request-time resolution
Static upstream hostnames are often resolved when Nginx loads configuration:
proxy_pass http://api:8080;
If api is not resolvable at startup, Nginx can fail to start.
Variable-based proxy targets need a resolver for request-time resolution:
resolver 127.0.0.11 valid=30s;
set $backend api:8080;
proxy_pass http://$backend;
The resolver directive tells Nginx which DNS server to use at runtime.
Docker branch
In Docker Compose, service names are resolved on the Compose network. Common failure causes:
- Nginx container is not on the same network as the upstream service;
- upstream service name differs from the hostname in Nginx config;
- Nginx starts before the DNS name exists;
localhostis used when the upstream is another container;- runtime resolver should be Docker’s embedded DNS, often
127.0.0.11.
Checks:
docker ps
docker inspect <nginx-container>
docker exec -it <nginx-container> cat /etc/resolv.conf
docker exec -it <nginx-container> getent hosts api
docker exec -it <nginx-container> nginx -T
Fix path:
- put Nginx and upstream on the same Docker network;
- use the Compose service name, not host-only names;
- avoid
localhostfor another container; - configure a runtime resolver when variable
proxy_passis required.
Kubernetes branch
In Kubernetes, prefer stable Service DNS names:
service-name.namespace.svc.cluster.local
Checks:
kubectl exec -it <nginx-pod> -- cat /etc/resolv.conf
kubectl exec -it <nginx-pod> -- getent hosts api.default.svc.cluster.local
kubectl get svc,endpointslices -o wide
Common causes:
- Service name or namespace is wrong;
- Nginx pod DNS policy is unexpected;
- CoreDNS is unhealthy;
- NetworkPolicy blocks DNS;
- Nginx config uses a short name that resolves differently than expected;
- the upstream name exists, but has no ready endpoints, which is a later routing problem.
If DNS resolves but requests still fail, move from host not found to upstream connection, 502, or timeout debugging.
resolver directive branch
Runtime DNS resolution needs a resolver:
resolver 10.96.0.10 valid=30s ipv6=off;
Common mistakes:
- no
resolverdirective with variableproxy_pass; - resolver IP works on the host but not inside the container;
- resolver points to public DNS for private service names;
- IPv6 queries are attempted when the environment has no IPv6 path;
- resolver cache
validhides recent changes longer than expected.
Use the resolver that is reachable from the Nginx worker environment.
Case: name works in shell but Nginx still fails
Possible reasons:
- the shell test was on the host, but Nginx runs in a container;
/etc/hostsdiffers between shell and Nginx worker environment;- Nginx resolves at config load before the name exists;
- systemd service starts before network or DNS is ready;
- Nginx uses its own configured resolver for variable upstreams.
Check the exact process environment and startup order:
systemctl status nginx
journalctl -u nginx --since -30m
nginx -t
What not to do
- Do not replace internal service DNS with public DNS.
- Do not use
localhostfor another container or pod. - Do not assume host DNS success proves Nginx DNS success.
- Do not add a
resolverdirective without testing that resolver from the Nginx environment. - Do not mix static upstream behavior and variable
proxy_passbehavior.
Decision tree
host not found in upstream
|
+-- fails during nginx -t or startup?
| +-- inspect static proxy_pass/upstream hostname and startup DNS
|
+-- fails at request time?
| +-- inspect variable proxy_pass and resolver directive
|
+-- Docker?
| +-- check container network, service name, 127.0.0.11
|
+-- Kubernetes?
| +-- check Service DNS, namespace, CoreDNS, NetworkPolicy
|
+-- name resolves but upstream still fails?
+-- debug 502, connect refused, connect timed out, or upstream timed out
Minimal incident note
error line:
nginx config line:
static upstream or variable proxy_pass:
nginx runtime environment:
/etc/resolv.conf in nginx environment:
resolver directive:
getent hosts result:
Docker/Kubernetes service name:
startup or request-time failure:
fix:
nginx -t result:
verification request:
The incident is solved when Nginx can resolve the intended upstream name at the time it needs it and the next failure, if any, moves to a concrete connection or upstream response phase.
References
- Nginx proxy module documentation
- Nginx core
resolverdirective - Docker networking overview
- Kubernetes DNS for Services and Pods
Related errors
Move laterally when the first symptom points to adjacent network failures.
What does "DNS server unreachable" mean?
A practical DNS server unreachable guide that separates resolver configuration, routing, firewall, UDP/TCP 53, container DNS, and upstream resolver outages.
Read guideHow to debug "temporary failure in name resolution"
A practical Linux DNS troubleshooting guide for temporary failure in name resolution, covering resolver config, systemd-resolved, search domains, containers, Kubernetes DNS, and resolver timeouts.
Read guideHow to fix "502 Bad Gateway" from Nginx
A practical Nginx 502 guide that separates down upstreams, wrong proxy targets, protocol mismatch, early closes, malformed responses, and deploy-time failures.
Read guideWhy "nginx upstream timed out" happens
A practical guide to Nginx upstream timed out errors that separates connect, send, and read timeouts from slow apps, dependency latency, and overloaded upstream workers.
Read guideKeep one representative log line, the failing source and destination, the command output you used, and the verification command after the change. This makes the result reproducible and helps separate temporary recovery from a proven fix.
Browse related error guides