<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Misbah Syed</title>
    <description>The latest articles on DEV Community by Misbah Syed (@misbahsy).</description>
    <link>https://dev.to/misbahsy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4106691%2F5e681711-311b-4aa2-a534-183eb6a41553.jpg</url>
      <title>DEV Community: Misbah Syed</title>
      <link>https://dev.to/misbahsy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/misbahsy"/>
    <language>en</language>
    <item>
      <title>How to set up OpenAI Codex with LiteLLM</title>
      <dc:creator>Misbah Syed</dc:creator>
      <pubDate>Wed, 09 Sep 2026 17:20:51 +0000</pubDate>
      <link>https://dev.to/misbahsy/how-to-set-up-openai-codex-with-litellm-485l</link>
      <guid>https://dev.to/misbahsy/how-to-set-up-openai-codex-with-litellm-485l</guid>
      <description>&lt;p&gt;This guide connects OpenAI Codex to a LiteLLM proxy, one you run yourself or one your team already hosts. Codex reads one base URL out of a config file, so pointing it at LiteLLM gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Any model LiteLLM can reach, from the same Codex CLI and desktop app&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A log line and a cost for every request, in one place&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Per-developer keys with their own budgets and their own model access&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One provider key on the server instead of a copy on every machine&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The five-minute walkthrough this guide is written from:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/avKQz7VqJZE" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The steps below are the ones in the video, so you can move between the two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Docker, for the setting up LiteLLM gateway. Not needed if you are pointing at a gateway already hosted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Node, for the Codex CLI&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One provider key. One is enough to start&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything below runs on the open-source image, &lt;code&gt;ghcr.io/berriai/litellm:main-stable&lt;/code&gt;. The admin UI, virtual keys and spend tracking come from having a database attached, which the compose file does.&lt;/p&gt;

&lt;p&gt;Versions used here: litellm 1.99.0, current &lt;code&gt;@openai/codex&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's go!
&lt;/h2&gt;

&lt;p&gt;If your team already hosts a LiteLLM gateway, skip steps 2 and 3 below.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Install OpenAI Codex
&lt;/h2&gt;

&lt;p&gt;Install the Codex CLI globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @openai/codex

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Configure LiteLLM for model routing
&lt;/h2&gt;

&lt;p&gt;Make a directory for the LiteLLM proxy and put &lt;code&gt;config.yaml&lt;/code&gt; in it. This file is the model list: the names your clients ask for, and where each one goes.&lt;/p&gt;

&lt;h3&gt;
  
  
  config.yaml
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;model_list&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# `codex -m &amp;lt;id&amp;gt;` works with any of them.&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;model_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gpt-5.6-terra&lt;/span&gt;
    &lt;span class="na"&gt;litellm_params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openai/gpt-5.6-terra&lt;/span&gt;
      &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;os.environ/OPENAI_API_KEY&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;model_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gpt-5.6-luna&lt;/span&gt;
    &lt;span class="na"&gt;litellm_params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openai/gpt-5.6-luna&lt;/span&gt;
      &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;os.environ/OPENAI_API_KEY&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;model_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gpt-5.6-sol&lt;/span&gt;
    &lt;span class="na"&gt;litellm_params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openai/gpt-5.6-sol&lt;/span&gt;
      &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;os.environ/OPENAI_API_KEY&lt;/span&gt;

  &lt;span class="c1"&gt;# Anything from another provider goes in the same list.&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;model_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude-sonnet-5&lt;/span&gt;
    &lt;span class="na"&gt;litellm_params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anthropic/claude-sonnet-5&lt;/span&gt;
      &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;os.environ/ANTHROPIC_API_KEY&lt;/span&gt;

  &lt;span class="c1"&gt;# Catch-all, so `codex -m &amp;lt;anything&amp;gt;` reaches OpenAI without editing&lt;/span&gt;
  &lt;span class="c1"&gt;# this file. Delete this entry to restrict a fleet to the list above.&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;model_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
    &lt;span class="na"&gt;litellm_params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openai/*&lt;/span&gt;
      &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;os.environ/OPENAI_API_KEY&lt;/span&gt;

&lt;span class="na"&gt;litellm_settings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;drop_params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;general_settings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;master_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;os.environ/LITELLM_MASTER_KEY&lt;/span&gt;
  &lt;span class="c1"&gt;# Coding turns stream for a long time. Do not cut them off.&lt;/span&gt;
  &lt;span class="na"&gt;request_timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could as many model names to this list from the ones &lt;a href="https://models.litellm.ai/" rel="noopener noreferrer"&gt;supported by LiteLLM&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;drop_params: true&lt;/code&gt; &lt;strong&gt;.&lt;/strong&gt; Coding agents sometimes send parameters that not every provider accepts, which is dropped by this line.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;master_key&lt;/code&gt; &lt;strong&gt;.&lt;/strong&gt; This is the key to access the proxy.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Start the LiteLLM proxy
&lt;/h2&gt;

&lt;p&gt;We'll start the LiteLLM gateway along with a postgres database, so that we can access the dashboard UI for the gateway..&lt;/p&gt;

&lt;h3&gt;
  
  
  docker-compose.yml
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;litellm-coding-agents&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;litellm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/berriai/litellm:main-stable&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--config"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/app/config.yaml"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--port"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4000"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4000:4000"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config.yaml:/app/config.yaml:ro&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql://litellm:litellm@postgres:5432/litellm&lt;/span&gt;
      &lt;span class="na"&gt;STORE_MODEL_IN_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;True"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-c&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;import&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;urllib.request,sys;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sys.exit(0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;if&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;urllib.request.urlopen('http://localhost:4000/health/liveliness').status==200&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;else&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1)&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
      &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;30s&lt;/span&gt;

  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="c1"&gt;# Deliberately not published to the host. Nothing outside this&lt;/span&gt;
    &lt;span class="c1"&gt;# network needs it, and 5432 is usually already taken.&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;litellm&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;litellm&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;litellm&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;litellm-pgdata:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;litellm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;litellm"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;litellm-pgdata&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Provider keys go in &lt;code&gt;.env&lt;/code&gt; next to the compose file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;
&lt;span class="py"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;
&lt;span class="py"&gt;LITELLM_MASTER_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;sk-1234&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sk-1234&lt;/code&gt; is the placeholder master key used in the LiteLLM docs. Replace it with a real secret key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bring it up
&lt;/h3&gt;

&lt;p&gt;Start the proxy and its database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First boot runs the database migrations and takes about eighty seconds. Every boot after that is about fifteen (depending on the machine spec).&lt;/p&gt;

&lt;p&gt;Check that it is alive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:4000/health/liveliness

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that it is serving the model list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:4000/v1/models &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer sk-1234"&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; 400

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A quick tip: If something else is running on port 4000, you can check using this command before running docker compose. You could either stop that process or run LiteLLM gateway on a different port but will have to adjust rest of the tutorial accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsof &lt;span class="nt"&gt;-nP&lt;/span&gt; &lt;span class="nt"&gt;-iTCP&lt;/span&gt;:4000 &lt;span class="nt"&gt;-sTCP&lt;/span&gt;:LISTEN

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The proxy is up. Now we will look at the Codex side.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Configure Codex to use LiteLLM
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ~/.codex/config.toml
&lt;/h3&gt;

&lt;p&gt;It's a good idea to back up the existing codex config file first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; ~/.codex/config.toml ~/.codex/config.toml.bak 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then edit the codex config file as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gpt-5.6-terra"&lt;/span&gt;
&lt;span class="py"&gt;model_provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"litellm"&lt;/span&gt;
&lt;span class="py"&gt;model_reasoning_effort&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"medium"&lt;/span&gt;

&lt;span class="nn"&gt;[model_providers.litellm]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"LiteLLM Gateway"&lt;/span&gt;
&lt;span class="py"&gt;base_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:4000/v1"&lt;/span&gt;
&lt;span class="c"&gt;# More on setting up LITELLM_API_KEY towards the end&lt;/span&gt;
&lt;span class="py"&gt;env_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"LITELLM_API_KEY"&lt;/span&gt;
&lt;span class="c"&gt;# Codex talks the Responses API. &lt;/span&gt;
&lt;span class="py"&gt;wire_api&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"responses"&lt;/span&gt;
&lt;span class="c"&gt;# A coding turn can stream for long time, hence the setting below&lt;/span&gt;
&lt;span class="py"&gt;stream_idle_timeout_ms&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7200000&lt;/span&gt;
&lt;span class="py"&gt;stream_max_retries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="py"&gt;request_max_retries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="c"&gt;# Codex cli complains if not in a trusted folder&lt;/span&gt;
&lt;span class="nn"&gt;[projects."/path/to/your/project"]&lt;/span&gt;
&lt;span class="py"&gt;trust_level&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"trusted"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;model_provider = "litellm"&lt;/code&gt; &lt;strong&gt;.&lt;/strong&gt; Has to match the &lt;code&gt;[model_providers.&amp;lt;name&amp;gt;]&lt;/code&gt; table below it. Any name works, as long as they both match.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wire_api = "responses"&lt;/code&gt; &lt;strong&gt;.&lt;/strong&gt; Codex uses the Responses API, whereas the default for a custom provider is chat completions.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Run Codex
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"reply with the word CONNECTED and nothing else"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Codex is now runs against your proxy, on your provider key, with your model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frii9ct2kod69dxc5v34j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frii9ct2kod69dxc5v34j.png" width="758" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or you can start a codex session in the terminal with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:4000/ui&lt;/code&gt;, sign in with the master key, and the request appears in the Logs tab.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Use the Codex desktop app
&lt;/h2&gt;

&lt;p&gt;The Codex desktop app reads the same &lt;code&gt;~/.codex/config.toml&lt;/code&gt;. Nothing new to write.&lt;/p&gt;

&lt;p&gt;But it will not see your environment variable. macOS hands apps launched from Finder or the Dock the GUI login session's environment, not your shell's. You can run this command to set env variable for the login session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;launchctl setenv LITELLM_API_KEY &lt;span class="s2"&gt;"sk-1234"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then fully quit and reopen the codex app. That holds until you log out. Make it a LaunchAgent if you want it permanent.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fslogowm5arn6ejkhojro.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fslogowm5arn6ejkhojro.png" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced options
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Manage usage with virtual keys
&lt;/h3&gt;

&lt;p&gt;Clients get a virtual key, issued from the Virtual Keys page in the admin UI at &lt;a href="http://localhost:4000/ui" rel="noopener noreferrer"&gt;http://localhost:4000/ui&lt;/a&gt;, with its own budget and its own list of allowed models.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmowu41ej6zmtot3rdxem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmowu41ej6zmtot3rdxem.png" width="798" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Issue one per person, per machine or per project, then set LITELLM_API_KEY to that key instead:&lt;/p&gt;

&lt;p&gt;export LITELLM_API_KEY=""&lt;/p&gt;

&lt;p&gt;Three things follow from that. Spend in the Logs tab is broken down by key, so you can see which project is costing what. A budget on the key stops it rather than surprising you at the end of the month. And if a key leaks, you can revoke that one key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using different models
&lt;/h3&gt;

&lt;p&gt;Any public name in the model list works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex &lt;span class="nt"&gt;-m&lt;/span&gt; gpt-5.6-luna

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Profiles are saved model and reasoning-effort pairs, that can get you started with quickly.&lt;/p&gt;

&lt;p&gt;In your ~/.codex/config.toml add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# Optional profiles &lt;/span&gt;
&lt;span class="c"&gt;# Saved model plus reasoning-effort pairs. `codex --profile deep`.&lt;/span&gt;
&lt;span class="nn"&gt;[profiles.fast]&lt;/span&gt;
&lt;span class="py"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gpt-5.6-luna"&lt;/span&gt;
&lt;span class="py"&gt;model_reasoning_effort&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"low"&lt;/span&gt;

&lt;span class="nn"&gt;[profiles.deep]&lt;/span&gt;
&lt;span class="py"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"gpt-5.6-sol"&lt;/span&gt;
&lt;span class="py"&gt;model_reasoning_effort&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"high"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can run a codex session with a specific profile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex &lt;span class="nt"&gt;--profile&lt;/span&gt; deep

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Additional resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;LiteLLM docs: &lt;a href="https://docs.litellm.ai" rel="noopener noreferrer"&gt;https://docs.litellm.ai&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Codex tutorial page: &lt;a href="https://docs.litellm.ai/docs/tutorials/openai%5C_codex" rel="noopener noreferrer"&gt;https://docs.litellm.ai/docs/tutorials/openai_codex&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;LiteLLM on GitHub: &lt;a href="https://github.com/BerriAI/litellm" rel="noopener noreferrer"&gt;https://github.com/BerriAI/litellm&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Video walkthrough: &lt;a href="https://youtu.be/avKQz7VqJZE" rel="noopener noreferrer"&gt;Watch it on YouTube&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>litellm</category>
      <category>codex</category>
      <category>openai</category>
    </item>
  </channel>
</rss>
