Self-hostingTroubleshooting

Troubleshooting

Common self-host failures: database URL, migrations, DSN, CORS, sessions.

What usually fails on a self-host?

A wrong database URL, a session cookie Secure mismatch, a missing CORS origin, or a revoked DSN key. Start with the matrix.

SymptomLikely causeFix
up cannot pull ghcr.io/epure-sh/epurePackage missing or privateWait for a tagged Image workflow; set the GHCR package to public. Contributors: docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
App exits on start / migrate errorsWrong DATABASE_URL or Postgres not readyMatch compose credentials; wait for postgres healthy; check docker compose logs epure
Connection refused on the old portEPURE_PORT changed, or .env not picked upCurl EPURE_PUBLIC_URL/health; recreate epure after .env edits
Boot refuses example DB passwordsEPURE_PUBLIC_URL is not localhost, or leftover CHANGE_MEUse .env.production.example; set the three role passwords
EPURE_PUBLIC_URL must be https://Production config without TLS originSet https://your-host; put Caddy/nginx in front
EPURE_CORS_ORIGINS must list real origins* in productionList frontend origins comma-separated
cargo test / host tools cannot connectUsing port 5432 on hostDev compose maps Postgres to 5433 (POSTGRES_HOST_PORT)
Login loops after HTTPS deployInsecure cookie on HTTPS or secure cookie on HTTPProd: EPURE_SESSION_SECURE=1 + TLS in front. Local HTTP: 0
Google button missingGOOGLE_CLIENT_ID emptySet Google env vars; restart epure
OAuth redirect errorRedirect URI mismatchGOOGLE_REDIRECT_URI = {EPURE_PUBLIC_URL}/api/v1/auth/google/callback
Browser SDK CORS failureOrigin not allowedSet EPURE_CORS_ORIGINS to your frontend origins (comma-separated)
Ingest 403Bad or revoked DSNCreate/rotate key; update SDK; revoked keys are rejected
Ingest 202 but no issueWorker lag or processing errorWait ~500 ms; docker compose logs epure
Events dropped under loadIngest cap or spike valveCheck project ingest cap (default 5000/hr); spike valve increments counters while discarding bodies
Webhook never arrivesPrivate URL / SSRF guardUse public HTTPS; do not set EPURE_WEBHOOK_ALLOW_PRIVATE=1 in prod
Disk growthRetention / partitionsLower retention (14/30/90); TTL drops old events_YYYY_MM partitions daily
Stack still minifiedMaps missing or wrong releaseUpload JS/TS maps to the matching release version (Releases)

Which database URL should I use?

Inside the epure container, Postgres is postgres:5432. On the host against default compose, use 5433 (POSTGRES_HOST_PORT in .env).

Compose (inside the epure container):

postgres://epure:epure@postgres:5432/epure

Host tools against default compose:

postgres://epure:epure@localhost:5433/epure

Also set when running outside Compose:

  • EPURE_INGEST_DATABASE_URL=postgres://epure_ingest:epure_ingest@localhost:5433/epure
  • EPURE_APP_DATABASE_URL=postgres://epure_app:epure_app@localhost:5433/epure

The prod overlay publishes no Postgres port; reach it with docker compose exec postgres psql -U epure -d epure.

When do migrations run?

Migrations apply on Epure startup, never as a manual job. Failures show up in docker compose logs epure.

Fix connectivity or credentials, then recreate the app container. After a failed upgrade migration, restore the pre-upgrade dump before retrying a new image.

How do I test DSN ingest?

POST envelope or store with X-Sentry-Auth. Expect 202 and { "id": "<uuid>" }; the body cap is 2 MB.

Interactive builder: Quickstart · Try ingest.

curl -sS -w "\nHTTP %{http_code}\n" \
  -X POST "http://localhost:8080/api/${PROJECT_ID}/envelope/" \
  -H "Content-Type: application/x-sentry-envelope" \
  -H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=${PUBLIC}, sentry_secret=${SECRET}" \
  --data-binary @fixtures/sentry/browser/envelope.txt

How do I debug CORS?

Browser SDKs need a successful OPTIONS preflight on envelope and store. Expect 200 or 204 with Access-Control-Allow-Origin.

curl -sS -D - -o /dev/null -X OPTIONS \
  "http://localhost:8080/api/${PROJECT_ID}/envelope/" \
  -H "Origin: http://localhost:5173" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: X-Sentry-Auth, Content-Type"

Why does my session drop?

Login succeeds, then /api/v1/* acts logged out. The browser is rejecting the cookie over a Secure flag mismatch.

DeployEPURE_SESSION_SECURECookie
Local HTTP0Epure.sid
HTTPS1__Host-epure.sid (Secure only)

How do I get more signal?

Follow the logs, raise the log level, then check container state and health. Recreate epure after any env change.

docker compose logs -f Epure
RUST_LOG=debug   # temporary: set in compose/env, then recreate
docker compose ps
curl -sS http://localhost:8080/health
Why does the app exit on migrate?

Wrong DATABASE_URL, or Postgres is not ready. Wait for postgres to report healthy and read docker compose logs epure. Host tools must use port 5433, and epure needs a recreate after credentials change. Copy URLs from Configuration.

Why is ingest 403?

The DSN public key is missing, wrong, or revoked, or the URL project id does not match the key. Copy a new key from Settings → SDK connection. Revoked keys return dsn_revoked and mismatched project ids return project_mismatch. The hourly cap returns ingest_cap_exceeded: Verify.

Why 202 with no issue?

Accept is non-blocking, so wait about a second. Match the environment chip to the SDK tag and confirm the project that owns the DSN. Then read docker compose logs epure. Spike-valve floods still return 202 while dropping bodies: Verify.

Why does login loop after HTTPS?

Cookie Secure flag mismatch. The production overlay sets EPURE_SESSION_SECURE=1 and needs TLS in front; local HTTP needs 0. Google OAuth also needs GOOGLE_REDIRECT_URI equal to {EPURE_PUBLIC_URL}/api/v1/auth/google/callback. Restart epure after env changes.

Why are events dropped under load?

The hourly project cap (default 5000) returns 403 ingest_cap_exceeded. The spike valve (~100/min/fingerprint) still returns 202 and bumps counters while dropping bodies. Raise the cap in project settings, or slow the flood. Codes: API errors.