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.
| File | Consumer | Purpose | Injection Method |
|---|---|---|---|
.env.example | Docker Compose template | Copied to root .env; defines image registry, image tag, published ports | Compose variable interpolation |
.env | Docker Compose | Untracked local config, interpolated by dc3/docker-compose*.yml | Compose variable interpolation |
dc3/env/dev.env | IDE (EnvFile plugin) | Environment variables for local Java processes, without export | Read by the IDE EnvFile plugin |
dc3/env/dev.env.sh | Shell | Environment variables for local Java processes, with export, loaded via source | Injected 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.
The mapping between host ports and internal ports is the core of this diagram:
| Dependency | host (for local processes) | internal (for container-to-container) |
|---|---|---|
| PostgreSQL | localhost:35432 | dc3-postgres:5432 |
| RabbitMQ AMQP | localhost:35672 | dc3-rabbitmq:5672 |
| EMQX MQTT | localhost:31883 | dc3-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):
cp .env.example .env
make up-db && make up-optional && make up-devcp .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 startVariables in the root .env interpolate the compose files, for example images and published ports:
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:
source dc3/env/dev.env.shWithout 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:
| profile | Who uses it | Logging | OpenAPI / Swagger | Secret gate | MQ name prefix |
|---|---|---|---|---|---|
dev | local IDE / make dev | DEBUG (io.github.pnoker) | on | inactive | dev_<username>. |
test | default in every Compose stack | DEBUG | on | inactive | none |
pre | pre-production | INFO default | on | active (startup refuses a blank or default AUTH_HMAC_SECRET) | none |
pro | production | INFO default | off (no springdoc endpoints exist) | active | none |
Three similarly named variables each own one job — don't mix them:
NODE_ENV: picks the profile (testby default in Compose stacks,devindev.env);SPRING_ENV: setsspring.envdirectly, outranking the profile YAML; it mainly drives the MQ prefix and the secret-gate check (baked totestin 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.
| Variable | Default (dev-stack fallback) | Purpose |
|---|---|---|
DC3_SECURITY_KEY | dc3.security.key.2026.io.github.pnoker | Signing key the auth center uses to generate and verify login tokens |
AUTH_HMAC_SECRET | io.github.pnoker.dc3 | HMAC-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.
| Variable | Default | Scope | Purpose |
|---|---|---|---|
POSTGRES_HOST | localhost | Runtime | localhost locally, dc3-postgres in-container |
POSTGRES_PORT | 35432 | Runtime | host-published port; internal is 5432 |
POSTGRES_USERNAME | dc3 | Runtime | Username |
POSTGRES_PASSWORD | dc3dc3dc3 | Runtime | Password |
POSTGRES_DB | dc3 | Runtime | Database name |
POSTGRES_SCHEMA | (unset) | Per-process | Single-service schema override |
DC3_POSTGRES_PORT | 35432 | Compose only | Port the container publishes to the host |
RabbitMQ (Runtime)
AMQP host port 35672, internal 5672. With TLS on, the internal port switches to 5671.
| Variable | Default | Scope | Purpose |
|---|---|---|---|
RABBITMQ_HOST | localhost | Runtime | localhost locally, dc3-rabbitmq in-container |
RABBITMQ_PORT | 35672 | Runtime | AMQP host port; internal 5672 |
RABBITMQ_USERNAME | dc3 | Runtime | Username |
RABBITMQ_PASSWORD | dc3dc3dc3 | Runtime | Password |
RABBITMQ_VIRTUAL_HOST | dc3 | Runtime | virtual host |
RABBITMQ_SSL_ENABLED | false | Runtime | Enable TLS (uses 5671 when true) |
DC3_RABBITMQ_PORT | 35672 | Compose only | AMQP published port |
DC3_RABBITMQ_MANAGEMENT_PORT | 15672 | Compose only | Management 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).
| Variable | Default | Purpose |
|---|---|---|
DC3_MQ_TYPE | rabbitmq | Async-plane carrier: rabbitmq / kafka / pulsar / mqtt |
DC3_MQ_KAFKA_BOOTSTRAP | kafka:9092 | Kafka bootstrap address (read when DC3_MQ_TYPE=kafka) |
DC3_MQ_PULSAR_URL | pulsar://pulsar:6650 | Pulsar service URL (read when DC3_MQ_TYPE=pulsar) |
DC3_MQ_MQTT_HOST | dc3-rabbitmq | MQTT carrier host (read when DC3_MQ_TYPE=mqtt) |
DC3_MQ_MQTT_PORT | 1883 | MQTT 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.
| Variable | Default | Scope | Purpose |
|---|---|---|---|
MQTT_BROKER_HOST | localhost | Runtime | broker host |
MQTT_BROKER_PORT | 31883 | Runtime | broker port (published by EMQX; internal is 1883) |
MQTT_USERNAME | dc3 | Runtime | Username |
MQTT_PASSWORD | dc3dc3dc3 | Runtime | Password |
DC3_EMQX_MQTT_PORT | 31883 | Compose only | MQTT published port |
DC3_EMQX_DASHBOARD_PORT | 18083 | Compose only | Dashboard 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.
| Variable | Default | Scope | Purpose |
|---|---|---|---|
CENTER_AUTH_HOST | localhost | Runtime | Auth center host |
CENTER_MANAGER_HOST | localhost | Runtime | Manager center host |
CENTER_DATA_HOST | localhost | Runtime | Data center host |
CENTER_AGENTIC_HOST | localhost | Runtime | Agentic center host |
DC3_FACADE_AUTH_MODE | grpc | Runtime | Auth center facade mode (grpc/local/disabled) |
DC3_FACADE_MANAGER_MODE | grpc | Runtime | Manager center facade mode |
DC3_FACADE_DATA_MODE | grpc | Runtime | Data center facade mode |
DC3_FACADE_GRPC_DEADLINE_MS | 3000 | Runtime | Per-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.
| Variable | Default | Scope | Purpose |
|---|---|---|---|
DC3_GATEWAY_PORT | 8000 | Compose only | Gateway HTTP published port (entry point) |
DC3_AUTH_PORT | 8300 | Compose only | Auth center HTTP |
DC3_MANAGER_PORT | 8400 | Compose only | Manager center HTTP |
DC3_DATA_PORT | 8500 | Compose only | Data center HTTP |
DC3_AGENTIC_PORT | 8600 | Compose only | Agentic center HTTP |
DC3_AUTH_GRPC_PORT | 9300 | Compose only | Auth center gRPC |
DC3_MANAGER_GRPC_PORT | 9400 | Compose only | Manager center gRPC |
DC3_DATA_GRPC_PORT | 9500 | Compose only | Data center gRPC |
DC3_LISTENING_VIRTUAL_TCP_PORT | 6270 | Compose only | Listening Virtual driver TCP publish |
DC3_LISTENING_VIRTUAL_UDP_PORT | 6271 | Compose only | Listening Virtual driver UDP publish (currently published as TCP) |
DC3_SINGLE_PORT | 8100 | Compose only | Single-center mode HTTP published port |
DC3_SINGLE_GRPC_PORT | 9100 | Compose only | Single-center mode gRPC published port |
DC3_WEB_HTTP_PORT | 8080 | Compose only | Web console HTTP published port |
DC3_WEB_HTTPS_PORT | 8443 | Compose only | Web console HTTPS published port |
SERVER_PORT | (unset) | Per-process | Single-service HTTP port override |
GRPC_SERVER_PORT | (unset) | Per-process | Single-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.
| Variable | Default | Purpose |
|---|---|---|
APP_API_HOST | dc3-gateway | Gateway host the console reverse-proxies to (nginx upstream) |
APP_API_PORT | 8000 | Gateway port the console reverse-proxies to |
DC3_GATEWAY_OAUTH_ENABLED | false | Whether gateway API routes use OAuth RS256 ticket mode |
DC3_GATEWAY_OAUTH_JWKS_URL | http://dc3-center-auth:8300/auth/oauth2/jwks | OAuth 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.
| Variable | Default | Purpose |
|---|---|---|
AGENTIC_FALLBACK_OPENAI_BASE_URL | https://api.openai.com | Fallback OpenAI-compatible API address |
AGENTIC_FALLBACK_OPENAI_API_KEY | (empty) | Fallback API key (fill in when the endpoint requires authentication) |
AGENTIC_FALLBACK_OPENAI_MODEL | gpt-4o | Fallback model name |
AGENTIC_FALLBACK_OPENAI_TEMPERATURE | 0.7 | Sampling temperature (0.0–2.0) |
AGENTIC_FALLBACK_OPENAI_MAX_TOKENS | 2048 | Maximum output tokens |
AGENTIC_MEMORY_SCHEMA_INIT | never | Spring AI JDBC memory table init mode (always/never/create_if_not_exists) |
AGENTIC_MEMORY_ENABLED | true | Whether persistent conversation memory is on |
AGENTIC_TOOL_CALLING_ENABLED | true | Whether tool calling is on |
AGENTIC_MEMORY_MAX_MESSAGES | 50 | Maximum messages retained per conversation window |
AGENTIC_ATTACHMENT_STORAGE_PATH | dc3/data/agentic/attachments | Attachment 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_SECONDS | 30 | Seconds waiting for a model concurrency slot before failing with UNAVAILABLE |
AGENTIC_TRANSPORT_GLOBAL_MAX_CONCURRENT_REQUESTS | 16 | In-flight model request cap across all providers |
AGENTIC_TRANSPORT_FALLBACK_ENABLED | false | Platform-wide fallback model switch (keep off in production: it bypasses per-tenant accounting) |
AGENTIC_TRANSPORT_PER_TENANT_QPS | 0 | Per-tenant chat requests per second; 0 disables |
AGENTIC_TRANSPORT_CACHE_TTL_SECONDS | 300 | In-process provider / model / client cache TTL (seconds) |
AGENTIC_CHECK_CACHE_MAXIMUM_SIZE | 256 | Upper bound of cached connectivity-check results |
AGENTIC_ATTACHMENT_ALLOWED_EXTENSIONS | png,jpg,jpeg,gif,webp,csv,txt,json,md,pdf | Attachment extension whitelist, checked before any byte is written |
AGENTIC_ATTACHMENT_TENANT_MAX_COUNT | 2000 | Per-tenant attachment count cap |
AGENTIC_ATTACHMENT_TENANT_MAX_BYTES | 1073741824 | Per-tenant total-bytes cap (1 GiB by default) |
AGENTIC_ATTACHMENT_NAME_MAX_LENGTH | 128 | Maximum 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.
| Variable | Default | Purpose |
|---|---|---|
MQTT_BATCH_SPEED | 100 | MQTT batch size threshold (records/batch) |
MQTT_BATCH_INTERVAL | 5 | MQTT batch interval (seconds) |
POINT_BATCH_SIZE | 500 | Point value batch size threshold (records/batch) |
POINT_BATCH_RECEIVE_TIMEOUT_MILLIS | 100 | Point value receive timeout (ms; first-to-trigger) |
POINT_CONCURRENT_CONSUMERS | 4 | Initial concurrent consumers for point values |
POINT_MAX_CONCURRENT_CONSUMERS | 16 | Maximum concurrent consumers for point values |
POINT_PREFETCH_COUNT | 1000 | Prefetch count per consumer |
POINT_RETRY_MAX_RETRIES | 3 | Maximum consumption retries |
POINT_RETRY_INITIAL_INTERVAL_MILLIS | 1000 | Initial retry interval (ms) |
POINT_RETRY_MULTIPLIER | 2 | Retry interval multiplier |
POINT_RETRY_MAX_INTERVAL_MILLIS | 10000 | Maximum 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.
| Variable | Default | Purpose |
|---|---|---|
REGISTRY | auto | Makefile image-source selector (accepts only auto/global/cn; other values error out) |
DC3_IMAGE_REGISTRY | pnoker | Image namespace |
DC3_IMAGE_TAG | 2026.9 | Image tag for all services and dependencies |
DC3_BASE_TAG | 2026.10 | dc3-docker base image line the dependency images build from (independent of DC3_IMAGE_TAG) |
DC3_VERSION | latest | Web console image version (dc3-web publishes only latest and full releases) |
DC3_BIND_HOST | 127.0.0.1 | Published-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.
| Variable | Default | Scope | Purpose |
|---|---|---|---|
GF_SERVER_ROOT_URL | http://localhost:3000 | Runtime | Grafana external root URL |
DC3_GRAFANA_PORT | 3000 | Compose only | Grafana published port |
DC3_KIBANA_PORT | 5601 | Compose only | Kibana published port |
DC3_ES_JAVA_OPTS | -Xms512m -Xmx512m | Runtime | Elasticsearch JVM heap |
DC3_LS_JAVA_OPTS | -Xms256m -Xmx256m | Runtime | Logstash JVM heap |
APM_AGENT_ENABLE | false | Runtime | Whether the Java APM agent is on |
DC3_JAEGER_UI_PORT | 16686 | Compose only | Jaeger UI published port |
DC3_JAEGER_OTLP_GRPC_PORT | 4317 | Compose only | Jaeger OTLP gRPC published port |
DC3_JAEGER_OTLP_HTTP_PORT | 4318 | Compose only | Jaeger OTLP HTTP published port |
Full Variable Reference (collapsed)
Security & Authentication (Runtime)
| Variable | Default | Purpose |
|---|---|---|
DC3_SECURITY_KEY | dc3.security.key.2026.io.github.pnoker | Login token signing key |
AUTH_HMAC_SECRET | io.github.pnoker.dc3 | X-Auth-Principal HMAC-SHA256 key |
PostgreSQL
| Variable | Default | Scope |
|---|---|---|
POSTGRES_HOST | localhost | Runtime |
POSTGRES_PORT | 35432 | Runtime |
POSTGRES_USERNAME | dc3 | Runtime |
POSTGRES_PASSWORD | dc3dc3dc3 | Runtime |
POSTGRES_DB | dc3 | Runtime |
POSTGRES_SCHEMA | (unset) | Per-process |
DC3_POSTGRES_PORT | 35432 | Compose only |
RabbitMQ
| Variable | Default | Scope |
|---|---|---|
RABBITMQ_HOST | localhost | Runtime |
RABBITMQ_PORT | 35672 | Runtime |
RABBITMQ_USERNAME | dc3 | Runtime |
RABBITMQ_PASSWORD | dc3dc3dc3 | Runtime |
RABBITMQ_VIRTUAL_HOST | dc3 | Runtime |
RABBITMQ_MQTT_EXCHANGE | dc3.e.mqtt | Runtime |
RABBITMQ_SSL_ENABLED | false | Runtime |
RABBITMQ_SSL_ALGORITHM | TLS | Runtime |
RABBITMQ_SSL_VALIDATE_SERVER_CERTIFICATE | false | Runtime |
RABBITMQ_SSL_VERIFY_HOSTNAME | false | Runtime |
RABBITMQ_CONTAINER_PORT | 5672 | Runtime |
DC3_RABBITMQ_PORT | 35672 | Compose only |
DC3_RABBITMQ_TLS_PORT | 35671 | Compose only |
DC3_RABBITMQ_MANAGEMENT_PORT | 15672 | Compose only |
Message Broker Selection
| Variable | Default | Scope |
|---|---|---|
DC3_MQ_TYPE | rabbitmq | Runtime |
DC3_MQ_KAFKA_BOOTSTRAP | kafka:9092 | Runtime |
DC3_MQ_PULSAR_URL | pulsar://pulsar:6650 | Runtime |
DC3_MQ_MQTT_HOST | dc3-rabbitmq | Runtime |
DC3_MQ_MQTT_PORT | 1883 | Runtime |
EMQX / MQTT
| Variable | Default | Scope |
|---|---|---|
MQTT_BROKER_HOST | localhost | Runtime |
MQTT_BROKER_PORT | 31883 | Runtime |
MQTT_USERNAME | dc3 | Runtime |
MQTT_PASSWORD | dc3dc3dc3 | Runtime |
MQTT_BATCH_SPEED | 100 | Runtime |
MQTT_BATCH_INTERVAL | 5 | Runtime |
DC3_EMQX_WS_PORT | 38083 | Compose only |
DC3_EMQX_WSS_PORT | 38084 | Compose only |
DC3_EMQX_MQTT_PORT | 31883 | Compose only |
DC3_EMQX_MQTTS_PORT | 38883 | Compose only |
DC3_EMQX_DASHBOARD_PORT | 18083 | Compose only |
gRPC / facade
| Variable | Default | Scope |
|---|---|---|
CENTER_AUTH_HOST | localhost | Runtime |
CENTER_MANAGER_HOST | localhost | Runtime |
CENTER_DATA_HOST | localhost | Runtime |
CENTER_AGENTIC_HOST | localhost | Runtime |
DC3_FACADE_AUTH_MODE | grpc | Runtime |
DC3_FACADE_MANAGER_MODE | grpc | Runtime |
DC3_FACADE_DATA_MODE | grpc | Runtime |
DC3_FACADE_GRPC_DEADLINE_MS | 3000 | Runtime |
DC3_AUTH_GRPC_PORT | 9300 | Compose only |
DC3_MANAGER_GRPC_PORT | 9400 | Compose only |
DC3_DATA_GRPC_PORT | 9500 | Compose only |
HTTP Gateway & Service Ports
| Variable | Default | Scope |
|---|---|---|
DC3_GATEWAY_PORT | 8000 | Compose only |
DC3_AUTH_PORT | 8300 | Compose only |
DC3_MANAGER_PORT | 8400 | Compose only |
DC3_DATA_PORT | 8500 | Compose only |
DC3_AGENTIC_PORT | 8600 | Compose only |
SERVER_PORT | (unset) | Per-process |
GRPC_SERVER_PORT | (unset) | Per-process |
DC3_LISTENING_VIRTUAL_TCP_PORT | 6270 | Compose only |
DC3_LISTENING_VIRTUAL_UDP_PORT | 6271 | Compose only |
DC3_SINGLE_PORT | 8100 | Compose only |
DC3_SINGLE_GRPC_PORT | 9100 | Compose only |
DC3_WEB_HTTP_PORT | 8080 | Compose only |
DC3_WEB_HTTPS_PORT | 8443 | Compose 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
| Variable | Default | Scope |
|---|---|---|
APP_API_HOST | dc3-gateway | Compose only |
APP_API_PORT | 8000 | Compose only |
DC3_GATEWAY_OAUTH_ENABLED | false | Compose only |
DC3_GATEWAY_OAUTH_JWKS_URL | http://dc3-center-auth:8300/auth/oauth2/jwks | Compose only |
Agentic / AI (Runtime)
| Variable | Default |
|---|---|
AGENTIC_FALLBACK_OPENAI_BASE_URL | https://api.openai.com |
AGENTIC_FALLBACK_OPENAI_API_KEY | (empty) |
AGENTIC_FALLBACK_OPENAI_MODEL | gpt-4o |
AGENTIC_FALLBACK_OPENAI_TEMPERATURE | 0.7 |
AGENTIC_FALLBACK_OPENAI_MAX_TOKENS | 2048 |
AGENTIC_MEMORY_SCHEMA_INIT | never |
AGENTIC_MEMORY_ENABLED | true |
AGENTIC_MEMORY_MAX_MESSAGES | 50 |
AGENTIC_TOOL_CALLING_ENABLED | true |
AGENTIC_ATTACHMENT_STORAGE_PATH | dc3/data/agentic/attachments |
DC3_AGENTIC_MASTER_KEY | (empty) |
AGENTIC_TRANSPORT_ACQUIRE_TIMEOUT_SECONDS | 30 |
AGENTIC_TRANSPORT_GLOBAL_MAX_CONCURRENT_REQUESTS | 16 |
AGENTIC_TRANSPORT_FALLBACK_ENABLED | false |
AGENTIC_TRANSPORT_PER_TENANT_QPS | 0 |
AGENTIC_TRANSPORT_CACHE_TTL_SECONDS | 300 |
AGENTIC_CHECK_CACHE_MAXIMUM_SIZE | 256 |
AGENTIC_ATTACHMENT_ALLOWED_EXTENSIONS | png,jpg,jpeg,gif,webp,csv,txt,json,md,pdf |
AGENTIC_ATTACHMENT_TENANT_MAX_COUNT | 2000 |
AGENTIC_ATTACHMENT_TENANT_MAX_BYTES | 1073741824 |
AGENTIC_ATTACHMENT_NAME_MAX_LENGTH | 128 |
Batch Processing / Driver Lease / Images / Observability
| Variable | Default | Scope |
|---|---|---|
POINT_BATCH_SIZE | 500 | Runtime |
POINT_BATCH_RECEIVE_TIMEOUT_MILLIS | 100 | Runtime |
POINT_CONCURRENT_CONSUMERS | 4 | Runtime |
POINT_MAX_CONCURRENT_CONSUMERS | 16 | Runtime |
POINT_PREFETCH_COUNT | 1000 | Runtime |
POINT_RETRY_MAX_RETRIES | 3 | Runtime |
POINT_RETRY_INITIAL_INTERVAL_MILLIS | 1000 | Runtime |
POINT_RETRY_MULTIPLIER | 2 | Runtime |
POINT_RETRY_MAX_INTERVAL_MILLIS | 10000 | Runtime |
DC3_DRIVER_LEASE_SECONDS | 30 | Runtime |
DC3_DRIVER_LEASE_RENEW_CRON | 0/10 * * * * ? | Runtime |
DC3_DRIVER_LEASE_QUEUE_EXPIRES_MILLIS | 300000 | Runtime |
REGISTRY | auto | Compose only |
DC3_IMAGE_REGISTRY | pnoker | Compose only |
DC3_IMAGE_TAG | 2026.9 | Compose only |
DC3_BASE_TAG | 2026.10 | Compose only |
DC3_VERSION | latest | Compose only |
DC3_LOG_MAX_SIZE | 10M | Compose only |
DC3_LOG_MAX_FILE | 20 | Compose only |
DC3_BIND_HOST | 127.0.0.1 | Compose only |
GF_SERVER_ROOT_URL | http://localhost:3000 | Runtime |
DC3_GRAFANA_PORT | 3000 | Compose only |
DC3_KIBANA_PORT | 5601 | Compose only |
DC3_ES_JAVA_OPTS | -Xms512m -Xmx512m | Runtime |
DC3_LS_JAVA_OPTS | -Xms256m -Xmx256m | Runtime |
APM_AGENT_ENABLE | false | Runtime |
DC3_JAEGER_UI_PORT | 16686 | Compose only |
DC3_JAEGER_OTLP_GRPC_PORT | 4317 | Compose only |
DC3_JAEGER_OTLP_HTTP_PORT | 4318 | Compose only |
NODE_ENV | dev | Runtime |
Constraints and Common Pitfalls
- Editing
.env.exampledoes nothing at runtime — you mustcp .env.example .envfirst. dc3/env/dev.envand the root.envserve different purposes. They are not the same file; don't copy one into the other.- Use
DC3_*_PORTconsistently for service published ports. The process internals still use Spring Boot's native names such asSERVER_PORTandGRPC_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_ENVthan local source runs.
Further Reading
- Develop Locally from Source — the full path of bringing up the stack, logging in, and running your first device end to end
- Deployment Modes and Image Sources — how the whole stack starts and how to use
REGISTRY=cn