Velvet Star Monitor

Standout celebrity highlights with iconic style.

general

Why a listen 443 default_server; nginx rule override already configured rule (http rules working normal way)?

Writer Mia Lopez

I have an nginx and different subdomains:

a.mydomain.com
b.mydomain.com
c.mydomain.com

Nginx has 4 rules:

1) rewrite rule:

server { listen 80 server_name gl.udesk.org; root /nowhere; rewrite ^ permanent;
}

2) https rule:

server { listen 443; server_name a.mydomain.com; root /home/a/a/public; ssl on; ssl_certificate conf.d/ssl/a.crt; ssl_certificate_key conf.d/ssl/a.key; ssl_protocols ... ssl_ciphers ... ssl_prefer_server_ciphers on; location ...
}

3) http default rule:

server { listen 80 default_server; return 444;
}

4) https default rule:

server { listen 443 default_server; return 444;
}

So if I start nginx and:

  • if I go in the browser to it redirects to and then it returns an Error 107 (net::ERR_SSL_PROTOCOL_ERROR): SSL protocol error.
  • if I go in the browser to I expect that it returns Error 444 back. But instead it returns the same Error 107 (net::ERR_SSL_PROTOCOL_ERROR): SSL protocol error.
  • and so for all registered by the DNS provider CNAMEs (i.e. a,b,c)
  • all the http-versions (e.g. rule 3 - ) working as expected:
    • redirects to the https:// version,
    • and are returning an Error 444 back as configured.

So why the https rules in nginx are so tricky to configure and how should I configure them properly to get the same behavior as with http version?

Update:

Creating a new certificate and adding:

ssl on;
ssl_certificate conf.d/ssl/default.crt;
ssl_certificate_key conf.d/ssl/default.key;

works now, but I would have a solution without any SSL certificate needed. Just reset all connections for all https (port 443) subdomains except without providing a certificate.

3

3 Answers

Don't mix Port 443 with ssl! Nginx is completely port agnostic. You can offer https through Port 80 too. Modern nginx versions allow

listen 1234 ssl;

and you don't need the ssl on; line then.

But if you want to serve https you need to specify a certificate. Your server enters https when it rewrites the http request into a https request.

You get the PROTOCOL ERROR, as the SSL Handshake is done before anything else. So return 444 isn't reached. And any SSL Handshake will need a ceritificate and a private key, to feed the encryption algorithms with the certificate/private key pair.

The return directive is part of the rewrite module. If you check the documentation, you may see that it works with requests. In HTTPS requests can only be made after the handshake has been finished.

There's a feature request: and a workaround solution is provided.

server { listen 443 ssl; server_name bbb.example.com; ssl_ciphers aNULL; ssl_certificate /path/to/dummy.crt; ssl_certificate_key /path/to/dummy.key; return 444;
}
1

I found answer in Nginx docs:

The SSL connection is established before the browser sends an HTTP request and nginx does not know the name of the requested server. Therefore, it may only offer the default server’s certificate.

Thus, you must configure the default certificate for SSL connections to default_server that will use for request first. After that nginx will search for the best match server_name virtual server and use its config.

Also you may need to set the SSL connection settings for the default_server, even with SNI support, because some SSL settings in matched server config will be ignored. I don't understand how it works yet, but nginx receives to client ssl_certificate from matched server config and ssl_protocols from default_server config.

And now, since Nginx 1.19.4, you can use ssl_reject_handshake directive:

server { listen 443 ssl; ssl_reject_handshake on;
}

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy