Nginx Dynamic Configuration: How to Use Variables in Server Blocks and Include Templates


4 views

Many developers coming from programming backgrounds expect Nginx variables to work like typical programming variables, but there are important limitations:

# This works for simple string substitution
set $port 80;

# This WON'T work for complex directives
# set $listen "listen $port;";  # Syntax error

For your specific use case, here's a working approach:

server {
    # Define core variables
    set $root_path /web/sites;
    set $site_type live;
    
    # Domain-specific configuration
    server_name domain.com *.domain.com;
    
    # Dynamic root path construction
    root $root_path/domain.com/$site_type/public_html/current/;
    
    # Other directives using variables
    access_log $root_path/domain.com/$site_type/logs/access.log;
    error_log  $root_path/domain.com/$site_type/logs/error.log;
    
    # PHP handling
    location ~ \.php$ {
        fastcgi_param SITE_TYPE $site_type;
        # ... other FastCGI params
    }
}

For multiple environments, consider this pattern:

# /etc/nginx/site-templates/base.conf
root /web/sites/$domain/$site_type/public_html/current/;
access_log /web/sites/$domain/$site_type/logs/access.log;

# /etc/nginx/conf.d/site1.conf
server {
    set $domain "example.com";
    set $site_type "production";
    include /etc/nginx/site-templates/base.conf;
    
    # site-specific overrides
    listen 443 ssl;
}

Remember that in Nginx:

  • Variables are scoped to the configuration level where they're defined
  • You can't use variables in all directives (like listen)
  • Map blocks often work better than conditionals for complex logic

For truly dynamic configurations, consider:

# Using map for conditional logic
map $host $subdomain {
    "~^(?.+)\.domain\.com$" $sub;
    default "";
}

server {
    # Now $subdomain contains the subdomain or empty string
    root /web/sites/domain.com/$subdomain/public_html/;
}

Remember that Nginx configuration is primarily declarative, not imperative. For complex dynamic needs, you might want to generate configurations programmatically before Nginx loads them.


Many developers attempt to use Nginx variables in ways similar to programming languages, but there are important limitations to understand. The set directive does work in Nginx configuration, but its usage scope is more restricted than you might expect.

# This works for simple variable assignment
set $port 80;
set $domain "example.com";

# But these variables have limited usage contexts
# They CANNOT be used in all configuration directives

The key issue in your configuration attempt is trying to use variables in directives where Nginx doesn't support them. Here's what works and what doesn't:

# Supported uses:
set $my_var "value";
if ($http_user_agent ~* "mobile") {
    set $mobile true;
}

# Unsupported uses:
# server_name $domain;  # Variables not allowed here
# root /path/$domain;   # Variables not allowed in root path

For dynamic site configurations, consider these approaches:

# Approach 1: Use include files with different configs
server {
    include /etc/nginx/sites-available/example.com.conf;
}

# Approach 2: Use map directive for conditional logic
map $http_host $root_path {
    default "/web/sites/default";
    "~^(?[^.]+)\.example\.com" "/web/sites/example.com/$subdomain";
}

Here's how I handle different environments (dev/stage/prod) in my Nginx configs:

# Define environment variable (set in OS or main nginx.conf)
env DEPLOY_ENV;

# Main server block
server {
    listen 80;
    
    # Use lua for more complex logic if needed
    set_by_lua $root_path '
        local env = os.getenv("DEPLOY_ENV") or "dev"
        return "/web/sites/" .. ngx.var.host .. "/" .. env
    ';
    
    root $root_path;
}

For logging, you can use variables in some contexts:

# This works for access_log
access_log /var/log/nginx/${host}-access.log;

# But error_log path cannot contain variables
error_log /var/log/nginx/error.log;
  • Use separate config files for different sites/environments
  • Leverage Nginx's include directive for modularity
  • Consider using configuration management tools (Ansible, Chef) for generation
  • For complex logic, explore Nginx+Lua (OpenResty)