{
  "schema_version": 1,
  "generated_at": "2026-10-22T00:00:00.000Z",
  "canonical_url": "https://openlogs.fyi/tools/wealthfolio",
  "slug": "wealthfolio",
  "name": "Wealthfolio",
  "tagline": "Local-first tracker for investments, net worth and spending.",
  "replaces": {
    "summary": "Paid investment tracking services, such as Empower.",
    "products": [
      {
        "slug": "empower",
        "name": "Empower",
        "vendor": "Empower",
        "url": "https://openlogs.fyi/alternatives/empower"
      }
    ]
  },
  "stack": [
    {
      "kind": "language",
      "name": "Rust"
    }
  ],
  "deployment_methods": [
    "docker_compose"
  ],
  "requirements": {
    "min_ram_mb": null,
    "min_cpu_cores": null,
    "source_url": null
  },
  "license": {
    "spdx": "AGPL-3.0",
    "class": "osi",
    "source_url": "https://github.com/wealthfolio/wealthfolio/blob/1e08bbc1e2ae88cb245130d315df4283b1fe256d/LICENSE"
  },
  "business_model": {
    "value": "unknown",
    "notes": "The README at the pinned commit does not state a business model, so it stays unknown.",
    "source_url": "https://github.com/wealthfolio/wealthfolio/blob/1e08bbc1e2ae88cb245130d315df4283b1fe256d/README.md",
    "checked_at": "2026-10-22"
  },
  "difficulty": {
    "value": "easy",
    "reason": "1 service, 1 volume mount, no env values to set, no elevated host access. Heuristic score 0 of 11: easy."
  },
  "repository": {
    "owner": "wealthfolio",
    "name": "wealthfolio",
    "url": "https://github.com/wealthfolio/wealthfolio"
  },
  "compose_check": {
    "status": "config_ok",
    "validated_at": "2026-10-22",
    "summary": "config_ok on 2026-10-22"
  },
  "recipe": {
    "version": 1,
    "source_path": "compose.yml",
    "source_repo": "wealthfolio/wealthfolio",
    "source_commit_sha": "1e08bbc1e2ae88cb245130d315df4283b1fe256d",
    "source_kind": "app_repo",
    "source_url": "https://github.com/wealthfolio/wealthfolio/blob/1e08bbc1e2ae88cb245130d315df4283b1fe256d/compose.yml"
  },
  "install_steps": [
    {
      "order": 1,
      "kind": "prerequisite",
      "language": "text",
      "label": "Docker with the Compose plugin",
      "body": "A host with Docker and the Docker Compose plugin. This entry runs from a compose file.",
      "source_url": "https://github.com/wealthfolio/wealthfolio/blob/1e08bbc1e2ae88cb245130d315df4283b1fe256d/compose.yml",
      "validation_status": "unvalidated"
    },
    {
      "order": 2,
      "kind": "compose",
      "language": "yaml",
      "label": "Save the compose file as compose.yml",
      "body": "# Wealthfolio - Production Docker Compose\n#\n# Usage: docker compose --env-file .env.docker up -d\n# Reverse proxy overlay: docker compose --env-file .env.docker -f compose.yml -f compose.proxy.yml up -d\n# Dev overlay: docker compose --env-file .env.docker -f compose.yml -f compose.dev.yml up\n#\n# Publishes port 8088 for direct browser access.\n\nservices:\n  wealthfolio:\n    image: wealthfolio/wealthfolio:latest\n    container_name: wealthfolio\n    restart: unless-stopped\n    ports:\n      - \"${WF_PORT:-8088}:8088\"\n    volumes:\n      - wealthfolio-data:/data\n    environment:\n      WF_LISTEN_ADDR: \"0.0.0.0:8088\"\n      # Optional installation root; empty uses the database's parent directory.\n      WF_DATA_DIR: \"${WF_DATA_DIR:-}\"\n      # Preserve the legacy filename by default and honor an explicitly empty path.\n      WF_DB_PATH: \"${WF_DB_PATH-/data/wealthfolio.db}\"\n      # Required — generate with: openssl rand -base64 32\n      WF_SECRET_KEY: \"${WF_SECRET_KEY:-}\"\n      # Alternative: path inside the container to a separately mounted secret.\n      WF_SECRET_KEY_FILE: \"${WF_SECRET_KEY_FILE:-}\"\n      # Startup requirement; convert existing databases offline before enabling.\n      WF_DB_REQUIRE_ENCRYPTION: \"${WF_DB_REQUIRE_ENCRYPTION:-0}\"\n\n      # ── Authentication ────────────────────────────────────────────────\n      # Required when listening on 0.0.0.0 (the default for Docker).\n      # Provide an Argon2id PHC hash of your password.\n      #\n      # IMPORTANT — Docker Compose interpolates \"$\" in .env files and YAML:\n      #   .env file  → WF_AUTH_PASSWORD_HASH='$argon2id$v=19$...'  (single quotes)\n      #   .env file  → WF_AUTH_PASSWORD_HASH=$$argon2id$$v=19$$...  (double every $)\n      #   YAML inline → WF_AUTH_PASSWORD_HASH: '$$argon2id$$v=19$$...'  (double every $)\n      #\n      # Generate a hash:\n      #   printf 'your-password' | argon2 yoursalt16chars! -id -e\n      #\n      # If a reverse proxy handles auth instead, set WF_AUTH_REQUIRED: \"false\"\n      # and leave WF_AUTH_PASSWORD_HASH empty.\n      WF_AUTH_PASSWORD_HASH: \"${WF_AUTH_PASSWORD_HASH:-}\"\n      WF_AUTH_TOKEN_TTL_MINUTES: \"${WF_AUTH_TOKEN_TTL_MINUTES:-60}\"\n      # Set to \"false\" to skip the auth requirement (e.g. reverse proxy handles auth)\n      # WF_AUTH_REQUIRED: \"true\"\n\n      # ── OIDC / SSO (optional) ─────────────────────────────────────────\n      # Sign in via any OpenID Connect provider (Authentik, PocketID, Authelia, …).\n      # Works alongside or instead of WF_AUTH_PASSWORD_HASH; enabled when both the\n      # issuer URL and client id are set. Redirect URL must be registered in the IdP.\n      WF_OIDC_ISSUER_URL: \"${WF_OIDC_ISSUER_URL:-}\"\n      WF_OIDC_CLIENT_ID: \"${WF_OIDC_CLIENT_ID:-}\"\n      WF_OIDC_CLIENT_SECRET: \"${WF_OIDC_CLIENT_SECRET:-}\"\n      WF_OIDC_REDIRECT_URL: \"${WF_OIDC_REDIRECT_URL:-}\"\n      # Optional space-separated scopes (default: \"openid email profile\")\n      WF_OIDC_SCOPES: \"${WF_OIDC_SCOPES:-}\"\n      # Allowlist (comma-separated). With NEITHER set the server refuses to start\n      # unless WF_OIDC_ALLOW_ANY=true is set — a missing allowlist must not silently\n      # grant every IdP user access.\n      WF_OIDC_ALLOWED_EMAILS: \"${WF_OIDC_ALLOWED_EMAILS:-}\"\n      WF_OIDC_ALLOWED_SUBS: \"${WF_OIDC_ALLOWED_SUBS:-}\"\n      # Set \"true\" to allow ANY IdP-authenticated user when no allowlist is set\n      # (only safe on a dedicated single-user IdP).\n      WF_OIDC_ALLOW_ANY: \"${WF_OIDC_ALLOW_ANY:-}\"\n      # Logout ends the IdP session too when supported (RP-Initiated Logout). To return\n      # to the app afterward, set this AND register it in the IdP; otherwise omit it.\n      WF_OIDC_POST_LOGOUT_REDIRECT_URL: \"${WF_OIDC_POST_LOGOUT_REDIRECT_URL:-}\"\n      # Set to \"false\" to force local-only logout even when the IdP supports RP-Initiated Logout.\n      WF_OIDC_RP_LOGOUT: \"${WF_OIDC_RP_LOGOUT:-}\"\n\n      # ── AI Agent Access / MCP (optional) ────────────────────────────────\n      # Requires Wealthfolio authentication via password or OIDC.\n      WF_MCP_ENABLED: \"${WF_MCP_ENABLED:-false}\"\n      WF_MCP_AUDIT_ENABLED: \"${WF_MCP_AUDIT_ENABLED:-true}\"\n\n      # Required when auth is enabled — set to your app's origin, e.g. https://wealthfolio.example.com\n      WF_CORS_ALLOW_ORIGINS: \"${WF_CORS_ALLOW_ORIGINS:-}\"\n      WF_REQUEST_TIMEOUT_MS: \"${WF_REQUEST_TIMEOUT_MS:-30000}\"\n    healthcheck:\n      test:\n        [\"CMD\", \"wget\", \"--quiet\", \"--tries=1\", \"--spider\", \"http://127.0.0.1:8088/api/v1/healthz\"]\n      interval: 30s\n      timeout: 10s\n      retries: 3\n      start_period: 15s\n    deploy:\n      resources:\n        limits:\n          memory: 512M\n        reservations:\n          memory: 128M\n    security_opt:\n      - no-new-privileges:true\n    read_only: true\n    tmpfs:\n      - /tmp:size=64M\n\nvolumes:\n  wealthfolio-data:\n    driver: local\n",
      "source_url": "https://github.com/wealthfolio/wealthfolio/blob/1e08bbc1e2ae88cb245130d315df4283b1fe256d/compose.yml",
      "validation_status": "config_ok"
    },
    {
      "order": 3,
      "kind": "shell",
      "language": "bash",
      "label": "Start it",
      "body": "docker compose up -d",
      "source_url": "https://github.com/wealthfolio/wealthfolio/blob/1e08bbc1e2ae88cb245130d315df4283b1fe256d/compose.yml",
      "validation_status": "unvalidated"
    },
    {
      "order": 4,
      "kind": "verify",
      "language": "text",
      "label": "Open the app",
      "body": "Open http://localhost:8088. The compose file publishes host port 8088 for the wealthfolio service.",
      "source_url": "https://github.com/wealthfolio/wealthfolio/blob/1e08bbc1e2ae88cb245130d315df4283b1fe256d/compose.yml",
      "validation_status": "unvalidated"
    }
  ],
  "notes": [
    {
      "kind": "gotcha",
      "title": "Some images use the latest tag or no tag",
      "body": "Images without a pinned version: wealthfolio: wealthfolio/wealthfolio:latest. A later pull can get a different version.",
      "source_url": "https://github.com/wealthfolio/wealthfolio/blob/1e08bbc1e2ae88cb245130d315df4283b1fe256d/compose.yml",
      "checked_at": "2026-10-22"
    },
    {
      "kind": "gotcha",
      "title": "The compose file publishes host ports",
      "body": "Host ports: 8088 (wealthfolio). A port without a host address listens on all host network interfaces.",
      "source_url": "https://github.com/wealthfolio/wealthfolio/blob/1e08bbc1e2ae88cb245130d315df4283b1fe256d/compose.yml",
      "checked_at": "2026-10-22"
    }
  ],
  "signals": {
    "captured_at": "2026-10-22",
    "stars": 9231,
    "forks": 768,
    "open_issues": 534,
    "last_push": "2026-10-22",
    "days_since_push": 0,
    "latest_release": "v3.10.0",
    "latest_release_date": "2026-10-14",
    "days_since_release": 7
  },
  "links": {
    "html": "https://openlogs.fyi/tools/wealthfolio",
    "markdown": "https://openlogs.fyi/tools/wealthfolio.md",
    "json": "https://openlogs.fyi/tools/wealthfolio.json"
  },
  "updated_at": "2026-10-22"
}
