When working on multiple local development projects, creating individual Nginx configurations for each test domain becomes tedious. Each new site typically requires:
1. Creating a new config file in /etc/nginx/sites-available
2. Creating a symbolic link in /etc/nginx/sites-enabled
3. Reloading or restarting Nginx
Nginx provides several built-in variables that can be used for dynamic configuration. The most relevant for our case is $host
, which contains the domain name from the request.
Here's the minimal configuration that solves our problem:
server {
listen 80;
server_name ~^(?.+)\.loc$;
root /www/$subdomain;
index index.html index.htm index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP processing if needed
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
}
}
For more complex setups, consider these enhancements:
1. Fallback Directory:
set $site_root /www/$host;
if (!-d $site_root) {
set $site_root /www/default;
}
root $site_root;
2. HTTPS Support:
server {
listen 443 ssl;
server_name ~^(?.+)\.loc$;
ssl_certificate /etc/ssl/certs/localhost.crt;
ssl_certificate_key /etc/ssl/private/localhost.key;
root /www/$subdomain;
# ... rest of configuration
}
Permission Problems:
sudo chown -R $USER:$USER /www
sudo chmod -R 755 /www
Cache Issues:
Add this to prevent browser caching during development:
add_header Last-Modified $date_gmt;
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
if_modified_since off;
expires off;
etag off;
For more complex domain patterns, you can use regex captures:
server {
listen 80;
server_name ~^dev-(?[a-z0-9-]+)\.loc$;
root /www/projects/$project/public;
# ... rest of configuration
}
This would map dev-myapp.loc
to /www/projects/myapp/public
.
For true efficiency, combine this with automatic DNS resolution. Add this to your /etc/hosts
:
127.0.0.1 mysite.loc
127.0.0.1 myothersite.loc
127.0.0.1 something.loc
127.0.0.1 *.loc
Or use dnsmasq
for wildcard DNS resolution.
When working with multiple local development sites, creating individual Nginx configurations for each domain quickly becomes tedious. The traditional approach requires:
# Traditional approach (time-consuming)
/etc/nginx/sites-available/mysite.loc
/etc/nginx/sites-available/myothersite.loc
/etc/nginx/sites-available/something.loc
Nginx provides a simple yet powerful solution through its built-in variables. The $host
variable contains the domain name from the HTTP request header, which we can leverage for dynamic root directory selection:
server {
listen 80;
server_name ~^(?.+)\.loc$;
root /www/$subdomain;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
For more complex setups, consider these enhancements:
# With fallback to default directory
map $host $root_path {
default /www/default;
"~^(?.+)\.loc$" /www/$domain;
}
server {
listen 80;
server_name ~.loc$;
root $root_path;
# Enable directory listing for development
autoindex on;
# PHP-FPM support
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
}
}
Here's a complete working example with error handling:
server {
listen 80;
server_name ~^(?.+)\.loc$;
root /www/$devsite/public;
access_log /var/log/nginx/$devsite-access.log;
error_log /var/log/nginx/$devsite-error.log;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ /\.ht {
deny all;
}
}
While this approach is convenient for development, consider these performance optimizations:
- Enable Nginx cache for static assets
- Disable access logs for development environments
- Implement proper gzip compression
When using this pattern:
# Restrict directory traversal
location ~ \. {
deny all;
return 444;
}
# Prevent access to hidden files
location ~ /\. {
deny all;
}