nginxsingle-page-applicationweb-hostinglets-encryptcertbot

How to handle https with multiple SPA on an nGinx conf?


I'm moving from apache2 to an nginx conf and I'm trying to use certbot (let's encrypt) to handle https on my multiple SPA.

I'm also trying to ease my worflow when I want to add another SPA that's why I'm doing it all in the same file and using some variables (This may be the problem with certbot ?).

Let's say I own domain.fr and I have differents SPA on subdomain1, subdomain2, subdomain3, ... Which sometimes they need some websocket connection (see below)

This is what I currently have but I don't know how to "list" the servernames for certbot to detect them ( when doing sudo certbot --nginx ) in order to create some certificates...

#################################
###   Variables definitions   ###
#################################

# Extract subdomain from 'www.subdomain.domain.fr' OR 'subdomain.domain.fr'
map $host $subdomain {
    default hub;
    ~^www\.(.*)\.domain\.fr$ $1;
    ~^(.*)\.domain\.fr$ $1;
}

# Detect which app to redirect to which web socket port : 
map $subdomain $websocket_port {
    default 3001;

    subdomain1     5551;
    subdomain5     5555;
    subdomain6     5556;
    subdomain7     5557;
    subdomain9     5559;
}

# Static path to builds to serve
map $subdomain $static_path {
    default /var/www/html/hub;

    subdomain1     /var/www/html/subdomain1/path;
    subdomain2     /var/www/html/subdomain2/path;
    subdomain3     /var/www/html/subdomain3/path;
    subdomain4     /var/www/html/subdomain4/path;
    subdomain5     /var/www/html/subdomain5/path;
    subdomain6     /var/www/html/subdomain6/path;
    subdomain7     /var/www/html/subdomain7/path;
    subdomain8     /var/www/html/subdomain8/path;
    subdomain9     /var/www/html/subdomain9/path;
    subdomain10    /var/www/html/subdomain10/path;
}


##########################################
#####   Conf server from variables   #####
##########################################
server {
    listen 80;
    #listen 443 ssl http2; #<-- I want to activate this with certbot !
    server_name $subdomain.domain.fr www.$subdomain.domain.fr;

    # Redirect HTTP --> HTTPS:
    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }

    # Serve static files
    root $static_path;
    index index.html;
    location / {
        # Redirect file query to the index 
        # SPA --> front rooting
        try_files $uri $uri/ /index.html;
    }

    # Redirect socket.io calls to the right pm2 demon
     location ~* \.io {
      proxy_pass http://localhost:$websocket_port;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Host $http_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_cache_bypass $http_upgrade;
      proxy_set_header X-NginX-Proxy false;
      proxy_redirect off;
    }

    # Logs
    error_log /var/log/nginx/${subdomain}_error.log warn;
    access_log /var/log/nginx/${subdomain}_access.log combined;
}

Solution

  • For anyone passing by ... I've discovered wildcard certificates with let's Encrypt. It's "harder" to set up because it uses a DNS-01 challenge but let's encrypt have various plugins to help you with (I worked with ovh)

    It fits my needs like a glove.

    Just use certbot to generate a wildcard certificate :

    sudo certbot certonly --dns-ovh --dns-ovh-credentials /etc/letsencrypt/ovh.ini -d *.domain.fr
    

    Where ovh.ini are your OVH API KEYS

    dns_ovh_endpoint = ovh-<region>
    dns_ovh_application_key = APPLICATION_KEY
    dns_ovh_application_secret = APPLICATION_SECRET
    dns_ovh_consumer_key = CONSUMER_KEY
    

    And here is the config :

    server {
        listen 80; # mandatory for http to https redirect
        listen 443 ssl http2;
        server_name *.domain.fr;
    
        # Redirect www.*.domain.fr to *.domain.fr
        if ($host ~* ^www\.(.*)\.domain\.fr$) {
            return 301 https://$1.domain.fr$request_uri;
        }
    
        # Redirect HTTP --> HTTPS:
        if ($scheme = http) {
            return 301 https://$host$request_uri;
        }
        
    
        # Wildcard certificate (*.domain.fr) 
        ssl_certificate /etc/letsencrypt/live/domain.fr/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain.fr/privkey.pem;
    
        root $static_path;
        index index.html;
        location / {
            try_files $uri $uri/ /index.html;
        }
    }