Sign inSign up

sebitro/balancia

By sebitro

•Updated 7 days ago

Self-hosted expense splitter — shared expenses, fairly balanced, on a server you control.

Image
0

7.7K

sebitro/balancia repository overview

⁠Balancia

Shared expenses, fairly balanced — on a server you control.

A free, privacy-first expense splitter for trips, households, couples, families, clubs and teams. Exact splits, multiple currencies, receipts, guests without accounts, and exports you can take elsewhere. No advertising, no third-party runtime service, and telemetry off unless an administrator turns it on.

This image is the whole application: the web app, the background worker and the migration runner, picked by the command it is given. Source, issues and the full documentation live at github.com/sebitr/balancia⁠.

⁠Tags

TagWhat it is
latestThe newest release. Moves under you at every pull.
0.1.0That release, permanently. What to pin an instance you care about to.
previewmain as it is right now, rebuilt on every merge that passes CI. Not a release.

Every tag is a manifest list covering linux/amd64 and linux/arm64, so docker pull serves the right one without being asked.

⁠Where it came from

Images are built by GitHub Actions from the repository, and only once the whole test suite has passed on the same commit. Each one carries SLSA build provenance and an SPDX SBOM, and the manifest list is attested by GitHub in a statement signed through Sigstore — so you can check that a tag was built by the repository's own workflow, and not merely pushed under its name:

gh attestation verify oci://docker.io/sebitro/balancia:latest -R sebitr/balancia

⁠Running it

Balancia needs a PostgreSQL database and a couple of secrets, so the shortest honest quick start is Compose — it brings up PostgreSQL 18 alongside the app, and the repository carries the setup script that points it at this image:

curl -fsSLO https://github.com/sebitr/balancia/releases/latest/download/bootstrap.sh
sh bootstrap.sh

bootstrap.sh is the installer. It asks where to install, fetches the Compose files for its own release into that directory, writes a .env with this instance's own database password and auth secret, asks which optional features to switch on, and offers to start the stack. It needs no Git and no checkout, and it is safe to run again. Then open http://localhost:3000⁠ and create the first account.

An install made this way pulls this image rather than building anything. To build from source instead, clone the repository and run ./scripts/bootstrap.sh from inside it.

To run the container yourself against a database you already have:

docker run -d --name balancia \
  -p 127.0.0.1:3000:3000 \
  -v balancia-uploads:/data/uploads \
  -e APP_URL=https://balancia.example.com \
  -e DATABASE_URL=postgres://balancia:secret@db:5432/balancia \
  -e AUTH_SECRET="$(openssl rand -base64 48)" \
  sebitro/balancia:latest

Back up AUTH_SECRET. Losing it signs everyone out.

The port is published on 127.0.0.1 for a reverse proxy on the same host, which is the only thing that should reach it: rate limiting trusts the X-Forwarded-For the proxy writes, and a caller who reaches the container directly writes their own.

⁠What the image does on start

Migrations are not a separate step. The entrypoint applies any pending ones before the app serves anything, under a PostgreSQL advisory lock, so several containers starting at once is safe.

Port3000
Volume/data/uploads — receipt files, when storage is local rather than S3
Usernon-root, uid 1001
HealthcheckGET /api/health/live; /api/health/ready also touches the database
Workercommand: ["node", "dist/worker.js"] runs the background jobs in their own container. Left to itself, the web process runs them.

⁠Configuration

Everything is environment variables — database, storage, SMTP, Sign in with Apple, exchange rates, receipt scanning, push notifications, telemetry, metrics. They are documented one by one in docs/environment.md⁠, and the deployment side of them in docs/self-hosting.md⁠.

⁠Upgrading

./backup.sh --database-only --keep 10 backups/pre-upgrade
docker compose pull
docker compose up -d

Migrations are forward-only and never destructive without warning, and an already-applied migration whose file has changed fails startup loudly rather than running twice. Forward-only is also why the first line is there: the dump it takes is the way back from an upgrade that went wrong. backup.sh comes with the standalone install; see docs/backup-and-restore.md⁠.

Going back to an older image without restoring that dump is refused: a release older than its database will not start, rather than run against a schema it was never written for. Rolling back, and the setting that overrides the refusal, are in docs/self-hosting.md⁠.

⁠Licence

AGPL-3.0-or-later. The source for this image is github.com/sebitr/balancia⁠.

Tag summary

Content type

Image

Digest

sha256:65f60255a…

Size

304.1 MB

Last updated

about 2 months ago

docker pull sebitro/balancia