Every setting each repo reads, where it's set, and whether it's secret.
Operators set none of these to get started. Everything below has a safe default; the operator-facing list is
in the monorepo’s README and .env.example. Never commit a .env.
Operator settings (.env next to docker-compose.yml)
Setting
Default
What it does
PORT
8080
The port on the server
BIND
127.0.0.1
Who can reach it: 127.0.0.1 this machine only, 0.0.0.0 every network
COMPOSE_PROFILES
https (Caddy), updater (one-click updates), or both comma-separated
DOMAIN
The domain Caddy serves with HTTPS
ADMIN_DATABASE_URL
Your own Postgres or Supabase, as its owner (start with --scale db=0)
OXR_APP_ID
Open Exchange Rates on your key instead of the free source
JOBS_HOUR
19
Daily jobs, as an hour in UTC (19 = 02:00 in Vietnam)
UPDATE_CHECK
on
off: never ask GitHub for the newest release
Inside the msaving container
Set by app/launch.py or the image; a developer sees them in backend/scripts/dev.sh.
Variable
Set by
What
DATABASE_URL
launcher
The API’s login (api_login); the API gets no other database URL
PURGE_DATABASE_URL, FX_DATABASE_URL
launcher
The jobs’ logins
BACKUP_DATABASE_URL
launcher
The owner, for pg_dump
BACKUP_DIR, PURGE_LOG
launcher
/backups, /backups/purged_accounts.jsonl
SECRETS_DIR
default /secrets
The database passwords (made on first start)
UPDATES_DIR
default /updates
The updater’s request, status and heartbeat files
WEB_DIR
image
The built web app (/srv/web)
UPDATE_REPO
default LeeMinNguyeen/msaving
Where releases are checked
DEV_RELOAD, DEV_ORIGIN
development only
uvicorn --reload; a localhost origin allowed through CORS