Configuration
--config names one exact regular file. A relative value is resolved once against the startup working directory; an absolute value keeps its absolute meaning. The file leaf is opened without following symlinks, and no parent or $HOME search occurs. Relative filesystem paths inside TOML are resolved against the canonical directory containing the opened config. . and .. are normalized; ~, environment references, globs, and URIs are not expanded. Parse time does not read .env or resolve secret values. Unknown fields are rejected.
Path examples on this page use /etc/open-compute/config.toml. Some embedded runbooks write platform.toml; the flag is only --config, not a second format keyed by filename.
ocd config init --data-dir /var/lib/open-compute > /etc/open-compute/config.tomlocd --config /etc/open-compute/config.toml config checkconfig init resolves data-dir against the startup working directory, writes absolute paths into the template, and prints it to stdout. It does not create directories or write secrets. config check is static parse and validation only.
The embedded default template matches share/default-config.toml. Live numeric limits come from ocd --config /abs/config.toml capabilities --json limits.
Secrets
Section titled “Secrets”Secrets are references only. Do not put them in units, images, the repository, or config plaintext.
server.admin_auth,server.deployer_auth, andserver.read_only_auth: three required, mutually distinct Bearer token references usingenvand/or afilepath.- S3 backend only:
storage.access_key_id_env/storage.access_key_id_fileandstorage.secret_access_key_env/storage.secret_access_key_file; each pair needs at least one. Local never reads these variables. - Master key:
data.master_key_file; optionaldata.master_key_env. - Environment variable names must be non-empty ASCII uppercase, digits, and underscore, and must not start with a digit.
- Tenant binding names must not start with
OPEN_COMPUTE_; that prefix is reserved by the platform, not a license to inline secrets.
Every admin listener, including loopback, requires all three role tokens. Startup rejects equal resolved token values instead of relying on match order.
[ai]: provider backends and embedding profiles
Section titled “[ai]: provider backends and embedding profiles”An AI backend is one operation-specific, final request URL. ocd never appends /embeddings or /chat/completions, so include any provider path prefix and the operation route in endpoint:
[ai.backends.bailian-embeddings]protocol = "openai_embeddings_v1"endpoint = "https://dashscope.aliyuncs.com/compatible-mode/v1/embeddings"auth = { kind = "bearer", secret = { env = "DASHSCOPE_API_KEY" } }headers = { "X-Title" = "open-compute" }
[ai.embedding_profiles."qwen/qwen3-1024"]dimensions = 1024max_input_tokens = 8192send_dimensions = truetokenizer = { kind = "qwen3", revision = "pinned-tokenizer-revision", artifact = { path = "/opt/open-compute/tokenizers/qwen3/tokenizer.json", sha256 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" } }
[ai.embedding_models."company/qwen-embedding"]backend = "bailian-embeddings"remote_model = "text-embedding-v4"profile = "qwen/qwen3-1024"Authentication is a closed choice: bearer, one custom secret header, or none. For providers that require a custom key header, use auth = { kind = "header", name = "X-API-Key", secret = { file = "/run/secrets/provider-key" } }. The optional headers map is only for non-secret static metadata. It cannot override Authorization, the custom auth header, host/content headers, cookies, proxy headers, or hop-by-hop headers. none is accepted only for loopback HTTP; non-loopback endpoints require HTTPS.
Profiles keep model facts reusable without making them implicit. Dimensions, maximum input tokens, whether to send dimensions, and a digest-pinned offline tokenizer belong in the profile. AI Search fixes its metric to cosine. config check validates the artifact declaration without reading it; ocd verifies the local bytes while composing AI Search services and never downloads a tokenizer.
[data]: platform state and lock
Section titled “[data]: platform state and lock”[data]:
| Field | Role |
|---|---|
path |
Data root. SQLite, identity, master key, runtime extraction, and cache live here |
master_key_file |
Master key path |
sqlite_busy_timeout_ms |
SQLite busy_timeout |
free_space_soft_bytes |
Health degrades below this |
free_space_hard_bytes |
Mutations refused below this; must be ≤ soft |
One ocd per data-dir. The exclusive lock is <data_dir>/platform.lock. A second instance gets DATA_DIR_IN_USE; do not bypass it. The data-dir must be writable and executable (the extracted workerd runs from here).
[storage]: object bytes
Section titled “[storage]: object bytes”storage.backend is required and is exactly local or s3. The variants are mutually exclusive, with no fallback, dual write, or automatic migration. Both use disjoint canonical prefix / r2_prefix values.
Local fields:
| Field | Constraint |
|---|---|
path |
Secure local object root; either <data.path>/objects or disjoint from data.path |
free_space_soft_bytes |
Object-storage health degrades below this |
free_space_hard_bytes |
Object writes are refused below this; must be ≤ soft |
partial_grace_ms |
Minimum age before strictly owned crash remnants are reclaimed |
The local root must be a mode-0700 directory on a supported local filesystem. Symlinks, special files, unexpected entries, insecure modes, and network/FUSE filesystems fail closed. Local is direct filesystem storage; it does not start an S3 server or rclone.
S3 uses AWS SDK SigV4:
| Field | Constraint |
|---|---|
endpoint |
Service URL |
region |
Non-empty; auto is accepted |
bucket |
Non-empty |
force_path_style |
Default true |
verify_tls |
Cannot be disabled |
prefix / r2_prefix |
Must be canonical and disjoint |
A failed upload is not committed. An initialized platform is bound to its backend kind and authority fingerprint. Do not temporarily switch backend, root, provider, bucket, or prefix to “just get it running”.
Other sections
Section titled “Other sections”The template also includes [server], [runtime], [cache], [response_cache], [images], [ai], [metrics], [hardening], [workers], [kv], [r2], [d1], [queues], [durable_objects], [scheduler] (including pools), and [workflows]. These are local quotas and timeouts, not Cloudflare plan SKUs. Run config check before changing them, then capabilities --json for actual limits.
hardening.emergency_reserve_bytes must be below the [data] hard reserve.