Running Claude Code with LiteLLM Proxy for Third-Party APIs in WSL-Ubuntu

 

This tutorial explains how to run Claude Code in a WSL (Windows Subsystem for Linux) Ubuntu environment by proxying third-party APIs (such as Poe API) through LiteLLM.

Prerequisites

  • WSL2 + Ubuntu (22.04 or later recommended)
  • Python 3.10+
  • Network proxy (this tutorial uses Clash as an example, port 7890, without TUN mode)
  • Third-party API key (such as Poe API Key)

1. Install LiteLLM

pip install 'litellm[proxy]'

2. Create LiteLLM Configuration File

Create the working directory and configuration file:

mkdir -p ~/litellm
cd ~/litellm

Create config.yaml:

model_list:
  - model_name: claude-opus-4.5
    litellm_params:
      model: openai/claude-opus-4.5
      api_base: os.environ/API_BASE_URL
      api_key: os.environ/API_KEY
      allowed_openai_params: ["reasoning_effort"]
  - model_name: claude-sonnet-4.5
    litellm_params:
      model: openai/claude-sonnet-4.5
      api_base: os.environ/API_BASE_URL
      api_key: os.environ/API_KEY
      allowed_openai_params: ["reasoning_effort"]
  - model_name: claude-haiku-4.5
    litellm_params:
      model: openai/claude-haiku-4.5
      api_base: os.environ/API_BASE_URL
      api_key: os.environ/API_KEY
      allowed_openai_params: ["reasoning_effort"]

litellm_settings:
  master_key: os.environ/LITELLM_MASTER_KEY

Configuration Details:

Field Description
model_name The model name used when Claude Code makes API calls
model The model format used by LiteLLM, openai/ prefix indicates OpenAI-compatible interface
api_base The base URL of the third-party API (uses environment variable for security)
api_key Third-party API key (uses environment variable for security)
master_key Access key for the LiteLLM proxy service (uses environment variable for security)

Note: LiteLLM supports os.environ/VARIABLE_NAME syntax to read sensitive values from environment variables, keeping your config file free of secrets.

3. Start LiteLLM Service

Option 1: Manual Start (for debugging)

# Set API credentials
export API_BASE_URL="https://your-api-provider.com/v1"
export API_KEY="your-api-key"
export LITELLM_MASTER_KEY="sk-litellm-your-secret-key"

# Ensure proxy is set (if external network access is needed)
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890

# Start LiteLLM
litellm --config ~/litellm/config.yaml --port 4331

Create the systemd service file:

sudo vim /etc/systemd/system/litellm.service

Add the following content:

[Unit]
Description=LiteLLM Proxy Server
After=network.target

[Service]
Type=simple
User=YOUR_USER_NAME
WorkingDirectory=/home/YOUR_USER_NAME/litellm
ExecStart=litellm --config /home/YOUR_USER_NAME/litellm/config.yaml --port 4331
Restart=always
RestartSec=5
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
Environment="API_BASE_URL=https://your-api-provider.com/v1"
Environment="API_KEY=your-api-key"
Environment="LITELLM_MASTER_KEY=sk-litellm-your-secret-key"
Environment="http_proxy=http://127.0.0.1:7890"
Environment="https_proxy=http://127.0.0.1:7890"

[Install]
WantedBy=multi-user.target

Note: Replace User and paths with your own username and actual paths.

Enable and start the service:

sudo systemctl daemon-reload
sudo systemctl enable litellm
sudo systemctl start litellm

Common commands for managing the service:

sudo systemctl status litellm
sudo journalctl -u litellm -f

4. Verify LiteLLM Service

Use curl to test if the service is running properly:

curl -X POST http://127.0.0.1:4331/v1/messages \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-4.5",
    "max_tokens": 1000,
    "messages": [{"role": "user", "content": "Hello, who are you?"}]
  }'

If you receive a normal JSON response, the service is ready.

5. Configure and Start Claude Code

Configure settings.json

The recommended way to configure Claude Code is using ~/.claude/settings.json. This makes settings persistent, easier to manage, and avoids the need for environment variables or startup scripts.

Create the configuration file:

mkdir -p ~/.claude
vim ~/.claude/settings.json

Add the following content:

{
  "model": "claude-opus-4.5",
  "permissions": {
    "allow": [
      "Bash(git apply:*)",
      "Bash(git status:*)",
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "Bash(git branch:*)",
      "Bash(git checkout:*)",
      "Bash(git add:*)",
      "Bash(git commit:*)",
      "Bash(git merge:*)",
      "Bash(git merge-base:*)",
      "Bash(git rebase:*)",
      "Bash(git stash:*)",
      "Bash(git reset:*)",
      "Bash(git clone:*)",
      "Bash(git remote:*)",
      "Bash(git tag:*)",
      "Bash(curl:*)",
      "Bash(cat:*)",
      "Bash(ls:*)",
      "Bash(grep:*)",
      "Bash(find:*)",
      "Bash(head:*)",
      "Bash(tail:*)"
    ]
  },
  "env": {
    "ANTHROPIC_BASE_URL": "http://127.0.0.1:4331/",
    "ANTHROPIC_AUTH_TOKEN": "sk-litellm-your-secret-key",
    "ANTHROPIC_MODEL": "claude-opus-4.5",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4.5",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4.5",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-haiku-4.5",
    "CLAUDE_CODE_SUBAGENT_MODEL": "claude-opus-4.5",
    "CLAUDE_CODE_MAX_OUTPUT_TOKENS": "64000",
    "MAX_THINKING_TOKENS": "16000"
  }
}

Configuration Details:

Field Description
model Default model, must match model_name in LiteLLM config
permissions.allow Commands allowed to run automatically (prefix matching)
ANTHROPIC_BASE_URL LiteLLM proxy URL (must end with /)
ANTHROPIC_AUTH_TOKEN LiteLLM’s master_key for authentication
ANTHROPIC_MODEL Default model name
CLAUDE_CODE_MAX_OUTPUT_TOKENS Maximum output tokens for most requests
MAX_THINKING_TOKENS Enables extended thinking mode with token budget for complex reasoning tasks

Notes:

  • Replace ANTHROPIC_AUTH_TOKEN with your actual LiteLLM master_key
  • Bash rules use prefix matching, e.g., Bash(git:*) matches all commands starting with git

Start Claude Code (WSL-specific)

Important for WSL users: WSL may inherit proxy settings from Windows or your shell configuration (e.g., .bashrc, .zshrc). Setting proxy to empty strings in settings.json does not work reliably. You must unset the proxy environment variables before starting Claude Code.

Create a startup script:

mkdir -p ~/bin
vim ~/bin/claude-start.sh

Add the following content:

#!/bin/bash

# Claude Code startup script for WSL
# Unset proxy to ensure direct connection to local LiteLLM service
unset http_proxy
unset https_proxy
unset HTTP_PROXY
unset HTTPS_PROXY
unset all_proxy
unset ALL_PROXY

# Start Claude Code
claude "$@"

Add execute permission and optionally add to PATH:

chmod +x ~/bin/claude-start.sh
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

Now start Claude Code:

cd /path/to/your/project
claude-start.sh

Why unset proxy in WSL?

Claude Code needs to directly access the local LiteLLM service at 127.0.0.1:4331. In WSL, proxy environment variables may be set globally (from Windows host or shell config), and simply setting them to empty strings in settings.json won’t override existing environment variables. Using unset completely removes these variables, ensuring direct local connections.

FAQ

Q1: Claude Code Connection Timeout

Possible causes:

  • LiteLLM service is not running
  • Proxy environment variables not properly unset (WSL-specific)
  • ANTHROPIC_BASE_URL misconfigured in settings.json

Solutions:

  1. Check LiteLLM service status: sudo systemctl status litellm
  2. Confirm proxy is unset: echo $http_proxy (should be empty)
  3. Use the startup script claude-start.sh which unsets all proxy variables
  4. Confirm ANTHROPIC_BASE_URL ends with a slash: http://127.0.0.1:4331/
  5. Verify settings.json syntax: cat ~/.claude/settings.json | jq .

Q2: LiteLLM Cannot Connect to Third-Party API

Possible causes:

  • Proxy not configured in systemd service
  • Proxy service is not running

Solutions:

  1. Check if Clash is running
  2. Verify proxy configuration in systemd service file
  3. View LiteLLM logs: sudo journalctl -u litellm -f

Q3: Model Name Mismatch

Possible causes:

  • Model name in settings.json doesn’t match model_name in LiteLLM’s config.yaml

Solutions: Ensure model and ANTHROPIC_MODEL in ~/.claude/settings.json exactly match the model_name in LiteLLM’s config.yaml.

Security Tips

  • Do not commit configuration files containing API keys to public repositories
  • Store sensitive information in environment variables or a separate .env file
  • Set a strong password for LiteLLM’s master_key

References