Skip to content

Environment variables

The core reads its configuration from environment variables at startup. There are two groups with different failure behaviour:

  • Core variables are validated strictly. A missing required value or an invalid one aborts the start with a message naming the variable.
  • Observability variables never abort. An invalid value prints an error prefixed [observability] and leaves observability disabled for the life of the process.

Legend: required optional

Core

DATABASE_URL required

PostgreSQL connection string.

DATABASE_URL=postgresql://axium:secret@axium-db:5432/axium-api

No default. The format is not validated beyond being a non-empty string; a wrong DSN shows up as [db] waiting for postgres... for 30 seconds followed by a crash. For a Cloud SQL Unix socket use postgresql://user:pass@localhost/dbname?host=/cloudsql/<connectionName> (the localhost is mandatory filler). See Database.

MASTER_ENCRYPTION_KEY required

Key used to encrypt provider credentials at rest with AES-256-GCM.

  • Format: exactly 64 hexadecimal characters (32 bytes). Anything else aborts with must be 64 hex characters (32 bytes). A trailing newline counts as a character.
  • Generate: openssl rand -hex 32
  • Cannot be rotated. Changing it makes every stored provider credential undecryptable; each provider has to be re-created or edited with its credentials again. Back it up with the database.

PORT optional

Listening port. Default 3000. Must be an integer between 0 and 65535. Platforms such as Cloud Run inject it for you.

NODE_ENV optional

One of development, test, production. The image sets production. Any other value aborts. Its only effect is the default of LOG_REQUESTS.

LOG_REQUESTS optional

true writes one line per HTTP request to stdout:

[req] POST /v1/proxy-apps/…/openai/v1/chat/completions 200 843ms
[req] POST /v1/proxy-apps/…/openai/v1/chat/completions 200 12043ms (aborted)

Default: on when NODE_ENV=development, off otherwise. An explicit value wins. Malformed JSON requests are logged too. See Request logging.

MAX_UPLOAD_SIZE optional

Ceiling for the body of a file upload request. Default 50mb. Accepts bytes-style strings: 10mb, 2gb, 524288000.

  • Applies only to the upload routes: …/openai/files, …/openai/v1/files, …/gemini/upload/v1beta/files, …/gemini/upload/v1/files.
  • The whole upload is held in RAM for the duration of the request. Size the container accordingly, or lower this value.
  • An empty string is not the default: it removes the limit entirely.
  • JSON bodies have a separate, fixed limit of 10 MB that is not configurable.

TRUST_PROXY optional

true makes the core trust X-Forwarded-For and X-Forwarded-Proto from the hop in front of it. Default false.

Set it to true only when a reverse proxy or load balancer terminates TLS in front of the core. It affects:

  • the client IP seen by the firewall policy and recorded as client_ip in traces;
  • the protocol used to rewrite Gemini resumable-upload URLs.

With false and a proxy in front, every client looks like the proxy. With true and no proxy, a client can forge its IP. See Reverse proxy & TLS.

PUBLIC_BASE_URL optional

Public URL of the core, e.g. https://axium-api.your-domain.com. No default.

Used for one thing: rewriting the x-goog-upload-url header that Google returns in the first step of a Gemini resumable upload, so the second step also goes through Axium. When unset, the core builds the URL from the request (protocol://host), which is only wrong when something in front terminates TLS. A trailing slash is removed.

AXIUM_LICENSE optional

Your license key, 40 hexadecimal characters. Validated once at startup against the Axium Lab license service. Today an absent or invalid license is only logged; the process starts anyway. See License.

AXIUM_LICENSE_FILE optional

Path to a JSON file holding the license, read only when AXIUM_LICENSE is empty. Default /license/license.json. Format:

{ "license": "0123456789abcdef0123456789abcdef01234567" }

A missing file means "no license". A file without a non-empty license string logs an error. Intended for mounting the key as a secret volume.

AXIUM_METASERVER optional

Base URL of the Axium Lab metadata service. Default https://meta.axium-lab.com/v1. Must be a valid URL or the start aborts. Used for GET {base}/license/check/{key} and POST {base}/telemetry. Only change it if Axium Lab gives you a different endpoint.

TELEMETRY_ENABLED optional

Default true. Once per process start (never periodically) the core sends one anonymous usage snapshot to the metadata service. It never blocks or fails the start, and nothing is sent when the schema is not installed.

TELEMETRY_ENABLED=false
What the snapshot contains

Aggregates over the whole history of the installation, no names, no prompts, no money:

{
  "telemetry_schema": 1,
  "install_id": "<random uuid generated at install>",
  "app_version": "3.1.0",
  "schema_version": 3,
  "installed_at": "…", "sent_at": "…",
  "traffic": {
    "requests": 0, "errors": 0, "denied": 0, "streamed": 0,
    "tokens_in": 0, "tokens_out": 0, "tokens_cached": 0,
    "tokens_reasoning": 0, "tokens_saved": 0,
    "avg_latency_ms": null, "max_latency_ms": null, "avg_ttfb_ms": null
  },
  "coverage": { "first_day": "YYYY-MM-DD", "last_day": "YYYY-MM-DD" }
}

Observability

These select and configure the per-request trace destination. The full behaviour is in the Observability section.

OBSERVABILITY_TYPE optional

Value Effect
unset, empty, none Traces are not recorded. Default.
postgres Traces are written to a PostgreSQL database and readable through the API.
http Traces are POSTed in batches to an HTTP endpoint.

Any other value logs unknown OBSERVABILITY_TYPE "<x>" (expected: postgres, http), disabled.

OBSERVABILITY_DB_POSTGRESQL required with postgres

Connection string of the database that receives the traces. It can be the main Axium database or a separate one. Empty with OBSERVABILITY_TYPE=postgres disables observability with a log line. The core opens a separate pool for it (max 8 connections).

OBSERVABILITY_HTTP_URL required with http

URL that receives one POST per batch. Not probed at startup: a wrong URL shows up on the first flush as a throttled error log.

OBSERVABILITY_HTTP_FORMAT optional

envelope (default) or ndjson. See Formats & event schema.

OBSERVABILITY_HTTP_HEADERS optional

A flat JSON object of string headers added to every POST, typically for authentication:

OBSERVABILITY_HTTP_HEADERS='{"Authorization":"Bearer xxx"}'
OBSERVABILITY_HTTP_HEADERS='{"DD-API-KEY":"…"}'

They are applied after Axium's own headers, so they can override content-type and x-axium-trace-version. Anything that is not a JSON object of strings disables observability with a log line.

Variables that do not exist

To save you a search: there is no configuration for CORS (it is open, see Security), rate limiting, provider timeouts or retries, log level or JSON logging, JWT secrets, OpenTelemetry (OTEL_*), Langfuse or feature flags. API_URL belongs to the ui, not the core; see Web console.

Quick reference

Variable Required Default Invalid value
DATABASE_URL yes — aborts
MASTER_ENCRYPTION_KEY yes — aborts
PORT no 3000 aborts
NODE_ENV no production (image) aborts
LOG_REQUESTS no off in production aborts
MAX_UPLOAD_SIZE no 50mb aborts
TRUST_PROXY no false aborts
PUBLIC_BASE_URL no request host —
AXIUM_LICENSE no — logged
AXIUM_LICENSE_FILE no /license/license.json logged
AXIUM_METASERVER no https://meta.axium-lab.com/v1 aborts
TELEMETRY_ENABLED no true aborts
OBSERVABILITY_TYPE no off observability disabled
OBSERVABILITY_DB_POSTGRESQL with postgres — observability disabled
OBSERVABILITY_HTTP_URL with http — observability disabled
OBSERVABILITY_HTTP_FORMAT no envelope observability disabled
OBSERVABILITY_HTTP_HEADERS no {} observability disabled