Evenbead docs

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 caddy gets a certificate for EVENBEAD_DOMAIN automatically (ports 80 and 443 reachable). For a box only on your LAN, set EVENBEAD_TLS=internal (Caddy's own CA; install its root certificate on your devices).
  • Your own proxy: point it at 127.0.0.1:8960, pass X-Forwarded-For, and set EVENBEAD_TRUSTED_PROXIES to 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

ProfileWhatSettings
emailSends invoices, reminders and sign-in emails through your SMTP serverbin/email-settings.sh <host> <port> tls <user> <from>, password in secrets/smtp.env as EVENBEAD_EMAIL_PASSWORD=...
inboxReads receipts forwarded to your mailboxEVENBEAD_INBOX_IMAP_HOST, EVENBEAD_INBOX_IMAP_USER, EVENBEAD_INBOX_DOMAIN, password in secrets/imap.env
minioS3-compatible receipt storage instead of the local diskEVENBEAD_RECEIPTS_BACKEND=s3 and EVENBEAD_RECEIPTS_S3_* (any S3-compatible store works)
caddyTLS in frontEVENBEAD_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).