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:
-
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
-
Delete the PGP key from the file system:
rm nginx_signing.key
-
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
-
Update your package list and install Nginx:
apt update && apt install nginx -y
-
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 runningnginx -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.
-
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.
-
Remove passphrase from private key:
openssl rsa -in example.com.key -out example.com.key
-
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 -
Create certificate:
openssl x509 -req -days 365 -in cert-request.csr -signkey example.com.key -out example.com.crt
-
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
-
Make nginx virtual host directories
mkdir /etc/nginx/sites-available && mkdir /etc/nginx/sites-enabled
-
Then run
nano /etc/nginx/nginx.conf
and find a directiveinclude /etc/nginx/conf.d/*.conf;
. Below this directive addinclude /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/*;
-
Create a file called
example.com.conf
inside/etc/nginx/sites-available
directory with this commandnano /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 thelisten
directive inside HTTPS virtual host will give you HTTP/2 support. -
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
-
Test configuration syntax
nginx -t
-
Restart Nginx to apply your changes:
systemctl restart nginx
-
Add
example.com
domain to/etc/hosts
fileecho '127.0.0.1 example.com' >> /etc/hosts
Install elinks
To test your virtual host we need text-based browser – elinks.
-
To install elinks use the following command:
apt install elinks
-
To test your
example.com
virtual host run:elinks https://example.com
-
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.
Want to contribute?
You could earn up to $300 by adding new articles
Suggest an update
Request an article