I have the following location configuration as part of a reverse proxy server:

error_page 503 502 @down;
location @down {
  try_files /error/test/$server_name.html /error/test/generic.html;
location /error/ {
  root /usr/share/nginx/html/;

For a server block with server_name of events.example.com, I would expect /usr/share/nginx/html/error/test/events.example.com.html to be served if it exists. Otherwise Nginx should serve /usr/share/nginx/html/error/test/generic.html.

Nginx is always displaying the generic.html page, even when the more specific page exists. I thought that it might be that the variable wasn't being evaluated, so I created a file called $server_name.html in the error directory. The problem still persisted. If I change the try_files line to

index /error/test/$server_name.html

the configuration works as expected.

How can I have Nginx resolve a file based on the $server_name variable and fallback to a generic file if the first file does not exist?

  • What's wrong with the solution you already gave? – Michael Hampton Jul 20 '18 at 0:47
  • 1
    My guess, you should use $host variable instead. $server_name is usually not what people thing it is. – Alexey Ten Jul 20 '18 at 10:17
  • I agree with Alexey Ten. If that location block is within a catch-all server block then you should use $host instead of $server_name because the latter is going to be an empty string. – bcs78 Jul 20 '18 at 10:57
  • The location is being included in every server block. I suppose I could make a catch all, but I don't actually want this to catch everything. I have a production environment which should show maintenance pages (using an almost identical configuration), and the test environment which uses the configuration above. They are both being served from the same nginx reverse proxy – WhiteAbeLincoln Jul 20 '18 at 16:38

Your root statement is not in scope when the try_files statement is encountered. So nginx cannot determine the correct path to the file.

Also, try_files will process the file terms within the same location, so you could combine both locations into a single named location (assuming that location /error/ { ... } is not required elsewhere).

For example:

error_page 503 502 @down;
location @down {
  root /usr/share/nginx/html/;
  try_files /error/test/$server_name.html /error/test/generic.html =404;

Add the =404 so that the second parameter is treated as a file parameter and not a URI parameter. See this document for more.

| improve this answer | |
  • It looks like the out of scope root statement was the issue. I tried placing the error location block above and it didn't change anything, but when I placed the root statement inside the @down location block, the page works as expected. I'm only using the /error/ location in two places, so I don't mind the duplication. – WhiteAbeLincoln Jul 20 '18 at 16:44
  • Ah, that documentation for try_files explains what was happening. Since nginx couldn't find the requested files (because the root statement was out of scope), then it deferred to the last parameter, which was treated as a uri and did an internal redirect. The /error/ location caught the redirect and displayed the page. If I had a code at the end originally this would have been a lot less confusing – WhiteAbeLincoln Jul 20 '18 at 16:48

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.