Configuration
The environment-variable reference for Cordy Gateway — database, Redis, provider keys, security, licensing, and runtime behavior.
Cordy Gateway is configured through environment variables, typically in a .env file consumed by Docker Compose. This page groups every variable you are likely to set, with defaults and notes. Start from deploy/env.template, which ships with placeholders and no real secrets.
Minimum required in production
These have no safe default and must be set for a production deployment:
DB_NAME,DB_USER,DB_PASSWORDDJANGO_SECRET_KEY,DJANGO_ALLOWED_HOSTS,DJANGO_ADMIN_URLCHANNEL_ENCRYPTION_KEYS(identical value for the Admin and Gateway services)
Generate secrets:
# DJANGO_SECRET_KEY
python -c "import secrets; print(secrets.token_urlsafe(50))"
# CHANNEL_ENCRYPTION_KEYS (a Fernet key)
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
Database
| Variable | Default | Notes |
|---|---|---|
DB_NAME | — | Database name. Read directly by the Gateway data plane. If unset, the Gateway falls back to a dev database name and cannot reach your production DB. |
DB_USER | — | Database user. Read directly by the Gateway. |
DB_PASSWORD | — | Database password. Read directly by the Gateway. |
DB_HOST | postgres (Admin) / pgbouncer (Gateway) | The Gateway connects through PgBouncer; the Admin connects to Postgres directly. |
DB_PORT | 5432 | |
DATABASE_URL | — | Consumed by the Admin (and migration/test tooling) only. The Gateway data plane does not parse DATABASE_URL; it builds its DSN from DB_*. Set both consistently. |
Gotcha: the Gateway builds its Postgres DSN from
DB_NAME/DB_USER/DB_PASSWORD, not fromDATABASE_URL. If those are missing on thegatewayservice, it defaults to a development database name, cannot connect, and every request fails auth with401. Mirror the Admin'sDB_*values onto the Gateway.
Redis
| Variable | Default | Notes |
|---|---|---|
REDIS_URL | redis://localhost:6379/0 | Redis connection URL. In the prod compose this is redis://redis:6379/0. |
REDIS_POOL_SIZE | 20 | Connection pool size. 20 is the tuned default; the shipped template raises it to 500 for high concurrency. |
Provider keys
Provider and channel credentials are normally managed as encrypted Channels in the Admin, not in the environment. The following environment keys exist because the underlying LiteLLM integration reads them automatically; they are optional and mainly useful for development seeding. Prefer per-channel encrypted credentials for production.
| Variable | Provider |
|---|---|
OPENAI_API_KEY | OpenAI |
ANTHROPIC_API_KEY | Anthropic |
OPENROUTER_API_KEY | OpenRouter |
GEMINI_API_KEY | Google Gemini |
AZURE_API_KEY, AZURE_API_BASE, AZURE_API_VERSION | Azure OpenAI |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION_NAME | AWS Bedrock |
COHERE_API_KEY | Cohere |
GROQ_API_KEY | Groq |
TOGETHERAI_API_KEY | Together AI |
DEEPINFRA_API_KEY | DeepInfra |
REPLICATE_API_TOKEN | Replicate |
HUGGINGFACE_API_KEY | Hugging Face |
See Providers for how channels and credentials work.
Security
| Variable | Default | Notes |
|---|---|---|
CHANNEL_ENCRYPTION_KEYS | — | Comma-separated Fernet keys that encrypt channel upstream credentials at rest. The first is the active (encrypting) key; the rest allow rotation. Mandatory in production — the Admin and Gateway refuse to start without it, and both must use the same value. |
CLIENT_CORS_ORIGINS | empty | Comma-separated Origins allowed to call the Gateway from a browser. Empty denies all cross-origin browser access (server-to-server callers do not use CORS). A literal * is refused at boot in production. |
CLIENT_CORS_ALLOW_WILDCARD_IN_PRODUCTION | false | Unsafe escape hatch to permit a * client CORS origin in production. Leave off. |
TRUSTED_PROXY_CIDRS | empty | CIDRs of trusted reverse proxies. X-Forwarded-For / X-Real-IP are honoured for the logged client IP only when the socket peer matches one of these; otherwise the socket peer is used. Prevents audit-IP spoofing. |
GATEWAY_METRICS_TOKEN | empty | Bearer token scrapers must present for /metrics/prometheus. In production, with neither this nor an allowed CIDR set, the endpoint is denied. |
GATEWAY_METRICS_ALLOWED_CIDRS | empty | CIDRs allowed to scrape /metrics/prometheus. |
DJANGO_SECRET_KEY | — | Django cryptographic key (Admin). Required in production. |
DJANGO_ALLOWED_HOSTS | — | Comma-separated hostnames the Admin serves. Required in production. |
DJANGO_ADMIN_URL | — | Admin URL path prefix; must end with /. Pick a non-obvious value. Required in production. |
DJANGO_CSRF_TRUSTED_ORIGINS | empty | Scheme-qualified origins allowed to POST to the Admin behind a TLS proxy (e.g. https://admin.example.com). |
DJANGO_SECURE_SSL_REDIRECT | True | Force HTTP→HTTPS redirect. Set False only for a local no-TLS test. |
ADMIN_HTTP_PORT | 8001 | Host port the Admin is published on. |
GATEWAY_HTTP_PORT | 8002 | Host port the Gateway (via nginx) is published on. |
Licensing
Cordy Gateway uses an offline, HMAC-signed license. Licensing defaults to audit-only (fail-open); it does not gate a normal deployment.
| Variable | Default | Notes |
|---|---|---|
LICENSE_KEY | empty | HMAC-signed license payload. Blank for unlicensed/dev. |
LICENSE_SIGNING_SECRET | empty | Shared secret used to verify the license, provided per customer. |
LICENSE_CUSTOMER_ID | empty | Expected customer id to match the payload; blank to skip. |
LICENSE_NODE_ID | node-1 | Current node id for node-count checks. |
LICENSE_ENFORCEMENT_MODE | audit_only | audit_only (fail-open, logs only) or strict (fail-closed). |
Runtime behavior
| Variable | Default | Notes |
|---|---|---|
GATEWAY_DEFAULT_ROUTING_STRATEGY | weighted | Default channel-selection strategy: weighted, cheapest, fastest, or region_aware. Overridable per request with X-Routing-Strategy. |
GATEWAY_MAX_BODY_BYTES | 10485760 (10 MiB) | Hard request-body cap. Larger bodies get 413. <= 0 disables the cap. |
GATEWAY_MAX_INFLIGHT_PER_KEY | 50 | Max concurrent in-flight requests per API key. <= 0 disables. |
GATEWAY_DEFAULT_MAX_COMPLETION_TOKENS | 4096 | Completion-token estimate used for quota admission when a request sets no max_tokens. |
GATEWAY_PRICE_TTL_SECONDS | 300 | Per-process TTL for the effective-price cache used in cost snapshots. |
GRANIAN_WORKERS | 8 | Granian worker processes per Gateway container. |
IDEMPOTENCY_TTL_SECONDS | 600 | Lifetime of a stored idempotent response / lock. |
Observability (OpenTelemetry)
Tracing is off by default. Enable it to export spans to an OTLP endpoint. See Deployment for the tracing backends.
| Variable | Default | Notes |
|---|---|---|
OTEL_TRACING_ENABLED | false | Enable OpenTelemetry tracing for the Gateway. |
OTEL_SERVICE_NAME | cordy-gateway | service.name reported in traces. |
OTEL_EXPORTER_OTLP_ENDPOINT | empty | OTLP HTTP endpoint for trace export. |
OTEL_EXPORTER_OTLP_HEADERS | empty | Comma-separated OTLP exporter headers. |
OTEL_SHUTDOWN_TIMEOUT_SECONDS | 2.0 | Bounded flush timeout on shutdown. |
Scaling and infrastructure
These tune the compose stack and horizontal scaling. See Deployment.
| Variable | Default | Notes |
|---|---|---|
SCALE_GRANIAN_WORKERS | 4 | Per-replica worker count when running multiple gateway replicas. |
ADMIN_WORKERS | 3 | Gunicorn workers for the Admin service. |
PGBOUNCER_POOL_SIZE | 100 | PgBouncer default pool size. |
PGBOUNCER_MAX_CLIENT_CONN | 400 | PgBouncer max client connections. |
REDIS_MAXMEMORY | 512mb | Redis max memory (with volatile-lru eviction that never touches money keys). |
Backups
| Variable | Default | Notes |
|---|---|---|
BACKUP_DIR | /var/backups/cordy | Where logical backups are written. |
BACKUP_RETENTION | 7 | Backups to retain. |
REQUIRE_PITR | 0 | Set to 1 once WAL archiving / point-in-time recovery is enabled to enforce it in acceptance checks. |
Next steps
- Deployment — apply these settings to a production topology.
- Security — the security-relevant variables in context.