I'm configuring nginx's handling of some error pages and other "default" media files (such as favicon.ico and robots.txt) at the moment and I ran into a minor problem getting things to work the way I want for certain error pages.
Basically, what I'm trying to do is serve certain files for a server under the root for that server, e.g. /var/www/someserver.com/robots.txt. If that file does not exist, I want nginx to go to the "default", i.e. /var/www/default/robots.txt. This is the basic gist of how I have that (successfully) configured:
server {
...
root /var/www/someserver.com;
location ~* ^/(robots\.txt)$ {
error_page 404 = @default;
}
location @default {
root /var/www/default;
}
}
That works great.
I'm trying to do the same for error pages, and I'm not able to make that happen though:
server {
...
root /var/www/someserver.com;
error_page 404 /404.html;
location ~* ^/(404\.html)$ {
error_page 404 = @default;
}
location @default {
root /var/www/default;
}
}
Note that this "works" in the sense that if you visit someserver.com/404.html, it will first try to load /var/www/someserver.com/404.html and then fall back to /var/www/default/404.html if that's not found. However, if you visit someserver.com/blahblah, it only shows the 404 page if it's set in /var/www/someserver.com/. It does not fall back to the default directory if that file doesn't exist.
Anyhow, you can probably what I was trying to accomplish (that's why I included the first working example).
Any ideas?
Edit:
Based on Martin F's answer, this is what I ended up putting together:
# Doesn't work when error page is returned on a POST request
server {
...
root /var/www/someserver.com;
error_page 404 = @notfound;
error_page 500 502 504 = @server_error;
error_page 503 = @maintenance;
location @notfound {
try_files /404.html /../default/404.html =404;
}
location @server_error {
try_files /500.html /../default/500.html =500;
}
location @maintenance {
try_files /503.html /../default/503.html =503;
}
}
This works awesome. The actual block of error_pages and locations above is in a server_defaults.conf file that gets included with every virtual host, which is why I didn't hard code the path into each location and used a relative path for the defaults.
Edit 2:
This approach has a problem. If you POST to a URL that returns an error, the POST request method gets sent with the try_files attempts. This (for me) results in a 405 Not Allowed error, because nginx is essentially trying to POST to e.g. /default/500.html instead of just getting that page.
Edit 3:
I posted a solution that works that's a lot closer to my original idea.