Skip to content

Environment Variables Explained ​

IoT DC3 has two separate sets of environment files, and they target different consumers. The root .env feeds Docker Compose interpolation; dc3/env/dev.env(.sh) feeds local Java processes. By the end of this page you'll know which variable belongs in which file, why localhost ports differ from the ports a container sees, and which two secrets you must change before going to production.

You are here: you've already developed locally from source or brought the stack up with Compose. Next, see Deployment Modes and Image Sources to learn how the whole stack starts.

Why Two Sets of Files ​

The same variable name (say POSTGRES_HOST) means different things inside a container versus in a Java process on your laptop. Containers reach each other by service name on the Compose network (dc3-postgres). A Java process running in your IDE lives on the host, so it can only connect through the ports Compose publishes to the host (such as localhost:35432). The two file sets exist for these two non-overlapping paths. Mix them up and a local process tries to resolve a container name it can't reach, or a container tries to talk to a localhost it can't see.

FileConsumerPurposeInjection Method
.env.exampleDocker Compose templateCopied to root .env; defines image registry, image tag, published portsCompose variable interpolation
.envDocker ComposeUntracked local config, interpolated by dc3/docker-compose*.ymlCompose variable interpolation
dc3/env/dev.envIDE (EnvFile plugin)Environment variables for local Java processes, without exportRead by the IDE EnvFile plugin
dc3/env/dev.env.shShellEnvironment variables for local Java processes, with export, loaded via sourceInjected into the shell environment

The root .env is not injected into local Java processes

The root .env serves Docker Compose only. It is not automatically passed to Java processes started by your IDE or command line. Running from source locally requires dc3/env/dev.env(.sh), which points the process at the dependency ports Compose publishes on localhost. Setting POSTGRES_HOST=localhost in the root .env changes nothing about any container's runtime environment.

Two Isolated Paths ​

The diagram shows how each file set takes effect along its own path. The key point: these two paths never cross. Compose does not read dev.env.sh, and local Java processes do not read the root .env.

Compose path · container worldLocal Java path · host worldno cross injection — the two paths never meetcp copyCompose interpolation sourceEnvFile pluginsource loadinterpolateservice-name DNSenv injectionpoints at localhostcontainer aliases★ localhost published ports.env.examplein-repo template.env (repo root)untracked · Compose interpolationsame content · two injection stylesdc3/env/dev.envIDE EnvFile plugin · no exportdc3/env/dev.env.shShell source · with exportpodman compose / makeinterpolates docker-compose*.ymlcontainer servicesonly explicitly referenced vars are injectedin-container accessdc3-postgres:5432 · dc3-rabbitmq:5672IDE / java -jarRun Config EnvFile or shell envlocal Java processauth / manager / data / agentic / drivervia published portslocalhost:35432 · localhost:35672dc3-postgresinternal: dc3-postgres:5432host ★ localhost:35432dc3-rabbitmqinternal: dc3-rabbitmq:5672host ★ localhost:35672The root .env never reaches a local JVM — writing POSTGRES_HOST=localhost there changes no container and is never read by the IDEdc3/env/dev.env(.sh) is never read by Compose — the two sets serve different purposes, they are not the same file, do not copy between themLocal Java pathCompose pathContainer servicesDependency containersTemplate fileBoundary / forbidden

The mapping between host ports and internal ports is the core of this diagram:

Dependencyhost (for local processes)internal (for container-to-container)
PostgreSQLlocalhost:35432dc3-postgres:5432
RabbitMQ AMQPlocalhost:35672dc3-rabbitmq:5672
EMQX MQTTlocalhost:31883dc3-emqx:1883 (EMQX's default internal port)

How to Use ​

Bring the Stack Up with Compose ​

Create a local .env from the template, then bring it up with make (the Makefile's COMPOSE auto-detects and prefers docker compose; you can also force COMPOSE='podman compose' explicitly):

bash
cp .env.example .env
make up-db && make up-optional && make up-dev
bash
cp .env.example .env
podman compose -f dc3/docker-compose-dev.yml up -d   # bring up the dev stack
podman compose -f dc3/docker-compose-dev.yml config --quiet   # validate only, don't start

Variables in the root .env interpolate the compose files, for example images and published ports:

yaml
image: ${DC3_IMAGE_REGISTRY:-pnoker}/dc3-gateway:${DC3_IMAGE_TAG:-2026.9}
ports:
  - "${DC3_BIND_HOST:-127.0.0.1}:${DC3_GATEWAY_PORT:-8000}:8000"

Compose does not inject every variable in .env into every container. Only the variables the compose files explicitly reference via environment or env_file reach a container.

Run Locally from Source ​

source the file before starting a Java process from the command line:

bash
source dc3/env/dev.env.sh

Without it, the local process falls back to container service names (dc3-postgres, dc3-rabbitmq, dc3-center-manager) or default ports, so it can't reach the dependencies on your machine. JetBrains IDEA users should use dc3/env/dev.env instead (same content, no export): install the EnvFile plugin, enable EnvFile in the Run Configuration, and add dc3/env/dev.env. Don't use .env.example directly as an IDEA environment file — it's a Compose template, not Java runtime configuration.

Runtime profiles: dev / test / pre / pro ​

NODE_ENV decides which application-<env>.yml each service loads. The four differ in small but definite ways:

profileWho uses itLoggingOpenAPI / SwaggerSecret gateMQ name prefix
devlocal IDE / make devDEBUG (io.github.pnoker)oninactivedev_<username>.
testdefault in every Compose stackDEBUGoninactivenone
prepre-productionINFO defaultonactive (startup refuses a blank or default AUTH_HMAC_SECRET)none
proproductionINFO defaultoff (no springdoc endpoints exist)activenone

Three similarly named variables each own one job — don't mix them:

  • NODE_ENV: picks the profile (test by default in Compose stacks, dev in dev.env);
  • SPRING_ENV: sets spring.env directly, outranking the profile YAML; it mainly drives the MQ prefix and the secret-gate check (baked to test in native images — see Message Bus Topology);
  • SPRING_GROUP: the group part of the MQ prefix, defaulting to the OS username.

Key Variables Grouped by Scenario ​

The groups below cover what you actually need for a given scenario. The full long table is collapsed under ::: details at the end of the page; here we list only the variables you'll really change or look up when troubleshooting. The three Scope values mean: Runtime (read by both local and in-container Java processes), Compose only (only the root .env for Compose), and Per-process (a single-service override).

Security Keys (Runtime) ​

Two secrets are the platform's root of identity. Their defaults exist only for first-run convenience and must never go to production. Note that .env.example intentionally does not set these two keys: local source runs get dev-specific values from dc3/env/dev.env; the dev/single compose files carry dev fallback defaults (the "Default" column below); the app/scale/swarm stacks require them to be set explicitly in the root .env and refuse to start otherwise.

VariableDefault (dev-stack fallback)Purpose
DC3_SECURITY_KEYdc3.security.key.2026.io.github.pnokerSigning key the auth center uses to generate and verify login tokens
AUTH_HMAC_SECRETio.github.pnoker.dc3HMAC-SHA256 key the gateway uses to sign X-Auth-Principal for backend services

Change to strong random values in production, and never commit or print them

DC3_SECURITY_KEY and AUTH_HMAC_SECRET ship with defaults. In production, change them to strong random values and never commit them to the repository, write them to logs, or print them as-is. When the Spring profile is pre or pro and AUTH_HMAC_SECRET is empty or still equals the default io.github.pnoker.dc3, the service throws IllegalStateException and refuses to start. This is an intentional security gate — don't bypass it.

PostgreSQL (Runtime) ​

Local processes connect to localhost:35432; in-container processes connect to dc3-postgres:5432. POSTGRES_SCHEMA overrides the schema only inside a single-service process (such as dc3_manager or dc3_data) — don't set it globally.

VariableDefaultScopePurpose
POSTGRES_HOSTlocalhostRuntimelocalhost locally, dc3-postgres in-container
POSTGRES_PORT35432Runtimehost-published port; internal is 5432
POSTGRES_USERNAMEdc3RuntimeUsername
POSTGRES_PASSWORDdc3dc3dc3RuntimePassword
POSTGRES_DBdc3RuntimeDatabase name
POSTGRES_SCHEMA(unset)Per-processSingle-service schema override
DC3_POSTGRES_PORT35432Compose onlyPort the container publishes to the host

RabbitMQ (Runtime) ​

AMQP host port 35672, internal 5672. With TLS on, the internal port switches to 5671.

VariableDefaultScopePurpose
RABBITMQ_HOSTlocalhostRuntimelocalhost locally, dc3-rabbitmq in-container
RABBITMQ_PORT35672RuntimeAMQP host port; internal 5672
RABBITMQ_USERNAMEdc3RuntimeUsername
RABBITMQ_PASSWORDdc3dc3dc3RuntimePassword
RABBITMQ_VIRTUAL_HOSTdc3Runtimevirtual host
RABBITMQ_SSL_ENABLEDfalseRuntimeEnable TLS (uses 5671 when true)
DC3_RABBITMQ_PORT35672Compose onlyAMQP published port
DC3_RABBITMQ_MANAGEMENT_PORT15672Compose onlyManagement UI published port

Message Broker Selection (Runtime) ​

The message carrier for the internal async plane (point values, commands) is selected by DC3_MQ_TYPE, defaulting to rabbitmq. The connection variables are only read when the matching carrier is selected; the defaults below point at service names inside the Compose network — for local source runs see dc3/env/dev.env (e.g. Kafka uses localhost:9092).

VariableDefaultPurpose
DC3_MQ_TYPErabbitmqAsync-plane carrier: rabbitmq / kafka / pulsar / mqtt
DC3_MQ_KAFKA_BOOTSTRAPkafka:9092Kafka bootstrap address (read when DC3_MQ_TYPE=kafka)
DC3_MQ_PULSAR_URLpulsar://pulsar:6650Pulsar service URL (read when DC3_MQ_TYPE=pulsar)
DC3_MQ_MQTT_HOSTdc3-rabbitmqMQTT carrier host (read when DC3_MQ_TYPE=mqtt)
DC3_MQ_MQTT_PORT1883MQTT carrier port (read when DC3_MQ_TYPE=mqtt)

EMQX / MQTT (Runtime) ​

MQTT broker host port 31883. EMQX also publishes several other ports (WebSocket, Dashboard) — see the collapsed long table for the full list.

VariableDefaultScopePurpose
MQTT_BROKER_HOSTlocalhostRuntimebroker host
MQTT_BROKER_PORT31883Runtimebroker port (published by EMQX; internal is 1883)
MQTT_USERNAMEdc3RuntimeUsername
MQTT_PASSWORDdc3dc3dc3RuntimePassword
DC3_EMQX_MQTT_PORT31883Compose onlyMQTT published port
DC3_EMQX_DASHBOARD_PORT18083Compose onlyDashboard published port

gRPC / facade (Runtime) ​

Center services talk to each other through facades. The facade implementation for each target center is selected per-target via dc3.facade.{auth,manager,data}.mode (default grpc when unset; local is the in-process call — see Facade modes), and local processes point CENTER_*_HOST at localhost.

VariableDefaultScopePurpose
CENTER_AUTH_HOSTlocalhostRuntimeAuth center host
CENTER_MANAGER_HOSTlocalhostRuntimeManager center host
CENTER_DATA_HOSTlocalhostRuntimeData center host
CENTER_AGENTIC_HOSTlocalhostRuntimeAgentic center host
DC3_FACADE_AUTH_MODEgrpcRuntimeAuth center facade mode (grpc/local/disabled)
DC3_FACADE_MANAGER_MODEgrpcRuntimeManager center facade mode
DC3_FACADE_DATA_MODEgrpcRuntimeData center facade mode
DC3_FACADE_GRPC_DEADLINE_MS3000RuntimePer-request gRPC deadline; 0 disables the client deadline

DC3_FACADE_MODE is a dead leftover

The DC3_FACADE_MODE entry in .env.example is read by no code (the real config keys are the per-target dc3.facade.{auth,manager,data}.mode, whose env forms are the three rows above); it is a historical leftover — changing it has no effect.

Gateway and Service Ports (Compose only) ​

The gateway is the only external HTTP entry point (8000). The HTTP and gRPC published ports of each center are listed below. SERVER_PORT and GRPC_SERVER_PORT are single-process overrides, useful only when you run multiple services locally and need to avoid port collisions.

VariableDefaultScopePurpose
DC3_GATEWAY_PORT8000Compose onlyGateway HTTP published port (entry point)
DC3_AUTH_PORT8300Compose onlyAuth center HTTP
DC3_MANAGER_PORT8400Compose onlyManager center HTTP
DC3_DATA_PORT8500Compose onlyData center HTTP
DC3_AGENTIC_PORT8600Compose onlyAgentic center HTTP
DC3_AUTH_GRPC_PORT9300Compose onlyAuth center gRPC
DC3_MANAGER_GRPC_PORT9400Compose onlyManager center gRPC
DC3_DATA_GRPC_PORT9500Compose onlyData center gRPC
DC3_LISTENING_VIRTUAL_TCP_PORT6270Compose onlyListening Virtual driver TCP publish
DC3_LISTENING_VIRTUAL_UDP_PORT6271Compose onlyListening Virtual driver UDP publish (currently published as TCP)
DC3_SINGLE_PORT8100Compose onlySingle-center mode HTTP published port
DC3_SINGLE_GRPC_PORT9100Compose onlySingle-center mode gRPC published port
DC3_WEB_HTTP_PORT8080Compose onlyWeb console HTTP published port
DC3_WEB_HTTPS_PORT8443Compose onlyWeb console HTTPS published port
SERVER_PORT(unset)Per-processSingle-service HTTP port override
GRPC_SERVER_PORT(unset)Per-processSingle-center gRPC port override

DC3_LISTENING_VIRTUAL_*_PORT are host-published ports

DC3_LISTENING_VIRTUAL_TCP_PORT and DC3_LISTENING_VIRTUAL_UDP_PORT are the ports Compose publishes to the host. The process's internal ports use TCP_PORT and UDP_PORT (Per-process). Don't confuse the two. Also note that 6271 is intended as the UDP channel, but no published port currently declares /udp, so it is actually published as TCP.

Web Console and Gateway OAuth (Compose only) ​

The web console (dc3-web) proxies API requests to the gateway through nginx; the gateway's API routes default to the internal auth headers, but can be switched to OAuth RS256 ticket mode.

VariableDefaultPurpose
APP_API_HOSTdc3-gatewayGateway host the console reverse-proxies to (nginx upstream)
APP_API_PORT8000Gateway port the console reverse-proxies to
DC3_GATEWAY_OAUTH_ENABLEDfalseWhether gateway API routes use OAuth RS256 ticket mode
DC3_GATEWAY_OAUTH_JWKS_URLhttp://dc3-center-auth:8300/auth/oauth2/jwksOAuth JWKS URL (points at the auth center)

Agentic / AI (Runtime) ​

The AGENTIC_FALLBACK_OPENAI_* group only kicks in as a fallback when dc3_model_provider has no usable provider configured. Conversation memory is on by default (.env.example and the in-code fallback agree). The master key, transport rate-limit, and attachment quota variables arrived in 2026.10; the Agentic Center security checklist explains what each one does.

VariableDefaultPurpose
AGENTIC_FALLBACK_OPENAI_BASE_URLhttps://api.openai.comFallback OpenAI-compatible API address
AGENTIC_FALLBACK_OPENAI_API_KEY(empty)Fallback API key (fill in when the endpoint requires authentication)
AGENTIC_FALLBACK_OPENAI_MODELgpt-4oFallback model name
AGENTIC_FALLBACK_OPENAI_TEMPERATURE0.7Sampling temperature (0.0–2.0)
AGENTIC_FALLBACK_OPENAI_MAX_TOKENS2048Maximum output tokens
AGENTIC_MEMORY_SCHEMA_INITneverSpring AI JDBC memory table init mode (always/never/create_if_not_exists)
AGENTIC_MEMORY_ENABLEDtrueWhether persistent conversation memory is on
AGENTIC_TOOL_CALLING_ENABLEDtrueWhether tool calling is on
AGENTIC_MEMORY_MAX_MESSAGES50Maximum messages retained per conversation window
AGENTIC_ATTACHMENT_STORAGE_PATHdc3/data/agentic/attachmentsAttachment storage path
DC3_AGENTIC_MASTER_KEY(empty)AES-256-GCM master key encrypting provider API keys at rest (Base64, 256-bit; derived from DC3_SECURITY_KEY when unset — set explicitly in production)
AGENTIC_TRANSPORT_ACQUIRE_TIMEOUT_SECONDS30Seconds waiting for a model concurrency slot before failing with UNAVAILABLE
AGENTIC_TRANSPORT_GLOBAL_MAX_CONCURRENT_REQUESTS16In-flight model request cap across all providers
AGENTIC_TRANSPORT_FALLBACK_ENABLEDfalsePlatform-wide fallback model switch (keep off in production: it bypasses per-tenant accounting)
AGENTIC_TRANSPORT_PER_TENANT_QPS0Per-tenant chat requests per second; 0 disables
AGENTIC_TRANSPORT_CACHE_TTL_SECONDS300In-process provider / model / client cache TTL (seconds)
AGENTIC_CHECK_CACHE_MAXIMUM_SIZE256Upper bound of cached connectivity-check results
AGENTIC_ATTACHMENT_ALLOWED_EXTENSIONSpng,jpg,jpeg,gif,webp,csv,txt,json,md,pdfAttachment extension whitelist, checked before any byte is written
AGENTIC_ATTACHMENT_TENANT_MAX_COUNT2000Per-tenant attachment count cap
AGENTIC_ATTACHMENT_TENANT_MAX_BYTES1073741824Per-tenant total-bytes cap (1 GiB by default)
AGENTIC_ATTACHMENT_NAME_MAX_LENGTH128Maximum attachment file-name length (characters)

The table binding for AGENTIC_MEMORY_SCHEMA_INIT is governed by the code

AGENTIC_MEMORY_SCHEMA_INIT defaults to never and is meant to control the memory table init mode. But after Compose injects it into the container, no application*.yml in the repository binds it to Spring AI's initialize-schema; the memory tables are actually pre-created by the initdb scripts. Whether setting it to always truly triggers automatic table creation needs to be determined from the code — don't treat it as a wired, working switch.

Real API keys must not enter docs, logs, or commit history

Sensitive values like AGENTIC_FALLBACK_OPENAI_API_KEY must never be written into docs, logs, or commit history. Configure production providers in the dc3_model_provider table; the fallback is just a safety net.

AGENTIC_ATTACHMENT_STORAGE_PATH differs between .env.example and the in-code fallback

The value above for AGENTIC_ATTACHMENT_STORAGE_PATH (dc3/data/agentic/attachments) comes from .env.example; on the cp .env.example .env + source path it is explicitly injected. But the in-code fallback default in application-agentic.yml is dc3/data/upload/agentic/attachment. When you're not on the .env.example path, the code takes precedence. All other rows (including AGENTIC_MEMORY_ENABLED=true) agree between the two.

Batch Processing and Consumption (Runtime) ​

MQTT reporting and point-value persistence each have a group of batching parameters. Point values flush on a dual "count + receive-timeout" threshold — whichever of POINT_BATCH_SIZE records or POINT_BATCH_RECEIVE_TIMEOUT_MILLIS milliseconds comes first; concurrent consumption and retries are governed by POINT_CONCURRENT_CONSUMERS and friends.

VariableDefaultPurpose
MQTT_BATCH_SPEED100MQTT batch size threshold (records/batch)
MQTT_BATCH_INTERVAL5MQTT batch interval (seconds)
POINT_BATCH_SIZE500Point value batch size threshold (records/batch)
POINT_BATCH_RECEIVE_TIMEOUT_MILLIS100Point value receive timeout (ms; first-to-trigger)
POINT_CONCURRENT_CONSUMERS4Initial concurrent consumers for point values
POINT_MAX_CONCURRENT_CONSUMERS16Maximum concurrent consumers for point values
POINT_PREFETCH_COUNT1000Prefetch count per consumer
POINT_RETRY_MAX_RETRIES3Maximum consumption retries
POINT_RETRY_INITIAL_INTERVAL_MILLIS1000Initial retry interval (ms)
POINT_RETRY_MULTIPLIER2Retry interval multiplier
POINT_RETRY_MAX_INTERVAL_MILLIS10000Maximum retry interval (ms)

On the MQTT side it remains a "count threshold + interval" pair: a timer flushes the accumulated buffer every MQTT_BATCH_INTERVAL seconds.

Image Sources (Compose only) ​

On mainland China networks, set REGISTRY to cn to use the Aliyun mirror. Note: the Makefile reads REGISTRY and Compose interpolation reads DC3_IMAGE_REGISTRY — each governs its own segment.

VariableDefaultPurpose
REGISTRYautoMakefile image-source selector (accepts only auto/global/cn; other values error out)
DC3_IMAGE_REGISTRYpnokerImage namespace
DC3_IMAGE_TAG2026.9Image tag for all services and dependencies
DC3_BASE_TAG2026.10dc3-docker base image line the dependency images build from (independent of DC3_IMAGE_TAG)
DC3_VERSIONlatestWeb console image version (dc3-web publishes only latest and full releases)
DC3_BIND_HOST127.0.0.1Published-port bind address (0.0.0.0 for external access)

Observability (Compose only / Runtime) ​

The optional stack (EMQX, ELK, Prometheus, Grafana) comes up via make up-optional. Its ports and JVM parameters are below.

VariableDefaultScopePurpose
GF_SERVER_ROOT_URLhttp://localhost:3000RuntimeGrafana external root URL
DC3_GRAFANA_PORT3000Compose onlyGrafana published port
DC3_KIBANA_PORT5601Compose onlyKibana published port
DC3_ES_JAVA_OPTS-Xms512m -Xmx512mRuntimeElasticsearch JVM heap
DC3_LS_JAVA_OPTS-Xms256m -Xmx256mRuntimeLogstash JVM heap
APM_AGENT_ENABLEfalseRuntimeWhether the Java APM agent is on
DC3_JAEGER_UI_PORT16686Compose onlyJaeger UI published port
DC3_JAEGER_OTLP_GRPC_PORT4317Compose onlyJaeger OTLP gRPC published port
DC3_JAEGER_OTLP_HTTP_PORT4318Compose onlyJaeger OTLP HTTP published port
Full Variable Reference (collapsed)

Security & Authentication (Runtime) ​

VariableDefaultPurpose
DC3_SECURITY_KEYdc3.security.key.2026.io.github.pnokerLogin token signing key
AUTH_HMAC_SECRETio.github.pnoker.dc3X-Auth-Principal HMAC-SHA256 key

PostgreSQL ​

VariableDefaultScope
POSTGRES_HOSTlocalhostRuntime
POSTGRES_PORT35432Runtime
POSTGRES_USERNAMEdc3Runtime
POSTGRES_PASSWORDdc3dc3dc3Runtime
POSTGRES_DBdc3Runtime
POSTGRES_SCHEMA(unset)Per-process
DC3_POSTGRES_PORT35432Compose only

RabbitMQ ​

VariableDefaultScope
RABBITMQ_HOSTlocalhostRuntime
RABBITMQ_PORT35672Runtime
RABBITMQ_USERNAMEdc3Runtime
RABBITMQ_PASSWORDdc3dc3dc3Runtime
RABBITMQ_VIRTUAL_HOSTdc3Runtime
RABBITMQ_MQTT_EXCHANGEdc3.e.mqttRuntime
RABBITMQ_SSL_ENABLEDfalseRuntime
RABBITMQ_SSL_ALGORITHMTLSRuntime
RABBITMQ_SSL_VALIDATE_SERVER_CERTIFICATEfalseRuntime
RABBITMQ_SSL_VERIFY_HOSTNAMEfalseRuntime
RABBITMQ_CONTAINER_PORT5672Runtime
DC3_RABBITMQ_PORT35672Compose only
DC3_RABBITMQ_TLS_PORT35671Compose only
DC3_RABBITMQ_MANAGEMENT_PORT15672Compose only

Message Broker Selection ​

VariableDefaultScope
DC3_MQ_TYPErabbitmqRuntime
DC3_MQ_KAFKA_BOOTSTRAPkafka:9092Runtime
DC3_MQ_PULSAR_URLpulsar://pulsar:6650Runtime
DC3_MQ_MQTT_HOSTdc3-rabbitmqRuntime
DC3_MQ_MQTT_PORT1883Runtime

EMQX / MQTT ​

VariableDefaultScope
MQTT_BROKER_HOSTlocalhostRuntime
MQTT_BROKER_PORT31883Runtime
MQTT_USERNAMEdc3Runtime
MQTT_PASSWORDdc3dc3dc3Runtime
MQTT_BATCH_SPEED100Runtime
MQTT_BATCH_INTERVAL5Runtime
DC3_EMQX_WS_PORT38083Compose only
DC3_EMQX_WSS_PORT38084Compose only
DC3_EMQX_MQTT_PORT31883Compose only
DC3_EMQX_MQTTS_PORT38883Compose only
DC3_EMQX_DASHBOARD_PORT18083Compose only

gRPC / facade ​

VariableDefaultScope
CENTER_AUTH_HOSTlocalhostRuntime
CENTER_MANAGER_HOSTlocalhostRuntime
CENTER_DATA_HOSTlocalhostRuntime
CENTER_AGENTIC_HOSTlocalhostRuntime
DC3_FACADE_AUTH_MODEgrpcRuntime
DC3_FACADE_MANAGER_MODEgrpcRuntime
DC3_FACADE_DATA_MODEgrpcRuntime
DC3_FACADE_GRPC_DEADLINE_MS3000Runtime
DC3_AUTH_GRPC_PORT9300Compose only
DC3_MANAGER_GRPC_PORT9400Compose only
DC3_DATA_GRPC_PORT9500Compose only

HTTP Gateway & Service Ports ​

VariableDefaultScope
DC3_GATEWAY_PORT8000Compose only
DC3_AUTH_PORT8300Compose only
DC3_MANAGER_PORT8400Compose only
DC3_DATA_PORT8500Compose only
DC3_AGENTIC_PORT8600Compose only
SERVER_PORT(unset)Per-process
GRPC_SERVER_PORT(unset)Per-process
DC3_LISTENING_VIRTUAL_TCP_PORT6270Compose only
DC3_LISTENING_VIRTUAL_UDP_PORT6271Compose only
DC3_SINGLE_PORT8100Compose only
DC3_SINGLE_GRPC_PORT9100Compose only
DC3_WEB_HTTP_PORT8080Compose only
DC3_WEB_HTTPS_PORT8443Compose only
TCP_PORT(unset)Per-process
UDP_PORT(unset)Per-process
GATEWAY_ROUTE_AUTH_TOKEN_URI(unset)Per-process
GATEWAY_ROUTE_AUTH_URI(unset)Per-process
GATEWAY_ROUTE_MANAGER_URI(unset)Per-process
GATEWAY_ROUTE_DATA_URI(unset)Per-process
GATEWAY_ROUTE_AGENTIC_URI(unset)Per-process

Web Console and Gateway OAuth ​

VariableDefaultScope
APP_API_HOSTdc3-gatewayCompose only
APP_API_PORT8000Compose only
DC3_GATEWAY_OAUTH_ENABLEDfalseCompose only
DC3_GATEWAY_OAUTH_JWKS_URLhttp://dc3-center-auth:8300/auth/oauth2/jwksCompose only

Agentic / AI (Runtime) ​

VariableDefault
AGENTIC_FALLBACK_OPENAI_BASE_URLhttps://api.openai.com
AGENTIC_FALLBACK_OPENAI_API_KEY(empty)
AGENTIC_FALLBACK_OPENAI_MODELgpt-4o
AGENTIC_FALLBACK_OPENAI_TEMPERATURE0.7
AGENTIC_FALLBACK_OPENAI_MAX_TOKENS2048
AGENTIC_MEMORY_SCHEMA_INITnever
AGENTIC_MEMORY_ENABLEDtrue
AGENTIC_MEMORY_MAX_MESSAGES50
AGENTIC_TOOL_CALLING_ENABLEDtrue
AGENTIC_ATTACHMENT_STORAGE_PATHdc3/data/agentic/attachments
DC3_AGENTIC_MASTER_KEY(empty)
AGENTIC_TRANSPORT_ACQUIRE_TIMEOUT_SECONDS30
AGENTIC_TRANSPORT_GLOBAL_MAX_CONCURRENT_REQUESTS16
AGENTIC_TRANSPORT_FALLBACK_ENABLEDfalse
AGENTIC_TRANSPORT_PER_TENANT_QPS0
AGENTIC_TRANSPORT_CACHE_TTL_SECONDS300
AGENTIC_CHECK_CACHE_MAXIMUM_SIZE256
AGENTIC_ATTACHMENT_ALLOWED_EXTENSIONSpng,jpg,jpeg,gif,webp,csv,txt,json,md,pdf
AGENTIC_ATTACHMENT_TENANT_MAX_COUNT2000
AGENTIC_ATTACHMENT_TENANT_MAX_BYTES1073741824
AGENTIC_ATTACHMENT_NAME_MAX_LENGTH128

Batch Processing / Driver Lease / Images / Observability ​

VariableDefaultScope
POINT_BATCH_SIZE500Runtime
POINT_BATCH_RECEIVE_TIMEOUT_MILLIS100Runtime
POINT_CONCURRENT_CONSUMERS4Runtime
POINT_MAX_CONCURRENT_CONSUMERS16Runtime
POINT_PREFETCH_COUNT1000Runtime
POINT_RETRY_MAX_RETRIES3Runtime
POINT_RETRY_INITIAL_INTERVAL_MILLIS1000Runtime
POINT_RETRY_MULTIPLIER2Runtime
POINT_RETRY_MAX_INTERVAL_MILLIS10000Runtime
DC3_DRIVER_LEASE_SECONDS30Runtime
DC3_DRIVER_LEASE_RENEW_CRON0/10 * * * * ?Runtime
DC3_DRIVER_LEASE_QUEUE_EXPIRES_MILLIS300000Runtime
REGISTRYautoCompose only
DC3_IMAGE_REGISTRYpnokerCompose only
DC3_IMAGE_TAG2026.9Compose only
DC3_BASE_TAG2026.10Compose only
DC3_VERSIONlatestCompose only
DC3_LOG_MAX_SIZE10MCompose only
DC3_LOG_MAX_FILE20Compose only
DC3_BIND_HOST127.0.0.1Compose only
GF_SERVER_ROOT_URLhttp://localhost:3000Runtime
DC3_GRAFANA_PORT3000Compose only
DC3_KIBANA_PORT5601Compose only
DC3_ES_JAVA_OPTS-Xms512m -Xmx512mRuntime
DC3_LS_JAVA_OPTS-Xms256m -Xmx256mRuntime
APM_AGENT_ENABLEfalseRuntime
DC3_JAEGER_UI_PORT16686Compose only
DC3_JAEGER_OTLP_GRPC_PORT4317Compose only
DC3_JAEGER_OTLP_HTTP_PORT4318Compose only
NODE_ENVdevRuntime

Constraints and Common Pitfalls ​

  • Editing .env.example does nothing at runtime — you must cp .env.example .env first.
  • dc3/env/dev.env and the root .env serve different purposes. They are not the same file; don't copy one into the other.
  • Use DC3_*_PORT consistently for service published ports. The process internals still use Spring Boot's native names such as SERVER_PORT and GRPC_SERVER_PORT.
  • Per-process variables (POSTGRES_SCHEMA, SERVER_PORT, TCP_PORT, and so on) are single-service overrides only — don't set them globally.
  • The Compose application stack can use a different NODE_ENV than local source runs.

Further Reading ​

Released under the AGPL-3.0 License