Environment variables
Every deployment variable for Lunnoa Automate, what it controls, and whether it is required.
Use this page when you self-host Lunnoa Automate and need to know which variable steers what. Values live in a single .env file at the repository root for Docker Compose and local pnpm runs, or in your orchestrator's secret store for production.
Where variables are defined
| Artifact | Role |
|---|---|
.env.example | Local and UAT template with comments |
.env.prod.example | Production template (SigNoz, OpenConnector, compose overrides) |
docker-compose*.yml | Injects service URLs (DATABASE_URL, REDIS_HOST, S3_ENDPOINT, WEAVIATE_URL, DOCLING_URL, OPEN_CONNECTOR_BASE_URL, …) inside Docker networks |
Generate a starter .env with random secrets:
Put server and sidecar secrets in that one .env (or secret store). UI VITE_* values are set at image build time, not in the server runtime env. For email, object storage, OAuth apps, SSO, and OpenTelemetry export, prefer Admin Space when a database config exists; it overrides matching env vars.
Required server variables
The server refuses to start without these. CRYPTO_ENCRYPTION_KEY must be exactly 32 characters. FEATHERLESS_API_KEY must be non-empty.
| Variable | Controls | Example |
|---|---|---|
ENVIRONMENT | development or production. Affects OAuth callbacks, S3 paths, knowledge namespaces, email behaviour | production |
DATABASE_URL | PostgreSQL connection string (Prisma) | postgresql://user:pass@host:5432/lunnoa?schema=public |
SERVER_URL | Public API base URL (OAuth callbacks, webhooks) | https://automate.example.com |
CLIENT_URL | UI origin (CORS, links in emails) | https://automate.example.com |
PORT | HTTP listen port inside the server container | 9094 |
AUTH_JWT_SECRET | Signs session JWTs | long random string |
APP_OAUTH_CALLBACK_STATE_SECRET | Encrypts OAuth state parameters | long random string |
CRYPTO_ENCRYPTION_KEY | Encrypts stored connection secrets (32 chars) | 32-character key |
FEATHERLESS_API_KEY | Bootstraps default Lunnoa LLMs connection; new agents default to DeepSeek on this provider | API key from Featherless |
Core platform (optional)
| Variable | Required | Default | What it steers |
|---|---|---|---|
PLATFORM_NAME | No | Lunnoa Automate | White-label name in the UI |
CORS_ALLOWED_ORIGINS | No | — | Comma-separated extra browser origins for custom portals (Pattern B in the Public API). CLIENT_URL is always allowed |
API_KEYS_ENABLED | No | true | Master switch for lna_ machine API keys. Set false to reject all API keys |
AUTH_DISABLED_METHODS | No | — | Comma-separated: password, google. SuperAdmins can always use password (break-glass) |
NGROK_TUNNEL_URL | No | — | Local dev tunnel for OAuth and webhooks when ENVIRONMENT=development |
NEW_USER_WORKFLOW_ID | No | — | Workflow (with webhook trigger) to run after signup |
CRON_TRIGGER_POLLING_INTERVAL | No | 5 min cron | How often polling triggers are checked |
DEV_EMAIL_DOMAIN | No | @lunnoalabs.ch | Dev-only email domain for test endpoints |
Database and Redis
| Variable | Required | Default | What it steers |
|---|---|---|---|
POSTGRES_DB | Compose / setup script | lunnoa | Database name (compose builds DATABASE_URL) |
POSTGRES_USER | Compose / setup script | — | Database user |
POSTGRES_PASSWORD | Compose / setup script | — | Database password |
POSTGRES_HOST | Local pnpm only | localhost | Host for setup-env script |
POSTGRES_PORT | Local pnpm only | 5435 | Host port mapped to Postgres |
REDIS_HOST | No | localhost | BullMQ job queue (workflows, agent turns) |
REDIS_PORT | No | 6379 | Redis port |
REDIS_PASSWORD | No | — | Redis auth (set in prod compose) |
REDIS_TLS_ENABLED | No | false | TLS for Redis connections |
Redis is required for parallel workflow execution and resumable agent chat streams.
Object storage (S3-compatible)
Used for profile images, workspace logos, knowledge uploads, and temporary workflow files. Super Admin → Object Storage overrides these when an active verified config exists.
| Variable | Required | Default | What it steers |
|---|---|---|---|
S3_ACCESS_KEY_ID | No* | — | S3 access key (*optional on AWS ECS with IAM role) |
S3_SECRET_ACCESS_KEY | No* | — | S3 secret key |
S3_REGION | For Knowledge | — | AWS region |
S3_BUCKET_ID | For Knowledge | — | Bucket name |
S3_ENDPOINT | No | AWS default | Custom endpoint (MinIO, R2, …). Compose sets http://minio:9000 |
S3_FORCE_PATH_STYLE | No | false | Set true for MinIO and many S3-compatible stores |
S3_PUBLIC_BASE_URL | No | — | Public CDN or custom domain prefix for readable uploads |
MINIO_ROOT_USER | Compose only | minioadmin | MinIO admin user (maps to S3_ACCESS_KEY_ID in compose) |
MINIO_ROOT_PASSWORD | Compose only | minioadmin | MinIO admin password |
GCP_STORAGE_* env vars are no longer read by the server. Configure Google Cloud Storage in Admin Space instead.
Knowledge (vector store)
Knowledge needs storage (S3 env or Admin Space storage) and Weaviate.
| Variable | Required | Default | What it steers |
|---|---|---|---|
WEAVIATE_URL | For Knowledge | — | Weaviate HTTP endpoint. Compose: http://weaviate:8080 |
WEAVIATE_GRPC_URL | For Knowledge | — | gRPC host:port (no scheme). Compose: weaviate:50051 |
WEAVIATE_API_KEY | No | — | Auth when anonymous access is disabled |
WEAVIATE_COLLECTION_NAME | No | Knowledge | Deprecated. Each notebook gets its own collection |
Legacy Pinecone (PINECONE_API_KEY, PINECONE_INDEX_NAME) is retained in config but Weaviate is the supported path.
AI providers
| Variable | Required | Default | What it steers |
|---|---|---|---|
FEATHERLESS_API_KEY | Yes | — | Default platform LLM connection at boot |
OPENAI_API_KEY | No | — | OpenAI actions and embeddings when configured |
ANTHROPIC_API_KEY | No | — | Anthropic models |
GEMINI_API_KEY | No | — | Google Gemini models |
OLLAMA_BASE_URL | No | http://127.0.0.1:11434/api | Local Ollama endpoint |
DEFAULT_LLM_PROVIDER | No | openai | Fallback provider label for AI actions |
DEFAULT_LLM_MODEL | No | gpt-4o | Fallback model name |
DEFAULT_EMBEDDING_PROVIDER | No | openai | Embedding provider for legacy paths |
DEFAULT_EMBEDDING_MODEL | No | text-embedding-3-small | Embedding model name |
Workspace admins can add more AI connections in the UI. FEATHERLESS_API_KEY is still mandatory at boot to provision the global default.
Document parsing (Docling)
| Variable | Required | Default | What it steers |
|---|---|---|---|
DOCLING_URL | No | — | Docling serve base URL. Compose sets http://docling:5001. Empty disables the Document Parser |
DOCLING_API_KEY | No | — | X-Api-Key header when Docling auth is enabled |
Long-tail integrations
First-party apps are always on. These variables are optional. They add Pipedream and/or OpenConnector catalogues for MCP, workflow actions, and triggers. If a provider is unset or credentials are incomplete, the server logs a warning and treats that surface as none. The rest of the platform keeps running.
Provider switches
| Variable | Required | Default | What it steers |
|---|---|---|---|
LUNNOA_MCP_PROVIDER | No | pipedream if Pipedream creds exist, else none | MCP catalogue: none, pipedream, open_connector |
LUNNOA_ACTION_PROVIDER | No | none | Workflow action catalogue: none, pipedream, open_connector |
LUNNOA_TRIGGER_PROVIDER | No | none | Workflow triggers (pipedream or none only; OpenConnector has no triggers) |
Pipedream (cloud)
| Variable | Required | Default | What it steers |
|---|---|---|---|
PIPEDREAM_CLIENT_ID | When provider is pipedream | — | Pipedream Connect OAuth client |
PIPEDREAM_CLIENT_SECRET | When provider is pipedream | — | Pipedream Connect secret |
PIPEDREAM_PROJECT_ID | When provider is pipedream | — | Pipedream project ID |
PIPEDREAM_ENVIRONMENT | No | development | Pipedream environment slug |
OpenConnector (self-hosted sidecar)
OpenConnector is included in docker-compose.local.yml, docker-compose.yml, docker-compose.uat.yml, and docker-compose.prod.yml. It does not replace other sidecars (Postgres, Redis, MinIO, Weaviate, Docling, SigNoz). Only the Lunnoa server talks to it.
Put these in the same .env as the server. Compose maps OPEN_CONNECTOR_* into the server and into the open-connector container as OOMOL_CONNECT_*.
| Variable | Required | Default | What it steers |
|---|---|---|---|
OPEN_CONNECTOR_BASE_URL | When provider is open_connector | Compose: http://open-connector:3000 | Sidecar origin for the Lunnoa server. On the Docker network you usually omit this from .env; compose injects the default. Override only if OC runs elsewhere |
OPEN_CONNECTOR_RUNTIME_TOKEN | When provider is open_connector | — | Bearer token for MCP and action runtime calls (oct_… or a bootstrap secret). You generate it (see below) |
OPEN_CONNECTOR_ADMIN_TOKEN | For catalog sync / admin API | — | Protects OC admin API and console. You invent a strong secret and set it before start |
OOMOL_CONNECT_ENCRYPTION_KEY | OpenConnector container | — | AES-256-GCM key for credentials stored by OC. Sidecar only; Lunnoa does not read this key. Generate a long random secret and keep it stable |
Example for UAT or production when you enable OpenConnector:
LUNNOA_MCP_PROVIDER=open_connector
LUNNOA_ACTION_PROVIDER=open_connector
LUNNOA_TRIGGER_PROVIDER=none
# OPEN_CONNECTOR_BASE_URL optional when using compose (defaults to http://open-connector:3000)
OPEN_CONNECTOR_RUNTIME_TOKEN=
OPEN_CONNECTOR_ADMIN_TOKEN=
OOMOL_CONNECT_ENCRYPTION_KEY=Local debug console (local compose only): http://localhost:3100. UAT and prod keep OC on the internal Docker network only.
Web search, scraping, and voice
| Variable | Required | What it steers |
|---|---|---|
SERPER_API_KEY | No | Google search for agents and workflows (WEB_SEARCH feature flag) |
APIFY_API_KEY | No | Website extraction (Apify) |
APIFY_EXTRACT_DYNAMIC_CONTENT_TASK_ID | No | Apify task for dynamic pages (WEB_EXTRACTION_DYNAMIC) |
APIFY_EXTRACT_STATIC_CONTENT_TASK_ID | No | Apify task for static pages (WEB_EXTRACTION_STATIC) |
VAPI_API_KEY | No | AI phone calls (CALLING feature flag) |
Runtime app installation
| Variable | Required | Default | What it steers |
|---|---|---|---|
PLUGINS_DIR | No | /data/plugins | Writable directory for npm-installed integration apps |
APP_REGISTRY_ALLOWLIST | No | empty | Comma-separated registry URLs or scopes (@lunnoa/*). Empty disables runtime install |
APP_REGISTRY_TOKEN | No | — | npm _authToken for private registries |
Jobs dashboard (SuperAdmin)
| Variable | Required | Default | What it steers |
|---|---|---|---|
JOBS_DASHBOARD_ENABLED | No | true | BullMQ UI at /api/admin/jobs |
JOBS_DASHBOARD_ALLOW_MUTATIONS | No | false | Retry, promote, remove buttons |
JOBS_DASHBOARD_REDACT_PAYLOADS | No | true | Mask secrets in job payloads |
JOBS_DASHBOARD_SHOW_AGENT_PROMPTS | No | false | Show full agent message content (staging only) |
HTTP and agent worker tuning
| Variable | Required | Default | What it steers |
|---|---|---|---|
SERVER_REQUEST_TIMEOUT_MS | No | 1200000 | Max HTTP request duration (20 min) |
KEEP_ALIVE_TIMEOUT_MS | No | 1210000 | Node keep-alive timeout |
HEADERS_TIMEOUT_MS | No | 1215000 | Node headers timeout |
AGENT_WORKER_CONCURRENCY | No | 10 | Parallel agent turn workers |
AGENT_TURN_MAX_MS | No | 600000 | Max duration per agent turn |
AGENT_TOOL_OUTPUT_MAX_CHARS | No | built-in limit | Truncate tool output sent back to the model |
TASK_RUN_STREAM_ATTACH_TIMEOUT_MS | No | 60000 | Timeout attaching to a running stream |
CHAT_RESUMABLE_STREAMS | No | enabled | Set false to disable Redis-backed stream resume |
CHAT_STREAM_CHUNK_DEBUG | No | off | Verbose SSE chunk logging |
CHAT_STREAM_CHUNK_DEBUG_VERBOSE | No | off | Extra verbose chunk logging |
DEBUG_LOG_SYSTEM_PROMPT | No | off | Log agent system prompts (never in prod) |
AWS Parameter Store (cloud deployments)
| Variable | Required | What it steers |
|---|---|---|
PARAM_STORE_ACCESS_KEY | When using SSM | AWS access key |
PARAM_STORE_SECRET_ACCESS_KEY | When using SSM | AWS secret key |
PARAM_STORE_REGION | When using SSM | AWS region |
When all three are set, the server loads /{ENVIRONMENT}/server-core/* from Parameter Store. Local .env still supplies keys missing from SSM (typical for dev integration secrets).
UI build-time variables (VITE_*)
Set these when building the UI image or running pnpm locally. They are not read by the server.
| Variable | Required | Default | What it steers |
|---|---|---|---|
VITE_CLIENT_URL | Local dev | http://localhost:5173 | Where the browser thinks the UI lives |
VITE_SERVER_URL | Local dev | http://localhost:9094 | API origin for fetch and SSE. Leave empty in prod when nginx proxies /api same-origin |
VITE_ENABLE_ANALYTICS | No | off | Vercel Analytics in the UI bundle |
VITE_ENABLE_BROWSER_OTEL | No | off | Browser OpenTelemetry traces |
VITE_OTEL_EXPORTER_OTLP_ENDPOINT | When browser OTEL on | /otlp in dev | OTLP HTTP endpoint for UI traces |
VITE_OTEL_SERVICE_NAME | No | lunnoa-automate-ui | Service name in traces |
VITE_MOCK_API_CALLS | No | off | Mock API layer (local dev only) |
VITE_LOG_API_CALLS | No | off | Console-log API calls (local dev only) |
Production UI images are built in CI with PROD_CLIENT_URL and PROD_SERVER_URL GitHub repository variables (see .github/workflows/deploy-ui-container.yml), not from the server .env.
Observability stack (SigNoz compose only)
| Variable | Required | What it steers |
|---|---|---|
SIGNOZ_JWT_SECRET | Prod/UAT SigNoz stack | SigNoz UI authentication |
Server-side trace export is configured in Admin Space → Observability, not via OTEL_* env vars on the server.
Configure in Admin Space instead of env
These capabilities do not need (or no longer accept) deployment env vars:
| Capability | Where to configure |
|---|---|
| Email (SMTP, Gmail, SendGrid, …) | Admin Space → System Settings → Email |
| Object storage (S3, R2, GCS) | Super Admin → Object Storage |
| OAuth apps (Google, Microsoft, HubSpot, …) | Admin Space → App configuration |
| SSO (OIDC) and SCIM | Admin Space → SSO |
| OpenTelemetry export | Admin Space → Observability |
| AI provider connections (beyond boot default) | Admin Space → AI configuration |
MAIL_* and SKIP_EMAIL_VERIFICATION env vars are ignored if present.
Feature flags vs variables
On startup the discovery service logs which features are enabled. Common env-driven gates:
| Feature | Env dependency |
|---|---|
KNOWLEDGE | WEAVIATE_URL + (S3_REGION + S3_BUCKET_ID or Admin storage) |
WEB_SEARCH | SERPER_API_KEY |
WEB_EXTRACTION_DYNAMIC | APIFY_API_KEY + APIFY_EXTRACT_DYNAMIC_CONTENT_TASK_ID |
WEB_EXTRACTION_STATIC | APIFY_API_KEY + APIFY_EXTRACT_STATIC_CONTENT_TASK_ID |
CALLING | VAPI_API_KEY |
EMAILS | Admin Space email config (database) |
SSO / SCIM | Admin Space providers and tokens (database) |
Workflows, agents, connections, variables, teams, skills, and code execution are on by default.
Quick reference by deployment path
Local pnpm
Copy
.env.example→.env, runsetup-env, setFEATHERLESS_API_KEY, start Postgres/Redis/MinIO/Weaviate via compose profiles as needed.Docker Compose (UAT/prod)
Copy
.env.prod.example→.env, fill secrets (including OpenConnector tokens if you enable long-tail OC), rundocker compose -f docker-compose.prod.yml up -d. Compose injects internal service URLs such asOPEN_CONNECTOR_BASE_URL.Dokploy / Kubernetes
Map the required server variables plus Redis, S3, and Weaviate for full platform features. Build or pull a UI image with correct
VITE_*build args.