Skip to content

Instantly share code, notes, and snippets.

@ooojustin
Created May 18, 2025 03:29
Show Gist options
  • Save ooojustin/85cb5ac3c073d6ea8e6386bb767afbeb to your computer and use it in GitHub Desktop.
Save ooojustin/85cb5ac3c073d6ea8e6386bb767afbeb to your computer and use it in GitHub Desktop.
Modular Nginx configuration for multiple domains with separate SSL certificates

Modular Nginx Configuration for Multiple Domains

This approach uses Nginx's include directive to avoid repetition while supporting multiple domains with different SSL certificates.

Directory Structure

/etc/nginx/
├── nginx.conf
├── sites-available/
│   ├── common-config.conf
│   ├── beta.mimir.pro.conf
│   └── staging.mimir.pro.conf
└── ssl/
    ├── beta.mimir.pro/
    │   ├── fullchain.pem
    │   └── privkey.pem
    └── staging.mimir.pro/
        ├── fullchain.pem
        └── privkey.pem

Main Configuration Files

1. /etc/nginx/sites-available/common-config.conf

This file contains all the common configuration that will be shared across domains.

# SSL optimization
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;

# HSTS (optional but recommended - uncomment if you're sure about this)
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

# Root directory and index file
root /usr/share/nginx/html;
index index.html;

# Normalize paths to prevent double slashes
merge_slashes on;

# API proxy configuration - match exact location without trailing slash
location = /api {
    # Redirect to ensure consistent URLs
    return 301 $scheme://$host/api/;
}

# API proxy with trailing slash - strip the /api/ prefix
location /api/ {
    # The trailing slash with specific path in proxy_pass removes the matched prefix
    proxy_pass http://backend:8000/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Original-URI $request_uri;
}

# WebSocket proxy configuration
location = /ws {
    # Redirect to ensure consistent URLs
    return 301 $scheme://$host/ws/;
}

location /ws/ {
    proxy_pass http://backend:8000/ws/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    
    # Increase timeout settings for WebSocket connections
    proxy_read_timeout 300s;
    proxy_connect_timeout 75s;
}

# Handle SPA routing
location / {
    try_files $uri $uri/ /index.html;
    
    # Add caching for static assets (optional)
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }
}

# Disable access to .htaccess, .git, etc.
location ~ /\. {
    deny all;
    access_log off;
    log_not_found off;
}

2. /etc/nginx/sites-available/beta.mimir.pro.conf

This file contains only the domain-specific configuration for beta.mimir.pro.

server {
    listen 443 ssl;
    server_name beta.mimir.pro;

    # SSL certificate configuration for beta.mimir.pro
    ssl_certificate /etc/nginx/ssl/beta.mimir.pro/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/beta.mimir.pro/privkey.pem;

    # Include common configuration
    include /etc/nginx/sites-available/common-config.conf;
}

3. /etc/nginx/sites-available/staging.mimir.pro.conf

This file contains only the domain-specific configuration for staging.mimir.pro.

server {
    listen 443 ssl;
    server_name staging.mimir.pro;

    # SSL certificate configuration for staging.mimir.pro
    ssl_certificate /etc/nginx/ssl/staging.mimir.pro/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/staging.mimir.pro/privkey.pem;

    # Include common configuration
    include /etc/nginx/sites-available/common-config.conf;
}

4. HTTP to HTTPS Redirect Configuration

Create a file for HTTP to HTTPS redirects:

# /etc/nginx/sites-available/http-redirect.conf
server {
    listen 80;
    server_name beta.mimir.pro staging.mimir.pro;

    # Redirect all HTTP requests to HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

Implementation Steps

  1. Create the directory structure for your SSL certificates:

    sudo mkdir -p /etc/nginx/ssl/beta.mimir.pro
    sudo mkdir -p /etc/nginx/ssl/staging.mimir.pro
  2. Place your SSL certificates in their respective directories.

  3. Create the configuration files as shown above.

  4. Create symbolic links to enable the sites:

    sudo ln -s /etc/nginx/sites-available/http-redirect.conf /etc/nginx/sites-enabled/
    sudo ln -s /etc/nginx/sites-available/beta.mimir.pro.conf /etc/nginx/sites-enabled/
    sudo ln -s /etc/nginx/sites-available/staging.mimir.pro.conf /etc/nginx/sites-enabled/
  5. Test the configuration:

    sudo nginx -t
  6. Reload Nginx:

    sudo systemctl reload nginx

Adding More Domains

To add more domains in the future, simply:

  1. Create a new domain-specific configuration file
  2. Set the server_name and SSL certificate paths
  3. Include the common configuration
  4. Add the domain to the HTTP redirect server block
  5. Create a symbolic link to enable the site
  6. Test and reload Nginx

This modular approach makes maintenance much easier as you only need to update the common configuration in one place when making changes that apply to all domains.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment