Install
Installation

Cloudflare

Run Relic in a Cloudflare Container behind a Worker, with R2 and your own PostgreSQL.

Each release publishes relic-cloudflare_v0.2.0-beta.4.tar.gz: a Worker that passes every request to one Relic container, set to run that release. Content goes to R2, metadata to a PostgreSQL database you run elsewhere.

Limits

  • The container's disk is wiped at every start, so this setup needs PostgreSQL and R2. Grype's database is downloaded again after each start.
  • Cloudflare limits request bodies by plan: 100 MB on Free and Pro, 200 MB on Business; Enterprise can raise it. Larger uploads fail with 413, including a Docker push with a larger layer.
  • One container runs the server and the background jobs (relic server start --worker --no-tls), on instance type standard-2 (1 vCPU, 6 GiB of memory, 12 GB of disk).
  • A cron trigger calls Relic every five minutes so background jobs keep running; Cloudflare bills that time. Without it, the container sleeps after 15 idle minutes, and background jobs stop.

Before you start

You need:

  • a Cloudflare account on the Workers Paid plan
  • Docker running locally, because Wrangler builds the image
  • Node.js 24 and pnpm
  • a PostgreSQL database that accepts TLS connections from the internet

Create the R2 buckets

Create the buckets, lifecycle rules and API token as Cloudflare R2 describes.

Configure

Download the deployment and unpack it:

curl -fsSL https://github.com/relicbuild/relic/releases/download/v0.2.0-beta.4/relic-cloudflare_v0.2.0-beta.4.tar.gz | tar -xz

Run the commands on this page in the directory it creates:

cd relic-cloudflare_v0.2.0-beta.4

Install the Worker's dependencies:

pnpm install

Edit wrangler.jsonc:

  • In vars, replace <account-id> in RELIC_OBJECT_STORAGE_ENDPOINT with your account ID. The buckets default to relic-artifacts and relic-temporary.
  • To serve Relic on your own domain, add "routes": [{ "pattern": "relic.example.com", "custom_domain": true }]. Without it, the Worker answers on its workers.dev address.
  • The container's image_vars set RELIC_VERSION to the release you downloaded, v0.2.0-beta.4; the image is ghcr.io/relicbuild/relic:v0.2.0-beta.4.

The Worker passes every RELIC_ variable and secret to the container, so any setting works. wrangler secret put asks for each secret's value.

Store the database URL, such as postgres://relic:<password>@db.example.com:5432/relic?sslmode=require:

pnpm exec wrangler secret put RELIC_DATABASE_URL

Store the R2 access key ID:

pnpm exec wrangler secret put RELIC_OBJECT_STORAGE_ACCESS_KEY

Store the R2 secret access key:

pnpm exec wrangler secret put RELIC_OBJECT_STORAGE_SECRET_KEY

Store the encryption key, the output of openssl rand -base64 32. Keep a copy outside Cloudflare: without it, Relic cannot read the secrets it stores.

pnpm exec wrangler secret put RELIC_ENCRYPTION_KEY

Store the admin password:

pnpm exec wrangler secret put RELIC_ADMIN_PASSWORD

Deploy

Build and push the image and deploy the Worker:

pnpm exec wrangler deploy

Open https://relic.example.com/ and sign in as admin.

Follow the Worker's requests and errors:

pnpm exec wrangler tail

Relic's own log is on the container's page in the Cloudflare dashboard.

Upgrade

Change RELIC_VERSION in image_vars to the new release's tag, then deploy again:

pnpm exec wrangler deploy

Relic applies migrations when the new container starts.

Run it locally

Locally the disk lasts as long as the container, so SQLite and a directory work. Put these settings in .dev.vars:

RELIC_DATABASE_URL=sqlite:///var/lib/relic/data/relic.db
RELIC_OBJECT_STORAGE_TYPE=filesystem
RELIC_OBJECT_STORAGE_PATH=/var/lib/relic/data/objects
RELIC_ADMIN_PASSWORD=<admin-password>
RELIC_ENCRYPTION_KEY=<openssl rand -base64 32>

Start the Worker and the container on http://localhost:8787:

pnpm exec wrangler dev