You can run draften on your own server. Mail, drafts and keys then stay with you; only what you send to the language model provider leaves (or nothing, with a local model).
This page is an overview. The detailed and always current procedure is in the README.md of the draften repository — follow it; here is only what is good to know up front.
What an installation is made of
Everything runs in Docker through docker compose:
| Service | What it does |
|---|---|
db | the MariaDB database — holds everything: settings, instructions, messages, drafts, encrypted secrets |
worker | reads the mailboxes, calls the models, writes drafts, learns, runs the wizard's steps. Several may run |
web | the web interface and API (Symfony on FrankenPHP) |
cloudflared | optionally: publishing the interface through a Cloudflare Tunnel |
The interface and the worker do not talk to each other directly — both work with the same database; what needs mail or a model, the interface queues as a job for the worker.
What you will need
- a server with Docker (Docker Compose v2),
- no Node.js or PHP on the server — everything is in the images,
- access to the mailboxes: an app registration in Microsoft Entra, a Google Workspace service account, or IMAP details,
- a model API key (Anthropic, OpenAI) or your own OpenAI-compatible server,
- the address the interface will be reachable at, with HTTPS.
On Windows with Docker Desktop, keep it in autostart and turn Resource Saver off.
Settings in .env
The .env file (the template is .env.example) holds only infrastructure and secrets. Everything about assistants is in the database and set in the interface.
| Variable | What for |
|---|---|
DB_ROOT_PASSWORD, DB_PASSWORD | database passwords |
MASTER_KEY | the key encrypting the secrets in the database (API keys, mailbox access, clients). Generate with openssl rand -hex 32 and keep a copy off the server — without it a database backup is unreadable |
WEB_APP_SECRET | a random string signing sessions |
WEB_PUBLIC_URL | the address users open the interface at; the redirect URIs are built from it |
CLOUDFLARE_TUNNEL_TOKEN | only with a Cloudflare Tunnel |
INTERVAL_SECONDS, WORKER_CONCURRENCY | the default check interval and concurrent checks (changeable in the interface too) |
WORKER_REPLICAS | how many worker processes run on this machine (default 1), see Operations |
The first start
docker compose up -d --build— at start the worker runs the database migrations and sets up the initial data by itself.- The operator's first sign-in: until they have a password or a Microsoft or Google binding, a one-time link is in the worker's log (
docker compose logs worker | grep set-password). It is valid for 7 days and renewed at every start. - On the Installation page, set the default API keys and the default outgoing mail (for invitations).
- On the Organisations page, set up an organisation or send an invitation to found one — see Installation administration.
Publishing
Nothing on the server needs to listen on the internet: a Cloudflare Tunnel (docker compose --profile tunnel up -d) routes the public address to the service http://web:80. Cloudflare Access in front of the address is a sensible second gate. Set WEB_PUBLIC_URL to the public address and add it as a redirect URI at the Microsoft and Google clients.
Next
- Installation administration — organisations, default keys and sender,
- Operations and capacity — how many workers and how to tell,
- Backup and restore,
- Updating draften,
- Troubleshooting.