// the find
mholt/caddy-l4
Layer 4 (TCP/UDP) app for Caddy
A layer-4 (TCP/UDP) plugin for Caddy that lets you route raw connections based on sniffed protocol signatures — SNI, HTTP Host headers, SSH/RDP/SOCKS handshakes, and more — before deciding where bytes go. Useful for anyone running Caddy as an edge proxy who needs to multiplex several protocols on one port (e.g. SSH and HTTPS both on 443) without a separate TCP router like HAProxy or nginx stream.
The matcher list is genuinely impressive for a side project — SSH, RDP, WireGuard, OpenVPN, SOCKS4/5, Postgres wire protocol, QUIC, DNS, and TLS ClientHello/ALPN parsing, all done by peeking at the start of a stream without fully terminating it. That's fiddly protocol-level work most people would never bother writing themselves. Nearly every module has a matching _test.go, plus a caddyfile_adapt integration suite that checks the Caddyfile-to-JSON conversion for each handler/matcher, so regressions in config parsing get caught. It also mirrors Caddy's own http app structure (servers/routes/matchers/handlers), so if you already know Caddy config, there's nothing new to learn conceptually.
The README leads with 'expect breaking changes' — this isn't a 1.0 and mholt isn't promising API stability, so pin a commit if you put it in front of real traffic. It's explicitly not an official Caddy org repo despite being written by Caddy's own author, which is a strange middle ground: more credible than a random fork, but no official support path if it's abandoned. There's no discussion anywhere of the performance cost of protocol sniffing — each matcher buffers some amount of the stream before deciding, and for high-connection-rate services that buffering/allocation cost per connection matters and isn't benchmarked or documented. Observability is also thin: l4proxy has a metrics.go, but there's no connection-level logging or metrics story for the matchers themselves, so debugging why a connection got routed (or dropped) the way it did means reading code, not logs.