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