Skip to content

Requirements

Hardware, dependency versions and network prerequisites for a self-hosted Pug deployment.

Updated View as Markdown

Backing services, toolchains, ports, and sizing for self-hosting Pug.

Toolchains

What you need depends on whether you build from source or run prebuilt container images.

Tool Version Needed for Why
Go ≥ 1.26 Building the backend Compiles the pug server, workers, and CLI. The repo targets 1.26.3.
Bun Latest Building the dashboard Installs deps and builds the React SPA. Node 22 is the runtime baseline.
Docker Any recent release Local infra or container builds Runs the four backing services locally, and builds the backend images.

If you deploy from published container images instead of building, you need neither Go nor Bun — only a container runtime. See Deployment.

git clone [email protected]:pug-sh/pug.git      # backend: server, workers, pug CLI
cd pug

The dashboard lives in a separate repo (pug-sh/app) and is covered in Dashboard.

Backing services

The backend requires four backing services: PostgreSQL, ClickHouse, NATS, and Dragonfly. The versions below are what the project develops and tests against (from the dev Docker Compose); you may run managed equivalents (e.g. Amazon RDS for Postgres, ClickHouse Cloud) at compatible versions. The Pug server itself appears in the table only for its listening port.

Component Image / Version Container port(s) Role
PostgreSQL postgres:18 5432 Auth, orgs, projects, dashboards, and config. Dev host mapping: 5433→5432.
ClickHouse clickhouse/clickhouse-server:26.5 8123 (HTTP / /ping), 9000 (native), 9009 (interserver) Analytics event storage and queries. Requires ulimits.nofile ≥ 262144.
NATS nats:2.14-alpine 4222 (client), 6222 (cluster), 8222 (monitoring) JetStream message queue. Must be started with --jetstream.
Dragonfly docker.dragonflydb.io/dragonflydb/dragonfly:v1.38.1 6379 Redis-compatible cache / rate-limit. Dev host mapping: 6380→6379.
Pug server 3000 The Connect RPC API server. Override with PUG_SERVER_PORT.

NATS JetStream is required. Start NATS with --jetstream (and --store_dir for a durable volume). The monitoring server (-m 8222) exposes /healthz on port 8222. Without JetStream, event ingestion will not function.

For how the dev Compose file wires these up locally — health checks, volumes, and the observability overlay — see Development.

Ports summary

Only the Pug server (and your static dashboard host) need to be reachable from outside your private network. All backing services should be kept on an internal network:

Port Service Exposure
3000 Pug server (Connect RPC) Public — behind a TLS terminator
8090 Worker health / readiness Internal only — probes (configurable via PUG_WORKER_HEALTH_ADDR)
5432 PostgreSQL Internal only
4222 NATS client Internal only
8123 / 9000 ClickHouse HTTP / native Internal only
6379 Dragonfly Internal only

Sizing guidance

These are starting-point ballparks, not hard requirements. Actual resource needs depend heavily on event volume and retention.

Development / staging

Component CPU RAM Disk
Pug server + workers 2 vCPU 2 GB
PostgreSQL 1 vCPU 2 GB 20 GB
ClickHouse 2 vCPU 4 GB 50 GB
NATS 1 vCPU 1 GB 10 GB (JetStream store)
Dragonfly 1 vCPU 1 GB

Production (small — up to ~1 k events/s)

Component CPU RAM Disk
Pug server 2 vCPU 2 GB
Workers (per type) 2 vCPU 2 GB
PostgreSQL 2 vCPU 8 GB 100 GB SSD
ClickHouse 4 vCPU 16 GB 500 GB SSD
NATS 2 vCPU 2 GB 20 GB SSD
Dragonfly 1 vCPU 2 GB

The dashboard is static files — it needs no compute of its own, only a web server or CDN.

Production (larger workloads)

Scale the events worker horizontally for higher ingest throughput — each replica is an independent JetStream consumer. Give ClickHouse more CPU, RAM, and disk as event volume and retention grow. NATS benefits from a 3-node cluster for JetStream HA.

Optional: geo enrichment (Cloudflare)

Server-side geo auto-properties ($country, $region, $city, $continent, and related fields) are resolved at ingestion by the server — it reads them from Cloudflare proxy headers (CF-IPCountry, CF-Region, CF-IPCity, CF-IPContinent, etc.) on the inbound request. So this needs Cloudflare (or a proxy that sets the same headers) in front of the server; the visitor IP itself is never persisted.

  • CF-IPCountry is added automatically when Cloudflare IP Geolocation is enabled on your zone.
  • CF-Region, CF-IPCity, and the remaining location headers require the “Add visitor location headers” Managed Transform to be enabled.

Geo lookup sits behind a small Provider interface (internal/geo), and Cloudflare headers are the only implementation today. The interface is designed to also accept a local database lookup — e.g. MaxMind (MMDB) — from the client IP in a future release. Until then, if Pug runs behind a different proxy or without these headers, geo auto-properties are simply absent from events; there’s no built-in GeoIP database yet.

Further reading

Navigation

Type to search…

↑↓ navigate↵ selectEsc close