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 port4000) 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.
What Gets Created
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 inlitellm.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.
Create the dictionary secret
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:secrets.name to this name. Secrets are org-level, so no GVC flag is involved.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.Installation
Once your dictionary secret exists, install from the marketplace registry, pointingsecrets.name at it and replacing the bundled database password:
postgres.config.credentialsSecretName to a name no other release uses — secret names are org-wide.
Other ways to install and manage the template:
UI
CLI
Terraform
Pulumi
Configuration
LiteLLM Proxy
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
Bundled PostgreSQL
The database is the postgres template as a subchart, so every knob of that template is available underpostgres.*. 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 namemymaster), 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.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.
Connecting
modelList:
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.Wait for the proxy to report ready
P1001 error, and restart once; it recovers on its own.Sign in to the Admin UI
/ui on the canonical endpoint (or the port-forward URL). The username is admin and the password is your LITELLM_MASTER_KEY.Mint a virtual key for each application
Point an OpenAI SDK at the proxy
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.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. Enablingpostgres.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.
- AWS S3
- Google Cloud Storage
- MinIO / S3-compatible
Create a bucket
postgres.backup.aws.bucket and postgres.backup.aws.region to match.Set up a cloud account
postgres.backup.aws.cloudAccountName to its name.Create a bucket-scoped IAM policy
YOUR_BUCKET_NAME) and set postgres.backup.aws.policyName to its name:Restoring a Backup
Each backup is a gzipped plain-SQLpg_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:
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.
Upgrading from 1.0.0
Version 1.1.0 adopted thepostgres 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:
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.
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:
Troubleshooting
Deployment never becomes ready and the logs are empty
Deployment never becomes ready and the logs are empty
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.Readiness never passes after the secret exists
Readiness never passes after the secret exists
/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:P1001 (cannot reach database server) followed by one restart on a cold install is normal and recovers on its own.Second install refused as managed by a different release
Second install refused as managed by a different release
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.Render fails because the Redis password value is required
Render fails because the Redis password value is required
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.Render fails because Sentinel auth must stay disabled
Render fails because Sentinel auth must stay disabled
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.Upgrade from 1.0.0 fails asking you to create a dictionary secret
Upgrade from 1.0.0 fails asking you to create a dictionary secret
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.Requests are rejected with 401 on the public endpoint
Requests are rejected with 401 on the public endpoint
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.namemust be a dictionary secret withLITELLM_MASTER_KEY,LITELLM_SALT_KEY, and everylitellm.providerEnvkey; 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 ofRELEASE_NAME-litellmafterwards 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.replicasof 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 changedvalue) 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.passwordbefore 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.