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
| Piece | Role |
|---|---|
functions | The 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-runtime | workerd 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 bucket | The 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. |
| Orchestrator | The Management API routes. Sends bundles to the functions service. |
| Worker | Cron schedules, the table-trigger installs, storage-trigger deliveries, the hourly bundle sweep. |
service-runner | Only 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
| Variable | Default | What it does |
|---|---|---|
CHELABASE_FUNCTIONS_TIMEOUT_MS | 30000 | An invocation's wall clock, in milliseconds. Past it: 504 function_timeout. A positive integer. |
CHELABASE_FUNCTIONS_ADDR | 127.0.0.1:8091 | The 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_ADDR | 127.0.0.1:8092 | The internal listener's runtime side (bundle GETs). Compose: functions-internal:8080. |
CHELABASE_FUNCTIONS_CONTROL_ADDR | 127.0.0.1:8093 | The internal listener's control side (bundle uploads, invocations, and the container services' image resolving, rollovers and logs). Compose: functions-control:8080. |
CHELABASE_FUNCTIONS_RUNTIME_URL | http://127.0.0.1:8080 | The runtime it calls. Compose: http://functions-runtime:8080. |
CHELABASE_FUNCTIONS_URL | http://127.0.0.1:8091 | The gateway's upstream for /functions/v1 and /services/v1. Compose: http://functions-public:8091. |
CHELABASE_FUNCTIONS_INTERNAL_URL | http://127.0.0.1:8093 | Where the orchestrator and the worker reach the control side. Compose: http://functions-control:8080. |
CHELABASE_ORCHESTRATOR_FUNCTIONS_TOKEN (or _FILE) | required | The orchestrator's bearer. At least 32 characters; read by the orchestrator and the functions service. |
CHELABASE_WORKER_FUNCTIONS_TOKEN (or _FILE) | required | The worker's bearer. At least 32 characters; must differ from the orchestrator's. |
CHELABASE_FUNCTIONS_SERVICE_RUNNER_TOKEN (or _FILE) | none | The functions service's bearer for the runner. |
CHELABASE_INTERNAL_URL | http://127.0.0.1:8083 | The orchestrator's internal listener, asked for the event dispatcher's database login. |
CHELABASE_COMPUTE_CA_FILE | none | The 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_FILE | compose sets chelabase-functions and the generated pair | The 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_MEMORY | 1g | The runtime container's memory limit (a compose size); every function shares it. Settable in .env. |
CHELABASE_FUNCTIONS_RUNTIME_TAG | latest | The runtime image tag a workbench builds and runs. Development only. |
CHELABASE_PUBLIC_SCHEME, CHELABASE_API_HOST | as set | What env.CHELABASE_URL holds, and the host env.CHELABASE always reaches. See Hosts. |
External services
| Variable | Default | What it does |
|---|---|---|
CHELABASE_SERVICES_ALLOW_HOSTS | none | Host 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_HTTP | false | true accepts http service URLs. Same two services. |
CHELABASE_INTERNAL_SUBNETS | none | Comma-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
| Variable | Default | What it does |
|---|---|---|
CHELABASE_SERVICE_RUNNER_MEMORY_CAP_MB | 512 | The most memory a container gets (MiB, at least 16). A spec may ask for less. |
CHELABASE_SERVICE_RUNNER_CPU_CAP | 1 | The most CPU a container gets (0.01 to 256). |
CHELABASE_SERVICE_RUNNER_RECONCILE_SECS | 30 | How often it reconciles desired and actual containers, in seconds. Settable in .env. |
CHELABASE_SERVICE_RUNNER_URL | none | Where the callers reach the runner. Compose: http://service-runner-control:8094. |
CHELABASE_SERVICE_RUNNER_ADDR | 127.0.0.1:8094 | Its API listener. Compose: service-runner-control:8094,127.0.0.1:8094. |
CHELABASE_COMPOSE_PROJECT | required | The compose project whose functions container the runner attaches to each service's network. Compose sets it from COMPOSE_PROJECT_NAME. |
CHELABASE_STACK | main | The only stack whose containers it touches. |
CHELABASE_FUNCTIONS_SERVICE_RUNNER_TOKEN, CHELABASE_WORKER_SERVICE_RUNNER_TOKEN (or _FILE) | required | The bearers of its two callers, the functions service and the worker. |
Development only
| Variable | What it does |
|---|---|
CHELABASE_STUB_SERVICE_URL | Where 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_PORT | The 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 -dWithout 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.CHELABASEbypasses 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 inCHELABASE_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/mereportsfunctions_available: falseso Studio hides the tab). A Cloudflare deployer is a later epic.
Using Amazon S3
Keep your app's files in an Amazon S3 bucket (or another S3-compatible store) instead of the bundled SeaweedFS.
Example organisation
Start a local Chelabase stack with a demo organisation, forty people in five teams, schemas, row-level security, app users and a branch to merge, and what to try in it.