Every environment variable AnvilBase reads, grouped by service. This is the
single source of truth — if a knob exists in the code or in
docker-compose.yml, it is listed here. Copy .env.example to .env and fill
the required values. For how to configure (secret generation, overrides,
hygiene), see Self-Hosting → Configuration.
Generate secrets: openssl rand -hex 24 (passwords), openssl rand -hex 32
(signing secrets), openssl rand -hex 64 (SECRET_KEY_BASE).
Reading the tables. Default is the value applied when the variable is
unset (a compose :-default, a code fallback, or a fixed container value). A
default of — with Secret = yes means there is no fallback — the stack
refuses to boot until you set it. Secret flags values that must never be
committed or logged.
Internal/service-to-service URLs (CONTROL_PLANE_INTERNAL_URL,
AUTH_SERVICE_URL, DENO_INTERNAL_URL, REALTIME_INTERNAL_URL,
SUPAVISOR_API_URL, VALKEY_URL, MINIO_ENDPOINT, DATABASE_URL) default to
the in-network compose service name and rarely need overriding. They are
documented for completeness and for non-compose (split-host) deployments.
Quick index
| Group | Jump |
|---|
| Compose & Docker | ↓ |
| Images (prod overlay) | ↓ |
| PostgreSQL | ↓ |
| Read replica | ↓ |
| Logical replication | ↓ |
| Scheduled base backups | ↓ |
| wal-g / PITR | ↓ |
| Offsite backup copy | ↓ |
| Control plane | ↓ |
| Scale-to-zero & pooling | ↓ |
| Auth (Better Auth) | ↓ |
| MFA tuning | ↓ |
| Realtime (Phoenix) | ↓ |
| Webhooks | ↓ |
| Deno edge functions | ↓ |
| Console | ↓ |
| Storage (MinIO / RustFS) | ↓ |
| imgproxy | ↓ |
| Valkey | ↓ |
| Supavisor (pooler) | ↓ |
| Traefik | ↓ |
| Observability (Prometheus/Grafana/OTel) | ↓ |
| SMTP / Mailpit | ↓ |
| mTLS (internal) | ↓ |
| Resource limits | ↓ |
| Required-secrets summary | ↓ |
| CLI environment | ↓ |
Compose & Docker
| Variable | Default | Description |
|---|
COMPOSE_FILE | docker-compose.yml | active overlay(s); append :docker-compose.rustfs.yml (RustFS storage backend), :docker-compose.prod.yml (pre-built images), or :docker-compose.supabase-pg.yml (legacy Postgres image, rollback) |
DOCKER_API_VERSION | 1.44 | Docker Engine API version for Traefik’s Docker provider (1.44 works on Docker 25+) |
Images (production overlay)
Used only by docker-compose.prod.yml, which pulls pre-built multi-arch images
instead of building locally.
| Variable | Default | Description |
|---|
ANVILBASE_IMAGE_NS | ghcr.io/paxtone-studio | image namespace/registry prefix for all anvilbase-* images |
ANVILBASE_VERSION | 1.2.0-rc.1 | image tag pulled for every service |
PostgreSQL
| Variable | Default | Secret | Description |
|---|
POSTGRES_PASSWORD | — | yes | superuser (supabase_admin) password — required |
ANVILBASE_DB_PASSWORD | — | yes | anvilbase application user password (used by all services) — required |
POSTGRES_PORT | 39432 | no | host port (internal 5432) |
ANVILBASE_PGDATA / PGDATA | /var/lib/postgresql/data | no | live data directory; PITR refuses to stage restores inside it. ANVILBASE_PGDATA wins if both are set |
Connection string: postgres://anvilbase:${ANVILBASE_DB_PASSWORD}@postgres:5432/anvilbase_platform.
The image bundles pgvector, pg_graphql, PGMQ, pgcrypto, pg_cron,
pg_stat_statements.
Read replica (opt-in)
OFF by default. Set the host to enable; read-only REST GET/HEAD route to the
replica, writes always hit the primary. See Read Replicas.
| Variable | Default | Secret | Description |
|---|
ANVILBASE_READ_REPLICA_HOST | unset (disabled) | no | replica hostname (e.g. postgres-replica). Empty/unset ⇒ feature off |
ANVILBASE_READ_REPLICA_PORT | 5432 | no | replica port (a bad value fails at boot, not silently) |
POSTGRES_REPLICA_PORT | 39433 | no | host port the compose postgres-replica service publishes |
ANVILBASE_REPLICATION_USER | replicator | no | streaming-replication role |
ANVILBASE_REPLICATION_PASSWORD | falls back to ANVILBASE_DB_PASSWORD | yes | replication role password |
Logical replication (opt-in)
| Variable | Default | Secret | Description |
|---|
ANVILBASE_WAL_LEVEL | replica | no | Postgres wal_level. Set logical to enable CDC / logical replication slots. See Logical Replication |
Scheduled base backups
Drives the wal-g base-backup scheduler sidecar (compose walg-scheduler).
| Variable | Default | Description |
|---|
ANVILBASE_BASEBACKUP_INTERVAL | 86400 | seconds between full base backups (24 h) |
ANVILBASE_BASEBACKUP_RETAIN_COUNT | 7 | full base backups to retain (older ones pruned) |
ANVILBASE_BASEBACKUP_INITIAL_DELAY | 0 | seconds to wait after start before the first backup |
wal-g / PITR
| Variable | Default | Secret | Description |
|---|
ANVILBASE_WALG_ENABLED | true | no | enable WAL archiving (a graceful no-op until WALG_S3_PREFIX + an S3 target are configured, so a stack without S3 still boots) |
WALG_S3_PREFIX | s3://anvilbase-wal/ | no | archive bucket prefix |
WALG_AWS_ENDPOINT | http://minio:9000 | no | S3 endpoint (mapped to wal-g’s AWS_ENDPOINT) |
WALG_AWS_REGION | us-east-1 | no | region (mapped to AWS_REGION) |
WALG_COMPRESSION_METHOD | lz4 | no | compression (lz4, zstd, …) |
WALG_LIBSODIUM_KEY | — | yes | WAL encryption key (keep safe — losing it loses recovery) |
ANVILBASE_WALG_BIN | wal-g | no | wal-g binary path the control plane shells out to for restores |
ANVILBASE_PITR_STAGING_DIR | /var/lib/anvilbase/pitr-staging | no | root for restore staging artifacts (never inside $PGDATA) |
The wal-g sidecar also receives AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
(derived from MINIO_ROOT_USER / MINIO_ROOT_PASSWORD) and PG* connection
vars from compose — these are wired automatically and not operator inputs.
See Point-in-Time Recovery.
Offsite backup copy (optional)
Secondary S3 target that every successful project backup is asynchronously
copied to. Set all four (region optional) or none — a partial config is
rejected at boot. See Backups & Restore.
| Variable | Default | Secret | Description |
|---|
BACKUP_OFFSITE_ENDPOINT | unset | no | S3-compatible endpoint URL |
BACKUP_OFFSITE_BUCKET | unset | no | destination bucket |
BACKUP_OFFSITE_ACCESS_KEY | unset | yes | access key |
BACKUP_OFFSITE_SECRET_KEY | unset | yes | secret key |
BACKUP_OFFSITE_REGION | us-east-1 | no | region (set the real one for AWS S3) |
Control plane
| Variable | Default | Secret | Description |
|---|
CONTROL_PLANE_PORT | 39001 (int. 3001) | no | HTTP port |
CONTROL_PLANE_SECRET | — | yes | signs PATs, encrypts the secrets vault (≥ 32 chars) — required |
ANVILBASE_ADMIN_TOKEN | unset | yes | bootstrap admin token for /api/v1 (disabled if unset) |
INTERNAL_SECRET | — | yes | shared X-Internal-Secret for service-to-service /internal/* routes; must match across control-plane, auth, realtime, deno. Unset ⇒ /internal/* fails closed (401); the public dev default is rejected at boot. anvilbase start generates it |
DATABASE_URL | derived from ANVILBASE_DB_PASSWORD | yes | Postgres connection string (…/anvilbase_platform) |
ANVILBASE_PG_AUTOTUNE | on | no | RAM-aware Postgres tuning (owned image). Sizes shared_buffers to 25% of the container memory limit (clamped 128 MB–16 GB) + effective_cache_size to 70% on each start. Set off to use stock Postgres config |
ANVILBASE_PG_SHARED_BUFFERS | auto (25% of mem limit) | no | pin shared_buffers explicitly (e.g. 2GB), overriding autotune |
ANVILBASE_PG_EFFECTIVE_CACHE_SIZE | auto (70% of mem limit) | no | pin effective_cache_size explicitly |
ANVILBASE_PG_SYNCHRONOUS_COMMIT | unset (= on, fully durable) | no | set off/local to trade a small crash-durability window for much higher write throughput on slow storage (e.g. networked Ceph). Leave unset for financial/critical writes |
VALKEY_URL | redis://localhost:6379 | yes | rate limiting + cache (compose injects credentials) |
ANVILBASE_RATE_LIMIT_ENABLED | true | no | per-scope API rate limiter, now keyed per-caller (per authenticated user, else per resolved client IP) — one client can no longer exhaust a whole project+scope bucket. Set false/0/no/off to disable entirely (fails open) — e.g. behind an external gateway that already throttles, or when load-testing raw capacity |
ANVILBASE_RATE_LIMIT_ANON | 100 | no | per-caller anon budget (requests per window). Garbage/0 falls back to 100 |
ANVILBASE_RATE_LIMIT_AUTHENTICATED | 1000 | no | per-caller authenticated budget (requests per window). Garbage/0 falls back to 1000 |
ANVILBASE_RATE_LIMIT_SERVICE_ROLE | 5000 | no | per-caller service_role budget (requests per window). Garbage/0 falls back to 5000 |
ANVILBASE_RATE_LIMIT_WINDOW_SECS | 60 | no | shared rate-limit window in seconds. Garbage/0 falls back to 60 |
ANVILBASE_REST_MAX_ROWS | 1000 | no | max rows a single REST read returns (PostgREST db-max-rows parity). A GET with no limit gets LIMIT 1000; a larger limit is clamped down. Content-Range still reports the true total. 0 disables the cap (unbounded reads); garbage/negative falls back to 1000 |
MINIO_ENDPOINT | http://localhost:9000 | no | storage endpoint (compose: http://minio:9000) |
MINIO_ACCESS_KEY | anvilbase | no | storage access key (compose: MINIO_ROOT_USER) |
MINIO_SECRET_KEY | — | yes | storage secret key (compose: MINIO_ROOT_PASSWORD) |
ANVILBASE_STORAGE_BUCKET_ENCRYPTION | on | no | apply explicit SSE-S3 (put_bucket_encryption) on new storage/backup buckets. Set off when pointing MINIO_ENDPOINT at a managed S3 that lacks the bucket-encryption API (e.g. some provider object stores) — buckets are then created without the SSE-config call and rely on the backend’s at-rest encryption. Lets you use external managed S3 instead of bundled MinIO |
ANVILBASE_CORS_ORIGINS | compose: http://localhost:39004; bare release builds: unset | no | comma-separated exact browser origins allowed cross-origin. Release builds fail closed when unset (no cross-origin access); debug builds mirror the request origin |
ANVILBASE_TRUSTED_PROXIES | RFC1918 + loopback | no | comma-separated CIDRs whose X-Forwarded-For is trusted for client-IP resolution |
ANVILBASE_METRICS_TOKEN | unset | yes | optional Bearer gate on /metrics. Unset ⇒ unauthenticated scrape on the internal network |
ANVILBASE_JWT_GRACE_SECONDS | 1800 | no | grace window a project’s previous jwt_secret keeps verifying after rotation (≤ 0 disables) |
ANVILBASE_DLQ_RETENTION_DAYS | 30 | no | default window for on-demand webhook DLQ purge (< 1 falls back to 30) |
ANVILBASE_AUDIT_RETENTION_DAYS | 90 | no | default window for on-demand audit/auth-event prune (< 1 falls back to 90). Does not change the nightly cron |
ALLOW_INTERNAL_WEBHOOK_TARGETS | false | no | when truthy, disables the SSRF guard that blocks webhook/function delivery to private/loopback IPs. Leave off in production |
EXTERNAL_BASE_URL | http://localhost:3001 | no | public base URL the control plane advertises in eIDAS issuer/verifier metadata |
AUTH_SERVICE_URL | http://auth:3002 | no | internal auth service URL |
DENO_INTERNAL_URL | http://deno:8082 | no | internal edge-runtime URL |
REALTIME_INTERNAL_URL | realtime:4000 | no | internal realtime service host:port |
RUST_LOG | info | no | log level (debug for troubleshooting) |
Scale-to-zero & connection pooling
| Variable | Default | Description |
|---|
ANVILBASE_PROJECT_POOL_MAX | 20 | max Postgres connections per project pool (values < 1 fall back to 20) |
ANVILBASE_POOL_IDLE_TIMEOUT_SECS | 300 | scale-to-zero idle window: release an idle project’s pooled DB + Valkey resources after this long, restoring lazily on next use. 0 disables eviction; bad values fall back to 300 |
Auth (Better Auth)
| Variable | Default | Secret | Description |
|---|
AUTH_PORT | 39002 (int. 3002) | no | HTTP port |
AUTH_SECRET | — | yes | Better Auth session signing secret — required |
DATABASE_URL | derived from ANVILBASE_DB_PASSWORD | yes | Postgres connection string |
INTERNAL_SECRET | — | yes | shared service-to-service secret (must match control plane) — required |
CONTROL_PLANE_SECRET | — | yes | also injected so auth can verify platform tokens — required |
CONTROL_PLANE_URL | http://control-plane:3001 | no | for event forwarding |
CONTROL_PLANE_INTERNAL_URL | http://control-plane:3001 | no | internal control-plane URL for settings/secret fetches |
BETTER_AUTH_URL | http://localhost:3002 | no | base URL Better Auth uses for callbacks |
TRUSTED_ORIGINS | unset | no | comma-separated extra origins Better Auth accepts (CSRF allow-list) |
AUTH_ALLOWED_REDIRECT_URLS | myapp://auth/reset-password,myapp://auth/callback | no | comma-separated allowed post-auth redirect URLs (incl. mobile deep links) |
AUTH_SETTINGS_FETCH_TIMEOUT_MS | 3000 | no | timeout (ms) when fetching per-project auth settings from the control plane |
PLATFORM_PROJECT_ID | empty | no | project id used for platform-level transactional email (password reset, etc.) |
MFA tuning (auth)
| Variable | Default | Description |
|---|
MFA_TOTP_ISSUER | AnvilBase | issuer label shown in authenticator apps |
MFA_MAX_ATTEMPTS | 5 | failed-verification attempts before a factor locks |
MFA_LOCKOUT_SECS | 900 | lockout duration in seconds (15 min) after MFA_MAX_ATTEMPTS |
OTP / magic-link / reset send caps (auth)
Per-recipient send caps (Supabase over_email_send_rate_limit /
over_sms_send_rate_limit parity) throttle how often the passwordless / reset
endpoints (/otp, /magiclink, /resend, /recover) can send to a single
recipient — complementing the per-IP control-plane guard. The cap is
recipient-keyed, so it fires identically for existing and non-existing
recipients (no user-enumeration signal). Over-limit returns 429 with a
Retry-After header.
| Variable | Default | Description |
|---|
OTP_EMAIL_SEND_MAX | 5 | max email sends per recipient per window |
OTP_SMS_SEND_MAX | 3 | max SMS sends per recipient per window (tighter — SMS costs money) |
OTP_SEND_WINDOW_SECS | 3600 | send-cap window length in seconds (1 hour) |
Realtime (Phoenix)
| Variable | Default | Secret | Description |
|---|
REALTIME_PORT | 39040 (int. 4000) | no | Phoenix HTTP port (host mapping; container reads PORT) |
PORT | 4000 | no | container-internal Phoenix port |
SECRET_KEY_BASE | — | yes | Phoenix secret (≥ 64 chars) — required |
DATABASE_URL | derived from ANVILBASE_DB_PASSWORD | yes | Postgres connection string |
INTERNAL_SECRET | — | yes | shared service-to-service secret — required |
CONTROL_PLANE_URL | (compose-set) | no | control-plane URL for project/secret lookups |
PHX_HOST | localhost | no | endpoint hostname |
PHX_SERVER | true | no | start the HTTP server (vs. release-only) |
MIX_ENV | prod | no | Elixir environment |
DNS_CLUSTER_QUERY | unset | no | DNS query for libcluster node discovery (multi-node; normally unset) |
ANVILBASE_REALTIME_MAX_DB_CONNECTIONS | compose 40 (code: unset = no budget) | no | clamp on total realtime DB connections (projects × (1 + query_pool_size)) |
ANVILBASE_REALTIME_MAX_LISTENERS | 256 | no | cap on concurrent per-project LISTEN connections |
ANVILBASE_REALTIME_QUERY_POOL_SIZE | 2 | no | per-project query-pool size (in addition to the 1 LISTEN connection) |
Webhooks
| Variable | Default | Secret | Description |
|---|
WEBHOOKS_PORT | 39003 (int. 3003) | no | HTTP port |
CONTROL_PLANE_SECRET | — | yes | decrypts per-project webhook signing material — required |
WEBHOOK_MAX_RETRIES | 5 | no | delivery attempts before dead-letter |
WEBHOOK_TIMEOUT | 30 | no | per-attempt delivery timeout (seconds) |
WEBHOOK_RETRY_BASE_DELAY | 10 | no | base seconds for exponential backoff between attempts |
WEBHOOK_MAX_CONCURRENT | 10 | no | max concurrent in-flight deliveries |
ALLOW_INTERNAL_WEBHOOK_TARGETS | false | no | disables the SSRF private-IP guard (leave off in production) |
ANVILBASE_METRICS_TOKEN | unset | yes | optional Bearer gate on /metrics |
The delivery-timeout env var is WEBHOOK_TIMEOUT (seconds), not
WEBHOOK_TIMEOUT_SECONDS.
Deno edge functions
The Deno runtime executes untrusted per-project function code. Most knobs tune
the per-project worker supervisor; defaults are production-safe.
| Variable | Default | Secret | Description |
|---|
DENO_PORT | 8082 | no | container-internal HTTP port |
ANVILBASE_EDGE_ISOLATION | per-project | no | isolation model: per-project (process per project) or per-invocation (fresh isolate per request) |
DENO_SUPERVISOR | on | no | off reverts to the legacy single-process runtime (rollback hatch) |
DENO_MAX_WORKERS | 16 | no | max live per-project workers (LRU eviction beyond this) |
DENO_WORKER_IDLE_MS | 300000 | no | reap an idle worker after this long (5 min) |
DENO_REQUEST_TIMEOUT_MS | 30000 | no | per-request upstream timeout |
DENO_WORKER_START_TIMEOUT_MS | 10000 | no | max time to wait for a worker to become ready |
DENO_WORKER_BACKOFF_START_MS | 1000 | no | initial restart backoff after a worker crash |
DENO_WORKER_BACKOFF_CAP_MS | 30000 | no | maximum restart backoff |
DENO_WORKER_HEALTHY_RESET_MS | 60000 | no | healthy uptime after which the backoff counter resets |
DENO_WORKER_TMP_BASE | (compose tmp mount) | no | base directory for per-worker scratch space |
FUNCTIONS_DIR | /functions | no | root of deployed function code (scoped /functions/<project_id>) |
CONTROL_PLANE_INTERNAL_URL | http://control-plane:3001 | no | for fetching per-project secrets |
INTERNAL_SECRET | — | yes | shared service-to-service secret — required |
Console
| Variable | Default | Description |
|---|
CONSOLE_PORT | 39004 (int. 3004) | web port |
VITE_API_URL | same origin | control-plane API URL baked at build time |
Storage (MinIO / RustFS)
| Variable | Default | Secret | Description |
|---|
MINIO_ROOT_USER | anvilbase | no | admin user (also the S3 access key) |
MINIO_ROOT_PASSWORD | — | yes | admin password (≥ 8 chars) — required |
MINIO_KMS_SECRET_KEY | — | yes | SSE-S3 key, <key-id>:<base64(32 bytes)> — required (bucket encryption / project creation rejects without it) |
MINIO_PORT | 39900 (int. 9000) | no | S3 API port |
MINIO_CONSOLE_PORT | 39901 (int. 9001) | no | MinIO web console |
ANVILBASE_TUS_STALE_HOURS | 24 | no | A resumable (TUS) upload untouched (updated_at) for longer than this is aborted + its rows dropped by the background sweeper. Values ≤ 0 fall back to 24. |
ANVILBASE_TUS_SWEEP_INTERVAL_SECS | 3600 | no | Cadence between abandoned-resumable-upload sweeps. Values ≤ 0 fall back to 3600. |
ANVILBASE_TUS_SWEEP_ENABLED | true | no | Set to false/0/off/no to disable the abandoned-resumable-upload sweeper. |
The RustFS overlay (docker-compose.rustfs.yml) reuses MINIO_ROOT_USER /
MINIO_ROOT_PASSWORD as its S3 credentials.
imgproxy (optional)
| Variable | Default | Secret | Description |
|---|
IMGPROXY_KEY | unset | yes | HMAC key for signed image URLs |
IMGPROXY_SALT | unset | yes | HMAC salt |
IMGPROXY_BASE_URL | http://imgproxy:8081 | no | internal URL the control plane reaches imgproxy at |
IMGPROXY_KEY and IMGPROXY_SALT must be set together to enable signing.
See Image Transformations.
Valkey
| Variable | Default | Secret | Description |
|---|
VALKEY_PORT | 39637 (int. 6379) | no | port |
VALKEY_PASSWORD | — | yes | auth password — required |
Supavisor (connection pooler)
| Variable | Default | Secret | Description |
|---|
SUPAVISOR_PORT | 39654 (proxies int. 6543) | no | transaction-pooler host port |
SUPAVISOR_API_PORT | 4100 (loopback → int. 4000) | no | Supavisor admin API host port |
SUPAVISOR_API_URL | http://supavisor:4000 | no | admin API URL the control plane calls to manage tenants |
SUPAVISOR_API_JWT_SECRET | unset | yes | JWT secret for the Supavisor admin + metrics APIs |
SUPAVISOR_PUBLIC_HOST | localhost:${SUPAVISOR_PORT} | no | host:port advertised to clients in pooled connection strings |
SUPAVISOR_SSL_MODE | prefer | no | client-facing SSL mode (disable/prefer/require) |
SUPAVISOR_POOL_SIZE | 15 | no | default per-tenant pool size |
SUPAVISOR_VAULT_ENC_KEY | unset | yes | encryption key for Supavisor’s tenant-credential vault |
See Connection Pooling.
Traefik
| Variable | Default | Description |
|---|
TRAEFIK_HTTP_PORT | 39080 (int. 80) | HTTP |
TRAEFIK_HTTPS_PORT | 39443 (int. 443) | HTTPS |
TRAEFIK_DASHBOARD_PORT | 39081 (int. 8080) | disable/relocate in production |
Observability
| Variable | Default | Secret | Description |
|---|
PROMETHEUS_PORT | 39090 (int. 9090) | no | Prometheus host port |
GRAFANA_PORT | 39091 (int. 3000) | no | Grafana host port |
GRAFANA_ADMIN_USER | admin | no | Grafana admin user — change in production |
GRAFANA_ADMIN_PASSWORD | admin | yes | Grafana admin password — change in production |
OTEL_EXPORTER_OTLP_ENDPOINT | unset | no | when set, control-plane / auth / realtime export OTLP traces here (off by default) |
OTEL_EXPORTER_OTLP_HEADERS | unset | yes | optional headers (e.g. auth) for the OTLP exporter |
ANVILBASE_METRICS_TOKEN (above) gates the control-plane and webhooks
/metrics endpoints. See Monitoring.
SMTP / Mailpit
In local dev, SMTP points at the always-on Mailpit catch-all so every
project sends mail out of the box. Per-project SMTP overrides live in the
console / anvilbase projects smtp. These env vars are the platform fallback.
| Variable | Default | Secret | Description |
|---|
SMTP_HOST | (Mailpit in dev) | no | server hostname |
SMTP_PORT | 587 | no | port |
SMTP_USER | unset | no | username |
SMTP_PASSWORD | unset | yes | password |
SMTP_FROM | noreply@anvilbase.local | no | default sender |
MAILPIT_SMTP_PORT | 1025 | no | Mailpit SMTP host port (local dev) |
MAILPIT_UI_PORT | 8025 | no | Mailpit web UI host port (local dev) |
mTLS (internal)
Off by default. When enabled, internal listeners require client certs and
internal clients present them (both legs). Generate with
docker/mtls/generate-certs.sh. See Internal mTLS.
| Variable | Default | Description |
|---|
ANVILBASE_MTLS_ENABLED | false | enable mutual TLS between services |
ANVILBASE_MTLS_CA | /etc/anvilbase/tls/ca.pem | CA cert (shared by all services) |
ANVILBASE_MTLS_CERT / ANVILBASE_MTLS_KEY | /etc/anvilbase/tls/control-plane*.pem | control-plane cert/key |
ANVILBASE_MTLS_AUTH_CERT / ANVILBASE_MTLS_AUTH_KEY | /etc/anvilbase/tls/auth*.pem | auth cert/key |
ANVILBASE_MTLS_REALTIME_CERT / ANVILBASE_MTLS_REALTIME_KEY | /etc/anvilbase/tls/realtime*.pem | realtime cert/key |
ANVILBASE_MTLS_DENO_CERT / ANVILBASE_MTLS_DENO_KEY | /etc/anvilbase/tls/deno*.pem | deno runtime cert/key |
Inside each container the per-service cert/key are remapped onto the generic
ANVILBASE_MTLS_CERT / ANVILBASE_MTLS_KEY the runtime reads.
Resource limits
Every service in docker-compose.yml declares an env-tunable
deploy.resources.limits ceiling (cpus + memory). Defaults are generous
— set above realistic usage so they catch a runaway container without
throttling normal operation. Lower them on small hosts (carefully — a
*_MEM_LIMIT below real usage OOM-kills the container, Postgres especially) or
raise them under load. Full per-service default table:
Self-Hosting → Resource limits.
| Variable pattern | Default | Description |
|---|
ANVILBASE_<SERVICE>_CPUS | per service (1–4) | CPU ceiling (deploy.resources.limits.cpus) |
ANVILBASE_<SERVICE>_MEM_LIMIT | per service (256m–8g) | memory ceiling (deploy.resources.limits.memory) |
ANVILBASE_DENO_PIDS_LIMIT | 512 | hard PID cap on the untrusted edge runtime (fork-bomb guard; never OOMs) |
ANVILBASE_CONTROL_PLANE_PIDS_LIMIT | 2048 | generous PID cap on the control plane |
ANVILBASE_WEBHOOKS_PIDS_LIMIT | 2048 | generous PID cap on the webhooks service |
<SERVICE> ∈ POSTGRES, POSTGRES_REPLICA, CONTROL_PLANE, REALTIME,
SUPAVISOR, DENO, WEBHOOKS, AUTH, MINIO, VALKEY, TRAEFIK,
IMGPROXY, PROMETHEUS, GRAFANA, MAILPIT, CONSOLE, SOCKET_PROXY,
WALG, WALG_SCHEDULER.
Required-secrets summary
Minimum to boot a stack (each refuses to default): POSTGRES_PASSWORD,
ANVILBASE_DB_PASSWORD, CONTROL_PLANE_SECRET, INTERNAL_SECRET,
AUTH_SECRET, SECRET_KEY_BASE, MINIO_ROOT_PASSWORD, MINIO_KMS_SECRET_KEY,
VALKEY_PASSWORD. anvilbase start generates the signing secrets for you.
CLI environment
The anvilbase CLI reads its own environment variables (also settable as
flags). Full command/flag catalog: CLI Reference.
| Variable | Flag | Default | Description |
|---|
ANVILBASE_URL | --url | — | control-plane base URL (empty value ignored; a .env in CWD is auto-loaded) |
ANVILBASE_TOKEN | --token | — | management credential (PAT or admin token) |
ANVILBASE_TOKEN_<ENV> | manifest token_source = "env:ANVILBASE_TOKEN_<ENV>" | — | per-environment token for multi-env link/deploy (you choose the suffix) |
REALTIME_URL | — | (derived from --url) | WebSocket URL for anvilbase realtime subscribe |
NO_COLOR | — | unset | disable ANSI color output |
CI | — | unset | CI mode (non-interactive defaults) |
Next: Ports.