Clarification on h2c


I’m checking my understanding here a bit, hopefully someone can help, provided I’m able to write something coherent. (to be determined…)

It looks like to get h2c working, Caddy (and golang…or…all web servers/provides?) needs to assume the backend is http2 only and accepts non-TLS connections (a.k.a. prior knowledge). Does that sound right?

Put another way: Caddy (and maybe all reverse proxies?) can’t expect a backend to accept both h2c and HTTP/1.1 connections?

It seems to be this way to me both because:

  1. Many web servers (backends in this example) don’t - can’t? - implement both (h2c HTTP/2 & HTTP/1.1) on the same listening socket (Nginx is what I’m testing with as a backend)
  2. Golang’s current required Transport hack for h2c where DialTLS is over-ridden to use DialTCP makes it so a given backend will always be connected to over a non-TLS connection. We’d have to have the reverse proxy listen on 2 network sockets so a client could choose which to use for TLS vs h2c connections.

If this question makes you think “I’d have to write a novel to explain all of this”, I’m perfectly happy to just hear that feedback instead of getting the novel :stuck_out_tongue:

1 Like

That’s basically right.

TLS has a feature called ALPN whereby the server and client negotiate which protocol to use after the TLS connection is established. Without TLS, there isn’t a way to indicate which protocol to use. You just have to start using it (or do something complex and less efficient by buffering+peeking bytes and then multiplexing protocols; the caddy-l4 plugin can do this, but it’s far from the norm). So without TLS the typical way to decide the protocol is to connect to the port that your protocol is served on. Then there’s no question.

1 Like


I don’t think it’s true that Caddy can’t serve both HTTP (non-TLS) 1.1 and H2C at the same time. You can configure protocols h1 h2c for your :80 server and it should work fine, I think.

Do you have evidence that it doesn’t?

1 Like

I’ll have to test to clear up the answer to that!

My backend was Nginx which might not specifically be able to do both. I’ll give it a shot with Caddy is the backend.

To clarify: Point 2 above was about the Transport used (I think in the RoundTripper) within the ReverseProxy when it’s taking an incoming request and opening a connection to the backend to proxy to it. The reverse proxy would have to know when it’s h2c vs whatever else, perhaps by making the Transport behave dynamically based on the request.

1 Like

Right, Caddy’s reverse_proxy won’t support both H1 and H2C simultaneously, that’s true. But it shouldn’t matter, because incoming H1 connections can be “upgraded” to H2C by the proxy (if configured to connect over H2C). That should work just fine.

1 Like

This topic was automatically closed after 60 days. New replies are no longer allowed.