Self-host in under 10 minutes
Run fikadesk on your own box with Docker Compose, from clone to first workspace.
One box, one image, Docker Compose. The single profile runs Caddy, Postgres 18, PgBouncer, Centrifugo, a one-shot migration job, the api, the worker and the mail ingest. Everything lives under deploy/compose/.
Requirements
- Docker Engine 24 or newer with the Compose plugin.
- 2 GB of RAM and 10 GB of disk to start; Postgres grows with your conversations.
- A DNS name pointing at the box if you want HTTPS.
- A second name for attachments,
FIKADESK_MEDIA_URL. Nothing serves that origin yet.
Get the code
git clone https://github.com/fikadesk/fikadesk.git
cd fikadeskConfigure and start
cp deploy/compose/.env.example deploy/compose/.env
openssl rand -hex 24 # POSTGRES_PASSWORD, FIKADESK_APP_PASSWORD
openssl rand -hex 32 # FIKADESK_AUTH_SECRET, FIKADESK_REALTIME_SECRET
$EDITOR deploy/compose/.env
docker compose -f deploy/compose/compose.yml --profile single up -d --wait
curl http://127.0.0.1/healthzKeep the passwords hex. They travel inside connection URLs, and the PgBouncer entrypoint splits DATABASE_URL with sed and cut, so an @, : or / in a password writes a broken userlist and authentication fails with no hint about why.
The first up builds the derived Postgres image, which pulls pgBackRest from the PostgreSQL APT repository. It needs network access and a minute or two. Later starts reuse the built image.
--wait returns when the api answers its health check. The order is fixed by depends_on: Postgres becomes healthy, the roles job creates the two app roles, migrate applies packages/db/migrations and installs the pg-boss schema, then the api, worker and ingest start once Centrifugo is healthy, and Caddy comes up last.
Run migrations
Migrations are additive SQL files that run before new code starts, never at boot. The first up runs them automatically. Run them by hand with the one-shot migrate job:
docker compose -f deploy/compose/compose.yml --profile single run --rm migrateCreate the first administrator
With FIKADESK_ALLOW_SIGNUP=false nobody can sign up, so the api prints a one-time setup token while the users table is empty. Spend it on the first administrator; after that everyone joins by invitation.
docker compose -f deploy/compose/compose.yml logs api | grep setupToken
curl -X POST http://127.0.0.1/api/setup -H 'content-type: application/json' \
-d '{"token":"<the token>","email":"[email protected]","name":"You","password":"<at least 12 characters>"}'pnpm fikadesk admin grant <email> and revoke change who may create workspaces afterwards. pnpm fikadesk admin two-factor-reset <email> clears a locked-out person's second factor.
Set up your first workspace
Sign in at FIKADESK_PUBLIC_URL with the administrator you just created. The inbox walks you through creating the first workspace, which also writes its default messenger channel.
Go public
Set these two variables in .env and restart. Caddy fetches a certificate on start and redirects HTTP to HTTPS. Leave both at their defaults to keep the stack on 127.0.0.1:80 and 127.0.0.1:443 behind your own proxy.
FIKADESK_DOMAIN=support.example.com
FIKADESK_BIND=0.0.0.0Upgrade
Every merge to main publishes the OSS image as ghcr.io/fikadesk/fikadesk, tagged with the full commit sha and with main. Bump FIKADESK_IMAGE, pull, migrate, then restart. Downgrading is not supported: removals take two releases, so the previous image still runs against the newer schema if you have to roll back.
$EDITOR deploy/compose/.env # bump FIKADESK_IMAGE to the new tag
docker compose -f deploy/compose/compose.yml --profile single pull
docker compose -f deploy/compose/compose.yml --profile single run --rm migrate
docker compose -f deploy/compose/compose.yml --profile single up -d --waitNote
The full guide covers reverse proxies, email delivery, backups and security defaults at docs/self-hosting.md in the repository.