4

I am trying to update our online shop to use HTTP/2 with Server Push capabilities but I can't find a solution for a webserver like Nginx(for proxying and some other stuff) with upstream HTTP/2. We are using Node.js with the node HTTP module at the moment, but would like to switch to the node spdy module. The spdy module supports HTTP/2 with Server Push. I have tried H2O as an alternative to Nginx, but it doesn't support HTTP/2 upstream either.

I am kind of lost at the moment and need help.

bschlueter
  • 3,817
  • 1
  • 30
  • 48

3 Answers3

2

Nginx has only just added support for HTTP/2 Push so unless you are rubbing the latest mainline version you will not be able to do this. Also because it is so new there are still some issues with it. Nginx do not support http2 over backend connections (and have stated they won’t support this). So you cannot directly push from a downstream system all the way up like you suggest.

There is some question as to whether that is the best way to push anyway. A downstream system may push to the upstream proxy server even if the client does not support push for example - which is a wasted push.

So the better way is to push from the proxy and have the downstream system tell the upstream system (via link headers) to do that push. This has several advantages in reducing complexity, allowing the downstream system to push assets it may not control (e.g. static assets like stylesheets, JavaScript, images... etc.), a central store of already pushed assets (cache digests) and also not requiring HTTP/2 to be supported all the way through (link headers can be sent over HTTP/1.1 as easily as HTTP/2).

The main downside to pushing from the upstream proxy via link headers is that you have to wait for the requested resource to be ready as the link headers are read from the response. If the request resource takes some time to generate then it may be more beneficial to start pushing other resources while it’s being processed. This is solved by a new 103 Early Hints HTTP Status code where you can reply back earlier before sending the main 200-status code later. This early message can have link headers which can be read by the upstream proxy and be used to push the resource. I am not sure if Nginx implementation will support this.

Incidentally Apache has supported Push for a while now and has a much more mature implementation. It supports it via direct Apache config or via link headers (including via 103 responses which by default are configured not to be sent on in case on compatibility issues). It even supports proxying to backends via HTTP/2 though does not support direct push over back end connections for reasons described above. Some other less well known servers (e.g. H2O) also support HTTP/2 better than Nginx.

Finally if using a CDN then they may support HTTP/2 Push (often via link headers) without you having to upgrade any of your backend infrastructure. In fact Cloudflare is an Nginx based CDN which has had HTTP/2 Push for a while and I fact it’s two Cloudflare engineers which have back ported their implementation to the base Nginx code.

Community
  • 1
  • 1
Barry Pollard
  • 40,655
  • 7
  • 76
  • 92
1

After NGINX 1.13.9 (just pushed to mainline today) you're able to have HTTP/2 server push out of the box by compiling it with the ngx_http_v2_module.

If you're interested in the recent addition, this is the commit that added most of the functionality: hg.nginx.org: HTTP/2: server push.

Its use is relatively straightforward: add the http2_push_preload directive to the server that is proxying Node and then from node make use of the Link header (as described in the W3 spec - https://www.w3.org/TR/preload/#server-push-http-2) and then NGINX will do the job of sending the h2 frame that indicates a server push.

For instance, assume that you have a / endpoint that serves a regular index.html but also pushes image.svg to the client.

In NGINX you could configure an upstream server and then in the server configuration enable http2_push_preload on the server configuration:

# Add an upstream server to proxy requests to.
upstream sample-http1 {
  server localhost:8080;
}


server {
  # Listen on port 8443 with http2 support on.
  listen                  8443 http2;


  # Enable TLS such that we can have proper HTTP2
  # support using browsers.
  ssl on;
  ssl_certificate         certs/cert_example.com.pem;
  ssl_certificate_key     certs/key_example.com.pem;


  # Enable support for using `Link` headers to indicate
  # origin server push.
  http2_push_preload on;


  # Act as a reverse proxy for requests going to /proxy/*.
  #
  # Because we don't want to rewrite our endpoints in the
  # Node app, rewrite the path such that `/proxy/lol` ends up
  # as `/lol`.
  location / {
    proxy_pass      http://sample-http1;
  }
}

Then in the NodeJS app, you'd serve / as you'd normally do but add an extra Link header to the response:

response.setHeader('Link', '</image.svg>; rel=preload; as=image');

ps.: yeah, you'd keep those angle brackets; I do not mean that you should replace them.

By the way, the example I just gave (with some debugging tips) is written up in complete here: https://ops.tips/blog/nginx-http2-server-push/ .

Ciro Costa
  • 2,455
  • 22
  • 25
  • NGINX Compilation: This module is not built by default, it should be enabled with the `--with-http_v2_module` configuration parameter. – buycanna.io Jul 05 '19 at 06:38
0

You can compile/recompile nginx from source and include the --with-http_v2_module configuration parameter to enable HTTP2 push capabilities.

buycanna.io
  • 1,166
  • 16
  • 18