How do I avoid nginx processing a request with an undefined server name using the https protocol.

The following configuration makes this work for normal http requests. It resets the connection for requests with empty host headers which equals to server_namein the nginx configuration:

server {
    listen      80;
    server_name "";
    return      444;

Updated for clarity:

The server does however serve html of the default ssl supporting server block when a request over https is sent with an empty host header. How can this be avoided?

I would like to achieve the exact behaviour as for http requests with an empty host header - no html served, connection reset (return 444).

What would be the proper way to block such https requests and achieve the mentioned behaviour for https connections as well? (I would like to avoid using the proper SSL cert for this as this may just hint spammers at the real server domain.)

Update 13.03.2015

Putting an haproxy in front of nginx with the setting


solved my issue completely.

  • What's an "undefined server" and "undefined https request"?
    – domen
    Apr 15, 2014 at 8:40
  • When you don't request for a specific host like www.abc.com but try to connect to the webserver directly with the ip. Usually scammers and bots do this only. nginx.org/en/docs/http/… Apr 16, 2014 at 18:34
  • Hostname is communicated after communication throught port 443 is established.
    – domen
    Apr 16, 2014 at 19:03
  • but it still slips through as i see requests like https://ip in the logs. Whereas http://ip is caught. Apr 16, 2014 at 22:01

4 Answers 4


I've solved it by generating a fake certificate that doesn't reveal domain name and adding it as a default one on the start of the config:

server {
    listen 443 default;
    server_name     _;

    ssl     on;
    ssl_certificate         /path/to/fake.crt;
    ssl_certificate_key     /path/to/fake.key;

    return 403;

And yes, it requires a nginx with SNI support (check nginx -V).

Follow on: How to create self signed SSL certificate for test purposes

  • is reload enough, or must nginx be restarted?
    – sebelk
    May 7, 2020 at 17:40
  • I don't remember and can't test right now, just do a full restart to be safe if you can afford it.
    – int_ua
    May 7, 2020 at 17:41

Due to the nature of how SSL works, the SSL/TLS handshake is performed before the intended hostname is given to the web server. This means that the default (first) certificate is used when trying to access the site, regardless of the domain name used.

This is true with both Apache and nginx.

From the Apache Wiki:

As a rule, it is impossible to host more than one SSL virtual host on the same IP address and port. This is because Apache needs to know the name of the host in order to choose the correct certificate to setup the encryption layer. But the name of the host being requested is contained only in the HTTP request headers, which are part of the encrypted content. It is therefore not available until after the encryption is already negotiated. This means that the correct certificate cannot be selected, and clients will receive certificate mismatch warnings and be vulnerable to man-in-the-middle attacks.

From the nginx documentation:

With this configuration a browser receives the default server’s certificate, i.e. www.example.com regardless of the requested server name. This is caused by SSL protocol behaviour. The SSL connection is established before the browser sends an HTTP request and nginx does not know the name of the requested server. Therefore, it may only offer the default server’s certificate.

How can you resolve this issue?

The easiest solution is to use separate IP addresses for each site you wish to secure.

If this is not possible, it might be possible to resolve the issue using Server Name Indication (SNI, RFC 6066). This allows a browser to pass the domain name to the server during the handshake.

Both Nginx and Apache support SNI. You can find out more on nginx SNI in the documentation.

It's worth noting that SNI can only be used for domain names, and not IP addresses. You should take extra precaution when configuring your web servers to address this issue, so any request to the IP is handled properly.

Only domain names can be passed in SNI, however some browsers may erroneously pass an IP address of the server as its name if a request includes literal IP address. One should not rely on this.

The Apache Wiki has some more information on implemeting SNI. But even their documentation advises that this solution is not perfect.

Using name-based virtual hosts with SSL adds another layer of complication. Without the SNI extension, it's not generally possible (though a subset of virtual host might work). With SNI, it's necessary to consider the configuration carefully to ensure security is maintained.

With that said, you can see how this configuration isn't as simple as regular virtual hosts. In order to further come up with a solution to your problem, we would need to know more details on your configuration and the expected behavior when an IP only request is sent.

Generally, to 'block' a non configured domain or IP request, you would configure it as the default site and then display an error, redirect, exit, etc.

  • Thanks for your answer David - I understand there is some complexity. Looks to me like SNI is needed to properly handle it, following your explanations. The expected behaviour is: Every https request that is not domain.com shall not be served and the connection resetted (return 444). Exactly as it happens for undefined http requests. I would like to avoid using the proper SSL cert for this as this may just hint spammers at the real server domain. Apr 26, 2014 at 11:17
  • Hmm, my question is still sort of unanswered but as you imho provided the best answer and obviously put in some effort - the bounty shall be yours :) May 2, 2014 at 17:03

If I understand you want to deny HTTP-Requests, which don't contain a Host header, even if these requests are inside a SSL connection (e.g. https-Requests). These are old-style HTTP/1.0 requests, HTTP/1.1 requires a Host header but also most HTTP/1.0 clients already send one. Blocking these clients can be done with:

    if ( $http_host = '' ) {
            return 444;

But this does not help if the client uses a Host header with junk or the IP-address in it. Thus it would better to verify, that the host header contains the expected values (as a bonus this also helps against DNS rebinding attacks), e.g.

    if ( $http_host !~* ^(example\.com|www\.example\.com)$ ) {
            return 444;
  • 2
    Thanks for your answer. This is what I would consider a "workaround". Especially as ifs are evil anyway. Apr 26, 2014 at 15:26

I used the similar method as @int_ua mentioned, but a bit tricky.

I configured my nginx to use RSA and ECDSA as TLS Authentication method, but issued a DSA certificate for the default server.
As there is no available cipher suite, the TLS handshake would fail before serving any page.
I think it would have the same result as what you configured (HAproxy strict-sni) and believe my method would have better performance.

You can view the result of my configuration:

Invalid SNI:
   (You can configure your hosts to this IP address and view the result as well)
Valid SNI: https://cloud.jemmylovejenny.tk/
   The Valid SNI link points to the same IP address as above

I would give my configuration here:

SSL Configuration
( I used a openssl equal ciphers patch so that ciphers is a bit strange... You can remain your configuration as well, but remember that don't contain any DSS ciphers! )

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
    #Key Exchange
    ssl_ecdh_curve X25519:P-256:P-384:P-224:P-521;
    ssl_dhparam /var/SSL/DH-param.pem;
    #Cipher Suites
    ssl_prefer_server_ciphers on;

Default Server Configuration

# General
# Listen
listen 8080 default_server;
listen 8443 ssl spdy http2 default_server;
# Server Name
server_name _;

# SSL Settings
# Certificate
#  DSA
ssl_certificate /var/SSL/certificates/DEFAULT.dsa.crt;
ssl_certificate_key /var/SSL/keys/DEFAULT.dsa.key;

root /var/www/html/nginx/;

The DSA key is generated from OpenSSL and the certificate is issued from my own PKI. You can use this certificate if you want.
( This certificate would never be sent from the nginx server, so everything of this certificate, including keylength and valid period is meaningless )




  • Hi, thanks for the great answer. I've couple of questions. 1. Is there any way to use your method without additional patch? 2. Is it possible to do redirect user with this method? e.g redirect back to http Mar 21, 2020 at 9:42
  • 1
    @ShinebayarG 1.Yes, you can use this method without the equal-cipher patch. 2.It is not possible to redirect users to http, as redirection happens after the TLS handshake, which means only with a valid SSL certificate can you redirect users back to http.
    – Jemmy1228
    Mar 22, 2020 at 10:06
  • @ShinebayarG What's more, if a patch is acceptable, you can use this one github.com/hakasenyang/openssl-patch/blob/master/…
    – Jemmy1228
    Mar 22, 2020 at 10:08

You must log in to answer this question.

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