1

I'm creating a "userdir" configuration, where the webserver serves files inside each user's ~/www directory.

I have the following configuration snippet:

server {
    listen 443;
    listen [::]:433;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    server_name ~^(?<user>\w+)\.example\.com$;

    root /var/www/userdir;
    index index.html;
    error_page 404 = @not_found;
    add_header X-User $user;

    location / {
        root /home/$user/www;
        try_files $uri $uri/ =404;
    }

    location @not_found {
        if (-f /home/$user/www/404.html)
        {
            root /home/$user/www;
        }

        try_files /404.html =500;
    }
}

When a non-existing file is requested, the @not_found named location is entered. It first checks whether the user has a custom 404 page, and if (s)he has, it sets the document root to the user's directory before trying to serve 404.html.

However, the result of the configuration block is that if 404.html exists in the user dir, the generic nginx 404 page is returned; if not, /var/www/userdir/404.html is returned.

2 Answers 2

1

Using if within a location block is counter intuitive, as this document illustrates. Also, using error_page with a named location, changes the response code from 404 to 200, which may not be desirable.

You can use your test to set a variable at the top of the server block, which can then be used to set the location of the error page file.

For example:

set $ERROR_ROOT "/var/www/userdir";
if (-f /home/$user/www/404.html) {
    set $ERROR_ROOT "/home/$user/www";
}

error_page 404 /404.html;

location / {
    root /home/$user/www;
    try_files $uri $uri/ =404;
}

location = /404.html {
    root $ERROR_ROOT;
}
3
  • I'm not sure I fully understand why my solution doesn't work, even after reading the article you linked and more. Thank you for providing a working solution. Sep 20, 2018 at 21:04
  • Is there an equal character in the second location ?
    – Stephane
    Sep 11, 2019 at 9:10
  • 1
    @Stephane see this document for the syntax of the location directive. Sep 11, 2019 at 9:14
2

This seems to do the trick:

location / {
    root /home/$user/www;
    try_files $uri $uri/ =404;
    error_page 404 /404.html;
}

You may need to remove the "error_page 404 = @not_found;".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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