NGINX in practice in just 10 minutes

NGINX (pronounced “eNGINe X”) is a Web Server: it will receive HTTP requests and create HTTP responses, simple as that. Besides that, you may also hear the term Application Server which is more specific when you have an application for handling the HTTP requests and rendering dynamically the HTTP responses, such a Java or PHP application.

Apache httpd (or commonly only “Apache”) and Microsoft IIS are the most used Web Server/Application Server ever since the internet became popular, but nowadays the demand for concurrency and scalability (being able to increase multiple servers to respond quickly to multiple users at the same time) is a modern concern and that’s why NGINX was created, it was designed by nature to answer to these problems, and I’m going to present its main features: Reverse Proxy, Load Balance and Caching.

Installing and Running

If you are using Ubuntu Linux it’s available at apt, just install on your terminal: “apt-get install nginx” , please search how to install if you are using other distro or operational system.

After install, just run “nginx” in your terminal and it’s running by default on localhost port 80.

Congratulations! nginx running on localhost:80

Configuring NGINX

After installing and running, you make changes in NGINX via its configuration file. To see where is located run at your terminal:

nginx -t

On my Linux Ubuntu the file is located at: “/etc/nginx/nginx.conf”

Practical Examples Warmup

To be able to play along and understand NGINX in practice I’m going to create an example application which will listen to a HTTP port, and give a simple HTTP response for each HTTP request received.

If you don’t know Node.Js or docker-compose it’s OK, you don’t need to write any code right now, just follow the examples it’s easy to read and understand even if don’t know these tools yet. After understanding, you can do these examples latter with your programming language of choice!

The application code, app.js:

const http = require(‘http’)
const app = http.createServer((req, res) => {
//it's nice to print the server ID and called URL to see which server is called by NGINX
console.log(`SERVER: ${process.env.SERVER_ID} called — url: ${req.url}`)
res.write(`SERVER: ${process.env.SERVER_ID} — url: ${req.url}`)
res.end()
})
app.listen(‘8000’)

See that I’m using fixed port 8000 and receiving the SERVER_ID via environment variables because I will use docker-compose to run it. If you won’t use docker-compose change the code to receive both port number and server ID by a parameter.

My docker-compose.yml file:

server1:
image: node:8
container_name: server1
command: "node app/app.js"
working_dir: /app
volumes:
- .:/app
environment:
- SERVER_ID=1
ports:
- "8001:8000"
server2:
image: node:8
container_name: server2
command: "node app/app.js"
working_dir: /app
volumes:
- .:/app
environment:
- SERVER_ID=2
ports:
- "8002:8000"

See that I will run the application twice with different ports, with docker compose, after I running it via docker-compose up, I can see the running application instances via docker-compose ps:

Name         Command       State           Ports
----------------------------------------------------------
server1 node app/app.js Up 0.0.0.0:8001->8000/tcp
server2 node app/app.js Up 0.0.0.0:8002->8000/tcp

You can call your running instances in the browser to ensure that’s everything is running.

2 instances of our application running. Note I called 0.0.0.0:8002/login just to check if it’s really 2 different instances. And /favicon.ico call is done automatically by the browser.

NGINX Reverse-Proxy

A reverse proxy will get the request from the client then it can redirect to multiple points. This is very useful to compose your web-application in multiple different applications (such as Microservices Architecture).

Let’s modify NGINX configuration file http section to make /login calls go to server #2 (:8002) , and any other calls go to server #1 (:8001)/ application directory.

Note: your NGINX configuration file may have a lot of configuration already, you only replace the http section:

http {
server {
location /login {
proxy_pass http://0.0.0.0:8002;
}
    location / {
proxy_pass http://0.0.0.0:8001/application/;
}
}
}

After any change on NGINX configuration file, you need to reload the configuration on your terminal, via:

nginx -s reload

Now we can test the servers redirections:

The NGINX reverse proxy redirected different locations for different servers.

Another good use-case is to split different resources of your website, such as videos, images, PDF files, etc.. to different servers.

Reverse-Proxy can have also multiple advantages rather than calling your application directly, you can cache the response, compress to make faster (eg.: GZIP) and add a security layer.

NGINX Load-Balancer

While Reverse-Proxy may respond different requests to different servers. Load-Balancer may respond same requests to different servers.

What’s the point of same requests going to different servers? Is to divide the job of a single server! If you don’t have multiple users using your web app at the same time it’s unnecessary indeed. However, if you have at least peak hours or heavy tasks, you notice that your application respond slow to the users, and then Load-Balancer shines.

Let’s modify our http section again from NGINX configuration file:

http {
upstream load_balancer_example {
server 0.0.0.0:8001;
server 0.0.0.0:8002 weight=2;
}
  server {
location / {
proxy_pass http://load_balancer_example;
}
}
}

Now call your application multiple times:

Load-Balancer distributing calls to different servers

The default approach of NGINX Load-Balancer is called “Round-Robin”, which only calls sequentially different servers for each request. Note: we used the optional parameter “weight” to make server #2 called twice as server #1, this is useful where you have servers with different capacity.

Besides “Round-Robin” there is “Least Connected” approach which is more performance-wise effective, where the request is redirected to serve which has least connections, and there is “By IP” approach where the same user only access the same server.

“By IP” approach is useful, because if you control the user session in your server, if the user request goes to another server, the session will be lost! If you still want to use benefits of other Load-Balance approaches and don’t want to lose user session, you have to store user session somewhere else than in the server, such as in a database, and identify the user between the servers via a token.

If you want to learn more about those approaches, there is more information in this link: http://nginx.org/en/docs/http/load_balancing.html

Caching

Caching is a simple and a very effective solution to solve a lot of performance problems in your web application. Instead, to make your application process every time a response to a request, it can be saved to simple show a saved response instead process again.

You may have heard about this for static files, but an advantage of having NGINX instead your application directly is that you can also cache dynamic pages! This approach is called “micro-caching”, there is an example of how you could do in NGINX configuration file:

http {
proxy_cache_path /tmp/cache keys_zone=micro_cache:10m levels=1:2 inactive=600s max_size=100m;
server {
proxy_cache micro_cache;
proxy_cache_valid 200 5s;
location / {
proxy_pass http://0.0.0.0:8001;
}
}
}

And in every successful response (code 200) it’ll be cached and for 5 seconds it will respond the cached content instead of asking again for your application.

Of course, this subject is very extensive and it’s only one of the multiple approaches that you could do.

So, can I forget about Apache and only sick with NGINX?

If you have noticed, NGINX is only the layer which will control the Web Server, and in many cases where you need an Application Server to run your application (such as PHP or Java), so you will run NGINX along an Application Server such as Apache!

Besides NGINX being designed for very high demanding and concurrent applications, of course, you still can tweak Apache to have similar capabilities, it will be probably more complicated, that’s why I like NGINX.

You only can’t compete Apache with NGINX when the subject is static websites, the performance of using NGINX for static websites are unreal!

How is NGINX in real-world scenarios?

Honestly, I don’t use much! As we use more cloud services such as AWS and Azure, mainly for concurrency and scalability, they already provide solutions for many problems NGINX solve, such as Load-Balancer. I mostly consider the use of NGINX if your company use physical servers.