HTTP/2 Server Push with NGINX

Dalibor Gogic
Dalibor Gogic

Server push allows a server to pre‑emptively push resources to a remote client, anticipating that the client may soon request those resources.

Table of Contents

Server push, which is defined in the HTTP/2 specification, allows a server to pre‑emptively push resources to a remote client, anticipating that the client may soon request those resources. By doing so, you can potentially reduce the number of RTTs (round trip time – the time needed for a request and response) in a page‑load operation by one RTT or more, providing faster response to the user.

Automatically Pushing Resources to Clients

NGINX supports the convention of intercepting Link preload headers, then pushing the resources identified in these headers. To enable preload, include the http2_push_preload directive in the configuration

server {
  listen 443 ssl http2;

  ssl_certificate ssl/certificate.pem;
  ssl_certificate_key ssl/key.pem;

  root /app;

  location = / {
    proxy_pass http://upstream;
    http2_push_preload on;
  }
}

When NGINX is operating as a proxy (for HTTP, FastCGI, or other traffic types), the upstream server can add a Link header like this to its response:

Link: </style.css>; as=style; rel=preload

NGINX intercepts this header and commences a server push of /style.css. The path in the Link header must be absolute – relative paths like ./style.css are not supported. The path can optionally include a query string.

To push multiple objects, you can provide multiple Link headers, or, better still, include all objects in a comma‑separated list.

If you don’t want NGINX to push a preloaded resource, add the nopush parameter to the header:

# Resource is not pushed
Link: </nginx.png>; as=image; rel=preload; nopush

When http2_push_preload is enabled, you can also initiate preload server push by setting the response header in your NGINX configuration:

add_header Link "</style.css>; as=style; rel=preload";

Verifying HTTP/2 Server Push

Verifying with Developer Tools (Google Chrome)

The Initiator column on the Network tab of Chrome’s Developer Tools indicates that several resources were pushed to the client as part of a request for /.

The Initiator column indicates server push was used to send resources

Verifying with a Command-Line Client nghttp

In addition to web browser tools, you can use the nghttp command‑line client from the nghttp2.org project to verify that server push is in effect. You can download the nghttp command‑line client from GitHub, or install the appropriate operating system package where available. For Ubuntu, use the nghttp2-client package.

cmd
nghttp -ans https://daliborgogic.com
output
***** Statistics *****

Request timing:
  responseEnd: the  time  when  last  byte of  response  was  received
               relative to connectEnd
 requestStart: the time  just before  first byte  of request  was sent
               relative  to connectEnd.   If  '*' is  shown, this  was
               pushed by server.
      process: responseEnd - requestStart
         code: HTTP status code
         size: number  of  bytes  received as  response  body  without
               inflation.
          URI: request URI

see http://www.w3.org/TR/resource-timing/#processing-model

sorted by 'complete'

id  responseEnd requestStart  process code size request path
 13    +52.55ms       +175us  52.37ms  200   3K /
  2    +87.54ms *   +51.07ms  36.48ms  200   1K /_nuxt/5b7fe7c15c2c9b5a934b.js
  8    +87.83ms *   +51.16ms  36.67ms  200  923 /_nuxt/1379e1f75a0348fc3050.js
  6   +118.19ms *   +51.14ms  67.04ms  200  16K /_nuxt/72a8068a8157c768035a.js
 15   +156.32ms     +52.58ms 103.74ms  200   1K /favicon.ico?v=1552306459
  4   +161.04ms *   +51.12ms 109.92ms  200  53K /_nuxt/3591e1b426a81d4d3c43.js