ServerSelf-host

Self-host

Run the Ear3 voice pipeline on your own Kubernetes cluster, in your own cloud account. Same Docker image as Ear3-managed, same SDK on the client — you only swap out where sessions spawn.

When this makes sense

  • Compliance — audio must stay inside your VPC / GovCloud / on-prem
  • Data residency — respondents in a region we don’t offer yet
  • Custom Python processors — you need bespoke Pipecat processors (guardrails, own moderation LLM, custom recording sink)
  • Cost floor at scale — > 100k interviews/month and you already have a voice-ops SRE

If none of the above applies, stay on Ear3-managed. Self-hosting real-time voice is a real ops commitment — see the honest cost math on the Server Overview.

What you’re standing up

    ┌────────────────────────────────────────────┐
    │  Your Kubernetes cluster                    │
    │                                             │
    │  ┌─────────────────────────────────────┐   │
    │  │ ear3-pipecat-worker (Deployment)    │   │
    │  │  • Python 3.11 + pipecat-ai 1.3     │   │
    │  │  • FastAPI /spawn endpoint          │   │
    │  │  • Warm pool of bot workers         │   │
    │  └─────────────────────────────────────┘   │
    │                     │                       │
    │                     ▼                       │
    │  ┌─────────────────────────────────────┐   │
    │  │ Redis (session state, warm pool)    │   │
    │  └─────────────────────────────────────┘   │
    └────────────────────────────────────────────┘

                        │ HTTPS (spawn requests)

                  app.ear3.ai
                  (session mint, dashboard, webhooks)

The daemon is pipecat-cloud-server — an open FastAPI service that exposes a POST / “spawn a bot” endpoint. Ear3’s app calls it the same way it would call Pipecat Cloud.

Prerequisites

  • Kubernetes ≥ 1.27 with an ingress controller
  • Node pool sized for your peak concurrency (rough rule: 1 vCPU per concurrent session for CPU-only STT, or 1 GPU per ~10 sessions if you’re also self-hosting Whisper)
  • API keys for the model providers you plan to use — Deepgram, Cartesia, OpenAI / Anthropic / Google, Daily. Set as env-vars on the worker. The worker never asks Ear3 for them.
  • A Daily account (or a self-hosted SFU — Daily is the default; talk to us about custom SFU integration)

The Docker image

docker pull ghcr.io/ear3-ai/pipecat-cloud-server:v1.3.0

Reference Dockerfile lives in the ear3-ai/pipecat-cloud-server repo — clone if you need to bake in custom Pipecat processors.

Deploying on Kubernetes

Minimal Deployment + Service manifest:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ear3-pipecat
spec:
  replicas: 3
  selector:
    matchLabels: { app: ear3-pipecat }
  template:
    metadata:
      labels: { app: ear3-pipecat }
    spec:
      containers:
        - name: bot-server
          image: ghcr.io/ear3-ai/pipecat-cloud-server:v1.3.0
          ports: [{ containerPort: 7860 }]
          resources:
            requests: { cpu: "2",   memory: 4Gi }
            limits:   { cpu: "4",   memory: 8Gi }
          env:
            - { name: DAILY_API_KEY,    valueFrom: { secretKeyRef: { name: ear3-secrets, key: daily } } }
            - { name: DEEPGRAM_API_KEY, valueFrom: { secretKeyRef: { name: ear3-secrets, key: deepgram } } }
            - { name: OPENAI_API_KEY,   valueFrom: { secretKeyRef: { name: ear3-secrets, key: openai } } }
            - { name: CARTESIA_API_KEY, valueFrom: { secretKeyRef: { name: ear3-secrets, key: cartesia } } }
            - { name: EAR3_BACKEND_URL, value: "https://app.ear3.ai" }
---
apiVersion: v1
kind: Service
metadata:
  name: ear3-pipecat
spec:
  selector: { app: ear3-pipecat }
  ports: [{ port: 443, targetPort: 7860 }]
  type: ClusterIP

Expose it via your existing ingress with TLS — Ear3 only speaks to HTTPS endpoints.

Pointing Ear3 at your cluster

In your workspace dashboard → Settings → Server → Self-host, set:

  • Pipecat endpointhttps://pipecat.your-domain.com
  • Auth token — a shared secret you set on the worker’s ingress

From that moment forward, every session spawned in your workspace goes to your cluster instead of Pipecat Cloud. Nothing in the SDK, the respondent UI, or the webhook contract changes.

How your app talks to your worker

The client SDK doesn’t know which substrate it’s on. It always POSTs to app.ear3.ai. Our backend decides where to spawn the bot based on your workspace config.

Client SDK (browser)
   │  POST /api/v2/sdk/connect
   │  { interviewId, publishableKey, metadata }

app.ear3.ai backend
   │  1. Verify pk → find workspace
   │  2. Read workspace.pipecatEndpoint  (may be null)
   │  3. Route:
   │       null   → spawn on Pipecat Cloud (default)
   │       set    → spawn on your endpoint

┌──────────────────────────────────┬────────────────────────────────┐
│  Ear3-managed (default)          │  Self-host (your endpoint)     │
│                                  │                                │
│  POST api.pipecat.daily.co/...   │  POST https://pipecat.you.com  │
│  Authorization: Bearer PCC_KEY   │  Authorization: Bearer         │
│                                  │      workspace.pipecatToken    │
│                                  │  (token encrypted at rest      │
│                                  │   via KMS, decrypted per call) │
│                                  │                                │
│  Response: { room_url, token }   │  Response: { room_url, token } │
└──────────────────────────────────┴────────────────────────────────┘
   │                                                              │
   └────────────► returned to client ──────────────────────────────┘


Client joins the Daily room → conversation

Key implication for your k8s setup: your worker ingress must be reachable by app.ear3.ai over public HTTPS. That means:

  • TLS terminated at your ingress (Let’s Encrypt / cert-manager or your own CA)
  • A public DNS name your ingress resolves to
  • Firewall / network policy that lets our egress reach it

If your compliance model requires the worker to be fully private (no public ingress at all), talk to us — we have a private-tunnel option (WireGuard between our egress worker and your cluster) but it needs manual setup per customer.

Security guarantees on our side

  • Token at rest — your worker auth token is encrypted with our KMS key. We can’t read it out of the DB in plaintext; each spawn call decrypts on-the-fly
  • Per-workspace rate limit — a misbehaving worker in your cluster can’t blow up spawn latency for other Ear3 customers
  • Spawn timeout — 10 seconds budget. If your endpoint doesn’t respond, the SDK gets a clean error message (“Your worker is unreachable — check the endpoint status”) rather than a hang
  • No secret exfiltration — we never send our Deepgram / Cartesia / OpenAI API keys to your worker. Your worker uses your vendor keys, set as k8s Secrets. This is why you own the vendor accounts on self-host

Warm pool sizing

Cold-starting a Python worker takes ~4 seconds on a warm image and ~15 seconds if the image is being pulled. Neither is acceptable for interactive voice.

Run a warm pool: replicas = P95 concurrent sessions + 20% headroom, plus a HPA that kicks in on CPU > 70%.

For workloads that spike (marketing pushes, cohort emails), pre-warm by bumping replicas 5 min before the spike lands.

Observability

The server emits OpenTelemetry traces via pipecat-ai[tracing]. Point them at Honeycomb / Datadog / your OTel collector:

env:
  - { name: OTEL_EXPORTER_OTLP_ENDPOINT, value: "https://otel.your-domain.com:4317" }
  - { name: OTEL_SERVICE_NAME,           value: "ear3-pipecat" }

Key spans to watch:

  • session.start — cold-start budget (should be under 200 ms on a warm pod)
  • llm.turn — LLM round-trip (main latency driver)
  • tts.first_byte — TTS TTFB (should be under 400 ms with Cartesia Sonic)

Migrating back to Ear3-managed

Blow away the endpoint override in workspace settings and the next session spawns on Ear3-managed Pipecat Cloud again. No data migration required — the pipeline is stateless.

Support tier

Self-hosting is on a paid support tier (SLA, upgrade assistance, incident escalation). Reach out via support@ear3.ai or in the #self-host channel on our Discord.


Built by Ear3 — voice interviews for any app.
⌘/