Self-Hosting Guide
Complete guide to deploying Budgero on your own infrastructure with Docker, native binaries, environment configuration, and optional integrations.
In this guide
- Deploy Budgero using Docker or native binaries on any platform.
- Zero configuration for localhost - admin account auto-created on first run.
- Set WEBSOCKET_ALLOWED_ORIGINS when accessing Budgero via a LAN IP or domain - sync requires it.
- Optionally configure currency conversion API for multi-currency support.
This guide walks you through deploying Budgero on your own infrastructure. Whether you prefer Docker containers or native binaries, you'll have a fully functional budget server running in minutes.
Deployment options
Budgero self-hosted can be deployed three ways:
- Docker - Recommended for most users. Single command, works on any platform with Docker.
- Native binary - Direct install on macOS, Linux, or Windows. Ideal for minimal setups or when Docker isn't available.
- Docker Compose - Best for production deployments with persistent storage and easy updates.
Quick start with Docker
docker run -d \ --name budgero \ -p 127.0.0.1:3001:3001 \ -v budgero_data:/data \ budgero/budgeroOn first startup, check the logs for your admin credentials:
docker logs budgero Admin account created:
Username: admin
Password: <randomly-generated-password>
⚠️ Save this password now - it will NOT be shown again.
- App:
http://localhost:3001 - Admin UI:
http://localhost:3001/admin
Use a reverse proxy (Caddy/nginx) if you need external access with HTTPS.
The quick-start command binds to 127.0.0.1, so it works out of the box. If you access Budgero from any other origin — a LAN IP, a hostname, or a domain behind a reverse proxy — you must also set WEBSOCKET_ALLOWED_ORIGINS (see WebSocket origins), or real-time sync will not connect.
Budgero persists all self-host data under /data:
- Metadata DB:
/data/budgero.db - Encrypted budget blobs:
/data/budget_spaces/
Docker Compose
services: budgero: image: budgero/budgero:latest ports: - "127.0.0.1:3001:3001" # environment: # # Required if you access Budgero from anywhere other than localhost: # - WEBSOCKET_ALLOWED_ORIGINS=http://192.168.1.50:3001 volumes: - budgero_data:/data restart: unless-stoppedvolumes: budgero_data:docker compose up -ddocker compose logs budgero # get admin credentials on first runWith Caddy for HTTPS
services: budgero: image: budgero/budgero:latest expose: - "3001" environment: - WEBSOCKET_ALLOWED_ORIGINS=https://budget.yourdomain.com volumes: - budgero_data:/data restart: unless-stopped caddy: image: caddy:2-alpine ports: - "80:80" - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data restart: unless-stoppedvolumes: budgero_data: caddy_data:# Caddyfile
budget.yourdomain.com {
reverse_proxy budgero:3001
}
Native binary installation
macOS and Linux
curl -fsSL https://budgero.app/install.sh | bashWindows (PowerShell)
irm https://budgero.app/install.ps1 | iexAfter installation, start the server:
budgero serveThe server runs on port 3001 by default. Your database is stored in ./data/budgero.db.
WebSocket origins (required for non-localhost access)
Budgero syncs your budget in real time over a WebSocket, and the server only accepts WebSocket connections from origins it knows. Out of the box, only localhost / 127.0.0.1 origins are allowed. If you open Budgero from anything else — a LAN IP like http://192.168.1.50:3001, or https://budget.yourdomain.com behind a reverse proxy — the sync connection is rejected and the app cannot load your budget.
Set WEBSOCKET_ALLOWED_ORIGINS to the exact origin(s) you use in the browser, comma-separated:
# Single origin (reverse proxy with HTTPS)WEBSOCKET_ALLOWED_ORIGINS=https://budget.yourdomain.com# Multiple origins (domain + direct LAN access)WEBSOCKET_ALLOWED_ORIGINS=https://budget.yourdomain.com,http://192.168.1.50:3001Each entry must match the browser's origin exactly: scheme, host, and port (when non-default). Wildcards are not supported. If it's missing or mismatched, the server logs WebSocket connection rejected due to CORS with the origin it saw and the list it allowed — copy the rejected origin from that log line verbatim.
Environment variables
| Variable | Default | Description |
|---|---|---|
PORT | 3001 | HTTP server port |
DB_PATH | data/budgero.db | SQLite database file path |
WEBSOCKET_ALLOWED_ORIGINS | localhost origins only | Comma-separated list of browser origins allowed to connect to sync. Required for any non-localhost access — see WebSocket origins |
LOG_LEVEL | info | debug, info, warn, error |
CURRENCYLAYER_API_KEY | - | Optional: enables multi-currency conversion |
UPDATE_CHECK_DISABLED | false | Set true to disable the update check — see Update check |
Update check
When someone opens the app, the server checks whether a newer Budgero release exists — at most once every 12 hours, cached in between. The request to budgero.app carries exactly three values: your install's version, its build sha, and the string selfhost. No instance ID, no user data, no cookies. We aggregate these into daily version counters to know roughly how many installs exist and which versions are in use — nothing per-instance is stored.
Set UPDATE_CHECK_DISABLED=true to turn it off completely; the app then makes no unsolicited outbound calls. Air-gapped installs need no configuration — a failed check is cached quietly and the app just behaves as if it's up to date.
First-run admin setup
On first startup (when no users exist), Budgero automatically creates an admin account with a random password and prints it once:
- Docker:
docker logs budgero - Foreground: Prints directly to your terminal
- Daemon mode: Check
data/logs/<name>.log
Currency conversion (optional)
For multi-currency accounts, get a free API key from currencylayer.com (100 requests/month, 168 currencies). Add it to your environment:
CURRENCYLAYER_API_KEY=your_api_key_hereSingle-currency users can skip this—Budgero works fine without it.
User management
Admin UI
Access the admin dashboard at /admin to manage users, view activity, and configure settings through a web interface.
CLI
Alternatively, manage users via command line:
# Create a userbudgero admin create-user --username johndoe --name "John" --password "secret"# List all usersbudgero admin list-users# Reset a passwordbudgero admin reset-password --username johndoe --password "new-password"# Block a userbudgero admin block-user --username johndoeRunning as a background service
Using the built-in daemon (all platforms)
budgero daemon start --port 3001 --name productionCheck running daemons:
budgero daemon listStop a daemon:
budgero daemon stop productionUsing systemd (Linux)
Create /etc/systemd/system/budgero.service:
[Unit]Description=Budgero Budget ServerAfter=network.target[Service]Type=simpleUser=budgeroWorkingDirectory=/opt/budgeroExecStart=/opt/budgero/budgero serveRestart=alwaysRestartSec=5[Install]WantedBy=multi-user.targetEnable and start:
sudo systemctl enable budgerosudo systemctl start budgeroUpdating
Docker
docker pull budgero/budgero:latestdocker compose downdocker compose up -dNative binary
budgero updateThis checks for the latest release and replaces the binary automatically.
Reverse proxy setup
For production, run Budgero behind a reverse proxy like nginx or Caddy for HTTPS.
Remember to set WEBSOCKET_ALLOWED_ORIGINS on the Budgero server to the public origin the proxy serves (e.g. https://budget.yourdomain.com), and make sure the proxy forwards WebSocket upgrades (both configs below do).
Caddy (automatic HTTPS)
budget.yourdomain.com {
reverse_proxy localhost:3001
}
nginx
server { listen 443 ssl http2; server_name budget.yourdomain.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; location / { proxy_pass http://localhost:3001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }}Troubleshooting
App loads but the budget never appears (sync won't connect)
If you can log in but the app hangs loading your budget — or devices stop seeing each other's changes — the sync WebSocket is almost certainly being rejected. Check the server logs for:
WebSocket connection rejected due to CORS
The log line includes the origin the browser sent and the origins the server allowed. Add the rejected origin to WEBSOCKET_ALLOWED_ORIGINS exactly as logged (scheme, host, and port must all match) and restart the server.
Database locked errors
SQLite doesn't handle concurrent writes well. If you see lock errors:
- Ensure only one Budgero instance is running
- Check that
DB_PATHpoints to a local filesystem (not a network share)
Port already in use
Change the port with PORT=4000 or --port 4000.
Container won't start
Check logs with docker logs budgero. Common issues:
- Volume permissions (ensure the container can write to
/data) - Port conflicts (another service using port 3001)
FAQ
- Do I need to set up a database? No. Budgero uses SQLite plus encrypted blob files. Just mount
/dataand Budgero handles the rest. - Can I migrate from Budgero Cloud to self-hosted? Yes. Export your data from Cloud and import it into your self-hosted instance.
- Is there a mobile app? Access your self-hosted instance from any browser. Add it to your home screen for an app-like experience.
- How do I back up my data? Back up the entire
/datavolume (includesbudgero.dbandbudget_spaces/).