Skip to main content
Version: v3.9.0

Controller configuration

src/config/config.yaml is the configuration file. src/config/env-mapping.js is the list of environment variables that override it. A variable that is not in that list is ignored by the loader. A YAML key that is not in that list can only be changed by editing the file.

The file that is loaded is CONFIG_PATH, or src/config/config.yaml when that variable is unset. CONFIG_PATH is not itself a config key.

How a value is chosen​

  1. The YAML file is the base. Keys under a # comment are not loaded.
  2. Each mapped environment variable is written on top of that base. The variable creates the key if the YAML block is commented out. VAULT_ENABLED=true creates vault.enabled even when the vault: block is commented.
  3. true, false, 1, and 0 become booleans. Any other numeric string becomes a number. Everything else stays a string. Because 1 and 0 are booleans, do not use them for a count or a port.
  4. OpenTelemetry is the exception. OTEL_* and ENABLE_TELEMETRY are not applied as overrides. If the variable is already set, it stays. If it is unset and the YAML value exists, Controller copies the YAML value into the process environment for the SDK.

DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_NAME, DB_USE_SSL, and DB_SSL_CA are not fixed paths. They write database.<provider>.<field>, where <provider> is database.provider (sqlite, mysql, or postgres). Set DB_PROVIDER to the same provider. On the default file that provider is sqlite, so DB_NAME updates database.sqlite.databaseName.

Application​

YAMLDefaultEnvironment variable
app.nameiofogCONTROLLER_NAME
app.uuidemptyCONTROLLER_UUID
app.controlPlaneRemoteCONTROL_PLANE
app.namespaceiofogCONTROLLER_NAMESPACE

app.controlPlane is Remote, Kubernetes, or Local. Kubernetes is the control plane that uses the operator-managed default router and NATS hub. Remote is the control plane where the first agent is the system node. See networking-topology-controlplane.md.

YAMLDefaultEnvironment variable
flavor.distributiondatasanceCONTROLLER_DISTRIBUTION
flavor.rbacApiVersiondatasance.com/v3RBAC_API_VERSION
flavor.serviceAnnotationTagservice.iofog.org/tagSERVICE_ANNOTATION_TAG
flavor.componentLabelDomainderivedCOMPONENT_LABEL_DOMAIN

flavor.componentLabelDomain is not set in the default file. When both the YAML key and COMPONENT_LABEL_DOMAIN are empty, the label is derived from the distribution: datasance.com/component for datasance, iofog.org/component for iofog. Any other distribution uses iofog.org/component.

APP_LABEL is read directly and is not in the mapping file. It overrides flavor.defaultAppLabelKey. The default is iofog.

Server​

YAMLDefaultEnvironment variable
server.port51121SERVER_PORT
server.devModetrueSERVER_DEV_MODE
server.publicUrlhttps://localhost:51121CONTROLLER_PUBLIC_URL
server.trustProxyfalseTRUST_PROXY

server.publicUrl is the external URL of this Controller. In production it must be https unless auth.insecureAllowHttp is true. server.trustProxy honors X-Forwarded-* when a reverse proxy sits in front.

TLS is commented out in the default file. Setting the variable creates the key.

YAMLEnvironment variable
server.tls.path.keyTLS_PATH_KEY
server.tls.path.certTLS_PATH_CERT
server.tls.path.intermediateCertTLS_PATH_INTERMEDIATE_CERT
server.tls.base64.keyTLS_BASE64_KEY
server.tls.base64.certTLS_BASE64_CERT
server.tls.base64.intermediateCertTLS_BASE64_INTERMEDIATE_CERT

Use either the path files or the base64 values.

WebSocket​

YAMLDefaultEnvironment variable
server.webSocket.pingInterval30000WS_PING_INTERVAL
server.webSocket.pongTimeout10000WS_PONG_TIMEOUT
server.webSocket.maxPayload1048576WS_MAX_PAYLOAD
server.webSocket.session.timeout3600000WS_SESSION_TIMEOUT
server.webSocket.session.maxConnections100WS_SESSION_MAX_CONNECTIONS
server.webSocket.session.cleanupInterval30000WS_CLEANUP_INTERVAL
server.webSocket.session.execPendingTimeoutMs60000WS_EXEC_PENDING_TIMEOUT_MS
server.webSocket.session.execMaxDurationMs28800000WS_EXEC_MAX_DURATION_MS
server.webSocket.session.execMaxConcurrentPerResource5WS_EXEC_MAX_CONCURRENT_PER_RESOURCE
server.webSocket.session.logPendingTimeoutMs120000WS_LOG_PENDING_TIMEOUT_MS
server.webSocket.session.logIdleTimeoutMs7200000WS_LOG_IDLE_TIMEOUT_MS
server.webSocket.session.logMaxConcurrentPerResource5WS_LOG_MAX_CONCURRENT_PER_RESOURCE
server.webSocket.session.logTailMaxLines5000WS_LOG_TAIL_MAX_LINES
server.webSocket.session.replicaMaxConcurrentWs500WS_REPLICA_MAX_CONCURRENT_WS
server.webSocket.session.drainTimeoutMs30000WS_DRAIN_TIMEOUT_MS
server.webSocket.ha.crossReplicaRequiresAmqptrueWS_HA_CROSS_REPLICA_REQUIRES_AMQP
server.webSocket.ha.failFastOnRouterUnavailabletrueWS_HA_FAIL_FAST_ON_ROUTER_UNAVAILABLE
server.webSocket.security.maxConnectionsPerIp10WS_SECURITY_MAX_CONNECTIONS_PER_IP
server.webSocket.security.maxRequestsPerMinute60WS_SECURITY_MAX_REQUESTS_PER_MINUTE
server.webSocket.security.maxPayload1048576WS_SECURITY_MAX_PAYLOAD

Durations on this table are milliseconds. execMaxDurationMs is 8 hours. logIdleTimeoutMs is 2 hours. session.timeout is the legacy idle fallback. Exec sessions use execMaxDurationMs.

These YAML keys have no environment variable:

YAMLDefaultMeaning
server.webSocket.perMessageDeflatefalsePer-message compression
server.webSocket.allowExtensionsfalseWebSocket extensions
server.webSocket.handshakeTimeout10000Handshake timeout, milliseconds
server.webSocket.maxFrameSize65536Maximum frame size, bytes
server.webSocket.relay.amqp.poolSize8AMQP relay pool
server.webSocket.relay.amqp.sendTimeoutMs5000AMQP send timeout
server.webSocket.relay.amqp.unsettledWarnThreshold1800Unsettled AMQP message warning
server.webSocket.relay.nats.maxPendingBytes33554432NATS relay pending bytes (32 MiB)
server.webSocket.relay.nats.maxPendingMessages8192NATS relay pending messages
server.webSocket.relay.nats.publishTimeoutMs5000NATS relay publish timeout

server.webSocket.ha.crossReplicaRequiresAmqp requires the router link before an exec or log session is handed to another replica. failFastOnRouterUnavailable fails that handoff when the router is down.

Console​

YAMLDefaultEnvironment variable
console.port8008CONSOLE_PORT
console.urlhttp://localhost:8008CONSOLE_URL

An empty console.url falls back to server.publicUrl.

Logging​

YAMLDefaultEnvironment variable
log.levelinfoLOG_LEVEL
log.directory/var/log/iofog-controllerLOG_DIRECTORY
log.fileSize1073741824LOG_FILE_SIZE
log.fileCount10LOG_FILE_COUNT

log.fileSize is bytes. The default is 1 GiB. log.fileCount is how many files are kept.

Settings​

Intervals below are seconds unless the name ends in Ms.

YAMLDefaultEnvironment variable
settings.fogStatusUpdateInterval30FOG_STATUS_UPDATE_INTERVAL
settings.fogStatusUpdateTolerance3FOG_STATUS_UPDATE_TOLERANCE
settings.fogStatusLivenessChunkSize50FOG_STATUS_LIVENESS_CHUNK_SIZE
settings.fogExpiredTokenCleanupInterval300FOG_EXPIRED_TOKEN_CLEANUP_INTERVAL
settings.eventRetentionDays7EVENT_RETENTION_DAYS
settings.eventCleanupInterval86400EVENT_CLEANUP_INTERVAL
settings.eventAuditEnabledtrueEVENT_AUDIT_ENABLED
settings.eventCaptureIpAddresstrueEVENT_CAPTURE_IP_ADDRESS
settings.controllerHeartbeatInterval30CONTROLLER_HEARTBEAT_INTERVAL
settings.controllerInactiveThreshold300CONTROLLER_INACTIVE_THRESHOLD
settings.controllerCleanupInterval600CONTROLLER_CLEANUP_INTERVAL
settings.fogPlatformReconcileWorkerIntervalSeconds3FOG_PLATFORM_RECONCILE_WORKER_INTERVAL_SECONDS
settings.fogPlatformReconcileTaskStalenessSeconds300FOG_PLATFORM_RECONCILE_TASK_STALENESS_SECONDS
settings.fogPlatformDeleteReconcileTaskStalenessSeconds60FOG_PLATFORM_DELETE_RECONCILE_TASK_STALENESS_SECONDS
settings.fogPlatformReconcileMaxAttempts10FOG_PLATFORM_RECONCILE_MAX_ATTEMPTS
settings.fogPlatformReconcileBackoffBaseSeconds5FOG_PLATFORM_RECONCILE_BACKOFF_BASE_SECONDS
settings.fogPlatformSweepIntervalSeconds900FOG_PLATFORM_SWEEP_INTERVAL_SECONDS
settings.servicePlatformReconcileMaxAttempts10SERVICE_PLATFORM_RECONCILE_MAX_ATTEMPTS
settings.hubRouterConfigLockTimeoutSeconds120HUB_ROUTER_CONFIG_LOCK_TIMEOUT_SECONDS
settings.serviceLoadBalancerWatchTimeoutSeconds300SERVICE_LOAD_BALANCER_WATCH_TIMEOUT_SECONDS
settings.jobStartupDelaySeconds3JOB_STARTUP_DELAY_SECONDS
settings.reconcileOutboxDrainerIntervalSeconds1RECONCILE_OUTBOX_DRAINER_INTERVAL_SECONDS
settings.reconcileOutboxDrainerBatchSize32RECONCILE_OUTBOX_DRAINER_BATCH_SIZE
settings.agentPropagationFogNotifyBatchSize100AGENT_PROPAGATION_FOG_NOTIFY_BATCH_SIZE
settings.wsSessionReconcileIntervalSeconds60WS_SESSION_RECONCILE_INTERVAL_SECONDS
settings.sqliteEnterpriseFogWarningThreshold50SQLITE_ENTERPRISE_FOG_WARNING_THRESHOLD
settings.dbWriteQueueMaxDepth256DB_WRITE_QUEUE_MAX_DEPTH
settings.dbWriteQueueBackpressureDepth32DB_WRITE_QUEUE_BACKPRESSURE_DEPTH
settings.dbTransactionTimeoutReadinessMs5000DB_TRANSACTION_TIMEOUT_READINESS_MS
settings.dbTransactionTimeoutInteractiveMs15000DB_TRANSACTION_TIMEOUT_INTERACTIVE_MS
settings.dbTransactionTimeoutBackgroundMs120000DB_TRANSACTION_TIMEOUT_BACKGROUND_MS
settings.dbBusyRetryMaxAttempts8DB_BUSY_RETRY_MAX_ATTEMPTS
settings.dbBusyRetryBaseMs25DB_BUSY_RETRY_BASE_MS

eventCaptureIpAddress set to false stops storing client addresses on audit events. controllerInactiveThreshold is how long a Controller replica can miss heartbeats before it is inactive (5 minutes). hubRouterConfigLockTimeoutSeconds is how long a replica waits for the Kubernetes router ConfigMap lock. sqliteEnterpriseFogWarningThreshold logs when a sqlite deployment has more agents than this. The dbWriteQueue* and dbTransaction* and dbBusyRetry* keys apply to sqlite.

These YAML keys have no environment variable:

YAMLDefaultMeaning
settings.natsReconcileChunkSize1Agents handled in one NATS reconcile task
settings.natsReconcileTaskStalenessSeconds900When a stuck NATS reconcile task can be reclaimed
settings.natsReconcileWorkerIntervalSeconds3How often the NATS reconcile worker polls

settings.defaultJobInterval is commented out and has no environment variable. It is not loaded.

Database​

YAMLDefaultEnvironment variable
database.providersqliteDB_PROVIDER

DB_PROVIDER is sqlite, mysql, or postgres. The six variables below land on that provider's section.

Environment variableField under database.<provider>MySQL / Postgres comment in the file
DB_HOSThostempty
DB_PORTport3306 / 5432
DB_USERNAMEusernameempty
DB_PASSWORDpasswordempty
DB_NAMEdatabaseNameempty; sqlite default is controller_db.sqlite
DB_USE_SSLuseSSLfalse
DB_SSL_CAsslCAempty. Base64 CA

MySQL and Postgres host, port, username, password, databaseName, useSSL, and sslCA are commented out, so they exist only after you uncomment them or set DB_*. Pool sizes are active and have no environment variable.

YAMLDefault
database.mysql.pool.max10
database.mysql.pool.min0
database.mysql.pool.idle20000
database.postgres.pool.max10
database.postgres.pool.min0
database.postgres.pool.idle20000
database.sqlite.loggingfalse
database.sqlite.transactionTypeIMMEDIATE
database.sqlite.pragmas.journalModeWAL
database.sqlite.pragmas.busyTimeoutMs10000
database.sqlite.pragmas.synchronousNORMAL
database.sqlite.pool.maxActive1
database.sqlite.pool.max1
database.sqlite.pool.min0
database.sqlite.pool.idle20000

pool.idle is milliseconds. Sqlite keeps one active connection. The write queue and busy-retry settings in the previous section sit in front of that connection.

Auth​

The auth block in the default file only activates mode, insecureAllowHttp, and insecureAllowBootstrapLog. Every other auth key below is commented out and is created when you uncomment it or set the variable.

YAMLDefault when setEnvironment variable
auth.modeembeddedAUTH_MODE
auth.insecureAllowHttpfalseAUTH_INSECURE_ALLOW_HTTP
auth.insecureAllowBootstrapLogfalseAUTH_INSECURE_ALLOW_BOOTSTRAP_LOG
auth.bootstrap.usernameemptyOIDC_BOOTSTRAP_ADMIN_USERNAME
auth.bootstrap.passwordemptyOIDC_BOOTSTRAP_ADMIN_PASSWORD
auth.issuerUrlemptyOIDC_ISSUER_URL
auth.client.idemptyOIDC_CLIENT_ID
auth.client.secretemptyOIDC_CLIENT_SECRET
auth.consoleClientemptyOIDC_CONSOLE_CLIENT_ID
auth.consoleClient.enabledAUTH_CONSOLE_CLIENT_ENABLED
auth.rateLimit.enabledtrueAUTH_RATE_LIMIT_ENABLED
auth.rateLimit.maxRequestsPerWindow60AUTH_RATE_LIMIT_MAX_REQUESTS
auth.rateLimit.windowMs60000AUTH_RATE_LIMIT_WINDOW_MS
auth.sessionStore.typememoryAUTH_SESSION_STORE_TYPE
auth.sessionStore.ttlMs600000AUTH_SESSION_STORE_TTL_MS
auth.sessionStore.secretemptyAUTH_SESSION_SECRET
auth.tokenTtl.accessTokenTtlSeconds900AUTH_ACCESS_TOKEN_TTL_SECONDS
auth.tokenTtl.refreshTokenTtlSeconds3600AUTH_REFRESH_TOKEN_TTL_SECONDS
auth.oidcTtl.interactionTtlSecondssession TTL in secondsAUTH_OIDC_INTERACTION_TTL_SECONDS
auth.oidcTtl.grantTtlSecondsinteraction TTLAUTH_OIDC_GRANT_TTL_SECONDS
auth.oidcTtl.sessionTtlSecondsrefresh-token TTLAUTH_OIDC_SESSION_TTL_SECONDS
auth.oidcTtl.idTokenTtlSecondsaccess-token TTLAUTH_OIDC_ID_TOKEN_TTL_SECONDS

auth.mode is embedded or external. External mode uses auth.issuerUrl, auth.client.id, and auth.client.secret. Embedded mode runs the issuer inside Controller. The bootstrap username and password create the first admin. auth.insecureAllowHttp allows an http public URL in production. auth.insecureAllowBootstrapLog allows the bootstrap password path to be logged in production.

OIDC_CONSOLE_CLIENT_ID sets auth.consoleClient to the console client id string. The console client id is also read from auth.consoleClient.id when that key is an object. AUTH_CONSOLE_CLIENT_ENABLED sets auth.consoleClient.enabled and defaults to false when unset. Set the enabled flag when the console client should be registered. The id falls back to ecn-viewer when nothing is configured.

auth.sessionStore.type is memory or database. When it is unset, mysql and postgres use database and sqlite uses memory. An empty auth.sessionStore.secret is generated and stored. auth.rateLimit.windowMs is the per-IP window for auth endpoints.

Token TTL values must be positive seconds. When an auth.oidcTtl.* value is omitted, it uses the fallback in the table: interaction TTL is the session-store TTL converted to seconds, grant TTL copies interaction TTL, session TTL copies the refresh-token TTL, and id-token TTL copies the access-token TTL. The policy defaults under those overrides are 900 seconds for access tokens and 3600 seconds for refresh tokens.

OIDC_COOKIE_KEYS is read directly and is not in the mapping file. It overrides auth.cookieKeys. A string is split on commas. The default is a single built-in key.

Bridge ports and system images​

YAMLDefaultEnvironment variable
bridgePorts.range10024-65535BRIDGE_PORTS_RANGE

This is the inclusive range Controller assigns to a Service bridgePort. Keep it a string (10024-65535). A bare number is stored as a number and is not a range.

System images are selected by architecture id:

IdArchitecture
1amd64 / x86
2arm64
3riscv64
4arm

The default image for every id is ghcr.io/eclipse-iofog/router:latest, ghcr.io/eclipse-iofog/debugger:latest, or ghcr.io/eclipse-iofog/nats:latest.

YAMLEnvironment variable
systemImages.router.1ROUTER_IMAGE_1
systemImages.router.2ROUTER_IMAGE_2
systemImages.router.3ROUTER_IMAGE_3
systemImages.router.4ROUTER_IMAGE_4
systemImages.debug.1DEBUG_IMAGE_1
systemImages.debug.2DEBUG_IMAGE_2
systemImages.debug.3DEBUG_IMAGE_3
systemImages.debug.4DEBUG_IMAGE_4
systemImages.nats.1NATS_IMAGE_1
systemImages.nats.2NATS_IMAGE_2
systemImages.nats.3NATS_IMAGE_3
systemImages.nats.4NATS_IMAGE_4

NATS​

YAMLDefaultEnvironment variable
nats.enabledtrueNATS_ENABLED

This switch is the Controller NATS relay. It does not turn off the per-agent NATS system microservice. Agent brokers are created from natsMode on the agent. See networking-topology-messaging-fabric.md.

Vault​

The whole vault: block is commented out. These variables create it.

YAMLDefault in the commentEnvironment variable
vault.enabledfalseVAULT_ENABLED
vault.providerhashicorpVAULT_PROVIDER
vault.basePathpot/$namespace/secretsVAULT_BASE_PATH
vault.hashicorp.addresshttp://localhost:8200VAULT_HASHICORP_ADDRESS
vault.hashicorp.tokenemptyVAULT_HASHICORP_TOKEN
vault.hashicorp.mountkvVAULT_HASHICORP_MOUNT
vault.aws.regionus-east-1VAULT_AWS_REGION
vault.aws.accessKeyIdemptyVAULT_AWS_ACCESS_KEY_ID
vault.aws.accessKeyemptyVAULT_AWS_ACCESS_KEY
vault.azure.urlhttps://your-vault.vault.azure.netVAULT_AZURE_URL
vault.azure.tenantIdemptyVAULT_AZURE_TENANT_ID
vault.azure.clientIdemptyVAULT_AZURE_CLIENT_ID
vault.azure.clientSecretemptyVAULT_AZURE_CLIENT_SECRET
vault.google.projectIdemptyVAULT_GOOGLE_PROJECT_ID
vault.google.credentialsemptyVAULT_GOOGLE_CREDENTIALS

vault.provider is hashicorp, openbao, vault, aws, aws-secrets-manager, azure, azure-key-vault, google, or google-secret-manager. $namespace in vault.basePath is replaced with app.namespace. When vault is enabled, secrets and private keys go to the provider instead of the encrypted database columns.

The vault client also accepts these variables directly. They are not in the mapping file, so they do not change the YAML tree. They are fallbacks when the mapped variable and the YAML key are both empty:

FallbackUsed when this mapped variable is empty
AWS_REGIONVAULT_AWS_REGION
AWS_ACCESS_KEY_IDVAULT_AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEYVAULT_AWS_ACCESS_KEY
AZURE_TENANT_IDVAULT_AZURE_TENANT_ID
AZURE_CLIENT_IDVAULT_AZURE_CLIENT_ID
AZURE_CLIENT_SECRETVAULT_AZURE_CLIENT_SECRET
GOOGLE_APPLICATION_CREDENTIALSVAULT_GOOGLE_CREDENTIALS

AWS region must look like us-east-1. If an access key id is set, the secret key is required, and the reverse. Azure service-principal auth requires tenant id, client id, and client secret together. vault.google.projectId is required for Google Secret Manager. vault.google.credentials is a path to the service-account key file.

OpenTelemetry​

The whole otel: block is commented out. Unlike every other section, a set OTEL_* or ENABLE_TELEMETRY variable is kept and is not overwritten from YAML. An unset variable is filled from YAML when that key is present.

YAMLDefault in the commentEnvironment variable
otel.enabledfalseENABLE_TELEMETRY
otel.serviceNamepot-controllerOTEL_SERVICE_NAME
otel.endpointhttp://localhost:4318/v1/tracesOTEL_EXPORTER_OTLP_ENDPOINT
otel.protocolhttp/protobufOTEL_EXPORTER_OTLP_PROTOCOL
otel.headersemptyOTEL_EXPORTER_OTLP_HEADERS
otel.resourceAttributesservice.version=3.5.0,deployment.environment=production,team=devopsOTEL_RESOURCE_ATTRIBUTES
otel.metrics.exporterotlpOTEL_METRICS_EXPORTER
otel.metrics.interval1000OTEL_METRICS_INTERVAL
otel.logs.levelinfoOTEL_LOG_LEVEL
otel.propagatorstracecontext,baggageOTEL_PROPAGATORS
otel.traces.samplerparentbased_traceidratioOTEL_TRACES_SAMPLER
otel.traces.samplerArg0.1OTEL_TRACES_SAMPLER_ARG
otel.batch.size512OTEL_BATCH_SIZE
otel.batch.delay1000OTEL_BATCH_DELAY

otel.protocol is grpc or http/protobuf. otel.metrics.interval and otel.batch.delay are milliseconds. otel.headers is the header list applied to outgoing traces, metrics, and logs. otel.resourceAttributes is a comma-separated key=value list.