Skip to main content
Custom hosts with private network routing — including the TRUSTED_CUSTOM_HOSTS allowlist — applies only to hybrid and air-gapped enterprise deployments of the Portkey AI Gateway. On Portkey SaaS, custom host URLs must be publicly reachable; routing to private or internal network IPs is not supported.
The custom_host parameter routes Portkey Gateway requests to your own model endpoints — whether running locally, in a private cloud, or on custom infrastructure. Portkey validates all custom host URLs to prevent SSRF attacks.

Setting a custom host

Specify a custom host using one of these methods:
MethodParameter
HTTP headerx-portkey-custom-host
Python SDKcustom_host
Node.js SDKcustomHost
Gateway configcustom_host (in the target object)
from portkey_ai import Portkey

portkey = Portkey(
    api_key="PORTKEY_API_KEY",
    provider="openai",
    custom_host="https://your-llm-server.com/v1/"
)

response = portkey.chat.completions.create(
    model="your-model",
    messages=[{"role": "user", "content": "Hello"}]
)
Also set custom_host in a Gateway config target:
{
  "strategy": { "mode": "fallback" },
  "targets": [
    {
      "provider": "openai",
      "custom_host": "https://your-private-llm.com/v1",
      "forward_headers": ["Authorization"]
    },
    {
      "provider": "openai",
      "api_key": "sk-xxxxx"
    }
  ]
}
Include the version path (e.g., /v1) in the custom_host URL. Portkey appends the endpoint path (/chat/completions, /responses, etc.) automatically.
forward_headers cannot include cloud metadata headers such as metadata-flavor, x-aws-ec2-metadata-token, or x-google-metadata-request, or the x-portkey-forward-headers header itself.
For a full guide on integrating private LLMs, see Bring Your Own LLM.

How validation works

Portkey applies SSRF checks at two layers on Node.js deployments:
  1. Request time — When a custom_host URL is accepted, the gateway validates the hostname, port, scheme, and URL shape before the request proceeds.
  2. Connection time — On outbound requests, DNS resolution validates every returned IP against the same rules and pins the connection to safe addresses. This blocks DNS rebinding attacks where a hostname initially resolves to a public IP but later resolves to a private or metadata address.
On Cloudflare Workers, request-time validation still applies; connection-time DNS pinning is a Node.js-only hardening layer. URLs must use http:// or https://, must not embed credentials, and are capped at 2048 characters.

Blocked host patterns

Portkey validates all custom host URLs to prevent requests to internal network resources. The following IP ranges and patterns are blocked by default (unless the hostname is explicitly trusted — see Trusted custom hosts (allowlist)).

Private IPv4 ranges

RangeDescription
10.0.0.0/8Private network (Class A)
172.16.0.0/12Private network (Class B)
192.168.0.0/16Private network (Class C)

Reserved IPv4 ranges

RangeDescription
127.0.0.0/8Loopback addresses (except 127.0.0.1 when trusted)
169.254.0.0/16Link-local addresses
100.64.0.0/10Carrier-grade NAT (CGNAT)
0.0.0.0/8Non-routable (includes 0.0.0.0)
224.0.0.0/4Multicast, reserved, and broadcast
198.18.0.0/15Benchmarking
192.0.0.0/24IETF protocol assignments
192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24TEST-NET ranges
192.88.99.0/24Former 6to4 relay anycast

Cloud metadata endpoints

These addresses are always blocked and cannot be allowlisted:
AddressDescription
169.254.169.254AWS / Azure / GCP / DO / Oracle / Hetzner / OpenStack IMDS (IPv4)
169.254.169.0/24Full AWS IMDS IPv4 subnet
169.254.170.2AWS ECS task metadata / credentials endpoint
169.254.170.23AWS ECS task metadata v4
100.100.100.200Alibaba Cloud instance metadata
168.63.129.16Azure platform (wireserver / DHCP / health)
192.0.0.192Oracle Cloud Classic metadata
fd00:ec2::/96AWS IMDSv2 IPv6 endpoint

Single-label blocked hostnames

These bare hostnames are always blocked (they often resolve to internal services via DNS search domains):
HostnameDescription
metadataKubernetes / generic metadata short name
instance-dataAWS instance metadata alternate name
kubernetesKubernetes API short name

Blocked hostname suffixes

Subdomains of known cloud metadata and internal service FQDNs are blocked, including (but not limited to):
  • metadata.google.internal, metadata.gce.internal, metadata.goog
  • metadata.azure.com, internal.cloudapp.net
  • metadata.internal, metadata.do.internal, metadata.packet.net
  • instance-data.ec2.internal, ec2.internal, compute.internal
  • metadata.cloud.ibm.com
  • kubernetes.default, kubernetes.default.svc, kubernetes.default.svc.cluster.local
  • cluster.local
  • consul (and *.service.consul, *.node.consul)
These suffix checks run before the trusted-host allowlist and cannot be overridden.

Wildcard DNS rebinding services

Hostnames that encode arbitrary IPs in the DNS label are blocked:
DomainExample
nip.io127.0.0.1.nip.io
sslip.io169-254-169-254.sslip.io
xip.ioArbitrary IP encoding
localtest.me, lvh.me, vcap.me, traefik.meResolve to loopback
localhost.runPublic tunnel service

Blocked internal TLDs

Hostnames ending in these TLDs are blocked unless explicitly trusted: .local, .localdomain, .internal, .intranet, .lan, .home, .corp, .test, .invalid, .onion, .localhost

IPv6 local and private ranges

RangeDescription
::1IPv6 loopback
::IPv6 unspecified
fc00::/7Unique local addresses (fc* / fd*)
fe80::/10Link-local addresses
fec0::/10Site-local addresses (deprecated)
ff00::/8Multicast
2001::/32Teredo
100:0:0:1::/64RFC 9780 dummy prefix

IPv6 addresses with embedded IPv4

IPv6 literals that embed a blocked IPv4 address are rejected, including:
  • IPv4-mapped (::ffff:127.0.0.1)
  • IPv4-compatible (::127.0.0.1, ::7f00:1)
  • 6to4 (2002:7f00:1::)
  • NAT64 (64:ff9b::7f00:1)
Public IPv6 addresses such as 2001:4860:4860::8888 remain allowed.

IP obfuscation tricks

The following alternate IP representations are also blocked to prevent bypass attempts:
  • Decimal form — e.g., 2130706433 (resolves to 127.0.0.1)
  • Hexadecimal form — e.g., 0x7f000001 (resolves to 127.0.0.1)
  • Shortened IPv4 — e.g., 127.1 (resolves to 127.0.0.1)
  • Octal notation — e.g., 0177.0.0.1 (resolves to 127.0.0.1)
  • Percent-encoded hostnames — e.g., %31%32%37...
  • Punycode labels — hostnames containing xn-- labels

Blocked ports

Even for trusted hostnames, Portkey blocks ports commonly used by non-HTTP internal services (SSH, databases, caches, admin APIs, etc.). Examples include 22, 25, 445, 3306, 5432, 6379, 6443, 9200, and 27017. HTTP and HTTPS service ports (such as 80, 443, 8000, 8080, 8443) are allowed. Ports must be between 1 and 65535.

Trusted custom hosts (allowlist)

Portkey maintains a trusted hosts allowlist via the TRUSTED_CUSTOM_HOSTS environment variable. Trusted hostnames bypass private/reserved IP range checks at request time, and their DNS-resolved addresses bypass private/reserved IP checks at connection time.
TRUSTED_CUSTOM_HOSTS is available only on self-hosted hybrid and air-gapped enterprise deployments of the Portkey AI Gateway.

Default behavior

EnvironmentTRUSTED_CUSTOM_HOSTS unsetBehavior
Non-production (NODE_ENV ≠ production)YesDefaults to localhost, 127.0.0.1, ::1, and host.docker.internal
Production (NODE_ENV = production)YesEmpty allowlist — localhost and private IPs are blocked until you opt in
AnyExplicitly setUses only the hosts you specify (replaces defaults; does not merge)
When setting TRUSTED_CUSTOM_HOSTS in non-production, include the default values (localhost, 127.0.0.1, ::1, host.docker.internal) along with your additions if you still need local development access.

Adding hosts to the allowlist

To route to a private network IP (e.g., 172.31.2.45), add it to the trusted hosts allowlist using the TRUSTED_CUSTOM_HOSTS environment variable. Set the environment variable as a comma-separated list of hosts:
TRUSTED_CUSTOM_HOSTS="localhost,127.0.0.1,::1,host.docker.internal,172.31.2.45,*.svc.internal"
Requests with custom_host set to http://172.31.2.45:8008/v1/ will then pass validation.

Entry format

Each entry can be:
FormatMatches
example.comExact hostname only (example.com)
*.example.comApex domain and any subdomain (example.com, api.example.com, v1.api.example.com, etc.)
172.31.2.45Exact IP literal only
https://example.com:8080/pathNormalized to example.com
Wildcard entries (*.domain) are supported in TRUSTED_CUSTOM_HOSTS. Subdomains are not inherited from a bare domain entry — example.com does not allow api.example.com. To trust subdomains, add an explicit wildcard entry such as *.example.com. Entries with schemes, ports, or paths are normalized automatically. Wildcard entries (*.) cannot target IP literals. When localhost is trusted, subdomains ending in .localhost (e.g., api.localhost) are also allowed.
Cloud metadata endpoints, metadata FQDN suffixes, and wildcard DNS rebinding domains cannot be allowlisted. Entries that overlap always-blocked ranges are silently dropped from TRUSTED_CUSTOM_HOSTS.

Validation rules for trusted hosts

Even for trusted hosts, Portkey enforces:
  • Port range — The port must be between 1 and 65535, and must not be on the blocked-ports list
  • Host-only matching — Only the hostname or IP is checked against the allowlist, not the full URL
  • IP literals are exact-match only — Trusting 127.0.0.1 does not unlock x.127.0.0.1
  • Subdomains require a wildcard — Trusting example.com does not unlock api.example.com; add *.example.com to cover subdomains
  • Always-blocked overrides — Cloud metadata, IMDS subnets, blocked hostname suffixes, wildcard rebinding domains, and dangerous IPv6-embedded-IPv4 forms remain blocked even when trusted

Common scenarios

ScenarioDefault behaviorAction needed
Local development (e.g., Ollama on localhost)Allowed in non-production — localhost and 127.0.0.1 are trusted by defaultNone in dev. In production, add to TRUSTED_CUSTOM_HOSTS. See the Ollama integration guide.
Docker containers (host.docker.internal)Allowed in non-production — trusted by defaultIn production, add to TRUSTED_CUSTOM_HOSTS
Private network IP (e.g., 172.31.2.45:8008)Blocked — falls within 172.16.0.0/12Add the IP to TRUSTED_CUSTOM_HOSTS (hybrid/air-gapped only)
Internal DNS name (e.g., llm.svc.internal)Blocked — .internal TLDAdd the hostname (or *.svc.internal) to TRUSTED_CUSTOM_HOSTS
Cloud metadata (169.254.169.254)Always blockedCannot be allowlisted for security reasons
DNS rebinding (127.0.0.1.nip.io)Always blockedCannot be allowlisted for security reasons
Last modified on June 15, 2026