Project: Multi-Domain Virtual Hosts

Introduction

One VPS often hosts multiple sites: marketing static pages on example.com and an API on api.example.com. This project configures two server blocks, separate logs, HTTPS for each, and HTTP→HTTPS redirects.

Prerequisites

Project Layout

DomainRoleBackend
example.comStatic marketing site/var/www/marketing
api.example.comREST API127.0.0.1:8080

Step 1: Deploy Content

bash
sudo mkdir -p /var/www/marketing
sudo rsync -av ./marketing-site/ /var/www/marketing/
sudo chown -R www-data:www-data /var/www/marketing

Start API on localhost

.

Step 2: Marketing Site Config

/etc/nginx/sites-available/marketing:

Step 3: API Site Config

/etc/nginx/sites-available/api:

nginx
server {
    listen 80;
    server_name api.example.com;
 
    access_log /var/log/nginx/api.access.log;
    error_log  /var/log/nginx/api.error.log;
 
    location / {
        proxy_pass http://127.0.0.1:8080;
        include /etc/nginx/proxy_params;
    }
}

Enable both:

bash
sudo ln -sf /etc/nginx/sites-available/marketing /etc/nginx/sites-enabled/
sudo ln -sf /etc/nginx/sites-available/api /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

Test with Host headers:

bash
curl -I -H "Host: example.com" http://127.0.0.1/
curl -I -H "Host: api.example.com" http://127.0.0.1/health

Step 4: TLS for Both

bash
sudo certbot --nginx -d example.com -d www.example.com
sudo certbot --nginx -d api.example.com

Or one cert with all names if preferred:

bash
sudo certbot --nginx -d example.com -d www.example.com -d api.example.com

Verify redirects:

bash
curl -I http://example.com/
curl -I https://api.example.com/

Step 5: Canonical www Redirect (Optional)

After TLS, redirect www to apex:

nginx
server {
    listen 443 ssl http2;
    server_name www.example.com;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    return 301 https://example.com$request_uri;
}

Log Separation Benefits

Tail one site without noise:

bash
sudo tail -f /var/log/nginx/api.access.log
sudo tail -f /var/log/nginx/marketing.access.log

Acceptance Checklist

  • https://example.com serves static site
  • https://api.example.com proxies to JVM/Node
  • Separate access logs receive entries
  • HTTP redirects to HTTPS on both
  • Wrong Host on IP does not leak wrong site (optional default_server hardening)

FAQ

One cert or two?

One SAN cert is simpler to renew; separate certs isolate expiry mistakes.

Third subdomain?

Add third file in sites-available + Certbot -d.

Same API from SPA domain?

Use project 25 single-domain pattern instead—or CORS across subdomains.

IPv6?

Add listen [::]:443 ssl http2; in each SSL server block.