0

I am using a docker stack with nginx and certbot. My domain is hosted on google domains.

I want a domain to be accessible via example.tld only:

  • redirect all http to https
  • redirect www to non-www

This is my nginx config:

server {
    listen      80;
    listen      [::]:80;
    access_log  off;
    error_log   off;
    server_name example.tld www.example.tld;
    return      301 https://example.tld$request_uri;
}

server {
    listen      443 ssl http2;
    listen      [::]:443 ssl http2;
    access_log  off;
    error_log   off;
    server_name www.example.tld;
    return      301 https://example.tld$request_uri;
}

server {
    listen      443 ssl http2;
    listen      [::]:443 ssl http2;
    server_name example.tld;

    root        /var/www/example.tld;

    index       index.html index.htm index.php;

    location / {
        try_files $uri $uri/ /index.php?/$request_uri;
    }

    location ~* ^/(assets|files|robots\.txt) { }

    location ~ \.php$ {
        include fastcgi-php.conf;
        fastcgi_pass phpfpm:9000;
    }

    location ~ /\.ht {
        deny all;
    }

    ssl_certificate     /etc/letsencrypt/live/example.tld/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.tld/privkey.pem;
    include             /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam         /etc/letsencrypt/ssl-dhparams.pem;
    add_header          Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

I created the certificate successfully with

certbot certonly --preferred-challenges=dns --cert-name example.tld -d example.tld,www.example.tld

When I open the www urls Safari tells me Safari can't open the page "http(s)://www.example.tld" because Safari can't establish a secure connection to the server "www.example.tld"

But what is working is:

curl -iL http://www.example.tld/ 
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Sat, 11 Jun 2022 11:17:05 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
Location: https://example.tld/
X-Frame-Options: SAMEORIGIN

HTTP/2 200 

What is not working:

curl -iL https://example.tld/
curl: (60) SSL: no alternative certificate subject name matches target host name 'www.example.tld'

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

A / AAA records for both example.tld and www.example.tld are set.

PhilHarmonie
  • 143
  • 2
  • 7
  • 1
    **ALL** SSL vhosts need a certificate. Those that redirect to non-www domains need certificates too. Nginx should complain on your config that you have ssl-enabled vhost where you did not configured any certificates. Also notice you need *valid* certificates on them. – Nikita Kipriyanov Jun 11 '22 at 11:37
  • Adding the certificate to the other vhosts resolved the issue. Do you want to post it in an answer so that I can accept it? Thank you, though! – PhilHarmonie Jun 11 '22 at 11:40

1 Answers1

1

This is wrong and it shouldn't work. Nginx should complain into error log that the configuration of this virtual host is incomplete:

server {
    listen      443 ssl http2;
    listen      [::]:443 ssl http2;
    access_log  off;
    error_log   off;
    server_name www.example.tld;
    return      301 https://example.tld$request_uri;
}

Any SSL virtual host needs to have a certificate. Even if all it does is redirect somewhere. Because it will only issue redirect after it has established a secure connection.

server {
    listen      443 ssl http2;
    listen      [::]:443 ssl http2;
    access_log  off;
    error_log   off;
    server_name www.example.tld;
    return      301 https://example.tld$request_uri;

    ssl_certificate     /etc/letsencrypt/live/example.tld/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.tld/privkey.pem;
    include             /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam         /etc/letsencrypt/ssl-dhparams.pem;
    add_header          Strict-Transport-Security "max-age=31536000 includeSubDomains" always;
}

Something like this. But the certificate should also be valid; you can create a cert which has both example.tld and www.example.tld as valid names (by putting them both into subjectAlternativeName field), Let's Encrypt does this when you create certificate in one shot and specify several domains into it:

certbot --nginx -d example.tld -d www.example.tld
Nikita Kipriyanov
  • 10,947
  • 2
  • 24
  • 45