Epure
Self-host

Self-hosted error tracking in two containers

Docker Compose with exactly two services: a Rust ingest binary and PostgreSQL 16. No Redis, no Kafka, no worker fleet. Keep the official Sentry SDK and swap the DSN.

On this pageShow
  1. Why container count wins
  2. The two-service stack
  3. No Redis on purpose
  4. Scoreboard
  5. Local compose path
  6. Production path
  7. Limitations
  8. Questions

Ops teams searching for docker compose two container error tracking postgres usually already know Sentry Cloud. What they want is a self-host shape they can reason about: how many images, which database, whether Redis is mandatory, and whether the official SDK still works.

This guide is the constraint narrative, not a RAM bake-off. For VPS memory floors see Self-hosted under 512 MB. For the roster see Sentry alternatives. Product install truth lives in Installation.

Why container count wins

Compose sprawl is the first failure mode on a small box. Each service is another image pull, another healthcheck, another thing that can refuse to start. Exception tracking does not need a queue broker if ingest can use an in-process queue and store sessions in Postgres.

  • Self-hosted Sentry: 20+ containers, documented as a full observability stack (FSL self-host).
  • GlitchTip: about four containers (web, worker, Postgres, Valkey) on MIT.
  • Bugsink: one Django container, SQLite-first, Polyform Shield.
  • Telebugs: one Rails + SQLite container, $299 appliance.
  • Epure: two containers only. Rust binary + PostgreSQL 16. Apache 2.0.

The two-service stack

Documented laptop Compose (Compose v2) from the public product repo:

Epure laptop Compose services (Installation defaults)

epure

Image
ghcr.io/epure-sh/epure:latest
Ports (defaults)
host EPURE_PORT → 8080 (default 8080)

postgres

Image
postgres:16-alpine
Ports (defaults)
host POSTGRES_HOST_PORT → 5432 (default 5433)
DimensionImagePorts (defaults)
epureghcr.io/epure-sh/epure:latesthost EPURE_PORT → 8080 (default 8080)
postgrespostgres:16-alpinehost POSTGRES_HOST_PORT → 5432 (default 5433)

No .env required for localhost:8080. Pin a tag with EPURE_IMAGE. Production uses a separate overlay and HTTPS in front; do not publish the laptop compose file.

What ships inside that binary: exception events and breadcrumbs, JS/TS source map demangle, Issues triage, releases, webhooks. What does not ship as Epure features: tracing/APM, session replay, profiling, generic logs (Welcome).

No Redis on purpose

Installation FAQ: do you need Redis? No. The stack is two containers. Welcome FAQ: do you need Redis or Kafka? No. Ingest uses an in-process Tokio queue; sessions live in Postgres (Installation, Welcome, Configuration).

Rate limits are also in-process on the Rust binary (spike valve and hourly project cap). There is no Redis-backed global rate limiter (API Errors). Soft-sample flood behavior is covered in Spike valve flood.

Scoreboard

Containers

Sentry
20+
GlitchTip
~4
Bugsink
1
Telebugs
1
Epure
2

Default DB

Sentry
Postgres (+ more)
GlitchTip
Postgres
Bugsink
SQLite (Postgres optional)
Telebugs
SQLite
Epure
PostgreSQL 16

Broker / cache

Sentry
Full fleet
GlitchTip
Valkey in the install
Bugsink
None required
Telebugs
None required
Epure
None (no Redis/Kafka)

License

Sentry
FSL self-host / Cloud prop.
GlitchTip
MIT
Bugsink
Polyform Shield
Telebugs
$299 appliance
Epure
Apache 2.0

SDK path

Sentry
Native
GlitchTip
DSN swap
Bugsink
DSN swap
Telebugs
DSN swap
Epure
DSN swap
DimensionSentryGlitchTipBugsinkTelebugsEpure
Containers20+~4112
Default DBPostgres (+ more)PostgresSQLite (Postgres optional)SQLitePostgreSQL 16
Broker / cacheFull fleetValkey in the installNone requiredNone requiredNone (no Redis/Kafka)
LicenseFSL self-host / Cloud prop.MITPolyform Shield$299 applianceApache 2.0
SDK pathNativeDSN swapDSN swapDSN swapDSN swap

Public docs as of 2026-09 (Sentry self-host, GlitchTip install, Bugsink, Telebugs, Epure Installation / Welcome). Idle RAM omitted here; remasure before claiming.

Local compose path

From Quickstart / Installation:

git clone https://github.com/epure-sh/epure.git && cd epure && docker compose up

Health: curl -sS http://localhost:8080/health{"status":"ok"}. Dashboard at http://localhost:8080. Register, create a project, copy the DSN from setup or Settings → SDK connection.

Point @sentry/browser@7.120.0 or @sentry/node@7.120.0 (Quickstart pins) at that DSN. Set traces, replay, and profile sample rates to 0. Ingest returns HTTP 202 before the Issues row appears. Wire honesty: Sentry SDK compatible.

If 8080 is taken: cp .env.example .env, set EPURE_PORT, recreate epure. Host tools talk to Postgres on **5433** by default, not 5432 (Configuration).

Production path

Production is a separate path: ./configure --prod (or .env.production.example), compose overlay, fresh Postgres volume, HTTPS reverse proxy in front of 127.0.0.1:8080. Do not reuse a laptop data directory. Do not publish the laptop compose file with example passwords on a public hostname (Installation).

  • Set EPURE_PUBLIC_URL to https://… (must be https).
  • Set EPURE_CORS_ORIGINS to your app origins (not *).
  • Replace every CHANGE_ME password; overlay refuses example passwords.
  • Forward Host, X-Forwarded-For, X-Forwarded-Proto; allow POST/OPTIONS on envelope and store.
  • Confirm GET /health{"status":"ok"} on the public origin.

Limitations

  • Exception-only. No tracing, replay, profiling, or generic logs product.
  • JS/TS sourcemaps via @sentry/cli; other languages group on raw frames.
  • Two containers beat Sentry and GlitchTip on count; Bugsink/Telebugs still win one-container SQLite ops.
  • Idle RAM figures are omitted here (dated sources conflict). Re-measure on your box before quoting.
  • This is not protocol parity with Sentry Cloud.

Pick Epure if

  • The brief is exactly two Compose services plus PostgreSQL 16.
  • You refuse Redis and Kafka in the error stack.
  • Counsel wants Apache 2.0 and a DSN swap on official Sentry SDKs.
  • You will set traces, replay, and profile sample rates to 0.

Pick another tool if

  • Replay or APM is the daily debug loop: stay on Sentry.
  • MIT plus Django/Valkey is already home: GlitchTip.
  • One SQLite container is the ops model: Bugsink (or Telebugs at $299).
  • You are shopping RAM floors only: Self-hosted under 512 MB.

Install: Installation. Marketing path: Self-host. Clone: GitHub.

FAQ

Questions

Do I need Redis for Epure?
No. The documented stack is two containers: the Rust binary and PostgreSQL 16. Ingest uses an in-process Tokio queue; sessions live in Postgres. See Installation and Welcome.
What are the two containers?
epure (ghcr.io/epure-sh/epure:latest by default) and postgres (postgres:16-alpine). Laptop defaults publish 8080 for the app and 5433 for Postgres. Details: Installation.
Is this the same as the under-512 MB guide?
No. That guide ranks by published RAM floors. This guide ranks by Compose service count and database shape (two containers + Postgres 16 + no Redis). Cross-link: Self-hosted under 512 MB.
Can I keep @sentry/browser or @sentry/node?
Yes. Paste the Epure DSN. Pin 7.120.0 as Quickstart does. Set tracesSampleRate, replaysSessionSampleRate, and profilesSampleRate to 0. More: Sentry SDK compatible.
Why not one container like Bugsink?
Epure defaults to PostgreSQL 16 as a separate process so the store matches how many teams already take backups. That costs one extra container versus SQLite-in-process designs. Trade license and DB: Apache 2.0 + Postgres versus Shield/SQLite or $299 SQLite.
Laptop compose on a public hostname?
No. Example DB passwords are allowed only while EPURE_PUBLIC_URL is localhost. Production needs ./configure --prod (or .env.production.example), the prod overlay, and HTTPS in front (Installation).