Skip to content

Standard Deployment Procedure

This SOP covers the standard deployment process for all HandyManny projects to production VPS servers.

Pre-Deploy Checklist

Before deploying ANY project, verify:

  • [ ] All tests passing locally
  • [ ] Code committed to git (local)
  • [ ] No uncommitted changes (git status clean)
  • [ ] Environment variables updated (if needed)
  • [ ] Database migrations tested (if applicable)
  • [ ] Docker compose file reviewed
  • [ ] Breaking changes documented
  • [ ] Backup plan ready (see Rollback SOP)

Standard Deployment Flow

1. Local Verification

bash
# Check git status
git status

# Verify no uncommitted changes
git diff

# Check current branch
git branch

# Ensure on main/master
git checkout master  # or main

2. Run Deployment Script

Most projects have a deploy script:

bash
# Navigate to project directory
cd ~/projects/[project-name]

# Run deploy script
bash deploy.sh

# OR for Windows-specific deploys
bash deploy-windows.sh

Deploy scripts typically:

  1. Build the project (npm/python)
  2. Create deployment archive (tar/zip)
  3. Transfer to VPS via SSH/SCP
  4. Extract on VPS
  5. Run docker compose down && docker compose up -d --build
  6. Verify container health

3. Manual Deployment (No Script)

If no deploy script exists:

bash
# 1. SSH to VPS
ssh -i ~/.ssh/id_hostinger root@srv1139900.hstgr.cloud

# 2. Navigate to project
cd /root/[project-name]

# 3. Pull latest code
git pull origin main

# 4. Rebuild containers
docker compose down
docker compose up -d --build

# 5. Check logs
docker logs -f [container-name]

4. Post-Deploy Verification

Immediately after deploy:

bash
# 1. Check container status
ssh -i ~/.ssh/id_hostinger root@[vps-hostname] 'docker ps'

# 2. Check container logs
ssh -i ~/.ssh/id_hostinger root@[vps-hostname] 'docker logs -f [container-name]'

# 3. Test application URL
curl -I https://[project-url]

# 4. Visual verification
# Open browser and test critical functionality

5. Commit & Push

After successful deployment:

bash
# Commit deployment
git add -A
git commit -m "deploy: [description of changes]"

# Push to remote
git push origin master

Project-Specific Deploy Commands

ProjectCommandVPS
Expedientecd ~/projects/expediente && bash deploy.shsrv1139900
CHAROScd ~/projects/charos-expediente && ./deploy.sh charossrv1139900
HandyManny Portalcd ~/projects/handymanny && ./deploy.sh u1stsrv1139900
FFTrackingcd ~/projects/fftracking && bash deploy.shsrv1139900
Mission Controlcd ~/projects/mission-control && bash deploy.sh production --yessrv1139900
Sales MCcd ~/projects/sales-mc && bash deploy.shsrv1139900
WSI MCcd ~/wsi-mc && bash deploy.shsrv1139900
VIA Platformcd ~/Downloads/via-plan-deploy && bash deploy-windows.sh appsrv1139900
Consultincd ~/projects/consultin-gruas && bash deploy.shsrv1139900
Landing Pagecd ~/projects/handymanny-site && bash deploy.shsrv1139900
Documentationcd ~/projects/docs && bash deploy-windows.shsrv1139900

Database Migration Deployments

For projects with database schema changes:

Prisma Projects (Next.js apps)

bash
# 1. Test migration locally
npx prisma migrate dev --name [migration-name]

# 2. Verify migration file
cat prisma/migrations/[timestamp]_[name]/migration.sql

# 3. Backup production database
ssh -i ~/.ssh/id_hostinger root@srv1139900.hstgr.cloud 'docker exec [db-container] pg_dump -U [user] [dbname] > /root/backups/[dbname]-$(date +%Y%m%d-%H%M%S).sql'

# 4. Deploy application (migration runs automatically on container start)
bash deploy.sh

# 5. Verify migration applied
ssh -i ~/.ssh/id_hostinger root@srv1139900.hstgr.cloud 'docker exec [app-container] npx prisma migrate status'

SQLAlchemy Projects (Python apps)

bash
# 1. Create migration locally (if using Alembic)
alembic revision --autogenerate -m "[description]"

# 2. Review migration file
cat alembic/versions/[revision_id]_[name].py

# 3. Backup production database
# (same as above)

# 4. Deploy and run migration
bash deploy.sh

# 5. SSH to VPS and apply migration
ssh -i ~/.ssh/id_hostinger root@srv1139900.hstgr.cloud
docker exec -it [container] alembic upgrade head

Docker Compose Deployments

Standard pattern for all Docker-based projects:

bash
# 1. Update docker-compose.yml (if needed)
# 2. Update .env file (if needed)

# 3. Deploy
ssh -i ~/.ssh/id_hostinger root@[vps]
cd /root/[project]

# Pull latest code
git pull origin main

# Rebuild and restart containers
docker compose down
docker compose up -d --build

# Check status
docker compose ps
docker compose logs -f

Environment Variable Updates

To update environment variables:

bash
# 1. SSH to VPS
ssh -i ~/.ssh/id_hostinger root@[vps]

# 2. Navigate to project
cd /root/[project]

# 3. Edit .env file
nano .env  # or vim .env

# 4. Restart containers (MUST restart for env changes)
docker compose down
docker compose up -d

# 5. Verify new env vars loaded
docker exec [container] env | grep [VAR_NAME]

⚠️ IMPORTANT: Docker entrypoints bake environment variables at container creation. You MUST use docker compose down && up -d, NOT docker restart.

Multi-Tenant Deployments

For CHAROS/U1ST (same codebase, different brands):

bash
# Deploy CHAROS tenant
cd ~/projects/handymanny
./deploy.sh charos

# Deploy U1ST tenant
./deploy.sh u1st

Each tenant has:

  • Separate Docker container
  • Separate PostgreSQL database
  • Separate environment variables (NEXT_PUBLIC_BRAND_*)
  • Separate subdomain (charos.handymanny.cloud / u1st.handymanny.cloud)

Traefik SSL Certificate Renewal

Traefik automatically renews Let's Encrypt certificates, but to manually trigger:

bash
# SSH to VPS
ssh -i ~/.ssh/id_hostinger root@srv1139900.hstgr.cloud

# Restart Traefik
docker restart traefik

# Check Traefik logs
docker logs -f traefik

# Verify certificate
curl -vI https://[domain] 2>&1 | grep -i "expire"

Common Deployment Issues

Issue: Container Fails to Start

Symptoms: docker ps shows container not running

Diagnosis:

bash
# Check logs
docker logs [container-name]

# Check for port conflicts
docker ps -a | grep [port]
netstat -tulpn | grep [port]

Solutions:

  • Check environment variables
  • Check database connectivity
  • Check port conflicts
  • Review docker-compose.yml syntax

Issue: Container Restarts Continuously

Symptoms: Container status shows "Restarting"

Diagnosis:

bash
# Check exit code
docker inspect [container] | grep ExitCode

# Check logs for errors
docker logs --tail 100 [container]

Solutions:

  • Application crash on startup (check logs)
  • Database not ready (add depends_on + healthcheck)
  • Missing environment variables
  • Entrypoint script fails

Issue: 502 Bad Gateway (Traefik)

Symptoms: Traefik returns 502 error

Diagnosis:

bash
# Check Traefik logs
docker logs traefik | grep [domain]

# Check target container
docker ps | grep [container]

# Check container logs
docker logs [container]

Solutions:

  • Container not running (start it)
  • Wrong Traefik labels in docker-compose.yml
  • Port mismatch between Traefik and container
  • Container not on same Docker network

Issue: Database Connection Failed

Symptoms: App logs show "ECONNREFUSED" or connection errors

Diagnosis:

bash
# Check database container
docker ps | grep postgres

# Test database connection from app container
docker exec [app-container] nc -zv [db-host] 5432

Solutions:

  • Database container not running
  • Wrong database host in env vars (use container name, not localhost)
  • Wrong credentials
  • Database not initialized

Deploy Verification Checklist

After every deployment:

  • [ ] Container running (docker ps)
  • [ ] No errors in logs (docker logs [container])
  • [ ] HTTPS working (SSL certificate valid)
  • [ ] Homepage loads
  • [ ] Login flow works
  • [ ] Critical features tested
  • [ ] Database queries working
  • [ ] API endpoints responding
  • [ ] No JavaScript console errors

Emergency Rollback

If deployment fails critically:

See Rollback SOP for complete rollback procedures.

Quick rollback:

bash
# SSH to VPS
ssh -i ~/.ssh/id_hostinger root@[vps]
cd /root/[project]

# Revert to previous commit
git log --oneline -5  # find previous commit
git reset --hard [previous-commit-hash]

# Rebuild
docker compose down
docker compose up -d --build

Best Practices

  1. Deploy during low-traffic hours (2-6 AM) when possible
  2. Test in staging first (if staging environment exists)
  3. One change at a time - don't bundle unrelated changes
  4. Monitor logs immediately after deployment
  5. Keep VPS disk space healthy - clean old images/logs regularly
  6. Document breaking changes in git commit messages
  7. Use semantic versioning for releases
  8. Create git tags for production releases

VPS Maintenance Commands

bash
# Clean up unused Docker resources
docker system prune -a --volumes

# Check disk space
df -h

# Remove old Docker images
docker images | grep "<none>" | awk '{print $3}' | xargs docker rmi

# Clean old logs (older than 7 days)
find /var/lib/docker/containers/ -name "*.log" -mtime +7 -delete

# Restart all containers
cd /root && for dir in */; do cd "$dir" && docker compose restart && cd ..; done

Last Updated: 2026-02-28 Related SOPs: Rollback SOP, Security Guide

HandyManny Documentation System