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
Option 2: Systemd Service (recommended, auto-start on boot)
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_TOKENwith your actual LiteLLMmaster_key - Bash rules use prefix matching, e.g.,
Bash(git:*)matches all commands starting withgit
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_URLmisconfigured insettings.json
Solutions:
- Check LiteLLM service status:
sudo systemctl status litellm - Confirm proxy is unset:
echo $http_proxy(should be empty) - Use the startup script
claude-start.shwhich unsets all proxy variables - Confirm
ANTHROPIC_BASE_URLends with a slash:http://127.0.0.1:4331/ - Verify
settings.jsonsyntax: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:
- Check if Clash is running
- Verify proxy configuration in systemd service file
- View LiteLLM logs:
sudo journalctl -u litellm -f
Q3: Model Name Mismatch
Possible causes:
- Model name in
settings.jsondoesn’t matchmodel_namein LiteLLM’sconfig.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
.envfile - Set a strong password for LiteLLM’s
master_key