Open-source alternatives guide
Self-Host Ghostfolio: Investment Portfolio Tracker 2026
Self-host Ghostfolio in 2026. AGPL 3.0, ~4K stars, TypeScript — privacy-first investment portfolio tracker with multi-currency support and benchmarking.
TL;DR
Ghostfolio (AGPL 3.0, ~4K GitHub stars, TypeScript/Angular) is a privacy-first investment portfolio tracker. Track stocks, ETFs, crypto, and other assets across multiple accounts and currencies — all on your own server. Personal Capital (now Empower) requires linking your brokerage accounts to their cloud; Ghostfolio keeps everything local. Multi-currency support, dividend tracking, benchmark comparison, and a clean UI for understanding your net worth.
Key Takeaways
- Ghostfolio: AGPL 3.0, ~4K stars, TypeScript — investment portfolio tracker
- Multi-currency: Track assets in any currency with automatic conversion
- Data providers: Yahoo Finance, Alpha Vantage, and more for real-time quotes
- Benchmarking: Compare portfolio performance against S&P 500, custom indices
- Dividend tracking: Track dividend income, yield, and reinvestment
- Privacy-first: No brokerage account linking — manual or CSV import only
Part 1: Docker Setup
# docker-compose.yml
services:
ghostfolio:
image: ghostfolio/ghostfolio:latest
container_name: ghostfolio
restart: unless-stopped
ports:
- "3333:3333"
environment:
NODE_ENV: production
HOST: "0.0.0.0"
PORT: 3333
# Database:
DATABASE_URL: "postgresql://ghostfolio:${DB_PASSWORD}@db:5432/ghostfolio"
# Redis:
REDIS_HOST: redis
REDIS_PORT: 6379
# Security:
ACCESS_TOKEN_SALT: "${ACCESS_TOKEN_SALT}" # openssl rand -hex 32
JWT_SECRET_KEY: "${JWT_SECRET}" # openssl rand -hex 32
# Data providers (at least one required):
# Yahoo Finance (free, default):
# No additional config needed
# Alpha Vantage (free tier: 25 req/day):
# ALPHA_VANTAGE_API_KEY: "your-key"
depends_on:
- db
- redis
db:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- ghostfolio_db:/var/lib/postgresql/data
environment:
POSTGRES_USER: ghostfolio
POSTGRES_PASSWORD: "${DB_PASSWORD}"
POSTGRES_DB: ghostfolio
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- ghostfolio_redis:/data
volumes:
ghostfolio_db:
ghostfolio_redis:
echo "DB_PASSWORD=$(openssl rand -base64 24)" >> .env
echo "ACCESS_TOKEN_SALT=$(openssl rand -hex 32)" >> .env
echo "JWT_SECRET=$(openssl rand -hex 32)" >> .env
docker compose up -d
Visit http://your-server:3333 → create your account.
Part 2: HTTPS with Caddy
portfolio.yourdomain.com {
reverse_proxy localhost:3333
}
Part 3: Adding Accounts and Holdings
Create accounts
Accounts represent your brokerage, bank, or crypto accounts:
- Accounts → + Add Account
- Name:
Fidelity,Vanguard,Coinbase,401k - Platform: select or create
- Currency: USD, EUR, GBP, etc.
Add holdings
- Portfolio → + Add Activity
- Activity type: Buy / Sell / Dividend
- Search for asset:
AAPL,VTI,BTC - Fill in:
- Date: purchase date
- Quantity: number of shares/units
- Unit price: price per share at purchase
- Fee: transaction fee
- Account: which account
- Save
Supported asset types
| Type | Examples |
|---|---|
| Stocks | AAPL, MSFT, GOOGL |
| ETFs | VTI, VOO, QQQ, VT |
| Crypto | BTC, ETH, SOL |
| Mutual Funds | VTSAX, FXAIX |
| Bonds | Treasury, Corporate |
| Precious Metals | Gold, Silver |
| Cash | Savings accounts, CDs |
Part 4: Portfolio Dashboard
Overview
The dashboard shows:
- Total net worth: Sum of all accounts
- Performance: Absolute and percentage returns
- Allocation: By asset class, region, sector, account
- Holdings table: Each position with current value, gain/loss, weight
Performance chart
- Time-weighted return vs money-weighted return
- Compare against benchmarks (S&P 500, total market)
- Filter by: 1M, 3M, 6M, YTD, 1Y, 5Y, Max
Allocation view
- By asset class: Stocks vs bonds vs crypto vs cash
- By region: US, Europe, Emerging Markets
- By sector: Technology, Healthcare, Finance, etc.
- By account: Distribution across brokerages
- By currency: USD, EUR, etc.
Part 5: Import Transactions
CSV import
Date,Type,Symbol,Quantity,Price,Fee,Currency,Account
2025-01-15,BUY,VTI,50,245.30,0,USD,Vanguard
2025-02-01,BUY,AAPL,10,180.50,4.95,USD,Fidelity
2025-03-01,DIVIDEND,VTI,,125.00,0,USD,Vanguard
2025-06-15,SELL,AAPL,5,195.20,4.95,USD,Fidelity
Portfolio → Import → CSV → upload file → map columns → import.
Manual entry tips
- Enter transactions in chronological order
- Include dividends for accurate total return
- Record fees for true cost basis
- Use the correct currency for each transaction
Part 6: Benchmarking
Compare your portfolio performance against indices:
- Settings → Benchmarks
- Add:
SPY(S&P 500),VT(Total World), custom index - Dashboard → toggle benchmark overlay on performance chart
Example insights
Your portfolio: +12.3% YTD
S&P 500 (SPY): +15.1% YTD
Difference: -2.8% (underperforming)
Part 7: Dividend Tracking
Log dividends
- + Add Activity → Dividend
- Symbol:
VTI - Amount: total dividend received
- Date: ex-dividend date
- Account: receiving account
Dividend dashboard
Shows:
- Dividend income by month/year: bar chart of passive income
- Dividend yield: weighted yield across portfolio
- Top dividend payers: which holdings contribute most
Part 8: Multi-User and Security
Additional users
Admin → User Management → Invite:
Email: partner@example.com
Role: User
Each user has their own private portfolio — no data shared between users.
Security practices
- No brokerage linking: Ghostfolio never has access to your actual accounts
- Self-hosted: Data stays on your server
- Manual entry: You control exactly what data is stored
- Encryption: Use HTTPS and encrypted database backups
Maintenance
# Update:
docker compose pull
docker compose up -d
# Backup database:
docker exec ghostfolio-db-1 pg_dump -U ghostfolio ghostfolio \
| gzip > ghostfolio-db-$(date +%Y%m%d).sql.gz
# Logs:
docker compose logs -f ghostfolio
Why Self-Host Ghostfolio
Ghostfolio's premium SaaS tier starts at $16.99/month — $203.88/year — for unlimited portfolio entries, advanced analytics, and priority support. The basic free tier limits portfolios to a single account and restricts some reporting features. Self-hosting gives you the full feature set with no account limits, no usage caps, and no subscription fee. Your only cost is the VPS.
The privacy argument is the stronger motivation for most users. Tracking investments requires entering sensitive financial information: which assets you own, how many shares, when you bought them, and at what price. This is information you wouldn't want to leak to a data breach or share with a SaaS provider's analytics pipeline. Ghostfolio is explicit that it does not require brokerage account linking — everything is entered manually or via CSV. When self-hosted, that data never leaves your server. For investors with significant holdings, this privacy guarantee is worth more than any subscription cost savings.
Ghostfolio's approach of manual entry (rather than automatic brokerage sync like Personal Capital or Wealthfront) is a feature, not a limitation. Automatic sync services require OAuth access to your brokerage accounts — meaning the service can read all your account activity. Ghostfolio's manual model means zero read access to your actual accounts. Yes, it takes a few minutes to enter each transaction, but that manual step is the security boundary that keeps your broker credentials entirely separate from your portfolio tracker.
Multi-currency support is a meaningful practical advantage for international investors. Ghostfolio handles assets denominated in different currencies and converts portfolio value using daily exchange rates. If you hold US stocks, European ETFs, and cryptocurrency, Ghostfolio shows your total net worth in your home currency with appropriate conversion applied historically.
When NOT to self-host Ghostfolio. If you want automatic portfolio sync from your broker, Ghostfolio isn't the tool — and neither is any self-hosted alternative (for obvious security reasons). If you need tax optimization advice, automated rebalancing recommendations, or a robo-advisor, purpose-built SaaS tools serve those use cases better. Ghostfolio is a tracking and visualization tool, not a financial advisor.
Prerequisites
Ghostfolio requires three services: the TypeScript/Angular application, PostgreSQL, and Redis (for caching market data). Together they use around 300–500MB RAM at idle. A Hetzner CX22 (2 vCPU, 4GB RAM) at €4.50/month is the recommended starting point. Market data fetching from Yahoo Finance is periodic (not continuous), so CPU requirements are modest. See the VPS comparison guide for full provider comparisons.
Docker Engine 24+ and Docker Compose v2 are required. Three environment variables must be generated before first run:
echo "DB_PASSWORD=$(openssl rand -base64 24)" >> .env
echo "ACCESS_TOKEN_SALT=$(openssl rand -hex 32)" >> .env
echo "JWT_SECRET=$(openssl rand -hex 32)" >> .env
These values are used to hash access tokens and sign JWTs — if they change after accounts are created, all existing sessions are invalidated and passwords must be reset.
DNS: create an A record for portfolio.yourdomain.com pointing to your server. Caddy handles HTTPS certificate provisioning automatically.
Data providers: Yahoo Finance works out of the box with no API key and covers most US stocks, ETFs, and major international securities. For broader coverage or higher request limits, configure Alpha Vantage (free tier: 25 requests/day) or Coingecko for cryptocurrency prices.
Production Security Hardening
Your investment portfolio data is sensitive financial information. Treating the Ghostfolio server with the same care as any financial account is appropriate.
UFW firewall. Allow only SSH, HTTP, and HTTPS:
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
Ghostfolio's internal port 3333, PostgreSQL's 5432, and Redis's 6379 should never be publicly exposed.
Fail2ban. Protect SSH and the application login endpoint:
apt install fail2ban -y
Create /etc/fail2ban/jail.local:
[DEFAULT]
bantime = 2h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
systemctl restart fail2ban
Secrets management. Store all three generated secrets (DB_PASSWORD, ACCESS_TOKEN_SALT, JWT_SECRET) in .env with restricted permissions:
chmod 600 .env
SSH hardening:
# /etc/ssh/sshd_config
PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
systemctl restart sshd
Automatic OS updates:
apt install unattended-upgrades -y
dpkg-reconfigure --priority=low unattended-upgrades
Database backups. All portfolio transactions live in PostgreSQL. A data loss event means losing your entire investment history. Schedule daily encrypted backups — the automated backup guide covers Restic-based backup workflows with rotation policies. Use Ghostfolio's built-in CSV export as a secondary backup: Portfolio → Export → CSV, and store the export offline.
For a complete hardening checklist, see the self-hosting security checklist.
Troubleshooting Common Issues
"JWT secret not set" or application fails to start. All three environment variables (ACCESS_TOKEN_SALT, JWT_SECRET, DB_PASSWORD) are required. If any are missing from .env, Ghostfolio refuses to start. Verify your .env file is in the same directory as docker-compose.yml and that Docker Compose is loading it. Check with docker compose config to see resolved environment variables.
Asset price not updating (stale quotes). Ghostfolio fetches market data periodically via Redis-cached jobs. If prices are stale, check whether the Redis container is running: docker compose ps. Also verify your data provider is reachable: docker compose logs ghostfolio | grep "Yahoo". Yahoo Finance occasionally rate-limits requests — if you're seeing consistent failures, configure Alpha Vantage as a secondary provider.
Cannot find asset when adding a holding. The asset search uses the configured data provider's symbol lookup. Try the exact ticker symbol (e.g., AAPL not Apple) or ISIN number. For international assets, the symbol format may differ by exchange — German stocks on XETRA use .DE suffix (e.g., SAP.DE). If an asset isn't in Yahoo Finance's database, you can add it manually as a custom security.
"Database connection failed" on startup. This usually means PostgreSQL hasn't finished initializing before Ghostfolio tries to connect. The compose file's depends_on uses a health check, but on very slow VPSes this may not be enough. Add a restart: unless-stopped to the Ghostfolio service so it retries automatically. Alternatively, start the database first: docker compose up -d db redis, wait 30 seconds, then docker compose up -d ghostfolio.
Portfolio performance calculation is incorrect. Ghostfolio uses time-weighted return (TWR) for performance, which handles cash flows correctly for buy/sell events. If your portfolio shows unexpected returns, verify all transactions are entered in chronological order and that the transaction type (Buy/Sell/Dividend) is correct. A "Sell" entered as a "Buy" will significantly distort performance calculations.
Backup restore fails. Stop Ghostfolio and Redis before restoring the PostgreSQL database: docker compose stop ghostfolio redis. Restore the dump: gunzip -c backup.sql.gz | docker exec -i ghostfolio-db-1 psql -U ghostfolio -d ghostfolio. Then restart: docker compose start redis ghostfolio. Redis cache will be cold after restart and will warm up as market data fetches run.
Portfolio shows incorrect allocation percentages. If your allocation chart doesn't add up to 100%, check whether you have cash accounts that are not assigned an asset class. Ghostfolio needs every account and activity to have a currency assigned. Accounts with no position value (empty accounts) can sometimes cause display rounding issues. Also verify that all your holdings have current market prices — assets with stale or missing prices (often happens with less-traded securities or manual custom assets) may show as 0% allocation.
Ghostfolio container restarting repeatedly. Check logs with docker compose logs ghostfolio. A common cause is the ACCESS_TOKEN_SALT or JWT_SECRET being empty strings rather than genuinely missing — Docker Compose substitutes empty strings for undefined variables. Ensure both values are non-empty 32+ character hex strings in your .env file. Also confirm that the Redis container is healthy before Ghostfolio starts, as the application requires Redis on startup for cache operations.
Dividend payments not showing in the monthly income chart. Dividend activities must be logged with the exact security symbol matching your portfolio entry. If you own VTI and log a dividend under a slightly different symbol (e.g., VTI.US vs VTI), Ghostfolio won't link the dividend to the holding. Check the exact symbol format by looking at how the holding appears in your portfolio and use the same format for dividend entries.
Market data for a custom asset not updating. Custom securities (manually created, not sourced from Yahoo Finance) require manually entering price updates. Ghostfolio doesn't auto-fetch prices for custom assets since there's no external data source to query. Set up a periodic reminder to update custom asset prices, or use the Ghostfolio API to automate price updates from whatever data source you have access to.
See also: Actual Budget — for budgeting and expense tracking
See all open source finance tools at OSSAlt.com/categories/finance.
The SaaS-to-Self-Hosted Migration Guide (Free PDF)
Step-by-step: infrastructure setup, data migration, backups, and security for 15+ common SaaS replacements. Used by 300+ developers.
Join 300+ self-hosters. Unsubscribe in one click.