Self-Hosting
By default, RootCX manages the infrastructure for you -- create a project on rootcx.com and a dedicated Core instance is provisioned automatically. This guide is for teams that need to run the Core on their own servers.
Quick start
The Core requires an external PostgreSQL database. The easiest way to get started is with Docker Compose:
# docker-compose.yml
services:
postgres:
image: ghcr.io/rootcx/postgresql:16-pgmq
user: root
entrypoint: ["/pg-entrypoint.sh"]
environment:
POSTGRES_USER: rootcx
POSTGRES_PASSWORD: rootcx
POSTGRES_DB: rootcx
PGDATA: /data/pgdata
volumes:
- pgdata:/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U rootcx -d rootcx"]
interval: 2s
timeout: 5s
retries: 10
core:
image: ghcr.io/rootcx/core:latest
depends_on:
postgres:
condition: service_healthy
environment:
DATABASE_URL: postgres://rootcx:rootcx@postgres:5432/rootcx
ports:
- "9100:9100"
volumes:
- data:/data
volumes:
pgdata:
data:
docker compose up -d
Verify it is running:
curl http://localhost:9100/health
# {"status":"ok"}
ghcr.io/rootcx/postgresql:16-pgmq image is PostgreSQL 16 with the pgmq extension pre-installed, which the Core uses for its job queue. You can use any PostgreSQL 16+ instance as long as the pgmq extension is available.Environment variables
DATABASE_URL is required. All other variables are optional for local development. For production, set explicit secrets.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
— (required) | PostgreSQL connection URL (e.g. postgres://user:pass@host:5432/db). |
ROOTCX_BIND |
not set | Set to any value to listen on 0.0.0.0 instead of 127.0.0.1. Required for remote access. |
ROOTCX_JWT_SECRET |
Auto-generated | String (min 32 characters) for JWT signing. Auto-generated in config/jwt.key if not set. |
ROOTCX_MASTER_KEY |
Auto-generated | Hex-encoded 32-byte key for AES-256-GCM encryption. Auto-generated in config/master.key if not set. |
ROOTCX_PUBLIC_URL |
not set | Public URL for OIDC callbacks (e.g. https://core.example.com). Falls back to ROOTCX_URL. |
ROOTCX_URL |
not set | Core instance URL (used as fallback for ROOTCX_PUBLIC_URL). |
RUST_LOG |
info |
Log filter. Values: trace, debug, info, warn, error. |
ROOTCX_OIDC_ISSUER |
not set | URL of your OIDC identity provider (e.g., Okta, Azure AD, Google). Seeds a provider on first boot. |
ROOTCX_OIDC_CLIENT_ID |
not set | Client ID for your OIDC provider. Required if ROOTCX_OIDC_ISSUER is set. |
ROOTCX_OIDC_CLIENT_SECRET |
not set | Client Secret for your OIDC provider. Required if ROOTCX_OIDC_ISSUER is set. Encrypted in the vault. |
ROOTCX_DISABLE_PASSWORD_LOGIN |
not set | Set to true or 1 to disable email/password login. A first-user bypass allows initial registration even when set. |
ROOTCX_JWT_SECRET and ROOTCX_MASTER_KEY. Relying on auto-generated secrets means losing them if the container is recreated without persistent storage.Development database
For local development, you can expose the PostgreSQL port to connect directly:
# docker-compose.dev.yml
services:
postgres:
image: ghcr.io/rootcx/postgresql:16-pgmq
user: root
entrypoint: ["/pg-entrypoint.sh"]
environment:
POSTGRES_USER: rootcx
POSTGRES_PASSWORD: rootcx
POSTGRES_DB: rootcx
PGDATA: /data/pgdata
volumes:
- pgdata-dev:/data
ports:
- "5480:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U rootcx -d rootcx"]
interval: 2s
timeout: 5s
retries: 10
volumes:
pgdata-dev:
psql -h 127.0.0.1 -p 5480 -U rootcx -d rootcx
Managed database
For teams using a managed database (RDS, Cloud SQL, etc.), point DATABASE_URL at your instance. Ensure the pgmq extension is available — on AWS RDS, enable it via the shared_preload_libraries parameter group.
docker run -d \
--name rootcx-core \
-p 9100:9100 \
-e DATABASE_URL=postgres://user:pass@your-rds-host:5432/rootcx \
-e ROOTCX_BIND=1 \
-e ROOTCX_JWT_SECRET="your-secret-min-32-characters-here" \
-e ROOTCX_MASTER_KEY="hex-encoded-32-byte-key" \
ghcr.io/rootcx/core:latest
Health checks
Use these endpoints for load balancer or orchestrator health checks:
# Liveness
curl http://localhost:9100/health
# {"status":"ok"}
# Detailed status
curl http://localhost:9100/api/v1/status
The Docker image includes a built-in health check (curl -fs http://localhost:9100/health) with a 10-second interval.
Connecting Studio
Once your self-hosted Core is running and reachable, open RootCX Studio, select Connect to a server, and paste your Core URL.