Skip to main content

Installing

All you need is Docker, and the patience to fill in two lines of a file. I come as one image with everything in it: the server, the web app, and the schedules that run behind them.

Getting The Files​

The compose files and .env.example live in my repository. Take a copy:

git clone https://github.com/DimwitLabs/Ebenezer.git
cd Ebenezer

There are two compose files. Pick one and use it from here on.

FileUse it when
docker-compose.ymlYou want me to bring my own Postgres. Start here if you are unsure.
docker-compose.external-db.ymlYou already have a Postgres, Supabase included, and want me to keep my tables in it.

Starting Me​

cp .env.example .env

Set POSTGRES_PASSWORD and EBENEZER_ENCRYPTION_KEY in it. The password ends up in a connection string, so keep it to letters and digits. This makes a suitable one:

openssl rand -hex 24

Make the key with:

openssl rand -base64 32

Then start me:

docker compose up -d

You will find me at http://localhost:8080. Whoever makes the first account there owns the place.

Keep This Key

Every key and password you hand me in Settings is locked with EBENEZER_ENCRYPTION_KEY. Lose it and I cannot open them. Nobody can. You will be typing the lot in again, so keep a copy somewhere other than this server.

The key must be at least 32 characters, or I refuse to start. Your ledger itself is not locked with it, only the OpenRouter key, the ntfy token or password, and the mail password. What happens when the key goes missing is in Troubleshooting.

The Bundled Database​

docker-compose.yml runs two containers: me, and a postgres:18-alpine called db. The database has no network of its own. It listens on a socket shared with my container and nowhere else, so nothing on your network can reach it, let alone the internet.

Its data lives in a Docker volume called postgres_data. Removing the containers leaves the volume alone. Removing the volume removes your ledger, so take a backup before you go anywhere near it.

Your Own Database​

If you would rather use your own Postgres, Supabase included, set EBENEZER_DATABASE_URL in .env and use the other compose file:

docker compose -f docker-compose.external-db.yml up -d

POSTGRES_PASSWORD is not used with this file.

  • Poolers work: I talk to the database in a way that survives a transaction pooler, so Supabase's pooled connection string is fine.
  • Ask for TLS: For a database across a network, end the connection string with sslmode=require, or sslmode=verify-full if you can.
  • A schema of my own: I keep my tables in a schema called ebenezer unless you set EBENEZER_DB_SCHEMA, so I can share a database without making a mess of it. I make the schema myself on first start.

The Published Image​

Both compose files run ghcr.io/dimwitlabs/ebenezer, built for linux/amd64 and linux/arm64. It is tagged several ways:

TagWhat it follows
latestThe newest build of main, released or not. The compose files use it unless told otherwise.
developmentThe newest build of the development branch, when there is one. Expect it to break.
X.Y.ZOne release exactly, numbered as in its release notes.
X.YThe newest patch of that minor version.
XThe newest release of that major version.

EBENEZER_VERSION in .env picks the tag; set it to X.Y to stay on releases. Each release on GitHub also lists the image with its exact digest. Moving between tags is covered in Upgrading.

HTTPS And Reaching Me​

By default I listen on 127.0.0.1:8080, which only the machine I run on can reach. EBENEZER_BIND and EBENEZER_PORT in .env change the address and the port.

I do not speak HTTPS myself. Put me behind a reverse proxy that does, and point it at the port above. Do this before you trust me with anything real: your sign-in cookie is marked secure, and a browser will not send it back over plain HTTP.

To try me over plain HTTP on your own machine, set this in .env:

EBENEZER_SECURE_COOKIES=false

I will warn you about it in my logs every time I start, and I mean it. Turn it back on before anyone else signs in.

Once I have an address of my own, tell me what it is, so the links in invites and reports go somewhere:

EBENEZER_PUBLIC_URL=https://ebenezer.example.com

Leave it empty and those emails go out without a link. Every setting is listed in Configuration.

The First Account​

The first person to open me becomes the owner, and there is only ever one. Once that account exists the screen is gone for good, so open me yourself before you tell anyone the address. What happens next is in First Run.