Skip to main content

Overview

LiteLLM is an OpenAI-compatible LLM gateway and proxy: a single endpoint in front of 100+ model providers, with virtual API keys, per-key and per-team spend tracking and budgets, rate limiting, and routing with fallbacks. This template deploys the stateless LiteLLM proxy tier (API and Admin UI on port 4000) backed by a bundled PostgreSQL for virtual keys, spend, teams, and budgets, and a bundled Sentinel-managed Redis for rate-limit counters and the response cache shared across proxy replicas. Clients call it exactly as they would call OpenAI — point any OpenAI SDK at the endpoint and swap in a LiteLLM key.
This template deploys into an existing GVC that you already have — it does not create or manage a GVC.

What Gets Created

Your master key, salt key, and provider API keys are not created by the template — see Prerequisites.

Prerequisites

LiteLLM needs three kinds of credential that never pass through Helm values: the master key that gates the Admin API and UI and mints virtual keys, the salt key that encrypts provider keys stored in PostgreSQL, and one provider API key per entry in litellm.providerEnv. All of them live in a single dictionary secret you create before installing; the chart references it by name and grants the proxy identity reveal on exactly that secret.
1

Create the dictionary secret

The keys LITELLM_MASTER_KEY and LITELLM_SALT_KEY are required and must start with sk-. Add one more entry for every environment-variable name listed in litellm.providerEnv (the default list is just OPENAI_API_KEY), holding that provider’s real API key:
Set secrets.name to this name. Secrets are org-level, so no GVC flag is involved.
2

Back the salt key up outside Control Plane

LITELLM_SALT_KEY is write-once: it encrypts every provider key stored in PostgreSQL, and changing it corrupts all of them. The master key can be rotated later; the salt key cannot once models or keys are stored. Keep a copy somewhere safe.
Create the secret before installing. Installing without it reports success, but the deployment then wedges silently — cpln logs returns nothing, and the only place the missing secret is named is status.versions[].message:
The message reads The secret LITELLM_SECRET_NAME no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed. Creating the secret lets the deployment recover on its own; cpln workload force-redeployment RELEASE_NAME-litellm --gvc GVC_NAME skips the wait.
Everything else works with the defaults. The bundled database password is template-managed plumbing — the chart creates the PostgreSQL credentials secret for you — and scheduled database backups, which need a bucket and cloud account, are described under Backing Up.

Installation

Once your dictionary secret exists, install from the marketplace registry, pointing secrets.name at it and replacing the bundled database password:
Installing a second LiteLLM release in the same org? Also set postgres.config.credentialsSecretName to a name no other release uses — secret names are org-wide. Other ways to install and manage the template:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations

Pulumi

Declare templates in your Pulumi programs

Configuration

LiteLLM Proxy

Every api_key in modelList points at an environment variable (os.environ/NAME), and every such name must appear in both providerEnv and your prerequisite secret. Adding a provider is therefore three edits: a new modelList entry, its variable name in providerEnv, and the key itself in the secret.

Prerequisite Secret

Access

The public endpoint is key-gated, not open: every request still needs a valid master or virtual key. A change to either access knob takes a couple of minutes to take effect after the upgrade reports success.

Bundled PostgreSQL

The database is the postgres template as a subchart, so every knob of that template is available under postgres.*. The chart builds the credentials secret from postgres.credentials.* for you — nothing to create before installing.

Bundled Redis

Redis is the redis template as a subchart: a Sentinel-managed master-replica set that the proxy reaches through Sentinel (master name mymaster), so a failover is transparent to it. It holds the rate-limit and budget counters and the response cache that all proxy replicas share.
Redis ships authless by default, with the same-GVC firewall as the boundary. Set redis.redis.auth.password.enabled: true to require AUTH: the redis template then creates RELEASE_NAME-redis-auth-password, and the chart passes that master password into the proxy’s cache config. Sentinel authentication must stay off — the proxy sends only the master password, and the chart refuses to render if redis.sentinel.auth is enabled.
The database password seeds PostgreSQL on first boot and is not updated by later value edits. Uninstalling the release deletes the volume set; reinstall to reset.

Connecting

Verify the proxy answers with your master key — the response lists the models from modelList:
With publicAccess.enabled: false there is no public endpoint; reach the proxy from your machine through a tunnel instead, then use http://localhost:4000 (UI at http://localhost:4000/ui) in place of the canonical endpoint:

First Run

The Admin UI is gated by the master key from the first request, so there is no setup wizard to race — but the master key should not be what your applications use.
1

Wait for the proxy to report ready

PostgreSQL comes up first, then the proxy runs its database migrations and starts serving. On a cold install the proxy can start before the database accepts connections, log a P1001 error, and restart once; it recovers on its own.
2

Sign in to the Admin UI

Open /ui on the canonical endpoint (or the port-forward URL). The username is admin and the password is your LITELLM_MASTER_KEY.
3

Mint a virtual key for each application

Create keys with their own budgets and rate limits under Virtual Keys in the UI, or with the API as shown in Managing Virtual Keys, and hand those out instead of the master key.
4

Point an OpenAI SDK at the proxy

Set the SDK’s base URL to the canonical endpoint (or the internal address for workloads in the same GVC) and its API key to a virtual key. The model names are the model_name values from modelList, plus any models added through the UI while litellm.storeModelInDb is true.

Operations

Managing Virtual Keys

Rather than handing out the master key, mint scoped virtual keys — each with its own budget, rate limits, and allowed models — and give those to your applications and teams. Spend is tracked per key in PostgreSQL.
The response includes a new sk-… key usable on /v1/chat/completions and /v1/models. Keys, teams, and budgets can also be managed visually in the Admin UI at /ui. Rate limits are enforced across all proxy replicas only while Redis is enabled; see Scaling and Availability.

Backing Up

Scheduled backups of the bundled PostgreSQL are off by default. Enabling postgres.backup.enabled: true adds one cron workload, RELEASE_NAME-postgres-backup, that runs pg_dumpall on the schedule and uploads a gzipped dump to your bucket under the configured prefix. Pick a postgres.backup.provider and complete the matching setup before installing or upgrading with it on.
1

Create a bucket

Create an S3 bucket. Set postgres.backup.aws.bucket and postgres.backup.aws.region to match.
2

Set up a cloud account

If you do not have one, create a cloud account for the AWS account holding the bucket. Set postgres.backup.aws.cloudAccountName to its name.
3

Create a bucket-scoped IAM policy

Create an IAM policy with the JSON below (replace YOUR_BUCKET_NAME) and set postgres.backup.aws.policyName to its name:
A zero-length backup object is a failed run, not a backup. If the dump cannot reach the database, the upload still writes a near-empty gzip under a normal timestamped filename. Check the object size before you rely on one.
The database dump covers virtual keys, spend, teams, budgets, and any models added through the UI. It does not cover your prerequisite secret — the salt key in particular is needed to read the provider keys stored in that dump, so keep it backed up alongside. Redis holds only counters and cache and is not backed up.

Restoring a Backup

Each backup is a gzipped plain-SQL pg_dumpall archive. Restoring means replaying that SQL into the bundled PostgreSQL. The one transport that carries a dump into the container intact is cpln workload exec with --stdin and a base64 wrapper on both ends — raw binary piped through exec is corrupted:
Two constraints make this a planned operation: the archive contains CREATE ROLE and CREATE DATABASE statements, so a straight replay collides with the database the proxy already created and migrated on first boot; and no proxy replica may be connected while you drop and recreate that database before the replay. The restored data is only readable with the same LITELLM_SALT_KEY the dump was taken under.
This restore path has not been exercised against this template end to end. Rehearse it on a throwaway release before you depend on it. Restoring from a volume set snapshot is likewise unverified here.

Upgrading from 1.0.0

Version 1.1.0 adopted the postgres 3.4.1 template, which stopped taking database credentials as values. LiteLLM absorbed that change rather than passing it on — the chart now creates the credentials secret itself — so there is no new prerequisite, only a rename of three keys: Move the three keys, keep the same values so the running database still matches, and upgrade in place. A values file that still carries an old key fails the render with the postgres template’s message (config.username was REMOVED in postgres 3.4.0), which tells you to create a dictionary secret yourself — ignore that advice here; this template creates it, and the database password stays a value exactly as before.
The first helm upgrade after an install can restart the bundled PostgreSQL and Redis even when their values are unchanged, so expect a brief interruption.

Scaling and Availability

litellm.replicas sets how many proxy replicas run. The proxy is stateless — all state lives in PostgreSQL and Redis — so replicas need no peer discovery and a rolling restart cycles one at a time. Set it to 2 or more for an always-on tier:
Keep redis.enabled: true whenever litellm.replicas is above 1. Rate-limit and budget counters are shared only through Redis; without it each replica counts in memory, so the effective limit becomes the configured value multiplied by the replica count.
The bundled Redis is already highly available: three Redis replicas with three Sentinels, and the proxy connects through Sentinel so a master failover needs no reconfiguration. The bundled PostgreSQL is a single instance on a persistent volume set, which survives restarts, redeploys, and upgrades under the same release name. Scale-out proxy replicas run the boot-time database migration as a no-op.

Troubleshooting

Symptom: cpln helm install reported success, cpln logs returns nothing, and cpln workload get-deployments RELEASE_NAME-litellm --gvc GVC_NAME -o yaml shows The secret LITELLM_SECRET_NAME no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed. under status.versions[].message.Cause: The prerequisite dictionary secret named by secrets.name does not exist, or it is missing one of the keys the workload references (LITELLM_MASTER_KEY, LITELLM_SALT_KEY, or a name listed in litellm.providerEnv).Fix: Create the secret with every required key (see Prerequisites). The deployment recovers on its own once the secret exists; cpln workload force-redeployment RELEASE_NAME-litellm --gvc GVC_NAME skips the wait.
Symptom: The proxy container starts but /health/readiness keeps failing and the deployment does not reach ready.Cause: The readiness check is database-aware. The proxy cannot reach the bundled PostgreSQL, or the migration it runs on boot has not completed.Fix: Check that RELEASE_NAME-postgres is ready, then read the proxy’s logs:
A single P1001 (cannot reach database server) followed by one restart on a cold install is normal and recovers on its own.
Symptom: Installing a second LiteLLM release fails with cannot be updated because it is being managed by a different release and creates nothing.Cause: Both releases use the same postgres.config.credentialsSecretName. Secret names are org-wide, and the first release owns that one. Nothing is shared, overwritten, or deleted.Fix: Set postgres.config.credentialsSecretName to a distinct name for the second release and install again.
Symptom: litellm: redis.redis.auth.password.value is required when redis.redis.auth.password.enabled is true — LiteLLM's cache config reads this master password.Cause: redis.redis.auth.password.enabled is true with an empty redis.redis.auth.password.value.Fix: Set redis.redis.auth.password.value to the password the bundled Redis should require, or set enabled back to false.
Symptom: litellm: redis.sentinel.auth must stay disabled — LiteLLM sends only the master password, not a sentinel password.Cause: redis.sentinel.auth.password.enabled or redis.sentinel.auth.fromSecret.enabled is true. The proxy authenticates to the Redis master only, so a Sentinel password would lock it out.Fix: Leave both Sentinel auth toggles at false. Use redis.redis.auth.password.enabled: true to protect the master; the same-GVC firewall is the boundary for Sentinel.
Symptom: The render fails with config.username was REMOVED in postgres 3.4.0 and the postgres template’s advice to create a prerequisite dictionary secret.Cause: Your values file still carries postgres.config.username, postgres.config.password, or postgres.config.database.Fix: Rename them to postgres.credentials.* as described in Upgrading from 1.0.0. Do not create a secret yourself — this template creates it.
Symptom: API calls return 401, including on the public endpoint.Cause: The endpoint is key-gated. The request carries no Authorization: Bearer header, or the key is not the master key or a valid virtual key for the requested model.Fix: Send the master key or a virtual key minted for that model (see Managing Virtual Keys). Compare the master key you are sending with cpln secret reveal LITELLM_SECRET_NAME -o yaml.

Important Notes

  • Create the prerequisite secret before installing. secrets.name must be a dictionary secret with LITELLM_MASTER_KEY, LITELLM_SALT_KEY, and every litellm.providerEnv key; without it the deployment wedges silently.
  • Never rotate LITELLM_SALT_KEY. It encrypts the provider keys stored in PostgreSQL; changing it corrupts every stored key. The master key may be rotated — force a redeployment of RELEASE_NAME-litellm afterwards so the proxy picks up the new value.
  • Hand out virtual keys, not the master key. The public endpoint is key-gated, and virtual keys carry their own budgets, rate limits, and model lists.
  • Keep Redis enabled for litellm.replicas of 2 or more. Otherwise rate limits are counted per replica.
  • Redis is authless by default, bounded by the same-GVC firewall. Set redis.redis.auth.password.enabled: true (with a changed value) to require a master password; Sentinel auth must stay off.
  • Give each release its own postgres.config.credentialsSecretName. Secret names are org-wide; a second release on the default name is refused at install.
  • Change postgres.credentials.password before installing. It seeds the database on first boot and later value edits do not change it.
  • PostgreSQL data survives proxy restarts and redeploys. To reset virtual keys and spend, uninstall the whole release — that deletes the volume set.

External References

LiteLLM Documentation

Official LiteLLM documentation

Proxy Deployment

LiteLLM proxy deployment reference

Virtual Keys

Create and manage virtual keys, budgets, and rate limits

Config Reference

Full proxy config.yaml settings reference

LiteLLM Template

View the source files, default values, and chart definition