How pi-web Honors HTTP_PROXY, HTTPS_PROXY, and NO_PROXY Environment Variables: Complete Technical Guide
The pi-web HTTP dispatcher in 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, 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 forhttp:URL schemesHTTPS_PROXY/https_proxy— Used forhttps:URL schemesNO_PROXY/no_proxy— Comma-separated list of hosts to connect to directly
Here's the core logic from lib/http-dispatcher.ts:
// 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:
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:
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:
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, the dispatcher is imported and used for:
- Model API requests
- Skill registry queries
- File downloads and uploads
- Telemetry submissions
// 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:
// 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
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
# 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
# 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.tslayer handles all request routing - Scheme-aware agent selection uses
HttpProxyAgentforhttp:andHttpsProxyAgentforhttps:URLs - NO_PROXY suffix matching supports domain wildcards and exact host exceptions
- Universal coverage through
lib/agent-client.tsensures every outbound request follows proxy rules - Comprehensive tests in
lib/http-dispatcher.test.mjsverify 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →