The HTTP/21 RFC (7540)2 is now 4 months old (May, 2015).

Its time for testing. Initially, I was using nginx3. I’ve used it for a while and been happy with it. I’d gone through a migration from wordpress to pelican with it, and even with PHP, it was pleasantly lightweight and responsive. Now that I’m using pelican, I don’t have any fancy requirements for this site, its all static content. No PHP, Ruby, or even CGI. After getting the new version of nginx deployed (1.9.x + HTTP/2 patches), things appeared to be working, until I looked at the logs. The logs claimed everything was being served as HTTP/1.1. After a little debugging, it seems that the logging was incorrect. It was serving HTTP/2, but logging it as 1.1.

sigh

I really wanted the logs to be acurate (if not, what is the purpose of logs? Yes, I know. Development patches for nginx. They’ll get things working before it lands in production. Fine. I want something now). After a little searching, I found h2o4. h2o is a fast and secure HTTP/2 server written in C. h2o can be used as an insecure HTTP server and/or a secure HTTPS (TLS5) server supporting HTTP 1.0, 1.1 and the shiny new HTTP/2 standard. Both h2o and nginx are very lightweight, and very fast, but h2o has an improved parser for html and thus comes out a little ahead. Oh yeah, h2o also reports things properly in the logs.

## Goals of HTTP/2

Negotiation mechanism that allows clients and servers to elect to use HTTP 1.1, 2.0, or potentially other non-HTTP protocols.

Maintain high-level compatibility with HTTP 1.1 (for example with methods, status codes, and URIs, and most header fields)

Decrease latency to improve page load speed in web browsers by considering:

• Data compression of HTTP headers
• Server push technologies
• Fixing the head-of-line blocking problem in HTTP 1

Support common existing use cases of HTTP, such as desktop web browsers, mobile web browsers, web APIs, web servers at various scales, proxy servers, reverse proxy servers, firewalls, and content delivery networks

6

## Differences between HTTP/1.x and HTTP/2

The changes for HTTP/2 don’t require changes for existing web applications to
continue working, however new applications are able to take advantage of the new features for additional speed.

HTTP/2 leaves most of HTTP 1.1’s high level syntax, things like methods, status
codes, header fields, and URIs, unchanged. What was modified is how the data is
framed and transported from the server to the client.

Websites that are efficient work to minimize the number of client requests
required to render an entire page. One example is minifying (reducing the size
of the code files and combining multiple code files into a single file, all without reducing its ability to function) resources such as stylesheets and javascript.

HTTP/2 allows the server to “push” content. The server can respond with
additional data which the client hasn’t requested yet, but will need (for example, the server could push images, or style sheets before the browser has had time to parse the DOM and discover it needs to request them. This also eliminates an additional request cycle from the browser.

Additional performance improvements in HTTP/2 come from the multiplexing of requests and responses which avoids the head-of-line blocking problem in HTTP 1 (this is present, even when HTTP pipelining is used), header compression (HPACK7), and prioritization of requests. Header compression will make a significant different to the mobile arena, where headers can be a significant percentage of the total data transmitted to the client.

## Browser Compatibility

The following browsers are compatible with HTTP/2:

Browser Version
Chrome 40 or newer (Currently only HTTP/2 over TLS is implemented)
Chrome for iOS
Firefox 36 or newer (Currently only HTTP/2 over TLS is implemented)
Internet Explorer 11 or newer (Currently only HTTP/2 over TLS is implemented8. Only on Windows 10)
Microsoft Edge
Opera

## Installing h2o

This is written for FreeBSD, if you choose to use something else, you will need to adjust the process for installation accordingly.

Installing h2o is very simple. You can build it from source (ports), or as a pkg. I’ll include both examples:

Source (I’ve stripped lines with warnings):

[root@www h2o 191 ]$make install clean ===> License MIT accepted by the user ===> h2o-1.4.4_1 depends on file: /usr/local/sbin/pkg - found ===> Fetching all distfiles required by h2o-1.4.4_1 for building ===> Extracting for h2o-1.4.4_1 => SHA256 Checksum OK for h2o-h2o-v1.4.4_GH0.tar.gz. ===> Patching for h2o-1.4.4_1 ===> Applying FreeBSD patches for h2o-1.4.4_1 ===> h2o-1.4.4_1 depends on file: /usr/local/bin/cmake - found ===> Configuring for h2o-1.4.4_1 ===> Performing in-source build /bin/mkdir -p /usr/ports/www/h2o/work/h2o-1.4.4 -- The C compiler identification is Clang 3.4.1 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Found PkgConfig: /usr/local/bin/pkg-config (found version "0.28") -- Looking for include file pthread.h -- Looking for include file pthread.h - found -- Found Threads: TRUE -- Found OpenSSL: /usr/local/lib/libssl.so;/usr/local/lib/libcrypto.so (found version "1.0.2d") -- checking for module 'libuv>=1.0.0' -- package 'libuv>=1.0.0' not found -- Could NOT find LIBUV (missing: LIBUV_LIBRARIES LIBUV_INCLUDE_DIR) -- checking for module 'libwslay' -- package 'libwslay' not found -- Could NOT find WSLAY (missing: WSLAY_LIBRARIES WSLAY_INCLUDE_DIR) -- checking for module 'libmruby' -- package 'libmruby' not found -- Could NOT find MRUBY (missing: MRUBY_LIBRARIES MRUBY_INCLUDE_DIR) -- Configuring done -- Generating done CMake Warning: Manually-specified variables were not used by the project: CMAKE_CXX_COMPILER CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_C_FLAGS_DEBUG CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS -- Build files have been written to: /usr/ports/www/h2o/work/h2o-1.4.4 ===> Building for h2o-1.4.4_1 Scanning dependencies of target h2o [ 2%] Building C object CMakeFiles/h2o.dir/deps/cloexec/cloexec.c.o [ 2%] Building C object CMakeFiles/h2o.dir/deps/libyrmcds/close.c.o [ 2%] Building C object CMakeFiles/h2o.dir/deps/libyrmcds/connect.c.o [ 5%] Building C object CMakeFiles/h2o.dir/deps/libyrmcds/recv.c.o [ 5%] Building C object CMakeFiles/h2o.dir/deps/libyrmcds/send.c.o [ 5%] Building C object CMakeFiles/h2o.dir/deps/libyrmcds/socket.c.o [ 7%] Building C object CMakeFiles/h2o.dir/deps/libyrmcds/strerror.c.o [ 7%] Building C object CMakeFiles/h2o.dir/deps/picohttpparser/picohttpparser.c.o [ 7%] Building C object CMakeFiles/h2o.dir/lib/common/file.c.o [ 10%] Building C object CMakeFiles/h2o.dir/lib/common/hostinfo.c.o [ 10%] Building C object CMakeFiles/h2o.dir/lib/common/http1client.c.o [ 10%] Building C object CMakeFiles/h2o.dir/lib/common/memcached.c.o [ 10%] Building C object CMakeFiles/h2o.dir/lib/common/memory.c.o [ 12%] Building C object CMakeFiles/h2o.dir/lib/common/multithread.c.o [ 12%] Building C object CMakeFiles/h2o.dir/lib/common/serverutil.c.o [ 12%] Building C object CMakeFiles/h2o.dir/lib/common/socket.c.o [ 15%] Building C object CMakeFiles/h2o.dir/lib/common/socketpool.c.o [ 15%] Building C object CMakeFiles/h2o.dir/lib/common/string.c.o [ 15%] Building C object CMakeFiles/h2o.dir/lib/common/time.c.o [ 17%] Building C object CMakeFiles/h2o.dir/lib/common/timeout.c.o [ 17%] Building C object CMakeFiles/h2o.dir/lib/common/url.c.o [ 17%] Building C object CMakeFiles/h2o.dir/lib/core/config.c.o [ 20%] Building C object CMakeFiles/h2o.dir/lib/core/configurator.c.o [ 20%] Building C object CMakeFiles/h2o.dir/lib/core/context.c.o [ 20%] Building C object CMakeFiles/h2o.dir/lib/core/headers.c.o [ 23%] Building C object CMakeFiles/h2o.dir/lib/core/proxy.c.o [ 23%] Building C object CMakeFiles/h2o.dir/lib/core/request.c.o [ 23%] Building C object CMakeFiles/h2o.dir/lib/core/token.c.o [ 25%] Building C object CMakeFiles/h2o.dir/lib/core/util.c.o [ 25%] Building C object CMakeFiles/h2o.dir/lib/handler/access_log.c.o [ 25%] Building C object CMakeFiles/h2o.dir/lib/handler/chunked.c.o [ 28%] Building C object CMakeFiles/h2o.dir/lib/handler/expires.c.o [ 28%] Building C object CMakeFiles/h2o.dir/lib/handler/fastcgi.c.o [ 28%] Building C object CMakeFiles/h2o.dir/lib/handler/file.c.o [ 28%] Building C object CMakeFiles/h2o.dir/lib/handler/headers.c.o [ 30%] Building C object CMakeFiles/h2o.dir/lib/handler/mimemap.c.o [ 30%] Building C object CMakeFiles/h2o.dir/lib/handler/proxy.c.o [ 30%] Building C object CMakeFiles/h2o.dir/lib/handler/redirect.c.o [ 33%] Building C object CMakeFiles/h2o.dir/lib/handler/reproxy.c.o [ 33%] Building C object CMakeFiles/h2o.dir/lib/handler/configurator/access_log.c.o [ 33%] Building C object CMakeFiles/h2o.dir/lib/handler/configurator/expires.c.o [ 35%] Building C object CMakeFiles/h2o.dir/lib/handler/configurator/fastcgi.c.o [ 35%] Building C object CMakeFiles/h2o.dir/lib/handler/configurator/file.c.o [ 35%] Building C object CMakeFiles/h2o.dir/lib/handler/configurator/headers.c.o [ 38%] Building C object CMakeFiles/h2o.dir/lib/handler/configurator/proxy.c.o [ 38%] Building C object CMakeFiles/h2o.dir/lib/handler/configurator/redirect.c.o [ 38%] Building C object CMakeFiles/h2o.dir/lib/handler/configurator/reproxy.c.o [ 41%] Building C object CMakeFiles/h2o.dir/lib/http1.c.o [ 41%] Building C object CMakeFiles/h2o.dir/lib/http2/connection.c.o [ 41%] Building C object CMakeFiles/h2o.dir/lib/http2/frame.c.o [ 43%] Building C object CMakeFiles/h2o.dir/lib/http2/hpack.c.o [ 43%] Building C object CMakeFiles/h2o.dir/lib/http2/scheduler.c.o [ 43%] Building C object CMakeFiles/h2o.dir/lib/http2/stream.c.o [ 46%] Building C object CMakeFiles/h2o.dir/deps/yaml/src/api.c.o [ 46%] Building C object CMakeFiles/h2o.dir/deps/yaml/src/dumper.c.o [ 46%] Building C object CMakeFiles/h2o.dir/deps/yaml/src/emitter.c.o [ 46%] Building C object CMakeFiles/h2o.dir/deps/yaml/src/loader.c.o [ 48%] Building C object CMakeFiles/h2o.dir/deps/yaml/src/parser.c.o [ 48%] Building C object CMakeFiles/h2o.dir/deps/yaml/src/reader.c.o [ 48%] Building C object CMakeFiles/h2o.dir/deps/yaml/src/scanner.c.o [ 51%] Building C object CMakeFiles/h2o.dir/deps/yaml/src/writer.c.o [ 51%] Building C object CMakeFiles/h2o.dir/src/ssl.c.o [ 51%] Building C object CMakeFiles/h2o.dir/src/main.c.o [ 53%] Linking C executable h2o [ 53%] Built target h2o Scanning dependencies of target libh2o-evloop [ 53%] Building C object CMakeFiles/libh2o-evloop.dir/deps/cloexec/cloexec.c.o [ 53%] Building C object CMakeFiles/libh2o-evloop.dir/deps/libyrmcds/close.c.o [ 56%] Building C object CMakeFiles/libh2o-evloop.dir/deps/libyrmcds/connect.c.o [ 56%] Building C object CMakeFiles/libh2o-evloop.dir/deps/libyrmcds/recv.c.o [ 56%] Building C object CMakeFiles/libh2o-evloop.dir/deps/libyrmcds/send.c.o [ 58%] Building C object CMakeFiles/libh2o-evloop.dir/deps/libyrmcds/socket.c.o [ 58%] Building C object CMakeFiles/libh2o-evloop.dir/deps/libyrmcds/strerror.c.o [ 58%] Building C object CMakeFiles/libh2o-evloop.dir/deps/picohttpparser/picohttpparser.c.o [ 61%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/file.c.o [ 61%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/hostinfo.c.o [ 61%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/http1client.c.o [ 64%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/memcached.c.o [ 64%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/memory.c.o [ 64%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/multithread.c.o [ 66%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/serverutil.c.o [ 66%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/socket.c.o [ 66%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/socketpool.c.o [ 69%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/string.c.o [ 69%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/time.c.o [ 69%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/timeout.c.o [ 69%] Building C object CMakeFiles/libh2o-evloop.dir/lib/common/url.c.o [ 71%] Building C object CMakeFiles/libh2o-evloop.dir/lib/core/config.c.o [ 71%] Building C object CMakeFiles/libh2o-evloop.dir/lib/core/configurator.c.o [ 71%] Building C object CMakeFiles/libh2o-evloop.dir/lib/core/context.c.o [ 74%] Building C object CMakeFiles/libh2o-evloop.dir/lib/core/headers.c.o [ 74%] Building C object CMakeFiles/libh2o-evloop.dir/lib/core/proxy.c.o [ 74%] Building C object CMakeFiles/libh2o-evloop.dir/lib/core/request.c.o [ 76%] Building C object CMakeFiles/libh2o-evloop.dir/lib/core/token.c.o [ 76%] Building C object CMakeFiles/libh2o-evloop.dir/lib/core/util.c.o [ 76%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/access_log.c.o [ 79%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/chunked.c.o [ 79%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/expires.c.o [ 79%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/fastcgi.c.o [ 82%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/file.c.o [ 82%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/headers.c.o [ 82%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/mimemap.c.o [ 84%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/proxy.c.o [ 84%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/redirect.c.o [ 84%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/reproxy.c.o [ 87%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/configurator/access_log.c.o [ 87%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/configurator/expires.c.o [ 87%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/configurator/fastcgi.c.o [ 87%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/configurator/file.c.o [ 89%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/configurator/headers.c.o [ 89%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/configurator/proxy.c.o [ 89%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/configurator/redirect.c.o [ 92%] Building C object CMakeFiles/libh2o-evloop.dir/lib/handler/configurator/reproxy.c.o [ 92%] Building C object CMakeFiles/libh2o-evloop.dir/lib/http1.c.o [ 92%] Building C object CMakeFiles/libh2o-evloop.dir/lib/http2/connection.c.o [ 94%] Building C object CMakeFiles/libh2o-evloop.dir/lib/http2/frame.c.o [ 94%] Building C object CMakeFiles/libh2o-evloop.dir/lib/http2/hpack.c.o [ 94%] Building C object CMakeFiles/libh2o-evloop.dir/lib/http2/scheduler.c.o [ 97%] Building C object CMakeFiles/libh2o-evloop.dir/lib/http2/stream.c.o [ 97%] Linking C static library libh2o-evloop.a [ 97%] Built target libh2o-evloop Scanning dependencies of target setuidgid [ 97%] Building C object CMakeFiles/setuidgid.dir/src/setuidgid.c.o [100%] Linking C executable setuidgid [100%] Built target setuidgid ===> Staging for h2o-1.4.4_1 ===> Generating temporary packing list [ 53%] Built target h2o [ 97%] Built target libh2o-evloop [100%] Built target setuidgid Installing the project stripped... -- Install configuration: "Release" -- Installing: /usr/ports/www/h2o/work/stage/usr/local/bin/h2o -- Set runtime path of "/usr/ports/www/h2o/work/stage/usr/local/bin/h2o" to "/usr/local/lib" -- Installing: /usr/ports/www/h2o/work/stage/usr/local/share/h2o/setuidgid -- Up-to-date: /usr/ports/www/h2o/work/stage/usr/local/include -- Installing: /usr/ports/www/h2o/work/stage/usr/local/share/h2o/annotate-backtrace-symbols -- Installing: /usr/ports/www/h2o/work/stage/usr/local/share/h2o/fetch-ocsp-response -- Installing: /usr/ports/www/h2o/work/stage/usr/local/share/h2o/kill-on-close -- Installing: /usr/ports/www/h2o/work/stage/usr/local/share/h2o/start_server /bin/mkdir -p /usr/ports/www/h2o/work/stage/usr/local/share/doc/h2o /usr/ports/www/h2o/work/stage/usr/local/etc/h2o /usr/ports/www/h2o/work/stage/var/log/h2o/ install -m 0644 /usr/ports/www/h2o/work/h2o-1.4.4/README.md /usr/ports/www/h2o/work/stage/usr/local/share/doc/h2o install -m 0644 /usr/ports/www/h2o/files/h2o.conf.sample /usr/ports/www/h2o/work/stage/usr/local/etc/h2o/h2o.conf.sample ====> Compressing man pages (compress-man) ===> Staging rc.d startup script(s) ===> Installing for h2o-1.4.4_1 ===> Registering installation for h2o-1.4.4_1 Installing h2o-1.4.4_1... ===> SECURITY REPORT: This port has installed the following files which may act as network servers and may therefore pose a remote security risk to the system. /usr/local/bin/h2o This port has installed the following startup scripts which may cause these network services to be started at boot time. /usr/local/etc/rc.d/h2o If there are vulnerabilities in these programs there may be a security risk to the system. FreeBSD makes no guarantee about the security of ports included in the Ports Collection. Please type 'make deinstall' to deinstall the port if this is a concern. For more information, and contact details about the security status of this software, see the following webpage: http://github.com/h2o/h2o ===> Cleaning for h2o-1.4.4_1 Time spent in user mode (CPU seconds) : 24.929s Time spent in kernel mode (CPU seconds) : 8.296s Total time : 0:33.89s CPU utilisation (percentage) : 97.9% Times the process was swapped : 0 Times of major page faults : 56 Times of minor page faults : 502856 [root@www h2o 192 ]$


pkg:

pkg install www/h2o


Next, we need a bit in the /etc/rc.conf to allow us to start the h2o service:

h2o_enable="YES"
h2o_config="/usr/local/etc/h2o/h2o.conf"


## Configuring h2o

I’m going to show the config file for my test/development machine. Its similar to production, and has been adapted from Calomel9. There are other example config files available here.

h2o has a straight forward config file. Many of the directives (in key/value form) fall under the individual host section.

# Original h2o config file from https://calomel.org/h2o.html

# global configuration
access-log: /var/log/h2o/h2o_access.log
error-log: /var/log/h2o/h2o_error.log
expires: off
file.dirlisting: off
file.send-gzip: on
limit-request-body: 1024
pid-file: /var/run/h2o.pid

# mime types, additional types and redefine of *.html
application/atom+xml: .xml
application/zip: .zip
"text/html; charset=utf-8": .html

# ssl resume, cache and ticket methods supported, stored in RAM
ssl-session-resumption:
mode: all

# listening ports and protocols
hosts:
"test.cryptomonkeys.com:8000":
listen:
host: 127.0.0.1
port: 8000
paths:
/:
redirect:
status: 301
url: https://test.cryptomonkeys.com:8443/

"test.cryptomonkeys.com:8443":
listen:
host: 127.0.0.1
port: 8443
ssl:
certificate-file: /usr/local/etc/sslmate/test.cryptomonkeys.com.crt
key-file: /usr/local/etc/sslmate/test.cryptomonkeys.com.key
cipher-preference: server
cipher-suite: ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA
minimum-version: TLSv1.2
paths:
/:
file.dir: /usr/local/www/cryptomonkeys.com
/stats:
file.dir: /usr/local/www/cryptomonkeys.com_stats

### EOF ###


Once the bits are placed in the config file (/usr/local/etc/h2o/h2o.conf), we can start the service with:

sudo service h2o start


You should now be able to point a browser at your h2o server and load a page. If you are successful, you should see some log bits similar to what is in the next section.

## h2o Logs

The location of the logs is defined in the h2o.conf file. Mine are in /var/log/h2o, and I give each domain its own log file. For example: /var/log/h2o/cryptomonkeys.com.log

There are a couple ways you can check from the browser whether you are communicating over HTTP/2. If you have an HTTP/2 capable browser (I’ve been using Firefox, because it has a handy plugin10 that will show me whether I’m connecting with HTTP/2 in the URL bar. It also shows me SPDY11 connections, but I’m less interested in that since SPDY is being phased out for HTTP/2).

You can also use a plugin like Firebug12 to inspect the communication between the browser and the server.

Lastly, when looking at your server logs (probably hidden away under /var/log/h2o/*.log) you should see a note that includes the magic bits HTTP/2.

127.0.0.1 - - [08/Sep/2015:23:46:18 +0000] "GET / HTTP/2" 200 3169 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:41.0) Gecko/20100101 Firefox/41.0"


## Troubleshooting and Debugging

If you need to do debugging of HTTP/2, and tools like firebug aren’t sufficient, you can take a look at nghttp213. They have implemented a client, server, and proxy that all speak HTTP/2. Also of note, Curl14 can be compiled with HTTP/2 support.

Footnotes and References