Upgrading phoenix framework to serve http2

Http2 is the next version of the http protocol and offers several advantages. It serves over a single connection, reducing the number of roundtrips necessary. With multiplexing it can handle multiple requests at the same time and as a whole is just better.

As the internet slowly moves to support http2, Phoenix does not lag behind. The webserver Phoenix uses, Cowboy, has released version 2 with support for http2 and the updates to Phoenix and Plug have followed in its path. If you’re curious as to how you can upgrade your phoenix/plug application to also serve over http2 please continue.

First, let’s create a minimal phoenix application.

mix phx.new --no-brunch --no-ecto http2_test

We leave out ecto and brunch for simplicity. If you open this in your browser by starting the server with mix phx.server, you’ll see the new app, in the network tab of the chrome developer tools you can see it is served over http.

Open up the mix.exs file and replace the dependencies with this:

  defp deps do
      {:phoenix, git: "https://github.com/phoenixframework/phoenix", branch: "master", override: true},
      {:plug, git: "https://github.com/elixir-plug/plug", branch: "master", override: true},
      {:phoenix_pubsub, "~> 1.0"},
      {:phoenix_html, "~> 2.10"},
      {:phoenix_live_reload, "~> 1.0", only: :dev},
      {:gettext, "~> 0.11"},
      {:cowboy, "~> 2.1", override: true},

The changes are that we use Cowboy 2.1, instead of 1.0 and furthermore we use the latest versions of phoenix and plug from their respective master branches on github.

Run mix deps.get to retrieve the new dependencies.

Next up is preparing the app itself, I will only deal with the dev environment but it should apply in other environments as well.

Open config/dev.exs, there should be a commented line telling you to generate a private key and self signed certificate. We will need to do this as, although http2 does not specifically require it, browser do expect http2 connections to be secured over TLS.

openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" -keyout priv/server.key -out priv/server.pem

Add the two generated files to .gitignore.

Now we will need to adjust the Endpoint configuration to use a secure connection and use a Cowboy 2 handler

Replace the configuration with the following.

config :http2_test, Http2TestWeb.Endpoint,
  debug_errors: true,
  handler: Phoenix.Endpoint.Cowboy2Handler,
  code_reloader: true,
  check_origin: false,
  watchers: [],
  https: [port: 4000, keyfile: "priv/server.key", certfile: "priv/server.pem"]

This tells phoenix to listen on port 4000 with the just generated certificate. Furthermore, the handler tells Phoenix to use Cowboy2.

If you now start the application with mix phx.server and go to https://localhost:4000 the browser will tell that the connection is not secure with for example NET::ERR_CERT_AUTHORITY_INVALID. This is because the certificate is self signed, and not by a certificate authority. You can open the certificate in for example Keychain on Mac OS X and tell your OS to trust the certificate.

If you try again, the browser should accept the certificate and the connections should be using http2. If you look in the network tab of the developer tools it should mention h2 in the protocol column.

See https://github.com/maartenvanvliet/phoenix_http2 for the code of this post