# Nginx Runtime DNS Resolution ## Problem nginx resolves all `proxy_pass` hostnames at **startup time**. If DNS isn't available when nginx starts (common at boot, especially with systemd-resolved still initializing), it fails with: ``` host not found in upstream "api.deepseek.com" in /etc/nginx/sites-enabled/shopproquote:7 ``` **One bad upstream takes down every site.** All services become unreachable until someone manually restarts nginx. ## Solution: Runtime DNS via variable When `proxy_pass` uses a **variable**, nginx resolves at **request time** instead of startup. Three directives needed: ```nginx location /deepseek/ { resolver 127.0.0.53 valid=30s; # DNS server + cache TTL set $deepseek_upstream api.deepseek.com; # variable holds hostname proxy_pass https://$deepseek_upstream/; # resolves at request time # ... rest of location block unchanged } ``` **Key points:** - `resolver` — use the local DNS stub (`127.0.0.53` on systemd-resolved systems, `8.8.8.8` as fallback). `valid=30s` caches resolved IPs for 30 seconds. - `set $upstream_name` — the variable name is arbitrary but must be unique per location. - `proxy_pass https://$upstream_name/` — the trailing `/` is critical (strips the location prefix from the proxied URI, same behavior as static `proxy_pass`). ## Worked example: ShopProQuote DeepSeek proxy **Before** (static — fails at boot if DNS down): ```nginx location /deepseek/ { proxy_pass https://api.deepseek.com/; proxy_http_version 1.1; proxy_set_header Host api.deepseek.com; proxy_set_header Authorization "Bearer sk-f73...b026"; proxy_set_header X-Real-IP $remote_addr; proxy_ssl_server_name on; proxy_ssl_protocols TLSv1.2 TLSv1.3; proxy_read_timeout 120; } ``` **After** (runtime DNS — safe at boot): ```nginx location /deepseek/ { resolver 127.0.0.53 valid=30s; set $deepseek_upstream api.deepseek.com; proxy_pass https://$deepseek_upstream/; proxy_http_version 1.1; proxy_set_header Host api.deepseek.com; proxy_set_header Authorization "Bearer sk-f73...b026"; proxy_set_header X-Real-IP $remote_addr; proxy_ssl_server_name on; proxy_ssl_protocols TLSv1.2 TLSv1.3; proxy_read_timeout 120; } ``` Test: `nginx -t && systemctl reload nginx` ## When to apply This pattern is needed for **any** `proxy_pass` to an external hostname (not a Tailscale IP or localhost). External hostnames that could be unresolvable at boot: - API endpoints (`api.deepseek.com`, `api.openai.com`) - CDN origins - Third-party service backends **NOT needed** for: - Tailscale IPs (`http://100.93.253.36:11434/`) — always resolvable, no DNS involved - `localhost` / `127.0.0.1` - IP literals of any kind ## Diagnosing at runtime ```bash # Is nginx running? systemctl status nginx # What error killed it? journalctl -u nginx --since "5 min ago" --no-pager | grep -i "host not found" # Does DNS work now? nslookup api.deepseek.com # If DNS works now but nginx is down, just restart: systemctl restart nginx ```