LiteLLMを自分でホストする方法と設定
LiteLLMで全プロバイダーを1つのOpenAI互換エンドポイントに集約します。VPSでの起動から仮想キー、キー別予算、フォールバック、固定イメージまで解説します。
自己ホスト型 LLM ゲートウェイの役割
LiteLLM は、自分でホストするオープンソースの LLM ゲートウェイです。すべてのアプリケーションが呼び出す 1 つの HTTP エンドポイントを提供し、各リクエストを応答すべきプロバイダーへ転送します。LLM は大規模言語モデルを意味します。このゲートウェイは OpenAI chat completions API(アプリケーションプログラミングインターフェース)に対応しているため、すでに OpenAI と通信しているクライアントライブラリであれば、変更するのは base URL と key の 2 つだけで利用できます。
この間接層こそが目的です。アプリケーションにプロバイダーの認証情報を保持させずに済みます。モデルの切り替えも、5 つのサービスのコードを変更するのではなく、サーバー上の設定ファイルの 1 行を変更するだけです。さらに、すべての呼び出しが 1 つのプロセスを通るため、予算を設定し、使用額の記録を保持する場所を確保できます。
起動すると、次の機能を利用できます。
- 1 つのエンドポイント。 アプリケーションは
https://gateway.example.com/v1を指定し、bulkやstrongのように自分で決めたモデル名を要求します。 - 仮想キー。 各アプリケーションに専用の key を割り当て、それぞれに利用可能なモデルの許可リストと支出上限を設定できます。1 つを無効にしても、ほかには影響しません。
- フォールバック。 呼び出しに失敗した場合やプロンプトが大きすぎる場合は、別のモデルに自動的に再試行します。
- ログに記録された履歴。 すべてのリクエストについて、コストを含む行を記録します。そのため、「どのアプリケーションが支出したのか」を確認できます。
自分でゲートウェイを運用する理由
マネージドルーターは、すべてのリクエストの中間に他者のプロセスが配置された同じ構成です。自分で運用すれば、プロバイダーのキーとプロンプトのテキストを、自分で管理するサーバーに置けます。ただし、コストも発生します。すべてのアプリケーションが依存するコンポーネントを、自分で運用する必要があるためです。このガイドの最後のセクションでは、そのコストを扱います。多くの解説で省かれている部分です。
必要なもの
- Docker と Compose plugin をインストールした Ubuntu 24.04 の VPS(仮想プライベートサーバー)。
- TLS(transport layer security)経由で外部のマシンからゲートウェイへ接続する場合は、VPS を指すドメイン名。
- プロバイダー API key を少なくとも 1 つ。
ゲートウェイは推論を実行しません。リクエストを転送し、応答をストリーミングで返します。そのため、CPU 負荷はモデルのサイズではなく、リクエスト量に応じて変化します。1 vCPU のサーバーでも、少数の内部アプリケーションであれば問題なく処理できます。増加するのはデータベースです。ゲートウェイはリクエストごとに支出レコードを 1 行書き込むためです。
まず config.yaml を作成します
設定ファイルでは、クライアントがリクエストできるモデルを指定します。重要なトップレベルセクションは model_list、litellm_settings、router_settings、general_settings の4つです。
model_list:
- model_name: bulk
litellm_params:
model: anthropic/claude-haiku-4-5
api_key: os.environ/ANTHROPIC_API_KEY
- model_name: strong
litellm_params:
model: anthropic/claude-sonnet-5
api_key: os.environ/ANTHROPIC_API_KEY
- model_name: strong
litellm_params:
model: openai/gpt-5.5
api_key: os.environ/OPENAI_API_KEY
litellm_settings:
num_retries: 2
request_timeout: 120
allowed_fails: 3
cooldown_time: 30
json_logs: true
set_verbose: false
router_settings:
fallbacks: [{"bulk": ["strong"]}]
context_window_fallbacks: [{"bulk": ["strong"]}]
general_settings:
background_health_checks: true
health_check_interval: 300model_name はクライアントが送信する名前です。litellm_params.model は実際のモデルで、provider/model として記述します。モデル名はベンダー名ではなく、用途に基づけてください。bulk をリクエストするアプリケーションは、翌月に bulk を別のモデルへ変更しても動作し続けます。
api_key: os.environ/ANTHROPIC_API_KEY により、LiteLLM は実行時にその変数を読み取ります。リテラルのキーはファイル内に記述されません。config.yaml はコミットするファイルであるため、この点が重要です。
意図的に strong という名前のエントリを2つ作成しています。同じ model_name を複数のデプロイメントが持つ場合、ルーターはそれらを同等のものとして扱います。最初のデプロイメントが失敗すると、もう一方を試します。これにより、1つのプロバイダーで一時的に障害が発生しても strong を維持できます。
num_retries: 2 は、再試行可能なエラーが発生したときに同じデプロイメントを再試行します。フォールバックは、これらの再試行を使い切った後にのみ実行されます。allowed_fails: 3 と cooldown_time: 30 を組み合わせると、3回失敗したデプロイメントが30秒間ローテーションから外れます。そのため、500を返し続けるプロバイダーがリクエストごとに試されることを防げます。
fallbacks と context_window_fallbacks では発動条件が異なります。後者は見落とされがちですが、特に有用です。
fallbacksは、プライマリの呼び出しが失敗したときに発動します。context_window_fallbacksは、リクエストがそのモデルのコンテキストウィンドウを超えているためプロバイダーが拒否したときに発動します。これにより、大きすぎるプロンプトは呼び出し元にエラーを返す代わりに、十分な容量のあるモデルへ送られます。
content_policy_fallbacks もあります。これは、プロバイダーがコンテンツポリシーを理由にリクエストを拒否した場合に使用します。そのリクエストを送る適切な宛先がある場合にのみ設定してください。
Docker Compose で VPS に LiteLLM をデプロイする
config.yaml、docker-compose.yml、.envの3つのファイルを格納するディレクトリを作成します。upstream のクイックスタートでは latest タグを取得します。代わりにリリースタグを固定してください。そうすれば、翌月に docker compose up -d を実行しても、今日と同じゲートウェイを使用でき、ロールバックも1行で行えます。
services:
litellm:
image: ghcr.io/berriai/litellm:v1.95.0
restart: unless-stopped
command: ["--config", "/app/config.yaml", "--num_workers", "1"]
ports:
- "127.0.0.1:4000:4000"
volumes:
- ./config.yaml:/app/config.yaml:ro
env_file: .env
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: litellm
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
POSTGRES_DB: litellm
healthcheck:
test: ["CMD-SHELL", "pg_isready -U litellm"]
interval: 5s
timeout: 5s
retries: 10
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:この例では、Compose は .env を2回読み込みます。1回目は、compose ファイル内の ${POSTGRES_PASSWORD} を置換するためです。2回目は、env_file によってすべての変数をコンテナへ渡すためです。
v1.95.0 は 2026年8月時点の最新リリースでした。プロジェクトのリリースページを確認し、デプロイ時点で最新のタグを固定してください。各リリースには署名が付いているため、信頼する前にイメージを検証できます。
cosign verify --key https://raw.githubusercontent.com/BerriAI/litellm/v1.95.0/cosign.pub ghcr.io/berriai/litellm:v1.95.0ポートの行は 127.0.0.1:4000:4000 です。これにより、loopback インターフェースでのみポートを公開します。4000:4000 と記述すると、ゲートウェイはインターネット全体から到達可能になります。Docker は独自のルールを iptables の FORWARD チェーンに追加し、これらは ufw のルールより先に評価されるため、ufw deny 4000 では阻止できません。自己ホスト型ゲートウェイが公開状態になる原因として、これが最も一般的です。Docker が ufw を直接経由してコンテナポートを公開する方法を参照してください。外部からのネットワークトラフィックは、代わりにリバースプロキシ経由で到達します。
プロバイダーのキーをイメージから除外する
.envファイルにはすべての Secret が含まれます。これは実行時に環境変数として渡すため、イメージに組み込まれることはなく、コミットされることもありません。
LITELLM_MASTER_KEY=sk-REPLACE_ME
LITELLM_SALT_KEY=sk-REPLACE_ME_TOO
POSTGRES_PASSWORD=REPLACE_ME_AS_WELL
DATABASE_URL=postgresql://litellm:REPLACE_ME_AS_WELL@db:5432/litellm
STORE_MODEL_IN_DB=True
LITELLM_MODE=PRODUCTION
LITELLM_LOG=ERROR
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-proj-...2 つの LiteLLM キーを安全な乱数で生成し、ファイルの権限を制限します。
printf 'sk-%s\n' "$(openssl rand -hex 32)"
chmod 600 .envLITELLM_MASTER_KEYは管理者用の認証情報です。管理 API の認証に使用し、/uiの Admin UI にログインするパスワードでもあります。アプリケーションがこの認証情報を保持することは絶対に避けてください。
LITELLM_SALT_KEYは、データベースに保存されるプロバイダー認証情報を暗号化します。1 度設定したら、そのまま変更しないでください。後から変更すると、すでに保存されている認証情報を復号できなくなります。その場合、ゲートウェイは正常に起動しますが、対象プロバイダーへのすべての呼び出しが認証エラーになります。
STORE_MODEL_IN_DB=Trueを使うと、config.yaml を変更せずに Admin UI からモデルを追加・編集できます。便利な一方で、正しい設定情報の参照元が 2 つに分かれます。どちらを正とするか決め、その判断を config の横に記録してください。
キーを設定ファイルから除外する理由は、エージェントに渡すツールからキーを除外する理由と同じです。AI エージェントからプロバイダーの Secret を除外するではこのパターンを説明し、Docker Compose の env ファイルと Secretでは具体的な方法を説明しています。
起動して、初回起動時のログを監視します。
docker compose up -d
docker compose logs -f litellm実際に動作していることを確認する
認証不要のプローブが2つ、認証が必要なプローブが1つあります。それぞれ失敗する理由が異なります。
curl -s http://127.0.0.1:4000/health/liveliness
curl -s http://127.0.0.1:4000/health/readiness/health/liveliness は認証不要で、プロセスの実行中は "I'm alive!" を返します。/health/readiness も認証不要です。"status": "healthy" と db フィールドを含む JSON オブジェクトを返し、データベースに接続できない場合は503を返します。監視対象には readiness を指定してください。liveliness は、ゲートウェイが仮想キーを1つも検索できない場合でも正常な状態を示し続けるためです。
認証付きチェックは、プロバイダーと通信するチェックです。
curl -s http://127.0.0.1:4000/health \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"healthy_endpoints 配列と unhealthy_endpoints 配列を返します。unhealthy_endpoints にあるモデルで認証エラーが発生している場合、.env のプロバイダーキーが間違っているか、設定されていません。現在確認したいのはこの障害です。background_health_checks: true が設定されているため、プロキシはhealth_check_interval秒ごとに自動でこれらのプローブを実行します。/health は最後の結果を返すため、これをポーリングしても毎回プロバイダーへテストリクエストは送信されません。
仮想キーとキーごとの予算
各アプリケーションには、マスターキーを基に発行した専用キーを割り当てます。
curl -s http://127.0.0.1:4000/key/generate \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H 'Content-Type: application/json' \
-d '{
"key_alias": "nightly-summariser",
"models": ["bulk"],
"max_budget": 5,
"budget_duration": "30d",
"rpm_limit": 60,
"tpm_limit": 200000
}'レスポンスには、key フィールドが含まれます。このフィールドは sk- で始まります。その文字列がアプリケーションに渡される値であり、アプリケーションが取得するのはそれだけです。
modelsは、このキーでリクエストできる対象の許可リストです。上記のキーでリクエストできるのはbulkだけです。max_budget: 5とbudget_duration: "30d"を合わせると、移動する30日間あたり5米ドルです。上限に達すると、そのキーは使えなくなります。rpm_limitとtpm_limitは、このキーだけに適用される1分あたりのリクエスト数とトークン数の上限です。key_aliasは、6週間後に支出ログで確認する識別子です。必ず設定してください。
予算を使い切ると、呼び出しは HTTP 401 で失敗し、本文は次の形式になります。
ExceededBudget: Current spend for token: 7.2e-05; Max Budget for Token: 2e-07このステータスコードが混乱の原因になります。クライアントライブラリは 401 を認証エラーとして報告するため、スタックトレースを確認する開発者は、キーが有効かどうかを調べ始めます。ステータスコードとともにレスポンス本文もログに記録してください。そうしないと、予算超過が毎回、認証情報の破損に見えてしまいます。
同じ管理 API を使用して、キーを確認および調整できます。
curl -s "http://127.0.0.1:4000/key/info?key=sk-..." \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
curl -s -X POST http://127.0.0.1:4000/key/update \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H 'Content-Type: application/json' \
-d '{"key": "sk-...", "max_budget": 25}'ゲートウェイで適用する予算は、問題の原因がエージェント自体であっても有効です。そのため、これは VPS 上の AI エージェントのコスト管理 の基盤になります。
安価なモデルに一括処理を送る
クライアントの接続先をゲートウェイに設定します。ベース URL、キー、モデル名は次のとおりです。
curl -s http://127.0.0.1:4000/v1/chat/completions \
-H "Authorization: Bearer sk-<the virtual key>" \
-H 'Content-Type: application/json' \
-d '{
"model": "bulk",
"messages": [{"role": "user", "content": "Say hello in five words."}]
}'OpenAI クライアントライブラリはすべて同じように動作します。base_url に https://gateway.example.com/v1 を、api_key に仮想キーを設定します。
config.yaml のルーティングポリシーが、呼び出し元に意識させることなく適用されます。bulk へのリクエストは安価なモデルに送られます。この呼び出しが再試行後も失敗すると、リクエストは strong に対して再試行されます。プロンプトが bulk に対して長すぎる場合、context_window_fallbacks はエラーを返さず、代わりに strong へ送信します。分類処理や未処理の要約などの一括処理は、デフォルトで安価なモデルを使用します。コストが高くなるのは、難しいリクエストだけです。
ツールを使用するエージェントでは、ゲートウェイの利点が特に明確になります。同じ VPS 上の MCP(モデルコンテキストプロトコル)サーバーと、それを操作するエージェントの両方を1つのエンドポイントに接続できます。そのため、どちらも再デプロイせずに、背後で使用するモデルを変更できます。
フォールバックが発生したことを確認するには
これは、何も壊れていないように見えるため、コストが発生する障害モードです。フォールバックが正常に行われると、通常のレスポンスボディとともに HTTP 200 が返ります。安価なモデルが 1 日停止していても、すべてのリクエストが高価なモデルで静かに処理される可能性があります。最初の証拠が請求書になることもあります。
証拠はレスポンスヘッダーにあります。取得してください。
curl -s -D - -o /dev/null http://127.0.0.1:4000/v1/chat/completions \
-H "Authorization: Bearer sk-<the virtual key>" \
-H 'Content-Type: application/json' \
-d '{"model":"bulk","messages":[{"role":"user","content":"ping"}]}' \
| grep -i '^x-litellm'x-litellm-model-groupはクライアントが要求したデプロイメントです。x-litellm-model-idは応答したデプロイメントです。この2つが一致しない場合、フォールバックが発生しています。x-litellm-attempted-fallbacksとx-litellm-attempted-retriesはフォールバックの回数を示します。正常なリクエストでは、どちらも 0 です。x-litellm-response-costは、そのリクエストの米ドル単位のコストです。x-litellm-call-idは、同じリクエストをログから検索するための識別子です。
すべてのリクエストで x-litellm-attempted-fallbacks を記録し、0 でなくなったときにアラートを出してください。この1つの値によって、ルーティングポリシーが正常に機能しているか、または「常に高価なモデルを使用する」状態へ気付かないうちに変わったかを判別できます。
この仕組みを完全に実装するにはトレーシングが必要であり、専用のセットアップが適しています。エージェント呼び出しをトレーシングする self-hosted Langfuse。LiteLLM にはコールバックが組み込まれているため、認証情報を含めて 2 行で接続できます。
litellm_settings:
success_callback: ["langfuse"]
failure_callback: ["langfuse"]LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=https://langfuse.example.comfailure_callback と success_callback の両方を設定してください。設定しない場合、保持されるトレースは問題が発生しなかったリクエストのものだけになります。これとは別に、LiteLLM はリクエストごとの利用額を Postgres に行として書き込み、/ui の Admin UI がそのテーブルを読み取ります。トラフィックに応じて増加するため、小容量のディスクでは監視してください。
ゲートウェイをリバースプロキシの背後に配置する
外部から port 4000 に到達できないようにします。nginx または Caddy で TLS を終端し、loopback address に転送します。
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 600s;
}この2行は省略されがちです。proxy_buffering offが必要なのは、ストリーミングによる completion が server-sent events の連続だからです。nginx で buffering が有効になっていると、レスポンスが終了するまでチャンクを保持します。そのため、クライアントは無応答のまま待機し、最後にすべてのデータを一度に受信します。proxy_read_timeout 600sが必要なのは、長い生成処理が nginx のデフォルトである 60 秒を超えるためです。超過すると、クライアントには 504 が返され、error log には upstream timed out (110: Connection timed out) while reading response header from upstream が記録されます。
証明書には、nginx で Certbot と Let's Encrypt を使用する方法が最も簡単です。すでに複数のコンテナをそのサーバーで提供している場合は、複数の Compose アプリの前段に Traefik を配置する方法を使うと、ルーティングと証明書を1か所で管理できます。
ゲートウェイが単一障害点になっています
構築した構成の実態を正しく把握してください。現在、管理しているすべてのアプリケーションが、1 台の VPS 上にある 1 つのコンテナに依存しています。そのコンテナが停止すると、正常に稼働しているプロバイダーを含め、どのアプリケーションからもモデルを呼び出せません。ここから、次の4点が分かります。
- 設定不備がすべてを同時に停止させます。
restart: unless-stoppedはクラッシュしたプロセスを再起動します。また、config.yaml を解析できないコンテナも繰り返し再起動します。設定を変更するたびにdocker compose logs litellmを確認し、変更後の状態を監視できる時間に設定を変更してください。 - Postgres がリクエスト処理経路にあります。 仮想キーの検索と利用量の記録の両方で Postgres を使用します。
/health/readinessが 503 を返す場合、ゲートウェイは稼働しているものの、どちらの処理も実行できないという警告です。 - スケールは 1 台を大型化せず、インスタンスを追加して行います。 プロジェクトの公式ガイダンスでは、1 インスタンスあたり 1 worker(
--num_workers 1)とし、複数のインスタンスで 1 つのデータベースを共有します。ロードバランサーの背後に小規模なゲートウェイを2台配置すれば、単一コンテナへの依存をなくせます。ただし、データベースへの依存はなくなりません。 - 再生成できないデータをバックアップしてください。 対象は
config.yamlと.env、およびデータベースのpg_dumpです。LITELLM_SALT_KEYを失うと、そのダンプに含まれる暗号化済みのプロバイダー認証情報が使えなくなります。そのため、環境ファイルとダンプは同じバックアップジョブに含めてください:オフホストストレージへの restic バックアップ。
アップグレードでは、イメージタグを編集して docker compose up -d を実行します。LiteLLM はデフォルトで起動時に prisma migrate deploy を実行するため、新しいコンテナは初回起動時にデータベーススキーマを移行します。タグを変更する前にダンプを取得してください。すでに実行された移行は、以前のイメージに戻しても元に戻らないためです。
FAQ
LiteLLM はすべての呼び出しに無視できない遅延を追加しますか?
プロジェクトは、2026 年 8 月の README で、1000 requests per second における 95 パーセンタイルの遅延として 8 ms を公表しています。これはベンダーの数値として扱ってください。実際に遅延を左右するのは、アプリケーションとゲートウェイ間のネットワーク距離です。すべての呼び出しに 1 往復が追加されるためです。ゲートウェイは、呼び出し元のアプリケーションと同じリージョンで実行してください。そのうえで、実際のレスポンスに含まれる x-litellm-overhead-duration-ms ヘッダーを使い、自環境で追加された遅延を測定します。
nginx を前段に置いた後、ストリーミングが機能しなくなったのはなぜですか?
nginx はデフォルトで upstream のレスポンスをバッファリングし、ストリーミングによる completion は server-sent events の連続として送信されるためです。proxy_buffering が有効だと、nginx はチャンクを収集し、レスポンスが完了するまで解放しません。そのため、クライアントは無通信のまま待機し、最後に回答全体を一度に受け取ります。location ブロックで proxy_buffering off; を設定してください。同じブロックで proxy_read_timeout も引き上げてください。そうしないと、長い生成処理が nginx のデフォルトである 60 秒を超え、クライアントが 504 を受け取ります。
仮想キーの予算を使い切るとどうなりますか?
呼び出しは HTTP 401 で失敗し、本文は ExceededBudget: Current spend for token: 7.2e-05; Max Budget for Token: 2e-07 の形式になります。401 が問題を分かりにくくします。クライアントライブラリはこれを認証失敗として報告するため、メッセージを読む代わりに、キーが有効かどうかを確認し始めるからです。ステータスコードとともにレスポンス本文をログに記録してください。マスターキーに対して /key/info?key=sk-... を使い、キーの実際の残額を確認します。予算の上限が低すぎる場合は、/key/update で引き上げてください。
ゲートウェイはホスト型モデルだけでなくローカルモデルにもルーティングできますか?
はい。model_list にもう 1 つエントリを追加します。api_base とともに ollama_chat/ プレフィックスを使用します。たとえば、model: ollama_chat/llama3.1 を api_base: http://ollama:11434 と併記します。コンテナ内では localhost はそのコンテナ自身を指します。そのため、Compose のサービス名または Docker ネットワーク上のホストのアドレスを使用し、127.0.0.1 は決して使用しないでください。ローカルモデルの起動は別の作業です。VPS 上で Ollama を使って LLM をセルフホストするを参照してください。