Implementing Wildcard Subdomain Routing with Nginx for Dynamic Virtual Hosts


1 views

When managing multiple subdomains pointing to different directories under a main domain, manually creating Nginx configurations for each subdomain becomes tedious. The ideal solution involves:

  • Automatic routing of *.example.com to corresponding /public_html/* directories
  • Eliminating the need for separate server blocks per subdomain
  • Maintaining clean URL structures without redirects

Here's the complete wildcard configuration that handles dynamic subdomains:

server {
    listen 80;
    server_name ~^(?<subdomain>.+)\.example\.com$;
    
    root /var/www/public_html/$subdomain;
    
    index index.html index.php;
    
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    # PHP handling (adjust as needed)
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    }
    
    # Additional security headers
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";
}

For this to work properly, you'll need:

*.example.com.    IN  A    192.0.2.1

Replace 192.0.2.1 with your actual server IP. This wildcard DNS record ensures all undefined subdomains resolve to your server.

The filesystem should mirror your URL structure:

/var/www/
└── public_html/
    ├── x/          # x.example.com
    │   └── index.html
    ├── y/          # y.example.com
    │   └── index.php
    └── assets/     # Shared resources

For production environments, consider these enhancements:

# Cache control for static assets
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 365d;
    add_header Cache-Control "public";
}

# Block access to hidden files
location ~ /\. {
    deny all;
}

# Custom error pages
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;

After making changes, always validate and reload:

sudo nginx -t
sudo systemctl reload nginx

Create test subdomains instantly by simply making directories:

mkdir -p /var/www/public_html/newsub
echo "Hello from newsub!" > /var/www/public_html/newsub/index.html

When setting up a web server with multiple subdomains, manually configuring each vhost becomes tedious. The ideal solution automatically routes *.example.com requests to corresponding directories under public_html without individual configurations.

Here's the complete wildcard vhost configuration for Nginx:

server {
    listen 80;
    server_name ~^(?<subdomain>[^.]+)\.example\.com$;
    
    root /var/www/public_html/$subdomain;
    
    index index.html index.php;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    # PHP handling (optional)
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
    }
}

For this to work, you need:

  • A wildcard DNS A record pointing *.example.com to your server IP
  • Proper directory permissions (www-data or nginx user must have read access)

The physical directory structure should mirror:

/var/www/public_html/
├── subdomain1/
│   ├── index.html
├── subdomain2/
│   ├── index.php
└── newsub/
    └── assets/

For enhanced functionality:

# Log separation
access_log /var/log/nginx/$subdomain-access.log;
error_log /var/log/nginx/$subdomain-error.log;

# SSL wildcard certificate
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

If subdomains aren't working:

  1. Verify DNS propagation with dig +short x.example.com
  2. Check Nginx syntax: sudo nginx -t
  3. Ensure directory exists and has correct permissions
  4. Review error logs: tail -f /var/log/nginx/error.log

For high-traffic implementations:

# Add to server block
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;