Chelabase

Functions and services

The services behind edge functions, every setting they add, the services compose profile, and the security notes an operator needs.

The user guides are Functions and Services. This page is what an operator runs and sets.

What runs

PieceRole
functionsThe functions service. Public listener behind the gateway at /functions/v1 and /services/v1; an internal listener in two sides: the runtime's (bundle downloads) and the control side (bundle uploads and the container services' internal routes, image resolving, rollovers and logs, from the orchestrator; invocations from the worker; each caller behind its own bearer). Resolves a branch's function, calls the runtime, proxies services, health-checks them, and delivers database events from the branches' outboxes.
functions-runtimeworkerd with a small supervisor. It loads bundles by hash through its Worker Loader, so a deploy needs no restart. Runs without secrets, as a non-root user, read-only, with every capability dropped and a memory limit, on two networks: functions (internal; shared only with the functions service and the gateway alias) and functions-egress (the way out for public addresses).
Bundle bucketThe chelabase-functions bucket in the object store, written and read through a functions S3 identity that can reach that bucket only. Only the functions service and the worker mount its keys.
OrchestratorThe Management API routes. Sends bundles to the functions service.
WorkerCron schedules, the table-trigger installs, storage-trigger deliveries, the hourly bundle sweep.
service-runnerOnly with the services profile. Starts container services.

The functions network is internal: true, so the runtime has no route to anything on it but the functions service and the gateway alias gateway-functions (the target of env.CHELABASE).

Secrets are generated by init-secrets like every other: the NATS functions password, the orchestrator's and the worker's bearers for the functions service, the functions service's and the worker's bearers for the runner, and the functions S3 keys. Pin any of them before the first up with the CHELABASE_SEED_* lines in .env: CHELABASE_SEED_NATS_FUNCTIONS_PASSWORD, CHELABASE_SEED_ORCHESTRATOR_FUNCTIONS_TOKEN, CHELABASE_SEED_WORKER_FUNCTIONS_TOKEN, CHELABASE_SEED_FUNCTIONS_SERVICE_RUNNER_TOKEN and CHELABASE_SEED_WORKER_SERVICE_RUNNER_TOKEN. Each token is at least 32 characters, and the orchestrator's and the worker's must differ.

Turn edge functions on

The functions service and its runtime run in every install: a plain docker compose up starts them. Container services also need the services profile (see below).

Settings

Set these in .env (blank means the default). Those marked "compose" are already wired by the compose files; they are listed for installs that run the services another way.

Functions service

VariableDefaultWhat it does
CHELABASE_FUNCTIONS_TIMEOUT_MS30000An invocation's wall clock, in milliseconds. Past it: 504 function_timeout. A positive integer.
CHELABASE_FUNCTIONS_ADDR127.0.0.1:8091The public listener (behind the gateway). Comma-separated host:ports, names resolved at start. Compose: functions-public:8091,127.0.0.1:8091.
CHELABASE_FUNCTIONS_INTERNAL_ADDR127.0.0.1:8092The internal listener's runtime side (bundle GETs). Compose: functions-internal:8080.
CHELABASE_FUNCTIONS_CONTROL_ADDR127.0.0.1:8093The internal listener's control side (bundle uploads, invocations, and the container services' image resolving, rollovers and logs). Compose: functions-control:8080.
CHELABASE_FUNCTIONS_RUNTIME_URLhttp://127.0.0.1:8080The runtime it calls. Compose: http://functions-runtime:8080.
CHELABASE_FUNCTIONS_URLhttp://127.0.0.1:8091The gateway's upstream for /functions/v1 and /services/v1. Compose: http://functions-public:8091.
CHELABASE_FUNCTIONS_INTERNAL_URLhttp://127.0.0.1:8093Where the orchestrator and the worker reach the control side. Compose: http://functions-control:8080.
CHELABASE_ORCHESTRATOR_FUNCTIONS_TOKEN (or _FILE)requiredThe orchestrator's bearer. At least 32 characters; read by the orchestrator and the functions service.
CHELABASE_WORKER_FUNCTIONS_TOKEN (or _FILE)requiredThe worker's bearer. At least 32 characters; must differ from the orchestrator's.
CHELABASE_FUNCTIONS_SERVICE_RUNNER_TOKEN (or _FILE)noneThe functions service's bearer for the runner.
CHELABASE_INTERNAL_URLhttp://127.0.0.1:8083The orchestrator's internal listener, asked for the event dispatcher's database login.
CHELABASE_COMPUTE_CA_FILEnoneThe CA every compute is verified against. Unset: database events aren't dispatched.
CHELABASE_FUNCTIONS_S3_BUCKET, CHELABASE_FUNCTIONS_S3_ACCESS_KEY_FILE, CHELABASE_FUNCTIONS_S3_SECRET_KEY_FILEcompose sets chelabase-functions and the generated pairThe worker's bundle-sweep identity. (The functions service uses the CHELABASE_STORAGE_BACKEND and CHELABASE_STORAGE_S3_* settings with the same bucket and pair.)
CHELABASE_FUNCTIONS_RUNTIME_MEMORY1gThe runtime container's memory limit (a compose size); every function shares it. Settable in .env.
CHELABASE_FUNCTIONS_RUNTIME_TAGlatestThe runtime image tag a workbench builds and runs. Development only.
CHELABASE_PUBLIC_SCHEME, CHELABASE_API_HOSTas setWhat env.CHELABASE_URL holds, and the host env.CHELABASE always reaches. See Hosts.

External services

VariableDefaultWhat it does
CHELABASE_SERVICES_ALLOW_HOSTSnoneHost names or IP literals, no port, that external services may use even if they resolve to non-public addresses. Set it on both the orchestrator and the functions service.
CHELABASE_SERVICES_ALLOW_HTTPfalsetrue accepts http service URLs. Same two services.
CHELABASE_INTERNAL_SUBNETSnoneComma-separated CIDRs added to the hard deny, beside every network the functions container is attached to. The compose files don't set it.

These are independent of CHELABASE_WEBHOOKS_ALLOW_HOSTS and _ALLOW_HTTP. The compose files pass CHELABASE_SERVICES_ALLOW_HOSTS and CHELABASE_SERVICES_ALLOW_HTTP through to the orchestrator and the functions service, so set them in .env. Internal hosts (the stack's own service names and networks) are always denied, allow-list or not.

Service runner

VariableDefaultWhat it does
CHELABASE_SERVICE_RUNNER_MEMORY_CAP_MB512The most memory a container gets (MiB, at least 16). A spec may ask for less.
CHELABASE_SERVICE_RUNNER_CPU_CAP1The most CPU a container gets (0.01 to 256).
CHELABASE_SERVICE_RUNNER_RECONCILE_SECS30How often it reconciles desired and actual containers, in seconds. Settable in .env.
CHELABASE_SERVICE_RUNNER_URLnoneWhere the callers reach the runner. Compose: http://service-runner-control:8094.
CHELABASE_SERVICE_RUNNER_ADDR127.0.0.1:8094Its API listener. Compose: service-runner-control:8094,127.0.0.1:8094.
CHELABASE_COMPOSE_PROJECTrequiredThe compose project whose functions container the runner attaches to each service's network. Compose sets it from COMPOSE_PROJECT_NAME.
CHELABASE_STACKmainThe only stack whose containers it touches.
CHELABASE_FUNCTIONS_SERVICE_RUNNER_TOKEN, CHELABASE_WORKER_SERVICE_RUNNER_TOKEN (or _FILE)requiredThe bearers of its two callers, the functions service and the worker.

Development only

VariableWhat it does
CHELABASE_STUB_SERVICE_URLWhere the end-to-end test for external services finds its stub service (infra/compose/fixtures/stub-service.yml). Unset, that test is skipped.
CHELABASE_STUB_SERVICE_BIND, CHELABASE_STUB_SERVICE_PORTThe address (172.17.0.1) and port (18099) the stub overlay publishes.

The services profile

The runner and container services are off by default. Enable them by setting the profile:

# in .env
COMPOSE_PROFILES=services
# or
docker compose --profile services up -d

Without it there is no service-runner: container deploys, rollovers and logs answer 503 runner_unavailable, and external services work as usual. The runner works with the functions service, which runs by default.

The runner is the third holder of the Docker socket, after the orchestrator and the worker (they start computes). It acts only on containers labelled with its stack and a service, creates them hardened (non-root, read-only, no capabilities, resource limits, no host mounts), and gives each its own private network that only the functions container joins. It does not filter egress. See What the runner doesn't isolate: a container can reach the host's private and link-local addresses, and an image registry that resolves to a non-public address is refused, which narrows but can't close pull-side SSRF. Give container deploys only to tenant admins you trust with the Docker host's network.

Security notes for operators

  • Functions share one runtime thread. A function in a busy loop stalls every function until the watchdog restarts the runtime, about 6 to 9 seconds, and it can be repeated. Only people you trust should have Developer access to a database with functions. See Auth modes and limits.
  • env.CHELABASE bypasses a reverse proxy in front of the API host: it reaches the gateway directly. Filters, allow-lists and rate limits at your proxy don't see function traffic, and all of it shares one per-IP bucket at the gateway. If you list the runtime's network in CHELABASE_GATEWAY_TRUSTED_PROXIES, the binding already strips client-address headers, but don't trust ranges that cover the runtime.
  • A function can call itself through the binding with no hop limit.
  • Outbound from a function is public addresses only, enforced by the runtime; outbound from a service is the allow-list above plus the hard deny.
  • Database triggers keep a compute awake while installed and enabled. The database's owner-level roles can read (and write) the outbox, and every row is vetted before delivery.
  • Platform mode: functions and services are unavailable (403 not_available_in_platform_mode, and /v1/me reports functions_available: false so Studio hides the tab). A Cloudflare deployer is a later epic.

On this page