Transport security for HTTP/2 protocol with Nginx

With Google sunsetting the SPDY protocol, and broad support for HTTP/2 shipping with most modern browsers, I began investigating moving our SPDY support over to HTTP/2.

Nginx recently released official support for HTTP/2 with the mainline repository version 1.9.5. While upgrading to the new release and enabling the http2 module we ran into an issue with transport security, as reported by Google Chrome:

# google chrome client error
ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY  
# or more generically 
INADEQUATE_SECURITY (0xc)  

According to the HTTP/2 specification, over TLS 1.2 HTTP/2 SHOULD NOT use any of the cipher suites that are listed in the cipher suite black list, found here.

The following settings (with changes to the ssl_ciphers directive) addressed the transport security issue reported by the browser.

server {

    listen 9443 ssl http2 proxy_protocol;
    port_in_redirect off;
    real_ip_header proxy_protocol;
    set_real_ip_from 10.0.0.0/16;
    server_name acme.com www.acme.com;

    ssl on;
    ssl_certificate /path/to/full-chain.pem;
    ssl_certificate_key /path/to/pivate-key.pem;

    # disable unsupported ciphers
    ssl_ciphers AESGCM:HIGH:!aNULL:!MD5;

    # ssl optimizations
    ssl_session_cache shared:SSL:30m;
    ssl_session_timeout 30m;
    add_header Strict-Transport-Security "max-age=31536000";

}

In the example, we are also opting into the HTTP Strict Transport Security (HSTS) enhancement to prevent client communications from being sent over standard HTTP. The proxy_protocol configuration in use by the load balancer (ELB) continues to work as expected without any changes. You can read more about using proxy protocol with Nginx here.