Safe deploy checklist
This is the longer version of the quickstart.
Use it when you do not want to deploy “by feel”: layout changes, several new pages, style updates, or client-side script updates.
The main rule: validate the build first, deploy second, validate production third.
0. Know what you are updating
For a content-only update, touch only:
~/getsrv-static-src
/var/www/getsrv.app
Do not change:
/etc/nginx/
/etc/haproxy/
systemd services
public listeners
TLS certificates
If the task is not about infrastructure, do not accidentally turn it into an infrastructure change.
1. Back up the source project
cd ~/getsrv-static-src
STAMP="$(date +%F-%H%M%S)"
BACKUP_DIR="$HOME/getsrv-static-backups/deploy-$STAMP"
mkdir -p "$BACKUP_DIR"
rsync -a --delete \
--exclude node_modules \
--exclude dist \
--exclude .astro \
~/getsrv-static-src/ "$BACKUP_DIR/getsrv-static-src/"
2. Back up the production web root
sudo rsync -a --delete /var/www/getsrv.app/ "$BACKUP_DIR/getsrv.app-www/"
Now you have two rollback points:
$BACKUP_DIR/getsrv-static-src/
$BACKUP_DIR/getsrv.app-www/
3. Build the project
npm run build
Expected result:
[build] Complete!
Stop condition: if the build fails, do not run rsync dist/.
4. Check required pages
test -f dist/index.html
test -f dist/en/index.html
test -f dist/en/docs/index.html
test -f dist/en/tools/index.html
test -f dist/en/docs/quickstart/index.html
test -f dist/en/tools/headers-inspector/index.html
If any test -f fails, the build is incomplete or a route changed.
5. Check page count
find dist -type f -name '*.html' | wc -l
The count alone does not prove quality, but it catches obvious failures.
If it was 44 yesterday and is 5 today, stop the deployment.
6. Check assets
find dist/assets -maxdepth 1 -type f | sort
CSS/JS should be under /assets/ and have hashed filenames.
7. Check external runtime URLs
grep -RInE 'https?://' dist --exclude='sitemap*.xml' --exclude='robots.txt' | grep -v 'https://getsrv.app' || true
For an autonomous static site, normal output is empty.
If the command finds a third-party URL, check:
- whether it is only a documentation link or a runtime dependency;
- whether a CDN appeared;
- whether an external font was added;
- whether analytics was introduced.
8. Deploy the build
sudo rsync -a --delete dist/ /var/www/getsrv.app/
sudo find /var/www/getsrv.app -type d -exec chmod 755 {} \;
sudo find /var/www/getsrv.app -type f -exec chmod 644 {} \;
sudo chown -R www-data:www-data /var/www/getsrv.app
9. Validate Nginx
sudo nginx -t
If the result is not syntax is ok and test is successful, do not reload.
10. Reload Nginx
sudo systemctl reload nginx
For a static-site update, reload is enough. A full restart is usually unnecessary.
11. Check main URLs
curl -kI https://getsrv.app/
curl -kI https://getsrv.app/en/
curl -kI https://getsrv.app/en/docs/
curl -kI https://getsrv.app/en/tools/
curl -kI https://getsrv.app/sitemap-index.xml
curl -kI https://getsrv.app/no-such-page
Expected:
/ 200
/en/ 200
/en/docs/ 200
/en/tools/ 200
/sitemap-index.xml 200
/no-such-page 404
12. Check headers
HTML:
curl -kI https://getsrv.app/
Expected:
Cache-Control: public, must-revalidate
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Content-Security-Policy: ...
Asset:
ASSET="$(find /var/www/getsrv.app/assets -maxdepth 1 -type f | head -n 1 | sed 's#^/var/www/getsrv.app##')"
curl -kI "https://getsrv.app$ASSET"
Expected:
Cache-Control: public, max-age=31536000, immutable
13. Check listeners
sudo ss -lntp | grep -E ':(443|7443|10443|11443)\b'
A content-only update must not change listeners.
14. Fast web-root rollback
If production is clearly broken after deployment and a backup exists:
sudo rsync -a --delete "$BACKUP_DIR/getsrv.app-www/" /var/www/getsrv.app/
sudo chown -R www-data:www-data /var/www/getsrv.app
sudo nginx -t
sudo systemctl reload nginx
Run smoke-test again after rollback.
15. Stop conditions
Stop if:
- build does not complete;
dist/is empty;- required pages are missing;
- unexpected external runtime URLs appear;
nginx -tfails;- production returns
403or404on the homepage; - headers do not match expectations;
- listeners changed without a reason.
A safe deploy is not a complex deploy. It is a deploy with checks before, checks after, and a clear way back.