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.)
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.
- 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
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.
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