Self-host Evenbead
Evenbead runs on your own machine with Docker: PostgreSQL 17, the web app with the REST API and MCP endpoint, the export worker, the maintenance loop and nightly backups, with optional email, the receipt inbox, MinIO and Caddy for TLS. Nothing calls home: no license check and no telemetry. (Pilot, dated 2026-10-12: images are built from the source repository; there is no public image registry yet. The Owned plan, $399 a year per company, is described below; its license is not enforced yet.)
Requirements
A Linux machine (or a VM) with Docker Engine 24+ and Docker Compose v2, 2 GB of RAM, and disk for your books and receipts. The Evenbead source (the private repository for now; Owned customers get access). A domain name pointing at the machine if you want automatic TLS.
First run
From components/deploy/selfhost in the repository:
bin/gen-env.sh https://books.example.com # writes .env: every database password and data key, random, 0600
bin/build.sh # builds the image from this checkout and pins it in .env (evenbead:<commit>)
bin/up.sh caddy # postgres, migrations, web, exports, maintenance, backups, and Caddy for TLS
bin/setup-link.sh owner you@example.com # a one-time link: open it, name the company, add a passkey
Back up .env somewhere safe, apart from the backups. Its data keys decrypt your receipt files, authenticator secrets and bank feed tokens; without them those are lost. Without Caddy (bin/up.sh alone) the app listens on 127.0.0.1:8960 (EVENBEAD_HTTP_PORT).
TLS
- Caddy (bundled):
bin/up.sh caddygets a certificate forEVENBEAD_DOMAINautomatically (ports 80 and 443 reachable). For a box only on your LAN, setEVENBEAD_TLS=internal(Caddy's own CA; install its root certificate on your devices). - Your own proxy: point it at
127.0.0.1:8960, passX-Forwarded-For, and setEVENBEAD_TRUSTED_PROXIESto its address.
Passkeys need HTTPS (or localhost), so use TLS for anything but a local trial.
Bringing your books
Export from any Evenbead (Settings, Export; see Export your books), copy the ZIP over, then:
bin/import.sh evenbead-yourcompany-20261012-091500-1a2b3c4d.zip
bin/setup-link.sh person <owner user id printed by the import>
The import reports identical when the trial balance, AR/AP aging and audit chain match the export. If the owner has no email address yet: docker compose exec maintenance bun run ops people set-email user <id> you@example.com first. Import into a server at the same Evenbead version as the export (the import refuses another).
Optional services
| Profile | What | Settings |
|---|---|---|
email | Sends invoices, reminders and sign-in emails through your SMTP server | bin/email-settings.sh <host> <port> tls <user> <from>, password in secrets/smtp.env as EVENBEAD_EMAIL_PASSWORD=... |
inbox | Reads receipts forwarded to your mailbox | EVENBEAD_INBOX_IMAP_HOST, EVENBEAD_INBOX_IMAP_USER, EVENBEAD_INBOX_DOMAIN, password in secrets/imap.env |
minio | S3-compatible receipt storage instead of the local disk | EVENBEAD_RECEIPTS_BACKEND=s3 and EVENBEAD_RECEIPTS_S3_* (any S3-compatible store works) |
caddy | TLS in front | EVENBEAD_DOMAIN, optional EVENBEAD_TLS=internal |
Start them with bin/up.sh caddy email inbox.
Receipt OCR: set EVENBEAD_OCR_URL to an OCR service on your own network (for example a local model server). Unset, receipts are read from their PDF text and HTML only. Nothing is sent anywhere unless you set it.
Bank feeds (Plaid), bring your own keys: create a Plaid account, then set EVENBEAD_PLAID_ENV (sandbox or production), EVENBEAD_PLAID_CLIENT_ID, EVENBEAD_PLAID_SECRET and EVENBEAD_PLAID_DATA_KEY (32 random bytes, base64: openssl rand -base64 32). Plaid's webhooks need a public HTTPS URL (EVENBEAD_PLAID_WEBHOOK_URL); without one, feeds sync every few hours from the maintenance loop. Statement files (OFX, QFX, CSV) always work without Plaid.
Backups and restore test
The backup service takes a pg_dump of the whole database and copies the receipt files into ./backups every night at EVENBEAD_BACKUP_AT (default 03:30, in TZ), keeping 14 days (EVENBEAD_BACKUP_KEEP_DAYS). Copy ./backups off the machine (and .env, separately).
bin/backup-now.sh # a backup now (do this before an upgrade)
bin/restore-test.sh # restore the newest backup into a throwaway database: every audit chain verifies, row counts check,
# every receipt file in the backup decrypts to its SHA-256
Upgrades
Images are pinned in .env (EVENBEAD_IMAGE=evenbead:<commit>). To upgrade: take a backup, check out the new version, then bin/build.sh and bin/up.sh. Migrations run first on start (forward-only, each in its own transaction; a changed migration is refused) and the services start only if they succeed. To go back, restore the backup taken before the upgrade with the previous image. The image registry for ready-made images is a later decision (see ADR-0042).
The Owned plan and licensing
Self-hosting is the Owned plan: $399 a year per company file, with updates and support, and no agent quotas because it runs on your hardware. Every company on a self-hosted server runs on the Owned plan. The license is not checked yet. When it is, it will be a license file signed by Evenbead and verified on your machine, offline: no phone-home, ever, and an expired license will never lock you out of your books or block exporting them (ADR-0043).