{"id":799,"date":"2026-08-04T23:50:34","date_gmt":"2026-08-04T23:50:34","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=799"},"modified":"2026-08-04T23:50:34","modified_gmt":"2026-08-04T23:50:34","slug":"zero-downtime-deploys-single-vps-systemd-blue-green-rollback","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/","title":{"rendered":"Zero-Downtime Deploys on a Single VPS: systemd, Blue-Green, and Rollback"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A plain <code>systemctl restart app<\/code> drops every in-flight request, closes established connections, and leaves a visible gap in your error log. On a single VPS you cannot spin up a second machine to absorb the switch \u2014 but you can get close to zero downtime with two systemd features you already have: socket activation, which keeps the listening socket alive across restarts, and a blue-green release layout that swaps a symlink instead of stopping the service. This guide builds both, plus a rollback path that takes one command.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The approach assumes your application is a long-running daemon that binds to a TCP or Unix socket and supports graceful shutdown (finishing current requests before exiting). If your app is a PHP-FPM or Apache worker pool, the same symlink trick applies to the document root. Budget matters too \u2014 the release directories need a little extra disk, so <a href=\"https:\/\/virtualserversvps.com\/#providers\">compare VPS plans on our comparison table<\/a> and pick one with SSD or NVMe storage and headroom for two full copies of the app.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Socket Activation: Restarts Without Dropped Connections<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With socket activation, systemd owns the listening socket and hands the file descriptor to your service on startup. When you restart the service, the socket stays open in systemd; new connections queue in the kernel backlog for the split second the app is down. For a typical web API that means restarts drop from &#8220;connection refused&#8221; to a few milliseconds of queueing. The units:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/systemd\/system\/myapp.socket\n[Socket]\nListenStream=\/run\/myapp.sock\nSocketMode=0660\nSocketUser=www-data\n\n[Install]\nWantedBy=sockets.target<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/systemd\/system\/myapp.service\n[Service]\nUser=www-data\nExecStart=\/srv\/app\/current\/bin\/myapp\nRestart=on-failure\n# systemd passes the socket as FD 3 (LISTEN_FDS=1)\n\n[Install]\nWantedBy=multi-user.target<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Enable the socket, not the service: <code>systemctl enable --now myapp.socket<\/code>. Test that a restart no longer interrupts clients:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>while true; do curl -s --unix-socket \/run\/myapp.sock http:\/\/localhost\/healthz; sleep 0.2; done\n# in a second terminal:\nsystemctl restart myapp\n# the loop above never prints a connection error<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Gunicorn, uWSGI, and most Node\/Python frameworks support inheriting the systemd socket natively \u2014 <code>gunicorn --bind unix:\/run\/myapp.sock<\/code> or the <code>LISTEN_FDS<\/code> env var in Go&#8217;s <code>systemd<\/code> package. If your app insists on opening its own port, you can also use <code>ListenStream=127.0.0.1:8080<\/code> and let the socket unit own the TCP port instead.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Blue-Green Release Directories<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Socket activation fixes restarts, but deploying a broken build still takes the site down until you notice. Blue-green solves that by keeping two complete copies of the app and switching <code>\/srv\/app\/current<\/code> atomically:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/srv\/app\/\n\u251c\u2500\u2500 current -&gt; releases\/2026-08-05-1530   # symlink, switched atomically\n\u251c\u2500\u2500 blue\/    -&gt; releases\/2026-08-05-1530\n\u251c\u2500\u2500 green\/   -&gt; releases\/2026-08-05-1400\n\u2514\u2500\u2500 releases\/\n    \u251c\u2500\u2500 2026-08-05-1400\/                   # old version (green)\n    \u2514\u2500\u2500 2026-08-05-1530\/                   # new version (blue)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The deploy script rsyncs the new build into the inactive slot, points <code>current<\/code> at it, restarts, and health-checks before declaring victory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\nset -euo pipefail\nRELEASE=\"\/srv\/app\/releases\/$(date +%Y-%m-%d-%H%M)\"\nrsync -a --delete \/tmp\/build\/ \"$RELEASE\/\"\nln -sfn \"$RELEASE\" \/srv\/app\/current          # atomic switch\nsystemctl restart myapp\nfor i in $(seq 1 10); do\n  curl -fsS http:\/\/127.0.0.1:8080\/healthz &amp;&amp; exit 0\n  sleep 1\ndone\nln -sfn \/srv\/app\/blue \/srv\/app\/current      # rollback\nsystemctl restart myapp\nexit 1<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Because <code>ln -sfn<\/code> is atomic, the symlink flip never leaves a half-written state, and the old release directory stays intact until you prune it. If you would rather not run this yourself on a busy production box, <a href=\"https:\/\/cloudways.com\/en\/?id=2010927&amp;data1=virtualserversvps\" rel=\"noreferrer noopener sponsored\" target=\"_blank\">Cloudways managed VPS hosting handles deployments with one-click Git pulls and instant rollback<\/a> \u2014 the same blue-green idea, without you writing the script.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Health Checks and Instant Rollback<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The health endpoint is the contract your deploy script depends on. Make it cheap (no database query if possible) but honest: it should fail when the app cannot serve traffic. A 200 within the retry window means the new version is live; anything else triggers the rollback branch, which flips the symlink back and restarts. Rollback stays instant because the previous release directory was never deleted.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Keep a rotation policy so disk does not fill up: delete releases older than 5\u201310 deploys with a cron job or systemd timer: <code>find \/srv\/app\/releases -mindepth 1 -maxdepth 1 -mtime +14 -exec rm -rf {} +<\/code>. Combined with socket activation, the whole cycle \u2014 deploy, verify, roll back \u2014 never interrupts an active connection.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What This Does Not Solve<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Schema migrations still need care: if the new code assumes a migrated database but the old code is still running during rollback, you get two versions fighting over one schema. Run backward-compatible migrations first, or gate them behind a feature flag. Long-lived WebSocket connections also survive the socket handover but not an app process exit \u2014 accept that and reconnect clients on the front end. And if you run multiple VPSes behind a load balancer, drain connections before restarting each node; on a single VPS this guide is the whole story. Start with socket activation alone if a full blue-green layout feels heavy \u2014 it already eliminates the visible restart gap, and you can add release directories later. For the hardware to run two app copies comfortably, <a href=\"https:\/\/virtualserversvps.com\/#providers\">see the full specs and pricing on our comparison table<\/a>.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>A plain systemctl restart app drops every in-flight request, closes established connections, and leaves a visible gap in your error log. On a single VPS you cannot spin up a&#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":[1],"tags":[],"class_list":["post-799","post","type-post","status-publish","format-standard","hentry","category-vps-guides-tutorials"],"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: systemd, Blue-Green, and Rollback - 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\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/\" \/>\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: systemd, Blue-Green, and Rollback\" \/>\n<meta property=\"og:description\" content=\"Zero-Downtime Deploys on a Single VPS: systemd, Blue-Green, and Rollback\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-04T23:50:34+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\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/\",\"name\":\"Zero-Downtime Deploys on a Single VPS: systemd, Blue-Green, and Rollback - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-08-04T23:50:34+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/#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: systemd, Blue-Green, and Rollback\"}]},{\"@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: systemd, Blue-Green, and Rollback - 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\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/","og_locale":"en_US","og_type":"article","og_title":"Zero-Downtime Deploys on a Single VPS: systemd, Blue-Green, and Rollback","og_description":"Zero-Downtime Deploys on a Single VPS: systemd, Blue-Green, and Rollback","og_url":"https:\/\/virtualserversvps.com\/blog\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-08-04T23:50:34+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\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/","url":"https:\/\/virtualserversvps.com\/blog\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/","name":"Zero-Downtime Deploys on a Single VPS: systemd, Blue-Green, and Rollback - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-08-04T23:50:34+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/zero-downtime-deploys-single-vps-systemd-blue-green-rollback\/#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: systemd, Blue-Green, and Rollback"}]},{"@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\/799","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=799"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/799\/revisions"}],"predecessor-version":[{"id":802,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/799\/revisions\/802"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=799"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=799"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=799"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}