Framework Agnostic Zero Downtime Deployment with NGINX

06 Jan 2015

Unless you're dealing with a low traffic or internal-facing site, zero downtime deployments are pretty important. Some frameworks have zero-downtime capacity built-in. Furthermore, at a larger scale, you'll want to roll out changes using more advanced routing and control mechanism. Still, for years, I've been using a simple nginx configuration trick when deploying web apps which I think is pretty useful.

The solution I use relies on alternating between two ports when deploying new code and having a short overlap between starting the new app and shutting down the existing one. The major downside is the doubling of resources for a brief period of time. At worse, you'll temporarily have twice the number of open connection to your DB, memory usage and so on.

The problem with this approach is the performance hit we get whenever the unavailable upstream is picked. We can tweak the frequency of that via the server's fail_timeout property, but ultimately this solution feels half-assed.

The solution that I'm currently using is to define to upstream groups an rely on the backup attribute. First, the upstream definitions:

For bonus points, since sed -i isn't portable, you could use perl -pi -e "s#$FROM#$TO#g" instead. Also, while NGINX should handle this well as-is, I normally shut down the currently running app by sending it a signal (SIGINT) which the app code catches and slowly shuts down. By slowy shutting down, I mean that, for a few seconds after receiving the signal, it'll keep answering requests but include a Connection: Close header in responses which should help clean up NGINX's keepalive connections.