Skip to content

Install

Run SAE Books yourself — from a double-click on your laptop to a hardened server install. Pick the path that fits.

Three ways to run SAE Books, easiest first:

Path For Time
One-click server One person, one computer, no Docker 2 minutes
Docker Community bundle Anyone with Docker; NAS / home server 5 minutes
From source (SAP bundle) Developers; Postgres-backed server installs 10+ minutes

Prefer hosted?

If you'd rather we ran the boxes, hosted SAE Books is the same software, $39/month, AU data centre. Same export format, no lock-in — switch to self-hosted any time with a database dump.

1 · One-click server (easiest)

One file, no Docker, no dependencies. Download from the v0.6 release:

Platform File Steps
Windows SAEBooks-windows-x64.exe Double-click. SmartScreen shows "Windows protected your PC" — click More info → Run anyway (unsigned build; expected). First run unpacks for about a minute, once only.
Linux SAEBooks-linux-x86_64 chmod +x SAEBooks-linux-x86_64 && ./SAEBooks-linux-x86_64
macOS (Apple Silicon) SAEBooks-macos-arm64 chmod +x SAEBooks-macos-arm64 && ./SAEBooks-macos-arm64. First run: macOS Gatekeeper blocks an unsigned binary — clear the download flag with xattr -d com.apple.quarantine SAEBooks-macos-arm64, or right-click the file in Finder and choose Open. Ad-hoc signed, not notarised; expected.

The launcher starts the engine and web UI on localhost and opens your browser at http://127.0.0.1:18960 (web UI; REST API on 127.0.0.1:18961, gRPC on 127.0.0.1:18962). Sign in with the starter books — [email protected] / change-me-now — and change the password. Your books are a SQLite file in one folder on your machine (the console window shows where); back that folder up and you've backed up your books.

Verify downloads against the release's SHA256SUMS. Plain-language walk-through and troubleshooting: installers/oneclick/INSTALL.md.

2 · Docker Community bundle (one command)

Three containers — the API engine, the web UI, and a XeLaTeX render service (latex-api, new in v0.6.1: invoice/statement PDFs and email attachments). SQLite-backed: no Postgres, no roles, no migrations to run.

curl -fsSLO https://raw.githubusercontent.com/saebooks/saebooks/main/docker-compose.community.yml
docker compose -f docker-compose.community.yml up -d

Open http://127.0.0.1:18960 and sign in with the starter books ([email protected] / change-me-now). The REST API is on 127.0.0.1:18961. Images are pulled anonymously from Docker Hub — saebooks/saebooks-community-api, saebooks/saebooks-community-web, saebooks/saebooks-community-latex (tags v0.6.1 + latest, multi-arch linux/amd64 + linux/arm64).

Before exposing beyond 127.0.0.1

The compose file ships local-only placeholder secrets so it runs with zero setup on one device. Binding to a LAN or public address requires setting your own SAEBOOKS_SECRET_KEY, SAEBOOKS_FIELD_ENCRYPTION_KEY, and SAEBOOKS_WEB_SECRET_KEY, and changing the starter password — see the SECURITY NOTE comments in the compose file.

The rest of this page covers the from-source SAP bundle: a Postgres-backed build for developers and production server installs.

3 · Prerequisites (from source)

SAE Books runs anywhere Docker runs. A small VPS is enough for a single company; for multi-tenant or high-volume work, plan for more RAM and a real Postgres.

Component Minimum Recommended
OS Linux x86_64 / arm64, kernel 5.10+ Ubuntu 24.04 LTS / Debian 12
CPU 2 cores 4 cores
RAM 2 GB 4 GB+ (more if many tenants)
Disk 10 GB 50 GB SSD
Docker Engine 24+ with Compose v2 Engine 26+
Postgres bundled in compose managed Postgres 15 or 16
Domain optional, IP works HTTPS via Caddy / Traefik
SMTP optional any provider for invoice email

You'll need a sudo-capable shell, Git, and outbound HTTPS so Docker can fetch base images during the build. Nothing else phones home.

4 · From source: the SAP bundle

Five commands. Replace books.example.com with your domain (or skip it and reach the app on port 8080).

Two repos required

The SAP bundle builds images from source. Clone both repos into the same parent directory before running docker compose up.

# 1. clone both repos as siblings
git clone https://github.com/saebooks/saebooks.git
git clone https://github.com/saebooks/saebooks-web.git

# 2. copy the env template and edit
cd saebooks/deploy/sap
cp .env.example .env
$EDITOR .env  # set POSTGRES_PASSWORD, SAEBOOKS_WEB_SECRET_KEY, SAEBOOKS_SECRET_KEY

# 3. build and bring up (first build is slow; subsequent builds are fast)
docker compose up -d

Migrations run automatically on first start (Alembic, ~45 s). Watch progress:

docker compose logs -f api

Once the api container is healthy, open http://localhost:8080 and create your first company. The Australian chart of accounts and tax codes are available in the first-run setup wizard.

Set your secrets before first up

POSTGRES_PASSWORD and SAEBOOKS_WEB_SECRET_KEY are required. Once Postgres has been initialised with a password it can't be changed without re-initialising the data directory — we know, we've done it. Also set SAEBOOKS_SECRET_KEY; without it the API signs JWTs with an empty key, which causes auth failures.

5 · Configuration

Everything lives in .env. The defaults work for a single private install; the table below covers the variables that matter.

Variable Default Notes
POSTGRES_PASSWORD — Required. python3 -c "import secrets; print(secrets.token_urlsafe(32))"
SAEBOOKS_WEB_SECRET_KEY — Required. Session signing secret. python3 -c "import secrets; print(secrets.token_hex(32))"
SAEBOOKS_SECRET_KEY (empty) Strongly recommended. JWT signing secret. Empty = tokens signed with empty key → auth fails. openssl rand -hex 32
POSTGRES_USER / _DB saebooks / saebooks Override if sharing a Postgres instance.
SAEBOOKS_EDITION community community | offline | business | pro | enterprise. Higher editions need a licence JWT.
SAEBOOKS_LOG_LEVEL INFO DEBUG for diagnostics; not recommended in production.
SAEBOOKS_LOG_JSON unset Set to 1 for structured JSON logs (recommended for log shipping).
SAEBOOKS_WEB_LOG_LEVEL INFO Log level for the web frontend.
SAEBOOKS_FIELD_ENCRYPTION_KEY (empty) Field-level encryption for sensitive data. Generate: python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())". Leaving empty disables field encryption — not recommended for production.
SEED_COMPANY_NAME / _LEGAL_NAME / _ABN unset Pre-fills company details on first DB initialisation only.
SMTP_HOST (empty) Empty = emails written to /app/mail-outbox (dev mode). Set for real delivery.
SMTP_PORT 587
SMTP_USER / SMTP_PASSWORD / SMTP_FROM unset
SENTRY_DSN unset Optional error reporting.
SAEBOOKS_ADMIN_EMAIL unset Optional — seeds an initial admin account.

The full env reference (OAuth, external Postgres, log shipping) lives at Operations → Deployment.

6 · First run

Sign in at http://localhost:8080. You'll land on a company-creation page.

  1. Create a company. Name, ABN, financial-year-end (default 30 June for AU). The ABN is validated against the ABR public API; it's optional but enables the GST registration check.
  2. Pick a chart of accounts. The Australian default is pre-loaded; you can edit accounts later. For other jurisdictions, upload your own CSV or start from blank. See First chart of accounts.
  3. Set tax codes. Defaults are GST 10% and GST-free. Add territory codes (NSW, VIC, etc.) only if registered.
  4. Invite users (optional). Each gets a role: Admin / Bookkeeper / Reader.

You can also load opening balances now (Settings → Opening balances). Skip if this is a brand-new business.

7 · License & editions

The same codebase runs every edition. Editions are gated by feature flags in your licence key — pasting a key promotes the install in place, no reinstall.

Edition What you get How to enable
Community Single tenant, ledger, invoices, bills, journal entries, reports. Offline-capable. Ship as-is. Leave SAEBOOKS_EDITION unset or set to community.
Business Multi-user, recurring invoices, payment reconciliation, STP for payroll. Buy a key at saebooks.com.au/editions and paste it into .env. Restart the api container.
Enterprise Multi-tenant, BAS lodgement, bank feeds, SSO, fixed assets, advanced reporting. Same flow. Includes priority support.

Licence keys are signed Ed25519 tokens validated locally. They check in with the licence server once a week to renew — if your network is air-gapped, contact us for an offline key.

8 · Reverse proxy & TLS

Don't expose ports 8080 or 8042 to the public internet. Put a reverse proxy in front, terminate TLS there, and let SAE Books speak plain HTTP on the private network. Caddy is the simplest:

books.example.com {
    reverse_proxy localhost:8080
}

That's the whole config. Caddy will auto-issue and renew a Let's Encrypt cert. Traefik, nginx, HAProxy all work the same way.

9 · Backups

Postgres is the only stateful component. Back up the database; the rest can be rebuilt from the compose file and source. A simple cron entry:

/etc/cron.daily/saebooks-backup
#!/usr/bin/env bash
set -euo pipefail
cd ~/projects/saebooks/deploy/sap
mkdir -p backups
docker compose exec -T db pg_dump -U saebooks saebooks \
  | gzip > backups/saebooks-$(date +%Y%m%d-%H%M).sql.gz
find backups -name 'saebooks-*.sql.gz' -mtime +30 -delete

The Postgres volume (saebooks_db) is unaffected by docker compose down — your data survives container restarts and image rebuilds.

(One-click / Community-bundle installs: your books are a single SQLite file — back up the data folder shown in the console, or the books_data Docker volume.)

10 · Updates

Pull both repos, rebuild, and restart:

cd ~/projects/saebooks && git pull
cd ~/projects/saebooks-web && git pull
cd ~/projects/saebooks/deploy/sap
docker compose up -d --build

Migrations run automatically on api startup. To pin to a specific release, git checkout <tag> in both repos before building:

cd ~/projects/saebooks && git checkout v0.6
cd ~/projects/saebooks-web && git checkout v0.6
cd ~/projects/saebooks/deploy/sap
docker compose up -d --build

Releases are tagged v0.N on the public repo (current: v0.6; Docker images v0.6.1); breaking schema changes ship migration notes in the release notes.

For zero-downtime upgrades, see Self-host in production.

11 · Troubleshooting

API container restarts every 30 s

Ninety-five percent of the time the database isn't ready. Check docker compose logs db — if Postgres is wedged, delete the volume (docker compose down -v, only on a fresh install with no data) and start again. Otherwise check that DATABASE_URL in the compose environment points to service name db, not localhost.

Auth failures or tokens rejected after login

SAEBOOKS_SECRET_KEY is unset or empty. The API does not raise an error on startup — it silently defaults to an empty signing key, which means tokens signed in one container session fail verification in the next. Generate a key (openssl rand -hex 32), set SAEBOOKS_SECRET_KEY in .env, and docker compose up -d to recreate the api container.

403 cross-tenant on every page after enabling multi-tenant

Row-level security is doing its job. The current user has no membership in the tenant they're trying to view. From an admin shell:

docker compose exec api python -m saebooks.scripts.assign_user \
  --user [email protected] --tenant default --role admin

Licence key shows "invalid" after paste

Whitespace. Licence keys are one line, no quotes. Re-paste from the confirmation email. If still failing, the system clock may be more than 24 hours off — timedatectl status on the host.

Build fails with "path not found" or "context not found"

Both repos must be siblings in the same parent directory. The api build context (../..) resolves to the saebooks repo root; the web build context (../../../saebooks-web) resolves to the saebooks-web repo root. If either path doesn't exist, the build fails.

I want to nuke this and start over

docker compose down -v removes containers and the database volume. Edit .env, then re-run docker compose up -d --build. Your .env survives because it's a host file.

12 · What's next

  • Production hardening

    Compose hardening, single-tenant appliance posture, real Postgres, rolling upgrades.

  • Build an integration

    REST + webhooks, idempotency, page cursors. Push 200 invoices from your job-management system.

  • Forum

    Other operators and the dev team. Ask before you re-architect.

  • API reference

    Every endpoint, with request and response shapes. Hit Try it.


Last reviewed 2026-07-22. The install flow is deliberately boring — if a step here surprises you, that's a documentation bug. Tell us.