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 statusclean) - [ ] 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
# Check git status
git status
# Verify no uncommitted changes
git diff
# Check current branch
git branch
# Ensure on main/master
git checkout master # or main2. Run Deployment Script
Most projects have a deploy script:
# Navigate to project directory
cd ~/projects/[project-name]
# Run deploy script
bash deploy.sh
# OR for Windows-specific deploys
bash deploy-windows.shDeploy scripts typically:
- Build the project (npm/python)
- Create deployment archive (tar/zip)
- Transfer to VPS via SSH/SCP
- Extract on VPS
- Run
docker compose down && docker compose up -d --build - Verify container health
3. Manual Deployment (No Script)
If no deploy script exists:
# 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:
# 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 functionality5. Commit & Push
After successful deployment:
# Commit deployment
git add -A
git commit -m "deploy: [description of changes]"
# Push to remote
git push origin masterProject-Specific Deploy Commands
| Project | Command | VPS |
|---|---|---|
| Expediente | cd ~/projects/expediente && bash deploy.sh | srv1139900 |
| CHAROS | cd ~/projects/charos-expediente && ./deploy.sh charos | srv1139900 |
| HandyManny Portal | cd ~/projects/handymanny && ./deploy.sh u1st | srv1139900 |
| FFTracking | cd ~/projects/fftracking && bash deploy.sh | srv1139900 |
| Mission Control | cd ~/projects/mission-control && bash deploy.sh production --yes | srv1139900 |
| Sales MC | cd ~/projects/sales-mc && bash deploy.sh | srv1139900 |
| WSI MC | cd ~/wsi-mc && bash deploy.sh | srv1139900 |
| VIA Platform | cd ~/Downloads/via-plan-deploy && bash deploy-windows.sh app | srv1139900 |
| Consultin | cd ~/projects/consultin-gruas && bash deploy.sh | srv1139900 |
| Landing Page | cd ~/projects/handymanny-site && bash deploy.sh | srv1139900 |
| Documentation | cd ~/projects/docs && bash deploy-windows.sh | srv1139900 |
Database Migration Deployments
For projects with database schema changes:
Prisma Projects (Next.js apps)
# 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)
# 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 headDocker Compose Deployments
Standard pattern for all Docker-based projects:
# 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 -fEnvironment Variable Updates
To update environment variables:
# 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):
# Deploy CHAROS tenant
cd ~/projects/handymanny
./deploy.sh charos
# Deploy U1ST tenant
./deploy.sh u1stEach 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:
# 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:
# 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:
# 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:
# 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:
# Check database container
docker ps | grep postgres
# Test database connection from app container
docker exec [app-container] nc -zv [db-host] 5432Solutions:
- 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:
# 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 --buildBest Practices
- Deploy during low-traffic hours (2-6 AM) when possible
- Test in staging first (if staging environment exists)
- One change at a time - don't bundle unrelated changes
- Monitor logs immediately after deployment
- Keep VPS disk space healthy - clean old images/logs regularly
- Document breaking changes in git commit messages
- Use semantic versioning for releases
- Create git tags for production releases
VPS Maintenance Commands
# 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 ..; doneLast Updated: 2026-02-28 Related SOPs: Rollback SOP, Security Guide