Skip to content

Operate a self-hosted instance

This page covers the routine tasks for a running Docker instance.

Know where data lives

With the default Compose file:

  • SQLite database: /data/invoicer.sqlite3
  • Generated files: /data/files
  • Managed backups: /data/backups
  • Docker volume: invoicer-data

Do not delete the Docker volume unless you intentionally want to remove the app data.

Generated PDFs use workspace-scoped relative storage keys under /data/files. At startup, legacy generated-file records are migrated only when their old file already resolves inside the configured storage root. An absolute or escaped legacy path is never copied or served; its metadata remains visible as a missing file so an operator can reconcile it deliberately.

Start, stop, and update

Start or rebuild:

bash
docker compose up -d --build

Stop:

bash
docker compose down

Check logs:

bash
docker compose logs -f invoicer

Check health:

bash
curl -fsS http://127.0.0.1:8000/api/health

Back up before risky changes

Use the Settings backup page to create and review managed backups.

Managed backup ZIP files contain:

  • manifest.json with metadata and row counts.
  • database.json with a portable finance backup envelope.
  • files/... for generated files that still exist in storage.

Store copies of backup ZIP files outside the Docker volume before upgrades, server moves, or destructive testing.

Secure public deployments

Before exposing the app outside localhost:

  • Set INVOICER_SETUP_TOKEN until setup is complete.
  • Keep the Compose port bound to 127.0.0.1 and proxy it through HTTPS.
  • Set INVOICER_COOKIE_SECURE=1.
  • Set INVOICER_ALLOWED_HOSTS to the exact public hostname.
  • Set INVOICER_ALLOWED_ORIGINS to the exact public HTTPS origin if the reverse proxy does not preserve that origin for backend requests.
  • Leave INVOICER_ALLOW_UNAUTHENTICATED_LOCAL=0.
  • Keep .env and invoicer.toml out of Git.
  • Use long unique passwords.
  • Put the app behind a reverse proxy that you control.
  • Create a backup before upgrades.

The app is designed for self-hosted trusted operators, not open public signup.

Add users and workspaces

After login, open SettingsWorkspaces and users.

Owners and admins can create users in the active workspace. Owners can manage all roles in that workspace. Admins can manage admins and members, but not owners.

For a new email, copy the one-time activation link and deliver it to the user through a trusted channel. The user chooses their own global password. Existing users keep their password when they are added to another workspace. Workspace administrators cannot reset a global password.

For operator recovery from the host, stop concurrent administrative work and run:

bash
uv run invoicer app reset-user-password user@example.com --db /data/invoicer.sqlite3

Use the host-visible SQLite path for non-container runs. In Docker, execute the command inside a disposable invocation of the same image with the data volume mounted; never copy the database into an untrusted environment.

Create a new workspace when you need isolated finances for a different business or project. A workspace has its own clients, work items, invoices, expenses, payments, settings, backups, and Notion connector settings.

Self-hosted freelancer finance tooling. Review local tax requirements before using generated invoices in production.