Skip to main content

Environment Variable Reference

This is the authoritative table of environment variables recognized by Open ACE, grouped by where they are declared: .env.example (the 13 user-facing variables for Docker Compose), the Compose files themselves, the scheduler service, the Kubernetes ConfigMap, and application code. Bare-metal deployments set the same variables through their service manager or shell.

Rotation impact describes what happens when you change the value on an existing deployment.

Table of Contents​

Security Mode and Secrets (.env.example)​

VariableDefaultPurposeRotation impactSource
OPENACE_SECURITY_MODEunset (Compose default: development)Security mode: production (strict checks, secrets required), pilot (auto-generate with strong warnings), development (auto-generate). Required explicitly in production (Issue #2331)Switching to production without explicit secrets refuses startup; switching away weakens checks.env.example, docker-compose.yml, app/utils/security_mode.py
SECRET_KEYemptyFlask session signing key (>= 32 characters in production)Rotation invalidates every logged-in session — all users are logged out; no data loss.env.example, docker-compose.yml
OPENACE_ENCRYPTION_KEYemptyFernet key material (>= 32 characters) encrypting all 8 secret stores (SSO, SMTP, API keys, integrations); also signs proxy tokensRotation without re-encrypting makes stored secrets permanently undecryptable and invalidates proxy tokens — see KEY_MANAGEMENT.md.env.example, docker-compose.yml
UPLOAD_AUTH_KEYemptyShared secret for workspace file-upload endpoints; empty disables the endpointRotation breaks upload clients until they use the new key.env.example, docker-compose.yml
SSO_ALLOWED_REDIRECT_DOMAINSempty (only localhost allowed)Comma-separated allowlist of domains SSO may redirect to after login (Issue #3224)Changing the list changes where SSO logins may land; removing a domain blocks its redirects.env.example

Database (.env.example)​

VariableDefaultPurposeRotation impactSource
DB_USERacePostgreSQL user (also POSTGRES_USER)Changing it requires re-provisioning the database user; not a routine rotation.env.example, docker-compose.yml
DB_PASSWORDempty (Compose falls back to dev-password-change-in-production)PostgreSQL password; passed both inside DATABASE_URL and standalone for the security baseline check (Issue #3095). Strong value (>= 9 chars) required in production (Issue #1893)Must be changed in .env AND in PostgreSQL (ALTER USER ... WITH PASSWORD), then the stack restarted; mismatch = connection failures.env.example, docker-compose.yml
DB_NAMEacePostgreSQL database name (also POSTGRES_DB)Renaming requires migrating the database; not a routine rotation.env.example, docker-compose.yml

Networking (.env.example)​

VariableDefaultPurposeRotation impactSource
PORT19888Host port mapping for the web UI; the container always listens on 19888 (Issue #1372)None on data; users and bookmarks must use the new port.env.example, docker-compose.yml
SERVER_IPempty (auto-detected)Address browsers use to reach the service (Issue #1306). The entrypoint auto-detects, rejects unreachable reserved ranges (e.g. 0.0.0.0/8 falls back to localhost); set explicitly for access from other machines, e.g. SERVER_IP=192.168.1.100Changes generated URLs (workspace links, config server_url).env.example, docker-compose.yml, docker-entrypoint.sh
WORKSPACE_PORT_RANGE_START3100Start of the published port range for per-user workspace WebUI instances; Compose expands the range into individual port mappingsShrinking the range blocks instances on removed ports; requires recreating containers.env.example, docker-compose.yml
WORKSPACE_PORT_RANGE_END3200End of the published workspace port rangeSame as above.env.example, docker-compose.yml

Workspace Mode (.env.example)​

VariableDefaultPurposeRotation impactSource
WORKSPACE_ISOLATION_BACKENDsharedWorkspace isolation backend (Issue #3446, v2.1.0; replaces WORKSPACE_MULTI_USER_MODE / WORKSPACE_REQUIRED_ISOLATION_LEVEL): shared = one shared WebUI, plain = one OS account per user (needs the root multi-user overlay with OPENACE_ALLOW_ROOT_MULTI_USER=1 and OPENACE_CONFIG_DIR=/home/open-ace/.open-ace), opensandbox = per-user pods on Kubernetes. Docker installs accept only these three values; the config.json counterpart is workspace.isolation (see WORKSPACE_ISOLATION.md and MULTI_USER_WORKSPACE.md)Changes the runtime security posture; takes effect after restart.env.example, docker-compose.yml, docker-entrypoint.sh
WORKSPACE_MULTI_USER_MODEfalseSuperseded in v2.1.0 (Issue #3446) by WORKSPACE_ISOLATION_BACKEND — use WORKSPACE_ISOLATION_BACKEND=plain for the old true. Historically: true enabled multi-user workspace mode (per-user system accounts + WebUI instances, container runs as root; with OPENACE_ALLOW_ROOT_MULTI_USER=1 and OPENACE_CONFIG_DIR=/home/open-ace/.open-ace, Issue #2242)Setting it (or WORKSPACE_REQUIRED_ISOLATION_LEVEL) now makes docker-entrypoint.sh refuse to start, naming the replacementpre-v2.1.0 .env.example / docker-compose.yml; rejected by docker-entrypoint.sh

Image and Compose Internals (docker-compose.yml)​

Declared inline by the Compose files; override in .env when needed.

VariableDefaultPurposeRotation impactSource
IMAGE_NAMEghcr.io/open-ace/open-ace:latestApplication image for the open-ace and scheduler servicesPinning a different tag is the standard upgrade/rollback lever (see UPGRADING.md)docker-compose.yml
BASE_REGISTRYdocker.ioBase-image registry override (e.g. docker.m.daocloud.io for mainland China); affects the build stage and the PostgreSQL image referenceRebuild/re-pull requireddocker-compose.yml
DATABASE_URLconstructedpostgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME} — assembled by Compose from the DB_* variablesFollows DB_* rotationdocker-compose.yml
WORKSPACE_BASE_DIR/workspace (Compose)Root directory for user projects; supports comma-separated multiple directories. Bare-metal root runs must set it explicitly (/root is rejected by the blacklist)Moving it orphans existing project directoriesdocker-compose.yml, app/utils/workspace.py
OPENACE_CONFIG_DIR/home/open-ace/.open-ace (overlay)Config persistence directory; must match the config-data volume mount pathPointing it elsewhere loses auto-generated config and secretsdocker-compose.multi-user.yml
OPENACE_ALLOW_ROOT_MULTI_USER1 (overlay)Explicit opt-in for root multi-user execution (Issue #1893)Removing it makes multi-user mode refuse to startdocker-compose.multi-user.yml
OPENACE_AGENT_STATE_ROOT/var/lib/openace/agent-stateCarried CLI transcripts; must match exactly between the app and scheduler services (Issue #3237)Mismatch breaks transcript purging between servicesdocker-compose.yml
FETCH_USE_SUDOfalseWhether fetchers use sudo (container runs as root, so sudo is unnecessary; Issue #1121)—docker-compose.yml
FLASK_ENVproduction (scheduler service)Legacy environment flag; as a security-mode signal it is deprecated and removed in v2.1.0 — migrate to OPENACE_SECURITY_MODE (use scripts/migrate_security_mode.sh)Relying on it for security mode stops working in v2.1.0docker-compose.yml, .env.example, app/utils/security_mode.py

Scheduler Service (docker-compose.yml)​

The scheduler service (profile scheduler in single-user mode; enabled by default under the multi-user overlay) uses:

VariableDefaultPurposeRotation impactSource
SCHEDULER_MODEschedulerMarks the process as the background scheduler worker (leader election ensures one active scheduler, Issue #2187)—docker-compose.yml
SCHEDULER_HEARTBEAT_INTERVAL10Heartbeat interval (seconds) between scheduler beatsMismatched values across replicas skew liveness detectiondocker-compose.yml
SCHEDULER_HEARTBEAT_TIMEOUT60Seconds after which a silent scheduler is considered deadSame as abovedocker-compose.yml
SCHEDULER_LOCK_TIMEOUT1800Seconds before the scheduler leadership lock expiresToo-low values can cause duplicate schedulers during long tasksdocker-compose.yml
SCHEDULER_METRICS_PORT9090Port for the scheduler metrics/health endpoint (healthcheck target)Container-internal; no host mappingdocker-compose.yml

Kubernetes (k8s/configmap.yaml)​

Declared by the Kubernetes manifests (see KUBERNETES.md); several overlap with the variables above.

VariableDefault (manifest)PurposeRotation impactSource
LOG_LEVELINFOApplication log levelNone; takes effect after restartk8s/configmap.yaml
AUDIT_LOG_RETENTION_DAYS90Audit log retention window (days)Shortening deletes older audit entries on the next cleanupk8s/configmap.yaml
DATA_RETENTION_DAYS365Data retention window (days) for cleanup jobsShortening deletes older retained data on the next cleanupk8s/configmap.yaml
DB_HOST / DB_PORTpostgres / 5432Database endpoint inside the clusterRestart requiredk8s/configmap.yaml
REDIS_HOST / REDIS_PORTredis / 6379Redis endpointRestart requiredk8s/configmap.yaml
ENABLE_SSO / ENABLE_MULTI_TENANT / ENABLE_AUDIT_LOG / ENABLE_CONTENT_FILTERtrueFeature flagsToggling enables/disables features after restartk8s/configmap.yaml
REDIS_PASSWORDplaceholderRedis password (secret; replace the placeholder before production)Must match the Redis deploymentk8s/configmap.yaml (Secret section)

Application-Level Variables (code)​

VariableDefaultPurposeRotation impactSource
OPENACE_PLATFORM_ADMIN_STRICT_MODEfalseWhen true, only explicit platform_admin role passes platform-admin checks; legacy admin no longer does (Issue #2332). Migrate existing role='admin' accounts to platform_admin FIRST, then enable and restart every process; each logs Platform admin strict mode: ENABLED at startupEnabling without migrating accounts locks legacy admins outapp/auth/permissions.py
OPENACE_ENCRYPTION_KEYSunsetJSON data-key registry: {"keys": [{"id": 1-255, "value": "...", "status": "active|deprecated|revoked"}, ...], "primary_key_id": N}; max 5 keys, exactly 1 active; takes precedence over OPENACE_ENCRYPTION_KEY; hot-reloaded roughly every 5 secondsKey changes re-bind new ciphertexts (v1k<id>: prefix); see KEY_MANAGEMENT.mdapp/utils/encryption_key_registry.py
OPENACE_CORS_ALLOWED_ORIGINSunsetComma-separated explicit API CORS allowlist for non-loopback WebUI originsTightening blocks requests from removed originsapp/__init__.py
OPENACE_WS_MAX_MESSAGE_BYTES8388608Maximum inbound browser WebSocket message size for the terminal / VSCode raw bridgesLower values reject large paste payloadsapp/ws_frame.py
OPENACE_TEST_MODEunset1 marks a CI/test context: skips production-level security checksNever enable in productionapp/utils/security_mode.py
OPENCLAW_TOKENunsetOpenClaw API token for data collectionRotation requires updating the collectorscripts/fetch_openclaw.py
OPENACE_REPLICA_ENDPOINTSunsetComma-separated replica endpoints queried for encryption-key config-version sync statusInformational only (sync dashboard)app/routes/encryption_keys.py

Auto-Generated Secrets​

For the single-user development path, missing secrets are not an error: docker-entrypoint.sh generates strong random values on first start and persists them to generated-secrets.env inside the config-data volume (/home/open-ace/.open-ace/generated-secrets.env); later restarts reuse them without rotating. Bare-metal development works the same via ~/.open-ace/generated-secrets.env (Issue #2667). Explicitly set values in .env always take precedence and are never written to that file. Production mode requires explicit secrets — see DEPLOYMENT.md.