Learn Enable HTTP/2 in Nginx on Ubuntu 16.04

November 2, 2019

Table of Contents

HTTP/2 is the new version of now obsolete HTTP/1.1 protocol which was standardized way back in 1999. A lot has changed on the web since then. Our applications are more complex than they were back than, so to cope with that, change in the underlying transport protocol was necessary. The most important thing about HTTP/2 is that it will make your web page faster for the end users.

In brief HTTP/2 adds 5 key features:

  • Single, persistent connection
  • Multiplexing
  • Header compression
  • Resource prioritization
  • Secures transport layer (only valid for browsers)

Explaining all these features is out of the scope of this tutorial but if you want to dig deeper into this topic I can recommend excerpt from High Performance Browser Networking book – HTTP/2 excerpt.

In this guide we are going to install latest stable version of Nginx on Ubuntu 16.04 (Xenial), generate self-signed SSL Certificate, enable HTTP/2 protocol in Nginx and install text based browser elinks to act as HTTP client.

Install Nginx

To install latest stable version of Nginx we need to issue quite a few commands:

  1. We need to download Nginx public PGP key used for signing packages and repositories and add it into the keyring used by the package manager to verify the authenticity of packages downloaded from the repository.

    wget https://nginx.org/keys/nginx_signing.key && apt-key add nginx_signing.key
    
  2. Delete the PGP key from the file system:

    rm nginx_signing.key
    
  3. Add new repository

    printf "deb http://nginx.org/packages/ubuntu/ xenial nginx ndeb-src http://nginx.org/packages/ubuntu/ xenial nginx n" >> /etc/apt/sources.list.d/nginx.list
    
  4. Update your package list and install Nginx:

    apt update && apt install nginx -y
    
  5. To verify Nginx version we can use the following:

    nginx -v 
    # nginx version: nginx/1.10.1
    

    If all goes well you should see pattern like 1.10.x in the output when running nginx -v command.

Self-signed certificate and HTTP/2

Although HTTP/2 spec doesn’t force browsers to implement HTTP/2 over TLS, all major browsers decided to only implement HTTP/2 over TLS, but not any TLS version, only TLS 1.2 or higher.

We are going to create self-signed certs for fictional example.com domain, for production you need valid domain and use trusted CA.

  1. Generate private key:

    openssl genrsa -aes128 -out example.com.key 2048
    

    After running this command you will need to enter passphrase 2 times. Because passphrases are annoying we are going to remove it.

  2. Remove passphrase from private key:

    openssl rsa -in example.com.key -out example.com.key
    
  3. Generate Certificate Signing Request (CSR):

    openssl req -new -sha256 -key example.com.key -out cert-request.csr 
    

    We are creating single-domain certificate so we need to set common-name field equal to example.com domain

  4. Create certificate:

    openssl x509 -req -days 365 -in cert-request.csr -signkey example.com.key -out example.com.crt
    
  5. Sort out certificate and private key:

    mkdir -p /etc/ssl/testing/private && mkdir /etc/ssl/testing/certs
    mv example.com.key /etc/ssl/testing/private && mv example.com.crt /etc/ssl/testing/certs
    
  6. Make nginx virtual host directories

    mkdir /etc/nginx/sites-available && mkdir /etc/nginx/sites-enabled
    
  7. Then run nano /etc/nginx/nginx.conf and find a directive include /etc/nginx/conf.d/*.conf;. Below this directive add include /etc/nginx/sites-enabled/*; Save (CTRL+O) and then quit (CTRL+X).

    ##
    # Virtual Hosts
    ##
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
    
  8. Create a file called example.com.conf inside /etc/nginx/sites-available directory with this command nano /etc/nginx/sites-available/example.com.conf and copy/paste the following code:

    server {
        listen 80;
        listen [::]:80;
        server_name example.com;
        return 301 https://$host$request_uri;
    }
    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name example.com;
        root /var/www/html;
        index index.nginx-debian.html;
        ssl_certificate /etc/ssl/testing/certs/example.com.crt;
        ssl_certificate_key /etc/ssl/testing/private/example.com.key;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
        ssl_prefer_server_ciphers on;
    }
    

    Congratulations, you now have HTTP/2 enabled web server. Adding http2 parameter to the listen directive inside HTTPS virtual host will give you HTTP/2 support.

  9. Create a symbolic link for /etc/nginx/sites-available/example.com.conf with this command:

    ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled
    
  10. Test configuration syntax

    nginx -t
    
  11. Restart Nginx to apply your changes:

    systemctl restart nginx
    
  12. Add example.com domain to /etc/hosts file

    echo '127.0.0.1    example.com' >> /etc/hosts
    

To test your virtual host we need text-based browser – elinks.

  1. To install elinks use the following command:

    apt install elinks
    
  2. To test your example.com virtual host run:

    elinks https://example.com
    
  3. To exit out of the elinks browser press q on your keyboard and then Enter.

Test HTTP/2

To see what protocols server advertises the easiest way is to use openssl toolkit.

    openssl s_client -connect example.com:443 -nextprotoneg ''

In the output of this command you should see something like this:

    CONNECTED(00000003)
    Protocols advertised by server: h2, http/1.1      

To see HTTP/2 in action you can use browser developer tools. HTTP/2 protocol is indicated either with h2 or HTTP/2.0 identifiers. Open network panel in dev-tools and refresh your page.

Conclusion

Now you should be aware of how “easy” is to enable HTTP/2 in Nginx configuration, but that is not the whole part of the overall picture. First you should think about enabling TLS/SSL on your server with strong cipher suites and make sure you are not using blacklisted ciphers. Only after enabling strong TLS/SSL on your server, you can start thinking about enabling HTTP/2.

Need help?

Do you need help setting up this on your own service?
Please contact us and we’ll provide you the best possible quote!