What is Actual Budget?
Actual Budget is a local-first personal finance app built around envelope budgeting, a popular alternative to YNAB. It is open source under the MIT license. The budget runs in your browser or desktop app, and the self-hosted sync server keeps your devices in sync and can end-to-end encrypt your data. It supports multiple budgets, rules, reports, scheduled transactions and optional bank sync.
Requirements
- Any Linux server with 1 vCPU and 512 MB of RAM.
- Docker Engine and Docker Compose v2.
- HTTPS. Actual needs a secure browser context, so you must reach it through HTTPS unless you browse on
localhost.
Step 1: Prepare the server
This guide assumes Ubuntu 24.04 with Docker installed. If you need Docker, follow the official install guide. Create a project folder:
mkdir -p ~/actual && cd ~/actual
Step 2: Create the Docker Compose file
This follows the official Compose file from the Actual repository. Save as docker-compose.yml:
services:
actual_server:
image: docker.io/actualbudget/actual-server:latest
container_name: actual
restart: unless-stopped
ports:
- "127.0.0.1:5006:5006"
environment:
ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB: 20
ACTUAL_UPLOAD_SYNC_ENCRYPTED_FILE_SYNC_SIZE_LIMIT_MB: 50
ACTUAL_UPLOAD_FILE_SIZE_LIMIT_MB: 20
volumes:
- ./actual-data:/data
healthcheck:
test: ["CMD-SHELL", "node build/scripts/health-check.js"]
interval: 60s
timeout: 10s
retries: 3
start_period: 20s
There are no secrets in this file. You set the server password in the browser on first launch. The port is bound to 127.0.0.1 because the reverse proxy in Step 4 provides the HTTPS that Actual requires. The latest tag is the most recent stable release; Actual publishes a new version roughly every month, and you can pin one such as 26.10.0 from the releases page. There is also a smaller latest-alpine variant for low-powered devices.
Step 3: Start and open the app
docker compose up -d
Complete Step 4 first, because the app will not load over plain HTTP on a remote IP. For a quick test before your domain is ready, use an SSH tunnel from your computer, ssh -L 5006:127.0.0.1:5006 user@server, and open http://localhost:5006.
On first visit Actual asks you to set a server password. Anyone with this password can open the budgets on the server, so make it long, for example from openssl rand -hex 32, and save it in your password manager. Then create a new budget or import one from YNAB 4, nYNAB or an Actual export. To protect your data even from someone with server access, enable end-to-end encryption under Settings, Encryption, and keep that key safe as well, since it cannot be recovered.
Step 4: Put it behind HTTPS
With Caddy:
budget.example.com {
reverse_proxy 127.0.0.1:5006
}
Caddy fetches a Let's Encrypt certificate automatically, which gives Actual the secure context it needs. Nginx Proxy Manager works the same way: a proxy host to port 5006 with an SSL certificate and "Force SSL". If you use OpenID Connect, Actual also supports OIDC login to replace the server password; configure it from the settings page after setup.
Backups and upgrades
The actual-data folder holds the server database (server-files/account.sqlite) and every synced budget (user-files/). Copy it off-site regularly:
docker compose stop && tar czf actual-$(date +%F).tgz actual-data && docker compose start
You can also export any budget as a zip from Settings, Export, which is the easiest way to restore into a new instance. Because Actual is local-first, each device keeps a full copy of the budget too, but that is not a substitute for a real backup.
Upgrade with:
docker compose pull && docker compose up -d
After an upgrade, reload the browser tab so the client loads the new version.
Troubleshooting
- "SharedArrayBuffer is not defined" or a fatal error page: you opened Actual over plain HTTP on a non-localhost address. Use your HTTPS domain.
- "File is too large" during sync: raise the
ACTUAL_UPLOAD_*limits and the reverse proxy's upload size limit. - Bank sync fails: GoCardless or SimpleFIN credentials expired, or your bank requires re-authorisation every 90 days. Reconnect the account in Actual.
- Forgotten server password: reset it from the container with
docker compose exec actual_server node build/scripts/reset-password.js.
Next steps
Set up rules to categorise transactions automatically, schedule recurring bills, link bank accounts through GoCardless or SimpleFIN, and install the desktop app or add the site to your phone's home screen.
Spotted something out of date? Tell us and we will update the guide.