Docker Compose
Run Wealthfolio with a compose.yml that bundles restart policies, env files, and reverse proxy integration in a single declarative file.
If you already manage your homelab with Compose, this is the path you
want. The Wealthfolio repo ships a production-ready compose.yml that
plays nicely with any reverse proxy (Coolify, Nginx, Caddy, Traefik).
Prerequisites
- Docker + Docker Compose v2 (
docker compose, notdocker-compose) opensslandargon2for generating secrets
Get the compose file
The official compose file lives in the project repo. Pull it locally:
mkdir -p /opt/wealthfolio && cd /opt/wealthfolio
curl -fsSL https://raw.githubusercontent.com/wealthfolio/wealthfolio/main/compose.yml -o compose.ymlIt declares a single service backed by the wealthfolio/wealthfolio:latest
image, with a named volume, healthcheck, resource limits, and security
hardening (read-only filesystem + dropped privileges).
Create your .env
Generate the required secrets and write them to .env:
SECRET=$(openssl rand -base64 32)
HASH=$(printf 'your-password' | argon2 yoursalt16chars! -id -e)
cat > .env <<EOF
WF_SECRET_KEY='${SECRET}'
WF_AUTH_PASSWORD_HASH='${HASH}'
WF_CORS_ALLOW_ORIGINS=https://wealthfolio.example.com
EOF
chmod 600 .envSingle quotes around WF_AUTH_PASSWORD_HASH are mandatory. Compose interpolates $ in .env
files by default, and the Argon2 hash is full of $ characters. Single-quote it, or double every
$ ($$argon2id$$...). Compose 2.30+ also supports format: raw in env_file to skip
interpolation entirely — see the escaping
table.
Start it
docker compose up -dThe compose file uses expose (not ports), so the container is only
reachable from other containers on the same Docker network, perfect for
sitting behind a reverse proxy. To expose it directly to your host (for
local testing), use the dev overlay:
docker compose -f compose.yml -f compose.dev.yml up -dNow http://localhost:8088 works from the host.
Inspect & manage
docker compose logs -f # Follow logs
docker compose ps # Status
docker compose restart # Bounce the container
docker compose down # Stop and remove (volume persists)
docker compose pull && docker compose up -d # Update to latestReverse proxy integration
The shipped compose file is built for “publish via expose, terminate at the proxy.” Add Wealthfolio to your existing proxy network:
# compose.override.yml
services:
wealthfolio:
networks:
- proxy
networks:
proxy:
external: trueThen point your proxy at wealthfolio:8088 over the proxy network. See
Reverse proxy setup for full
examples.
Traefik labels
If you’re on Traefik, add labels in your compose.override.yml:
services:
wealthfolio:
labels:
- traefik.enable=true
- traefik.http.routers.wealthfolio.rule=Host(`wealthfolio.example.com`)
- traefik.http.routers.wealthfolio.entrypoints=websecure
- traefik.http.routers.wealthfolio.tls.certresolver=letsencrypt
- traefik.http.services.wealthfolio.loadbalancer.server.port=8088Set WF_CORS_ALLOW_ORIGINS=https://wealthfolio.example.com in your
.env to match.
Permissions
The container runs as non-root UID/GID 1000:1000. The shipped compose
file uses a named volume (wealthfolio-data), so fresh installs get the
right ownership automatically. If you swap in a bind mount, chown it
to 1000:1000 first.
Upgrading from a pre-v3.4.0 image? Older images ran as root, so the existing volume is
owned by root and the new container can’t write to it. Stop the stack and chown the volume once
using the snippet below.
docker compose down
# Replace `wealthfolio_wealthfolio-data` with your actual volume name.
# Compose prefixes the volume with the project name (folder name or `-p` flag).
# Run `docker volume ls` to find it.
docker run --rm -v wealthfolio_wealthfolio-data:/data alpine chown -R 1000:1000 /data
docker compose up -dPinning the version
wealthfolio/wealthfolio:latest rolls forward on every release. For
production, pin a tag:
services:
wealthfolio:
image: wealthfolio/wealthfolio:3.3.0Then update deliberately by bumping the tag and running
docker compose up -d.
Backups
The compose file uses a named volume wealthfolio-data. Back it up by
running a sidecar tar:
docker run --rm \
-v wealthfolio_wealthfolio-data:/data \
-v "$(pwd):/backup" \
alpine tar czf /backup/wealthfolio-$(date +%Y%m%d).tar.gz -C / data(Volume name is <compose-project>_<volume-name>. Adjust if your
project name differs.)
Back up .env (which holds WF_SECRET_KEY) separately from the data volume. The encrypted
secrets in the volume are useless without the key.
Configuration
Every variable Wealthfolio reads is documented in the Configuration reference.