Wealthfolio logo Wealthfolio
Download
Docs
Docker Compose

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, not docker-compose)
  • openssl and argon2 for 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.yml

It 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 .env

Single 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 -d

The 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 -d

Now 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 latest

Reverse 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: true

Then 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=8088

Set 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 -d

Pinning the version

wealthfolio/wealthfolio:latest rolls forward on every release. For production, pin a tag:

services:
  wealthfolio:
    image: wealthfolio/wealthfolio:3.3.0

Then 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.