Self-Hosting Guide
Deploy Vibe Ledger on your own infrastructure
Prerequisites
- A VPS or server (Ubuntu 22.04 recommended, minimum 1GB RAM)
- Python 3.10+
- Node.js 20+ (for building frontend)
- PostgreSQL 14+ (or SQLite for dev)
- A domain with DNS configured
- Plaid API credentials (
client_idandsecretfrom dashboard.plaid.com) - Stripe API keys (for billing, optional if self-hosting for personal use)
- An Anthropic API key (for Claude AI categorization in Plaid sync and PDF extraction)
Backend Setup
1. Clone the repository
git clone git@github.com:JamestheDon/vibe-ledger.git /srv/fflmt
2. Create virtual environment
python3 -m venv /srv/fflmt/.venv && source /srv/fflmt/.venv/bin/activate
3. Install dependencies
pip install -r requirements.txt
4. Configure environment
Copy the example environment file and fill in your values:
cp .env.example .env
Edit .env and set the following variables:
DATABASE_URL=postgres://user:pass@localhost:5432/fflmt
SECRET_KEY=your-random-secret-key
PLAID_CLIENT_ID=your-plaid-client-id
PLAID_SECRET=your-plaid-secret
PLAID_ENV=sandbox # or production
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
ANTHROPIC_API_KEY=sk-ant-...
5. Run migrations
python manage.py migrate
6. Create superuser
python manage.py createsuperuser
7. Run with gunicorn
gunicorn --bind 127.0.0.1:8000 --workers 2 --timeout 120 fflmt.wsgi:application
Frontend Build
1. Navigate to frontend source
cd vibe-ledger-app/
2. Install dependencies
npm install
3. Create environment file
VITE_API_URL=https://api.yourdomain.com
4. Build for production
npm run build
5. Deploy static files
Copy the dist/ contents to your static file serving directory:
cp -r dist/* /path/to/static/
Web Server (Caddy)
Caddy is recommended because it auto-provisions HTTPS via Let's Encrypt. Example Caddyfile configuration:
api.yourdomain.com {
reverse_proxy localhost:8000
}
app.yourdomain.com {
root * /path/to/dist
file_server
try_files {path} /index.html
}
yourdomain.com {
root * /path/to/landing
file_server
}
Caddy automatically obtains and renews TLS certificates from Let's Encrypt for all configured domains.
Systemd Service
Create a systemd unit file to run gunicorn as a managed service with auto-restart:
[Unit]
Description=Vibe Ledger (gunicorn)
After=network.target postgresql.service
[Service]
User=www-data
Group=www-data
WorkingDirectory=/srv/fflmt
Environment="PATH=/srv/fflmt/.venv/bin"
ExecStart=/srv/fflmt/.venv/bin/gunicorn \
--bind 127.0.0.1:8000 \
--workers 2 \
--timeout 120 \
fflmt.wsgi:application
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl enable fflmt.service
sudo systemctl start fflmt.service
Plaid Sync (Cron/Timer)
Set up a systemd timer or cron job to keep bank transactions up to date automatically. Daily sync is recommended.
Using cron:
# Run Plaid sync daily at 6:00 AM
0 6 * * * /srv/fflmt/.venv/bin/python /srv/fflmt/manage.py plaid_sync
Or using a systemd timer, create /etc/systemd/system/fflmt-sync.timer:
[Unit]
Description=Daily Plaid sync for Vibe Ledger
[Timer]
OnCalendar=*-*-* 06:00:00
Persistent=true
[Install]
WantedBy=timers.target
And the corresponding service unit /etc/systemd/system/fflmt-sync.service:
[Unit]
Description=Vibe Ledger Plaid Sync
[Service]
User=www-data
WorkingDirectory=/srv/fflmt
Environment="PATH=/srv/fflmt/.venv/bin"
ExecStart=/srv/fflmt/.venv/bin/python manage.py plaid_sync
Type=oneshot
Key Vault / Secrets
Vibe Ledger uses a keyvault module to load secrets. In production, set environment variables or use the Django settings directly. Never commit .env or credentials files to version control.
Always use HTTPS in production. Never expose Django DEBUG=True. Rotate your SECRET_KEY periodically. Keep Plaid and Stripe credentials secure.