Tools: Ultimate Guide: How We Deploy Full-Stack Apps in 2 Minutes with Jenkins + Docker

Tools: Ultimate Guide: How We Deploy Full-Stack Apps in 2 Minutes with Jenkins + Docker

The Stack

The Pipeline (5 Stages)

Stage 1: Pull & Build

Stage 2: Save & Transfer

Stage 3: Health Check

Stage 4: Zero-Downtime Swap

Stage 5: Cleanup

The Webhook Magic

Lessons Learned

Result Most dev teams I've worked with spend 30-60 minutes on each deployment. SSH into the server, pull the code, rebuild, restart services, pray nothing breaks. We got it down to 2 minutes. Fully automated. Zero SSH. Jenkins pulls the latest code and builds a Docker image. No npm install on the server — everything is baked into the image. Why not use a registry? For small teams, direct transfer is simpler and faster. Before deploying, we verify infrastructure is alive: If any check fails, the pipeline stops immediately. No half-deployed states. Push to dev branch → Jenkins builds and deploys to dev server.

Push to uat branch → Jenkins builds and deploys to UAT server. No manual triggers. No Slack messages asking "can someone deploy?" Don't check for containers that don't exist — Our UAT uses RDS, not a local DB container. The pipeline kept failing because it checked for global-db. Remove checks that don't apply to the environment. SSL is not optional — Even for internal APIs. RDS requires SSL by default. Set DB_SSL=true and move on. Use variables, not hardcoded values — redis://${REDIS_CONTAINER}:6379 not redis://global-redis:6379. Your future self will thank you. The best deployment is the one nobody has to think about. We use this pipeline at HEY!BOSS to deploy 100+ websites and multiple backend services. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ -weight: 500;">git pull → -weight: 500;">docker build -t app:latest . -weight: 500;">git pull → -weight: 500;">docker build -t app:latest . -weight: 500;">git pull → -weight: 500;">docker build -t app:latest . -weight: 500;">docker save app:latest | gzip > app.tar.gz scp app.tar.gz deploy-server:/opt/services/ -weight: 500;">docker save app:latest | gzip > app.tar.gz scp app.tar.gz deploy-server:/opt/services/ -weight: 500;">docker save app:latest | gzip > app.tar.gz scp app.tar.gz deploy-server:/opt/services/ -weight: 500;">docker -weight: 500;">stop app-old -weight: 500;">docker rm app-old -weight: 500;">docker load < app.tar.gz -weight: 500;">docker run -d --name app --network shared-net app:latest -weight: 500;">docker -weight: 500;">stop app-old -weight: 500;">docker rm app-old -weight: 500;">docker load < app.tar.gz -weight: 500;">docker run -d --name app --network shared-net app:latest -weight: 500;">docker -weight: 500;">stop app-old -weight: 500;">docker rm app-old -weight: 500;">docker load < app.tar.gz -weight: 500;">docker run -d --name app --network shared-net app:latest -weight: 500;">docker image prune -f rm app.tar.gz -weight: 500;">docker image prune -f rm app.tar.gz -weight: 500;">docker image prune -f rm app.tar.gz - Jenkins — CI/CD orchestrator - Docker — Containerized everything - GitLab — Webhook triggers on push - Nginx Proxy Manager — SSL + reverse proxy - Database container running? - Redis container running? - Network exists? - Don't check for containers that don't exist — Our UAT uses RDS, not a local DB container. The pipeline kept failing because it checked for global-db. Remove checks that don't apply to the environment. - SSL is not optional — Even for internal APIs. RDS requires SSL by default. Set DB_SSL=true and move on. - Use variables, not hardcoded values — redis://${REDIS_CONTAINER}:6379 not redis://global-redis:6379. Your future self will thank you. - Dev pushes code → 2 minutes later it's live - UAT deployment → Same pipeline, different branch - Rollback → Re-run previous build