23

I have a wildcard SSL certificate and several subdomains on the same ip. Now I want my nginx to handle only mentioned server names and drop connection for others so that it'd look like nginx is not running for unlisted server names (not responding, rejecting, dead, not a single byte in response). I do the following

ssl_certificate tls/domain.crt; ssl_certificate_key tls/domain.key; server { listen 1.2.3.4:443 ssl; server_name validname.domain.com; // } server { listen 1.2.3.4:443 ssl; server_name _; // deny all; // return 444; // return 404; //location { // deny all; //} } 

I've tried almost everything in the last server block, but no success. I get either valid response from known virtual server or error code. Please help.

6 Answers 6

7

It doesn't work that way: the SSL handshake happens before HTTP, so the name on the certificate will get evaluated in the browser before you can redirect or do anything else inside the nginx configuration.

1
  • 3
    This is not true: you can do something else at lower level, like dropping connection without any response, as explained in other answers. Commented Mar 19, 2014 at 15:19
24

At this time, the answer to this question can be updated.

For Nginx ≥ 1.19.4: http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_reject_handshake

server { listen 443 ssl default_server; ssl_reject_handshake on; } server { listen 443 ssl; server_name example.com; ssl_certificate example.com.crt; ssl_certificate_key example.com.key; } 

For Nginx < 1.19.4: Using https://git.hakase.app/Hakase/openssl-patch

http { # control options strict_sni on; strict_sni_header on; # fake server block server { server_name localhost; listen 80; listen 443 ssl default_server; # "default_server" is necessary ssl_certificate /root/cert.crt; # Can be any certificate here ssl_certificate_key /root/cert.key; # Can be any certificate here location / { return 444; } } # normal server blocks server { server_name normal_domain.tld; listen 80; listen 443 ssl; ssl_certificate /root/cert.crt; # Your real certificate here ssl_certificate_key /root/cert/cert.key; # Your real certificate here location / { echo "Hello World!"; } } } 

For newbies who is not familiar with applying the patch to Nginx, you can check this: https://stackoverflow.com/questions/64225024/64225025#64225025

0
21

The answer by cjc already correctly pointed out the problem with trying to match host names when SSL is enabled. However, it is possible to do it, like this:

server { ... if ($host !~* ^validname\.domain\.com$ ) { return 444; } ... } 

Note: yes it is true that generally if is evil, but it is safe to use if in this case. (Read the linked page if you need to convince yourself.)

Contrarily to what has been suggested, just adding the following block won't work:

server { listen 80; listen 443 ssl; return 444; } 

because an SSL certificate that matches validname.domain.com won't match some random domain name. I've tried it, and nginx acted like the block was not present at all.

This also won't work:

server { listen 443; server_name _; return 444; } 

because it will make every single HTTPS connection on port 443 fail, even those that should go through. I've tried this one too. wget reported an SSL handshake error.

2
  • This answer is absolutely right. Just for those who doubt you should to add this section to the working server config. So for the topic starter config would be server { listen 443 ssl; server_name validname.domain.com; if ($host !~* ^validname\.domain\.com$ ) { return 444; } } Commented Feb 26, 2020 at 3:05
  • This doesn't work for me, e.g. curl reports "certificate subject name (realhostname) does not match target host name 'someipaddress'" Commented Oct 16, 2020 at 6:51
7

Most answers here are about why it doesn't work, not how to make it work.

Here is how - you need to make such catch-all server a 'default_server' and need to provide paths to cert/key so that it can decrypt incoming ssl request and match the Host header:

server { listen 80 default_server; listen 443 ssl default_server; server_name _; ssl_certificate <path to cert>; ssl_certificate_key <path to key>; return 404; } 

Note the ssl_certificate/ssl_certificate_key there. If they are not specified, nginx still tries to use such default_server and fails as it can't accept ssl connection w/o a cert/key. One can use any cert/key e.g. self-signed. ...

To generate a self-signed certificate:

openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365 

Also see https://serverfault.com/a/841643/87439

4
  • 1
    Have you tried this? How do you create a SSL certificate that matches a server name of "_"? Commented Mar 30, 2017 at 20:52
  • Yes, this solution works for me. I had same exact problem and figured from documentation that nginx needs a cert/key as it doesn't look at TLS SNI. You can use any cert/key, e.g. self-signed. Commented Mar 30, 2017 at 20:59
  • Not working for me, even if the client doesn't verify the certificate. Maybe it worked e.g. prior to TLS 1.2? Commented Oct 16, 2020 at 6:39
  • This still seems to be a nice solution however, as the client gets an invalid response and we don't leak the real hostname. Commented Oct 16, 2020 at 7:22
1

I implemented the above solution today, and it worked swimmingly. All URL's not specified are dropped, now. Placing this server code before the actual virtual server entry was key - all mal-formed URL's now go to this 'default' server.

... server { listen 443; server_name _; return 444; } server { listen 443; server_name [URL] 
1
  • 2
    Nope, this doesn't work for me. Commented Mar 21, 2020 at 6:56
-1

You should be able to handle this by making the server that handles the unlisted items the first server block in your config.

http { ... server { listen 80; listen 443 ssl; return 444; } server { server_name validname.domain.com; ... } } 

All domains not specifically identified will be handled by this server block.

1
  • 3
    It does not work Commented Jul 9, 2018 at 6:50

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.