A free, open, self-hosted app platform (GNU AGPLv3): one-click app deploys, Traefik reverse proxy with automatic SSL, rootless Docker support, gluetun VPN routing, and a web dashboard to manage it all. Free & open forever to self-host; optional paid hosted services fund it. See PROMISE.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
95 lines
3.5 KiB
Markdown
95 lines
3.5 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
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`.
|
|
|
|
```bash
|
|
# 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.
|