How to Configure Nginx as Reverse Proxy for Multiple Domains on Single Server


2 views

When setting up Nginx as a reverse proxy for multiple websites on a single server, the fundamental architecture requires proper server blocks configuration and SSL handling. Your existing configuration shows good practices with HTTP to HTTPS redirection, but needs expansion for multi-domain support.

The key is creating separate server blocks for each domain while maintaining a clean configuration structure. Here's how to extend your existing setup:

# Default HTTP to HTTPS redirect (catch-all for all domains)
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;  # Matches all domains
    return 301 https://$host$request_uri;
}

# Domain-specific configurations
server {
    listen 443 ssl;
    server_name my_domain123.com www.my_domain123.com;
    
    # SSL configuration
    ssl_certificate /etc/letsencrypt/live/my_domain123.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/my_domain123.com/privkey.pem;
    
    location / {
        proxy_pass http://localhost:4000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

server {
    listen 443 ssl;
    server_name another_domain.com www.another_domain.com;
    
    # SSL configuration
    ssl_certificate /etc/letsencrypt/live/another_domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/another_domain.com/privkey.pem;
    
    location / {
        proxy_pass http://localhost:5000;  # Different backend port
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

For maintainability, consider these approaches:

  1. Separate files in sites-available:
    # /etc/nginx/sites-available/my_domain123.com
    server {
        # Domain-specific config
    }
    
    # /etc/nginx/sites-available/another_domain.com
    server {
        # Another domain config
    }
  2. Wildcard SSL certificates when appropriate:
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

For more complex setups, you might need:

# Load balancing across multiple backend servers
upstream backend_servers {
    server 127.0.0.1:4000;
    server 127.0.0.1:4001;
}

server {
    listen 443 ssl;
    server_name my_domain123.com;
    
    location / {
        proxy_pass http://backend_servers;
        proxy_next_upstream error timeout invalid_header;
    }
}
  • SSL Certificate Errors: Ensure each domain has valid certificates
  • Port Conflicts: Verify backend applications listen on different ports
  • Cache Issues: Consider adding cache-control headers in proxy responses

Let's start by examining the existing nginx configuration that handles a single domain:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name my_domain123.com www.my_domain123.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name localhost www.my_domain123.com;
    return 301 https://my_domain123.com$request_uri;
}

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;
    server_name my_domain123.com;

    location / {
        proxy_redirect      http://localhost:4000 https://my_domain123.com;
        # Additional proxy settings...
    }
}

To host multiple websites, we need to create separate server blocks for each domain while maintaining the redirect and SSL functionality. Here's how to expand the configuration:

# HTTP to HTTPS redirect for all domains
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name my_domain123.com www.my_domain123.com 
                domain2.com www.domain2.com
                domain3.net www.domain3.net;
    return 301 https://$host$request_uri;
}

# HTTPS configuration for primary domain
server {
    listen 443 ssl;
    server_name my_domain123.com;
    ssl_certificate /path/to/domain123.crt;
    ssl_certificate_key /path/to/domain123.key;

    location / {
        proxy_pass http://localhost:4000;
        include proxy_params;
    }
}

# HTTPS configuration for second domain
server {
    listen 443 ssl;
    server_name domain2.com www.domain2.com;
    ssl_certificate /path/to/domain2.crt;
    ssl_certificate_key /path/to/domain2.key;

    location / {
        proxy_pass http://localhost:5000;
        include proxy_params;
    }
}

# HTTPS configuration for third domain
server {
    listen 443 ssl;
    server_name domain3.net www.domain3.net;
    ssl_certificate /path/to/domain3.crt;
    ssl_certificate_key /path/to/domain3.key;

    location / {
        proxy_pass http://localhost:6000;
        include proxy_params;
    }
}

For better maintainability with multiple domains, consider these approaches:

# Method 1: Separate files in sites-available
# /etc/nginx/sites-available/domain123.com
# /etc/nginx/sites-available/domain2.com
# Then symlink to sites-enabled

# Method 2: Wildcard SSL certificate
server {
    listen 443 ssl;
    server_name *.mydomains.com;
    ssl_certificate /path/to/wildcard.crt;
    ssl_certificate_key /path/to/wildcard.key;
    
    location / {
        proxy_pass http://localhost:$port;
        include proxy_params;
    }
}

Watch out for these issues when configuring multiple domains:

# 1. Default server conflict
# Always specify one default_server for HTTPS
server {
    listen 443 ssl default_server;
    server_name _;
    return 444; # Close connection
}

# 2. Missing server_name in redirects
# Use $host instead of $server_name for multi-domain setups
return 301 https://$host$request_uri;

# 3. SSL certificate mismatch
# Ensure each domain has its own certificate or a wildcard cert

For more complex setups with load balancing and caching:

upstream backend_domain1 {
    server localhost:4000;
    server backend1.example.com:4000;
}

upstream backend_domain2 {
    server localhost:5000;
    server backend2.example.com:5000;
}

server {
    listen 443 ssl;
    server_name domain1.com;
    
    ssl_certificate /path/to/domain1.crt;
    ssl_certificate_key /path/to/domain1.key;
    
    location / {
        proxy_pass http://backend_domain1;
        proxy_cache my_cache;
        proxy_cache_valid 200 1d;
    }
}