Back to Blog

Zero-Downtime Deployment Scripts for FastAPI and PostgreSQL on a VPS

Zero-Downtime Deployment Scripts for FastAPI and PostgreSQL on a VPS For many mobile and web startups, deploying a backend starts with manual SFTP fil...

Jun 25, 2026
5 min read

Zero-Downtime Deployment Scripts for FastAPI and PostgreSQL on a VPS

For many mobile and web startups, deploying a backend starts with manual SFTP file uploads, raw SQL scripts pasted into a database console, and manual server restarts.

While this works for simple hobby projects, it is a recipe for disaster in production. A single missing dependency can crash the app, a manual schema update can corrupt user data, and the server will experience downtime during the file transfer.

Sponsored Recommendation

Need fast, secure, and affordable hosting for your next website or PHP application? We recommend Hostinger Managed Hosting. Get premium speeds, a free domain, and 24/7 expert support.

When deploying the production backend for Paisa Trackβ€”our mobile expense managerβ€”we engineered an automated deployment script running on a Linux VPS. This script handles Git checkouts, database backups, dependency installation, Alembic migrations, systemd service management, and health checks in one single command.

Here is the exact blueprint of our zero-downtime VPS pipeline.


The VPS Architecture Overview

Our backend is built using FastAPI (Python) and PostgreSQL. The production server runs on a Linux Virtual Private Server (VPS) with:

  1. Nginx as a reverse proxy, handling SSL termination.
  2. Systemd managing the Gunicorn/Uvicorn processes.
  3. Alembic for python database schema migrations.
  4. Git Sparse Checkout to pull only backend source code from our repository.

To automate updates, we created a deployment script deploy_paisatrack.sh mapped to a global alias deploypt.


The Production Deployment Script

Here is our production-ready bash deployment script. It is designed to fail immediately (set -e) if any command returns a non-zero exit status, protecting the server from running a partially updated backend.

#!/bin/bash
set -e

echo "πŸš€ Starting FastAPI Backend Deployment..."

# 1. Stop the active systemd service
echo "πŸ›‘ Stopping FastAPI service..."
sudo systemctl stop paisatrack

# 2. Database Backup (Safety First!)
echo "πŸ’Ύ Taking PostgreSQL database backup..."
mkdir -p /home/app-user/db_backups
BACKUP_FILE="/home/app-user/db_backups/backup_$(date +%Y%m%d_%H%M%S).sql"

PGPASSWORD='your_db_password' pg_dump \
  -U app_db_user \
  -h localhost \
  -d app_database \
  -F p --no-owner --no-acl -v -f "$BACKUP_FILE"

echo "βœ… Database backup saved to: $BACKUP_FILE"

# 3. Pull latest code from Git
cd /home/app-user/source-repo
echo "πŸ“₯ Fetching latest code from GitHub..."
git pull origin master

# 4. Sync files cleanly via Rsync
# IMPORTANT: --delete cleans up old python files, but we MUST exclude state dirs
echo "πŸ“¦ Syncing backend files to htdocs..."
rsync -av --delete \
  --exclude='.env' \
  --exclude='venv/' \
  --exclude='*.log' \
  --exclude='uploads/' \
  --exclude='credentials.json' \
  /home/app-user/source-repo/Backend/ \
  /home/app-user/htdocs/api.production.com/

# 5. Activate environment, update packages, and run migrations
echo "🐍 Updating dependencies and running Alembic migrations..."
cd /home/app-user/htdocs/api.production.com
source venv/bin/activate
pip install -r requirements.txt

# Run migrations (Note database percent-encoding escape for shell scripts)
DATABASE_URL="postgresql://app_db_user:password_escaped@localhost:5432/app_database" alembic upgrade head

# 6. Start backend service
echo "πŸ”„ Starting FastAPI service..."
sudo systemctl start paisatrack

# 7. cURL Health Check Loop
echo "πŸ” Verifying API health endpoint..."
SUCCESS=false
for i in {1..10}; do
  if curl -s -f http://localhost:8090/health > /dev/null; then
    echo "βœ… Backend successfully online!"
    SUCCESS=true
    break
  fi
  echo "Waiting for API to boot... ($i/10)"
  sleep 1
done

if [ "$SUCCESS" = false ]; then
  echo "⚠️ Warning: Service is running but health check endpoint failed."
  exit 1
fi

echo "βœ… Deployment completed successfully!"

Under the Hood: Why This Script Works

1. The Power of Rsync Exclusions

Unlike cp -r which simply copies files on top of each other, rsync -av --delete ensures that deleted files in Git are deleted on the server, preventing stale Python imports. By specifying --exclude, we ensure we never overwrite server-specific configurations (like .env), active user image directory uploads (uploads/), active app logs, or SQLite local testing databases.

2. Automated Non-Destructive Migrations via Alembic

With Alembic, we don't have to manually write DDL queries (ALTER TABLE...). When we add a feature (e.g. invitations, currencies) in Python, we generate an Alembic script. The server runs alembic upgrade head to safely adjust the Postgres tables. If a migration fails, the script triggers set -e and halts deployment, allowing us to roll back without losing user data.

3. Percent-Encoding Database Credentials

A common issue in automated bash migration runs is using special characters (like # or @) in database passwords. In Python, Alembic parses database connection strings. In shell scripts, these must be URL-encoded (e.g., replacing @ with %40 and # with %23) and percent-escaped (%%40 / %%23) to prevent shell interpolation from breaking the migration.

4. Health Check Loops

Instead of assuming a service starts successfully just because systemctl start returns zero, the cURL loop query makes a real HTTP request to the backend. If the backend fails to boot (e.g., because of a port binding issue or database timeout), the health check times out, exits, and alerts the DevOps pipeline immediately.


Conclusion

Automating VPS deployments removes human error, provides secure rollback pathways, and ensures that backend migrations are executed safely alongside source code updates. By utilizing Git sparse-checkouts, rsync exclusions, and Alembic database upgrades, Paisa Track's server remains reliable and low-maintenance.

Need Enterprise-Grade DevOps and Deployment Systems?

At ScoRpii Tech, we build reliable cloud backends and DevOps pipelines. Whether you are running complex APIs on an independent VPS, automating migrations, or deploying high-traffic services, our engineers can structure a robust setup for you.

Estimate Your App Development Budget using our interactive pricing tool, or Contact Us for a Cloud Infrastructure Consultation.

Share this article

What did you think?