Quick Start
The fastest way to deploy Codex-LB is using Docker with a named volume for data persistence:
# Create a named volume for data persistence
docker volume create codex-lb-data
# Run the container
docker run -d --name codex-lb \
-p 2455:2455 -p 1455:1455 \
-v codex-lb-data:/var/lib/codex-lb \
ghcr.io/soju06/codex-lb:latest
Open http://localhost:2455 in your browser to access the dashboard.
Port Mapping
Codex-LB requires two ports:
| Port | Purpose | Description |
|---|
| 2455 | Main API & Dashboard | Primary endpoint for API requests and web dashboard |
| 1455 | OAuth Callback | OAuth authentication callback endpoint (required for account login) |
Port 1455 cannot be changed. OpenAI’s OAuth flow requires this specific port for the redirect URI.
Volume Mounts
Data Directory
All persistent data is stored in /var/lib/codex-lb/ inside the container:
# Using a named volume (recommended)
-v codex-lb-data:/var/lib/codex-lb
# Using a bind mount (alternative)
-v /path/on/host:/var/lib/codex-lb
This directory contains:
- Database:
store.db (SQLite by default)
- Encryption keys:
encryption.key
- Backup files: Automatic pre-migration backups (if enabled)
Environment Configuration
You can provide environment variables using:
# Using --env-file
docker run -d --name codex-lb \
--env-file .env.local \
-p 2455:2455 -p 1455:1455 \
-v codex-lb-data:/var/lib/codex-lb \
ghcr.io/soju06/codex-lb:latest
# Using individual -e flags
docker run -d --name codex-lb \
-e CODEX_LB_DATABASE_URL=postgresql+asyncpg://... \
-e CODEX_LB_OAUTH_REDIRECT_URI=http://localhost:1455/auth/callback \
-p 2455:2455 -p 1455:1455 \
-v codex-lb-data:/var/lib/codex-lb \
ghcr.io/soju06/codex-lb:latest
See Configuration for all available options.
Docker Compose
Basic Setup
Create a docker-compose.yml file:
services:
codex-lb:
image: ghcr.io/soju06/codex-lb:latest
ports:
- "2455:2455"
- "1455:1455"
volumes:
- codex-lb-data:/var/lib/codex-lb
env_file:
- .env.local
restart: unless-stopped
volumes:
codex-lb-data:
name: codex-lb-data
Start the service:
With PostgreSQL
For production deployments with higher concurrency, use PostgreSQL:
services:
codex-lb:
image: ghcr.io/soju06/codex-lb:latest
ports:
- "2455:2455"
- "1455:1455"
volumes:
- codex-lb-data:/var/lib/codex-lb
environment:
CODEX_LB_DATABASE_URL: postgresql+asyncpg://codex_lb:codex_lb@postgres:5432/codex_lb
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: codex_lb
POSTGRES_PASSWORD: codex_lb
POSTGRES_DB: codex_lb
ports:
- "5432:5432"
volumes:
- codex-lb-postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U codex_lb -d codex_lb"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
volumes:
codex-lb-data:
name: codex-lb-data
codex-lb-postgres-data:
name: codex-lb-postgres-data
PostgreSQL is optional. SQLite is sufficient for most deployments and provides zero-config startup.
Database Migrations
Automatic Migrations
By default, Codex-LB runs database migrations automatically on startup:
# Enabled by default
CODEX_LB_DATABASE_MIGRATE_ON_STARTUP=true
The Docker entrypoint script (/app/scripts/docker-entrypoint.sh) executes:
#!/bin/sh
set -eu
python -m app.db.migrate upgrade
export CODEX_LB_DATABASE_MIGRATE_ON_STARTUP=false
exec fastapi run --host 0.0.0.0 --port 2455
SQLite Backup Before Migration
SQLite databases are automatically backed up before migrations:
# Enabled by default
CODEX_LB_DATABASE_SQLITE_PRE_MIGRATE_BACKUP_ENABLED=true
CODEX_LB_DATABASE_SQLITE_PRE_MIGRATE_BACKUP_MAX_FILES=5
Backup files are stored in the data directory with timestamps.
Manual Migrations
To run migrations manually:
# Using docker exec
docker exec codex-lb python -m app.db.migrate upgrade
# Using docker compose
docker compose exec codex-lb python -m app.db.migrate upgrade
Migration Validation
Check migration status and validate schema:
# Check current revision
docker exec codex-lb python -m app.db.migrate current
# Validate migrations (checks head count, naming, drift)
docker exec codex-lb codex-lb-db check
Backup and Restore
Backing Up Data
Using Docker Volumes
# Stop the container
docker stop codex-lb
# Create a backup tarball
docker run --rm \
-v codex-lb-data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/codex-lb-backup-$(date +%Y%m%d-%H%M%S).tar.gz -C /data .
# Restart the container
docker start codex-lb
Using Bind Mounts
If you’re using a bind mount, simply copy the directory:
cp -r /path/to/codex-lb-data /path/to/backup-$(date +%Y%m%d-%H%M%S)
PostgreSQL Backup
For PostgreSQL deployments:
# Dump the database
docker compose exec postgres pg_dump -U codex_lb codex_lb > backup-$(date +%Y%m%d-%H%M%S).sql
# Or using pg_dumpall for all databases
docker compose exec postgres pg_dumpall -U codex_lb > backup-all-$(date +%Y%m%d-%H%M%S).sql
Restoring Data
Restoring SQLite from Volume Backup
# Stop the container
docker stop codex-lb
# Restore from tarball
docker run --rm \
-v codex-lb-data:/data \
-v $(pwd):/backup \
alpine sh -c "cd /data && rm -rf * && tar xzf /backup/codex-lb-backup-TIMESTAMP.tar.gz"
# Restart the container
docker start codex-lb
Restoring PostgreSQL
# Restore from SQL dump
docker compose exec -T postgres psql -U codex_lb codex_lb < backup-TIMESTAMP.sql
If your SQLite database becomes corrupted:
# Attempt recovery
docker exec codex-lb python -m app.db.recover \
--input /var/lib/codex-lb/store.db \
--output /var/lib/codex-lb/store-recovered.db
# If successful, replace the original
docker exec codex-lb sh -c \
"mv /var/lib/codex-lb/store.db /var/lib/codex-lb/store.db.old && \
mv /var/lib/codex-lb/store-recovered.db /var/lib/codex-lb/store.db"
# Restart the container
docker restart codex-lb
Health Checks
Built-in Health Endpoint
Codex-LB provides a health check endpoint:
curl http://localhost:2455/health
Response:
Docker Health Check
Add a health check to your docker-compose.yml:
services:
codex-lb:
image: ghcr.io/soju06/codex-lb:latest
ports:
- "2455:2455"
- "1455:1455"
volumes:
- codex-lb-data:/var/lib/codex-lb
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:2455/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped
Or with plain Docker:
docker run -d --name codex-lb \
-p 2455:2455 -p 1455:1455 \
-v codex-lb-data:/var/lib/codex-lb \
--health-cmd="curl -f http://localhost:2455/health || exit 1" \
--health-interval=30s \
--health-timeout=10s \
--health-retries=3 \
--health-start-period=40s \
ghcr.io/soju06/codex-lb:latest
Container Management
Viewing Logs
# Follow logs
docker logs -f codex-lb
# Last 100 lines
docker logs --tail 100 codex-lb
# With Docker Compose
docker compose logs -f codex-lb
Restarting
# Restart the container
docker restart codex-lb
# Or with Docker Compose
docker compose restart codex-lb
Updating
# Pull the latest image
docker pull ghcr.io/soju06/codex-lb:latest
# Stop and remove the old container
docker stop codex-lb
docker rm codex-lb
# Start with the new image
docker run -d --name codex-lb \
-p 2455:2455 -p 1455:1455 \
-v codex-lb-data:/var/lib/codex-lb \
ghcr.io/soju06/codex-lb:latest
With Docker Compose:
docker compose pull
docker compose up -d
Troubleshooting
Container Won’t Start
Check logs for errors:
Common issues:
- Port already in use: Another service is using port 2455 or 1455
- Permission denied: Volume mount permissions issue
- Database migration failed: Check migration logs
Database Issues
Verify database connectivity:
# Check current database revision
docker exec codex-lb python -m app.db.migrate current
# Validate database integrity (SQLite)
docker exec codex-lb sqlite3 /var/lib/codex-lb/store.db "PRAGMA integrity_check;"
Reset Everything
To start fresh:
# Stop and remove container
docker stop codex-lb
docker rm codex-lb
# Remove the volume (WARNING: This deletes all data!)
docker volume rm codex-lb-data
# Recreate and start
docker volume create codex-lb-data
docker run -d --name codex-lb \
-p 2455:2455 -p 1455:1455 \
-v codex-lb-data:/var/lib/codex-lb \
ghcr.io/soju06/codex-lb:latest
Next Steps