Skip to content

Self-host - Docker Compose

Self-host OpenQuok with Docker Compose — env setup, Supabase, bring-up, and updates for API, web, Redis, and BullMQ workers.

5 min read

Connect your agent today

Draft from chat, review in your calendar, and publish only what you approve.

Start for $0

Overview

You run OpenQuok on your computer or private network with Docker Compose. The stack lives under infra/self-host/. It starts the API, web UI, Redis, and background workers.

Self-host defaults turn off email and billing. You can sign up without inbox verification or a paywall. See email and Stripe.

Prepare your environment file

Copy the example file from the repo root:

cp infra/self-host/.env.example infra/self-host/.env

Compose loads infra/self-host/.env into the API and workers. The web service does not load the full file. VITE_* values are set at web image build time.

Supabase (required)

You need a Supabase project before the first start. Apply OpenQuok migrations to that project. See Database & migrations and Supabase.

VariableRole
PUBLIC_SUPABASE_URLAPI / Auth URL
PUBLIC_SUPABASE_PUBLISHABLE_KEYPublishable key
SUPABASE_SECRET_KEYSecret key (server only)
VITE_PUBLIC_SUPABASE_URLSame URL for the web build
VITE_PUBLIC_SUPABASE_PUBLISHABLE_KEYSame publishable key for the web build

If Supabase runs on your host with supabase start, use http://host.docker.internal:54321 for the API URL (port from supabase status, not Postgres 5432).

Local-friendly defaults

EMAIL_ENABLED=false
STRIPE_PUBLISHABLE_KEY=
STRIPE_SECRET_KEY=
DISABLE_REGISTRATION=false
NOT_SECURED=true
FRONTEND_DOMAIN_URL=http://localhost:4007
BACKEND_DOMAIN_URL=http://localhost:3000
VITE_FRONTEND_DOMAIN_URL=http://localhost:4007
VITE_API_BASE_URL=

Set SECURITY_SECRET (for example openssl rand -hex 32). Leave VITE_API_BASE_URL empty so the web container proxies /api to the API service.

Use NOT_SECURED=true for plain HTTP on localhost. Set false behind HTTPS. With true, API rate limiting is off by default (see RATE_LIMIT_ENABLED in infra/self-host/.env.example).

Redis and uploads use Compose defaults (REDIS_HOST=redis, STORAGE_PROVIDER=local).

Social channels (optional)

Leave provider keys empty until you connect a channel. Fill only the networks you use. Then recreate API and workers. Setup guides: Social integration.

VariableChannel
FACEBOOK_APP_ID / FACEBOOK_APP_SECRETFacebook Page
INSTAGRAM_APP_ID / INSTAGRAM_APP_SECRETInstagram
THREADS_APP_ID / THREADS_APP_SECRETMeta Threads
YOUTUBE_CLIENT_ID / YOUTUBE_CLIENT_SECRETYouTube
TIKTOK_CLIENT_ID / TIKTOK_CLIENT_SECRETTikTok
LINKEDIN_CLIENT_ID / LINKEDIN_CLIENT_SECRETLinkedIn / LinkedIn Page
X_API_KEY / X_API_SECRETX

Dev.to uses a user API key in the dashboard; Bluesky uses an app password in Add Channel. You do not add operator env vars for either. See Dev.to and Bluesky.

For cutover windows, set MAINTENANCE_MODE and recreate containers. See Maintenance mode.

Install and start

Run all commands from the repository root.

Check requirements

See System requirements for Docker, disk space, and Supabase.

Edit .env

Copy infra/self-host/.env.example to infra/self-host/.env. Fill Supabase keys and SECURITY_SECRET.

Start the stack

Option A — Build everything (default)

docker compose -f infra/self-host/docker-compose.yml up --build

The first run can take 20–40 minutes or more. Later starts are faster. Add -d to run in the background.

Option B — Pull API and workers

Set in infra/self-host/.env:

OPENQUOK_IMAGE_REGISTRY=ghcr.io/ratimon
OPENQUOK_IMAGE_TAG=0.1.1

Then:

docker compose -f infra/self-host/docker-compose.yml -f infra/self-host/docker-compose.images.yml pull
docker compose -f infra/self-host/docker-compose.yml -f infra/self-host/docker-compose.images.yml up -d --build

Use the same two -f files for down, logs, and updates when you chose Option B.

Open the app

  • Web: http://localhost:4007
  • API: http://localhost:3000

Change the web port with OPENQUOK_WEB_HOST_PORT if 4007 is busy.

Optional: CLI login profile

For openquok auth:login device flow:

docker compose -f infra/self-host/docker-compose.yml --profile cli up --build

Register an OAuth app with redirect http://localhost:3111/device/callback. See Configuration - Agent.

Stop the stack

Option A:

docker compose -f infra/self-host/docker-compose.yml down

Option B (both compose files):

docker compose -f infra/self-host/docker-compose.yml -f infra/self-host/docker-compose.images.yml down

Add —profile cli if you used the CLI profile.

Start again

Reuse images when you did not change code or VITE_*:

docker compose -f infra/self-host/docker-compose.yml up -d --no-build

With Option B, add the second -f infra/self-host/docker-compose.images.yml file. Open http://localhost:4007 when containers are up.

Update

From the repo root:

git pull origin main
docker compose -f infra/self-host/docker-compose.yml up -d --build

For Option B, set a new OPENQUOK_IMAGE_TAG, then pull and up -d —build with both compose files.

If release notes mention database changes, run migrations on Supabase. Docker does not do that step. See Database & migrations.

What runs in the stack

ServiceRole
redisCache and job queue
apiBackend API
webWeb UI
worker-* (three)Background jobs
postgres / agent-serverOnly with —profile cli

Troubleshooting

If orchestrator build fails with already exists, update the repo or use Option B pull.

Security and exposure

This stack targets your machine or a trusted private network. It is not a hardened public SaaS edge.

TopicGuidance
HTTPNOT_SECURED=true on localhost only; use HTTPS and false on the public internet
SignupOpen by default; email verify is off when EMAIL_ENABLED=false
SecretsNever commit infra/self-host/.env
PortsWeb and API bind on the host; use a firewall on shared or cloud hosts
RedisNo password; not published to the host

For Vercel or Railway deploys, see Production deployment.

Search documentation
Find a docs page
Discord Support