Why self-host
The free app keeps your progress in your browser. That is enough for one device. If you learn on a phone and on a computer, the two copies do not know about each other.
The server keeps a copy of all progress in SQLite. Each device pushes its changes and pulls the changes of the other devices. The app still works offline. When the device is online again, the changes sync.
Run it with Docker
You need Docker. The container needs no other services.
docker run -d --name catechize \
-p 3000:3000 \
-v ./catechize-data:/data \
--restart unless-stopped \
ghcr.io/3stacks/hearers:latestOpen http://your-server:3000. On the server, the app opens at the root, without this homepage.
Docker Compose
services:
catechize:
image: ghcr.io/3stacks/hearers:latest
restart: unless-stopped
ports:
- "3000:3000"
environment:
- HEARERS_TOKEN=${HEARERS_TOKEN:-}
volumes:
- ./catechize-data:/dataAccess token
To keep other people out of your progress, set HEARERS_TOKEN. Make a token with this command:
openssl rand -hex 24Each device asks for the token once, in Settings. If the server is only on your home network or on Tailscale, you can leave the token empty.
Settings
| Variable | Default | Description |
|---|---|---|
PORT | 3000 | The HTTP port in the container. |
DATA_DIR | /data | The directory for catechize.db. |
HEARERS_TOKEN | none | When set, sync needs this token. |
Backups
Do not copy catechize.db while the container runs. The copy can include a write that is not complete. Tell the container to write a snapshot, and then copy the snapshot:
docker exec catechize node server/backup.ts /data/backup/catechize.db
cp ./catechize-data/backup/catechize.db ~/backups/catechize-$(date +%F).dbTo restore, stop the container. Delete catechize.db-wal and catechize.db-shm, and then put the snapshot in place as catechize.db. Each device notices the restore and sends its newer records to the server again.
You can also export a backup from Settings in the app. That file holds the progress of one device, in JSON.
HTTPS
The app works offline only over HTTPS, or on localhost. Put the container behind a reverse proxy such as Caddy:
catechize.example.com {
encode zstd gzip
reverse_proxy localhost:3000
}Update
docker compose pull catechize
docker compose up -d catechizeOpen the app on each device after an update. The new version installs in the background, and it starts the next time you open the app.