Back to docsGuide7 min read

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

Bash
docker run -d \  --name budgero \  -p 127.0.0.1:3001:3001 \  -v budgero_data:/data \  budgero/budgero

On first startup, check the logs for your admin credentials:

Bash
docker logs budgero
Code
  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

YAML
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:
Bash
docker compose up -ddocker compose logs budgero  # get admin credentials on first run

With Caddy for HTTPS

YAML
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:
Code
# Caddyfile
budget.yourdomain.com {
    reverse_proxy budgero:3001
}

Native binary installation

macOS and Linux

Bash
curl -fsSL https://budgero.app/install.sh | bash

Windows (PowerShell)

POWERSHELL
irm https://budgero.app/install.ps1 | iex

After installation, start the server:

Bash
budgero serve

The 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:

Bash
# 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:3001

Each 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

VariableDefaultDescription
PORT3001HTTP server port
DB_PATHdata/budgero.dbSQLite database file path
WEBSOCKET_ALLOWED_ORIGINSlocalhost origins onlyComma-separated list of browser origins allowed to connect to sync. Required for any non-localhost access — see WebSocket origins
LOG_LEVELinfodebug, info, warn, error
CURRENCYLAYER_API_KEY-Optional: enables multi-currency conversion
UPDATE_CHECK_DISABLEDfalseSet 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:

Bash
CURRENCYLAYER_API_KEY=your_api_key_here

Single-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:

Bash
# 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 johndoe

Running as a background service

Using the built-in daemon (all platforms)

Bash
budgero daemon start --port 3001 --name production

Check running daemons:

Bash
budgero daemon list

Stop a daemon:

Bash
budgero daemon stop production

Using systemd (Linux)

Create /etc/systemd/system/budgero.service:

INI
[Unit]Description=Budgero Budget ServerAfter=network.target[Service]Type=simpleUser=budgeroWorkingDirectory=/opt/budgeroExecStart=/opt/budgero/budgero serveRestart=alwaysRestartSec=5[Install]WantedBy=multi-user.target

Enable and start:

Bash
sudo systemctl enable budgerosudo systemctl start budgero

Updating

Docker

Bash
docker pull budgero/budgero:latestdocker compose downdocker compose up -d

Native binary

Bash
budgero update

This 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)

Code
budget.yourdomain.com {
    reverse_proxy localhost:3001
}

nginx

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:

Code
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:

  1. Ensure only one Budgero instance is running
  2. Check that DB_PATH points 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 /data and 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 /data volume (includes budgero.db and budget_spaces/).