• Get In Touch
June 27, 2016

How to Setup Nginx with HTTP2 Support on Ubuntu 16.04

Want your very own server? Get our 1GB memory, Xeon V4, 25GB SSD VPS for £10.00 / month.
Get a Cloud Server

Introduction

Nginx (pronounced “engine x”) is a web server. It can act as a reverse proxy server for HTTP, HTTPS, SMTP, POP3, and IMAP protocols, as well as a load balancer and an HTTP cache. Nginx was created by Igor Sysoev in 2002 which runs on UNIX, Linux, BSD variants, OS X, Solaris, AIX, HP-UX, and Windows. NGINX, Inc. was founded in July 2011 by Sysoev to provide commercial products and support for the software.

NGINX is high-performance HTTP server and reverse proxy, as well as an IMAP/POP3 proxy server. NGINX is known for its high performance, stability, rich feature set, simple configuration, and low resource consumption.

NGINX is one of a handful of servers written to address the C10K problem. Unlike traditional servers, NGINX doesn’t rely on threads to handle requests. Instead it uses a much more scalable event-driven (asynchronous) architecture. This architecture uses small, but more importantly, predictable amounts of memory under load. Even if you don’t expect to handle thousands of simultaneous requests, you can still benefit from NGINX’s high-performance and small memory footprint. NGINX scales in all directions: from the smallest Virtual Private Server (VPS) all the way up to large clusters of servers. NGINX is the world’s most popular open source web server and load balancer for high-traffic sites, powering over 140 million properties.

HTTP/2 is a replacement for how HTTP is expressed “on the wire.” It is not a ground-up rewrite of the protocol; HTTP methods, status codes and semantics are the same, and it should be possible to use the same APIs as HTTP/1.x (possibly with some small additions) to represent the protocol. The focus of the protocol is on performance; specifically, end-user perceived latency, network and server resource usage. One major goal is to allow the use of a single connection from browsers to a Web site. It is based on the SPDY (pronounced speedy) protocol, originally developed by Google. HTTP/2 was developed by the Hypertext Transfer Protocol working group (httpbis, where bis means “second”) of the Internet Engineering Task Force.

HTTP/2 is the first new version of HTTP since HTTP 1.1, which was standardized in RFC 2068 in 1997. The Working Group presented HTTP/2 to Internet Engineering Steering Group (IESG) for consideration as a Proposed Standard in December 2014, and IESG approved it to publish as Proposed Standard on February 17, 2015. The HTTP/2 specification was published as RFC 7540 in May 2015. The standardization effort was supported by Chrome, Opera, Firefox, Internet Explorer 11, Safari, Amazon Silk and Edge browsers. Most major browsers added HTTP/2 support by the end of 2015. According to W3Techs, as of April 2016, 7.1% of the top 10 million websites supported HTTP/2.

Differences Between HTTP 1.1 and HTTP/2

The proposed changes do not require any changes to how existing web applications work, but new applications can take advantage of new features for increased speed. HTTP/2 leaves most of HTTP 1.1’s high-level syntax, such as methods, status codes, header fields, and URIs, the same. The element that is modified is how the data is framed and transported between the client and the server. Websites that are efficient minimize the number of requests required to render an entire page by minifying (reducing the amount of code and packing smaller pieces of code into bundles, without reducing its ability to function) resources such as images and scripts.
Additional performance improvements in the first draft of HTTP/2 (which was a copy of SPDY) come from multiplexing of requests and responses to avoid the head-of-line blocking problem in HTTP 1 (even when HTTP pipelining is used), header compression, and prioritization of requests.
HTTP/2 solves below problem because it brings a few fundamental changes:

  • All requests are downloaded in parallel, not in a queue
  • HTTP headers are compressed
  • Pages transfer as a binary, not as a text file, which is more efficient
  • Servers can “push” data even without the user’s request, which improves speed for users with high latency

Even though HTTP/2 does not require encryption, developers of two most popular browsers, Google Chrome and Mozilla Firefox, stated that for the security reasons they will support HTTP/2 only for HTTPS connections. Hence, if you decide to set up servers with HTTP/2 support, you must also secure them with HTTPS.

HTTP2 Features

  • Maintain high-level compatibility with HTTP 1.1
  • Decrease latency to improve page load speed
  • Data compression of HTTP headers
  • HTTP/2 Server Push
  • Pipelining of requests
  • Fixing the head-of-line blocking problem in HTTP 1.x
  • Multiplexing multiple requests over a single TCP connection

In this tutorial, we will learn how to install and setup Nginx with HTTP2 support on Ubuntu-16.04.

Requirements

A server running Ubuntu-16.04
A static IP Address for your server
A non-root user account with sudo privilege set up on your server

Install Nginx

Support of the HTTP/2 protocol was introduced in Nginx 1.9.5. Fortunately, the default repository in Ubuntu 16.04 contains a version higher than this, so we don’t have to add a third party repository. Before starting, you will need to update your system. You can do this by running the following command:

sudo apt-get update -y
sudo apt-get upgrade -y

When you are finished, install Nginx by running the following command:

sudo apt-get install nginx

After the installation process finishes, you can check the version of Nginx by typing:

sudo nginx –v

The output should be similar to the following:

    nginx version: nginx/1.10.0 (Ubuntu)

Changing the Listening Port and Enabling HTTP/2

The first change we will make will be to change the listening port from 80 to 443.

Let’s open the configuration file:

sudo nano /etc/nginx/sites-available/default

By default, Nginx is set to listen to port 80, which is the standard HTTP port:

    server {

            listen 80 default_server;

            listen [::]:80 default_server;

As you can see, we have two different listen variables. The first one is for all IPv4 connections. The second one is for IPv6 connections. We will enable encryption for both.

Modify the listening port to 443, which is used by the HTTPS protocol:

    server {

            listen 443 ssl http2 default_server;

            listen [::]:443 ssl http2 default_server;

Notice that in addition to ssl, we also added http2 to the line. This variable tells Nginx to use HTTP/2 with supported browsers.

Changing the Server Name

The next line after listen is server_name. Here is where we specify which domain should be associated with the configuration file. By default, server_name is set to _ (underscore), which means the config file is responsible for all incoming requests. Change _ to your actual domain, like this:

sudo nano /etc/nginx/sites-available/default

    server_name server-ip-address;

Save the configuration file, and exit the text editor.

Check the configuration for syntax errors:

sudo nginx -t

If the syntax is error-free, you will see the following output:

    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

    nginx: configuration file /etc/nginx/nginx.conf test is successful

Generate a Self-signed Certificate

TLS/SSL works by using a combination of a public certificate and a private key. The SSL key is kept secret on the server. It is used to encrypt content sent to clients. The SSL certificate is publicly shared with anyone requesting the content. It can be used to decrypt the content signed by the associated SSL key. We can create a self-signed key and certificate pair with OpenSSL in a single command:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt

The entirety of the prompts will look something like this:

    Generating a 2048 bit RSA private key

    ..................................+++

    ......................................................................+++

    writing new private key to '/etc/ssl/private/nginx-selfsigned.key'

    -----

    You are about to be asked to enter information that will be incorporated

    into your certificate request.

    What you are about to enter is what is called a Distinguished Name or a DN.

    There are quite a few fields but you can leave some blank

    For some fields there will be a default value,

    If you enter '.', the field will be left blank.

    -----

    Country Name (2 letter code) [AU]:IN 

    State or Province Name (full name) [Some-State]:GJ

    Locality Name (eg, city) []:AHMEDABAD

    Organization Name (eg, company) [Internet Widgits Pty Ltd]:HOSTPRESTO

    Organizational Unit Name (eg, section) []:IT

    Common Name (e.g. server FQDN or YOUR name) []:HITESH

    Email Address []:hitjethvagmail.com

Fill out the prompts appropriately. The most important line is the one that requests the Common Name (e.g. server FQDN or YOUR name). You need to enter the domain name associated with your server or, more likely, your server’s public IP address.

Both of the files you created will be placed in the appropriate subdirectories of the /etc/ssl directory.

While we are using OpenSSL, we should also create a strong Diffie-Hellman group, which is used in negotiating Perfect Forward Secrecy(In cryptography, forward secrecy (FS is a property of secure communication protocols in which compromise of long-term keys does not compromise past session keys.) with clients.

You can do this by typing:

sudo openssl hitesh -out /etc/ssl/certs/hitesh.pem 2048

This may take a few minutes, but when it’s done you will have a strong DH group at /etc/ssl/certs/hitesh.pem that we can use in our configuration by entering below command –

cat /etc/ssl/certs/hitesh.pem

Output:

    -----BEGIN DH PARAMETERS-----

    MIIBCAKCAQEArduNkJMZ06yjzCwqDs6n1pSjBVbTpzo8AV5RPjWkR/uuZ4SJGZxv

    xZexkS03qYgA8n+XjC7066C28LAF3G9wYyTkk8rKa29MEqV5Fh86jP5ZcGY6v/PR

    KiLJSuDqearTUviy6+fcydJeGTKgvoInoMJxyqPKIJWqqRfmgRf8CrGjiIndfKDc

    RVCMcRdqXb8anGpQRdpruwb2dQWfs7rNbdrdFoc0LlHZpy/wDfrAtiEDHm0aN9tJ

    SoTO4E2X9+/bsETqQH0paVaehEPk38ikcj5XH89MMzmgmBxAt/KyPzF5eCC/u3a4

    5hi4YRzJDky97oh31VccHq25IL4z97xCwwIBAg==

    -----END DH PARAMETERS-----

Adding the SSL Certificates

Next, you need to configure Nginx for your SSL certificate. Create a directory to store your SSL certificates inside the Nginx configuration directory:

Create a directory to store your SSL certificates inside the Nginx configuration directory:

sudo mkdir /etc/nginx/ssl

Copy your certificate and the private key to this location. We will also rename the files to show which domain they are associated. (It will come in handy in the future, when you will have more than one domain.) You can give any hostname according to your requirement:

sudo cp /etc/ssl/certs/nginx-selfsigned.crt /etc/nginx/ssl/ubuntu.crt
sudo cp /etc/ssl/private/nginx-selfsigned.key /etc/nginx/ssl/ubuntu.key

Now, let’s open our configuration file once again and configure SSL.

`sudo nano /etc/nginx/sites-available/default

On new lines inside the server block, define the location of your certificates:

    ssl_certificate /etc/nginx/ssl/ubuntu.crt;
    ssl_certificate_key /etc/nginx/ssl/ubuntu.key;

Save the file, and exit the text editor.

Avoiding Old Cipher Suites

HTTP/2 has a huge blacklist of old and insecure ciphers, so we must avoid them. Cipher suites are a bunch of cryptographic algorithms, which describe how the transferring data should be encrypted. We will use a really popular cipher set, whose security was approved by Internet giants like CloudFlare. It does not allow the usage of MD5 encryption (which was known as insecure since 1996, but despite this fact, its use is widespread even to this day).
Open the following configuration file:

sudo nano /etc/nginx/nginx.conf

Add this line after ssl_prefer_server_ciphers on;

    ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;

Increasing Key Exchange Security

By default, Nginx uses a 1028-bit DHE (Ephemeral Diffie-Hellman) key, which is relatively easy to decrypt. To provide maximum security, we should build our own, more secure DHE key.

To do so, issue the following command:

sudo openssl hitesh -out /etc/nginx/ssl/hitesh.pem 2048

The variable after the file path (in our case it is 2048) specifies the length of the key. A key with a 2048-bit length is secure enough and recommended by the Mozilla Foundation, but if you are looking for even more encryption, you can change it to 4096.

The generation process will take about 5 minutes. Once it is complete, open the default Nginx configuration file again:

sudo nano /etc/nginx/sites-available/default

On a new line inside server block, define the location of your custom DHE key:

    ssl_hitesh  /etc/nginx/ssl/hitesh.pem;

Redirecting all HTTP Requests to HTTPS

Since we are interested in serving the content through HTTPS only, we should tell Nginx what it should do if the server receives an HTTP request.

At the bottom of our file, we will create a new server block for redirecting all HTTP requests to HTTPS (be sure to replace the server name with your actual domain name):

    server {

           listen         80;
           listen    [::]:80;
           server_name    example.com;
           return         301 https://$server_name$request_uri;

    }

Save the file, and exit the configuration file.

Reloading Nginx

That’s it for all the Nginx configuration changes. Since we checked for syntax errors with each change, you should be ready to restart Nginx and test your changes.

To summarize, ignoring commented out lines, your configuration file should now look similar to this:

cat /etc/nginx/sites-available/default | egrep -v "^s*(#|$)"

    server {
      listen 443 ssl http2 default_server;
      listen [::]:443 ssl http2 default_server;
      root /var/www/html;
      index index.html index.htm index.nginx-debian.html;
      server_name server-ip-address;
      location / {
        try_files $uri $uri/ =404;
      }
      ssl_certificate /etc/nginx/ssl/ubuntu.crt;
            ssl_certificate_key /etc/nginx/ssl/ubuntu.key;
            ssl_hitesh  /etc/nginx/ssl/hitesh.pem;
    }
    server {
           listen         80;
           listen    [::]:80;
           server_name    server-ip-address;
           return         301 https://$server_name$request_uri;

    }

To apply the changes, restart the Nginx server.

sudo systemctl restart nginx

Verifying the Changes

Let’s check that our server is up and running. Open your web browser and type the URL http://server-ip-address.

You will get “Your connection is not private”. This is expected and normal. We are only interested in the encryption aspect of our certificate, not the third party validation of our host’s authenticity. Click “ADVANCED” and then click on Proceed to 192.168.13.149.

HP_NO_IMG/data/uploads/users/fd35bf73-10f3-43bf-b753-4edc26228307/1656586230.png” alt=”” />
HP_NO_IMG/data/uploads/users/fd35bf73-10f3-43bf-b753-4edc26228307/1116049004.png” alt=”” />
HP_NO_IMG/data/uploads/users/fd35bf73-10f3-43bf-b753-4edc26228307/1568843501.png” alt=”” />

If everything was configured properly, you should be automatically redirected to HTTPS. Now, let’s check that HTTP/2 is working: open the Chrome Developer Tools (View -> Developer -> Developer Tools) and reload the page (View -> Reload This Page). Then navigate to the Network tab, click on table header row that starts with Name, right-click on it, and select the Protocol option.
Now you should see h2 (which stands for HTTP/2) in a new column for your website serving HTTP/2 content.

HP_NO_IMG/data/uploads/users/fd35bf73-10f3-43bf-b753-4edc26228307/243110035.png” alt=”” />

##Conclusion
In this tutorial, you have learned how to set up nginx with HTTP-2 protocol support on Ubuntu 16.04. By using nginx over HTTP-2, we will get more speed and accuracy on our web server. Feel free to comment if you have any questions.

Want your very own server? Get our 1GB memory, Xeon V4, 25GB SSD VPS for £10.00 / month.
Get a Cloud Server

Share this Article!

Related Posts

Node.js Authentication – A Complete Guide with Passport and JWT

Node.js Authentication – A Complete Guide with Passport and JWT

Truth be told, it’s difficult for a web application that doesn’t have some kind of identification, even if you don’t see it as a security measure in and of itself. The Internet is a kind of lawless land, and even on free services like Google’s, authentication ensures that abuses will be avoided or at least […]

Node.js and MongoDB: How to Connect MongoDB With Node

Node.js and MongoDB: How to Connect MongoDB With Node

MongoDB is a document-oriented NoSQL database, which was born in 2007 in California as a service to be used within a larger project, but which soon became an independent and open-source product. It stores documents in JSON, a format based on JavaScript and simpler than XML, but still with good expressiveness. It is the dominant […]

Using MySQL with Node.js: A Complete Tutorial

Using MySQL with Node.js: A Complete Tutorial

Although data persistence is almost always a fundamental element of applications, Node.js has no native integration with databases. Everything is delegated to third-party libraries to be included manually, in addition to the standard APIs. Although MongoDB and other non-relational databases are the most common choice with Node because if you need to scale an application, […]

Node.Js Vs Django: Which Is the Best for Your Project

Node.Js Vs Django: Which Is the Best for Your Project

Django and NodeJs are two powerful technologies for web development, both have great functionality, versatile applications, and a great user interface. Both are open source and can be used for free. But which one fits your project best? NodeJs is based on JavaScript, while Django is written in Python. These are two equally popular technologies […]

Nodejs Vs PHP:  Which Works Best?

Nodejs Vs PHP: Which Works Best?

Before getting into the “battle” between Node.js and PHP we need to understand why the issue is still ongoing. It all started with the increased demand for smartphone applications, their success forcing developers to adapt to new back-end technologies that could handle a multitude of simultaneous requests. JavaScript has always been identified as a client-side […]