This guide covers deploying StudyQuest using Docker containers for both local development and production environments.
- Prerequisites
- Quick Start
- Building Docker Images
- Running with Docker Compose
- Environment Configuration
- Production Deployment
- Health Checks
- Troubleshooting
Before you begin, ensure you have the following installed:
- Docker: Version 20.10 or higher
- Install: https://docs.docker.com/get-docker/
- Docker Compose: Version 2.0 or higher
- Usually included with Docker Desktop
- Git: For cloning the repository
Verify installations:
docker --version
docker-compose --versionGet up and running in 3 steps:
# 1. Clone the repository
git clone <repository-url>
cd studyquest
# 2. Set up environment variables
cp backend/.env.example backend/.env
cp frontend/.env.local.example frontend/.env.local
# Edit both files with your actual values
# 3. Start all services
docker-compose up -dAccess the application:
- Frontend: http://localhost:3000
- Backend API: http://localhost:8000
- API Docs: http://localhost:8000/docs
The backend uses a multi-stage build for optimal size and security:
# Build the backend image
cd backend
docker build -t studyquest-backend:latest .
# Build with custom tag
docker build -t studyquest-backend:v1.0.0 .Dockerfile Features:
- Multi-stage build: Separates build and runtime dependencies
- Non-root user: Runs as
appuser(UID 1000) for security - Minimal base: Uses
python:3.11-slimfor smaller image size - Health checks: Built-in health monitoring
- Optimized layers: Efficient caching for faster rebuilds
The frontend uses Next.js standalone output for minimal production size:
# Build the frontend image
cd frontend
docker build -t studyquest-frontend:latest .
# Build with custom tag
docker build -t studyquest-frontend:v1.0.0 .Dockerfile Features:
- Three-stage build: Dependencies → Build → Production
- Standalone output: Minimal Next.js runtime
- Non-root user: Runs as
nextjs(UID 1001) - Alpine base: Ultra-small image size (~150MB)
- Health checks: Automatic health monitoring
You can pass build arguments for customization:
# Backend with custom Python version
docker build --build-arg PYTHON_VERSION=3.11 -t studyquest-backend .
# Frontend with custom Node version
docker build --build-arg NODE_VERSION=18 -t studyquest-frontend .Docker Compose orchestrates both services with proper networking and dependencies.
# Start in detached mode (background)
docker-compose up -d
# Start with logs visible
docker-compose up
# Start specific service
docker-compose up -d backend# View all logs
docker-compose logs
# Follow logs in real-time
docker-compose logs -f
# View specific service logs
docker-compose logs -f backend
docker-compose logs -f frontend
# View last 100 lines
docker-compose logs --tail=100# Stop all services (containers remain)
docker-compose stop
# Stop and remove containers
docker-compose down
# Stop and remove containers + volumes
docker-compose down -v
# Stop and remove containers + images
docker-compose down --rmi all# Restart all services
docker-compose restart
# Restart specific service
docker-compose restart backend# Rebuild images and restart
docker-compose up -d --build
# Force rebuild (no cache)
docker-compose build --no-cache
docker-compose up -dCreate backend/.env from the example:
cp backend/.env.example backend/.envRequired Variables:
# Supabase Configuration
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_KEY=your_supabase_anon_key_here
# OpenRouter AI Configuration
OPENROUTER_API_KEY=sk-or-v1-your-api-key-here
# Security
JWT_SECRET=your_supabase_jwt_secret_here
ALLOWED_ORIGINS=http://localhost:3000
# Database Connection Pool
DB_POOL_SIZE=10
DB_MAX_OVERFLOW=5
DB_POOL_TIMEOUT=30Optional Variables:
# Application
ENVIRONMENT=production
PORT=8000
LOG_LEVEL=info
# Service Role (admin operations only)
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key_hereCreate frontend/.env.local from the example:
cp frontend/.env.local.example frontend/.env.localRequired Variables:
# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key_here
# Backend API URL
NEXT_PUBLIC_API_URL=http://localhost:8000Production Variables:
# Use your deployed backend URL
NEXT_PUBLIC_API_URL=https://your-backend.railway.appThe docker-compose.yml automatically loads environment files:
- Backend:
./backend/.env - Frontend:
./frontend/.env.local
You can override variables in docker-compose.yml:
services:
backend:
environment:
- LOG_LEVEL=debug
- DB_POOL_SIZE=20The docker-compose configuration includes production-ready resource limits:
Backend:
- CPU: 1.0 core (limit), 0.5 core (reservation)
- Memory: 512MB (limit), 256MB (reservation)
Frontend:
- CPU: 0.5 core (limit), 0.25 core (reservation)
- Memory: 256MB (limit), 128MB (reservation)
Both services use restart: on-failure:3:
- Automatically restart on failure
- Maximum 3 restart attempts
- Prevents infinite restart loops
Built-in health checks monitor service availability:
Backend Health Check:
# Runs every 30 seconds
curl http://localhost:8000/healthFrontend Health Check:
# Runs every 30 seconds
curl http://localhost:3000/api/healthBefore deploying to production:
- Update environment variables with production values
- Set
ENVIRONMENT=productionin backend - Update
ALLOWED_ORIGINSwith production domain - Use production Supabase project
- Configure proper logging (structured JSON)
- Set up monitoring and alerting
- Configure backup strategy
- Test health check endpoints
- Review resource limits
- Enable HTTPS/TLS
- Set up reverse proxy (nginx/Caddy)
# Install Railway CLI
npm install -g @railway/cli
# Login
railway login
# Deploy backend
cd backend
railway up# Install Vercel CLI
npm install -g vercel
# Login
vercel login
# Deploy frontend
cd frontend
vercel --prodPush images to a registry for deployment:
# Tag images
docker tag studyquest-backend:latest your-registry/studyquest-backend:latest
docker tag studyquest-frontend:latest your-registry/studyquest-frontend:latest
# Push to registry
docker push your-registry/studyquest-backend:latest
docker push your-registry/studyquest-frontend:latestBasic Health Check:
# Backend
curl http://localhost:8000/health
# Response:
# {
# "status": "healthy",
# "timestamp": "2025-11-22T10:30:00.000Z"
# }Detailed Health Check:
# Backend with dependency status
curl http://localhost:8000/health/detailed
# Response:
# {
# "status": "healthy",
# "timestamp": "2025-11-22T10:30:00.000Z",
# "dependencies": {
# "supabase": {
# "status": "healthy",
# "response_time_ms": 45
# },
# "openrouter": {
# "status": "healthy"
# }
# }
# }Frontend Health Check:
curl http://localhost:3000/api/health
# Response:
# {
# "status": "healthy",
# "backend": "connected",
# "supabase": "connected"
# }Check container health status:
# View health status
docker ps
# Inspect health check details
docker inspect studyquest-backend | grep -A 10 Health
docker inspect studyquest-frontend | grep -A 10 HealthSymptom: docker-compose up fails or containers exit immediately
Solutions:
# Check logs for errors
docker-compose logs backend
docker-compose logs frontend
# Verify environment variables
docker-compose config
# Check if ports are already in use
lsof -i :3000
lsof -i :8000
# Remove old containers and try again
docker-compose down
docker-compose up -dSymptom: Application can't connect to Supabase or OpenRouter
Solutions:
# Verify .env files exist
ls -la backend/.env
ls -la frontend/.env.local
# Check if variables are loaded
docker-compose exec backend env | grep SUPABASE
docker-compose exec frontend env | grep NEXT_PUBLIC
# Rebuild with no cache
docker-compose down
docker-compose build --no-cache
docker-compose up -dSymptom: API calls fail with CORS or connection errors
Solutions:
# Check backend is running
curl http://localhost:8000/health
# Verify ALLOWED_ORIGINS in backend/.env
# Should include: http://localhost:3000
# Check docker network
docker network inspect studyquest_studyquest-network
# Restart both services
docker-compose restartSymptom: Backend logs show Supabase connection failures
Solutions:
# Verify Supabase credentials
# Check SUPABASE_URL and SUPABASE_KEY in backend/.env
# Test connection manually
docker-compose exec backend python -c "
from config.supabase_client import get_supabase_client
client = get_supabase_client()
print(client.table('users').select('user_id').limit(1).execute())
"
# Check connection pool settings
# Increase DB_POOL_SIZE if neededSymptom: Containers crash with OOM (Out of Memory) errors
Solutions:
# Check memory usage
docker stats
# Increase memory limits in docker-compose.yml
# Backend: 512M → 1G
# Frontend: 256M → 512M
# Restart with new limits
docker-compose down
docker-compose up -dSymptom: docker build or docker-compose build fails
Solutions:
# Clear Docker cache
docker builder prune -a
# Build with verbose output
docker-compose build --progress=plain
# Check Dockerfile syntax
docker build --no-cache -t test-build ./backend
# Verify dependencies
# Backend: Check requirements.txt
# Frontend: Check package.jsonSymptom: Containers show "unhealthy" status
Solutions:
# Check health check logs
docker inspect studyquest-backend --format='{{json .State.Health}}'
# Test health endpoint manually
docker-compose exec backend curl http://localhost:8000/health
# Increase health check timeout in docker-compose.yml
# timeout: 10s → 30s
# Check if application is actually running
docker-compose exec backend ps auxRun containers in debug mode for troubleshooting:
# Run backend with shell access
docker-compose run --rm backend /bin/bash
# Run frontend with shell access
docker-compose run --rm frontend /bin/sh
# Execute commands in running container
docker-compose exec backend python --version
docker-compose exec frontend node --version# View structured logs (JSON format)
docker-compose logs backend | jq .
# Monitor resource usage
docker stats studyquest-backend studyquest-frontend
# Export logs to file
docker-compose logs > logs.txt
# Follow logs with timestamps
docker-compose logs -f -tIf all else fails, start fresh:
# Stop everything
docker-compose down -v
# Remove all StudyQuest images
docker rmi studyquest-backend studyquest-frontend
# Remove dangling images
docker image prune -a
# Rebuild from scratch
docker-compose build --no-cache
docker-compose up -dCurrent image sizes:
- Backend: ~200MB (Python slim)
- Frontend: ~150MB (Node Alpine)
Tips for further optimization:
- Use
.dockerignoreto exclude unnecessary files - Minimize layers in Dockerfile
- Use multi-stage builds (already implemented)
- Clean up package manager cache
# Use BuildKit for faster builds
DOCKER_BUILDKIT=1 docker-compose build
# Cache dependencies separately
# Already implemented in multi-stage builds
# Parallel builds
docker-compose build --parallel- Adjust resource limits based on actual usage
- Monitor with
docker stats - Use connection pooling (already configured)
- Enable response caching in application
✅ Already Implemented:
- Non-root users in containers
- Multi-stage builds (minimal attack surface)
- Health checks for monitoring
- Resource limits to prevent DoS
- Environment variable isolation
🔒 Additional Recommendations:
- Use Docker secrets for sensitive data
- Scan images for vulnerabilities:
docker scan studyquest-backend - Keep base images updated
- Use specific image tags (not
latest) - Enable Docker Content Trust
- Run containers in read-only mode where possible
- Review CI/CD Guide for automated deployments
- Check Operations Runbook for monitoring
- See Production Deployment Guide for cloud deployment
For issues or questions:
- Check logs:
docker-compose logs - Review health checks:
curl http://localhost:8000/health/detailed - Consult troubleshooting section above
- Open an issue on GitHub