Skip to content

Configuration reference

Faber is configured entirely through environment variables. It checks them at startup and refuses to start if one is malformed or out of range; the error names the variable. Numbers must be positive unless stated otherwise. Sizes in bytes are plain integers except MEMORY_MAX.

GET /api/v1/info reports the effective limits, profiles, cache state and toolchains of a running instance.

VariableDefaultMeaning
API_KEYrequiredKey expected in the Authorization header (Bearer <key> or the raw key). A comma-separated list accepts every listed key, for rotation. Faber logs a warning for keys shorter than 32 characters; generate them with openssl rand -hex 32
HOST0.0.0.0Listen address
PORT3000Listen port. The API is served under /api/v1
SHUTDOWN_TIMEOUT_MS5000How long in-flight requests may drain after SIGTERM. Keep it below the container’s stop grace period (10 s in Docker by default)
HEADER_READ_TIMEOUT_MS10000Time a client has to send a request’s headers. It also closes idle keep-alive connections, so slow or stalled clients cannot hold connections open
REQUEST_BODY_TIMEOUT_MS60000Time a client has to send a request body once the headers have arrived
RATE_LIMIT_PER_MINUTE0 (off)Requests per API key and minute on protected routes, as a token bucket. A request over the limit gets 429 with code rate_limited and a Retry-After header. Everyone using the same key shares its bucket
RATE_LIMIT_BURSTone minute’s worthRequests a key may send at once before the per-minute rate applies. Must be at least 1 when rate limiting is on
LOG_FORMATtextjson writes one JSON object per log line
RUST_LOGfaber=info,faber_api=info,faber_runtime=infoLog filter (tracing EnvFilter syntax)
VariableDefaultMeaning
MAX_CONCURRENCY10Task slots: sandboxed tasks that may run at once across all requests. A request reserves one slot per task of its widest step; requests that do not fit get 503
MAX_PARALLEL_TASKS8Tasks in one parallel step. Must not exceed MAX_CONCURRENCY
MAX_STEPS_PER_REQUEST64Steps in one request
MEMORY_MAX256MPer-task memory.max, in bytes or with a K, M, G or T suffix. Must be finite and at least 1M
PIDS_MAX64Per-task pids.max (processes and threads)
CPU_MAX50000 100000Per-task cpu.max: <quota> [<period>] in microseconds. Quota is max or at least 1000; period 1000 to 1000000 (default 100000). The default is half a core
WALL_TIMEOUT_MS5000Wall-clock limit per task
CPU_TIME_LIMIT_SECS5RLIMIT_CPU per task process
OVERALL_TIMEOUT_MS30000Deadline for a whole request. Faber warns at startup when MAX_STEPS_PER_REQUEST × WALL_TIMEOUT_MS exceeds it
OUTPUT_LIMIT_BYTES1048576Bytes kept per output stream per task; the task is killed beyond it
REQUEST_OUTPUT_LIMIT_BYTES16777216Output bytes kept across every task of a request
EXECUTE_BODY_LIMIT_BYTES1048576Largest /execute request body
VariableDefaultMeaning
DEFAULT_SANDBOX_PROFILEcompile_v2Seccomp profile for tasks that do not name one. Must be in ALLOWED_SANDBOX_PROFILES
ALLOWED_SANDBOX_PROFILEScompile_v2,native_v2Profiles a request may select: any of compile_v2, native_v2, compile_v1, native_v1. See sandbox profiles
SANDBOX_READONLY_PATHS/bin,/lib,/lib64,/usr,/etc/alternatives,/etc/ld.so.cache,/etc/passwd,/etc/groupPaths of the image that tasks see read-only. Replaces the default list, so include the defaults when adding to it. Each must be absolute, without .., and not / or under /proc, /sys, /dev, /tmp or /faber
SANDBOX_IDENTITY_BASE100000First host UID/GID leased to requests
SANDBOX_IDENTITY_COUNT65536Size of that range. Several Faber instances on one kernel must use ranges that do not overlap

A toolchain that keeps files outside the default paths needs them added, for example the JDK’s configuration:

Terminal window
SANDBOX_READONLY_PATHS=/bin,/lib,/lib64,/usr,/etc/alternatives,/etc/ld.so.cache,/etc/passwd,/etc/group,/etc/java-17-openjdk

The Dockerfile builder computes this list for the languages you pick.

See step cache for the semantics.

VariableDefaultMeaning
CACHE_ENABLEDfalseTurns the step cache on (true, false, 1 or 0). Off, cache flags in requests are ignored and responses report "enabled": false
CACHE_BACKENDmemorymemory: the in-process tier only. redis: the in-process tier plus a shared Redis tier
CACHE_REDIS_URLnoneRedis connection URL, for example redis://:password@redis:6379/0. Required when CACHE_BACKEND=redis
CACHE_NAMESPACEdefaultPrefix of every Redis key, and part of every layer key. Use one per environment sharing a Redis. DELETE /cache clears only this namespace
CACHE_TTL_SECS300Lifetime of a cached layer, in both tiers; refreshed on every hit
CACHE_MAX_BYTES67108864Bytes held by the in-process tier, results and file contents included; least recently used layers are evicted
CACHE_MAX_ENTRIES1024Layers and blobs held by the in-process tier
CACHE_MAX_LAYER_BYTES67108864Largest workspace a layer may capture. A step whose workspace is bigger runs normally but is not stored
CACHE_MAX_LAYER_FILES4096Most files and directories a layer may capture
VariableDefaultMeaning
FABER_TOOLCHAINSemptyThe language toolchains installed in the image, as comma-separated id@version or id entries, for example c@12,python@3.12,node. Reported by GET /info and part of every cache key. Images from the Dockerfile builder set it
FABER_IMAGE_IDemptyAn identifier of the image build, such as its digest or a CI build ID. Part of every cache key, so a rebuilt image never replays layers produced by different toolchains. Set it when the cache is enabled

See file store.

VariableDefaultMeaning
FABER_STORE_BACKENDmemorymemory, filesystem or hybrid
FABER_STORE_PATH/var/lib/faber/storeDirectory of the filesystem and hybrid backends. Needs a writable volume, since the production container’s root is read-only
FABER_STORE_MAX_TOTAL_BYTES536870912Total bytes of stored files; uploads beyond it are refused
FABER_STORE_MAX_ENTRIES1000Number of stored files; uploads beyond it are refused
FABER_STORE_TTL_SECS3600Files expire this long after their last upload or read. 0 disables expiry
FABER_STORE_TTL_CHECK_SECS60Interval of the sweep that removes expired files
FABER_STORE_MAX_MEMORY_ENTRIES1000hybrid only: files cached in memory
FABER_STORE_MAX_MEMORY_SIZE104857600hybrid only: bytes cached in memory
UPLOAD_FILE_LIMIT_BYTES52428800Largest single upload (413 above it)
MAX_CONCURRENT_UPLOADS4Uploads buffered at once (503 above it)

Aggregate resources. Faber’s own cgroup is capped at (MEMORY_MAX + supervisor allowance) × MAX_CONCURRENCY bytes and (PIDS_MAX + 3) × MAX_CONCURRENCY processes, which covers every admitted task at its own limit together with the root processes that run it. The supervisor allowance is 64 MiB + 2 × REQUEST_OUTPUT_LIMIT_BYTES (output capped at 1 GiB) plus the 288 MiB the workspace and /tmp tmpfs can hold (their data and 1 KiB for each of their inodes). Each request runs in its own cgroup capped at its widest step times the per-task limits plus that allowance. Sizing turns this into container and host memory.

Deadlines. Each step’s wall timeout is clipped to what is left of OVERALL_TIMEOUT_MS, and steps that cannot start are returned as not_started. With the defaults, a request of 64 slow steps (64 × 5 s) cannot finish within 30 s; that is intended, and the startup warning says so.

Memory per request. A response holds at most REQUEST_OUTPUT_LIMIT_BYTES of task output. JSON escaping can grow control bytes up to six times, and the result exists in the sandbox controller, the API process and (with the cache) the cache, so budget roughly 6 × REQUEST_OUTPUT_LIMIT_BYTES per copy per concurrent request.

Fan-out. MAX_PARALLEL_TASKS must not exceed MAX_CONCURRENCY, or the widest allowed step could never be admitted.