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:
- Click Add Account from the sidebar
- Choose the account type — checking, savings, credit card, investment, property, vehicle, crypto, or other
- Enter the current balance and currency
- 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:
- Export transactions from your bank as CSV
- Navigate to the account in Maybe
- Use the Import feature to upload your CSV
- Map columns (date, amount, description, category) to Maybe’s fields
- Review and confirm the import
Enabling AI Features (Optional)
If you want Maybe’s AI chat and rules engine:
- Get an OpenAI API key
- Add it to your
.envfile:
echo 'OPENAI_ACCESS_TOKEN=sk-your-key-here' >> .env
- 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:
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
.envfile exists and contains the key - Database not ready — The healthcheck should handle this, but try
docker compose down && docker compose up -dfor 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_TOKENis set correctly in.env - Restart the stack after adding the key
- Check that your OpenAI account has available credits
Maybe vs Alternatives
| Feature | Maybe | Actual Budget | Firefly III |
|---|---|---|---|
| Docker setup | Simple (4 containers) | Simple (1 container) | Moderate (2+ containers) |
| Bank sync | Manual/CSV | Manual/CSV | Manual/CSV + importers |
| Net worth tracking | ✅ Built-in | ❌ Budget-focused | ✅ With setup |
| Investment tracking | ✅ Full portfolio | ❌ | ⚠️ Limited |
| AI features | ✅ OpenAI-powered | ❌ | ❌ |
| Active development | Community forks | Active | Active |
| Learning curve | Low | Low | Medium |
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.