COREDNS-PROXYPROTO(7)
π COREDNS-PROXYPROTO π
okay bestie so you're reading the coredns-proxyproto page, part of the CoreDNS Plugins manual set. Buckle in, because this plugin is lowkey the glow-up your DNS server needed: it adds PROXY protocol support (spec lives at β¨https://www.haproxy.org/download/1.8/doc/proxy-protocol.txtβ©) and honestly? it ate. π«Ά
β¨ NAME β¨
proxyproto β adds PROXY protocol support, with that spec link up above. That's the whole vibe. π
πΈ DESCRIPTION πΈ
This plugin adds support for PROXY protocol version 1 and 2. Basically it lets CoreDNS receive connections from a load balancer or proxy that's speaking the PROXY protocol, and that's how it gets the original client's IP address and port info. No more "who even are you" energy β the real client identity arrives intact. π
π SYNTAX π
proxyproto {
allow <CIDR...>
default <use|ignore|reject|skip>
udp_session_tracking <duration> [max_sessions]
tlv_metadata
}
So here's the tea on each bit:
- If
allowis unspecified, PROXY protocol headers are accepted from all IP addresses. Everybody's welcome, no bouncer. π - The
defaultoption controls how connections from sources not listed inalloware handled. Ifdefaultis unspecified, it defaults toignore. - The possible values are:
use: accept and use PROXY protocol headers from these sources βignore: accept and ignore PROXY protocol headers from other sources π€·ββοΈreject: reject connections with PROXY protocol headers from other sources βskip: skip PROXY protocol processing for connections from other sources, treating them as normal connections preserving the PROXY protocol headers πββοΈ
π¦ the UDP session tracking era π¦
The udp_session_tracking <duration> [max_sessions] option enables UDP session state tracking for Cloudflare Spectrum's PROXY Protocol v2 over UDP. Wild, I know. Here's how that works:
- Spectrum sends the PPv2 header as a standalone first datagram (with no DNS payload). Iconic but confusing.
- Subsequent datagrams from the same client arrive without any header. Rude, honestly.
- When this option is set to a positive duration, the real client address from the header-only datagram is cached (keyed by the Spectrum-side remote address) for that duration, and automatically applied to all subsequent headerless datagrams within that window. Chef's kiss. π
- The TTL is refreshed on each matching packet.
- The optional
max_sessionsargument caps the number of concurrent sessions in the LRU cache (default:10240). - This option has no effect for TCP connections. Spoiler: TCP doesn't need it.
π TLV metadata (the fancy extra) π
The tlv_metadata option exposes the PROXY Protocol v2 TLV β¨https://www.haproxy.org/download/2.3/doc/proxy-protocol.txtβ© (Type-Length-Value) vector from the header to downstream plugins via the metadata β¨../metadata/README.mdβ© plugin. So:
- When set, and the
metadataplugin is enabled, the raw TLV vector is published under the labelproxyproto/tlvas a hex-encoded string. - Consumers decode the hex and split it with
proxyproto.SplitTLVsfromgithub.com/pires/go-proxyprototo read individual TLVs (e.g. the AWS VPC endpoint ID, SSL client CN, or vendor-specific custom TLVs). Very demure, very mindful. π§ - This option is opt-in: without it, TLVs are not captured and no extra per-connection processing occurs. Zero overhead, zero drama.
- It applies to all transports:
dns://(UDP and TCP),tls://(DoT),https://(DoH),grpc://,quic://(DoQ), andhttps3://(DoH3). All of them. Every single one. β
For the QUIC-based transports (quic:// and https3://), the PPv2 header arrives as a standalone first datagram ahead of the QUIC handshake, so TLV capture additionally requires udp_session_tracking to be enabled β the cached session links the subsequent headerless QUIC datagrams to the header's source and TLVs. Teamwork makes the dream work. π€
β οΈ fr fr read that last bit twice: forquic://andhttps3://,tlv_metadataon its own is not enough. You needudp_session_trackingtoo.
π METADATA π
When the tlv_metadata option and the metadata plugin are both enabled, the following metadata label is made available:
proxyproto/tlv: the raw PPv2 TLV vector, hex-encoded. Only set when the request's connection carried a PPv2 header with at least one TLV.
π₯ EXAMPLES π₯
π everybody's allowed π
In this configuration, we allow PROXY protocol connections from all IP addresses:
. {
proxyproto
forward . /etc/resolv.conf
}
π allowlist only, ignore the rest π
In this configuration, we only allow PROXY protocol connections from the specified CIDR ranges and ignore proxy protocol headers from other sources:
. {
proxyproto {
allow 192.168.1.1/32 192.168.0.1/32
}
forward . /etc/resolv.conf
}
π allowlist only, reject the rest π
In this configuration, we only allow PROXY protocol headers from the specified CIDR ranges and reject connections without valid PROXY protocol headers from those sources:
. {
proxyproto {
allow 192.168.1.1/32
default reject
}
forward . /etc/resolv.conf
}
π Spectrum UDP session tracking, 28s TTL π
In this configuration, we enable UDP session tracking for Cloudflare Spectrum's PPv2-over-UDP with a 28-second TTL (slightly shorter than Spectrum's 30-second UDP idle timeout) and the default session cap of 10240:
. {
proxyproto {
allow 192.168.1.1/32
udp_session_tracking 28s
}
forward . /etc/resolv.conf
}
π raising the session cap π
In this configuration, the session cap is raised to 20480:
. {
proxyproto {
allow 192.168.1.1/32
udp_session_tracking 28s 20000
}
forward . /etc/resolv.conf
}
π TLV + metadata + log, the full stack π
In this configuration, PPv2 TLVs are exposed to downstream plugins as metadata. The metadata plugin must also be enabled. Here the log plugin records the raw TLV vector:
. {
metadata
proxyproto {
allow 192.168.1.1/32
tlv_metadata
}
forward . /etc/resolv.conf
log . "{remote} {/proxyproto/tlv}"
}
okay that's the whole page, you're officially a proxyproto girlie now πβ¨ this was CoreDNS, October 2026 edition β go forth and forward those original client IPs like the main character you are π ππ¦
π¦ where this page comes from
- opensuse-leap 16.0: coredns-extras 1.15.0-bp160.1.1 Β· Apache-2.0 AND MPL-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms