- Home
- Blog
- Information
- Technology
- DevOps
- Zero-Downtime Deploys on a Single VPS
Zero-Downtime Deploys on a Single VPS
A boring, reliable deploy pipeline for a Laravel site on one VPS: atomic releases, health checks, cached config and a rollback that takes ten seconds.
You do not need Kubernetes to deploy a personal site without downtime. A release directory, a symlink swap and a health check are enough, and the whole thing fits in a script you can read in one sitting.
Atomic releases
Each deploy clones into `releases/<timestamp>`, installs dependencies, builds assets and only then switches the `current` symlink. PHP-FPM keeps serving the previous release until the swap, which is a single atomic operation.
Key points
- Never build on the server you serve from; build in CI and ship artifacts.
- Migrations must be backwards compatible with the release still running.
- Cache config, routes and views after every deploy.
- Keep the queue worker under supervisor and restart it on release.
Health checks before the swap
The script runs migrations with `--force`, warms the config, route and view caches and hits a local health endpoint. If anything fails the new release is deleted and the old one is never touched.
Example in code
#!/usr/bin/env bash
set -euo pipefail
release="/var/www/site/releases/$(date +%Y%m%d%H%M%S)"
git clone --depth 1 git@github.com:example/site.git "$release"
cd "$release"
composer install --no-dev --optimize-autoloader --no-interaction
npm ci && npm run build
php artisan migrate --force
php artisan optimize
ln -sfn "$release" /var/www/site/current
sudo systemctl reload php8.4-fpm
Rolling back
Because releases are directories, a rollback is just pointing the symlink at the previous one and reloading PHP-FPM. Keeping the last five releases costs a few hundred megabytes and has saved an evening more than once.
The deploy script is boring on purpose; excitement belongs in the product, not the pipeline.
Takeaways
Downtime is usually a symbol of a deploy that mutates the running release. Build somewhere else, swap atomically and keep the last few releases around.