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

9

5

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 ^ https://a.mydomain.com$request_uri 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:

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 https://a.mydomain.com without providing a certificate.

static

Posted 2013-06-27T00:34:27.463

Reputation: 1 087

2You can't. SSL requires a certificate before the web server knows what domain you want. It has to have a certificate to send, or it can't establish the connection to talk to the client. – Darth Android – 2013-06-27T03:17:24.657

2

@DarthAndroid: The magic is called SNI - http://en.wikipedia.org/wiki/Server_Name_Indication.

– Shi – 2013-07-23T23:51:29.920

@Shi I'm aware of SNI - That allows the webserver to pick which certificate to send, but it still must pick a certificate. nginx isn't smart enough to realize that it doesn't need a certificate for what the user wants to do. – Darth Android – 2013-07-24T14:35:40.670

Answers

3

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: https://trac.nginx.org/nginx/ticket/195 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;
}

VBart

Posted 2013-06-27T00:34:27.463

Reputation: 131

Note this will break non-SNI-capable HTTPS clients (like nginx's own proxy_pass, unless you set proxy_ssl_server_name on;) from reaching any other server_names (so essentially break the legitimate server_names that you do want to let through). See https://trac.nginx.org/nginx/ticket/195#comment:11 for details.

– nh2 – 2018-06-27T22:48:09.483

3

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.

ikrabbe

Posted 2013-06-27T00:34:27.463

Reputation: 181