A common way to put a website into 'maintenance mode' is to have another, separate, website whose only purpose is to return an informative message along with a HTTP Service Unavailable (503) response code, regardless of the request sent to it. This way, if a site becomes unavailable, we can divert all traffic away from the primary site to the maintenance website and hey presto, you're free to upgrade the application, OS, server etc.
It's worth noting that the swap should be done using a reverse proxy (we use CloudFlare) instead of DNS as even if you reduce your TTL right down, some DNS servers will ignore the short TTL and continue to send traffic to the website that's meant to be offline. With CloudFlare, the DNS records remain the same throughout and you can switch between sites in minutes.
We're big fans of Platform as a Service (PaaS) and Serverless Architectures at Moneybox (notably because we don't have any dedicated engineers in Operations) and were looking for a way to host our application with the least amount of required maintenance possible. Azure was out of the question at they're our main hosting provider and we wanted to be in control even if they have a region wide outage (as has just happened with their WebApp service in North Europe). Instead we looked towards AWS.
After a little research and tinkering, it turned out that we could achieve what we wanted with a little hack on top of AWS S3 and CloudFront. The added bonus is that is that not a single line of code is required!
In its normal mode of operation, CloudFront sits in front of S3 (or another origin server) and caches requested content at one of its numerous edge locations. Our hack relies on a feature called Error Pages that allows a different response code (along with custom content) to be returned if the origin server returns a non 200 response.
If we place a single file containing our error response on S3 (a JSON file in our case), a request for anything else will result in a default 403 Forbidden response from S3. This response is returned regardless of the requested HTTP operation, be it GET, PUT, POST etc. With the Error Page feature, we can intercept this 403 response and return back a 503 along with the contents on the single file (below) in our S3 bucket:
We now have a cheap endpoint that will return our maintenance message no matter the request sent to it (except if the error page itself is directly accessed of course). The best bit is that this is server free, code free and consequently maintenance free - just the way we like things :)
Finally, below are a two solutions to gotchas I encountered along the way:
Make sure the content type of the error file is set to the content type you would like returned. In our case it is
application/jsonbut it would have to be
text/htmlif you wanted to return an HTML page. This can be done through the AWS portal itself or through a client such as CyberDuck.
CloudFront will cache content a lot longer than the minimum specified when setting up the error page. If you want to force an update to your error content, use the Invalidation feature to force CloudFront's edge nodes to update.