Tally

Tally

Docker app from JaydenRoberts' Repository

Overview

Self-hosted personal finance for households. Track accounts, transactions, budgets, savings goals, and debt. Link transactions to savings goals and debts. Record transfers between accounts. CSV and PDF bank statement import with reconciliation. AI chat interface (Anthropic, OpenAI, or Ollama). One-click backup, full JSON export, and CSV export from Settings, plus an automatic verified snapshot before any upgrade that changes the database. Dracula theme. Single Docker container. Runs as a non-root user; the appdata data path must remain writable by the container (default on Unraid). Single-tenant design: any authenticated user (owner or viewer) can see all financial data — roles limit actions, not data visibility. Do not expose to untrusted users or the public internet. If you reach Tally through a reverse proxy, tunnel, or custom domain, set ALLOWED_ORIGINS.

Tally

A self-hosted personal finance web application for households. Track accounts, transactions, budgets, savings goals, and debt — all in one place, on your own infrastructure.

License


⚠️ Security: single-tenant only

Tally is designed for a single household you fully trust. Authentication gates access to the app, but the data layer is not user-scoped: any authenticated user (owner or viewer) can read all accounts, transactions, budgets, debts, and savings in the instance. Roles limit actions, not data visibility.

Do not expose Tally as a shared multi-user service to people who should not see each other's finances, and do not put it on the public internet. Run it on your LAN or behind a private tunnel/VPN. Per-user data isolation is tracked as a future enhancement.

Cross-origin browser access is additionally restricted to an explicit allow-list (ALLOWED_ORIGINS), and the login and password-recovery endpoints are rate-limited per IP. See Configuration.


Features

  • Multi-user with configurable roles (Owner / Viewer by default)
  • Transaction tracking — verified/unverified status, sortable columns, inline category editing, bulk category update
  • Transfers — record money moving between accounts; excluded from budget calculations
  • Budgets by category and period (transfers and debt payments excluded)
  • Savings goals — allocate income across goals in one step; link withdrawals back to the goal
  • Debt tracking — interest rate, minimum payment, paydown strategy badges; link expense transactions directly to a debt
  • Closed account lifecycle — mark accounts as closed rather than deleting them
  • CSV/PDF import — upload your bank statement files directly through the import wizard
  • AI chat interface — ask questions about your finances in plain language; powered by Anthropic, OpenAI, or any OpenAI-compatible endpoint (e.g. Ollama); persona system controls data access and write permissions
  • Backup & export — automatic verified snapshot before every upgrade; one-click database backup, full JSON export, and transactions CSV from Settings → Data
  • Mobile navigation — slide-in drawer on small screens
  • Dracula-inspired UI with custom logo and favicon
  • Single Docker container — easy self-hosting

Installation

Option 1 — Docker run (quick start)

Warning: Tally runs as a non-root user inside the container. The host directory you mount at /data must be writable by that user, or Tally will fail to create its database on first start. On Unraid, /mnt/user/appdata/... is writable by default. On a plain Linux host, make the data directory writable by the container's user first (see Getting Started).

# Generate a secret key
SECRET_KEY=$(openssl rand -hex 32)

docker run -d \
  --name tally \
  --restart unless-stopped \
  -p 8092:8091 \
  -v /path/to/your/data:/data \
  -e SECRET_KEY=$SECRET_KEY \
  -e FIRST_RUN_OWNER_USERNAME=admin \
  -e FIRST_RUN_OWNER_PASSWORD=changeme \
  jaydenroberts/tally:latest

Open http://localhost:8092 — your owner account will be created automatically on first run.

Option 2 — Docker Compose

Create a docker-compose.yml:

services:
  tally:
    image: jaydenroberts/tally:latest
    container_name: tally
    restart: unless-stopped
    ports:
      - "8092:8091"
    volumes:
      - ./data:/data
    environment:
      - SECRET_KEY=${SECRET_KEY}
      - ACCESS_TOKEN_EXPIRE_DAYS=30
      - FIRST_RUN_OWNER_USERNAME=${FIRST_RUN_OWNER_USERNAME}
      - FIRST_RUN_OWNER_PASSWORD=${FIRST_RUN_OWNER_PASSWORD}

Create a .env file alongside it:

SECRET_KEY=         # generate with: openssl rand -hex 32
FIRST_RUN_OWNER_USERNAME=admin
FIRST_RUN_OWNER_PASSWORD=changeme

Then start:

docker compose up -d

Option 3 — Unraid Community Applications

  1. Open your Unraid web UI and go to the Apps tab.
  2. Search for Tally.
  3. Click Install and fill in the required fields (SECRET_KEY is mandatory — generate one with openssl rand -hex 32).
  4. Click Apply and wait for the container to start.
  5. Open http://[your-unraid-ip]:8092.

Manual install via Docker tab (without CA):

  1. Go to the Docker tab in Unraid and click Add Container.
  2. Set the repository to jaydenroberts/tally:latest.
  3. Add a path: Container path /data → Host path /mnt/user/appdata/tally/data (Read/Write).
  4. Add a variable: SECRET_KEY = your generated key.
  5. Set port: Host 8092 → Container 8091.
  6. Click Apply.

Configuration

All configuration is via environment variables:

Variable Required Default Description
SECRET_KEY Yes — JWT signing secret. Generate with openssl rand -hex 32. Never reuse across installs.
ACCESS_TOKEN_EXPIRE_DAYS No 30 How long login sessions last, in days.
FIRST_RUN_OWNER_USERNAME No — Auto-creates the first owner account on startup. Leave blank to use the setup page instead.
FIRST_RUN_OWNER_PASSWORD No — Required if FIRST_RUN_OWNER_USERNAME is set.
DATABASE_URL No sqlite:////data/tally.db SQLite database path. Change only if you know what you're doing.
AI_PROVIDER No — AI provider for the chat feature: anthropic (default when unset), openai, or ollama (any OpenAI-compatible endpoint). To keep the feature inactive, set no API key (see AI_API_KEY).
AI_API_KEY No — API key for the selected provider. If unset, falls back to ANTHROPIC_API_KEY when present in the container environment — unset both to keep the chat feature inactive. Not required for local Ollama.
AI_MODEL No — Model name to use (e.g. claude-sonnet-4-6, gpt-4o, llama3).
AI_BASE_URL No — Base URL override for OpenAI-compatible endpoints (e.g. http://ollama:11434/v1). Required for Ollama; not needed for Anthropic or OpenAI.
ALLOWED_ORIGINS No local origin Comma-separated allow-list of origins permitted to call the API from a browser (CORS). Add your LAN/tunnel URL here if you access Tally from another hostname.
AUTH_RATE_LIMIT_MAX No 5 Maximum login/password-recovery attempts per IP within the rate-limit window.
AUTH_RATE_LIMIT_WINDOW_SECONDS No 60 Length of the auth rate-limit window, in seconds.
MAX_UPLOAD_BYTES No 10485760 Maximum size (in bytes) of a statement file uploaded through the import wizard. Uploads over this limit are rejected.
RECOVERY_TOKEN No — Enables the POST /api/auth/recover endpoint for owner password recovery. Use a token of at least 32 random characters (openssl rand -hex 32). Remove after use.
BACKUP_DIR No backups beside the database Where automatic pre-upgrade snapshots are written. With the shipped defaults this is /data/backups.
BACKUP_KEEP No 5 How many automatic snapshots to keep. Older ones are deleted after a new one is written. Minimum 1.
PRE_MIGRATION_BACKUP No on Set to off to skip the automatic snapshot taken before an upgrade changes the database. See Backup & Restore.
CHAT_HISTORY_TURNS No 30 hosted / 10 Ollama How many prior chat turns are replayed as context in the AI Coach. Does not limit what is stored — the full conversation is always kept in the database.
TALLY_LOCAL_PROVIDER_WRITE_TOOLS No deny Only applies when AI_PROVIDER=ollama. Set to allow to let a local model use write tools; the default strips them.

First-Run Setup

On first start, Tally checks whether any users exist. If none do, it enters setup mode.

Automatic setup (via env vars): If FIRST_RUN_OWNER_USERNAME and FIRST_RUN_OWNER_PASSWORD are set, the owner account is created silently at startup. No setup page is shown.

Manual setup (via browser): If those vars are not set, navigate to http://[host]:8092 — you will be redirected to a setup page where you can create the first owner account. This endpoint is disabled once any user exists.

After setup, log in with your owner credentials. You can add viewer accounts, configure roles, and invite household members from the Settings page.


Role System

Tally ships with two roles:

Slug Default Display Name Permissions
owner Owner Full access: manage users, accounts, all data
viewer Viewer Read-only access to shared household data

Display names are editable by any owner via the UI without affecting permissions logic.


Documentation

Full documentation is available in the docs/ directory:

Guide Description
Getting Started First-run setup, logging in, adding accounts
Configuration All environment variables explained
Dashboard Balance summary and recent transactions
Accounts Adding accounts, closed account lifecycle
Transactions Logging, importing, transfers, linking to savings/debt
Budgets Monthly category budgets and progress tracking
Savings Goals Goal setup, contributions, bucket allocation
Debt Tracker Debt tracking, payment logging, paydown strategies
CSV & PDF Import Importing bank statements, column mapping, reconciliation
AI Coach Chat interface, personas, data access levels
Settings User management, categories, personas, data exports, preferences
Backup & Restore Automatic snapshots, exports, and the restore procedure

Development

Prerequisites

  • Python 3.14 — the version the runtime image and CI use; older versions are untested
  • Node.js 26 — the version the image build and CI use; older versions are untested

Backend

cd backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8091

Frontend

cd frontend
npm install
npm run dev   # proxies /api to port 8091

Build & Run (Docker)

docker build -t tally .
docker run -p 8092:8091 -v $(pwd)/data:/data tally

Financial File Import

Tally imports transactions from bank statement files you upload directly through the import wizard. Uploads are parsed locally and never leave your machine.

Supported formats: CSV (auto-detected column mapping), PDF bank statements (text extraction).


Privacy

Tally is fully self-hosted. Tally's application code collects no data, contains no telemetry or analytics, and makes no network requests on your behalf. All your financial data stays in your own SQLite database, on your own hardware. Uploaded financial statement files are only parsed locally for import (see Financial File Import).

The AI chat feature (see AI Coach) is optional, but it is not disabled by default: the provider defaults to anthropic, and the feature will make requests whenever an API key is available — from AI_API_KEY, or falling back to an ANTHROPIC_API_KEY present in the container environment. If you want the feature off, ensure neither variable is set; with no key available, no request is ever made and no data leaves your machine. When a key is configured, your chat messages and the financial context your persona settings permit are sent only to the AI provider you configure with your own API key — Anthropic, OpenAI, or a local OpenAI-compatible endpoint such as Ollama — under that provider's terms. Running a local model via Ollama keeps even that traffic on your own network.

These statements describe what Tally's own code does. They do not cover the Docker base image, your operating system, or third-party services you choose to connect — those are outside Tally's control.

Note: Tally is a budgeting and tracking tool, not financial advice. The software is provided as-is under the MIT license.


License

MIT — see LICENSE.

Categories

Download Statistics

1,913
Total Downloads

Related apps

Explore more like this

Explore all

Details

Repository
jaydenroberts/tally:latest
Last Updated2026-09-25
First Seen2026-04-06

Runtime arguments

Web UI
http://[IP]:[PORT:8091]
Network
bridge
Privileged
false

Template configuration

Web UI PortPorttcp

Host port Tally is reached on. Access the app at http://[serverIP]:[this port]. Tally listens on 8091 inside the container; only change the host side unless you know why.

Target
8091
Default
8092
Value
8092
Data VolumePathrw

SQLite database storage. Must be a persistent path on the host. The container runs as a non-root user, so this path must be writable by the container (the default /mnt/user/appdata location on Unraid already is). Tally fails to create its database on first start if it is not writable.

Target
/data
Default
/mnt/user/appdata/tally/data
Value
/mnt/user/appdata/tally/data
SECRET_KEYVariable

JWT signing key. Generate with: openssl rand -hex 32

ACCESS_TOKEN_EXPIRE_DAYSVariable

JWT token lifetime in days.

Default
30
Value
30
ALLOWED_ORIGINSVariable

Comma-separated allow-list of browser origins permitted to call the app (CORS). Leave blank to allow only the local origin. If you reach Tally through a reverse proxy, tunnel, or custom domain/hostname, you MUST list that origin here or the browser app will break. Example: https://tally.example.com,https://tally.example.duckdns.org

MAX_UPLOAD_BYTESVariable

Maximum size in bytes for an uploaded bank statement file (CSV/PDF). Default 10485760 (10 MB). Increase only if you import unusually large statements.

Default
10485760
Value
10485760
FIRST_RUN_OWNER_USERNAMEVariable

Auto-creates the first owner account on startup. Leave blank to use the setup page instead.

FIRST_RUN_OWNER_PASSWORDVariable

Required if FIRST_RUN_OWNER_USERNAME is set.

RECOVERY_TOKENVariable

Emergency owner password reset token. Set to any strong random value (openssl rand -hex 32), call POST /api/auth/recover, then remove this variable and restart. Leave blank when not in use.

BACKUP_DIRVariable

Directory where automatic pre-upgrade database snapshots are written. Leave blank to use a backups folder beside the database — /data/backups with the shipped Data Volume path.

BACKUP_KEEPVariable

How many automatic pre-upgrade snapshots to keep. Older snapshots are deleted after a new one is written. Minimum 1.

Default
5
Value
5
PRE_MIGRATION_BACKUPVariable

Set to off to skip the automatic verified snapshot Tally takes before an upgrade changes the database. Leave on unless you run your own backup process and want faster upgrades.

Default
on
Value
on
AI_PROVIDERVariable

AI provider for the chat feature: anthropic, openai, or ollama (any OpenAI-compatible endpoint). AI is entirely optional — the rest of Tally works fully without it, and with no API key set no request is ever made. Note that clearing this field does NOT turn the feature off and does NOT hide the AI Coach page: the page stays visible in the sidebar and opens normally, but shows an error if you try to send a message without an API key. Leave this set to a real provider name; control whether AI is active with AI_API_KEY.

Default
anthropic
Value
anthropic
AI_API_KEYVariable

API key for the selected AI provider. Not required for local Ollama.

AI_MODELVariable

Model name to use (e.g. claude-sonnet-4-6, gpt-4o, llama3). Defaults to provider default if left blank.

AI_BASE_URLVariable

Base URL for OpenAI-compatible endpoints (e.g. http://ollama:11434/v1). Required for Ollama; leave blank for Anthropic or OpenAI.

CHAT_HISTORY_TURNSVariable

How many prior chat turns are replayed as context in the AI Coach. Defaults to 30 for hosted providers (Anthropic/OpenAI) or 10 for Ollama. Does not limit what is stored — the full conversation is always kept in the database.

TALLY_LOCAL_PROVIDER_WRITE_TOOLSVariable

Only applies when AI_PROVIDER=ollama. Set to allow to let a local model use write tools; the default (deny) strips them.

Default
deny
Value
deny