Cloudflare
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 typestandard-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>inRELIC_OBJECT_STORAGE_ENDPOINTwith your account ID. The buckets default torelic-artifactsandrelic-temporary. - To serve Relic on your own domain, add
"routes": [{ "pattern": "relic.example.com", "custom_domain": true }]. Without it, the Worker answers on itsworkers.devaddress. - The container's
image_varssetRELIC_VERSIONto the release you downloaded,v0.2.0-beta.4; the image isghcr.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