# How pi-web Honors HTTP_PROXY, HTTPS_PROXY, and NO_PROXY Environment Variables: Complete Technical Guide

> Learn how pi-web automatically uses HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables for outbound requests. Discover proxy agent instantiation and bypass rules in this technical guide.

- Repository: [Alex Yang/pi-web](https://github.com/agegr/pi-web)
- Tags: deep-dive
- Published: 2026-08-16

---

**The pi-web HTTP dispatcher in [`lib/http-dispatcher.ts`](https://github.com/agegr/pi-web/blob/main/lib/http-dispatcher.ts) automatically detects and applies `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` environment variables to all outbound requests by instantiating the appropriate proxy agent based on URL scheme and bypass rules.**

The **pi-web** repository provides a lightweight HTTP dispatch layer that transparently handles proxy configuration for every network call. Whether you're fetching model data, installing skills, or calling external APIs, pi-web respects standard proxy environment variables without requiring explicit configuration in your application code.

## How the HTTP Dispatcher Reads Proxy Environment Variables

In [`lib/http-dispatcher.ts`](https://github.com/agegr/pi-web/blob/main/lib/http-dispatcher.ts), pi-web constructs a dispatcher function that inspects `process.env` at runtime. The implementation checks for both uppercase and lowercase variants of each variable, following common Unix conventions.

The dispatcher extracts three key configuration sources:

- **`HTTP_PROXY` / `http_proxy`** — Used for `http:` URL schemes
- **`HTTPS_PROXY` / `https_proxy`** — Used for `https:` URL schemes  
- **`NO_PROXY` / `no_proxy`** — Comma-separated list of hosts to connect to directly

Here's the core logic from [`lib/http-dispatcher.ts`](https://github.com/agegr/pi-web/blob/main/lib/http-dispatcher.ts):

```typescript
// lib/http-dispatcher.ts (simplified)
function createHttpDispatcher() {
  const httpProxy  = process.env.HTTP_PROXY  ?? process.env.http_proxy;
  const httpsProxy = process.env.HTTPS_PROXY ?? process.env.https_proxy;
  const noProxy    = (process.env.NO_PROXY ?? process.env.no_proxy ?? "")
                     .split(/\s*,\s*/)
                     .filter(Boolean);

  return (url: string, init?: RequestInit) => {
    const { hostname, protocol } = new URL(url);
    // Bypass proxy if host matches NO_PROXY
    if (noProxy.some(p => hostname.endsWith(p))) return fetch(url, init);

    // Choose the proper proxy agent
    const agent =
      protocol === "http:" && httpProxy
        ? new HttpProxyAgent(httpProxy)
        : protocol === "https:" && httpsProxy
          ? new HttpsProxyAgent(httpsProxy)
          : undefined;

    return fetch(url, { ...init, agent });
  };
}

```

The **split and filter** operation on `NO_PROXY` handles extra whitespace and empty entries, making the parser tolerant of real-world configuration styles like `"localhost, 127.0.0.1, *.internal"`.

## Proxy Agent Selection Based on URL Scheme

### HTTP Proxy Agent

When the target URL uses `http:` and `HTTP_PROXY` is set, pi-web creates an `HttpProxyAgent` from the **http-proxy-agent** package:

```typescript
protocol === "http:" && httpProxy
  ? new HttpProxyAgent(httpProxy)

```

This agent implements the HTTP CONNECT tunneling method required to route unencrypted HTTP traffic through a proxy server.

### HTTPS Proxy Agent

For `https:` URLs with `HTTPS_PROXY` configured, pi-web instantiates `HttpsProxyAgent` from **https-proxy-agent**:

```typescript
protocol === "https:" && httpsProxy
  ? new HttpsProxyAgent(httpsProxy)

```

The HTTPS agent performs TLS encryption **after** establishing the CONNECT tunnel, ensuring end-to-end security even through the proxy.

### Direct Connection Fallback

If no matching proxy variable is set, or if the agent creation fails, the dispatcher passes `undefined` as the agent parameter. Modern Node.js `fetch` implementations (Undici) then use the default global agent for direct connections.

## NO_PROXY Bypass Logic

The **most nuanced part** of pi-web's proxy handling is the `NO_PROXY` implementation. Before applying any proxy, the dispatcher checks:

```typescript
if (noProxy.some(p => hostname.endsWith(p))) return fetch(url, init);

```

This **suffix match** behavior means:

| NO_PROXY entry | Matches these hosts |
|---------------|---------------------|
| `localhost` | `localhost`, `myapp.localhost` |
| `.example.com` | `api.example.com`, `deep.sub.example.com` |
| `192.168.1.1` | Exact match only |

The `.endsWith()` approach aligns with curl's interpretation and handles the leading-dot convention for domain wildcards.

## Integration with Higher-Level Components

All pi-web network operations flow through this dispatcher. In [`lib/agent-client.ts`](https://github.com/agegr/pi-web/blob/main/lib/agent-client.ts), the dispatcher is imported and used for:

- Model API requests
- Skill registry queries  
- File downloads and uploads
- Telemetry submissions

```typescript
// lib/agent-client.ts usage pattern
import { createHttpDispatcher } from './http-dispatcher';

const dispatch = createHttpDispatcher();

export async function fetchModelMetadata(modelId: string) {
  return dispatch(`https://registry.example.com/models/${modelId}`);
}

```

This **centralized routing** ensures consistent proxy behavior across the entire application without scattering environment variable checks throughout the codebase.

## Test Coverage for Proxy Behavior

The `lib/http-dispatcher.test.mjs` file validates proxy handling with a local mock proxy server:

```javascript
// lib/http-dispatcher.test.mjs - conceptual test structure
test('uses HTTP_PROXY for http URLs', async () => {
  process.env.HTTP_PROXY = 'http://localhost:9999';
  const server = createMockProxy();
  
  const dispatch = createHttpDispatcher();
  await dispatch('http://example.com/data');
  
  expect(server.receivedConnections).toBe(1);
});

test('bypasses proxy for NO_PROXY hosts', async () => {
  process.env.HTTP_PROXY = 'http://localhost:9999';
  process.env.NO_PROXY = 'direct.example.com';
  
  const dispatch = createHttpDispatcher();
  await dispatch('http://direct.example.com/data');
  
  // Request went directly, not through proxy
});

```

Additional coverage in `lib/project-command-env.test.mjs` verifies that command-line tooling respects `HTTPS_PROXY` when executing subcommands.

## Practical Configuration Examples

### Basic Corporate Proxy Setup

```bash
export HTTP_PROXY="http://proxy.corp.internal:8080"
export HTTPS_PROXY="http://proxy.corp.internal:8080"
export NO_PROXY="localhost,127.0.0.1,.internal.corp"

# Run pi-web application - all requests automatically proxied

npm start

```

### Split HTTP/HTTPS Proxies

```bash

# Different proxies for encrypted vs unencrypted traffic

export HTTP_PROXY="http://http-proxy.prd:3128"
export HTTPS_PROXY="https://secure-proxy.prd:8443"
export NO_PROXY="metadata.google.internal,.cluster.local"

```

### Container/Kubernetes Deployment

```yaml

# Kubernetes deployment snippet

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - name: pi-web
          env:
            - name: HTTP_PROXY
              value: "http://$(PROXY_SERVICE_HOST):$(PROXY_SERVICE_PORT)"
            - name: HTTPS_PROXY
              value: "http://$(PROXY_SERVICE_HOST):$(PROXY_SERVICE_PORT)"
            - name: NO_PROXY
              value: "kubernetes.default.svc,.cluster.local,169.254.169.254"

```

## Summary

- **pi-web's proxy support is automatic** — set environment variables and the [`lib/http-dispatcher.ts`](https://github.com/agegr/pi-web/blob/main/lib/http-dispatcher.ts) layer handles all request routing
- **Scheme-aware agent selection** uses `HttpProxyAgent` for `http:` and `HttpsProxyAgent` for `https:` URLs
- **NO_PROXY suffix matching** supports domain wildcards and exact host exceptions
- **Universal coverage** through [`lib/agent-client.ts`](https://github.com/agegr/pi-web/blob/main/lib/agent-client.ts) ensures every outbound request follows proxy rules
- **Comprehensive tests** in `lib/http-dispatcher.test.mjs` verify correct behavior across proxy, direct, and bypass scenarios

## Frequently Asked Questions

### How does pi-web handle lowercase proxy variables like `http_proxy`?

pi-web checks both uppercase and lowercase variants using the nullish coalescing operator: `process.env.HTTP_PROXY ?? process.env.http_proxy`. The uppercase form takes precedence if both are present, matching the behavior of most Unix networking tools.

### Can I disable proxying for specific subdomains only?

Yes. Add the subdomain pattern to `NO_PROXY` with a leading dot to match all subdomains: `export NO_PROXY=".internal.example.com"` matches `api.internal.example.com` but not `external.example.com` or `example.com` itself.

### What happens if HTTPS_PROXY is set but the proxy URL uses http:// scheme?

The `HttpsProxyAgent` accepts both `http://` and `https://` proxy URLs. An `http://` proxy URL for HTTPS traffic establishes an unencrypted CONNECT tunnel, which is then encrypted end-to-end between your application and the destination server. This is the most common enterprise configuration.

### Does pi-web support authenticated proxies?

Yes. Include credentials directly in the proxy URL: `https://user:pass@proxy.example.com:8080`. The `http-proxy-agent` and `https-proxy-agent` packages parse and apply these credentials automatically in the `Proxy-Authorization` header.