Menu
OpenCount docs

Configuration

There is no configuration file. The container reads a few environment variables at boot, and everything else (sign-ups, sign-in methods, email, receipt reading) is set by an admin in the app and stored in the database.

Every variable is declared and validated in one place. The server refuses to start with an invalid value and names it, rather than running half configured.

#Required

VariableDefaultWhat it does
AUTH_SECRETnoneSigns sessions and encrypts the stored secrets

AUTH_SECRET must be at least 32 characters. Generate one with openssl rand -base64 32 and keep it with your backups.

It signs session cookies and, through keys derived from it, encrypts what the database must not hold in clear: the SMTP password, single sign-on client secrets and authenticator app secrets. Changing it signs everyone out, and those secrets can no longer be read: an admin has to enter the SMTP password and the client secrets again, and everyone has to set up their authenticator app again.

#Origin

VariableDefault in the imageWhen you need it
ORIGINunsetPlain HTTP with no proxy; harmless anywhere
PROTOCOL_HEADERx-forwarded-protoYour proxy sends the scheme in another one
HOST_HEADERx-forwarded-hostYour proxy sends the host in another one
ADDRESS_HEADERunsetTo see the client's IP, not the proxy's
XFF_DEPTHunsetWith ADDRESS_HEADER: x-forwarded-for
PORT3000To listen on another port
BODY_SIZE_LIMIT256MTo accept bigger or smaller uploads

Every form post is checked against the app's public origin, and a mismatch is refused with 403 Cross-site POST form submissions are forbidden. OpenCount takes that origin from the request: the scheme and host your proxy forwards in X-Forwarded-Proto and X-Forwarded-Host. When those headers are missing, the server assumes https.

So behind an HTTPS reverse proxy that sets both headers, it just works. On plain HTTP with no proxy, set ORIGIN to the exact URL people type, scheme and port included, like http://192.168.1.10:3000; the check then accepts it too. Setting ORIGIN behind a proxy does no harm, and it also fixes the base URL of invite links and single sign-on callbacks.

PROTOCOL_HEADER, HOST_HEADER, ADDRESS_HEADER, XFF_DEPTH, PORT and BODY_SIZE_LIMIT belong to the Bun adapter; its documentation lists the rest. Only trust forwarded headers when every request reaches the server through a proxy you control.

#Database

VariableDefault in the imageWhat it does
DATABASE_PATH/data/opencount.sqliteThe SQLite file

The image keeps the database on its /data volume. Outside the image the default is ./data/opencount.sqlite, relative to the working directory. The directory is created when missing. Migrations run at every boot, before the worker starts; see Backups and upgrades.

#Background worker

VariableDefaultRangeWhat it does
WORKER_CONCURRENCY21 to 32Background jobs run at once
WORKER_POLL_INTERVAL_MS1000100 to 60000How often the worker looks for due jobs

The worker sends emails, adds repeating expenses, builds backups and exports, imports Tricounts and prunes finished jobs and old downloads. The defaults suit any instance; there is rarely a reason to touch them.

#Logging

VariableDefault in the imageValues
LOG_LEVELinfotrace, debug, info, warn, error
LOG_FORMATconsolejson, console

json writes one object per line for a log shipper; console writes coloured lines for a terminal, and is the default outside the image.

#Version

VariableDefaultWhat it does
APP_VERSIONset by the release buildShown in the footer, sent with traces and errors

#Traces and errors

VariableDefaultWhat it does
OTEL_EXPORTER_OTLP_ENDPOINTunsetOTLP/HTTP collector base URL; traces are off unset
OTEL_SERVICE_NAMEopencountservice.name on every span
OTEL_RESOURCE_ATTRIBUTESunsetExtra resource attributes, key=value,key=value
SENTRY_DSNunsetWhere errors are reported; off when unset
SENTRY_RELEASEAPP_VERSIONRelease attached to reported errors
SENTRY_ENVIRONMENTproductionEnvironment attached to reported errors

With none of them set, no telemetry leaves the server. See Logs, traces and errors.

#Outbound calls

Besides your SMTP and single sign-on servers, the server calls three services, and only when someone uses the feature: api.frankfurter.dev for the exchange rate of an expense in another currency, api.tricount.bunq.com to import a Tricount from its share link, and api.enablebanking.com for bank sync. Block them and those features fail, nothing else.

#Set in the app, not here

This guide lives in the project repo: edit it there, and this page follows within a day.