services: web: restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s retries: 3 nginx: restart: unless-stopped db: restart: unless-stopped volumes: - postgres_data:/var/lib/postgresql/data
services: web: restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s retries: 3 nginx: restart: unless-stopped db: restart: unless-stopped volumes: - postgres_data:/var/lib/postgresql/data
services: web: restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s retries: 3 nginx: restart: unless-stopped db: restart: unless-stopped volumes: - postgres_data:/var/lib/postgresql/data - Single server setup — your app fits on one machine (most small businesses do)
- Low traffic — under ~1,000 concurrent users
- Small team — 1-5 developers who don't want Kubernetes complexity
- Predictable load — no need for auto-scaling
- Budget constraints — one EC2 instance costs $15-30/month vs $150+ for managed Kubernetes - No auto-healing — if a container crashes, you need a restart policy to bring it back
- No horizontal scaling — you can't easily add more web servers
- No rolling deployments — deploys cause a brief downtime window
- Single point of failure — if the server goes down, everything goes down - Sync new code to the server (rsync)
- Build the new image: docker compose build web
- Run migrations: docker compose exec web rails db:migrate
- Reload: docker compose up -d --no-deps web