Skip to content

Configuration reference

Environment files contain production secrets

Keep .env.prod mode 0600, outside version control, and accessible only to the owning host administrators. Share individual cross-host values through a protected channel, never by copying the whole file.

Use .env.prod.example as the production key inventory. Create .env.prod with scripts/generate-production-env.sh or copy the template, keep it mode 0600, and never commit it. A variable is required only on hosts running its owning profile.

Runtime product policy is not an environment variable. Manage it through Platform settings.

Control plane

VariableRequiredMeaning and default
APP_KEYcontrolLaravel encryption key; required, retained with backups
EDGE_ARTIFACT_SIGNING_KEYcontrolIndependent high-entropy Ed25519 signing seed
APP_URLcontrolCanonical public control-panel URL
SESSION_SECURE_COOKIEHTTPS controlSecure-cookie flag; production default true
CONTROL_BINDcontrolHost publication for web; default 127.0.0.1:8080
CONTROL_HOSTNAMEcontrolPublic browser/API hostname in independent management DNS
TELEMETRY_HOSTNAMEcontrol/telemetryPublic telemetry-ingest hostname in independent management DNS
CONTROL_PUBLIC_IPV4_ALLOWLISTDNS API gatewayExact control/worker sources allowed to call PowerDNS
CONTROL_PUBLIC_IPV6_ALLOWLISTDNS API gatewayOptional IPv6 control/worker sources allowed to call PowerDNS
EDGE_PUBLIC_IPV6_ALLOWLISTtelemetry gatewayOptional IPv6 edge sources allowed to submit telemetry
LOG_SOURCE_IPV6_ALLOWLISTtelemetry gatewayOptional IPv6 node sources allowed to submit operational logs
EDGE_PUBLIC_IPV4_ALLOWLISTtelemetry gatewayExact edge/Vector ingestion sources
CONTROL_DB_PASSWORDlocal control DBPostgreSQL password for database cdnf
REDIS_PASSWORDlocal ValkeyRequired Valkey password
DB_URLexternal DBFull PostgreSQL URL; empty uses individual DB fields
DB_HOSTcontrolDefault control-db
DB_PORTcontrolDefault 5432
DB_SSLMODEcontrolDefault prefer; use verified TLS across hosts
REDIS_URLexternal ValkeyFull URL; empty uses host and port
REDIS_HOSTcontrolDefault redis
REDIS_PORTcontrolDefault 6379
METRICS_TOKEN_FILEcontrol/telemetryAbsolute root:www-data mode-0640 bearer-token file shared with Prometheus group 82

The Compose file fixes APP_ENV=production, APP_DEBUG=false, DB_CONNECTION=pgsql, database/user cdnf, CACHE_STORE=redis, SESSION_DRIVER=redis, QUEUE_CONNECTION=redis, REDIS_CLIENT=predis, CLICKHOUSE_DATABASE=cdnf, CLICKHOUSE_USER=cdnf, and GEOIP_DATABASE=/mmdb/GeoLite2-City.mmdb.

Backup (optional)

Leave RESTIC_REPOSITORY, RESTIC_PASSWORD_FILE, and both credential values empty to disable the built-in backup integration. The control plane still starts, while backup creation returns an explicit unavailable error and backup health remains degraded. The supported generator path uses S3-compatible object storage; other Restic backends need their own credential/mount wiring.

VariableRequiredMeaning and default
RESTIC_REPOSITORYoptional controlRestic storage location, such as s3:https://endpoint/bucket/prefix; empty disables built-in backups
RESTIC_PASSWORD_FILEconfigured backupAbsolute file containing the separate Restic encryption password
BACKUP_ACCESS_KEY_IDconfigured S3 backupBucket/prefix-scoped access key
BACKUP_SECRET_ACCESS_KEYconfigured S3 backupBucket/prefix-scoped secret
BACKUP_DEFAULT_REGIONS3 repositoryDefault us-east-1
BACKUP_RESTORE_ALLOWEDrestore executorMust be true in explicit maintenance context; default false

Managed TLS

VariableRequiredMeaning and default
ACME_ENABLEDcontrolCompose sets true
ACME_CONTACT_EMAILcontrolACME account contact
ACME_DIRECTORY_URLcontrolLet's Encrypt production directory by default
ACME_ORDER_BUDGET_PER_HOURcontrolNew-order ceiling; default 20
ACME_VERIFY_TLSoptionalVerify ACME directory TLS; default true, false only for local Pebble
ACME_RENEW_BEFORE_DAYSoptionalRenewal window; default 30
ACME_DNS_TTLoptionalChallenge TTL; default 60
ACME_CHALLENGE_LIFETIME_MINUTESoptionalChallenge expiry; default 120
ACME_INITIAL_JITTER_SECONDSoptionalInitial spread; default 300
TLS_EXPIRY_ALERT_DAYSoptionalAdministrator expiry warning; default 14

Managed WAF

VariableRequiredMeaning and default
WAF_RULESET_VERSIONoptional control-plane labelImmutable WAF runtime identifier recorded in signed snapshots and telemetry; default owasp-crs/4.26.0-modsecurity/3.0.14. Change it only with the matching pinned edge image rollout.

Authoritative DNS

VariableRequiredMeaning and default
PDNS_DB_PASSWORDDNSPowerDNS PostgreSQL password
PDNS_API_KEYDNSPrivate PowerDNS API credential
DNS_BIND_V4DNSDNSdist IPv4 publication; default 0.0.0.0
PDNS_CA_CERTIFICATEcontrol workerTrust anchor for HTTPS PowerDNS API gateways
EDGE_GATEWAY_BINDINGSedge agentOptional rollout override. When absent, the agent fetches the bounded, revisioned edge/pool endpoint candidate over mTLS; when set, this static JSON remains authoritative.
EDGE_CELL_TARGETSedge agentOptional development-only JSON map from stable cell names to private container HTTP/HTTPS endpoints; production host-network cells use control-plane loopback targets
EDGE_GATEWAY_ADDRESSESedge agentOptional development-only JSON array of at most two gateway listener IPs; never set in production
EDGE_GATEWAY_ADDRESS_MAPproduction edge agentOptional JSON object translating advertised service IPv4/IPv6 addresses to private local listeners for NAT/load-balancer hosts. Directly assigned public addresses bind without a map. Both sides use the same family; wildcard, public-to-different-public, and duplicate local values fail closed. Default {}.
EDGE_GATEWAY_REQUIRE_ADDRESS_MAPproduction edge agentSet true only when local policy requires every fetched endpoint to have an explicit translation before activation. Default false.
EDGE_GATEWAY_STATUS_URLedge agentGateway metrics URL used for heartbeat readiness
EDGE_GATEWAY_METRICS_ADDRESSedge gatewayRestricted metrics listener; production default 0.0.0.0:9105
EDGE_GATEWAY_MAX_CONNECTIONSedge gatewayGlobal accepted-connection bound, 12865536 (default 8192)
DNS_API_HOSTNAMEDNSDNS API TLS hostname in independent management DNS
DNS_API_SERVER_CERTIFICATEDNSAbsolute server certificate path
DNS_API_SERVER_PRIVATE_KEYDNSAbsolute mode-0600 key path

Telemetry and GeoIP

VariableRequiredMeaning and default
CLICKHOUSE_PASSWORDtelemetry/control queryClickHouse password
CLICKHOUSE_URLtelemetry/control queryLocal http://clickhouse:8123 or verified external endpoint
CLICKHOUSE_DATABASEinternal/defaultDatabase queried by Laravel; Compose fixes cdnf
GEOIP_DATABASEedge runtimeMMDB file path; Compose fixes /mmdb/GeoLite2-City.mmdb
PROMETHEUS_URLoptional controlDefault http://prometheus:9090
VECTOR_METRICS_URLoptional controlVector metrics probe URL when overridden
METRICS_TOKENoptional controlDirect metrics bearer token fallback; prefer METRICS_TOKEN_FILE
MMDB_STALE_HOURSoptional controlHealth threshold; default 48
MMDB_PROVIDERupdaterdbip-jsdelivr default, dbip-official, ip66, or generic
MMDB_TARGET_FILEupdaterDefault GeoLite2-City.mmdb
MMDB_DOWNLOAD_INTERVAL_SECONDSupdaterDefault 86400, clamped to at least 300
MMDB_DOWNLOAD_RETRIESupdaterDefault 5
MMDB_EXPECTED_SHA256updaterOptional lowercase candidate checksum
MMDB_DOWNLOAD_URLcustom updaterHTTPS artifact URL
MMDB_DOWNLOAD_HEADERcustom updaterOptional authorization header; treat as secret

Grafana telemetry variables are:

VariableRequiredMeaning and default
GRAFANA_ADMIN_USERtelemetryInitial administrator name; default admin
GRAFANA_ADMIN_PASSWORDtelemetryHigh-entropy administrator password; no production default
GRAFANA_BINDtelemetryHost bind; default 127.0.0.1:3000
GRAFANA_COOKIE_SECUREHTTPS telemetrySecure-cookie flag; default true
GRAFANA_CLICKHOUSE_PASSWORDtelemetryDedicated read-only ClickHouse password; no default
GRAFANA_CLICKHOUSE_HOST, GRAFANA_CLICKHOUSE_PORTtelemetryLocal clickhouse:9000 or external query endpoint
GRAFANA_CLICKHOUSE_PROTOCOL, GRAFANA_CLICKHOUSE_SECUREtelemetrynative/false locally; use provider-supported verified TLS externally
GRAFANA_CLICKHOUSE_USERtelemetryDefault cdnf_grafana
GRAFANA_POSTGRES_PASSWORDtelemetryDedicated read-only PostgreSQL password; no default
GRAFANA_POSTGRES_HOST, GRAFANA_POSTGRES_PORTtelemetryLocal control-db:5432 or external endpoint
GRAFANA_POSTGRES_DATABASE, GRAFANA_POSTGRES_USERtelemetryDefaults cdnf, cdnf_grafana
GRAFANA_POSTGRES_SSLMODEtelemetryDefault disable for embedded private PostgreSQL; set require or verify-full for external endpoints
GRAFANA_POSTGRES_PROVISION_HOST, GRAFANA_POSTGRES_PROVISION_PORTlocal account provisioningPrivileged endpoint; external operators may apply the SQL separately
PROMETHEUS_EDGE_TARGETS_FILEtelemetryPrivate file_sd target file; production default is empty
PROMETHEUS_LOG_TARGETS_FILEtelemetryPrivate file_sd targets for remote collector metrics; production default is empty
PROMETHEUS_CONTROL_TARGETS_FILEtelemetryGenerated file_sd targets for authenticated control-plane metrics
PROMETHEUS_NODE_TARGETS_FILEtelemetryGenerated file_sd targets for node-exporter metrics on every fleet host
PROMETHEUS_DNS_TARGETS_FILEtelemetryGenerated file_sd targets for DNSdist metrics on DNS hosts
GRAFANA_EXPLORE_URLcontrolOptional deployment fallback for the admin-only Live Logs link. The PostgreSQL-backed Platform settings → Observability links → Grafana Explore URL overrides it. Laravel supplies Loki, a safe selector, and a one-hour range when the chosen URL has no query; both empty hides the link
GRAFANA_HOSTNAMEcontrol/telemetryPublic Grafana hostname in the independently hosted operator DNS zone
GRAFANA_LOKI_URLtelemetryPrivate Grafana-to-Loki endpoint; default http://loki:3100
LOKI_RETENTION_PERIODtelemetryLoki retention; production default 336h
LOKI_MAX_QUERY_LENGTHtelemetryMaximum query range; production default 336h
LOKI_ENDPOINTlogsCollector push endpoint; use the source-restricted HTTPS telemetry gateway off-host
LOG_ROLElogsStable host role: control, dns, edge, or telemetry
LOG_HOSTlogsStable deployment host name
LOG_COLLECTOR_IDlogsGlobally unique stable collector identity
LOG_AUTH_TOKENlogsSecret bearer credential used by the per-host Vector collector when pushing to the source-restricted Loki gateway
LOG_BUFFER_BYTESlogsPer-host disk-buffer bytes; production default 2147483648
LOG_METRICS_BINDlogsHost metrics publication; generated bundles use monitor_ipv4 or the local bind_ipv4, never an advertised NAT-only address
LOG_SOURCE_IPV4_ALLOWLISTtelemetry gatewayExact non-edge host sources allowed to push logs

Vector receives CLICKHOUSE_ENDPOINT, CLICKHOUSE_USER, and CLICKHOUSE_PASSWORD from Compose. MMDB_DIR is an internal updater override whose default is /mmdb.

Laravel containers fix LOG_CHANNEL=stderr, LOG_STACK=stderr, and the allowlisting JSON formatter. Changing these back to a private file would bypass the supported host collector.

Images and host publication

VariableRequiredMeaning and default
CDNF_RELEASEevery production hostExact commit SHA or exact release tag
CDNF_CORE_IMAGEproduction control/edge supportImmutable core image reference from the release manifest
CDNF_WEB_IMAGEproduction controlImmutable web image reference from the release manifest
CDNF_EDGE_CONTROL_IMAGEproduction controlImmutable edge-control ingress image reference from the release manifest
CDNF_EDGE_RUNTIME_IMAGEproduction edgeImmutable OpenResty runtime image reference from the release manifest
CDNF_EDGE_AGENT_IMAGEproduction edgeImmutable edge-agent image reference from the release manifest
CDNF_EDGE_GATEWAY_IMAGEproduction edgeImmutable edge-gateway image reference from the release manifest
CDNF_MMDB_UPDATER_IMAGEproduction hosts using GeoIPImmutable MMDB updater image reference from the release manifest
CDNF_GRAFANA_IMAGEproduction telemetryImmutable provisioned Grafana image reference from the release manifest
CDNF_LOKI_IMAGEproduction telemetryImmutable Loki image reference from the release manifest
HOST_BIND_IPV4generated multi-host bundleLocal listener address; default 0.0.0.0, independent of public/NAT DNS addresses
HOST_BIND_IPV6generated dual-stack bundleLocal IPv6 listener; default ::; publish only after end-to-end IPv6 qualification
EDGE_QUARANTINE_HTTP_BINDedgeQuarantine HTTP, default 127.0.0.1:18080
EDGE_QUARANTINE_HTTPS_BINDedgeQuarantine HTTPS, default 127.0.0.1:18443
EDGE_RUNTIME_TLS_CERTIFICATEedgeBootstrap listener certificate path
EDGE_RUNTIME_TLS_PRIVATE_KEYedgeBootstrap listener key path

Edge control and identity

VariableRequiredMeaning and default
EDGE_CONTROL_URLedge agentPublic mutual-TLS control URL
EDGE_CONTROL_BINDcontrolListener publication, default 0.0.0.0:8443
EDGE_CONTROL_SERVER_CERTIFICATEcontrolEdge-control server certificate path
EDGE_CONTROL_SERVER_PRIVATE_KEYcontrolEdge-control private key path
EDGE_CONTROL_CA_CERTIFICATEedge agentServer trust anchor
EDGE_IDENTITY_CA_CERTIFICATEcontrol/edge-controlClient identity CA certificate
EDGE_IDENTITY_CA_PRIVATE_KEYcoreRestricted worker-readable CA key
EDGE_IDENTITY_CA_PRIVATE_KEY_PASSPHRASEoptional coreCA-key passphrase
EDGE_STATUS_TOKENedge hostSeparate agent-to-cell control token
EDGE_IDfirst enrollmentAdministrator-created edge UUID
EDGE_BOOTSTRAP_TOKENfirst enrollmentOne-time secret; spent after successful identity issuance

The edge-agent binary also accepts these internal variables:

VariableDefaultPurpose
EDGE_STATE_DIR/var/lib/cdnfoundry/agentPersistent identity, state, controls, acknowledgements
EDGE_RUNTIME_DIRemptyActive and previous compiled runtime directories
EDGE_CELL_STATUS_URLSemptyComma-separated internal cell endpoints
EDGE_CELL_ASSIGNMENTS{}JSON object mapping at most 32 stable cell-NN names to a pool name or an empty unassigned value
EDGE_RUNTIME_VERSIONS{}JSON object containing the four immutable gateway, agent, normal-cell, and WAF-cell image digests reported after a fixed installer upgrade
EDGE_ONCEfalseRun one sync cycle for diagnostics

Production fixes EDGE_CELL_ASSIGNMENTS to eight stable slots. The OpenResty container receives EDGE_CELL_NAME, EDGE_RUNTIME_FILE, and EDGE_STATUS_TOKEN from Compose. These describe a cell and are not customer settings.

Development-only environment

.env.dev supports:

VariablePurpose
CDNF_DEV_EDGE_A_ID, CDNF_DEV_EDGE_B_IDCreated edge UUIDs
CDNF_DEV_EDGE_A_BOOTSTRAP_TOKEN, CDNF_DEV_EDGE_B_BOOTSTRAP_TOKENOne-time tokens
CDNF_DEV_EDGE_STATUS_TOKENShared development agent/cell token
CDNF_DEV_EDGE_CONTROL_BINDOptional host override for port 9443
POWERADMIN_ADMIN_USERNAMEPowerAdmin diagnostic login; default admin
POWERADMIN_ADMIN_PASSWORDPowerAdmin diagnostic password; development-only default

The development Compose file contains public test credentials. Never copy them to production.

Documentation build

VariableDefaultPurpose
DOCS_SITE_URLhttps://vaheed.github.io/CDNFoundryCanonical and sitemap origin
DOCS_BASE/CDNFoundry/VitePress deployment base path

Set both when deploying the static site under a different origin or path.

Laravel framework variables

The application retains conventional Laravel configuration keys in core/config/: APP_NAME, APP_ENV, APP_KEY, APP_DEBUG, APP_URL, APP_LOCALE, APP_FALLBACK_LOCALE, APP_FAKER_LOCALE, APP_PREVIOUS_KEYS, APP_MAINTENANCE_DRIVER, and APP_MAINTENANCE_STORE.

Database drivers additionally accept DB_CONNECTION, DB_URL, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD, DB_SOCKET, DB_CHARSET, DB_COLLATION, DB_FOREIGN_KEYS, DB_ENCRYPT, DB_TRUST_SERVER_CERTIFICATE, DB_CONNECT_TIMEOUT, MYSQL_ATTR_SSL_CA, and the documented DB_SSLMODE.

Cache, queue, Redis, and session drivers accept their standard keys: CACHE_STORE, CACHE_PREFIX, DB_CACHE_CONNECTION, DB_CACHE_TABLE, DB_CACHE_LOCK_CONNECTION, DB_CACHE_LOCK_TABLE, DYNAMODB_CACHE_TABLE, DYNAMODB_ENDPOINT, MEMCACHED_HOST, MEMCACHED_PORT, MEMCACHED_USERNAME, MEMCACHED_PASSWORD, MEMCACHED_PERSISTENT_ID, QUEUE_CONNECTION, QUEUE_FAILED_DRIVER, DB_QUEUE_CONNECTION, DB_QUEUE_TABLE, DB_QUEUE, DB_QUEUE_RETRY_AFTER, BEANSTALKD_QUEUE_HOST, BEANSTALKD_QUEUE, BEANSTALKD_QUEUE_RETRY_AFTER, SQS_PREFIX, SQS_QUEUE, SQS_SUFFIX, REDIS_CLIENT, REDIS_URL, REDIS_HOST, REDIS_USERNAME, REDIS_PASSWORD, REDIS_PORT, REDIS_DB, REDIS_CACHE_DB, REDIS_PREFIX, REDIS_PERSISTENT, REDIS_CLUSTER, REDIS_MAX_RETRIES, REDIS_BACKOFF_ALGORITHM, REDIS_BACKOFF_BASE, REDIS_BACKOFF_CAP, REDIS_CONNECT_TIMEOUT, REDIS_READ_TIMEOUT, REDIS_QUEUE_CONNECTION, REDIS_QUEUE, REDIS_QUEUE_RETRY_AFTER, REDIS_CACHE_CONNECTION, REDIS_CACHE_LOCK_CONNECTION, SESSION_DRIVER, SESSION_LIFETIME, SESSION_EXPIRE_ON_CLOSE, SESSION_ENCRYPT, SESSION_PATH, SESSION_DOMAIN, SESSION_SECURE_COOKIE, SESSION_HTTP_ONLY, SESSION_SAME_SITE, SESSION_PARTITIONED_COOKIE, SESSION_CONNECTION, SESSION_TABLE, and SESSION_STORE.

Mail/logging/storage/auth integrations retain the keys declared in their Laravel config files: FILESYSTEM_DISK, CACHE_STORAGE_DISK, CACHE_STORAGE_PATH, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, AWS_BUCKET, AWS_URL, AWS_ENDPOINT, AWS_USE_PATH_STYLE_ENDPOINT, MAIL_MAILER, MAIL_URL, MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_PASSWORD, MAIL_SCHEME, MAIL_SENDMAIL_PATH, MAIL_EHLO_DOMAIN, MAIL_FROM_ADDRESS, MAIL_FROM_NAME, MAIL_LOG_CHANNEL, POSTMARK_API_KEY, POSTMARK_MESSAGE_STREAM_ID, RESEND_API_KEY, SLACK_BOT_USER_OAUTH_TOKEN, SLACK_BOT_USER_DEFAULT_CHANNEL, LOG_CHANNEL, LOG_STACK, LOG_LEVEL, LOG_DAILY_DAYS, LOG_DEPRECATIONS_CHANNEL, LOG_DEPRECATIONS_TRACE, LOG_STDERR_FORMATTER, LOG_SYSLOG_FACILITY, PAPERTRAIL_URL, PAPERTRAIL_PORT, LOG_PAPERTRAIL_HANDLER, LOG_SLACK_WEBHOOK_URL, LOG_SLACK_USERNAME, LOG_SLACK_EMOJI, AUTH_GUARD, AUTH_MODEL, AUTH_PASSWORD_BROKER, AUTH_PASSWORD_RESET_TOKEN_TABLE, AUTH_PASSWORD_TIMEOUT, SANCTUM_STATEFUL_DOMAINS, and SANCTUM_TOKEN_PREFIX.

Horizon accepts HORIZON_NAME, HORIZON_DOMAIN, and HORIZON_PATH. Production Compose intentionally fixes the supported drivers and does not expose most framework alternatives in .env.prod.example.

CDNFoundry documentation