COREDNS-PROXYPROTO(7)

πŸ“¦
version 1.15.0 Β· 2 versions
, in opensuse-leap 16.0

πŸ’… 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 allow is unspecified, PROXY protocol headers are accepted from all IP addresses. Everybody's welcome, no bouncer. πŸ™ˆ
  • The default option controls how connections from sources not listed in allow are handled. If default is unspecified, it defaults to ignore.
  • 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_sessions argument 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 metadata plugin is enabled, the raw TLV vector is published under the label proxyproto/tlv as a hex-encoded string.
  • Consumers decode the hex and split it with proxyproto.SplitTLVs from github.com/pires/go-proxyproto to 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), and https3:// (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: for quic:// and https3://, tlv_metadata on its own is not enough. You need udp_session_tracking too.

🌈 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