AI-API: Self-Hosted Bifrost Gateway
Managing multiple AI provider APIs (OpenAI, Anthropic, Google) across different services becomes unwieldy quickly. I prefer a unified gateway approach. I started with the LiteLLM reverse proxy and later switched to Bifrost for two main reasons:
- Smaller memory footprint: LiteLLM’s reverse proxy consumed roughly 500-1000 MB in my setup, which is significant for a single low-cost host.
- Less configuration overhead: I am not using advanced governance/rate-management features, and Bifrost’s pass-through model configuration reduced alias and routing management for my use case.
Why Bifrost?
Bifrost translates requests between different AI provider APIs, presenting a unified OpenAI-compatible interface. This means:
- Single integration point - all services use the same API format
- Provider abstraction - switch between models without changing application code
- Centralized authentication - one master key instead of multiple provider keys
- Built-in features - logging, rate limiting, cost tracking, and fallbacks
Configuration
My AI-API runs as a Docker container in the HomeStack with this Bifrost configuration:
{
"$schema": "https://www.getbifrost.ai/schema",
"providers": {
"openai": {
"keys": [
{ "name": "openai-primary", "value": "env.OPENAI_API_KEY", "weight": 1 },
]
},
"anthropic": {
"keys": [
{ "name": "anthropic-primary", "value": "env.ANTHROPIC_API_KEY", "weight": 1 }
]
},
"gemini": {
"keys": [
{ "name": "gemini-primary", "value": "env.GEMINI_API_KEY", "weight": 1 }
]
},
"vertex": {
"keys": [
{
"name": "vertex-primary",
"weight": 1,
"vertex_key_config": {
"project_id": "vertex-487414",
"region": "global",
"auth_credentials": "env.VERTEX_CREDENTIALS_JSON"
}
}
]
}
},
"governance": {
"virtual_keys": [
{
"id": "vk-master",
"name": "master",
"value": "env.AI_API_MK",
"is_active": true,
"provider_configs": [
{ "provider": "openai" },
{ "provider": "anthropic" },
{ "provider": "gemini" },
{ "provider": "vertex" }
]
}
]
},
"auth_config": {
"admin_username": "env.AI_API_ADMIN_USER",
"admin_password": "env.AI_API_ADMIN_PASS",
"is_enabled": true,
"disable_auth_on_inference": true
},
"client": {
"enforce_governance_header": true,
"enforce_auth_on_inference": true,
"enable_litellm_fallback": true
},
"config_store": {
"enabled": true,
"type": "sqlite",
"config": {
"path": "/app/db/bifrost.db"
}
}
}
Docker Integration
The AI-API service integrates seamlessly into my Docker Compose stack:
ai-api:
container_name: ai-api
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- OPENAI_API_KEY_BF=${OPENAI_API_KEY_BF}
- ANTHROPIC_API_KEY_BF=${ANTHROPIC_API_KEY_BF}
- AI_API_MK=${AI_API_MK}
- GEMINI_API_KEY=${GEMINI_API_KEY}
- GOOGLE_APPLICATION_CREDENTIALS=${VERTEX_CREDENTIALS_JSON}
- VERTEX_CREDENTIALS_JSON=${VERTEX_CREDENTIALS_JSON}
- AI_API_ADMIN_USER=${AI_API_ADMIN_USER}
- AI_API_ADMIN_PASS=${AI_API_ADMIN_PASS}
- APP_PORT=10200
image: maximhq/bifrost:latest
labels:
- traefik.enable=true
- traefik.http.services.ai-api.loadbalancer.server.port=10200
- traefik.http.routers.ai-api.middlewares=ai-api-stripprefix
- traefik.http.middlewares.ai-api-stripprefix.stripprefix.prefixes=/ai-api
ports:
- 10200:10200
profiles:
- site
- dev
- prod
- stage
restart: unless-stopped
volumes:
- ./ai-api/config.json:/app/data/config.json:ro
- ./ai-api/db:/app/db
Key configuration details:
- Path-based routing - accessible at
www.nickhedberg.com/ai-api/v1 - Environment variables - provider API keys loaded from encrypted secrets
- Volume mount - configuration file mounted into container
- Master key authentication - single key controls access to all models
Usage Examples
Services can now use any AI model through a single endpoint:
Chat Completion
const response = await fetch(
"https://www.nickhedberg.com/ai-api/v1/chat/completions",
{
method: "POST",
headers: {
Authorization: `Bearer ${AI_API_MK}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "anthropic/claude-4-5-sonnet",
messages: [{ role: "user", content: "Explain containerization" }],
}),
},
);
Model Switching
// Switch providers without changing code
const models = ["openai/gpt-4o-mini", "anthropic/claude-3-5-sonnet", "vertex/gemini-2.0-flash"];
const model = models[Math.floor(Math.random() * models.length)];
const response = await fetch(
"https://www.nickhedberg.com/ai-api/v1/chat/completions",
{
// ... same headers and structure
body: JSON.stringify({
model: model, // Dynamic model selection
messages: messages,
}),
},
);