Hands-on: stand up your own gateway, then break it on purpose
7 lessons2026-08-13AI-generated
1Overview
An open-sourceLLM proxy: one OpenAI-compatible endpoint in front of many providers, adding virtual keys, budgets, routing, fallbacks and a spend log.
The gateway chapter argues the case. This one is the keyboard: install LiteLLM, put two providers behind one endpoint, cut a virtual key for a colleague with a hard budget, watch the 429 arrive when they spend it, and read the log that says who spent what. → It follows the same shape as the other per-tool chapters in this course — one product, start to finish, with the parts that bite you called out rather than smoothed over. → Note before you start: LiteLLM was rearchitected onto a Rust core with a Python SDK, so guides written before that describe a different deployment.
One product, end to end. Install it, route through it, cut a budgeted key, break it deliberately, and read what it recorded. By the end you have a gateway a small team can actually use — and you have seen each failure mode before it finds you in production.
→Run LiteLLM locally and route one request through it
→Put two providers behind a single OpenAI-compatible endpoint
→Cut a virtual key with a hard budget and watch it refuse the request
→Configure a fallback chain and prove it by taking a provider away
→Read the spend log and attribute a cost spike to a caller
→Route by task so bulk work never lands on the expensive model
→Deploy it somewhere your team can reach, with its own failure plan
1.3When to reach for it
Two or more AI projects, or two or more providers, and nobody can currently say who is spending what.
1.4Key parts
The proxy, a config file listing model routes, a database for keys and spend, virtual keys with budgets, and a fallback chain.
1.5Free vs paid
The proxy is open source and self-hostable at the cost of one container and a database. There is also a paid enterprise tier; nothing in this chapter needs it.
1.6Watch out
It sits on the critical path of every AI call your organisation makes. Anything that takes the gateway down takes all of them down, so it needs its own availability plan before production traffic does.
2Lessons 7
2.1Run the LiteLLM proxy and make a request
The litellm --config config.yaml command launches the LiteLLM proxy, exposing an OpenAI‑compatible endpoint that routes calls defined in a YAML file.
Start the LiteLLM gateway and receive a completion through it.
Create a new empty folder and install the proxy with uv tool install 'litellm[proxy]'
Add a file named config.yaml containing the model mapping and reference to the OpenAI API keyenvironment variable
Export your OpenAI key and start the gateway by running litellm --config config.yaml in the same terminal
Open a second terminal and send a request with curl http://0.0.0.0:4000/chat/completions using a JSON payload
You'll see A normal OpenAI‑shaped JSON response appears in the second terminal and a request line is logged in the first terminal where the proxy runs
Takeaway The LiteLLM gateway provides a single process that routes model calls defined in a YAML file via /chat/completions or /v1/chat/completions
Check What does the litellm --config config.yaml command achieve when starting the LiteLLM gateway?
Cost Free to run the proxy itself. You pay your provider (OpenAI, in this example) for the actual tokens the test request used — a few fractions of a cent.
2.2Call different models through the same endpoint
model_list entries in config.yaml define each provider that the proxy can route to.
Add a second provider to the configuration and invoke both models using identical request shapes, varying only the model name.
Stop the running proxy by pressing Ctrl+C in its terminal
Edit config.yaml to add a second entry under model_list with the new provider’s details
Export the Anthropic key using export ANTHROPIC_API_KEY=your_key in the same terminal
Restart the gateway with litellm --config config.yaml
Send a request for the OpenAI model with curl, keeping the endpoint and headers unchanged and setting model to gpt-3.5-turbo
Send a request for the Anthropic model with curl, changing only the model field to claude-haiku
You'll see Two responses from two distinct providers appear, each identifying its own model while the curl commands are otherwise identical
Takeaway Each new provider is added as another entry under model_list without altering the caller‑facing API
Check How does adding a second entry under model_list let you invoke different providers using identical request shapes?
Cost Free for the proxy config change. You pay each provider for its own request — two small charges instead of one.
2.3Create a budget‑limited virtual key and trigger its exhaustion
A virtual API key created through /key/generate that includes a max_budget limit.
Generate a virtual key with a $0.01 spend limit, use it until the limit is reached, and observe the proxy’s budget‑exceeded error.
Stop any running LiteLLM proxy and launch the quickstart stack with Docker using curl -sSL https://docs.litellm.ai/docker-compose.yml | docker compose -f - up -d
Verify that both containers are active by running docker compose ps
Locate the automatically generated master key in the downloaded docker‑compose.yml (or set your own by exporting LITELLM_MASTER_KEY before starting the stack)
Generate a virtual key with a $0.01 budget by calling curl 'http://0.0.0.0:4000/key/generate' --header 'Authorization: Bearer ' --header 'Content-Type: application/json' --data-raw '{"models": ["gpt-3.5-turbo"], "max_budget": 0.01}'
Use the returned virtual key to make several /chat/completions requests, authenticating with Authorization: Bearer until spend exceeds $0.01
Observe the final response: the proxy returns HTTP 400 and a JSON error containing ExceededTokenBudget
You'll see Initial requests succeed, then the same endpoint returns HTTP 400 with an ExceededTokenBudget message once the budget is spent
Takeaway A virtual key with a max_budget returns a 400 ExceededTokenBudget error as soon as its allocated spend is exhausted
Check What response does the proxy return when a virtual key’s $0.01 max_budget is exceeded?
Cost A few cents of real provider spend to exhaust the test budget — that is the point of the lesson. Running the quickstart's Postgres container is free; it is one more local container.
2.4Set up a fallback model and verify it triggers when the primary fails
litellm_settings.fallbacks maps a primary model like gpt‑3.5‑turbo to fallback models such as claude‑haiku.
Create a fallback from one model to another, break the primary key, and confirm the request still returns a 200 response.
Add a litellm_settings.fallbacks block to config.yaml that maps gpt-3.5-turbo to ["claude-haiku"] and set num_retries: 1
Edit the gpt-3.5-turbo entry’s api_key line so it references a non‑existent environment variable, e.g. api_key: os.environ/THIS_VAR_IS_NOT_SET
Restart the LiteLLM proxy to load the modified configuration
Send a request for model: "gpt-3.5-turbo" using curl as you normally would
Inspect the JSON response; verify that the model field reports claude-haiku and the HTTP status is 200
You'll see An HTTP 200 with a valid answer where the JSONmodel field shows claude-haiku instead of the broken gpt-3.5-turbo
Takeawayfallbacks under litellm_settings redirects errors to alternate models without changing the caller’s request
Check When the primary model’s API key is invalid, how does the fallbacks setting affect the returned model field and HTTP status?
Cost One provider key deliberately broken costs nothing — no requests reach it. The fallback model bills normally for the requests it actually answers.
2.5Identify which key and model caused a cost spike
The GET /spend/logsendpoint returns request‑level spend data for analysis.
Extract the request‑level spend log from the proxy and pinpoint the keys and models responsible for recent spending.
Open a browser and navigate to http://0.0.0.0:4000/ui
Select the Usage tab to view the spend table and chart
Use the filter controls to narrow results by the virtual API key used in lesson 3
Add a second filter for the model_group column to see which model actually answered each request
Optionally, run curl 'http://0.0.0.0:4000/spend/logs?summarize=true' --header 'Authorization: Bearer ' to retrieve aggregated totals
You'll see A table of rows, one per request made in the chapter, each showing spend amount, model used and API key – including fallback requests logged as claude-haiku while the caller asked for gpt-3.5-turbo
Takeaway The spend logs turn anonymous cost increases into concrete key‑model request data
Check Which endpoint or UI feature lets you filter spend logs to pinpoint the virtual key and model responsible for a cost increase?
Cost Free — reading the log costs nothing beyond what the underlying requests already cost.
2.6Expose model groups by task name
model_name assigns a custom label (e.g., bulk-classify) to a provider model.
Expose two model groups by task name instead of by model name, so an application asks for "bulk" or "judgment" and the config decides what actually answers.
Edit config.yaml to add entries with model_name: bulk-classify and model_name: judgment-review, each pointing to the desired provider model under litellm_params
Restart the LiteLLM proxy so it reloads the updated configuration
Send a request using "model": "bulk-classify" and another using "model": "judgment-review" in the same JSON shape as previous lessons
You'll see Two calls with different task‑shaped model names resolve to two different real models and appear as separate rows in the spend log showing the actual model used
Takeaway A model_name is just a label you choose, so naming it by task lets you swap underlying models later without changing any caller code
Check How does defining a model_name like bulk-classify in config.yaml change the way callers specify tasks versus concrete provider models?
Cost No new cost — same requests as lesson 2, renamed. The saving this pattern buys is routing volume to the cheap group instead of defaulting everything to the expensive one, which only pays off once real call volume goes through it.
2.7Run LiteLLM as a reachable, fault‑tolerant service
The /health/readinessendpoint reports the proxy’s readiness status.
Turn your local LiteLLM container into a network‑accessible service that survives failures.
Run docker run -v $(pwd)/config.yaml:/app/config.yaml -e OPENAI_API_KEY -e LITELLM_MASTER_KEY -p 4000:4000 docker.litellm.ai/berriai/litellm:latest --config /app/config.yaml with your real key values
From a second machine, execute curl http://:4000/v1/chat/completions … to confirm the API is reachable
Check the health endpoint by running curl http://:4000/health/readiness and verify it returns 200 OK
Document the on‑call owner who will be paged if the gateway becomes unreachable
You'll see A curl request from another machine returns a normal response and the /health/readinessendpoint returns 200 OK
TakeawayDeploying the stateless proxy behind a load balancer with shared storage removes the gateway as a single point of failure
Check What HTTP status code indicates the LiteLLM service is ready when querying /health/readiness after containerdeployment?
Cost One always-on container (or two-plus, once you take replicas seriously) plus a managed or self-hosted Postgres — the same shape as any other small production service, not something specific to LiteLLM.
3You’ll know it worked 12 checkable outcomes in this chapter
✓curl http://localhost:4000/v1/chat/completions with model=anthropic.claude works and returns a response
✓An API call with the key after the quota is spent returns status 429 and the server log shows the offending key ID
✓The model appears in the “Models & Endpoints” list and shows a success toast after adding.
✓After restarting the container with the config mounted, the models appear in the dashboard without manual UI entry.
✓The third rapid request returns an error like “current limit has hit”, and the dashboard shows a log entry for that attempt.
✓Opening http://localhost:4000 in a browser shows the Swagger UI and health endpoint returns OK
✓Using the generated key to call /v1/chat/completions for any other model returns “key not allowed to access model” and spending stops once $10 is reached (observed in usage tab)
✓The API call returns status code 429 with message “budget exhausted” and the dashboard’s Usage tab shows total spent = $10
12 outcomes in all — one per recipe below.
4FAQ, Tips & How-to 12
one problem, one solution, one action
▸How-toEveryone
Multiple AI models behind one URL
LiteLLM can run as a Dockerized proxy that normalizes API calls to different LLM providers. By defining each provider in the config file you expose a single endpoint that forwards requests to the chosen backend, simplifying client code.
The LiteLLM UI lets you generate API keys (virtual keys) with per‑key quotas. When a user exceeds the allocated request count or token budget, LiteLLM returns HTTP 429 and logs the overage, enabling precise cost control.
Docker provides an isolated environment for LiteLLM, ensuring all dependencies are met and the service runs consistently across machines. Starting the container exposes the API on localhost:4000, ready for configuration.
The dashboard lets you register external LLM providers without editing code. Selecting a provider, entering its API key, and saving creates a model entry that LiteLLM can route requests to.
Need to define multiple models without manual entry
A configuration file allows bulk model definitions and version‑controlled setup, which the Dockercontainer can read at startup to auto‑populate models.
Virtual keys let you grant scoped access to specific models and enforce spending caps, preventing runaway costs. The dashboard captures these constraints per key.
The video shows how to clone the LiteLLM repo, set a master key and salt in .env, then launch the proxy with Docker Compose. This creates a local HTTPserver (default port 4000) that serves the OpenAI‑compatible API for all configured models.
After the proxy is running, the admin UI lets you register multiple LLM providers. By entering each provider’s API key and selecting a model (e.g., GPT‑4.1 mini for OpenAI, Llama 3 for Groq), the gateway can route requests to either backend using the same OpenAI‑compatible endpoint.
Need a team API key that can’t overspend or see other models
The UI’s Virtual Keys page lets you generate per‑team secret keys that are scoped to specific models and can enforce a dollar budget. This isolates teams (e.g., Finance) so they only see the Groq model and cannot exceed $10 spend.
When the Finance virtual key’s $10 budget is exhausted, LiteLLM returns HTTP 429 Too Many Requests. The video demonstrates sending repeated requests until the limit is hit and then checking the logs for the exact spend and offending request.
LiteLLM Logging — view per‑request logs showing who spent what
The gateway records each request with model, token usage, team, and API key identifier. The video shows navigating to Logs in the UI to see a table where you can filter by virtual key or team and see exact token counts and dollar cost.