NGINX Configuration: How to Serve Multiple Domains from One Location


2 views

When managing multiple domain variations (like example.com, example.co.uk, example.net) that all point to the same website content, many developers create separate server blocks in their NGINX configuration. This approach works but leads to unnecessary code duplication:

server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/example.com/html;
}

server {
    listen 80;
    server_name example.co.uk www.example.co.uk;
    root /var/www/example.com/html;
}

NGINX allows you to handle all domain variations in a single server block by listing multiple domains in the server_name directive:

server {
    listen 80;
    server_name example.com www.example.com 
                example.co.uk www.example.co.uk
                example.net www.example.net;
    root /var/www/example.com/html;
}

For more complex scenarios, you can use regular expressions or wildcards:

server {
    listen 80;
    server_name ~^(www\.)?example\.(com|co\.uk|net)$;
    root /var/www/example.com/html;
    
    # Additional settings
    index index.html;
    location / {
        try_files $uri $uri/ =404;
    }
}

When using SSL certificates (especially wildcard or multi-domain certificates), this approach becomes even more valuable:

server {
    listen 443 ssl;
    server_name example.com www.example.com
                example.co.uk www.example.co.uk;
                
    ssl_certificate /etc/ssl/certs/wildcard_example.crt;
    ssl_certificate_key /etc/ssl/private/wildcard_example.key;
    
    root /var/www/example.com/html;
}

Using a single server block offers several advantages:

  • Reduced configuration file size
  • Simpler maintenance
  • Faster NGINX startup (fewer blocks to parse)
  • Consistent behavior across all domains

To verify your configuration works for all domains:

sudo nginx -t  # Test configuration
sudo systemctl reload nginx  # Apply changes
curl -I http://example.com
curl -I http://example.co.uk

When managing multiple domain variants (like example.com, example.co.uk, example.net) that all point to identical content, creating separate server blocks for each domain violates the DRY (Don't Repeat Yourself) principle. Not only does this create maintenance overhead, but it also makes your nginx configuration unnecessarily verbose.

Nginx's server_name directive supports multiple domain declarations in a single server block. Here's the optimized configuration:

server {
    listen 80;
    server_name example.com www.example.com 
               example.co.uk www.example.co.uk
               example.net www.example.net
               example.org www.example.org;
    
    root /var/www/example.com/html;
    
    # Additional recommended directives
    index index.html index.php;
    access_log /var/log/nginx/example.access.log;
    error_log /var/log/nginx/example.error.log;
}

For more complex domain patterns, you can use regular expressions:

server {
    listen 80;
    server_name ~^(www\.)?example\.(com|co\.uk|net|org)$;
    
    root /var/www/example.com/html;
}

If using HTTPS with a wildcard or multi-domain certificate:

server {
    listen 443 ssl http2;
    server_name example.com www.example.com 
               example.co.uk www.example.co.uk;
    
    ssl_certificate /etc/ssl/certs/wildcard_example.crt;
    ssl_certificate_key /etc/ssl/private/wildcard_example.key;
    
    root /var/www/example.com/html;
}

While this approach is cleaner, be aware that:

  • Nginx processes server blocks in order - place your catch-all blocks last
  • Extremely long server_name lists may impact performance
  • For 100+ domains, consider using a map directive or separate include files

Here's my production configuration for a SaaS platform serving multiple TLDs:

# Primary domains
server {
    listen 80;
    listen [::]:80;
    server_name app.example.com app.example.net 
               app.example.io app.example.co
               app.example.tech app.example.dev;
    
    root /var/www/app/current/public;
    
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    # PHP-FPM configuration
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    }
}

# Redirect all HTTP to HTTPS
server {
    listen 80;
    server_name ~^(www\.)?example\.(com|net|io|co|tech|dev)$;
    return 301 https://$host$request_uri;
}
  • Missing semicolons at line endings
  • Not including www/non-www variants
  • Forgetting to reload nginx after changes (sudo systemctl reload nginx)
  • DNS not properly configured for all domains