How to make nginx try_files get html resources in a timely way

sootsnoot asked:

Using nginx 1.8.1 on an Amazon Linux EC2 instance. Using as a reverse proxy to support https for Apache running on a different instance. All is working fine, except for this issue.

I want to serve a static page from nginx in case I want to take the Apache server instance down. So I did this:

    location   / {
        try_files /site-down.html $uri @backend;
    }

So before I shut down the backend server, I create a symbolic link in the nginx server’s root directory to a static html file that looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

  <title>example.com</title>
  <style type="text/css">
  body {
    background-image:url('/images/back-soon-background.jpg');
    font-family: arial,verdana,sans-serif;
    text-align: center;
  }
  #msg {
    background-image: url('/images/back-soon-oval.png');
    background-repeat: no-repeat;
    width: 600px;
    padding-top: 140px;
    padding-left: 50px;
    padding-right: 50px;
    padding-bottom: 150px;
  }
  </style>
</head>

<body>
<div id="msg">
<h1>Sorry, the site is currently unavailable.</h1>
<h2>We expect to be back within 2 hours.</h2>
</div>
</body>
</html>

The problem is that when I do that, the page gets displayed immediately as just the text content of the div, without the images specified by the <style> in the <head> section. Using Chrome developer tools Network tab, I can see requests for the image urls going out, and getting 200 status codes. But if I click on those requests, there is no preview available, and the body length is too short. Reloading the page doesn’t help right away. But if I let it sit there for a while, eventually the correct output with the images appears. If I point my browser directly at /site-down.html, the page displays correctly right away.

Both Chrome 52.0.2743.116 m and Firefox 48.0.2 behave the same way. I’m new to nginx, but I can’t imagine why the first uri in a try_files should behave any differently from going directly to that uri in the case where the file exists. What am I missing?

My answer:


Use the error_page directive to handle the situation when your backend is down. This will also let you return a proper HTTP response code.

For example:

server {
    try_files $uri @backend;

    error_page 500 502 503 504 =503 /site-down.html;

    #....

In this case, we serve static files first, then go to the backend. If the backend returns one of the listed errors, then nginx will serve /site-down.html with a HTTP 503 response.

The benefit of this method is that you don’t have to manually add or remove the site-down.html file. You leave it in place, and nginx will automatically serve it if the backend is actually down.


View the full question and answer on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.