Self-Hosting Maybe Finance: Open Source Personal Finance Tracker

Most personal finance apps want your bank credentials, store your data on their servers, and charge a monthly fee for the privilege. Maybe Finance flips that model — it’s a fully open-source personal finance app you run on your own hardware.

Maybe started as a funded fintech startup, pivoted to open source, and eventually archived the project under AGPLv3. The app is feature-complete and actively forked by the community. You get net worth tracking, transaction management, account aggregation, spending breakdowns, and even AI-powered features — all running on your own server with your data never leaving your network.

What Maybe Finance Does

  • Multi-account tracking — Bank accounts, credit cards, investments, crypto, property, vehicles — anything with a value
  • Net worth dashboard — Real-time snapshot across all your accounts with historical trends
  • Transaction management — Import, categorize, and search transactions with bulk editing
  • Spending insights — Category breakdowns, monthly comparisons, and trend analysis
  • Investment tracking — Portfolio performance, holdings, and allocation views
  • Optional AI features — Chat with your financial data and create rules using OpenAI (requires your own API key)
  • Multi-currency support — Track accounts in different currencies with automatic conversion
  • Family/household support — Multiple users on a single instance

Prerequisites

  • A Linux server (Ubuntu/Debian, or any Docker-capable host)
  • Docker and Docker Compose installed (install guide)
  • At least 1 GB of free RAM (PostgreSQL + Redis + Rails)
  • Basic familiarity with the terminal

Deploying Maybe Finance with Docker Compose

Step 1: Create the Project Directory

mkdir -p ~/docker-apps/maybe && cd ~/docker-apps/maybe

Step 2: Generate a Secret Key

Maybe requires a SECRET_KEY_BASE for session encryption. Generate one:

openssl rand -hex 64

Copy the output — you’ll need it in the next step.

Step 3: Create the Environment File

Create a .env file with your credentials:

cat > .env << 'EOF'
SECRET_KEY_BASE=paste_your_generated_key_here
POSTGRES_USER=maybe_user
POSTGRES_PASSWORD=replace_with_a_strong_password
POSTGRES_DB=maybe_production
EOF

Replace the placeholder values with your actual generated key and a strong database password.

Step 4: Create the Docker Compose File

Create docker-compose.yml:

x-db-env: &db_env
  POSTGRES_USER: ${POSTGRES_USER}
  POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
  POSTGRES_DB: ${POSTGRES_DB}

x-rails-env: &rails_env
  <<: *db_env
  SECRET_KEY_BASE: ${SECRET_KEY_BASE}
  SELF_HOSTED: "true"
  RAILS_FORCE_SSL: "false"
  RAILS_ASSUME_SSL: "false"
  DB_HOST: db
  DB_PORT: 5432
  REDIS_URL: redis://redis:6379/1
  # Optional: enable AI features (costs money per query)
  # OPENAI_ACCESS_TOKEN: ${OPENAI_ACCESS_TOKEN}

services:
  web:
    image: ghcr.io/maybe-finance/maybe:stable
    container_name: maybe-web
    volumes:
      - app-storage:/rails/storage
    ports:
      - "3000:3000"
    restart: unless-stopped
    environment:
      <<: *rails_env
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - maybe_net

  worker:
    image: ghcr.io/maybe-finance/maybe:stable
    container_name: maybe-worker
    command: bundle exec sidekiq
    restart: unless-stopped
    depends_on:
      redis:
        condition: service_healthy
    environment:
      <<: *rails_env
    networks:
      - maybe_net

  db:
    image: postgres:16
    container_name: maybe-db
    restart: unless-stopped
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      <<: *db_env
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
      interval: 5s
      timeout: 5s
      retries: 5
    networks:
      - maybe_net

  redis:
    image: redis:7-alpine
    container_name: maybe-redis
    restart: unless-stopped
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 5s
      retries: 5
    networks:
      - maybe_net

volumes:
  app-storage:
  postgres-data:
  redis-data:

networks:
  maybe_net:
    driver: bridge

Step 5: Start Maybe Finance

docker compose up -d

Docker will pull the images (the first run takes a minute or two), set up the database, and start all services. Check the logs to confirm everything is healthy:

docker compose logs -f web

Once you see Rails booting and listening on port 3000, open your browser and navigate to http://your-server-ip:3000.

Step 6: Create Your Account

On first launch, you’ll see the Maybe registration screen. Click Create your account, enter your email and password, and you’re in. This first account becomes the admin.

Configuring Maybe Finance

Adding Accounts

After logging in, start adding your financial accounts:

  1. Click Add Account from the sidebar
  2. Choose the account type — checking, savings, credit card, investment, property, vehicle, crypto, or other
  3. Enter the current balance and currency
  4. Optionally set the account as a liability (credit cards, loans)

Maybe doesn’t automatically sync with banks (that was the commercial feature). You’ll manually enter balances or import transactions via CSV — which is actually the more private approach.

Importing Transactions

To bulk-import transaction history:

  1. Export transactions from your bank as CSV
  2. Navigate to the account in Maybe
  3. Use the Import feature to upload your CSV
  4. Map columns (date, amount, description, category) to Maybe’s fields
  5. Review and confirm the import

Enabling AI Features (Optional)

If you want Maybe’s AI chat and rules engine:

  1. Get an OpenAI API key
  2. Add it to your .env file:
echo 'OPENAI_ACCESS_TOKEN=sk-your-key-here' >> .env
  1. Restart the stack:
docker compose down && docker compose up -d

This enables chatting with your financial data (“What did I spend on groceries last month?”) and creating automated categorization rules. Note that each AI query costs money through OpenAI’s API.

Putting Maybe Behind a Reverse Proxy

For remote access with HTTPS, put Maybe behind a reverse proxy. Here’s a Caddy example:

m}ayber.eyvoeurrsdeo_mparionx.ycolmoc{alhost:3000

Or with Nginx:

server {
    listen 443 ssl;
    server_name maybe.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/maybe.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/maybe.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

If using SSL termination at the proxy level, update your .env:

RAILS_FORCE_SSL=false
RAILS_ASSUME_SSL=true

This tells Rails that SSL is handled externally, so it generates correct HTTPS URLs without trying to force redirects itself.

Backing Up Your Financial Data

Your financial data lives in PostgreSQL. Set up automated backups:

#!/bin/bash
# save as ~/docker-apps/maybe/backup.sh
BACKUP_DIR="$HOME/backups/maybe"
mkdir -p "$BACKUP_DIR"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

docker exec maybe-db pg_dump -U maybe_user maybe_production | \
  gzip > "$BACKUP_DIR/maybe_${TIMESTAMP}.sql.gz"

# Keep last 30 backups
ls -t "$BACKUP_DIR"/maybe_*.sql.gz | tail -n +31 | xargs -r rm
echo "Backup completed: maybe_${TIMESTAMP}.sql.gz"

Make it executable and add it to cron:

chmod +x ~/docker-apps/maybe/backup.sh
crontab -e
# Add: 0 3 * * * ~/docker-apps/maybe/backup.sh

To restore from a backup:

gunzip -c ~/backups/maybe/maybe_20260319_030000.sql.gz | \
  docker exec -i maybe-db psql -U maybe_user maybe_production

Updating Maybe Finance

Pull the latest image and recreate the containers:

cd ~/docker-apps/maybe
docker compose pull
docker compose up -d

The app handles database migrations automatically on startup. If you pinned to :stable, you’ll get the latest release. For more control, pin to a specific version tag from the GitHub packages page.

Troubleshooting

Container keeps restarting

Check the logs first:

docker compose logs web --tail 50

Common causes:

  • Missing SECRET_KEY_BASE — Make sure your .env file exists and contains the key
  • Database not ready — The healthcheck should handle this, but try docker compose down && docker compose up -d for a clean start
  • Port conflict — If port 3000 is taken, change the host port: "3001:3000"

Database connection refused

Verify the database container is healthy:

docker compose ps

If maybe-db shows as unhealthy, check its logs:

docker compose logs db

Usually this is a permissions issue with the data volume. Try removing and recreating it (warning: this deletes data):

docker compose down -v  # removes volumes
docker compose up -d    # fresh start

Slow performance

Maybe runs Rails + Sidekiq + PostgreSQL + Redis. On a low-spec server:

  • Ensure at least 1 GB RAM is free
  • Consider adding swap if memory is tight: fallocate -l 2G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile
  • Redis and PostgreSQL benefit from SSD storage

AI features not working

  • Verify OPENAI_ACCESS_TOKEN is set correctly in .env
  • Restart the stack after adding the key
  • Check that your OpenAI account has available credits

Maybe vs Alternatives

FeatureMaybeActual BudgetFirefly III
Docker setupSimple (4 containers)Simple (1 container)Moderate (2+ containers)
Bank syncManual/CSVManual/CSVManual/CSV + importers
Net worth tracking✅ Built-in❌ Budget-focused✅ With setup
Investment tracking✅ Full portfolio⚠️ Limited
AI features✅ OpenAI-powered
Active developmentCommunity forksActiveActive
Learning curveLowLowMedium

Maybe excels at giving you a complete financial picture — net worth, investments, spending — in a polished interface. Actual Budget is better for pure envelope budgeting. Firefly III offers the most flexibility but requires more setup.

Conclusion

Maybe Finance gives you a private, comprehensive view of your finances without handing your data to a third party. The setup is straightforward — four Docker containers, one environment file, and you’re tracking your net worth in minutes.

The project is archived but feature-complete, and the community continues to maintain forks. For a self-hoster who wants to track accounts, spending, investments, and net worth in one place, it’s one of the best options available.

Start with manual account entry to get your dashboard populated, set up automated backups, and put it behind a reverse proxy if you want access from anywhere. Your bank data stays on your hardware — exactly where it should be.