Skip to main content

Self-Hosted Proxy

Self-hosted mode runs the same knoxcall/proxy Docker image on your infrastructure. Live API traffic — request bodies, response bodies, injected secrets — stays entirely within your VPC. Only routing metadata, tenant config, and re-encrypted secrets flow from the control plane over TLS.
Requires a Pro or Enterprise subscription with byoAgentEnabled (the same flag gates the Go Agent). Reach out if you need to pilot — we can provision a sandbox agent.

Why Self-Host

  • Data-residency regulation: HIPAA, FedRAMP-adjacent, EU-residency, sovereign-cloud contracts that require payload data to stay on-prem.
  • Air-gapped environments: systems without outbound internet except to a single control-plane endpoint.
  • Latency-sensitive workloads: proxy sits in the same VPC as your apps and upstream APIs.
  • Compliance audits: every byte of customer data remains under your audit log.

How It Works

┌──────────────────────┐       HTTPS (session bundles,
│  KnoxCall cloud      │       analytics, heartbeat)
│  (control plane)     │ ◀─────────────────────────────┐
│  Admin UI, routes,   │                               │
│  secrets (encrypted) │                               │
└──────────────────────┘                               │

┌──────────────────────────────────────────────────────┤
│  Your infrastructure                                 │
│                                                      │
│  ┌────────────┐    ┌───────────────┐   ┌──────────┐ │
│  │  Your app  │───▶│ knoxcall/     │──▶│ Upstream │ │
│  │            │    │ proxy         │   │   API    │ │
│  │            │    │ (docker)      │   │          │ │
│  └────────────┘    └───────────────┘   └──────────┘ │
│                          │                           │
│                    ┌─────┴─────┐                    │
│                    │ Postgres  │ (your DB)          │
│                    │  Redis    │                    │
│                    └───────────┘                    │
└─────────────────────────────────────────────────────┘
  • Control plane at knoxcall.com holds route config and MASTER_KEY-wrapped secrets.
  • Your container pulls a signed session bundle every hour.
  • Request flow: your app → knoxcall/proxy (your infra) → upstream API. Control-plane hop only happens during session-bundle refresh.

Prerequisites

  1. Credentials: create a server-mode agent under Automation → Agents with mode: server. Copy the kc_agent_xxx ID and secret (shown only once).
  2. Local Postgres + Redis: one of each, reachable from the container. SQLite is not supported.
  3. Local MASTER_KEY_B64: generate a 32-byte base64 key locally (openssl rand -base64 32). Do NOT share this with KnoxCall; it stays on your infrastructure and wraps integration credentials at rest.
  4. Outbound HTTPS to knoxcall.com (for session-bundle refresh + metrics reporting).
  5. Public HTTPS endpoint (typically https://proxy.yourdomain.com) behind your preferred TLS terminator.

Install

Docker Compose

Before bringing anything up, generate two strong secrets and place them in a local .env file (never commit):
# MASTER_KEY_B64 — stays on your infra; wraps integration credentials at rest
openssl rand -base64 32

# POSTGRES_PASSWORD — database credential; any long random string
openssl rand -base64 24
Create .env alongside the compose file:
KNOXCALL_TENANT_ID=<from-admin-ui>
KNOXCALL_AGENT_ID=kc_agent_xxx
KNOXCALL_AGENT_SECRET=<shown-once-on-creation>
MASTER_KEY_B64=<openssl output from above>
POSTGRES_PASSWORD=<openssl output from above>
Then the compose file:
services:
  proxy:
    image: knoxcall/proxy:latest
    restart: unless-stopped
    ports: ["8080:8080"]
    environment:
      KNOXCALL_DEPLOYMENT_MODE: self_hosted
      KNOXCALL_TENANT_ID: ${KNOXCALL_TENANT_ID}
      KNOXCALL_AGENT_ID: ${KNOXCALL_AGENT_ID}
      KNOXCALL_AGENT_SECRET: ${KNOXCALL_AGENT_SECRET}
      KNOXCALL_CONTROL_PLANE_URL: https://knoxcall.com
      PG_URL: postgres://kc:${POSTGRES_PASSWORD}@postgres:5432/kc
      MASTER_KEY_B64: ${MASTER_KEY_B64}
      REDIS_URL: redis://redis:6379
    depends_on: [postgres, redis]

  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: kc
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: kc
    volumes: ["./pgdata:/var/lib/postgresql/data"]

  redis:
    image: redis:7-alpine
docker compose up -d, then point your TLS terminator (Caddy, Nginx, Cloudflare Tunnel, ALB) at :8080.

Health Checks

Once running, the container exposes:
  • GET /healthz — readiness probe. Returns 503 until the first control-plane sync succeeds, then 200 with sync stats. Returns 503 again if the bundle goes stale (control plane unreachable for >1 hour).
  • GET /livez — liveness probe. Always 200 while the process is responsive.
Point your orchestrator’s readiness probe at /healthz so a container with a dead control-plane link is depooled automatically.

Session Bundles

Every hour the container POSTs to /agent/v1/session with its agent credentials and receives a bundle containing:
  • Routes merged with their production-environment config
  • Secrets re-encrypted with an HKDF-derived session key (decrypts locally)
  • Tenant metadata (slug, subdomain hash)
  • Environments and API keys
The session key never leaves the container. The MASTER_KEY_B64 on the control plane is never sent — secrets are re-encrypted per-window so even a packet capture during refresh yields nothing useful past the current hour.

Local Integrations

The control plane never pushes KnoxCall’s own integration credentials (SMTP, Twilio, S3, Anthropic) to a self-hosted container. You configure your own under Settings → Integrations. Required minimum for a functional self-hosted deployment:
  • Email provider — otherwise alerts, invitations, and password resets fail silently.
Optional:
  • S3 — for response-body archival
  • Anthropic — for AI anomaly detection on your alerts
  • Twilio — for SMS alerts

Tamper Seal

Every knoxcall/proxy image is built with a two-pass build_sig:
  1. Compile the image with a placeholder signature.
  2. Hash the compiled dist/ contents.
  3. HMAC-SHA256 of hash:version with a CI-only secret.
  4. Rebuild with the real signature baked in.
The control plane validates this on every session refresh. In strict mode (KNOXCALL_STRICT_TAMPER_CHECK=true), an unknown signature = session refused. Default mode logs a tamper event but still issues the session so you have time to investigate.

Next Steps