Configuration
Farna Control is configured through environment variables. In a development checkout they live in a .env file in the backend/ directory; the Docker Compose and Helm installs set the same variables through their compose files and chart values. The tables below name each variable regardless of how it is supplied.
Required
| Variable | Description |
|---|---|
DATABASE_URL |
Async database connection string |
SECRET_KEY |
At least 32 bytes, used for JSON Web Token (JWT) signing. Known placeholder values are rejected at startup. |
FERNET_KEY |
Fernet-compatible key for credential encryption |
Database
DATABASE_URL=postgresql+asyncpg://user:password@host:5432/modulo
By default, the Docker Compose setup publishes PostgreSQL on port 5432. The development Compose file (docker-compose.local.yml) also publishes it on port 5434, so use 5434 there when a local PostgreSQL server already occupies 5432.
MODULO_DB selects the backend and defaults to postgres. The accepted values are postgres, sqlite, mariadb, and mysql; MariaDB and MySQL use the aiomysql driver. Choosing sqlite disables the PostgreSQL-specific security features (row-level security, advisory locks, and flood protection), so tenant isolation falls back to filtering in the object-relational mapping (ORM) layer. See Database Abstraction for what each backend supports.
Authentication
# Static users for local development (comma-separated, user:pass format)
MODULO_USERS=admin:admin,dev:dev
Credential encryption
# Generate your own. Do not use the example key in production.
FERNET_KEY=replace-with-your-generated-key
Generate one:
python3 -c "import base64, os; print(base64.urlsafe_b64encode(os.urandom(32)).decode())"
The output is a 32-byte key, URL-safe base64 encoded. The command needs only the Python standard library.
Public URL and licensing
These settings tell Farna Control how it is reached and which features are unlocked:
| Variable | Description |
|---|---|
MODULO_PUBLIC_URL |
The externally reachable base URL of your instance. Farna Control builds absolute links from it: OpenID Connect (OIDC) callback URLs, Model Context Protocol (MCP) server URLs, and the run links in human-in-the-loop (HITL) webhook payloads. Defaults to http://localhost:8000; set it to your instance’s public host before exposing Farna Control beyond local use. |
MODULO_LICENSE_KEY |
A Team-tier license key. It unlocks the paid feature gates, such as Single Sign-On and System for Cross-domain Identity Management (SCIM) provisioning. Leave it unset in the Community tier. |
MODULO_LICENSE_PUBLIC_KEY |
The Ed25519 public key (64 hex characters) that verifies your license key. This is the trust anchor, and it is required in production. Set it to the public key Farna Labs issued with your license. The built-in default is the public half of the development keypair, which is trusted only in debug and cannot verify a Farna Labs-issued production license. |
MODULO_LICENSE_PRIVATE_KEY |
The Ed25519 private key (hex) Farna Control uses to sign the license keys it issues. Leave it unset unless you issue licenses yourself; an unset value disables issuance. |
A Farna Labs-issued license can only verify against the public key Farna Labs issued with it. If you set MODULO_LICENSE_KEY on an instance with debug off and leave MODULO_LICENSE_PUBLIC_KEY unset, the instance refuses to start and names the missing variable, rather than booting on the Community tier. If you install a license at runtime while only the development key is available, the request fails with 422 and "reason": "anchor_mismatch" in the response body.
MODULO_FRONTEND_URL overrides where the browser lands after login and defaults to MODULO_PUBLIC_URL; you only need it when the frontend is served from a different origin than the API. See Single Sign-On.
Connectors
Connector credentials are configured per connector instance in the Connector Hub (for example, a GitHub personal access token), not through environment variables. See Connectors for example configurations and Secrets for how credentials are handled.
CORS (Cross-Origin Resource Sharing)
CORS_ORIGINS=http://localhost:5173,https://modulo.run
Logging
MODULO_LOG_LEVEL=INFO
Log output is always structured JSON, so there is no format setting. MODULO_LOG_LEVEL sets the global level and defaults to INFO. To change one module only, set a per-module override named MODULO_LOG_LEVEL_<MODULE>, with dots replaced by underscores. For example, MODULO_LOG_LEVEL_MODULO_CONNECTORS=DEBUG raises the level for modulo.connectors alone, and takes precedence over the global value.
OpenTelemetry
Telemetry is off by default. Set MODULO_TELEMETRY_ENABLED=true to turn it on.
MODULO_TELEMETRY_ENABLED=true
# OTLP (OpenTelemetry Protocol) collector endpoint
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
# Service name reported in the telemetry; defaults to "Farna Control"
MODULO_OTEL_SERVICE_NAME=modulo
When telemetry is enabled, spans always export to stdout for local debugging. The OpenTelemetry Protocol (OTLP) exporter is added only when OTEL_EXPORTER_OTLP_ENDPOINT is set, so leaving that variable unset keeps tracing on stdout without sending anything off the host. On the Team tier, an administrator can also toggle telemetry at runtime through the runtime config store, without a restart. On Community, change the environment variable and restart.
Redis
REDIS_URL=redis://localhost:6379/0
Redis is required. Farna Control uses it for event coordination, rate limiting, caching, and session state, so an empty REDIS_URL fails startup with an explicit error rather than degrading to a reduced feature set. The variable defaults to redis://localhost:6379/0, so a local Redis on the default port needs no configuration.
The default docker-compose.yml publishes Redis on port 6379. The development Compose file (docker-compose.local.yml) publishes it on port 6380.
Within Redis, Farna Control uses a WebSocket event broker for live run-event streaming and a run event ring buffer for recent event replay after a reconnect.
Feature-specific settings
The variables below configure one feature each, so they are documented in full where that feature lives. They are set in the same .env file as the settings above.
| Variable | What it sets | Documented in |
|---|---|---|
MODULO_MAX_LOCAL_CONCURRENCY |
Concurrent agent subprocesses for the local runtime provider (default 2) |
Execution Environments, Concurrency and capacity sizing |
MODULO_DOCKER_HOST (or DOCKER_HOST) |
The Docker engine the runner_docker provider connects to |
Execution Environments |
MODULO_E2B_API_KEY |
Registers the E2B runtime provider | Execution Environments |
MODULO_RUNNER_MACHINE_ID |
Distinguishes two deployments that share one Docker engine | Execution Environments |
MODULO_KUBERNETES_ENABLED, MODULO_KUBERNETES_NAMESPACE, MODULO_KUBERNETES_SERVICE_ACCOUNT |
Register and scope the Kubernetes runtime provider | Kubernetes |
MODULO_SCHEMA_VALIDATOR_MODE |
First-boot seed for the schema validation mode: lenient (default) or strict |
Bring Your Own Agent |
MODULO_SCIM_TOKEN |
The bearer token SCIM provisioning requests authenticate with | SCIM Provisioning |
MODULO_SSO_DEFAULT_ROLE |
Role granted to a user provisioned through SSO (default runner) |
Single Sign-On (SSO) |
MODULO_SAML_IDP_METADATA_URL, MODULO_SAML_IDP_METADATA_XML |
Security Assertion Markup Language (SAML) identity provider (IdP) metadata for the legacy single-tenant SAML endpoints | Single Sign-On (SSO) |
SAQ_WORKER_CONCURRENCY, SAQ_REDIS_POOL_SIZE, SAQ_WORKER_DB_POOL_SIZE |
Worker throughput and the database and Redis connection pools each worker holds | Concurrency and capacity sizing |
TRIGGER_BACKPRESSURE_MAX_AGE_SECONDS |
Age at which the trigger backpressure guard refuses new fires (default 3600) | Concurrency and capacity sizing |
DB_CAPACITY_BYTES, DB_CAPACITY_PATH, DB_CAPACITY_HARD_STOP_PCT |
Database storage guard thresholds | Concurrency and capacity sizing |
Related
- Connectors: tool integrations for pipeline nodes
- Cost Management: token spend tracking and limits
- SCIM Provisioning: user and group lifecycle management
- Secrets: how the signing and encryption keys protect stored credentials