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?
Comments by @Michael-Hampton provided the answer to the question as I asked it. I suggested about 6 weeks ago that if he posted that information as an answer, I'd mark it accepted. But since he didn't do that, I'm constructing an answer here to accept. Seems a shame to leave this unanswered.
The answer to the question as I asked it is just that the nginx configuration I specified forced all requests to first attempt to serve the static
site-down.html
page. And since the images were specified as urls to the same site, those image requests also got handled by the/
location
directive, so thetry_files
got applied and changed them also to serve thesite-down.html
page.I don't know why the images eventually showed up at all after some reloads and waiting, something must have timed out.
The most direct way to address the problem as I was seeing it was to change the background-image url's into
data
url's with the image content itself embedded inbase64
strings. By doing that, thesite-down.html
page does not generate any additional requests for resources, and it works as I originally intended.But he also noted that what I'm trying to do, when working, gives a 200 status code even though the site is basically down. I explained that the site is intended solely for interactive users, not servers, and this is for short-term intentional outages, not errors like a backend server crash. So I don't see that as a big problem. But the truth is, it's always best to give a meaningful status code. So I think the "right" solution for me is have two different "available" nginx config files, one of which simply hard-codes a 503 response using site-down.html as a custom error page. Then instead of creating/removing a symlink named site-down.html in the root, and relying on try_files to give the desired behavior, I should just change the symlink in the sites-enabled directory to select the right configuration and do a
sudo service nginx reload
to smoothly switch behaviors.The advantage of using try_files is that the behavior switches immediately with one command, while the disadvantage is that the status code indicates the site is working fine even though it isn't. The advantage of switching config files is that it gives meaningful status, while the disadvantage is the extra step of reloading nginx is something that could be forgotten. However, in the end the switch will be done by a script, and the script won't forget to reload the configuration.
try_files tries files in the order you specify. Change the order to something like this
I assume since the page is being served now you have everything else set up ok. Give this a go and comment on the answer if you need further help. Be sure to include logs if applicable.
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:
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.