When working with Nginx configurations, many developers expect the $hostname
variable to seamlessly integrate with server_name
directives. However, there's a crucial implementation detail that causes this approach to fail:
# This WON'T work as expected:
server_name static.$hostname;
The $hostname
variable in Nginx is indeed populated from the system's gethostname()
call, but it's designed for logging and conditional evaluation rather than server name resolution. The server_name
directive requires static values during configuration parsing, before request processing begins.
Here are three reliable approaches to achieve dynamic server naming:
1. Using Regular Expression Patterns
server {
listen 80;
server_name ~^static\.(?.+)$;
root /var/www/static;
# Access the captured domain via $domain
access_log /var/log/nginx/static.$domain.access.log;
}
2. Multiple Server Blocks with Includes
# Main config file
include /etc/nginx/sites-available/*.conf;
# Separate file (e.g., static.conf)
server {
listen 80;
server_name static.your-actual-hostname.com;
root /var/www/static;
}
3. Dynamic Configuration Generation
For more complex scenarios, consider generating configurations:
#!/bin/bash
HOSTNAME=$(hostname)
cat > /etc/nginx/conf.d/static.conf <
When implementing dynamic server naming:
- Always test configuration with
nginx -t
- Implement proper error handling for missing hostnames
- Consider using environment variables in Docker/K8s environments
- Document your naming conventions clearly
In containerized environments where hostnames change frequently, understanding these techniques becomes essential for:
- Blue-green deployments
- Multi-tenant architectures
- CI/CD pipeline integration
- Dynamic staging environments
The $hostname
variable in Nginx is designed to return the system's hostname as obtained through the gethostname()
system call. While this works in most cases, there are specific scenarios where it might not behave as expected in server_name directives.
Server_name evaluation occurs during configuration parsing, while $hostname
is evaluated at runtime. This fundamental timing mismatch causes the variable to be ineffective in this context:
# This won't work as expected:
server_name static.$hostname;
Here are three practical approaches to achieve dynamic server_name configuration:
1. Template Configuration with envsubst
# template.conf
server {
listen 80;
server_name static.${HOSTNAME};
...
}
# Deployment script
export HOSTNAME=$(hostname)
envsubst < template.conf > /etc/nginx/conf.d/static.conf
2. Multiple Server Blocks with Hostname Matching
map $host $is_static_domain {
"~^static\." 1;
default 0;
}
server {
listen 80;
server_name ~^static\.(?.+)$;
if ($subdomain != $hostname) {
return 444;
}
root /var/www/static;
...
}
3. Lua Module for Dynamic Resolution
server {
listen 80;
server_name _;
access_by_lua_block {
local hostname = ngx.var.hostname
if not string.find(ngx.var.host, "^static%."..hostname) then
return ngx.exit(444)
end
}
root /var/www/static;
...
}
The template approach (solution 1) is most efficient as it resolves the hostname at configuration time. The regex and Lua approaches introduce minimal runtime overhead but offer more flexibility for dynamic environments.
- DNS must resolve both the base hostname and static.* subdomain
- Certificate management becomes more complex with dynamic hostnames
- Testing requires actual DNS resolution, not just /etc/hosts entries