Skip to content

Stateless Docker Compose

This Docker Compose configuration runs only the application containers (frontend, backend, publisher) and connects to external managed services for PostgreSQL, Redis, and S3-compatible storage. This is the recommended setup for:

  • Production environments
  • High-availability deployments
  • Kubernetes or container orchestration platforms
  • Environments with managed database services (AWS RDS, DigitalOcean, Neon, etc.)

Use this configuration when:

  • You have access to managed PostgreSQL, Redis, and S3 storage services
  • You need horizontal scaling (multiple backend/publisher instances)
  • You want to separate compute from storage
  • You’re deploying in a high-availability environment

For simpler deployments or local installations, consider using the Stateful Docker Compose configuration instead.

# Production Docker Compose - Uses pre-built images from GHCR
# Usage: docker compose -f docker-compose.prod.yml up -d
#
# Requires external services:
# - PostgreSQL database
# - Redis instance
# - S3-compatible storage (AWS S3, Cloudflare R2, etc.)
services:
backend:
image: ghcr.io/isekai-sh/isekai-backend:${IMAGE_TAG:-latest}
container_name: isekai-backend
ports:
- "${BACKEND_PORT:-4000}:4000"
environment:
# Database & Cache (Must be set in .env)
DATABASE_URL: ${DATABASE_URL}
REDIS_URL: ${REDIS_URL}
# Application Config
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:3000}
PORT: 4000
NODE_ENV: production
# Security
SESSION_SECRET: ${SESSION_SECRET}
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
COOKIE_DOMAIN: ${COOKIE_DOMAIN:-}
SESSION_MAX_AGE_DAYS: ${SESSION_MAX_AGE_DAYS:-7}
REFRESH_TOKEN_EXPIRY_DAYS: ${REFRESH_TOKEN_EXPIRY_DAYS:-90}
# DeviantArt OAuth
DEVIANTART_CLIENT_ID: ${DEVIANTART_CLIENT_ID}
DEVIANTART_CLIENT_SECRET: ${DEVIANTART_CLIENT_SECRET}
DEVIANTART_REDIRECT_URI: ${DEVIANTART_REDIRECT_URI}
# S3-Compatible Storage
S3_ENDPOINT: ${S3_ENDPOINT}
S3_REGION: ${S3_REGION:-us-east-1}
S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID}
S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY}
S3_BUCKET_NAME: ${S3_BUCKET_NAME:-isekai-uploads}
S3_PUBLIC_URL: ${S3_PUBLIC_URL}
S3_FORCE_PATH_STYLE: ${S3_FORCE_PATH_STYLE:-false}
SESSION_STORE: ${SESSION_STORE:-redis}
env_file:
- .env
restart: always
networks:
- isekai-network
healthcheck:
test:
[
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"http://localhost:4000/api/health",
]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
publisher:
image: ghcr.io/isekai-sh/isekai-publisher:${IMAGE_TAG:-latest}
container_name: isekai-publisher
ports:
- "${PUBLISHER_HEALTH_PORT:-8000}:8000"
environment:
DATABASE_URL: ${DATABASE_URL}
REDIS_URL: ${REDIS_URL}
NODE_ENV: production
DEVIANTART_CLIENT_ID: ${DEVIANTART_CLIENT_ID}
DEVIANTART_CLIENT_SECRET: ${DEVIANTART_CLIENT_SECRET}
# S3-Compatible Storage
S3_ENDPOINT: ${S3_ENDPOINT}
S3_REGION: ${S3_REGION:-us-east-1}
S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID}
S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY}
S3_BUCKET_NAME: ${S3_BUCKET_NAME:-isekai-uploads}
S3_PUBLIC_URL: ${S3_PUBLIC_URL}
S3_FORCE_PATH_STYLE: ${S3_FORCE_PATH_STYLE:-false}
# Publisher Tuning
PUBLISHER_CONCURRENCY: ${PUBLISHER_CONCURRENCY:-5}
PUBLISHER_MAX_ATTEMPTS: ${PUBLISHER_MAX_ATTEMPTS:-7}
PUBLISHER_JOB_TIMEOUT_MS: ${PUBLISHER_JOB_TIMEOUT_MS:-600000}
HEALTH_CHECK_PORT: 8000
HEALTH_CHECK_ENABLED: true
env_file:
- .env
restart: always
networks:
- isekai-network
healthcheck:
test:
[
"CMD-SHELL",
"wget --no-verbose --tries=1 --spider http://localhost:8000/health || exit 1",
]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
frontend:
image: ghcr.io/isekai-sh/isekai-frontend:${IMAGE_TAG:-latest}
container_name: isekai-frontend
ports:
- "${FRONTEND_PORT:-3000}:80"
environment:
VITE_API_URL: ${VITE_API_URL}
VITE_DEVIANTART_CLIENT_ID: ${DEVIANTART_CLIENT_ID}
VITE_S3_PUBLIC_URL: ${S3_PUBLIC_URL}
env_file:
- .env
depends_on:
- backend
restart: always
networks:
- isekai-network
healthcheck:
test:
[
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"http://localhost:80/",
]
interval: 30s
timeout: 10s
retries: 3
networks:
isekai-network:
driver: bridge
  • Image: ghcr.io/isekai-sh/isekai-backend
  • Purpose: API server, authentication, and job scheduling
  • External Dependencies: Managed PostgreSQL, Redis, and S3 storage
  • Port: 4000 (configurable via BACKEND_PORT)
  • Image: ghcr.io/isekai-sh/isekai-publisher
  • Purpose: Background worker for publishing to DeviantArt
  • External Dependencies: Managed PostgreSQL, Redis, and S3 storage
  • Port: 8000 (health check endpoint)
  • Scaling: Can run multiple instances for higher throughput
  • Image: ghcr.io/isekai-sh/isekai-frontend
  • Purpose: User interface (React SPA)
  • Dependencies: Backend API
  • Port: 80 internally, mapped to 3000 externally (configurable via FRONTEND_PORT)

Since this configuration uses external services, you must provide connection strings in your .env file:

Terminal window
# External Database (REQUIRED)
DATABASE_URL="postgresql://user:password@your-db-host:5432/isekai?sslmode=require"
# External Redis (REQUIRED)
REDIS_URL="rediss://default:password@your-redis-host:6379"
# S3-Compatible Storage (REQUIRED)
# See Storage Setup guide for provider-specific values
S3_ENDPOINT=https://your-storage-endpoint
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
S3_BUCKET_NAME=isekai-uploads
S3_PUBLIC_URL=https://your-public-url
# All other variables from the Environment Variables reference
# ...

See the Storage Setup guide for provider-specific S3 configuration (Cloudflare R2, AWS S3, DigitalOcean Spaces, etc.).

This configuration makes it easy to scale your deployment:

  • Backend: Scale to multiple instances behind a load balancer
  • Publisher: Scale to process more jobs concurrently
  • Frontend: Scale for high traffic (served via CDN recommended)
Terminal window
# Scale publisher to 3 instances
docker compose up -d --scale publisher=3