Docker & Docker Compose Setup

The provided docker-compose.yml: services (server, web, postgres), volume mounts for data persistence, environment variable injection via .env files, and the build/up workflow.

Docker Setup for Production

What you'll learn

Run Paperclip AI in Docker, understand the three-container architecture, and configure the production environment file.

The Three-Container Architecture

# docker-compose.yml
services:
  postgres:     # PostgreSQL database
  api:          # Paperclip API server (Express.js)
  frontend:     # Vite React SPA served by Nginx

The Official docker-compose.yml

version: '3.9'

services:
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB:       paperclip
      POSTGRES_USER:     paperclip
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./db/schema.sql:/docker-entrypoint-initdb.d/01-schema.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U paperclip"]
      interval: 10s
      timeout: 5s
      retries: 5

  api:
    build:
      context: .
      dockerfile: packages/server/Dockerfile
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      DATABASE_URL:       postgres://paperclip:${POSTGRES_PASSWORD}@postgres:5432/paperclip
      NODE_ENV:           production
      PORT:               3100
      ANTHROPIC_API_KEY:  ${ANTHROPIC_API_KEY}
      OPENAI_API_KEY:     ${OPENAI_API_KEY}
      JWT_SECRET:         ${JWT_SECRET}
    ports:
      - "3100:3100"

  frontend:
    build:
      context: .
      dockerfile: packages/frontend/Dockerfile
    restart: unless-stopped
    depends_on:
      - api
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/ssl/paperclip:ro  # your TLS certs

volumes:
  postgres_data:

The .env File

# .env (never commit this file)
POSTGRES_PASSWORD=change_me_in_production
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
JWT_SECRET=generate_with_openssl_rand_hex_32

Generate a secure JWT secret:

openssl rand -hex 32

Starting the Stack

# Build and start
docker compose up -d --build

# View logs
docker compose logs -f api

# Run database migrations
docker compose exec api pnpm db:migrate

# Seed the schema
docker compose exec api pnpm db:seed

Health Check

# API health
curl http://localhost:3100/health
# → {"status": "ok", "db": "connected", "version": "1.x.x"}

# Verify heartbeat scheduler is running
docker compose logs api | grep HEARTBEAT
# → [HEARTBEAT] company=... scheduled cron=*/5 * * * *

Checkpoint ✓

Sign in for progress tracking & Q&A →