Updated:

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 -t fails;
  • production returns 403 or 404 on 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.