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.