When deploying Nginx in containerized environments like Docker or virtual machines, hardcoding DNS resolver addresses becomes problematic. The network configuration often changes between environments, making static IPs for resolvers unreliable. The traditional approach:
resolver 8.8.8.8 8.8.4.4;
fails when these public DNS servers aren't accessible or when internal DNS resolution is required.
In Linux systems, /etc/resolv.conf
contains the current DNS configuration. We can parse this file to dynamically set Nginx's resolver directive. Here's a solution using a shell script:
#!/bin/sh
# Extract nameservers from resolv.conf
RESOLVERS=$(grep -E '^nameserver' /etc/resolv.conf | awk '{print $2}' | tr '\n' ' ')
# Generate nginx config snippet
echo "resolver $RESOLVERS valid=30s;" > /etc/nginx/conf.d/resolvers.conf
# Reload nginx
nginx -s reload
For Docker containers, we need to handle the special case of the default resolver (127.0.0.11):
#!/bin/sh
if [ -f /etc/resolv.conf ]; then
if grep -q '127.0.0.11' /etc/resolv.conf; then
# Docker's internal resolver
RESOLVERS="127.0.0.11"
else
RESOLVERS=$(grep -E '^nameserver' /etc/resolv.conf | awk '{print $2}' | tr '\n' ' ')
fi
cat > /etc/nginx/conf.d/resolvers.conf <
In Kubernetes environments, CoreDNS creates more complex resolv.conf files. This enhanced version handles multiple search domains:
#!/bin/sh
RESOLVERS=$(awk '/^nameserver/ {print $2}' /etc/resolv.conf | xargs)
SEARCH=$(awk '/^search/ {print $2}' /etc/resolv.conf)
cat > /etc/nginx/conf.d/resolvers.conf <
For production containers, combine this with your entrypoint:
#!/bin/sh
# Generate resolver config
grep -E '^nameserver' /etc/resolv.conf | awk '{print $2}' | xargs echo resolver > /etc/nginx/conf.d/resolvers.conf
# Start nginx
exec nginx -g "daemon off;"
Verify the dynamic resolver works with this location block:
location /testdns {
set $backend "example.com";
proxy_pass http://$backend;
include /etc/nginx/conf.d/resolvers.conf;
}
Check logs with docker logs [container]
or journalctl -u nginx
to confirm DNS resolution works as expected.
When working with Nginx in containerized environments like Docker or virtual machines, DNS resolution becomes particularly important. The traditional approach of hardcoding DNS resolver addresses in Nginx configurations presents several challenges:
# Static configuration example (problematic in dynamic environments)
resolver 8.8.8.8 8.8.4.4 valid=300s;
The main issues with static resolver configuration include:
- DNS servers might change between environment deployments
- Container networking often relies on host resolv.conf
- DNS caching behavior needs careful consideration
There are several approaches to make Nginx resolver configuration more dynamic:
Option 1: Using envsubst for Template Processing
# Dockerfile example
FROM nginx:alpine
RUN apk add --no-cache gettext
COPY nginx.conf.template /etc/nginx/nginx.conf.template
CMD ["/bin/sh", "-c", "envsubst '${RESOLVER}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && nginx -g 'daemon off;'"]
The template file would contain:
resolver ${RESOLVER} valid=30s;
Option 2: Shell Script to Extract Nameservers
For more sophisticated parsing of resolv.conf:
#!/bin/sh
# Extract nameservers from resolv.conf
NAMESERVERS=$(grep nameserver /etc/resolv.conf | awk '{print $2}' | tr '\n' ' ')
sed -i "s/resolver .*/resolver $NAMESERVERS;/" /etc/nginx/nginx.conf
exec nginx -g 'daemon off;'
When implementing dynamic DNS resolution in Nginx:
- Always set an appropriate TTL (valid= parameter)
- Consider IPv6 compatibility if needed
- Handle cases where /etc/resolv.conf might be empty
- Log DNS resolution failures for debugging
# Recommended configuration with fail-safe
resolver $(awk '/nameserver/{print $2}' /etc/resolv.conf | xargs) valid=30s ipv6=off;
Dynamic DNS resolution introduces some tradeoffs:
Approach | Pros | Cons |
---|---|---|
Static IPs | Predictable | Inflexible |
envsubst | Simple | Requires container restart |
Runtime parsing | Most flexible | More complex setup |