Environment Variables
This document describes how to configure environment variables for working with OWOX Data Marts.
The system automatically loads configuration when starting the application with the owox serve command.
Table of Contents
Section titled “Table of Contents”Core Principles
Section titled “Core Principles”OWOX Data Marts can receive environment variables in two ways:
- From system environment - variables set directly in the runtime environment
- From configuration file - variables loaded from a
.envfile
Depending on the selected database type for the backend (DB_TYPE) and identity provider (IDP_PROVIDER), you need to set the corresponding additional environment variables:
- For
DB_TYPE=mysql- add MySQL connection variables (DB_HOST,DB_PORT,DB_USERNAME,DB_PASSWORD,DB_DATABASE) - For
IDP_PROVIDER=better-auth- add Better Auth variables (IDP_BETTER_AUTH_SECRET,IDP_BETTER_AUTH_BASE_URL, etc.) - For Report Run execution on self-managed deployments - follow Configure a Self-Managed License Key to create a LICENSE-bound key in Project Settings → License keys, match it to
PUBLIC_ORIGIN, and set it asLICENSE_KEY. Without a valid key the deployment runs asCOMMUNITY: configuration stays fully available, but Report Runs finish asRESTRICTED - For the shared Cloud deployment - provision a separate INTERNAL-bound
LICENSE_KEYthrough the deployment secret process; Project Settings never issues this key. It must be bound to the CloudPUBLIC_ORIGIN, must not carry a customer billing project, and requires the completeBALANCE_ENDPOINT_*integration. Rotate it through the same secret process and retain every old signing key until the last license it signed expires - For the Cloud deployment that issues customer license keys - set
LICENSE_ISSUANCE_ENABLED=truetogether withLICENSE_SIGNING_SERVICE_ACCOUNT_KEY_JSON(a user-managed key of the OWOX license service account, injected from the secret store) and theBALANCE_ENDPOINT_*variables. Self-managed deployments never set these
The complete list of all available environment variables is located in the .env.example file in the project root directory.
Configuration Methods
Section titled “Configuration Methods”You can configure environment variables using one of the following methods:
Option A: Through Configuration File
Section titled “Option A: Through Configuration File”By default, the owox serve command looks for a .env file in the current directory (where you run the command).
Creating Configuration File
Section titled “Creating Configuration File”Create and edit the .env file and set the values required for your configuration:
# Common variablesPORT=3030LOG_FORMAT=pretty
# DatabaseDB_TYPE=sqliteSQLITE_DB_PATH=./database/backend.db
# Identity providerIDP_PROVIDER=noneRunning the Application
Section titled “Running the Application”Various ways to specify the path to the file:
# 1. If .env is in the current directoryowox serve
# 2. If .env is in another location - via flagowox serve --env-file /path/to/.envowox serve -e /path/to/.envOption B: Through Docker/Containers
Section titled “Option B: Through Docker/Containers”When using containers, environment variables are passed from outside the container inside through the corresponding platform mechanisms (Docker, Kubernetes, etc.).
🐳 Containers: Environment variables are set outside the container and passed inside during startup. Inside the container, the application sees them as regular environment variables.
Option C: Through Hosting Platform
Section titled “Option C: Through Hosting Platform”Most hosting platforms provide their own interface for setting environment variables. Usually it’s an “Environment Variables” or “Config Vars” section in project settings.
Option D: Through Command Line Arguments
Section titled “Option D: Through Command Line Arguments”Some environment variables can be configured directly through command line arguments. This option provides the highest priority for configuration:
# Using command line arguments (highest priority)owox serve --port 3030 --log-format json
# Combined with environment fileowox serve --env-file .env.production --port 3030⚠️ Limited scope: Only a limited set of variables can be configured through command line arguments. Currently supported:
PORT(via--port) andLOG_FORMAT(via--log-format). For other variables, use environment files or system environment variables.
Option E: Through Environment Variables
Section titled “Option E: Through Environment Variables”Set environment variables directly before running the command:
# Linux/macOS/Windows (Git Bash)DB_TYPE=sqlite SQLITE_DB_PATH=./database/backend.db IDP_PROVIDER=none owox serve
# Windows (Command Prompt)set DB_TYPE=sqlite && set SQLITE_DB_PATH=./database/backend.db && set IDP_PROVIDER=none && owox serve
# Windows (PowerShell)$env:DB_TYPE="sqlite"$env:SQLITE_DB_PATH="./database/backend.db"$env:IDP_PROVIDER="none"owox serveEnvironment Loading Priority
Section titled “Environment Loading Priority”This section describes the internal logic of the environment variable loading system. Understanding this order will help you configure the correct setup and diagnose problems.
The system loads environment variables in the following priority order (highest to lowest):
1. Command Line Arguments (Highest Priority)
Section titled “1. Command Line Arguments (Highest Priority)”Variables specified through command line arguments override all other sources:
owox serve --port 3030 --log-format json⚠️ Note: Only
--portand--log-formatare currently supported as command line arguments.
2. System Environment Variables
Section titled “2. System Environment Variables”Variables set directly in the runtime environment (system environment variables or variables set through hosting platform interfaces).
3. Explicitly Specified Environment File
Section titled “3. Explicitly Specified Environment File”When you specify a path to a configuration file via --env-file:
owox serve --env-file /path/to/.env.production4. Default .env File
Section titled “4. Default .env File”If no environment file is explicitly specified, the system looks for a .env file in the current directory:
owox serve5. Default Values (Lowest Priority)
Section titled “5. Default Values (Lowest Priority)”If variables are not set through any of the above methods, the system uses default values:
PORT=3000LOG_FORMAT=prettyPriority Example
Section titled “Priority Example”Example demonstrating priority:
# All these sources can provide PORT value:# 1. Command line argument (highest priority): --port 3030# 2. System environment: export PORT=3010# 3. Explicitly specified file: PORT=3020 in custom.env# 4. Default .env file: PORT=3000# 5. Default value: PORT=3000 (lowest priority)
owox serve --env-file custom.env --port 3030# Result: PORT=3030 (from command line argument)Public URLs
Section titled “Public URLs”-
PUBLIC_ORIGIN: Base public URL of the application (scheme + host [+ optional port]).
- Examples:
http://localhost:3000,https://data-marts.example.com - Default:
http://localhost:${PORT} - In production, set this to your actual deployment URL.
- For a licensed self-managed deployment, it must match the Public origin of the configured license key.
- Examples:
-
LOOKER_STUDIO_DESTINATION_ORIGIN: Public origin used to generate the deployment URL for the Data Studio Destination.
- If empty, it falls back to
PUBLIC_ORIGIN. - Example:
https://looker.example.com
- If empty, it falls back to
-
MCP_DYNAMIC_CLIENT_ALLOWED_REDIRECT_ORIGINS: Comma-separated HTTPS origins allowed as OAuth redirect targets for dynamic MCP clients.
- Loopback HTTP redirects for desktop/CLI clients are always allowed.
- Example for Claude web:
https://claude.ai - Default: empty.
-
MCP_PUBLIC_BASE_URL: Public origin of the shared hosted MCP server.
- Example:
https://mcp.owox.com MCP_OAUTH_RESOURCEdefaults to${MCP_PUBLIC_BASE_URL}/mcpwhen not set.- Project-specific MCP URLs are derived from this value. For
MCP_PUBLIC_BASE_URL=https://mcp.owox.com, the project URL format ishttps://{projectId}.mcp.owox.com/mcp. - Do not configure a separate project-domain environment variable. The deployment must route both
mcp.owox.comand*.mcp.owox.comto the same MCP backend and preserveHost,X-Forwarded-Host, andX-Forwarded-Proto.
- Example:
- CORS_ALLOWED_HEADERS: Additional comma-separated request headers allowed by the
API CORS configuration.
- The values are added to the default allowed headers:
content-type,authorization,x-owox-authorization. - Example for local tunnels or proxies:
CORS_ALLOWED_HEADERS=ngrok-skip-browser-warning,x-custom-header
- The values are added to the default allowed headers:
MySQL SSL
Section titled “MySQL SSL”DB_MYSQL_SSL, IDP_BETTER_AUTH_MYSQL_SSL, IDP_OWOX_MYSQL_SSL enable TLS for MySQL (mysql2). Supported formats:
-
Boolean-like (strings)
true→{}(enable TLS with default options:rejectUnauthorized: true)falseor empty → nosslfield (TLS disabled)
-
JSON object (forwarded to mysql2 TLS options)
- Strict CA verification:
{"rejectUnauthorized": true}
- Custom CA bundle (inline PEM):
{"rejectUnauthorized": true, "ca": "-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n"}
- Mutual TLS (client cert + key):
{"rejectUnauthorized": true, "cert": "-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----\\n", "key": "-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n"}
- Minimum TLS version (TLS 1.2):
{"minVersion": "TLSv1.2", "rejectUnauthorized": true}
- Strict CA verification:
See also: mysql2 official SSL documentation — https://sidorares.github.io/node-mysql2/docs/documentation/ssl
Connectors
Section titled “Connectors”Ads connectors can resolve short links in landing URL fields to the address their service points to.
Resolution runs only for known short link services (bit.ly, tinyurl.com, t.co, lnkd.in,
youtu.be, amzn.to, ow.ly, buff.ly, cutt.ly, is.gd, rebrand.ly) and for
the domains you list here. Links on other domains stay unchanged. In OWOX Cloud, OWOX manages
this value; contact support to add a domain.
| Variable | Purpose |
|---|---|
CONNECTOR_SHORT_LINK_DOMAINS | Comma-separated domains of your own short link services, for example links.example.com. Subdomains match too. Empty by default. |
Plugins
Section titled “Plugins”Plugins are third-party web apps embedded in a sandboxed iframe. These variables control who may publish them and how OWOX Data Marts reads their GitHub sources.
| Variable | Purpose |
|---|---|
OWOX_DEPLOYMENT_PLUGIN_PUBLISHER_API_KEY_IDS | Comma-separated API key IDs allowed to publish, suspend and resume plugins for the whole deployment. |
GITHUB_TOKEN | Read-only, fine-grained PAT for reading private plugin repositories. Self-managed deployments. |
GITHUB_APP_ID, GITHUB_APP_SLUG, GITHUB_APP_PRIVATE_KEY | OWOX Data Marts GitHub App credentials, for reading private repositories in the cloud. Required together. The key takes the whole PEM with newlines as \n, or just its base64 body with the BEGIN/END lines stripped when a secret store mangles the armour. |
GITHUB_API_BASE_URL | GitHub REST base URL. Override only for GitHub Enterprise. |
PLUGIN_HOST_SYNC_MIN_INTERVAL_SEC | Optional minimum seconds between two synchronizations of the same plugin. Defaults to 30 with GitHub App or server-token access and 300 with anonymous access. An explicit value overrides every access mode. During the cooldown, publishing reuses the last validated version. |
PLUGIN_HOST_REMOTE_PROBE_TIMEOUT_MS | Timeout for probing a plugin’s delivery URL. Default 8000. |
Plugin collections database
Section titled “Plugin collections database”Plugin JSON collections use a named database connection. With no additional variables it
falls back option-by-option to the main DB_* configuration (and to SQLITE_DB_PATH for
SQLite), which is the recommended local and self-hosted setup. A Cloud deployment can isolate
this data in a separate MySQL instance by setting the variables below.
| Variable | Fallback |
|---|---|
PLUGIN_COLLECTIONS_DB_TYPE | DB_TYPE |
PLUGIN_COLLECTIONS_SQLITE_DB_PATH | SQLITE_DB_PATH / default app path |
PLUGIN_COLLECTIONS_DB_HOST | DB_HOST |
PLUGIN_COLLECTIONS_DB_PORT | DB_PORT |
PLUGIN_COLLECTIONS_DB_USERNAME | DB_USERNAME |
PLUGIN_COLLECTIONS_DB_PASSWORD | DB_PASSWORD |
PLUGIN_COLLECTIONS_DB_DATABASE | DB_DATABASE |
PLUGIN_COLLECTIONS_DB_MYSQL_SSL | DB_MYSQL_SSL |
Blank override values count as absent. The collection connection has its own migration table,
and RUN_MIGRATIONS applies pending migrations to both databases. Migration status also checks
both by default. A down migration targets only the main database by default; set
MIGRATIONS_DATA_SOURCE=pluginCollections when intentionally reverting the latest collection
migration. MIGRATIONS_DATA_SOURCE=all is rejected for down migrations because the two histories
advance independently.
The publisher allowlist is the authorization model for deployment-scope publishing — it stands in for an administration panel that is deliberately not built. An unset or blank value denies everyone; it never means “any key”. A Project Admin without an allowlisted key can still publish to their own project, and any member can publish for themselves.
A vendor may name your origin in a Content-Security-Policy: frame-ancestors directive
instead of allowing * or https:. The origin compared against is PUBLIC_ORIGIN, the
same value the rest of the deployment uses — the page that embeds a plugin is served from
it, so a plugin-specific copy could only drift away from the real one.
GitHub access falls back in order: App installation token, then GITHUB_TOKEN, then
anonymous. Public repositories need no credential at all, and an App configured but not
installed on a given public repository does not block it.
See the plugin authoring guide for what this means on the plugin side.
Connector execution limits
Section titled “Connector execution limits”These variables bound the cost of running and testing custom (no-code) connectors. All three are validated at startup: a value that is not a whole number inside the stated range stops the application with a configuration error instead of being silently ignored.
| Variable | Purpose |
|---|---|
MAX_CONNECTOR_TESTS_PER_PROJECT | Concurrent live connector tests (POST /connectors/custom/test) a single project may run. Default 3, range 1–1000. Mirrors MAX_CONNECTOR_RUNS_PER_PROJECT, which bounds the same class of work for scheduled runs. |
MAX_CONNECTOR_TESTS_TOTAL | Concurrent live connector tests across all projects on one instance. Default 10, range 1–1000. See the per-instance note below. |
CONNECTOR_RUN_LOG_FLUSH_INTERVAL_MS | How often a running connector flushes its accumulated logs and errors to the database, in milliseconds. Default 2000, range 0–3600000. 0 disables incremental streaming, so logs are written once when the run ends. |
MAX_CONNECTOR_TESTS_TOTAL is a per-instance limit, not a deployment-wide one — the name
does not convey this. Each replica counts only the tests it is running itself and knows nothing
about its peers, so a deployment of N replicas admits up to MAX_CONNECTOR_TESTS_TOTAL x N
connector tests at once. Size the value against what one replica can carry, then multiply by the
replica count to get the real ceiling on the backing host and on the upstream APIs being called.
Each test spawns a real Node child process that drives outbound HTTP to a host the manifest author controls, so both caps bound processes in flight rather than requests per second. The per-project cap keeps one project from taking a whole instance; the total cap keeps many projects from doing together what none of them can do alone.
A blank value for any of these three means its default, so a key templated to an empty string leaves streaming on and the caps at their defaults.
Lowering CONNECTOR_RUN_LOG_FLUSH_INTERVAL_MS increases database write volume for the entire
duration of every connector run, because each flush rewrites the run’s whole log and error
buffer. Raise it, or set 0, on deployments where run logs matter less than database load.
Troubleshooting
Section titled “Troubleshooting”Checking Variable Loading
Section titled “Checking Variable Loading”The system outputs detailed messages about the loading process to help you understand what’s happening during environment setup:
owox serve --env-file .env.productionExpected success messages:
📂 Using specified environment file: .env.production🔄 Starting to process environment file: .env.production✅ Set 5 variables✨ Environment file processed successfully
Expected file path resolution messages:
📂 Using specified environment file: /path/to/.env.production(when--env-fileis specified)⚙️ Using default environment file: /current/directory/.env(default fallback)
Expected file processing messages:
🔄 Starting to process environment file: .env.production✅ Set 5 variables⏭️ Skipped 2 existing variables: PORT (already exists), LOG_FORMAT (already exists)🗑️ Ignored 1 invalid variables: EMPTY_VAR (empty string value)✨ Environment file processed successfully
Common Errors
Section titled “Common Errors”File Not Found
Section titled “File Not Found”🔍 Environment file not found: /path/to/.env.productionSolution: Check the correctness of the file path and ensure the file exists.
File Reading Error
Section titled “File Reading Error”📖 Failed to read file /path/to/.env: ENOENT: no such file or directorySolution: Verify file permissions and path accessibility.
Parsing Error
Section titled “Parsing Error”💥 Empty content or failed to parse environment file: /path/to/.envSolution: Check the syntax of the .env file and ensure it’s not empty. The file should contain valid KEY=value pairs.
Variables Not Loading
Section titled “Variables Not Loading”🔍 Environment file not found: /current/directory/.env🚫 Failed to process environment fileSolution:
- Create a
.envfile in the root directory - Specify the correct path via
--env-file - Set variables directly in the environment (without using a file):
- Via environment variables:
PORT=3030 DB_TYPE=sqlite owox serve - Via hosting platform environment variables interface
- Via system environment variables
- Via environment variables:
Debug Tips
Section titled “Debug Tips”Common Variable Issues
Section titled “Common Variable Issues”When variables are ignored or skipped, the system provides specific reasons:
EMPTY_VAR (empty string value)- Variable has no value after trimmingINVALID_KEY (invalid key)- Key is empty or contains only whitespaceUNDEFINED_VAR (undefined/null value)- Variable is undefined or nullPORT (already exists)- Variable already exists and override is disabled