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