Skip to main content
The server ships with a Docker Compose file that bundles Postgres, MinIO (S3-compatible), and the BlindCast server.

Quick start

cd packages/server

# Generate required secrets
export MASTER_KEY_HEX=$(openssl rand -hex 32)
export SALT_HEX=$(openssl rand -hex 32)

# Start all services
docker compose up -d
The stack is healthy when all three services are running:
docker compose ps
# NAME        STATUS
# postgres    healthy
# minio       healthy
# blindcast   healthy
Open http://localhost:4100/admin to access the admin dashboard.

Environment variables

Required

VariableDescriptionExample
MASTER_KEY_HEXMaster key as hex (32+ bytes)openssl rand -hex 32
SALT_HEXSalt as hex (32 bytes)openssl rand -hex 32

Database

VariableDefaultDescription
DATABASE_URLBundled PostgresPostgreSQL connection string
POSTGRES_PASSWORDblindcast-dev-onlyPassword for bundled Postgres

S3 / Storage

VariableDefaultDescription
S3_BUCKETblindcast-segmentsS3 bucket name. Setting this enables presign.
S3_ENDPOINThttp://minio:9000S3 endpoint URL (for MinIO/R2)
S3_REGIONus-east-1AWS region
AWS_ACCESS_KEY_IDblindcastS3 access key
AWS_SECRET_ACCESS_KEYblindcast-dev-onlyS3 secret key

Authentication

VariableDefaultDescription
CORS_ORIGINS*Allowed CORS origins (comma-separated)
ADMIN_API_KEYBootstrap admin API key (skips setup wizard)
AUTH_JWT_SECRETHS256 secret for viewer JWT auth
AUTH_JWKS_URLJWKS URL for RS256/ES256 viewer auth
AUTH_JWT_AUDIENCEExpected JWT audience claim

Optional

VariableDefaultDescription
PORT4100Server listen port
LEASE_TTL_MSLease duration in ms (requires auth)
ENABLE_PRESIGNAutoExplicitly enable/disable presign (true/false)

Bring your own Postgres

To use an external Postgres instance, set DATABASE_URL and remove the postgres service from docker-compose.yml:
services:
  blindcast:
    # ...
    environment:
      DATABASE_URL: postgresql://user:password@your-host:5432/blindcast
The server creates tables automatically on startup (CREATE TABLE IF NOT EXISTS).

Bring your own S3

Replace MinIO with any S3-compatible storage (AWS S3, Cloudflare R2, Backblaze B2):
services:
  blindcast:
    environment:
      S3_BUCKET: your-bucket
      S3_REGION: us-west-2
      AWS_ACCESS_KEY_ID: AKIA...
      AWS_SECRET_ACCESS_KEY: ...
      # Omit S3_ENDPOINT to use real AWS S3
      # For R2: S3_ENDPOINT=https://<account>.r2.cloudflarestorage.com

Production considerations

The default docker-compose.yml uses dev-only passwords. For production:
  1. Set strong POSTGRES_PASSWORD and AWS_SECRET_ACCESS_KEY values
  2. Use a managed Postgres instance (RDS, Cloud SQL, etc.)
  3. Set CORS_ORIGINS to your specific domain(s)
  4. Configure viewer auth (AUTH_JWT_SECRET or AUTH_JWKS_URL)

Persistent data

The Compose file defines three named volumes:
VolumePurpose
postgres-dataPostgres database files
minio-dataMinIO object storage
blindcast-dataServer data directory

Health checks

All services include health checks:
  • Postgres: pg_isready
  • MinIO: GET /minio/health/live
  • BlindCast: GET /health

Building from source

# From the repository root
docker compose -f packages/server/docker-compose.yml build
The multi-stage Dockerfile builds @blindcast/crypto, @blindcast/keys, @blindcast/storage, and @blindcast/server in sequence, then creates a minimal production image.

Next steps