How to deploy a Node Application Server with “Nginx Reverse Proxy” on Ubuntu 22.04

Prasad Beligalage
7 min readOct 27, 2022

--

What is Nginx?

Nginx is a high performance web server. Not only it’s fast, but also it does consume less memory than other popular web servers such as Apache. In addition to better performance, Nginx also comes with many other features such as web acceleration, caching and load balancing (read more about why Nginx is a good choice for Node deployment).

How to use Nginx as a Reverse Proxy

Nginx is basically has two components, a HTTP server and a content serving component. For the reverse proxy configuration, we use only the HTTP component as the web serving task is going to be handled by the Node application we create. In order to make Nginx a reverse proxy, we have to place Nginx (the HTTP server component) in between the client browser and the Node Application (also known as the Node Web Application server). Thus, with reverse proxy configuration, Nginx stays as an intermediate person who forwards the client requests to the Application Server (Node app) and responds back to the client with the responses sent by Node application.

Prerequisites

You need an Ubuntu Desktop or Server (20.04 or 22.04 preferred) with Node.js installed. You also need a valid domain name which has DNS configured and pointing to the server’s IP address.

Whether you’re using Ubuntu or Debian, you need to have “root” user privileges (root terminal) to run the commands in this tutorial. If you don’t have root terminal access, then you have to run commands with “sudo”. Ex. sudo apt-get install nginx

Installing and using Nginx

Open a terminal and run this command to install nginx.

apt-get install nginx

To confirm the installation, run;

nginx -v

This should return the nginx version.

Once nginx is installed, it should be automatically activated. To check the status, run;

systemctl status nginx

systemctl is a Linux utility that is used to manage systemd and services

If Nginx is activated successfully, you should see a screen similar to the following.

If you see the nginx server is inactive, then you can start nginx by running the command below.

systemctl start nginx

Now, open a web browser tab and type http://localhost in the address bar. If Nginx is properly installed, you should see the default nginx html page. The page you see is located in the html directory in the Nginx default document root which is the directory where, usually all the websites or applications are stored. The location of the document root is, /var/www/. The webpage you see is located inside the html directory in the document root /var/www/html.

Creating a minimal Node HTTP application server for content serving

First, we need a basic server app created using Node. If you already have an app, you can skip to the next section, or otherwise create this simple http server as described below.

You may use a framework such as Express, Koa, Nest, Fasitify etc. to create the Node server app. Since we just need a basic application for demonstration purposes, I am using the Node HTTP module which is the base of all frameworks listed above.

First let’s create a folder, “NodeAppp” in the document root and create a file called app.js. Here I am using vim editor, but you can use any text editor you like.

cd /var/www
mkdir NodeApp
cd NodeApp
vim app.js

Now copy the code below and save the file (Ex. :wq to save VIM file).

import http from 'http'const server = http.createServer((request, response)=>{response.writeHead(200, {'content-type': 'text/html'})response.end('<html><body><h1>Hello World!</h1></body></html>')}).listen(3030)

Here we create a http server using createServer() method which is listening on port 3030. We also write the response header with status code 200 and send a response in the html format.

In order to test the app, open a terminal and run;

node app.js

Then open a browser tab and type http://localhost:3030 in the address bar. You should see our app works on port 3030 and displays Hello World!

Creating the Nginx Reverse Proxy

By now we have successfully installed nginx and also, we have a working Node app. So, now we can configure Nginx to operate as a reverse proxy.

When creating a reverse proxy, the first task is to create a Server Block. A Server Blocks is a part of Nginx which comes under the load balancing feature. The question is, why do we need a server block?

More often, it’s possible that our server machine could host more than one Node application, or other applications created using PHP, python etc. So, creating server blocks allows us to deploy more than one app on our server at the same time.

Server blocks have to be created within the /etc/nginx/sites-available directory. So, first navigate to the directory;

cd /etc/nginx/sites-available

Now create a file with your domain name. I am using strawbwerry.gleeze.com as my domain name. So, remember to replace this domain name (strawbwerry.gleeze.com) with your domain name. Ex. vim mydomain.com.

vim strawberry.gleeze.com

Add the code below and save the file. You can use “#” symbol to add comments in the file. Here we are using the proxy_pass directive of Nginx to forward the client requests to the application server.

server {    listen 80;    listen [::]:80;    server_name strawberry.gleeze.com www.strawberry.gleeze.com;    location / {      proxy_pass http://localhost:3030;    }}

Now, save the file.

We have created a server block which listens on port 80 for the strawberry.gleeze.com domain name. This server block will discard all incoming requests other than strawberry.gleeze.com. Then we have added one location directive block of “/” (root) which will respond to all requests coming to strawbweey.gleeze.com. Then we have to specify the address of our Node application server where we forward the requests to process. Note that, at this point, we are using only the HTTP server component of the nginx and the content serving process is handed over to the application server (Node app). Therefore, the Node app will receive only the requests coming to strawberry.gleeze.com with port 80, and all other requests are filtered out by Nginx. The communication between the HTTP server of nginx and our Node application is done via HTTP protocol.

Next we have to create a symbolic link from the /etc/nginx/sites-enabled directory to the file we’ve just created. First you have to navigate to the sites-enabled directory before you create the symbolic link.

cd /etc/nginx/sites-enabledln -s /etc/nginx/sites-available/strawberry.gleeze.com /etc/nginx/sites-enabled/strawberry.gleeze.com

Then restart the server.

systemctl restart nginx

Now your app has to be working when you access the URL, in my case http://strawberry.gleeze.com. Here what the nginx does is, it accepts all the http requests that arrive under name strawberry.gleeze.com on port 80, and forward them to the Node app which is at http://localhost/3030. Then the responses sent by the Node app (for each request) will be sent back to the client.

Optional configuration

What we’ve done so far is the basic reverse proxy configuration, which is of course enough to run our Node application. However, we can also add more configuration and override the default header values of the request that is being passed to the Node application. Given below are some of the optional configurations that you can add into the location block.

Set the HTTP version; The default value is set to HTTP version 1.0, so it’s recommended to use the HTTP version 1.1.

proxy_http_version 1.1;

Overriding default header values can be done using proxy_set_header directive.

The Host value is by default set to $http_host which gives both the hostname and port number. You can replace this as below, so the Host will contain only the server name.

proxy_set_header Host $host;

If you check the remote IP of the request header in the Node app, it will be the loopback IP, 127.0.0.1 as Nginx stays in between the client and the Node app. Therefore, we can forward the actual client IP address to the Node app as below;

proxy_set_header real-client-ip $remote_addr;

Now you can access the actual client IP address in the request header object in your Node app.

Adding Error and Access log files

You can ask Nginx to save all server related errors in an error log by using the error_log directive.

First, let’s create a folder /home/nginx and then let’s create a file (error.log) to save the errors.

cd /homemkdir nginxcd nginxvim error.log

Now let’s tell Nginx to save the errors based on different severity levels, in this file we’ve created.

error_log /home/nginx/error.log

Note that, you can also add an Access Log file using the access_log directive. The Access Log is written for each and every request made by the client and as it can affect the performance if your app is accessed by thousands of users, make sure to use it only when it’s extremely required. You can add the access log as below;

access_log /home/nginx/access.log

You may add many other optional configurations, but unnecessary configuration might result in unexpected behaviour or performance issues. Nginx comes with numerous features and you can add them in the configuration file. For example, you can speed up the performance by enabling caching in Nginx. Please refer to the official documentation to learn about caching. However, what I’ve mentioned here is pretty much enough for any Node Application.

Ok, now it’s time to add it all together.

vim /etc/nginx/sites-available/strawberry.gleeze.com

Add the code below and save the file. (remember to replace the domain name and change the proxy_pass address if you’re using a different one)

server {    listen 80;    listen [::]:80;    server_name strawberry.gleeze.com www.strawberry.gleeze.com;    location / {        ##proxy_pass directive (required)        proxy_pass http://localhost:3030;
##Optional configuration proxy_http_version 1.1; proxy_set_header Host $host; error_log /home/nginx/error.log ##Create an access log as below, if only it’s required #access_log /home/nginx/access.log proxy_set_header client-ip $remote_addr; }}

Then restart Nginx

systemctl restart nginx

Summary

In this tutorial we learnt what Nginx is how to use Nginx as a reverse proxy. Then we’ve created a simple Node application and deployed with a Nginx reverse proxy. Finally we’ve added a few optional configurations such as changing the HTTP version, logging and forwarding remote IP, in the server block.

Next step: Add SSL/TLS layer (HTTPS) to the app

--

--