HTTP/2 support is now live!
Since my last post, I have been investigating alternatives to enabling HTTP/2 support on randomCoder. My first attempts involved using HAProxy as the public front-end and SSL termination point for this site (and others I host). However, since HAProxy does not (yet) support HTTP/2 natively, proxying was limited to TCP mode for HTTPS connections.
My plan was to use SNI to redirect to one of several backends depending on the requested site. This seemed to work; however, there is a (IMO) unfortunate behavior of HTTP/2 which allows browsers to re-use secure connections to a website for multiple hosted domains, provided the SSL certificate returned is valid for all of them. This caused requests for domain A to sometimes be routed to domain B's backend, resulting in incorrect content being generated. As I currently have a multi-domain certificate and hosting all of the sites using the same backend is near impossible, this seemed like a show-stopper.
Fast forward to last week, and Let's Encrypt is now out of beta. I have been following this project for several months now, and had thought about replacing my single multi-domain SSL cert with one per domain, thereby forcing browsers to make a separate connection to HAProxy for each one. Unfortunately, another issue cropped up - Let's Encrypt certificates are not trusted by any shipping version of Java, making building API sites to be consumed by Java clients difficult.
Enter Nghttpx , an HTTP/2 native proxy (part of the Nghttp2 project). Nghttpx can be configured to listen on both secure and non-secure ports, speaking both HTTP/1.1 and HTTP/2, and proxy to multiple backends. This is a solution I had evaluated earlier, but at the time (version 1.7.x), backend protocol (h1 or h2) was configured globally, so all sites had to be one or the other. Version 1.9 is now out, and supports configuring these options per-backend. Finally, I have a solution to enable HTTP/2 publicly.
HAProxy is now out of the mix, and all front-end connections hit Nghttpx first. The backends all have either Nginx 1.10.x or Jetty 9.x backends, so we can connect to them via h2c (HTTP/2 plaintext). All of this is seamless to the user, and allows us to do things like enable HTTP/2 server push via Link: headers (as well as gives me a platform for playing with HTTP/2 related technologies such as gRPC .
I do have one hitch (so far): I am using Nghttpx's mruby support to do things like force redirect to SSL and canonicalize domain names at the proxy level. Everything was working well last night, but this morning every page load resulted in an exception while executing the mruby code (TypeError: expected String). Strangely, restarting Nghttpx fixed it with no changes to the script. If anyone knows why this might be occurring, please let me know...
Update: I have (hopefully) resolved the Nghttpx errors by disabling mruby... Since the scripting was only being used for HTTPS and hostname redirects, I have modified the backends to do this work directly.