I've recently set up a VPS with a couple of websites running on it (all using different domains) using nginx to proxy requests to the correct application.

I've a valid SSL certificate for one of these domains, so I set up a http->https direct for this:

server {
  listen         80;
  server_name    example.com www.example.com;
  return         301 https://$server_name$request_uri;

server {
  listen        443 ssl;
  server_name   example.com www.example.com;

  ssl_certificate ..... (etc)

For the other domains, I only listen at port 80 and obviously do not set the SSL certificates. Although all domains are accessible, and the HTTPS redirection works as expected for the main domain, I noticed that when I load one of the other domains (without SSL certificate) over HTTPS, nginx is serving the wrong website, instead of... not accepting the connection at all, I would expect?

I tried adding a default config before loading the sites-available:

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

Which gives me the expected behaviour except for the fact that my main domain is not available over HTTPS anymore (although the HTTP->HTTPS redirection is still functional).

This is probably something stupid and/or me not correctly understanding the way nginx handles configuration, but I've no idea where the problem lies exactly. Help?

1 Answer 1


That's the expected behaviour.

You are using vhosts on a single IP address where you both listen on HTTP and HTTPs. So the server block handling SSL is acting as the default one for everything going to this IP port 443.

You won't be able to refuse the SSL handshake but after it has been completed you can forbid further HTTP requests not targetting a particular domain by adding a separate catch-all server block returning nginx special 444 code.

The generic solution is to have one unique IP for the domain that should support both HTTP and HTTPS and handle all other HTTP vhost on an other IP.

  • As mentioned, adding a default block that returns the 444 code also catches the request to the domain that should accept the HTTPS connection (as if nginx ignores the explicit definition with server_name later on). I understand that having separate IPs would be a better solution, but as far as I know, the required behaviour should be possible with a shared IP.
    – tkers
    Dec 2, 2014 at 15:31
  • @Lapixx No it doesn't. You miss the default_server directive in your default server block. Also, the default server block should include ssl certificate and key and the domain-specific server block should not carry it nor using the ssl keyword in the listen directive : only listen 443;. Dec 2, 2014 at 16:03
  • Aah, right. For whatever reason I was under the impression that the requested hostname is sent before the SSL handshake, but now it makes sense. Working correctly (as much as possible on a shared IP) now, thanks!
    – tkers
    Dec 3, 2014 at 11:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .