How to Inject Dynamic Docker Environment Variables into Nginx Configuration


4 views

When running Nginx in Docker containers with dynamically linked services, you'll encounter a fundamental limitation: Nginx doesn't natively support environment variable substitution in configuration files. Traditional approaches like $VARIABLE syntax won't work because Nginx configuration isn't processed through a shell environment.

Here are three proven methods to handle this scenario:

Method 1: Using envsubst with Docker Entrypoint

The most robust approach involves template processing during container startup:

# Dockerfile
FROM nginx:latest
COPY nginx.conf.template /etc/nginx/nginx.conf.template
COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
#!/bin/bash
# entrypoint.sh
envsubst '\$APP_HOST_NAME \$APP_HOST_PORT' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
exec nginx -g 'daemon off;'
# nginx.conf.template
upstream gunicorn {
    server ${APP_HOST_NAME}:${APP_HOST_PORT};
}

Method 2: Lua Module for Advanced Scenarios

For more complex cases, consider OpenResty's Lua integration:

http {
    lua_package_path "/path/to/lua/?.lua;;";
    
    init_by_lua_block {
        APP_HOST = os.getenv("APP_HOST_NAME") or "localhost"
        APP_PORT = os.getenv("APP_HOST_PORT") or "5000"
    }
    
    upstream gunicorn {
        server ${{APP_HOST}}:${{APP_PORT}};
    }
}

When implementing these solutions, watch for:

  • Missing envsubst package in your container (install via apt-get install gettext-base)
  • Incorrect variable escaping in templates (use \$VAR to prevent premature expansion)
  • Permission issues with entrypoint scripts (ensure executable flag is set)

For enterprise deployments, consider this enhanced pattern:

#!/bin/bash
# entrypoint.sh

# Validate required variables
required_vars=("APP_HOST_NAME" "APP_HOST_PORT")
for var in "${required_vars[@]}"; do
    if [ -z "${!var}" ]; then
        echo "Error: $var is not set"
        exit 1
    fi
done

# Process all environment variables starting with NGINX_
for var in $(env | grep '^NGINX_' | cut -d= -f1); do
    export "$var"
done

# Generate final config
envsubst "$(printf '${%s} ' $(env | cut -d= -f1))" < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf

exec "$@"

This handles multiple environment variables and includes proper validation, making it suitable for production environments.


When running Nginx in a Docker container that needs to connect to other dynamically linked containers, you'll often need to reference environment variables in your nginx.conf. The standard Nginx configuration doesn't natively support environment variable substitution, which becomes problematic when dealing with Docker's dynamic networking.

The initial attempt using env directive and $ENV{"VAR"} syntax fails because:

nginx: [emerg] unknown directive "env" in /etc/nginx/sites-enabled/default:1

This occurs because Nginx doesn't process environment variables in the same way as shell scripts or other applications.

Here are three proven methods to handle this scenario:

1. Using envsubst with a Template File

This is the most reliable approach for production environments:

# Create a template file
cat > /etc/nginx/templates/default.conf.template << 'EOL'
upstream gunicorn {
    server ${APP_WEB_1_PORT_5000_TCP_ADDR}:5000;
}
EOL

# Use envsubst to generate the final config
envsubst '$APP_WEB_1_PORT_5000_TCP_ADDR' < /etc/nginx/templates/default.conf.template > /etc/nginx/conf.d/default.conf

# Start Nginx
nginx -g "daemon off;"

2. Using Lua with OpenResty

For more complex scenarios, consider OpenResty's Lua integration:

http {
    lua_package_path '/usr/local/lib/lua/?.lua;;';
    
    init_by_lua_block {
        local env = require "resty.env"
        env.init()
    }
    
    server {
        location / {
            set_by_lua $upstream_host 'return os.getenv("APP_WEB_1_PORT_5000_TCP_ADDR")';
            proxy_pass http://$upstream_host:5000;
        }
    }
}

3. Using a Custom Entrypoint Script

A simple bash script can handle the substitution:

#!/bin/bash

# Generate the nginx config
cat > /etc/nginx/conf.d/default.conf <

When implementing this in Docker:

  • Use multi-stage builds to keep the final image small
  • Ensure your entrypoint script has proper error handling
  • Consider using dockerize tool for more complex templating needs
  • Always test your configuration with nginx -t before starting

If you encounter problems:

# Check if environment variables are properly set
docker exec -it your_nginx_container env | grep APP

# Verify the generated config
docker exec -it your_nginx_container cat /etc/nginx/conf.d/default.conf

# Test Nginx configuration
docker exec -it your_nginx_container nginx -t