Configuration
AnvilBase is configured entirely through environment variables (.env for
Compose, Helm values for Kubernetes). This page explains how configuration works
and the security-relevant settings; the complete variable catalog is in
Reference → Configuration.
Where configuration lives
- Docker Compose —
.envin the repo root (copied from.env.example). - Kubernetes — Helm
values.yaml/ a referenced Secret (Kubernetes). - Per-project settings (auth, SMTP, eIDAS, OAuth, quotas) are not env vars — they’re configured at runtime via the console/API and stored per project.
Generating secrets
openssl rand -hex 24 # passwords (48 hex chars)openssl rand -hex 32 # signing secrets (CONTROL_PLANE_SECRET, AUTH_SECRET)openssl rand -hex 64 # SECRET_KEY_BASE (Phoenix needs >= 64 chars)# MinIO SSE-S3 KMS key (key-id:base64):echo "anvilbase-prod:$(openssl rand -base64 32)"Required secrets
| Variable | Purpose |
|---|---|
POSTGRES_PASSWORD | Postgres superuser |
ANVILBASE_DB_PASSWORD | application DB user (used by all services) |
CONTROL_PLANE_SECRET | signs PATs; encrypts the secrets vault (≥ 32 chars) |
AUTH_SECRET | Better Auth session signing |
SECRET_KEY_BASE | Phoenix realtime (≥ 64 chars) |
MINIO_ROOT_PASSWORD | storage admin |
MINIO_KMS_SECRET_KEY | SSE-S3 bucket encryption (required — see below) |
VALKEY_PASSWORD | cache auth |
MINIO_KMS_SECRET_KEYis required. Project provisioning callsput_bucket_encryptionon every new bucket; without a KMS key MinIO rejects it and project creation rolls back. Format:<key-id>:<base64(32 bytes)>.
Management authentication
| Variable | Role |
|---|---|
ANVILBASE_ADMIN_TOKEN | the bootstrap admin token for /api/v1 (root credential). If unset, that bootstrap path is disabled and you authenticate with PATs only. |
CONTROL_PLANE_SECRET also HMAC-verifies Personal Access Tokens and signs
platform session JWTs (console login). Mint scoped PATs with
anvilbase token mint --name ci --scope admin|deploy|read once the bootstrap
token is configured. See
Reference → Management API.
Ports
Host ports default to a dedicated 39xxx block to avoid collisions; container-
internal ports stay at conventional defaults. Override any with *_PORT. Full
table: Reference → Ports.
Security-relevant toggles
| Variable | Default | Effect |
|---|---|---|
ANVILBASE_MTLS_ENABLED | false | mutual TLS between internal services (enable for prod) |
ANVILBASE_WALG_ENABLED | true | WAL archiving for PITR (a no-op until an S3 target is configured) |
ALLOW_INTERNAL_WEBHOOK_TARGETS | false | when truthy, disables the SSRF guard blocking webhook/function delivery to private/loopback IPs. Leave off in production. |
ANVILBASE_CORS_ORIGINS | compose: http://localhost:39004; bare release builds: unset = cross-origin disabled | exact-origin CORS allow-list for browser apps (the console). Release builds fail closed without it. |
ANVILBASE_TRUSTED_PROXIES | RFC1918 + loopback | CIDRs whose X-Forwarded-For is trusted for client-IP resolution (credential brute-force guard) |
ANVILBASE_METRICS_TOKEN | unset | optional Bearer gate on the control-plane / webhooks /metrics endpoints |
TRAEFIK_DASHBOARD_PORT | 39081 | relocate/close in production |
IMGPROXY_KEY / IMGPROXY_SALT | unset | enable signed image URLs (Image Transformations) |
BACKUP_OFFSITE_ENDPOINT / _BUCKET / _ACCESS_KEY / _SECRET_KEY (+ optional _REGION) | unset | asynchronous offsite/DR copy of every successful project backup to a secondary S3 target (Backups & Restore). Set all four or none — partial config fails at boot. |
Tuning
| Variable | Default | Effect |
|---|---|---|
ANVILBASE_PROJECT_POOL_MAX | 20 | max Postgres connections per project pool |
ANVILBASE_POOL_IDLE_TIMEOUT_SECS | 300 | scale-to-zero idle window (seconds): release an idle project’s pooled DB + Valkey cache resources after this long, restoring them lazily on next use. 0 disables eviction (keep pools warm). Garbage falls back to 300. |
ANVILBASE_AUDIT_RETENTION_DAYS | 90 | default window (days) for the on-demand audit prune (POST /admin/audit/prune, anvilbase audit prune) over the audit_log table and the auth-event PGMQ archive. The nightly scheduled prune uses its own cron literal (90; change via UPDATE cron.job) — this var does not alter the schedule. Values <1 fall back to 90. See Audit log retention. |
ANVILBASE_DLQ_RETENTION_DAYS | 30 | retention window (days) for the webhook dead-letter queue nightly purge. Values <1 fall back to 30. |
WEBHOOK_MAX_RETRIES | 5 | webhook delivery attempts |
WEBHOOK_TIMEOUT | 30 | per-attempt webhook timeout (seconds) |
WEBHOOK_RETRY_BASE_DELAY | 10 | base backoff seconds between webhook attempts |
WEBHOOK_MAX_CONCURRENT | 10 | max concurrent in-flight webhook deliveries |
RUST_LOG | info | control-plane log level (debug for troubleshooting) |
This page covers the security-relevant and commonly-tuned settings. For the complete catalog — every variable for every service (read replicas, logical replication, scheduled base backups, the Deno worker supervisor, Supavisor, observability, MFA, and more) — see Reference → Configuration.
Watch the connection math: replicas × active_projects × ANVILBASE_PROJECT_POOL_MAX
must stay under Postgres max_connections (Scaling).
Resource limits (Compose)
Every service in docker-compose.yml declares a deploy.resources.limits block
(cpus + memory) that Docker Compose v2 enforces on docker compose up (it
maps to --cpus / --memory). These are env-tunable ceilings with generous
defaults: each default sits comfortably above realistic usage, so the
limits only contain a runaway container — they do not right-size normal
operation, and an existing deployment is never throttled or OOM-killed by the
defaults.
Override per service in .env with ANVILBASE_<SERVICE>_CPUS /
ANVILBASE_<SERVICE>_MEM_LIMIT:
- Small hosts can lower them — but do so carefully: a
*_MEM_LIMITset below a container’s real memory usage makes Docker OOM-kill it on the nextup. Postgres is the most sensitive (it holds every project’s data) — keep its limit well aboveshared_buffers+work_mem× concurrency. - Heavy load can raise them.
| Service | CPUs var (default) | Memory var (default) |
|---|---|---|
| postgres | ANVILBASE_POSTGRES_CPUS (4) | ANVILBASE_POSTGRES_MEM_LIMIT (8g) |
| control-plane | ANVILBASE_CONTROL_PLANE_CPUS (4) | ANVILBASE_CONTROL_PLANE_MEM_LIMIT (2g) |
| realtime | ANVILBASE_REALTIME_CPUS (2) | ANVILBASE_REALTIME_MEM_LIMIT (2g) |
| supavisor | ANVILBASE_SUPAVISOR_CPUS (2) | ANVILBASE_SUPAVISOR_MEM_LIMIT (1g) |
| deno | ANVILBASE_DENO_CPUS (2) | ANVILBASE_DENO_MEM_LIMIT (2g) |
| webhooks | ANVILBASE_WEBHOOKS_CPUS (2) | ANVILBASE_WEBHOOKS_MEM_LIMIT (1g) |
| auth | ANVILBASE_AUTH_CPUS (2) | ANVILBASE_AUTH_MEM_LIMIT (1g) |
| minio | ANVILBASE_MINIO_CPUS (2) | ANVILBASE_MINIO_MEM_LIMIT (2g) |
| valkey | ANVILBASE_VALKEY_CPUS (2) | ANVILBASE_VALKEY_MEM_LIMIT (2g) |
| traefik | ANVILBASE_TRAEFIK_CPUS (2) | ANVILBASE_TRAEFIK_MEM_LIMIT (512m) |
| imgproxy | ANVILBASE_IMGPROXY_CPUS (2) | ANVILBASE_IMGPROXY_MEM_LIMIT (1g) |
| prometheus | ANVILBASE_PROMETHEUS_CPUS (2) | ANVILBASE_PROMETHEUS_MEM_LIMIT (2g) |
| grafana | ANVILBASE_GRAFANA_CPUS (1) | ANVILBASE_GRAFANA_MEM_LIMIT (1g) |
| mailpit | ANVILBASE_MAILPIT_CPUS (1) | ANVILBASE_MAILPIT_MEM_LIMIT (512m) |
| console | ANVILBASE_CONSOLE_CPUS (1) | ANVILBASE_CONSOLE_MEM_LIMIT (512m) |
| docker-socket-proxy | ANVILBASE_SOCKET_PROXY_CPUS (1) | ANVILBASE_SOCKET_PROXY_MEM_LIMIT (256m) |
| wal-g | ANVILBASE_WALG_CPUS (2) | ANVILBASE_WALG_MEM_LIMIT (2g) |
PID caps (fork-bomb protection)
The deno runtime executes untrusted per-project edge-function code, so it
also pins a hard PID cap (deploy.resources.limits.pids, the schema-correct
form of pids_limit) — a PID cap bounds process/thread count and never OOMs:
| Service | PID-limit var (default) |
|---|---|
| deno | ANVILBASE_DENO_PIDS_LIMIT (512) |
| control-plane | ANVILBASE_CONTROL_PLANE_PIDS_LIMIT (2048) |
| webhooks | ANVILBASE_WEBHOOKS_PIDS_LIMIT (2048) |
These limits live in docker-compose.yml (the canonical local-=-cloud stack).
The production overlay (docker-compose.prod.yml) is a separate concern and
does not currently re-declare them; layer your own there if you need
prod-specific ceilings.
Local development overrides
Create docker-compose.override.yml (git-ignored, auto-merged) for local tweaks —
debug logging, exposed ports, source mounts for hot reload:
services: control-plane: environment: - RUST_LOG=debug console: volumes: - ./console/src:/app/srcHygiene
- Never commit
.envor secret values. - Store production secrets in a secrets manager (Vault, AWS/GCP Secrets Manager) and inject them.
- Rotate on a schedule — application keys via rotation endpoints, database passwords via the hardening procedure.
Full catalog: Reference → Configuration.
Next: Production Checklist.