How to Conditionally Include Dynamic Configuration Files in Nginx Virtual Hosts


1 views

When configuring Nginx virtual hosts, we often need to include site-specific configuration files dynamically. A common approach would be using an if statement with -f check, but Nginx's configuration language has important limitations:

# This WON'T work in Nginx:
if (-f /path/www/$host/nginx.conf) {
    include /path/www/$host/nginx.conf;
}

The include directive in Nginx has specific parsing rules. It cannot be used within if blocks or other conditional contexts. The configuration parser evaluates includes during the initial loading phase, before request processing begins.

Here are several working approaches to implement this functionality:

Solution 1: Wildcard Includes

Nginx supports wildcard patterns in include directives. This is the most elegant solution when you want to include all matching files:

server {
    listen 80 default;
    server_name _;
    root /path/www/$host;

    # Include all matching config files
    include /path/www/$host/*.nginx;
    
    location ~ \\.php {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
    }
}

Solution 2: Server-specific Config Files

For more control, you can create a separate config file for each server name:

# Main nginx.conf
http {
    include /etc/nginx/sites-enabled/*.conf;
}

# /etc/nginx/sites-enabled/example.com.conf
server {
    listen 80;
    server_name example.com;
    include /path/www/example.com/nginx.conf;
    ...
}

Solution 3: Using Lua Scripts (Advanced)

For complex conditional logic, you can use the Nginx Lua module:

location / {
    access_by_lua_block {
        local host = ngx.var.host
        local config_path = "/path/www/" .. host .. "/nginx.conf"
        
        local file = io.open(config_path, "r")
        if file then
            file:close()
            ngx.exec("@dynamic_config")
        end
    }
}

location @dynamic_config {
    include /path/www/$host/nginx.conf;
}
  • Nginx doesn't support dynamic variables in include paths during initial configuration parsing
  • Wildcard includes won't work with variables like $host in the path
  • Always test configuration with nginx -t after changes
  • Consider using symlinks or a configuration management tool for complex setups

While wildcard includes are convenient, they can impact performance if:

  • You have hundreds of included files
  • The included files are large
  • The file system is slow (e.g., network storage)

In such cases, consider generating a single optimized configuration file during deployment.


Many developers need to include additional configuration files for specific sites in their Nginx setup, particularly when dealing with multiple virtual hosts that require unique fastcgi_params or other custom settings. The intuitive approach of using an if condition to check file existence doesn't work because:

location ~ \.php {
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    
    # This won't work:
    if (-f /path/www/$host/nginx.conf) {
        include /path/www/$host/nginx.conf;
    }
}

The fundamental issue stems from Nginx's configuration parsing model. The include directive is processed during configuration parsing, while if conditions are evaluated at request time. This temporal mismatch makes the intuitive solution impossible.

Here are three workable approaches to achieve conditional includes:

1. Wildcard Include Pattern

The most elegant solution uses Nginx's built-in wildcard pattern matching:

server {
    listen 80 default;
    server_name _;
    root /path/www/$host;
    
    location ~ \.php {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        
        # Will include matching files if they exist
        include /path/www/$host/*.nginx;
    }
}

2. Multiple Server Blocks

For more complex scenarios, consider separate server blocks:

# Default configuration
server {
    listen 80 default;
    server_name _;
    root /path/www/default;
    include /path/www/default/nginx/*.conf;
}

# Site-specific configuration
server {
    listen 80;
    server_name example.com;
    root /path/www/example.com;
    include /path/www/example.com/nginx/*.conf;
}

3. Map Directive for Conditional Logic

For advanced users, the map directive can help implement conditional logic:

map $host $config_file {
    default "";
    example.com "/path/www/example.com/nginx/example.conf";
    test.com "/path/www/test.com/nginx/test.conf";
}

server {
    listen 80 default;
    server_name _;
    root /path/www/$host;
    
    location ~ \.php {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        
        include $config_file;
    }
}
  • Use consistent file naming conventions (e.g., *.nginx or *.conf)
  • Place configuration fragments in a dedicated subdirectory
  • Document which variables are available in included files
  • Test configuration with nginx -t after changes