Behind a reverse proxy¶
The most common production topology runs h2corn behind a reverse proxy that handles browser-facing TLS:
The proxy takes care of ALPN negotiation, TLS termination, and public-edge hardening. h2corn runs the application side of the connection on h2c — cleartext HTTP/2 over TCP or a Unix socket inside the trust boundary.
When a separate proxy isn't a good fit for your environment, h2corn can terminate TLS itself instead — see Direct TLS.
Why h2c upstream?
Keeping the proxy → app hop on HTTP/2 avoids the HTTP/1.1 downgrade surface that request smuggling and HTTP/2 downgrading research repeatedly targets. If your proxy can speak h2c upstream, prefer that over an HTTP/1.1 fallback.
Proxy headers and PROXY protocol¶
h2corn accepts two kinds of trust hop metadata, both opt-in and gated by --forwarded-allow-ips:
--proxy-headerstrusts standardForwardedandX-Forwarded-*headers from peers in--forwarded-allow-ips. These carry request metadata such as scheme, host, and the original client address.--proxy-protocol v1|v2parses HAProxy's PROXY protocol on inbound connections. It carries transport-level peer information on the connection itself, useful when you want the original source IP for connection-level metrics or per-IP limits.
In most deployments, proxy headers alone are enough. Add PROXY protocol when the upstream is explicitly configured to send it.
Caddy¶
Caddy speaks h2c upstream natively with its reverse_proxy directive.
Pair it with:
h2corn hello:app \
--bind 127.0.0.1:8000 \
--proxy-headers \
--forwarded-allow-ips 127.0.0.1,::1,unix \
--no-http1
HAProxy¶
HAProxy speaks HTTP/2 upstream with proto h2 and can layer PROXY protocol v2 on the same connection — see the HAProxy HTTP guide for the full directive set.
global
log stdout format raw daemon
defaults
mode http
timeout connect 5s
timeout client 30s
timeout server 30s
frontend public_https
bind :443 ssl crt /etc/haproxy/certs/example.pem alpn h2,http/1.1
default_backend h2corn_backend
backend h2corn_backend
server app1 127.0.0.1:8000 check proto h2 send-proxy-v2
Pair it with:
h2corn hello:app \
--bind 127.0.0.1:8000 \
--proxy-protocol v2 \
--proxy-headers \
--forwarded-allow-ips 127.0.0.1,::1,unix \
--no-http1
Other proxies¶
h2corn works with any reverse proxy that speaks h2c upstream — Caddy and HAProxy are simply the two that do it cleanly today. If you're evaluating an alternative that cannot, pick one that can rather than falling back to HTTP/1.1 between the proxy and the application.