Docker Compose
The services, profiles and settings in opendesk's self-hosted docker-compose.yml.
The installer is a convenience around Docker Compose. The same docker-compose.yml is at the root of the repository and is published with every release, so you can run it yourself.
Services
Section titled “Services”| Service | Image | Role |
|---|---|---|
caddy |
caddy:2.11-alpine |
Ports 80 and 443 with automatic HTTPS. /socket* goes to realtime, everything else to opendesk. |
opendesk |
ghcr.io/useopendesk/opendesk:${OPENDESK_VERSION} |
The API, workers and web app (SERVE_WEB=true), with NATS embedded on the internal network. |
realtime |
ghcr.io/useopendesk/realtime:${OPENDESK_VERSION} |
The Phoenix gateway, connected to opendesk’s NATS with NATS_TOKEN. |
postgres |
pgvector/pgvector:pg17 |
Postgres 17 with pgvector for semantic search, data in the postgres-data volume. |
Postgres, NATS and the app ports are on an internal network and are never published. Only Caddy (and the optional SMTP relay) face the host.
Every service runs with no-new-privileges, and the app containers run with a read-only root filesystem and all Linux capabilities dropped. Logs rotate at 10 MB, five files each.
Run it
Section titled “Run it”Download the release files
From the GitHub release for the version you want, download
docker-compose.yml,Caddyfile,env.template,opendesk-ctlandSHA256SUMSinto one directory, then check them:Terminal window mkdir -p /opt/opendesk && cd /opt/opendesksha256sum -c SHA256SUMS --ignore-missingWrite .env
Terminal window cp env.template .env && chmod 600 .envFill in the address and generate the secrets (see The .env file).
Pull the images and start
Terminal window docker compose pulldocker compose up -d
From a checkout, make selfhost-env writes .env with fresh secrets (it never overwrites one), and docker compose up -d --build builds the images from source instead of pulling them. Every app service has both image: and build:, so docker compose pull && docker compose up -d compiles nothing.
The .env file
Section titled “The .env file”.env sits next to docker-compose.yml. The template (deploy/self-host/.env.template) documents each setting. The ones specific to this bundle:
| Variable | Default | Meaning |
|---|---|---|
OPENDESK_VERSION |
pinned by the installer | Release of the opendesk and realtime images. Change it, then docker compose pull && docker compose up -d, to upgrade. |
OPENDESK_IMAGE, REALTIME_IMAGE |
ghcr.io/useopendesk/... |
Image names, for a mirror. |
OPENDESK_DOMAIN |
localhost |
The hostname Caddy serves. localhost uses Caddy’s local CA; :80 serves plain HTTP behind another proxy. |
OPENDESK_URL |
https://localhost |
Public URL. Sets API_URL, APP_URL, CORS_ORIGINS and SITE_URL. |
OPENDESK_GATEWAY_URL |
wss://localhost/socket |
Public WebSocket URL (GATEWAY_URL). |
CADDY_GLOBAL_OPTIONS |
empty | Caddy global options, such as email [email protected] for the ACME account. |
HTTP_PORT, HTTPS_PORT |
80, 443 |
Host ports Caddy publishes. |
OPENDESK_CADDYFILE |
./deploy/caddy/Caddyfile |
The Caddyfile to mount. |
CHECK_ORIGINS |
OPENDESK_URL |
Browser origins the gateway accepts for agent sockets. |
POSTGRES_PASSWORD |
required | Password for the bundled Postgres. |
SECRET_KEY_BASE |
required | The gateway’s Phoenix secret. |
NATS_TOKEN |
required | Authenticates the gateway to the embedded NATS. |
INBOUND_SECRET |
required | Authenticates POST /v1/inbound/email. |
COMPOSE_PROFILES |
empty | Optional services, comma separated: minio, smtp-inbound, ollama. |
WEB_POSTHOG_KEY, WEB_POSTHOG_HOST |
empty | Browser-side analytics for the web app. Empty sends nothing. |
OPENDESK_DATA, OPENDESK_PG_DATA, OPENDESK_S3_DATA, OPENDESK_OLLAMA_DATA |
named volumes | Override where data is stored, for example with a host path. |
Inside the bundle, opendesk always runs with OPENDESK_ENV=production, OPENDESK_ROLE=all and TRUST_PROXY=true (Caddy is the only way in), and DATABASE_URL points at the bundled Postgres. Every other application setting is passed through from .env.
Profiles
Section titled “Profiles”Optional services are compose profiles. Turn them on with COMPOSE_PROFILES in .env, or --profile on the command line.
S3-compatible attachment storage on the same machine, instead of the opendesk-data volume. It runs RustFS, which speaks the same S3 API, and an s3-init job creates the bucket once.
COMPOSE_PROFILES=minioSTORAGE_DRIVER=s3S3_ENDPOINT=http://s3:9000S3_FORCE_PATH_STYLE=trueS3_BUCKET=opendeskS3_REGION=us-east-1S3_ACCESS_KEY_ID=opendeskS3_SECRET_ACCESS_KEY=<a long random value>It refuses to start without S3_SECRET_ACCESS_KEY. Attachment downloads are presigned URLs, so browsers must be able to reach S3_ENDPOINT too.
smtp-inbound
Section titled “smtp-inbound”Publishes opendesk’s built-in SMTP receiver on the host, so an MX record for INBOUND_DOMAIN can point at this machine. A small TCP relay keeps opendesk itself unpublished.
COMPOSE_PROFILES=smtp-inboundINBOUND_SMTP_ADDR=:2525INBOUND_SMTP_PORT=25 # host port, default 25See Email setup.
ollama
Section titled “ollama”Fully local AI through Ollama’s OpenAI-compatible API. Nothing leaves the machine.
COMPOSE_PROFILES=ollamaAI_PROVIDER=openaiOPENAI_BASE_URL=http://ollama:11434/v1OPENAI_API_KEY=ollamaAI_MODEL=llama3.1:8bAI_FAST_MODEL=llama3.1:8bEMBEDDINGS_DRIVER=openaiEMBEDDINGS_MODEL=nomic-embed-textAn ollama-init job pulls AI_MODEL, AI_FAST_MODEL and EMBEDDINGS_MODEL once into the ollama-data volume. CPU is enough for small models; a GPU needs the host’s NVIDIA container toolkit. The installer’s --ollama flag sets all of this. See Self-hosting AI.
Combine profiles with commas: COMPOSE_PROFILES=minio,ollama.
Routing
Section titled “Routing”| Path | Goes to |
|---|---|
/socket, /socket/* |
realtime:4000, including the chat widget socket at /socket/widget |
| everything else | opendesk:8080: the API, web app, widget script, help center, /config.js and /config.json |
Caddy’s access log strips the token query parameter and the Authorization and Cookie headers, since realtime tokens travel in ?token=.
Volumes
Section titled “Volumes”| Volume | Holds |
|---|---|
opendesk-data |
Attachments and raw email (local storage), embedded NATS data |
postgres-data |
The database |
caddy-data, caddy-config |
Certificates and Caddy state |
s3-data |
The minio profile’s objects |
ollama-data |
The ollama profile’s models |
Common commands
Section titled “Common commands”docker compose psdocker compose logs -f opendeskdocker compose restart opendeskdocker compose down # stop, keep dataMigrations run automatically when opendesk starts. For backups and upgrades, use opendesk-ctl.