Many developers try to use variables in Nginx's server_name
directive, only to find it doesn't work as expected. The configuration below is a common attempt:
server {
listen 80;
index index.php index.html;
set $foo "bar.example.com";
server_name $foo;
# This won't work!
}
Nginx needs to know all possible server names during configuration parsing phase, before requests are processed. Since variables are evaluated at request time, they can't be used in server_name
.
Here are practical workarounds depending on your use case:
1. Using Multiple server Blocks
The most straightforward solution is to list all possible server names:
server {
listen 80;
server_name bar.example.com baz.example.com;
# ... other config
}
2. Using Regular Expressions
For dynamic subdomains, use regex patterns:
server {
listen 80;
server_name ~^(?.+)\.example\.com$;
location / {
# Use captured subdomain
set $site_root /sites/$subdomain;
root $site_root;
}
}
3. Using Map Directive
For more complex mappings between domains and variables:
map $http_host $site_root {
default /sites/default;
bar.example.com /sites/bar;
baz.example.com /sites/baz;
}
server {
listen 80;
server_name bar.example.com baz.example.com;
root $site_root;
}
For truly dynamic domains (like SaaS applications), consider:
- Generating Nginx config files programmatically
- Using OpenResty with Lua scripts
- Implementing a custom module
Remember that regex server names and maps have performance implications:
- Place exact matches first in server_name lists
- Order regex patterns from most specific to most general
- Use
server_names_hash_max_size
andserver_names_hash_bucket_size
for large numbers of domains
Many Nginx users encounter a frustrating limitation when trying to use variables in the server_name
directive. The configuration you attempted:
server {
listen 80;
index index.php index.html;
set $foo "bar.example.com";
server_name $foo;
}
Doesn't work because Nginx evaluates the server_name
directive during configuration parsing, before variables are available at runtime.
Nginx needs to determine which server block to use for incoming requests very early in the processing pipeline. Server name matching happens:
- Before request processing begins
- During the configuration loading phase
- When the server name map is built
Here are several approaches to achieve dynamic server name handling:
1. Using Regular Expressions
server {
listen 80;
server_name ~^(www\.)?(?.+)$;
# Use captured group
set $full_domain $domain;
if ($http_host ~* ^www\.(.*)$) {
set $full_domain $1;
}
# Now use $full_domain in other directives
root /var/www/$full_domain;
}
2. Multiple Server Blocks with Includes
# main.conf
server {
listen 80;
include /etc/nginx/conf.d/sites/*.conf;
}
# /etc/nginx/conf.d/sites/bar.example.com.conf
server_name bar.example.com;
root /var/www/bar;
# other directives...
3. Using map Directive for Dynamic Routing
map $http_host $backend {
default default_backend;
"~*.example.com" $http_host;
}
server {
listen 80;
server_name .example.com;
location / {
proxy_pass http://$backend;
}
}
For cases requiring true dynamic hostnames, consider:
server {
listen 80 default_server;
# Extract host without port
set $host_without_port $host;
if ($host ~* ^([^:]+)) {
set $host_without_port $1;
}
# Use in rewrites or other directives
if ($host_without_port ~* ^(.+)\.example\.com$) {
set $customer $1;
rewrite ^ /$customer$uri;
}
location / {
# Process based on $customer variable
}
}
Remember that regular expressions in server_name are evaluated in order:
- Exact names first (most efficient)
- Wildcard names starting with *
- Wildcard names ending with *
- Regular expressions (least efficient)
For large configurations, prefer exact matches or wildcards over regex when possible.