I have a testing site with 2 domains and I want to enable SSL for both.
Also, I want to have a default server to display an error page if a client is accessing some page out of those 2 domains.
This is my nginx.conf
:
server {
listen 443 ssl;
server_name a.com;
ssl_certificate a.cert;
ssl_certificate_key a.key;
}
server {
listen 443 ssl;
server_name b.com;
ssl_certificate b.cert;
ssl_certificate_key b.key;
}
server {
listen 443 default_server ssl;
...
}
Problem: The default server must have a valid cert/key pair, even if the client is connecting to a.com
or b.com
.
If I don't specify a cert/key pair on the default ssl server, nginx gives me this error:
no "ssl_certificate" is defined in server listening on SSL port while SSL handshaking
I don't understand the logic here. With SNI enabled, when a client clearly says it's accessing a.com
, which has a standalone server block in nginx.conf
, why does nginx still require the default server to have a cert/key pair? Why does it even bother with the default server?
Best Answer
The certificate is mandatory for the ssl servers, if there was no certificate, what's the point? HTTPS wouldn't work.
You must define the ssl certificate and key, inside or outside the server block. If you define a "default_server", but you are not defining a domain, then it will always display a warning that the domain doesn't match the certificate (unless you are using wildcard certificates or some other specific use cases).
When you define name-based HTTPS servers, you have to keep in mind the following, from the official docs:
As you found out, a self-signed certificate accomplishes this and will allow you to present a webpage or redirect in a default_server in case there was no match for any other of the defined server_name blocks, although it (might, depending on configuration) present a warning.
If your question is why you need to define a default_server, you don't. If you don't specify a default_server block, it will use the first by alphabetical order, if someone reached your server with an unknown domain name (usually won't happen), or present the corresponding server_name.
Update
Extending my answer in response to your comment:
Check my last paragraph above, that's how virtual hosts (or server blocks in nginx terminology) and the default_server work. Nginx will serve the default_server block if you define one in a server block and the server_name doesn't match the request in the other blocks. You can define a server block with a default_server to force a catch-all to that specific block, otherwise, nginx will default to the first server block (either in nginx.conf or in sites-enabled/conf.d if included). Either you define it or nginx will choose the first block for that purpose, but a server block will be the default.
It won't serve it unless someone reaches your server with an undefined server_name, following your example, let's say someone pointed "c.com" to the IP of your nginx, then the default_server will catch that request and present whatever you defined.