Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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.

share|improve this question
add comment

2 Answers

up vote 1 down vote accepted

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;
        # ...
    }
}
share|improve this answer
add comment

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.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.