Playground fails to reach private-IP model endpoints behind a domain-allowlist proxy
Last updated: August 26, 2026
Symptom
In self-hosted LangSmith prior to 0.16, Playground requests to an OpenAI-compatible model endpoint that resolves to a private or internal IP address fail when invoking or streaming a response. This happens even though the Playground pod has HTTP_PROXY/HTTPS_PROXY/NO_PROXY, OPENAI_BASE_URL, and OPENAI_API_KEY configured, and even though a plain curl or a standard OpenAI client run from inside the same pod succeeds against the same endpoint.
Playground logs show one of:
openai.APIConnectionError("Connection error.")
httpx.ConnectError("All connection attempts failed")
You may also see an explicit block:
SSRF blocked: private IP rangeIf you disable the private-IP block but the corporate proxy only allowlists by domain name, the request fails differently:
httpx.ProxyError('403 Forbidden')This pattern is common in enterprise self-hosted deployments where the model endpoint sits behind an internal network path only reachable through a corporate proxy.
Cause
Playground routes outbound model calls through an SSRF-safe transport that protects against DNS-rebinding attacks. This transport resolves the target hostname to an IP address and, for a proxied request, pins the outbound CONNECT to that resolved IP instead of the original hostname, even when a proxy is configured.
This causes two related failures:
Without any override, the transport rejects the request outright because the resolved address falls in a private IP range (
SSRF blocked: private IP range).Once the private-IP block is overridden, the transport still pins the proxied CONNECT to the resolved IP. Corporate proxies that allowlist by domain name (a common pattern, since the private IP behind such an endpoint can rotate) reject the CONNECT with a 403, because they only recognize the original hostname, not the IP.
A related pitfall to watch for while diagnosing this: if the private-IP-resolving hostname is added to NO_PROXY, the client bypasses the proxy entirely for that host and routes directly through the SSRF transport to the resolved private IP. That fails outright if the pod can't reach the IP without going through the proxy. Keep the hostname out of NO_PROXY so traffic routes through HTTPS_PROXY.
Resolution
This was fixed as a product change: the SSRF-safe transport now preserves the hostname (instead of pinning to the resolved IP) for proxied CONNECT requests, so domain-allowlist proxies no longer reject the tunnel with a 403. The fix shipped to SaaS first and was backported to the self-hosted 0.15 stable line, and is included in later 0.16.x builds. Relevant version: self-hosted LangSmith 0.15.x lines and early 0.16.x builds prior to the fix.
If you're on a build before the fix, use this interim configuration for private-IP-backed, proxy-routed model endpoints in Playground:
Set
SSRF_ALLOW_K8S_INTERNAL=trueandSSRF_ALLOW_PRIVATE_IPS_PLAYGROUND=trueinplayground.deployment.extraEnv(and addSSRF_ALLOW_K8S_INTERNALtocommonEnvas well) to disable the private-IP SSRF block for the Playground surface.Keep
HTTP_PROXY/HTTPS_PROXYconfigured, and do not add the private-IP-resolving hostname toNO_PROXY. It needs to keep routing through the proxy rather than being resolved and connected to directly.
After upgrading to a build with the fix, this workaround is no longer needed. The SSRF transport hands the hostname (not the resolved IP) to the proxy for the CONNECT, so domain-allowlist proxies accept it.