Deploy the AI Interview Simulator using Docker and Docker Compose.
- Prerequisites
- Quick Start
- Configuration
- Production Deployment
- Docker Commands Reference
- Troubleshooting
| Requirement | Version | Check Command |
|---|---|---|
| Docker | 24+ | docker --version |
| Docker Compose | 2.20+ | docker compose version |
Ubuntu/Debian
# Install Docker
curl -fsSL https://get.docker.com | sh
# Add your user to docker group
sudo usermod -aG docker $USER
# Log out and back in, then verify
docker run hello-worldmacOS
Download and install Docker Desktop for Mac
Windows
Download and install Docker Desktop for Windows
git clone https://github.com/dkirichev/interviewSimulator.git
cd interviewSimulatorcat > .env << 'EOF'
# Database Configuration
DB_HOST=postgres
DB_PORT=5432
DB_NAME=interview_simulator
DB_USERNAME=postgres
DB_PASSWORD=your_secure_password_here
# Application Mode (PROD = users provide their own API key)
# REVIEWER = hide API modal, use multi-key rotation (for competition judges)
APP_MODE=PROD
# Optional: Only needed in DEV mode
# GEMINI_API_KEY=AIza...
# Optional: Only needed in REVIEWER mode
# GEMINI_REVIEWER_KEYS=AIza...key1,AIza...key2,AIza...key3
# GEMINI_GRADING_MODELS=gemini-3-flash-preview,gemini-2.5-flash,gemini-2.5-flash-lite,gemma-3-12b-it
EOFdocker compose up -dOpen your browser at: http://localhost:8080
Navigate to: http://localhost:8080/admin
Default credentials: admin / noit2026P4$$
⚠️ Change the default password immediately via the admin dashboard.
The project includes a docker-compose.yml:
services:
# PostgreSQL Database
postgres:
image: postgres:16-alpine
container_name: interview-db
environment:
POSTGRES_DB: ${DB_NAME:-interview_simulator}
POSTGRES_USER: ${DB_USERNAME:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-secret}
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME:-postgres}"]
interval: 10s
timeout: 5s
retries: 5
# Spring Boot Application
app:
build:
context: .
dockerfile: Dockerfile
container_name: interview-app
ports:
- "8080:8080"
environment:
APP_MODE: ${APP_MODE:-PROD}
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: ${DB_NAME:-interview_simulator}
DB_USERNAME: ${DB_USERNAME:-postgres}
DB_PASSWORD: ${DB_PASSWORD:-secret}
GEMINI_API_KEY: ${GEMINI_API_KEY:-}
GEMINI_REVIEWER_KEYS: ${GEMINI_REVIEWER_KEYS:-}
GEMINI_GRADING_MODELS: ${GEMINI_GRADING_MODELS:-gemini-3-flash-preview,gemini-2.5-flash,gemini-2.5-flash-lite,gemma-3-12b-it}
JAVA_OPTS: ${JAVA_OPTS:-"-Xmx512m -Xms256m"}
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
volumes:
postgres_data:# Build stage
FROM eclipse-temurin:25-jdk-alpine AS builder
WORKDIR /app
RUN apk add --no-cache bash
COPY mvnw pom.xml ./
COPY .mvn .mvn
COPY package.json package-lock.json tailwind.config.js ./
RUN chmod +x mvnw && ./mvnw dependency:go-offline -B
COPY src src
RUN ./mvnw clean package -DskipTests -B
# Runtime stage
FROM eclipse-temurin:25-jre-alpine
WORKDIR /app
RUN addgroup -g 1001 -S appgroup && \
adduser -u 1001 -S appuser -G appgroup
COPY --from=builder /app/target/*.jar app.jar
RUN chown -R appuser:appgroup /app
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
CMD wget -q --spider http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-jar", "app.jar"]- Use PROD mode - Users provide their own API keys
- Strong database password - Use a randomly generated password
- HTTPS - Use a reverse proxy (nginx/Traefik) with SSL
- Firewall - Only expose port 443, keep 5432 internal
services:
traefik:
image: traefik:v3.0
command:
- "--api.insecure=false"
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.email=your@email.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
app:
# ... existing app config ...
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`interview.yourdomain.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"| Variable | Required | Default | Description |
|---|---|---|---|
APP_MODE |
Yes | - | DEV, PROD, or REVIEWER |
DB_HOST |
Yes | - | Database hostname |
DB_PORT |
Yes | 5432 |
Database port |
DB_NAME |
Yes | - | Database name |
DB_USERNAME |
Yes | - | Database user |
DB_PASSWORD |
Yes | - | Database password |
GEMINI_API_KEY |
DEV only | - | Backend API key (ignored in PROD/REVIEWER) |
GEMINI_REVIEWER_KEYS |
REVIEWER only | - | Comma-separated API keys for model rotation |
GEMINI_GRADING_MODELS |
No | gemini-3-flash-preview,gemini-2.5-flash,gemini-2.5-flash-lite,gemma-3-12b-it |
Grading model fallback chain |
# Start in background
docker compose up -d
# Start with build (after code changes)
docker compose up -d --build
# Start specific service
docker compose up -d postgres# All services
docker compose logs -f
# Specific service
docker compose logs -f app
# Last 100 lines
docker compose logs --tail=100 app# Stop all services
docker compose down
# Stop and remove volumes (deletes database!)
docker compose down -v# View running containers
docker compose ps
# Restart a service
docker compose restart app
# Execute command in container
docker compose exec app sh
# View database
docker compose exec postgres psql -U postgres -d interview_simulator# Rebuild image
docker compose build
# Rebuild without cache
docker compose build --no-cache
# Pull latest base images
docker compose pull# Check logs
docker compose logs app
# Common issues:
# - Database not ready: check postgres health
# - Missing env vars: verify .env fileCould not create connection to database server
Solution: Ensure PostgreSQL is healthy:
docker compose ps # Check status
docker compose logs postgres # Check logsBind for 0.0.0.0:8080 failed: port is already allocated
Solution: Change the port in docker-compose.yml:
ports:
- "8081:8080" # Use port 8081 externallyjava.lang.OutOfMemoryError: Java heap space
Solution: Add memory limits:
app:
environment:
JAVA_OPTS: "-Xmx512m -Xms256m"# Stop containers and remove all data
docker compose down -v
# Remove unused images
docker system prune -acurl http://localhost:8080/actuator/healthdocker compose exec postgres pg_isready -U postgresdocker compose exec postgres pg_dump -U postgres interview_simulator > backup.sqlcat backup.sql | docker compose exec -T postgres psql -U postgres interview_simulator