Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1446dae
feat(config): add ProxyConfig schema
Thesam1798 Jan 27, 2026
9a704ea
feat(util): add proxy-aware fetch wrapper
Thesam1798 Jan 27, 2026
fb6fd11
test(fetch): add unit tests for proxy wrapper
Thesam1798 Jan 27, 2026
d6ad2ab
refactor(models): use proxyFetch for models.dev
Thesam1798 Jan 27, 2026
78f1a4a
refactor(installation): use proxyFetch for version checks
Thesam1798 Jan 27, 2026
410dcd8
refactor(tools): use proxyFetch for webfetch/websearch/codesearch
Thesam1798 Jan 27, 2026
34bc348
refactor(share): use proxyFetch
Thesam1798 Jan 27, 2026
3006a2c
refactor(mcp): use proxyFetch for remote transports
Thesam1798 Jan 27, 2026
4dfb1de
refactor(lsp): use proxyFetch for JS/TS servers
Thesam1798 Jan 27, 2026
6b3162d
refactor(lsp): use proxyFetch for system language servers
Thesam1798 Jan 27, 2026
c73a8cb
refactor(lsp): use proxyFetch for other servers
Thesam1798 Jan 27, 2026
ad339e7
refactor(ripgrep): use proxyFetch for binary download
Thesam1798 Jan 27, 2026
b237159
refactor(config): use proxyFetch for well-known
Thesam1798 Jan 27, 2026
1e4ee24
refactor(instruction): use proxyFetch for remote instructions
Thesam1798 Jan 27, 2026
ddb25e7
refactor(plugins): use proxyFetch for OAuth
Thesam1798 Jan 27, 2026
a8c003b
refactor(cli): use proxyFetch for CLI commands
Thesam1798 Jan 27, 2026
7618019
test(fetch): add integration tests for proxy support
Thesam1798 Jan 27, 2026
02cb0e7
docs: add proxy configuration documentation
Thesam1798 Jan 27, 2026
c13f25c
fix(opencode): resolve type intersection for proxy option
Thesam1798 Jan 27, 2026
c824688
fix(opencode): wire proxy config from opencode.json to fetch layer
Thesam1798 Jan 27, 2026
14e20ba
test(opencode): improve proxy test cleanup and naming
Thesam1798 Jan 27, 2026
cba1dbd
docs(opencode): replace insecure TLS workaround with proper solutions
Thesam1798 Jan 27, 2026
fafcafd
feat(opencode): add TLS configuration for proxy connections
Thesam1798 Jan 27, 2026
2d15b75
test(opencode): add tests for proxy TLS configuration
Thesam1798 Jan 27, 2026
9629601
docs(opencode): document proxy TLS configuration
Thesam1798 Jan 27, 2026
8a344fd
fix(opencode): address Copilot review feedback
Thesam1798 Jan 27, 2026
88e2004
test(opencode): add regression tests for issues #6953 and #10710
Thesam1798 Jan 27, 2026
85aac49
refactor(skill): use proxyFetch for skill discovery downloads
Thesam1798 Feb 6, 2026
292afe5
refactor(codex): use proxyFetch for OAuth headless flow
Thesam1798 Feb 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 226 additions & 0 deletions packages/opencode/docs/proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
# Proxy Configuration

OpenCode supports HTTP/HTTPS proxy configuration for environments that require outbound traffic to go through a corporate proxy.

## Quick Start

Set the environment variables before running OpenCode:

```bash
export HTTPS_PROXY=http://proxy.example.com:8080
export HTTP_PROXY=http://proxy.example.com:8080
export NO_PROXY=localhost,127.0.0.1,*.internal.com

opencode
```

## Environment Variables

| Variable | Description | Example |
| ------------------------ | ------------------------------------------- | -------------------------- |
| `HTTPS_PROXY` | Proxy URL for HTTPS requests | `http://proxy:8080` |
| `HTTP_PROXY` | Proxy URL for HTTP requests | `http://proxy:8080` |
| `NO_PROXY` | Comma-separated list of hosts to bypass | `localhost,*.internal.com` |
| `https_proxy` | Alternative (lowercase) | Same as above |
| `http_proxy` | Alternative (lowercase) | Same as above |
| `no_proxy` | Alternative (lowercase) | Same as above |
| `OPENCODE_DISABLE_PROXY` | Emergency bypass flag (any non-empty value) | `1` |

## Configuration File

You can also configure proxy settings in `opencode.json`:

```json
{
"proxy": {
"http": "http://proxy.example.com:8080",
"https": "http://proxy.example.com:8080",
"no_proxy": ["localhost", "127.0.0.1", "*.internal.com"]
}
}
```

**Priority Order:**

1. Configuration file (`opencode.json`) - highest priority
2. Environment variables - fallback

## NO_PROXY Patterns

The `NO_PROXY` / `no_proxy` setting supports these patterns:

| Pattern | Description | Example |
| --------------- | -------------------------------- | ---------------- |
| `*` | Bypass all hosts (disable proxy) | `*` |
| `hostname` | Exact match or suffix match | `localhost` |
| `*.domain.com` | Wildcard subdomain match | `*.internal.com` |
| `.domain.com` | Suffix match (subdomains only) | `.ft.intra` |
| `192.168.1.100` | Exact IP match | - |

### Examples

```bash
# Bypass proxy for localhost and internal networks
NO_PROXY=localhost,127.0.0.1,*.internal.com,.ft.intra

# Bypass proxy for all hosts (emergency)
NO_PROXY=*
```

## Proxy URL Format

Standard proxy URL format:

```
http://[user:password@]host:port
```

**Examples:**

```bash
# Without authentication
HTTPS_PROXY=http://proxy.example.com:8080

# With authentication
HTTPS_PROXY=http://user:password@proxy.example.com:8080
```

## Emergency Bypass

If the proxy configuration causes issues, you can temporarily disable it:

```bash
OPENCODE_DISABLE_PROXY=1 opencode
```

This bypasses all proxy settings and uses direct connections.

## What Uses the Proxy

All HTTP/HTTPS requests made by OpenCode go through the proxy when configured:

- Model API calls (Anthropic, OpenAI, etc.)
- Provider authentication (OAuth flows)
- Version check and auto-update
- LSP language server downloads
- MCP server connections (HTTP/SSE transports)
- Web fetch/search tools
- GitHub API integration
- Share functionality

## Limitations

- **WebSocket connections**: Not proxied (Bun limitation)
- **Local MCP servers**: stdio-based servers are not affected

## Troubleshooting

### Proxy not being used

1. Check if the environment variable is set:

```bash
echo $HTTPS_PROXY
```

2. Verify the URL format is correct (must include `http://`)

3. Check if the host is in NO_PROXY:
```bash
echo $NO_PROXY
```

### SSL/TLS errors through proxy

Some corporate proxies perform SSL interception. You may need to:

1. Configure the proxy's CA certificate in your system trust store
2. Use `NODE_EXTRA_CA_CERTS=/path/to/ca.pem` to trust additional certificates
3. Use `BUN_OPTIONS="--use-system-ca"` to use system certificate store
4. Configure `proxy.tls` in opencode.json (see below)

### Proxy TLS Configuration

If your corporate proxy uses a self-signed certificate or custom CA, you can configure TLS settings directly in `opencode.json`.

**Custom CA certificate for proxy (recommended):**

```json
{
"proxy": {
"https": "http://proxy:8080",
"tls": {
"ca": "/path/to/proxy-ca.pem"
}
}
}
```

**Multiple CA certificates:**

```json
{
"proxy": {
"https": "http://proxy:8080",
"tls": {
"ca": ["/path/to/ca1.pem", "/path/to/ca2.pem"]
}
}
}
```

**Accept self-signed proxy certificates (use with caution):**

```json
{
"proxy": {
"https": "http://proxy:8080",
"tls": {
"rejectUnauthorized": false
}
}
}
```

> **Warning:** Setting `rejectUnauthorized: false` disables TLS certificate validation for proxy connections. This makes the connection vulnerable to man-in-the-middle attacks. Only use this for trusted internal proxies where you cannot install the CA certificate.

### Proxy authentication failing

Ensure special characters in password are URL-encoded:

```bash
# Password with @ symbol
HTTPS_PROXY=http://user:p%40ssword@proxy.example.com:8080
```

## Example Configurations

### Corporate Proxy (France Travail)

```bash
export HTTPS_PROXY=http://proxyaws.pole-emploi.intra:8080
export HTTP_PROXY=http://proxyaws.pole-emploi.intra:8080
export NO_PROXY=localhost,127.0.0.1,*.pole-emploi.intra,*.ft.intra
```

### Docker with Proxy

```dockerfile
ENV HTTPS_PROXY=http://proxy.example.com:8080
ENV HTTP_PROXY=http://proxy.example.com:8080
ENV NO_PROXY=localhost,127.0.0.1
```

### CI/CD Pipeline

```yaml
# GitLab CI
variables:
HTTPS_PROXY: http://proxy.example.com:8080
NO_PROXY: localhost,127.0.0.1,*.internal.com

# GitHub Actions
env:
HTTPS_PROXY: http://proxy.example.com:8080
NO_PROXY: localhost,127.0.0.1
```
3 changes: 2 additions & 1 deletion packages/opencode/src/cli/cmd/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Config } from "../../config/config"
import { Global } from "../../global"
import { Plugin } from "../../plugin"
import { Instance } from "../../project/instance"
import { proxyFetch } from "../../util/fetch"
import type { Hooks } from "@opencode-ai/plugin"

type PluginAuth = NonNullable<Hooks["auth"]>
Expand Down Expand Up @@ -229,7 +230,7 @@ export const AuthLoginCommand = cmd({
UI.empty()
prompts.intro("Add credential")
if (args.url) {
const wellknown = await fetch(`${args.url}/.well-known/opencode`).then((x) => x.json() as any)
const wellknown = await proxyFetch(`${args.url}/.well-known/opencode`).then((x) => x.json() as any)
prompts.log.info(`Running \`${wellknown.auth.command.join(" ")}\``)
const proc = Bun.spawn({
cmd: wellknown.auth.command,
Expand Down
11 changes: 6 additions & 5 deletions packages/opencode/src/cli/cmd/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
import { UI } from "../ui"
import { cmd } from "./cmd"
import { ModelsDev } from "../../provider/models"
import { proxyFetch } from "../../util/fetch"
import { Instance } from "@/project/instance"
import { bootstrap } from "../bootstrap"
import { Session } from "../../session"
Expand Down Expand Up @@ -354,7 +355,7 @@ export const GithubInstallCommand = cmd({
s.stop("Installed GitHub app")

async function getInstallation() {
return await fetch(
return await proxyFetch(
`https://api.opencode.ai/get_github_app_installation?owner=${app.owner}&repo=${app.repo}`,
)
.then((res) => res.json())
Expand Down Expand Up @@ -784,7 +785,7 @@ export const GithubRunCommand = cmd({
const filename = path.basename(url)

// Download image
const res = await fetch(url, {
const res = await proxyFetch(url, {
headers: {
Authorization: `Bearer ${appToken}`,
Accept: "application/vnd.github.v3+json",
Expand Down Expand Up @@ -973,14 +974,14 @@ export const GithubRunCommand = cmd({

async function exchangeForAppToken(token: string) {
const response = token.startsWith("github_pat_")
? await fetch(`${oidcBaseUrl}/exchange_github_app_token_with_pat`, {
? await proxyFetch(`${oidcBaseUrl}/exchange_github_app_token_with_pat`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ owner, repo }),
})
: await fetch(`${oidcBaseUrl}/exchange_github_app_token`, {
: await proxyFetch(`${oidcBaseUrl}/exchange_github_app_token`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
Expand Down Expand Up @@ -1534,7 +1535,7 @@ query($owner: String!, $repo: String!, $number: Int!) {
async function revokeAppToken() {
if (!appToken) return

await fetch("https://api.github.com/installation/token", {
await proxyFetch("https://api.github.com/installation/token", {
method: "DELETE",
headers: {
Authorization: `Bearer ${appToken}`,
Expand Down
3 changes: 2 additions & 1 deletion packages/opencode/src/cli/cmd/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { cmd } from "./cmd"
import { bootstrap } from "../bootstrap"
import { Storage } from "../../storage/storage"
import { Instance } from "../../project/instance"
import { proxyFetch } from "../../util/fetch"
import { EOL } from "os"

export const ImportCommand = cmd({
Expand Down Expand Up @@ -39,7 +40,7 @@ export const ImportCommand = cmd({
}

const slug = urlMatch[1]
const response = await fetch(`https://opncd.ai/api/share/${slug}`)
const response = await proxyFetch(`https://opncd.ai/api/share/${slug}`)

if (!response.ok) {
process.stdout.write(`Failed to fetch share data: ${response.statusText}`)
Expand Down
3 changes: 2 additions & 1 deletion packages/opencode/src/cli/cmd/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { McpOAuthProvider } from "../../mcp/oauth-provider"
import { Config } from "../../config/config"
import { Instance } from "../../project/instance"
import { Installation } from "../../installation"
import { proxyFetch } from "../../util/fetch"
import path from "path"
import { Global } from "../../global"
import { modify, applyEdits } from "jsonc-parser"
Expand Down Expand Up @@ -651,7 +652,7 @@ export const McpDebugCommand = cmd({

// Test basic HTTP connectivity first
try {
const response = await fetch(serverConfig.url, {
const response = await proxyFetch(serverConfig.url, {
method: "POST",
headers: {
"Content-Type": "application/json",
Expand Down
Loading
Loading