Self-Hosting
Run the full Pug stack on your own infrastructure. Self-hosting gives you complete data ownership, custom deployment topology, and air-gapped operation.
What you’ll run
A working Pug instance has two deployables — the backend and the dashboard — plus four backing stores. They live in two repositories:
| Part | Repo | What it is | You deploy it as |
|---|---|---|---|
| Backend | pug-sh/pug | The Go API server, the background workers, and the pug CLI — all one binary | Long-running server + worker processes |
| Dashboard | pug-sh/app | The React UI (“Pug UI”) that reads and manages your data | Static files behind a web server / CDN |
Everything else — Postgres, ClickHouse, NATS, and Dragonfly — you either run yourself or point at a managed equivalent.
Once both are up, you do one more thing: point your SDKs at your own server instead of Pug Cloud. That’s the whole job.
Get the code
The backend — the server, every worker, and the pug CLI — builds from one repo:
git clone [email protected]:pug-sh/pug.git
cd pugThe dashboard is a separate repo; see Dashboard for its build. To build from source you need a Go ≥ 1.26 toolchain (backend) and Bun (dashboard); to run from prebuilt container images you need neither. Full prerequisites are in Requirements.
Recommended reading order: Requirements → Configuration → Deployment → Dashboard → Connect your SDKs. To run the whole stack on one machine for local work, follow Development instead.
When to self-host
| Self-host when… | Use Pug Cloud when… |
|---|---|
| Data must stay in your VPC | You want the fastest path to production |
| Compliance or regulatory requirements | You prefer managed infrastructure and upgrades |
| You have an existing Postgres / ClickHouse / NATS cluster | You don’t want to operate stateful services |
| Air-gapped or on-premise environments |
Architecture
The backend is two kinds of process — the API server and a set of background workers — backed by four stores. The dashboard is a static single-page app that talks to the same API server.
Both the SDKs (ingest) and the dashboard (read/manage) hit the same pug server on port 3000 — they differ only in which RPC services they call and how they authenticate (public key for SDKs, JWT for the dashboard). Dragonfly (a Redis-compatible store) backs caching and rate limiting; it is never on the durable event path.
Tracing one event end-to-end:
Processes at a glance
Every runtime process is a sub-command of the single pug binary: the API server (pug server) plus 7 worker processes — events, email, compliance, demo, and three profile workers (identify, alias, upsert).
You can run these three ways, mixed and matched:
| Way | What it is | Best for |
|---|---|---|
pug dev (alias pug start) | One process that runs the server and every worker together | Local dev, or a small single-node instance |
| Sub-commands | pug server, pug worker events, … — one process each | Production, when you want to scale and restart processes independently |
| Standalone binaries / images | A single-purpose binary (pug-worker-events) or container image per role | Kubernetes, systemd — see Deployment |
For the complete command tree, every flag, and the build output, see the CLI reference. Deployment is the canonical runbook for running each process in production.
The
demoworker only generates the public demo dataset and stays idle unlessPUG_DEMO_ENABLED=true— a normal self-host doesn’t run it. The other six workers are the real pipeline.