30

I have a number of vhosts, and I'd like to "turn off" the default vhost, either by blank page, error page, or generally whatever is the most efficient use of Nginx's resources, whilst only allowing other vhosts to be access via pre-defined domains.

DanH
  • 827
  • 2
  • 9
  • 26

6 Answers6

54

Define a default_server that returns an HTTP 444 code:

server {
    listen      80 default_server;
    server_name _;
    return      444;
}

(Returning a 4xx error code means requests can be interpreted by a client as an unsuccessful request, rather an HTTP 200 Blank Page But Totally Worked Trust Me.)

For port 443 / SSL requests, you can use ssl_reject_handshake on

Ayub
  • 133
  • 7
Rob Howard
  • 656
  • 6
  • 4
  • 3
    444 is a [non-standard nginx](http://nginx.org/en/docs/http/request_processing.html) specific code: _"a special nginx’s non-standard code 444 is returned that closes the connection"_ – bzeaman Apr 13 '16 at 09:39
  • 4
    This does not work for https. A simple listen 443 default_server won't work either as the ssl handshake happens first of all and nginx will error before returning 444. One solution I have yet to try but should work is to create a self signed certificate for the default https server and optinally redirect to http to avoid any browser errors. – Simon Bengtsson Jul 21 '16 at 14:22
  • 3
    The nginx ticket to provide a nice way to refuse SSL connections is [here](https://trac.nginx.org/nginx/ticket/195). They also provide a [workaround](https://trac.nginx.org/nginx/ticket/195#comment:6), setting `ssl_ciphers aNULL;`. – nh2 Jun 27 '18 at 17:26
  • 2
    Note the workaround I mentioned 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_name`s for port 443 that you _do_ want to let through). See https://trac.nginx.org/nginx/ticket/195#comment:11 for details. – nh2 Jun 27 '18 at 22:48
  • 2
    I am not editing this in because it will only work in the recent `1.19.4` release, but [`ssl_reject_handshake`](https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_reject_handshake) is now available to provide better handling of the https case. – anx Nov 16 '20 at 14:21
4

Just define default vhost that will point to directory with blank index.html file.

server {
    listen       80 default_server;
    server_name  _ ;
    root /var/www/placeholder ; 
    index index.html;
}

and place blank index in /var/www/placeholder

wojciechz
  • 538
  • 3
  • 11
1

This is what worked for me for both HTTP and HTTPS on Debian 10 (buster) running nginx 1.18.0.

Note: I always append include /etc/nginx/sites-enabled/*; to the http section of /etc/nginx/nginx.conf and manage vhosts using /etc/nginx/sites-available and /etc/nginx/sites-enabled` folders.

Step 1: create self-signed placeholder cert

$ mkdir -p /usr/local/etc/ssl

$ cd /usr/local/etc/ssl

$ openssl req -new -x509 -days 1 -nodes -out default-cert.pem -keyout default-key.pem
Generating a RSA private key
.+++++
.........................+++++
writing new private key to 'default-key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:

Step 2: create default vhost

cat << EOF > /etc/nginx/sites-available/default
server {
    listen 80 default_server;
    listen 443 default_server ssl;

    return 444;

    ssl_ciphers aNULL;
    ssl_certificate /usr/local/etc/ssl/default-cert.pem;
    ssl_certificate_key /usr/local/etc/ssl/default-key.pem;
}
EOF

Step 3: enable default vhost

cd /etc/nginx/sites-enabled
ln -s ../sites-available/default default

Step 4: restart nginx

enter image description here

enter image description here

sunknudsen
  • 701
  • 3
  • 14
  • 28
  • Why are you manually creating a new cert? Was always having a dummy certificate already configured not the point of the `ssl-cert` package in debian&ubuntu? – anx Nov 16 '20 at 14:17
  • @anx I didn't know about that... what cert (and path) do you recommend using? – sunknudsen Nov 16 '20 at 14:20
  • On my machine (Ubuntu 20.04), I'm able to `include snippets/snakeoil.conf`, which points to the `/etc/ssl/certs/ssl-cert-snakeoil.pem` and `/etc/ssl/private/ssl-cert-snakeoil.key` the ssl-cert package generates. – theY4Kman Sep 18 '21 at 19:07
1

why not just deny all

server {
    listen       80 default_server;
    server_name  _;

    location / {
        deny    all;
    }
}
Joel Ma
  • 11
  • 1
1

I learn this form asp.net core document

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-3.1#configure-nginx

server {
    listen   80 default_server;
    # listen [::]:80 default_server deferred;
    return   444;
}

You can find it in nginx document too

https://nginx.org/en/docs/http/request_processing.html

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

Here, the server name is set to an empty string that will match requests without the “Host” header field, and a special nginx’s non-standard code 444 is returned that closes the connection.

ws_
  • 111
  • 2
0

In newer versions you can simply do this:

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

Taken trom http://nginx.org/en/docs/http/request_processing.html

andyhasit
  • 173
  • 1
  • 7