Self-hosting
Configuration
Environment variables for the control-plane and edge, production guardrails, and observability.
Control-plane
| Var | Purpose | Default |
|---|---|---|
DATABASE_URL | Postgres DSN | local socket DSN |
PORT | HTTP port | 8080 |
TOKEN_HMAC_SECRET | widget JWT signing secret | dev default (must set in prod) |
EDGE_ORIGIN_DEFAULT | fallback proxy origin | http://localhost:3001 |
WORKER_ENABLED | 1 starts background pollers | off |
CD_ENV | production enables guardrails | unset |
CREDENTIAL_ENC_KEY | 32-byte key (base64/hex) to encrypt DNS credentials | unset (required in prod to store credentials) |
CORS_ALLOWED_ORIGINS | optional comma-separated allowlist | unset (reflects) |
DEMO_API_KEY | seeded demo key | sk_test_demo |
ADAPTER_TEST_MOCK, DNS_STUB_FILE, DNS_STUB_JSON | test bypasses (refused in prod) | unset |
Edge
| Var | Purpose | Default |
|---|---|---|
CONTROLPLANE_URL | control-plane base for ask | http://localhost:8080 |
EDGE_TLS_PORT | on-demand-TLS listener | 8443 |
EDGE_HTTP_PORT | plain-HTTP admin/health | 8081 |
EDGE_ISSUER | internal or letsencrypt | internal |
EDGE_STORAGE_DIR | cert/key + CA storage | ./edge-data |
EDGE_ACME_EMAIL | ACME contact | "" |
EDGE_ACME_STAGING | Let's Encrypt staging | false |
EDGE_ASK_TIMEOUT | max time for one ask | 3s |
EDGE_ASK_POSITIVE_TTL | cache TTL for allow=true | 60s |
EDGE_ASK_NEGATIVE_TTL | cache TTL for allow=false | 5s |
EDGE_PROXY_TIMEOUT | upstream request timeout | 30s |
Production guardrails
Setting CD_ENV=production makes the control-plane refuse to start (or store) on
unsafe configuration:
TOKEN_HMAC_SECRETunset or the dev default → refuse to start.ADAPTER_TEST_MOCKorDNS_STUB_*set → refuse to start.- Storing a DNS credential without
CREDENTIAL_ENC_KEY→ refused.
Observability
GET /metrics exposes Prometheus gauges (aggregate only, no tenant identifiers):
customdomain_connections{state=…}customdomain_certificates{status=…}customdomain_webhook_deliveries{status=…}customdomain_certificates_expiring_soon— the renewal-failure alerting signal; alert on this (andcertificates{status="failed"}) in your monitoring system.
Background worker
Set WORKER_ENABLED=1 to run the pollers that advance connections on their own:
auto-verify (ownership TXT), auto-propagate (records → live), drift detection,
and webhook retry. Interval 5s, batch 100, cert TTL mirror 90d.