Guide: Replicating the CRE + Docker System
This guide explains how to put your own Chainlink Runtime Environment (CRE) workflow in a Docker container, expose it via an HTTP gateway, and optionally run it on a schedule with in-container cron. It is based on the pattern used in this project (CRE simulate gateway) and is written so you can replicate the setup for your own workflow.
What You Get
- HTTP gateway inside the container that accepts JSON payloads and runs
cre workflow simulate <workflow> --http-payload @file. - Optional in-container cron that triggers a specific action (e.g. a "batch job" action) at a configurable schedule.
- Same interface as a deployed CRE workflow: any service (e.g. your backend) can POST to the container instead of to the CRE platform, and get the same request/response shape.
You do not need to deploy the workflow to the CRE platform to use it; the container acts as a local/simulate variant.
Prerequisites
- CRE CLI installed and (for onchain writes) logged in (
cre login), or a CRE API key. - Docker (and optional: Infisical or another secret manager for env injection).
- Your workflow project that compiles with CRE (e.g.
cre-compileorcre workflow simulatefrom the workflow directory).
1. Workflow and Config
- Have a CRE workflow in a directory (e.g.
markets/) with:- Entry point (e.g.
main.ts) that registers HTTP and optionally Cron triggers. - A config file (e.g.
config.docker.json) read by the workflow forbackendUrl,schedule, contracts, etc.
- Entry point (e.g.
- Config
schedule(if you use cron): CRE uses a 6-field cron format:second minute hour day month day-of-week. Example:"*/30 * * * * *"= every 30 seconds. When running in Docker, the entrypoint can convert this to a 5-field host cron by dropping the first field (see below).
2. Gateway Server
Create a small HTTP server that:
- Accepts POST requests (e.g. to
/or/trigger) with a JSON body. - Writes the body to a temporary file.
- Runs:
cre workflow simulate <workflowDir> --non-interactive --trigger-index 1 --http-payload @<tmpFile> --target <CRE_TARGET> [--broadcast] - Reads stdout/stderr, parses the workflow result (e.g. JSON after a known prefix), and returns it as the HTTP response.
Important details:
- Working directory: run
crefrom the project root so the workflow can resolve config and relative paths. - Secrets: the CRE CLI (and your workflow) need env vars (e.g. API keys, private keys). Either:
- Inject them at container runtime (e.g.
--env-file,-e, or Infisical in the entrypoint), and optionally write a.envin the working directory before callingcreso the workflow can load them. - Or mount a volume (e.g.
~/.cre) for CRE CLI auth and pass other secrets via env.
- Inject them at container runtime (e.g.
- Broadcast: for actions that must write onchain, pass
--broadcasttocre workflow simulate. You can derive this from the request body (e.g.body.broadcast === true) or from an env var (e.g.CRE_GATEWAY_BROADCAST=true) so every trigger in Docker is onchain.
Example flow (pseudocode):
POST / body = { action: "createMarketsFromBackend", broadcast: true }
-> write body to /tmp/cre-payload-<id>.json
-> cre workflow simulate markets --non-interactive --trigger-index 1 --http-payload @/tmp/cre-payload-<id>.json --target docker-settings --broadcast
-> parse stdout for "Workflow Simulation Result: {...}"
-> return 200 + JSON or 502 on non-zero exit
3. Cron Trigger (Optional)
If you want the same "batch" action to run on a schedule inside the container:
-
Cron script (e.g.
gateway/cron-trigger.sh): a script that POSTs a fixed payload to the gateway. Example:#!/usr/bin/env bash PORT="${GATEWAY_PORT:-8080}" HOST="${GATEWAY_HOST:-localhost}" curl -sS -X POST "http://${HOST}:${PORT}" -H "Content-Type: application/json" -d '{"action":"createMarketsFromBackend","broadcast":true}' -
Entrypoint installs a crontab that runs this script at the desired schedule. The schedule can come from:
- Env: e.g.
CRE_CRON_SCHEDULE="*/10 * * * *"(5-field: minute hour day month dow). - Config file: read
schedulefrom your workflow config (e.g.config.docker.json). If it is 6-field (CRE style), convert to 5-field by dropping the first (seconds) field, then install that as the crontab. Example:"*/30 * * * * *"→* * * * *(every minute).
- Env: e.g.
-
Start cron in the background in the entrypoint (e.g.
cronorcrond) so the cron daemon runs inside the container.
4. Entrypoint
The entrypoint script should:
- Optional – config file: if
CRE_CONFIG_FILEis set and points to a file (e.g. mounted from the host), copy it to the workflow's config path (e.g.markets/config.docker.json) so the workflow uses your chosen backend URL, contracts, and schedule. - Optional – cron:
- If
CRE_CRON_SCHEDULEis set, use it as the 5-field crontab. - Else, if the workflow config has a
schedulefield, read it, convert 6→5 if needed, and install the crontab. - Install the cron job that runs
gateway/cron-trigger.shand start the cron daemon.
- If
- Optional – secrets: if you use Infisical (or similar), run the main process under
infisical run ... -- "$@"so secrets are injected; otherwise rely on Docker env (exec "$@"). - Main process: start the HTTP gateway (e.g.
bun run gateway/server.tsornode gateway/server.js).
Use a Debian-based image if you rely on the CRE CLI; Alpine (musl) can cause "cannot execute" for the CLI binary.
5. Dockerfile
- Base: use a Debian-based runtime that matches how you run the gateway (e.g. Node/Bun).
- Install:
- CRE CLI (e.g. from
https://cre.chain.link/install.shinto/opt/creand add toPATH). - Dependencies for the entrypoint:
curl,bash,cron,jq(for parsing config schedule). - Optional: Infisical CLI if you inject secrets in the entrypoint.
- CRE CLI (e.g. from
- Copy: workflow directory, gateway (server + entrypoint + cron script), config, and any payload examples.
- Precompile (optional): run
cre-compileor a dry-run ofcre workflow simulateso the first HTTP request doesn't pay compile time. - Env: set
PORT,CRE_TARGET, and optionallyCRE_GATEWAY_BROADCAST=true. - Entrypoint: the script that sets up config, cron, and then runs the gateway.
Example structure:
FROM oven/bun:1
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates bash cron jq && rm -rf /var/lib/apt/lists/*
ENV CRE_INSTALL=/opt/cre
ENV PATH="/opt/cre/bin:${PATH}"
RUN curl -sSL https://cre.chain.link/install.sh | bash
WORKDIR /app
COPY markets ./markets
COPY gateway ./gateway
RUN chmod +x /app/gateway/entrypoint.sh /app/gateway/cron-trigger.sh
RUN bun install --cwd ./markets
ENV PORT=8080
ENV CRE_TARGET=docker-settings
EXPOSE 8080
ENTRYPOINT ["/app/gateway/entrypoint.sh"]
CMD ["bun", "run", "gateway/server.ts"]
6. Running the Container
- Port: map the gateway port (e.g.
-p 8080:8080). - Backend reachable from container: if the workflow calls a backend on the host, use
backendUrl: "http://host.docker.internal:4000"(or similar) and on Linux run Docker with--add-host=host.docker.internal:host-gateway. - Secrets: pass via
-e,--env-file, or Infisical in the entrypoint. For CRE CLI auth you can use-v "$HOME/.cre:/root/.cre"aftercre loginon the host, or setCRE_API_KEY. - Config override: mount your config and set
CRE_CONFIG_FILE=/config/cre.json(and copy it in the entrypoint to the workflow's config path). - Cron schedule: set
CRE_CRON_SCHEDULE="*/10 * * * *"to override the config's schedule; otherwise the entrypoint can derive the schedule from the config'sschedulefield (6→5 conversion).
Example:
docker build -t my-cre-gateway .
docker run --rm -p 8080:8080 \
--add-host=host.docker.internal:host-gateway \
-e CRE_TARGET=docker-settings \
-e CRE_CRON_SCHEDULE="*/10 * * * *" \
-v "$(pwd)/markets/config.docker.json:/config/cre.json" \
-e CRE_CONFIG_FILE=/config/cre.json \
--env-file .env \
my-cre-gateway
7. Using the Gateway from Your Backend
Point your backend at the container instead of at the CRE platform:
- Set
CRE_HTTP_URL=http://<host>:8080(or the URL of the gateway). - For a cron-triggered action (e.g. createMarketsFromBackend), you can either:
- Rely on the in-container cron to POST to the gateway at the schedule, or
- Have the backend call the gateway on its own schedule (e.g. backend cron POSTs to
CRE_HTTP_URL).
The request body must include the action (and any other fields your workflow expects); the gateway forwards the full body as the HTTP payload to cre workflow simulate.
Summary Checklist
| Step | Description |
|---|---|
| 1 | CRE workflow with HTTP (and optional Cron) trigger; config file for backend URL, schedule, etc. |
| 2 | Gateway server: POST → write body to temp file → cre workflow simulate ... --http-payload @file → return parsed result. |
| 3 | Optional: cron script that POSTs to the gateway; entrypoint installs crontab (from env or from config schedule 6→5) and starts cron. |
| 4 | Entrypoint: optional config copy, optional cron setup, optional Infisical, then run gateway. |
| 5 | Dockerfile: install CRE CLI, cron, jq; copy workflow + gateway; set PORT and CRE_TARGET; entrypoint + CMD. |
| 6 | Run container with port map, host alias for backend, secrets, and optional CRE_CONFIG_FILE / CRE_CRON_SCHEDULE. |
| 7 | Backend uses CRE_HTTP_URL to POST to the container as if it were the CRE platform. |
This gives you a replicable CRE + Docker system: your workflow runs in a container, triggered by HTTP and optionally by in-container cron, with the same contract as a deployed CRE workflow.