Configuration
This page lists every key the gateway reads, how compose.yaml sets them, and what lives in the data directory. It is for the person who installs and operates the gateway.
How configuration is read
The gateway is an ASP.NET Core application, so keys follow its conventions: an environment variable, with __ standing for the : of a section (EventBackbone__Url is EventBackbone:Url). On start the gateway also reads .env.local and then .env from its working directory; a value already in the process environment wins and is never overwritten. Lines starting with # are ignored and surrounding double quotes are stripped.
In Docker, compose.yaml passes a few environment variables into the container and the image's Dockerfile sets the rest as defaults. Everything is read once at start, so a change to any key below takes effect at the next restart. Nothing re-reads configuration while the gateway runs.
Gateway keys
| Key | Default | Purpose |
|---|---|---|
GATEWAY_PORT | 3000 (image: 8080) | HTTP port. The gateway listens on http://0.0.0.0:<port>. |
AUTH_BASE_URL | http://localhost:3000 | Public address. An https:// value makes the session cookie Secure; otherwise it follows the request. |
AUTH_TRUSTED_ORIGINS | (empty) | Comma-separated origins allowed to change anything or to open /sync. Empty means none, so signed-in writes get 403. |
DATA_DIR | <content-root>/data (image: /data) | SQLite database, Data Protection keys and internal data. |
DATABASE_PATH | <DATA_DIR>/scadex.db | The SQLite file. Set it only to put the database somewhere other than the data directory. |
The session cookie is named scadex.session, is HttpOnly and SameSite=Lax, and expires 7 days after sign-in without sliding. These are not configurable.
Event backbone
Section EventBackbone. NATS JetStream is the internal event timeline for tag values and metadata; the appliance runs it inside the container.
| Key | Default | Purpose |
|---|---|---|
EventBackbone__Url | nats://127.0.0.1:4222 | The NATS endpoint. |
EventBackbone__ValueRetention | 7.00:00:00 | How long tag values stay in the backbone: the window tag.replay and replays answer from without a historian. |
EventBackbone__MetadataRetention | 30.00:00:00 | How long metadata events stay replayable. |
EventBackbone__CheckpointInterval | 01:00:00 | How often every tag's last value is published as a checkpoint for replays to start from. A whole fraction of an hour. Checkpoints are kept for the value retention plus two hours. |
EventBackbone__BatchMaxCount | 256 | Most values in one published batch. |
EventBackbone__BatchMaxLatencyMs | 25 | Longest a batch waits before it is published. |
Durations are .NET TimeSpan strings: d.hh:mm:ss.
Modules
Section Modules. See Modules for what each path holds.
| Key | Default | Purpose |
|---|---|---|
Modules__Path | <app>/modules (image: /modules) | The controlled module directory. Each subfolder is one installed module; compose.yaml mounts ./.local/modules here. |
Modules__Disabled | (empty) | Comma-separated ids of installed modules not to load. They show as disabled with lockedByConfiguration, and an operator cannot start them. SCADEX_DISABLED_MODULES in compose. |
Modules__DataPath | <DATA_DIR>/modules | Each module's private data directory, <DataPath>/<module id>/. |
Modules__LicensePath | <DATA_DIR>/licenses | Where signed *.license grants are read from. |
Modules__SettingsPath | <DATA_DIR>/modules.json | Where the gateway remembers which modules an operator stopped and each module's log level. Empty keeps both in memory only. |
Modules__LogPath | <DATA_DIR>/logs/modules | One folder of rotating log files per module. Empty keeps logs in memory only. |
Modules__LogFileBytes | 2097152 (2 MB) | Size at which a module's log file rotates. Five files are kept. |
Modules__StopTimeoutSeconds | 30 | How long a module gets to stop before the gateway moves on without it. |
Modules__StartTimeoutSeconds | 120 | How long a module gets to start before the gateway gives up on it. |
Alarms
| Key | Default | Purpose |
|---|---|---|
Alarms__EventRetention | 365.00:00:00 | How long alarm lifecycle events stay in the history table. A replay asking further back shows no alarms. |
Image defaults
deploy/Dockerfile sets these in the appliance image:
| Key | Value |
|---|---|
ASPNETCORE_ENVIRONMENT | Production |
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT | false (ICU is installed for the SQL Server driver) |
ASPNETCORE_HTTP_PORTS | empty, so GATEWAY_PORT decides |
GATEWAY_PORT | 8080 |
DATA_DIR | /data |
EventBackbone__Url | nats://127.0.0.1:4222 |
Modules__Path | /modules |
The bundled NATS server reads /etc/scadex/nats-server.conf: it listens on 127.0.0.1:4222 only, stores JetStream under /data/nats/jetstream, and exposes its monitoring endpoint on 127.0.0.1:8222, inside the container only.
Compose variables
compose.yaml and compose.dev.yaml read these from .env (copy .env.example). Every value is optional.
| Variable | Default | Maps to |
|---|---|---|
SCADEX_BIND | 0.0.0.0 | The host interface the port is published on. 127.0.0.1 keeps the gateway on the loopback, for a reverse proxy or for creating the first account. |
SCADEX_PORT | 8080 | The host port, mapped to 8080 in the container. |
SCADEX_TAG | dev | The image tag of registry.gitlab.com/scadex.io/platform/gateway. |
SCADEX_MODULES | all | Build argument: the module folders built into the image (all, a list such as mqtt opcua, or empty for none). |
SCADEX_DISABLED_MODULES | (empty) | Modules__Disabled. |
AUTH_BASE_URL | http://localhost:8080 | AUTH_BASE_URL. |
AUTH_TRUSTED_ORIGINS | http://localhost:8080 | AUTH_TRUSTED_ORIGINS. |
SCADEX_DEV_DASHBOARD_PORT | 5173 | compose.dev.yaml only: host port of the Vite dev server. |
SCADEX_DEV_GATEWAY_PORT | 3000 | compose.dev.yaml only: host port of the gateway. |
COMPOSE_FILE | Layer another compose file over compose.yaml, as the repository does for its Traefik labels. |
compose.dev.yaml sets GATEWAY_PORT=3000, AUTH_BASE_URL=http://localhost:3000 and AUTH_TRUSTED_ORIGINS=http://localhost:5173 on its gateway, so the dev dashboard's origin is trusted.
Other settings live in the dashboard
Some things that look like configuration are stored in the database and changed from the dashboard, not from the environment: the project directory (Gateway > System > Project), the historian's retention (retentionDays, 90 by default, on the historian's settings), module log levels, which modules are stopped, database connections, identity providers and API keys. They survive a restart because they are in the data directory.
The data directory
DATA_DIR (/data in the container, the scadex-data volume) is the gateway's whole state. What is in it:
| Path | Holds |
|---|---|
scadex.db (with -wal and -shm) | Configuration and the current-state projection: users, sessions, tags, types, screens, alarms and their history, module state, audit rows. SQLite in WAL mode. |
keys/ | ASP.NET Data Protection keys. Module state (driver passwords included) is encrypted with them; without this folder the stored state cannot be read. Back it up with the database. |
nats/jetstream/ | The JetStream store: the recent value and metadata timeline and the checkpoints. |
modules.json | Which modules an operator stopped, and each module's log level. Delete it to forget both. |
modules/<id>/ | Each module's private data directory, such as modules/io.scadex.historian/history.db and modules/io.scadex.cron/runs.db. |
logs/modules/<id>/module.log | Each module's rotating log files, 2 MB each, newest five kept. |
licenses/ | Signed *.license grants for paid modules. Copy a grant here and restart. |
backups/ | Database backups made from Backup & restore, and the previous database kept when a staged restore is applied at start. |
certificates/, historian/, internal/ | Created by the container's entrypoint for the OPC UA stack, the historian and internal use. |
A restore staged from the dashboard is applied at the next start, before anything opens the database, and the previous file is kept under backups/. See Backup and restore.
keys/ is stored unencrypted beside the database. Encryption at rest protects a leaked scadex.db, not a copied volume. Treat the whole data directory as secret, and keep keys/ with every backup of the database.
What needs a restart
| Change | Takes effect |
|---|---|
Any environment key above (GATEWAY_PORT, AUTH_*, DATA_DIR, EventBackbone__*, Modules__*, Alarms__*) | At the next restart. |
A module dropped into /modules on disk | At the next restart, or when the module is restarted from Modules |
| A module installed, started, stopped or removed from Modules or the API | At once |
| A module's log level | At once, and remembered in modules.json |
A licence file copied to licenses/ | At the next restart; expiry is also checked only when the module loads |
| Historian retention, project directory, users, connections, screens, alarms | At once |
| Roles | On the user's next request; an open /sync socket closes within 30 seconds if its session no longer holds a known role |