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.
Run Paperclip AI in Docker, understand the three-container architecture, and configure the production environment file.
# docker-compose.yml
services:
postgres: # PostgreSQL database
api: # Paperclip API server (Express.js)
frontend: # Vite React SPA served by Nginx
docker-compose.ymlversion: '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:
.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
# 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
# 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 * * * *
docker compose up -d --build