This directory contains deployment artifacts and instructions for running Operator Reward Distributor in production-like environments.
Dockerfile— app image build (TypeScript →dist/)docker-compose.yml— Docker Compose stack (scheduler + API + Nginx proxy; optional local node)docker-compose.local-node.yml— local-node override (makesschedulerwait fornodehealth)nginx.conf— Nginx config template (used byproxy).env.example— example environment for Docker Compose
The runnable artifacts live directly under infra/.
- Docker and Docker Compose plugin installed
The repository includes a GitHub Actions workflow (.github/workflows/docker-build.yml) that builds Docker images on pushes to main and via manual dispatch.
- Go to the Actions tab in your GitHub repository
- Select Build Docker Image workflow
- Select the branch to build from using the branch dropdown (defaults to
main) - Click Run workflow
After building an image via GitHub Actions, you can use it in your deployment:
- Set
APP_IMAGEininfra/.env:
APP_IMAGE=ghcr.io/subspace/operator-reward-distributor:latest- Pull and start the stack (no build needed):
docker compose -f infra/docker-compose.yml pull
docker compose -f infra/docker-compose.yml up -dNote: When APP_IMAGE is set, docker-compose will use the pre-built image and skip local builds. Leave APP_IMAGE unset to build from source locally.
Images are tagged with:
latestand short commit SHA (main branch only)- Branch name and short commit SHA (other branches)
Images are pushed to: ghcr.io/subspace/operator-reward-distributor
- Copy and edit environment:
cp infra/.env.example infra/.env- Build and start the stack:
docker compose -f infra/docker-compose.yml up -d --build- Check API health (via the Nginx proxy):
curl -s http://127.0.0.1:${PROXY_HOST_PORT:-80}/health- Tail logs:
docker compose -f infra/docker-compose.yml logs -f api scheduler- App variables are documented in
src/config.ts. Compose readsinfra/.envviaenv_file. - Root
.env.exampleis for local development (yarn dev/yarn serve) and is not used by Compose. - Set
APP_IMAGEininfra/.envto use a pre-built image from registry (e.g., from GitHub Actions). Leave unset to build locally. - Set
NODE_DOCKER_TAG,NETWORK_ID, and (optionally)DOMAIN_IDininfra/.env. Compose uses${DOMAIN_ID:-0}to default the domain id to 0 if unset. Adjust node flags ininfra/docker-compose.ymlas needed. - Conditional local node: the
nodeservice is under thelocal-nodeprofile. To run with a local node, use the local-node override (addsscheduler -> nodehealth dependency) and pass the profile:
docker compose \
-f infra/docker-compose.yml \
-f infra/docker-compose.local-node.yml \
--profile local-node up -d --buildAlternatively, set the files once in your shell:
export COMPOSE_FILE=infra/docker-compose.yml:infra/docker-compose.local-node.yml
docker compose --profile local-node up -d --builddocker compose -f infra/docker-compose.yml up -d --builddocker compose -f infra/docker-compose.yml down- Copy env and adjust values
cp infra/.env.example infra/.env
# edit CHAIN_WS, ACCOUNT_PRIVATE_KEY, TIP_AI3, DAILY_CAP_AI3, etc.- Start stack (scheduler + api + proxy)
docker compose -f infra/docker-compose.yml up -d --build- Verify
curl -s http://127.0.0.1:${PROXY_HOST_PORT:-80}/health | jq .Notes:
- API service binds to
SERVER_HOST=0.0.0.0inside the network; it is not exposed directly. - Nginx listens on host port
${PROXY_HOST_PORT}(default 80) and proxies toapi:${SERVER_PORT}. - Sensitive endpoints
/configand/infoare allowlisted to127.0.0.1by default ininfra/nginx.conf. - For production, front Nginx with TLS (LB or certbot) and restrict access as needed.
- Copy env and adjust values
cp infra/.env.example infra/.env
# edit NODE_DOCKER_TAG, NETWORK_ID (and optionally DOMAIN_ID)
# set ACCOUNT_PRIVATE_KEY, TIP_AI3, DAILY_CAP_AI3, etc.- Start stack with local node enabled (base + override)
docker compose \
-f infra/docker-compose.yml \
-f infra/docker-compose.local-node.yml \
--profile local-node up -d --build- Verify
# API via Nginx proxy
curl -s http://127.0.0.1:${PROXY_HOST_PORT:-80}/health | jq .
# Optional: check embedded node JSON-RPC directly
curl -s -H 'Content-Type: application/json' \
-d '{"id":1,"jsonrpc":"2.0","method":"system_health","params":[]}' \
http://127.0.0.1:9944/ | jq .Notes:
- The
nodeservice is only started when thelocal-nodeprofile is used. - The local-node override (
docker-compose.local-node.yml) makesschedulerwait untilnodeis healthy before starting. .env.examplesetsCHAIN_WS=ws://node:8944,...so the app uses the embedded node's WebSocket RPC by default. JSON-RPC HTTP remains at127.0.0.1:9944(used by the healthcheck).- Node RPC ports are forwarded to the host at
127.0.0.1:9944(HTTP) and127.0.0.1:8944(WebSocket); seedocker-compose.yml.