{"id":909,"date":"2026-08-17T23:21:29","date_gmt":"2026-08-17T23:21:29","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=909"},"modified":"2026-08-17T23:21:29","modified_gmt":"2026-08-17T23:21:29","slug":"blue-green-canary-deploys-single-vps-nginx","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/","title":{"rendered":"Zero-Downtime Deploys on a Single VPS: Blue-Green and Canary Releases with Nginx"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Deploying a new version of your application should not mean telling users &#8220;be right back&#8221;. On a single VPS you cannot spin up a second datacenter, but you can still get zero-downtime releases \u2014 because Nginx is a perfectly good traffic switch. With two application directories, two upstream pools, and an atomic reload, you can run blue-green swaps and canary releases without Kubernetes or a load balancer in front. The only prerequisite is a VPS with enough RAM to hold two copies of the app, so check the plans on our <a href=\"https:\/\/virtualserversvps.com\/#providers\">VPS comparison table<\/a> if you need headroom.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Blue-Green with Two Upstreams<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Blue-green means running the old version (blue) and the new version (green) side by side, then switching traffic at the proxy. With Nginx this is two <code>upstream<\/code> blocks pointing at different ports or sockets, and a default that selects one:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>upstream app_blue {\n  server 127.0.0.1:8001;\n}\nupstream app_green {\n  server 127.0.0.1:8002;\n}\n\n# Point this at the active color\nupstream app_active {\n  server 127.0.0.1:8001;\n}\n\nserver {\n  listen 80;\n  server_name app.example.com;\n  location \/ {\n    proxy_pass http:\/\/app_active;\n    proxy_set_header Host $host;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n  }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">To deploy version 2: start it on port 8002, run health checks against <code>127.0.0.1:8002<\/code>, then flip <code>app_active<\/code> to <code>server 127.0.0.1:8002;<\/code> and reload: <code>nginx -s reload<\/code>. The reload is atomic \u2014 Nginx finishes in-flight requests with the old config and applies the new one to everything after, so no connection is dropped. If the new version misbehaves, flip the pointer back and reload again. Rollback is a config edit, not a redeploy.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Canary Releases with Weighted Upstreams<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Blue-green is binary: all or nothing. A canary is graduated \u2014 send 5% of traffic to the new version, watch error rates, then ramp to 25%, 50%, 100%. Nginx does this with upstream weights:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>upstream app_canary {\n  server 127.0.0.1:8001 weight=95;  # blue: 95%\n  server 127.0.0.1:8002 weight=5;   # green: 5%\n}<\/code>\n\n\n\n<p class=\"wp-block-paragraph\">Each reload with a new weight is a canary step. Watch three things between steps: HTTP 5xx rate in <code>access.log<\/code>, application error logs, and latency percentiles. If the canary's error rate matches or beats blue's, keep ramping; the moment it spikes, reload with <code>weight=0<\/code> on green and investigate. For a cleaner signal, give the canary its own log file (<code>access_log \/var\/log\/nginx\/canary.log;<\/code> in a server block that only green sees) so you can compare populations instead of averages.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Header and Cookie-Based Routing: Canary for Specific Users<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Weighted routing is random; sometimes you want deterministic canaries \u2014 internal testers always see green, everyone else stays on blue. A <code>map<\/code> block decides the upstream per request:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>map $http_cookie $backend {\n  default        app_blue;\n  \"~*canary=1\"   app_green;\n}\n\nserver {\n  location \/ {\n    proxy_pass http:\/\/$backend;\n  }\n}<\/code>\n\n\n\n<p class=\"wp-block-paragraph\">Testers visit <code>app.example.com<\/code> with the <code>canary=1<\/code> cookie; everyone else stays on blue. The same pattern works with a header (<code>$http_x_canary<\/code>) for API clients or CI smoke tests. This is the classic staging-inside-production trick: the canary is fully deployed and serving real requests, but only for a population you control.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Minimal Deploy Script<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The whole cycle fits in a short script: deploy to the inactive color, health-check it, switch, verify, and keep the previous version around for rollback.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/usr\/bin\/env bash\nset -euo pipefail\nAPP_DIR=\/srv\/app\nNEW_PORT=8002   # alternate between 8001\/8002 per release\n\n# 1. Ship code to the inactive color\nrsync -a --delete .\/build\/ $APP_DIR\/green\/\n\n# 2. Start the green app (systemd unit on port 8002)\nsystemctl restart app-green\n\n# 3. Health-check before touching Nginx\nfor i in {1..10}; do\n  curl -fsS http:\/\/127.0.0.1:8002\/healthz &amp;&amp; break || sleep 1\ndone\n\n# 4. Switch traffic and reload atomically\nsed -i 's\/server 127.0.0.1:8001;\/server 127.0.0.1:8002;\/' \\\n  \/etc\/nginx\/conf.d\/app.conf\nnginx -t &amp;&amp; nginx -s reload\n\n# 5. Post-deploy smoke test through the public entrypoint\ncurl -fsS https:\/\/app.example.com\/healthz<\/code>\n\n\n\n<p class=\"wp-block-paragraph\">The two colors can be two systemd units (<code>app-blue.service<\/code>, <code>app-green.service<\/code>), two directories under <code>\/srv\/app\/<\/code>, or two containers \u2014 Nginx does not care, it only balances between the ports. Just ensure the app reads its config from the environment so both colors run with identical settings except the version.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where This Breaks (Know the Limits)<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Stateful sessions:<\/strong> sticky sessions and in-memory sessions break when traffic moves between colors. Keep sessions in Redis or the database, or pin by cookie.<\/li><li><strong>Long-lived WebSockets:<\/strong> <code>nginx -s reload<\/code> does not kill existing connections, so in-flight WebSocket upgrades survive \u2014 but new connections during the reload window may hit either color. Version the WebSocket protocol defensively.<\/li><li><strong>Database migrations:<\/strong> the old version still runs during the switch, so schema changes must be backward-compatible (expand-migrate-contract). This is the real constraint on single-VPS blue-green, not Nginx.<\/li><li><strong>One box, one point of failure:<\/strong> this gives you zero-downtime deploys, not high availability. A hardware failure still takes the site down until you restore from backup.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For most small applications this pattern removes the most stressful part of shipping: the moment where a bad release takes the site down for everyone. Nginx gives you the switch for free; the discipline is in keeping both colors deployable and health-checked at all times. If you are about to size a server for running two app instances plus a database, our <a href=\"https:\/\/virtualserversvps.com\/#features\">memory and storage comparison<\/a> helps you pick a tier that fits, and the <a href=\"https:\/\/virtualserversvps.com\/#providers\" rel=\"noreferrer noopener sponsored\">provider ranking<\/a> is a good starting point for hosts with fast NVMe for the rsync step.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Deploying a new version of your application should not mean telling users &#8220;be right back&#8221;. On a single VPS you cannot spin up a second datacenter, but you can still&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":0,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-909","post","type-post","status-publish","format-standard","hentry","category-performance-optimization"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Zero-Downtime Deploys on a Single VPS: Blue-Green and Canary Releases with Nginx - Virtual Servers VPS Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Zero-Downtime Deploys on a Single VPS: Blue-Green and Canary Releases with Nginx\" \/>\n<meta property=\"og:description\" content=\"Zero-Downtime Deploys on a Single VPS: Blue-Green and Canary Releases with Nginx\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-17T23:21:29+00:00\" \/>\n<meta name=\"author\" content=\"Virtual-Servers-Vps-Editor\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Virtual-Servers-Vps-Editor\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/\",\"name\":\"Zero-Downtime Deploys on a Single VPS: Blue-Green and Canary Releases with Nginx - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-08-17T23:21:29+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Zero-Downtime Deploys on a Single VPS: Blue-Green and Canary Releases with Nginx\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/\",\"name\":\"Virtual Servers VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\",\"name\":\"Virtual-Servers-Vps-Editor\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"caption\":\"Virtual-Servers-Vps-Editor\"},\"sameAs\":[\"https:\/\/virtualserversvps.com\/blog\"],\"url\":\"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Zero-Downtime Deploys on a Single VPS: Blue-Green and Canary Releases with Nginx - Virtual Servers VPS Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/","og_locale":"en_US","og_type":"article","og_title":"Zero-Downtime Deploys on a Single VPS: Blue-Green and Canary Releases with Nginx","og_description":"Zero-Downtime Deploys on a Single VPS: Blue-Green and Canary Releases with Nginx","og_url":"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-08-17T23:21:29+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/","url":"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/","name":"Zero-Downtime Deploys on a Single VPS: Blue-Green and Canary Releases with Nginx - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-08-17T23:21:29+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/blue-green-canary-deploys-single-vps-nginx\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Zero-Downtime Deploys on a Single VPS: Blue-Green and Canary Releases with Nginx"}]},{"@type":"WebSite","@id":"https:\/\/virtualserversvps.com\/blog\/#website","url":"https:\/\/virtualserversvps.com\/blog\/","name":"Virtual Servers VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0","name":"Virtual-Servers-Vps-Editor","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","caption":"Virtual-Servers-Vps-Editor"},"sameAs":["https:\/\/virtualserversvps.com\/blog"],"url":"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/"}]}},"_links":{"self":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/909","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/comments?post=909"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/909\/revisions"}],"predecessor-version":[{"id":912,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/909\/revisions\/912"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=909"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=909"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=909"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}