Epure
Self-hostingUpgrades

Upgrades

The image is ghcr.io/epure-sh/epure. There is no worker fleet or Redis stream to drain. Path: backup → git pull the clone → bump EPURE_IMAGE → compose up → watch health. Keep .env; Compose still interpolates it.

Pinning only the GHCR tag is not enough when the release also changes compose, .env.example, or deploy overlays — those files live in the git checkout. Operators who only changed EPURE_IMAGE and still saw old UI (for example Register after EPURE_REGISTRATION=false) needed a git pull first.

Upgrade in five steps

Dump Postgres, note the commit you are leaving, check out the new revision, bump the image pin, compose up (pulls GHCR), confirm /health.

Pin production

In production set EPURE_IMAGE=ghcr.io/epure-sh/epure:v0.1.7 in .env. Keep EPURE_REGISTRATION in that file when you bump the image. Current release: v0.1.7 (2026-10-04) — release notes, docs changelog.

Dump Postgres

docker compose exec -T postgres pg_dump -U epure -d epure -Fc > "epure-$(date +%Y%m%d).dump"

Store the dump off-box. Prod overlay: same exec; Postgres has no host port.

Optional artifacts (if you upload maps):

Archive source-map volume

command

docker volume ls
docker run --rm \
-v epure_artifacts_data:/data \
-v "$(pwd)/backups:/backup" \
alpine tar czf /backup/artifacts-$(date +%Y%m%d).tar.gz -C /data .

Note the git commit you are leaving.

Check out the new revision and pin the image

Check out the release tag

command

git fetch
git checkout v0.1.7   # or: git pull origin main

In .env (create from .env.example if needed):

Pin the release image

command

EPURE_IMAGE=ghcr.io/epure-sh/epure:v0.1.7

Compose reads both the checkout (compose files, overlays) and EPURE_IMAGE. Skipping git pull leaves you on old templates even when the container tag is new.

Pull and start

Pull local stack

command

docker compose up -d

Migrations apply when the epure process starts. There is no separate migrate container.

Confirm health

docker compose logs -f Epure

Check health

Local default. Use EPURE_PUBLIC_URL/health if you changed the port or are on HTTPS.

command

curl -sS http://localhost:8080/health

Expected

{"status":"ok"}

On production, use EPURE_PUBLIC_URL/health. Local default is http://localhost:8080/health. Then: login, Issues list, one store POST → 202. Quickstart Try ingest.

Roll back if it fails

Schema may move forward only. Restore the dump before starting an older binary if a migration is not backward-compatible.

Restore dump and previous binary

Keep Postgres up. Stop only the app, restore, then compose up the previous image.

command

docker compose stop Epure
git checkout <previous-commit>
docker compose exec -T postgres pg_restore -U epure -d epure --clean --if-exists < epure-YYYYMMDD.dump
docker compose up -d
curl -sS http://localhost:8080/health

Expected

{"status":"ok"}

--clean drops objects before restore. Confirm /health and login. Keep EPURE_SESSION_SECURE matched to HTTP vs HTTPS.

What stays the same

No upgrade introduces Redis or a worker fleet.

  • Two-container topology (app + Postgres 16)
  • EPURE_MODE=all
  • RLS session variable: app.current_org_id
  • Volume names for Postgres and artifacts (unless you rename the Compose project)

Checklist

  • Dump taken and stored off-box
  • Artifacts archived if needed
  • docker compose … up -d completed without migrate errors
  • /health OK
  • Session still works
  • Ingest smoke test passed
What if migrate errors show in Epure logs?

Stop retrying a half-applied schema. Restore the dump, check out the previous commit, compose up. Migrations run when the epure process starts, so there is no separate migrate container. Keep the dump off-box: Troubleshooting.

Why does login loop after an upgrade?

Cookie Secure flag mismatch. The prod overlay sets EPURE_SESSION_SECURE=1; local HTTP needs 0. Keep that value matched to HTTP vs HTTPS when you roll back, then confirm /health. See Configuration.

Can I roll back the schema with an older binary?

Only if you restore the pre-upgrade dump first, since schema moves forward only. --clean on pg_restore drops objects before restore. Confirm /health and login after compose up.

Do I drain Redis or workers?

No. Two containers, with no Redis stream and no worker fleet. Stop epure, restore Postgres if needed, compose up. Artifacts live on the artifacts_data volume if you uploaded maps.

I set EPURE_REGISTRATION=false but Register is still visible?

The running binary is current, but the clone is stale — or the container was not recreated after the env change. git pull, confirm EPURE_IMAGE=ghcr.io/epure-sh/epure:v0.1.7 (or newer), then docker compose up -d so Compose recreates epure. Configuration.

SDK ingest returns invalid_dsn after upgrade?

Pre-v0.1.5 required sentry_secret. Official Sentry SDKs send public-key-only auth. Pin v0.1.5, recreate, and use the DSN from Settings → SDK connection (http://PUBLIC_KEY@HOST/PROJECT_ID). Authentication.