This guide shows how to put NGINX in front of Bifrost for TLS termination, centralized routing, and load balancing.
Incoming reverse-proxy behavior is configured in your infrastructure layer (NGINX/Ingress), not in config.json.
When to use this setup
- You want HTTPS termination in front of Bifrost.
- You run multiple Bifrost replicas and want L7 load balancing.
- You need one stable gateway URL for SDKs and agent clients.
Docker Compose deployment
Use this when Bifrost and NGINX run as services in the same Compose project.
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- bifrost-1
- bifrost-2
- bifrost-3
bifrost-1:
image: maximhq/bifrost:latest
expose:
- "8080"
bifrost-2:
image: maximhq/bifrost:latest
expose:
- "8080"
bifrost-3:
image: maximhq/bifrost:latest
expose:
- "8080"
events {
worker_connections 1024;
}
http {
upstream bifrost_backend {
least_conn;
server bifrost-1:8080;
server bifrost-2:8080;
server bifrost-3:8080;
}
server {
listen 80;
location / {
proxy_pass http://bifrost_backend;
# Preserve original request context
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Keep streaming responses stable
proxy_http_version 1.1;
proxy_buffering off;
proxy_request_buffering off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
}
If you expose WebSocket traffic through the same endpoint, add upgrade headers in the same location / block:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
Use the same NGINX location / settings as above, and point upstream servers to hostnames/IPs reachable from that VM.
If you terminate TLS directly on NGINX, add:
listen 443 ssl;
server_name bifrost.example.com;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
Kubernetes (NGINX Ingress)
If you deploy with Helm, use Ingress values instead of a standalone NGINX config:
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/proxy-buffering: "off"
hosts:
- host: bifrost.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: bifrost-tls
hosts:
- bifrost.example.com
Verify the proxy path
# Docker Compose: render final config and validate syntax
docker compose config
# Kubernetes: validate ingress manifest locally
kubectl apply --dry-run=client -f ingress.yaml
# Health check through reverse proxy
curl -i http://bifrost.example.com/health
# Streaming check through NGINX
curl -N http://bifrost.example.com/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-mini",
"stream": true,
"messages": [{"role": "user", "content": "test stream"}]
}'
If streaming responses arrive in delayed bursts, confirm buffering is disabled in NGINX or Ingress annotations.
Runnable example files
Use the complete Docker Compose + Helm/Kubernetes example in the repository: