← All posts

Self-Hosted Invoicing with Docker (Coolify & Dokploy Guide)

  • selfhosted
  • docker
  • opensource
  • invoicing

Self-hosting your invoicing means your client data, invoices, and numbers live on infrastructure you control — no subscription, no lock-in, no third party holding your books. With a single-container app like Inkvoice it takes minutes. Here’s how to do it on plain Docker, Coolify, or Dokploy.

Why self-host your invoicing

  • You own the data. Everything lives in one SQLite file on your server.
  • No per-seat pricing. Run it for your whole team for the cost of a tiny VPS.
  • Tiny footprint. Inkvoice idles around ~50–100 MB RAM — the cheapest VPS tier is plenty.

(Prefer not to run a server at all? There’s a managed Cloud — skip to the end.)

What you need

A host that runs Docker. A $4–6/mo VPS is fine. You’ll expose port 3000 and keep a persistent volume so the database survives redeploys.

Option A — Plain Docker

docker compose up -d

Open http://localhost:3000 (or your server’s IP) and log in with admin / changeme — then change the password from the user menu immediately. Mount a volume on /app/data so the SQLite database persists across restarts.

Option B — Coolify

  1. New Resource → Public Repository → paste the repo URL.
  2. Build pack: Dockerfile (repo root).
  3. Port: 3000.
  4. Persistent storage: add a volume on /app/data — without it, every deploy wipes the database.
  5. Environment: set JWT_SECRET (≥ 32 chars), ADMIN_PASS, and COOKIE_SECURE=true.
  6. Domain: attach one (Coolify issues a Let’s Encrypt cert), then set ENABLE_HSTS=true.
  7. Health check: point it at /health.

Option C — Dokploy

Same shape as Coolify: create a Docker service from the repo, expose port 3000, mount a volume on /app/data, and set JWT_SECRET + ADMIN_PASS. Attach a domain and you’re live.

The env vars that actually matter

  • JWT_SECRET — a random string ≥ 32 chars. Don’t skip this.
  • ADMIN_PASS — your initial admin password.
  • COOKIE_SECURE=true and ENABLE_HSTS=true — once you’re on HTTPS.
  • A volume on /app/data — the single most important step; it’s where your data lives.

Backups are trivial

Because it’s one SQLite file under /app/data, backing up is just copying that file (or snapshotting the volume) on a schedule. Restoring is dropping it back. No database dumps, no orchestration.

…or skip the ops entirely

Self-hosting is great, but it’s not for everyone. If you’d rather not manage a server, Inkvoice Cloud gives you the same app — free, open-source, your data exportable anytime — with zero setup. Either way you own your billing. Star or fork it on GitHub.