Home > Mobile >  Nginx display custom error page if folder does not exist
Nginx display custom error page if folder does not exist

Time:02-23

I would like to display a custom error page if there is a folder missing.

My directory structure is the following:

data
   defaults
      error.html
      nothosted.html
   example.com
      misc
         error.html
   example.net
   ...

So when someone accesses example.de whose folder does not exist the defaults/nothosted.html gets displayed. But if the folder exists my @error location should be used.

Currently this is my configuration which does not work.

    server_name ~^(\*\.)?(?<subdomain>[a-z\d][a-z\d-]*[a-z\d]\.)(?<domain>. ) $;

    location / {
        root /data/$subdomain$domain;
        try_files $uri $uri/ @nothosted;
        index index.html index.htm index.php;
    }

    location @nothosted {
        root      /data;

        set $link /$subdomain$domain;

        if (!-d $link) {
           set $link /defaults/nothosted.html;
        }

        try_files  $link @error;
    }

    error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 @error;
    location @error {
        internal;
        ssi         on;
        auth_basic  off;
        root        /data;
        try_files   /$subdomain$domain/misc/error.html /$domain/misc/error.html /defaults/error.html =404;
    }

The error i get in the nginx log is the following:

*1 directory index of "/data/" is forbidden

The error i get trying to connect to a domain whose folder does not exist is a "403 forbidden" from the @error location.

The permissions should be right (the whole /data/ folder is owned by the nginx user)

EDIT: When using the following nothosted location the correct link gets displayed on the webpage once accessed. So the problem has to be the try_files function.

    location @nothosted {
        root      /data;

        set $link /$subdomain$domain;

        if (!-d $document_root/$subdomain$domain) {
           set $link /defaults/nothosted.html;
        }

        return 200 $link;
        add_header Content-Type text/plain;
    }

CodePudding user response:

This one can't be solved the way you are trying to solve it. This is some kind of a preliminary answer, I will add an explanation later. You can try the following instead:

    if (!-d /data/$subdomain$domain) {
        rewrite ^ /defaults/nothosted.html;
    }

    location / {
        root /data/$subdomain$domain;
        try_files $uri $uri/ =404;
        index index.html index.htm index.php;
    }

    location = /defaults/nothosted.html {
        internal;
        root      /data;
    }

    error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 @error;
    location @error {
        internal;
        ssi         on;
        auth_basic  off;
        root        /data;
        try_files   /$subdomain$domain/misc/error.html /$domain/misc/error.html /defaults/error.html =404;
    }

This solution has a drawback - the /defaults/nothosted.html URI won't work for any of the hosted sites. If you find it unacceptable, you can use some kind of unique random string instead of nothosted one (and rename that nothosted.html file accordingly).

  • Related