Nginx – Redirect all subdomains to main domain with HTTPS without a wildcard cert (nginx)

httpsnginxredirectsubdomainwildcard-subdomain

I have a domain name with a main site and a few vhosts. I want all sites (main and vhosts) to only be accessible through HTTPS (using HSTS), and I want non-existing subdomains to be redirected to the main site.

To summarize what I want:

  • https:/example.com: no redirect (main site)
  • http:/example.com: redirected to https:/example.com
  • https:/vhost.example.com: no redirect (virtual host)
  • http:/vhost.example.com: redirected to https:/vhost.example.com
  • https:/doesntexist.example.com: redirected to https:/example.com
  • http:/doesntexist.example.com: redirected to https:/example.com

I'm very close to this, but the second to last redirection doesn't work. I'm using a certificate from Let's Encrypt, which doesn't offer wildcard certs at the moment, so the certificate is only valid for the main domain and the vhosts (that I've explicitly listed when I created the certificate). Because the certificate is invalid, browsers block the connection.

What would be the best way (if any) to circumvent this problem?

Here's my (simplified) nginx configuration if it helps:

server {
    listen 80;
    server_name _;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 spdy;
    server_name _;
    # SSL settings snipped for brevity. SPDY and HSTS are enabled.
    return 301 https://example.com$request_uri;
}

server {
    listen 443 spdy;
    server_name example.com;
    root /var/www/example.com;
    index index.html index.htm;
}

server {
    listen 443 spdy;
    server_name vhost.example.com;
    root /var/www/vhost.example.com;
    index index.html index.htm;
}

Best Answer

Practically, you can't get around the problem without a wildcard cert. If you can't present a certificate that matches up with the name being requested, you're going to get a connection error -- it's a fundamental part of the protocol.

I suppose, in theory, you could write something that, when it received an SNI header for a name not in the certificate, did a quick certificate issuance from Let's Encrypt, and sent back that newly-minted certificate in the TLS handshake, but... well, it isn't exactly a practical solution, is it?