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/afadil/wealthfolio/main/compose.yml -o compose.yml

It declares a single service backed by the afadil/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.

Pinning the version

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

services:
  wealthfolio:
    image: afadil/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.