0

I have an odd problem with nginx subdomains. First, my configuration:

server {
    listen              443 ssl;
    server_name         secure.example.com;
    ssl_certificate     example.crt;
    ssl_certificate_key example.key;
    keepalive_timeout   70;

    location / {
        fastcgi_pass    127.0.0.1:8000;
        ...
    }
}

server {
    listen              80;
    server_name         example.com www.example.com;

    location / {
        fastcgi_pass    127.0.0.1:8000;
        ...
    }
}

The idea being that I have a secure domain, secure.example.com and a normal domain, example.com. In practice, I can go to https://example.com and http://secure.example.com. I worked around the second issue with an intermediary server:

server {
    listen              80;
    server_name         secure.example.com;
    rewrite     ^(.*)  https://secure.example.com$1 permanent;
}

But this is not an optimal solution and I'd have to create another one to redirect https on the tld to the subdomain. I feel like I must be doing something wrong if I need multiple servers like that. Why does https://example.com work when there is no server listening on 443 there? Shouldn't it just fail to connect? I'm rather confused.

user8585
  • 117
  • 1
  • 5

2 Answers2

1

Why does https://example.com work when there is no server listening on 443 there? Shouldn't it just fail to connect?

The server_name (or more precisely the HTTP/1.1 Host header) is evaluated after a connection on 80/tcp (HTTP) or 443/tcp (HTTPS) has been established. This means that if secure.example.com and example.com have the same A resource record (they point to the same IP address), there is no way to tell which virtual host the client wants to see before the connection has been established and the HTTP/1.1 Host header has been sent.

Even more precisely TCP/IP works with IP addresses (the IP part) and ports (the TCP part). So if you bind a process (e. g. nginx) to a certain IP address and port, it will always answer on this socket and TCP/IP does not know anything about HTTP/1.1 and its Host header.

If you want to streamline your nginx configuration you could write the following:

server {
    listen              443 ssl;
    listen              80;

    server_name         secure.example.com;
    ssl_certificate     example.crt;
    ssl_certificate_key example.key;
    keepalive_timeout   70;

    if ($scheme = http) {
        rewrite  ^(.+)$  https://example.com$1  redirect;            
    }

    location / {
        fastcgi_pass    127.0.0.1:8000;
        # ...
    }
}

server {
    listen              80;
    server_name         example.com www.example.com;

    location / {
        fastcgi_pass    127.0.0.1:8000;
        # ...
    }
}
joschi
  • 21,387
  • 3
  • 47
  • 50
0

Have a look at Nginx server_name documentation. It says that without any match in your virtual host list, nginx will use the first server {} block with a matching listen directive.

If you want to force users to use secure.example.com host with https, you could have the same kind of workaround you did for the opposite case.

clement
  • 131
  • 3