librelad 6813621fe9 config: enable multiple instances everywhere it is actually possible
Three apps were instanceable and the rest were silent, so the feature
looked far narrower than it is. Every app has now been checked against
the two rules instance_create.sh enforces, and the answer recorded in
its config rather than left unset.

32 apps are instance-safe and now say so. Six are not, and each says why
in its own words instead of being indistinguishable from an app nobody
had reviewed:

  pihole      a DNS server must own port 53
  unbound     a resolver must own its fixed 5335
  stalwart    a mail server must own 25/465/587/993
  traefik     must own 443, and one Traefik routes every other app
  prometheus  node-exporter and cadvisor carry no "prometheus" prefix
  stoat       pins 7881, and database/redis/rabbit/minio carry no prefix

The first four are genuinely one-per-host: the port is not arbitrary, it
is the protocol. The last two are compose-identity problems and could be
fixed by prefixing those service names, which is a change to make
deliberately rather than in passing.

Recorded as an explicit false with a reason, not left unset, so the next
person reads a decision instead of an absence. The audit was verified not
to pass anything vacuously: every app resolves at least one service name,
so no app reached "eligible" merely because nothing was found to check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 23:38:34 +01:00
..

MoneyApp

Self-hosted money management for one or more users in a household. Recurring rules, projected ledger, budgets, savings goals + compound-interest calculator, and a 12-month forecast with what-if sliders.

Stack: Next.js 15 + SQLite (Drizzle ORM) + Auth.js. Runs as a single Docker container.

Requirements

  • Docker 20.10+ with Compose v2 (docker compose version should print v2.x or v5.x)
  • Port 3000 free on the host

Install

# 1. From inside the MoneyApp folder, create the environment file
cp .env.example .env

# 2. Edit .env and set AUTH_SECRET to a random 32-byte string.
#    Generate one with:
echo "AUTH_SECRET=$(openssl rand -base64 32)" >> .env

# 3. Build and start
docker compose up -d --build

The first build takes 3-5 minutes (it compiles better-sqlite3 natively and runs next build inside the container). Subsequent starts are instant.

Open http://localhost:3000 and sign up. The first account becomes the household owner.

Daily commands

What Command
Start docker compose up -d
Stop docker compose down (data preserved)
Logs docker compose logs -f
Restart after pulling new code docker compose up -d --build
Shell inside container docker compose exec moneyapp sh

Updating

Replace the source folder with the new version (keep your .env and the moneyapp-data Docker volume), then:

docker compose up -d --build

Migrations run automatically on container start.

Backup

The entire database is one SQLite file at /data/moneyapp.db inside the container, mounted from the named volume moneyapp-data.

# Snapshot
docker compose exec moneyapp sh -c 'cat /data/moneyapp.db' > backup-$(date +%F).db

# Restore (with the app stopped)
docker compose down
docker run --rm -v moneyapp_moneyapp-data:/data -v "$PWD":/host alpine \
  sh -c 'cp /host/backup-2026-05-07.db /data/moneyapp.db'
docker compose up -d

Accessing from other devices on the LAN

By default the container listens on 0.0.0.0:3000, so from the same network just use the host's IP: http://<host-ip>:3000. For HTTPS or remote access, put a reverse proxy (Caddy, Traefik, nginx) in front.

If you do put it behind a domain, update AUTH_URL in .env to the public URL — Auth.js uses it to construct callback URLs.

Troubleshooting

  • set AUTH_SECRET in .env on up — you skipped step 2 above. Create .env and set AUTH_SECRET.
  • Port 3000 already in use — stop whatever else is on 3000, or change the host-side port in docker-compose.yml (e.g. "3001:3000").
  • Database looks empty after a rebuild — that means the volume was removed. docker compose down keeps it; docker compose down -v deletes it. Restore from a backup if needed.

Project layout

MoneyApp/
├── Dockerfile           multi-stage build (deps → build → runtime)
├── docker-compose.yml   service + volume definition
├── .dockerignore
├── .env.example         template; copy to .env and fill in
├── README.md
└── app/                 the Next.js project
    ├── src/             application code
    ├── drizzle/         generated SQL migrations
    ├── public/          static assets
    ├── package.json + lock
    └── *.ts/.mjs        build configs (tsconfig, tailwind, postcss, etc.)

The deployment files stay at the root so it's clear what the installer interacts with. Everything inside app/ is the application itself — the Dockerfile copies it in during the build.