TL;DR
- Self-hosting an LLM gateway on Kubernetes brings external model routing, credential security, token budgeting, and caching entirely within your cluster boundary.
- Bifrost, an open-source AI gateway written in Go by Maxim AI, adds 11 microseconds of routing overhead at 5,000 requests per second.
- Deploying the gateway with Helm provides built-in high availability, horizontal autoscaling, Kubernetes pod discovery, and native Prometheus telemetry.
- Teams can complete a production-grade Kubernetes deployment over a single weekend by provisioning PostgreSQL storage, injecting encrypted API keys, and configuring Ingress controllers.
Production AI applications running across multiple commercial and local model providers fail when upstream APIs return rate-limit errors, network timeouts, or sudden outages. Rather than hardcoding provider credentials and retry loops into separate microservices, platform engineers route inference calls through a dedicated ingress point. To self-host an LLM gateway on Kubernetes means operating a centralized proxy inside your own cloud boundary to control model routing, credentials, and telemetry without sending prompt logs to third-party services. Bifrost is an open-source AI gateway designed for high-concurrency environments, supporting drop-in SDK replacements across supported providers. This weekend guide walks through the architectural choices, Helm configurations, ingress setups, and observability pipelines required to run a scalable LLM gateway on Kubernetes.
Why Self-Host an LLM Gateway on Kubernetes?
A self-hosted LLM gateway centralizes AI routing, key rotation, and request governance within an organization's existing Kubernetes infrastructure to eliminate security blind spots and vendor lock-in. Instead of exposing raw provider keys to every developer pod, the gateway accepts requests via virtual credentials, checks policy boundaries, and distributes traffic across providers.
+-----------------------------------------------------------------------+
| Kubernetes Cluster |
| |
| +--------------------+ +------------------------------------+ |
| | Application Pods | ----> | Bifrost Gateway Service | |
| | (Client SDKs) | | (ClusterIP / Ingress) | |
| +--------------------+ +-----------------+------------------+ |
| | |
| +-----------------------------+-----------+ |
| | | | |
| v v v |
| +-------------------+ +-------------+ +------------+ |
| | Virtual Keys | | Semantic | | Prometheus | |
| | & Rate Limits | | Caching | | Metrics | |
| +-------------------+ +-------------+ +------------+ |
| | | |
+-------------------|-----------------------------|---------------------+
v v
+-------------------------+ +-------------------------+
| Upstream Cloud APIs | | In-Cluster Inference |
| (OpenAI, Bedrock, etc.) | | (vLLM / Triton / Ollama)|
+-------------------------+ +-------------------------+
When engineering teams scale generative AI features, five infrastructure challenges arise almost immediately:
- Credential dispersion: Distributing proprietary API keys across dozens of Kubernetes namespaces, secrets, and developer repositories increases the risk of secret leaks.
- Provider instability: Upstream provider downtime or rate limits (HTTP 429 status codes) break application workflows unless complex fallback logic is re-implemented across every service.
- Cost opacity: Without centralized attribution, platform teams cannot trace which microservices or user groups generate token spikes.
- Compliance boundaries: Regulated environments subject to HIPAA, SOC 2, or GDPR require strict control over prompt residency, preventing data from flowing through intermediate SaaS proxies.
- Latency penalties: Adding proxy layers can degrade the user experience of streaming text tokens if the proxy architecture introduces millisecond-level bottlenecks.
Operating the gateway inside Kubernetes resolves these operational issues. The cluster scheduler manages pod health, native services route internal RPCs over private subnets, and in-VPC deployments ensure that unencrypted prompts never touch external infrastructure before routing to authorized model providers.
Architecture of a Self-Hosted LLM Gateway on Kubernetes
A production LLM gateway architecture on Kubernetes decouples the stateless routing data plane from stateful storage layers such as PostgreSQL and Redis. The gateway pods handle HTTP and gRPC traffic, stream Server-Sent Events (SSE) back to client pods, and synchronize cluster state across nodes.
When designing the deployment, platform engineers must choose between a lightweight single-replica setup for development or a multi-replica clustered topology for mission-critical workloads. Bifrost supports both operating models out of the box through its official Helm chart.
| Deployment Model | Compute Pattern | Storage Backend | State Synchronization | Target Workload |
|---|---|---|---|---|
| Sandbox / Staging | StatefulSet (1 Replica) | Local SQLite (PersistentVolumeClaim) | Single-process memory | Local developer clusters, integration testing |
| High Availability (HA) | Deployment (3+ Replicas) | Managed PostgreSQL (RDS/Cloud SQL) | Kubernetes API Pod Discovery | Production microservices, internal enterprise APIs |
| Distributed Multi-Zone | Multi-AZ Deployment | High-Availability PostgreSQL + Redis | Gossip-based peer discovery | Cross-region failover, mission-critical production |
In production setups, stateful components should remain decoupled from gateway pods. SQLite on a PersistentVolumeClaim works well for sandboxes, but shared persistent storage introduces locking issues when scaling out to multiple replicas. A stateless Deployment backed by a managed PostgreSQL instance allows the Horizontal Pod Autoscaler (HPA) to scale pods dynamically based on CPU and concurrent request metrics.
Prerequisites and Pre-Flight Cluster Planning
Deploying an enterprise-grade LLM gateway requires a Kubernetes cluster running version 1.19 or higher, administrative access via kubectl, and Helm 3.2.0 or newer. Additionally, verify that your cluster has a default StorageClass configured if persistent volumes are required for local caching.
Before applying manifests, complete the following pre-flight preparations:
-
Namespace Isolation: Dedicate a distinct namespace (such as
bifrost) to isolate network policies, role bindings, and secrets. - PostgreSQL Database: Provision a dedicated PostgreSQL database instance (version 14 or later) with UTF-8 encoding. Ensure network connectivity from the Kubernetes worker node subnets to the database port.
- Master Encryption Key: Generate a cryptographically secure 32-byte key using OpenSSL to encrypt provider tokens and virtual keys at rest.
- Provider Credentials: Gather API keys for OpenAI, Anthropic, AWS Bedrock, Google Vertex AI, or local in-cluster endpoints like vLLM.
- Ingress and DNS: Ensure an Ingress controller (such as ingress-nginx) is operational if external or cross-cluster access is required.
According to official Kubernetes networking documentation, using explicit namespaces and standard Ingress controllers simplifies network policy management and TLS termination across microservice boundaries.
Step 1: Configuring Storage, Secrets, and the Helm Repository
Begin the setup on Saturday morning by initializing the Bifrost Helm repository and creating Kubernetes secrets to hold sensitive credentials. Never store API keys or database passwords in plaintext Helm values files.
First, add and update the official Bifrost Helm repository:
helm repo add bifrost https://maximhq.github.io/bifrost/helm-charts
helm repo update
Next, create the dedicated namespace:
kubectl create namespace bifrost
Generate the master encryption key and store it inside a native Kubernetes Secret. This key secures sensitive credentials in the database:
# Generate a 32-byte base64-encoded key
ENCRYPTION_KEY=$(openssl rand -base64 32)
kubectl create secret generic bifrost-encryption-key \
--namespace bifrost \
--from-literal=encryption-key="${ENCRYPTION_KEY}"
Create a second secret containing upstream provider credentials and PostgreSQL connection parameters:
kubectl create secret generic bifrost-core-secrets \
--namespace bifrost \
--from-literal=postgres-password="YourSecureDbPasswordHere" \
--from-literal=openai-api-key="sk-proj-yourOpenAiKey" \
--from-literal=anthropic-api-key="sk-ant-yourAnthropicKey"
Managing secrets through native Kubernetes mechanisms allows integration with external secret stores such as HashiCorp Vault, AWS Secrets Manager, or Google Secret Manager via the Kubernetes External Secrets Operator.
Step 2: Deploying Bifrost with Helm and High Availability
Deploying Bifrost in high availability mode ensures that incoming inference requests continue processing even if a worker node fails or undergoes rolling updates. This step uses a structured values.yaml file to configure multi-replica scaling, database connectivity, and resource reservations.
Create a local deployment configuration file named bifrost-production-values.yaml:
# bifrost-production-values.yaml
image:
repository: maximhq/bifrost
tag: v1.4.11
pullPolicy: IfNotPresent
replicaCount: 3
bifrost:
encryptionKeySecret:
name: bifrost-encryption-key
key: encryption-key
database:
type: postgres
host: "postgres-service.database.svc.cluster.local"
port: 5432
name: "bifrost_db"
user: "bifrost_user"
sslmode: "require"
passwordSecret:
name: bifrost-core-secrets
key: postgres-password
clustering:
enabled: true
discoveryMethod: "kubernetes"
k8sLabelSelector: "app.kubernetes.io/name=bifrost"
providers:
openai:
keys:
- name: "primary-openai"
value: "env.OPENAI_API_KEY"
weight: 1
anthropic:
keys:
- name: "primary-anthropic"
value: "env.ANTHROPIC_API_KEY"
weight: 1
providerSecrets:
openai:
existingSecret: bifrost-core-secrets
key: openai-api-key
envVar: OPENAI_API_KEY
anthropic:
existingSecret: bifrost-core-secrets
key: anthropic-api-key
envVar: ANTHROPIC_API_KEY
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "2000m"
memory: "2Gi"
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- bifrost
topologyKey: "kubernetes.io/hostname"
Apply the Helm release using the custom configuration file:
helm install bifrost bifrost/bifrost \
--namespace bifrost \
-f bifrost-production-values.yaml
The configuration sets pod anti-affinity rules, instructing Kubernetes to schedule gateway replicas across distinct physical worker nodes. Clustering uses native Kubernetes API discovery to locate peer pods and sync state across the cluster.
Verify that all pods have reached the Running state:
kubectl get pods -n bifrost -l app.kubernetes.io/name=bifrost
Step 3: Configuring Ingress, TLS, and Health Probes
Exposing the LLM gateway to client microservices inside or outside the cluster requires reliable networking rules and continuous health checks. Streaming LLM tokens rely on long-lived HTTP connections, meaning ingress proxies must be configured to prevent connection drops mid-generation.
Bifrost serves HTTP traffic on port 8080 and exposes a dedicated /health endpoint on the same port. Configure readiness and liveness probes in your Helm values or deployment manifests:
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 2
successThreshold: 1
failureThreshold: 2
For ingress routing via ingress-nginx, define an Ingress manifest that disables proxy response buffering. Buffering breaks Server-Sent Events, increasing time-to-first-token (TTFT) for user-facing applications.
# bifrost-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: bifrost-ingress
namespace: bifrost
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
nginx.ingress.kubernetes.io/proxy-buffering: "off"
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- llm-gateway.internal.example.com
secretName: bifrost-tls-cert
rules:
- host: llm-gateway.internal.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: bifrost
port:
number: 8080
Apply the ingress manifest:
kubectl apply -f bifrost-ingress.yaml
Once applied, applications can call the gateway using its fully qualified domain name (FQDN). Bifrost serves as a drop-in replacement for OpenAI-compatible SDKs, requiring changes only to the base URL parameter in application code.
Step 4: Setting Up Model Routing, Fallbacks, and Virtual Keys
Configuring intelligent routing, fallback chains, and virtual keys ensures resilient operation under provider outages while enforcing departmental spend controls. The gateway handles model translation transparently, allowing client pods to request a standard model alias while the gateway routes to available backends.
Through Bifrost's configuration engine, administrators configure automatic fallbacks. If a primary provider returns an HTTP 500 or 429 status code, traffic diverts instantly to an alternative model or provider without throwing an exception to the client pod.
Incoming Request: "claude-3-5-sonnet"
|
v
+-----------------------+
| Bifrost Proxy Engine |
+-----------+-----------+
|
+-----------+-----------+
| |
(Primary: Healthy) (Primary Fails: 429 / 5xx)
| |
v v
+---------------+ +-----------------------+
| Anthropic API | | AWS Bedrock Fallback |
| Direct | | (claude-3-5-sonnet) |
+---------------+ +-----------------------+
To govern access across teams, configure virtual keys. A virtual key acts as a virtual token issued to specific application deployments or teams, enforcing budgets, rate limits, and allowed model lists.
{
"name": "data-science-team-key",
"budget": {
"amount": 500.0,
"currency": "USD",
"reset_period": "monthly"
},
"rate_limits": {
"requests_per_minute": 120,
"tokens_per_minute": 150000
},
"allowed_models": [
"openai/gpt-4o",
"anthropic/claude-3-5-sonnet",
"meta-llama/llama-3.1-70b"
]
}
In addition to routing, enabling semantic caching reduces inference spend and response latency by serving semantically similar requests directly from an in-cluster vector cache without invoking upstream APIs. Review the comprehensive LLM Gateway Buyer's Guide to evaluate how caching mechanisms lower overall token overhead across large engineering organizations.
Step 5: Enabling Observability with Prometheus and OpenTelemetry
Observability is essential when managing production LLM traffic. Platform engineers must monitor token consumption, time-to-first-token latency, error rates, and cache hit ratios across all services. Bifrost provides native Prometheus metrics and distributed tracing via OpenTelemetry without requiring external daemon sidecars.
The gateway exposes Prometheus metrics natively. If your cluster operates the Prometheus Operator, configure a ServiceMonitor resource to scrape metrics on port 8080:
# bifrost-servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: bifrost-metrics
namespace: bifrost
labels:
release: prometheus-stack
spec:
selector:
matchLabels:
app.kubernetes.io/name: bifrost
endpoints:
- port: http
path: /metrics
interval: 15s
scrapeTimeout: 10s
Apply the ServiceMonitor configuration:
kubectl apply -f bifrost-servicemonitor.yaml
The Prometheus metrics include request counts, token counters split by prompt and completion, error statuses, and histogram latencies.
For distributed tracing across microservices, Bifrost exports trace telemetry using the OpenTelemetry (OTLP) protocol. Traces capture the full request lifecycle, including request parsing, semantic cache lookup, upstream provider latency, and token streaming durations. Standardizing on OpenTelemetry standards enables platform teams to visualize request flows in Grafana Tempo, Jaeger, or Honeycomb.
In sustained tests published on the official benchmarks page, Bifrost introduced only 11 microseconds of overhead per request under sustained loads of 5,000 requests per second. This negligible latency makes it suitable for high-throughput microservices where intermediate network hops must not impact user experience.
Step 6: Extending Cluster Governance to Developer Workstations with Bifrost Edge
While securing server-side microservices within Kubernetes is a major milestone, ungoverned AI access on developer laptops creates an organizational blind spot known as shadow AI. Beyond routing, Bifrost applies governance and security controls (virtual keys, budgets, guardrails, audit logs) centrally, and Bifrost Edge extends that same governance and security to AI traffic on employee machines, with endpoint enforcement on each device.
Bifrost operates as the centralized control plane and policy engine deployed on your infrastructure, while Bifrost Edge, currently in alpha, acts as the endpoint extension running on macOS, Windows, and Linux machines. It routes desktop AI tools, browser interfaces, and terminal coding assistants through the central Kubernetes gateway without requiring developers to change their local configuration files.
Key capabilities delivered by combining the Kubernetes gateway with Bifrost Edge include:
- Unified policy enforcement: Developers running desktop apps like Claude Desktop, Cursor, or terminal tools like Claude Code automatically inherit the virtual keys, budgets, and rate limits defined on the Kubernetes gateway.
- Application governance: Security administrators use app governance to approve or block specific desktop AI clients across employee machines.
- MCP server visibility: As developers wire Model Context Protocol (MCP) servers into their local environments, Edge inventories and controls tool permissions fleet-wide.
- Enterprise rollout: Systems teams deploy the Edge client silently across fleets via MDM deployment tools like Jamf, Microsoft Intune, and Kandji.
By extending the same governance policies enforced inside your Kubernetes cluster directly onto engineer workstations, platform teams maintain complete visibility over AI operations across both cloud services and local endpoints.
Operational Maintenance and Day-2 Guide
Operating an LLM gateway in production requires structured maintenance workflows for schema updates, provider key rotation, and disaster recovery. The following routine maintenance procedures ensure uninterrupted service.
Zero-Downtime Key Rotation
When rotating upstream provider keys (such as an OpenAI or Anthropic corporate credential), update the underlying Kubernetes secret:
kubectl create secret generic bifrost-core-secrets \
--namespace bifrost \
--from-literal=openai-api-key="sk-proj-newKeyHere" \
--dry-run=client -o yaml | kubectl apply -f -
Because Bifrost loads environment variables and watches configuration updates, performing a rollout restart propagates the updated credentials across all running pods without dropping active sessions:
kubectl rollout restart deployment/bifrost -n bifrost
Database Schema Migrations
Bifrost executes necessary schema migrations automatically upon startup. When upgrading gateway container versions, deploy an updated image tag through Helm. Multi-replica deployments coordinate startup sequences safely across peer nodes, ensuring that new migrations complete before incoming HTTP traffic switches to upgraded pods.
According to the official Helm documentation, utilizing declarative values files with strict version pinning (--set image.tag=v1.4.11) prevents accidental upgrades during automated CI/CD pipeline runs.
Frequently Asked Questions
What hardware resources are required to run an LLM gateway on Kubernetes?
A standard production deployment of Bifrost running three replicas requires minimal compute: approximately 250m CPU and 512Mi memory requests per pod, with limits set to 2 CPU and 2Gi memory. Because the gateway is compiled in Go and functions as a high-throughput network proxy rather than an inference engine, it runs efficiently on standard commodity CPU nodes without requiring expensive GPU accelerators.
Can a self-hosted LLM gateway route to local models running in the same cluster?
Yes. Bifrost routes requests to any OpenAI-compatible HTTP endpoint. This includes self-hosted open-weight model runtimes running inside the same Kubernetes cluster, such as vLLM, KServe, Triton Inference Server, or Ollama. Internal cluster services can be targeted directly using standard Kubernetes DNS names like http://vllm-service.inference.svc.cluster.local:8000/v1.
How does the gateway handle streaming responses via Server-Sent Events?
Bifrost streams Server-Sent Events (SSE) natively using chunked transfer encoding. When deploying behind Kubernetes Ingress controllers (such as ingress-nginx or Traefik), ensure that proxy response buffering is explicitly disabled. Disabling buffering ensures that generated tokens stream directly from upstream providers to client pods with zero intermediate buffering delay.
Does self-hosting an LLM gateway ensure complete data privacy?
Self-hosting the gateway ensures that all prompt logs, API keys, virtual tokens, routing rules, and internal metrics remain strictly within your private network boundary. However, if you route requests to external commercial model APIs (such as OpenAI or Anthropic), the prompt payload will still leave your network to reach that specific vendor unless you route exclusively to local in-cluster model runtimes.
How do virtual keys differ from native provider API keys?
Native provider API keys grant unrestricted access to a specific provider account and are difficult to rotate safely across distributed applications. Virtual keys are internal tokens generated and validated by the gateway. They allow administrators to assign fine-grained budgets, rate limits, and model access permissions to individual teams without ever revealing the master provider keys to application developers.
Is SQLite recommended for production Kubernetes deployments?
No. SQLite requires a PersistentVolumeClaim and locks the database file during concurrent write operations, which prevents scaling the gateway beyond a single pod. For production environments requiring high availability and autoscaling, always configure an external PostgreSQL database with UTF-8 encoding.
Getting Started and Next Steps
Self-hosting an LLM gateway on Kubernetes provides engineering teams with complete control over AI traffic, data privacy, model routing, and cost attribution. Over a single weekend, you can transition your infrastructure from scattered API tokens and brittle client-side retries to a centralized, highly available control plane.
Once your gateway is operational, test failure scenarios by intentionally revoking a primary provider key to verify that fallback chains route traffic smoothly to secondary models. Teams evaluating enterprise AI gateways can request a Bifrost demo or review the open-source repository to inspect the codebase and join the community.



Top comments (0)