NGINX is a high-performance HTTP server as well as a reverse proxy. Unlike traditional servers, NGINX follows an event-driven, asynchronous architecture. As a result, the memory footprint is low and performance is high. If you’re running a Node.js-based web app, you should seriously consider using NGINX as a reverse proxy.
NGINX can be very efficient in serving static assets. For all other requests, it will talk to your Node.js back end and send the response to the client. In this tutorial, we’ll discuss how to configure NGINX to work with Node.js. We’ll also see how to setup SSL in the NGINX server.
Note: Node also has a built-in HTTPS module and can be configured to read the necessary certificate files without the need for a reverse proxy. You can find out more about this in our article How to Use SSL/TLS with Node.js.
Installing NGINX
Assuming you already have Node.js installed on your machine (if not, check here), let’s see how to install NGINX.
Installation on Linux
If you’re running Ubuntu, you can use the following command to install NGINX:
sudo apt-get update
sudo apt-get install nginx
If you’re running a Linux distro other than Ubuntu, check out the NGINX installation docs for more information.
NGINX will start automatically once it’s installed.
Installation on macOS
If you’re on macOS, you can use Homebrew to install NGINX easily. The steps are as following:
-
Homebrew needs the directory
/usr/local
to bechown
’d to your username. So, run the following command in terminal first:sudo chown -R 'username here' /usr/local
-
Now the following two commands will install NGINX on your system:
brew link pcre brew install nginx
-
Once the installation is complete, you can type the following command to start NGINX:
sudo nginx
-
The NGINX config file can be found here:
/usr/local/etc/nginx/nginx.conf
.
Installation on Windows
For Windows, head over to the NGINX downloads page and get the zip. The next step is unzipping the archive and moving to the directory in the command prompt as follows:
unzip nginx-1.3.13.zip
cd nginx-1.3.13
start nginx
As you can see, the command start nginx
will start NGINX.
Now that the installation is done, let’s see how you can configure a simple server.
Setting Up a Node.js Server
First, let’s create a simple Node.js server. We’ll start by initiating a project and installing the Express package:
mkdir node-demo && cd node-demo
npm init -y
npm i express
Create a file called server.js
, with the following contents:
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
You can start the server by running node server.js
.
Configuring NGINX
Now let’s open up the NGINX default site config file:
sudo nano /etc/nginx/sites-available/default
If you want, you can go directly to the directory and open up the config file with your favorite text editor.
As you scroll down, you’ll find a server
block. It looks something like this:
server {
listen 80;
server_name localhost;
....
more config goes here
}
Next, we’ll configure the server
block to suit our needs. We want to configure NGINX to pass all requests through to our Node.js server. Replace the above server
block with a new block as shown below:
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
As you can see, the web server will listen on http://localhost
port 80
. The location /
block tells NGINX what to do with any incoming request. We use proxy_pass
to point to our Node.js application, which is running at http://localhost:3000
in our case.
At this point, you should save the file and type the following to restart NGINX, depending on your operating system.
Ubuntu:
sudo service nginx restart
Or:
sudo /etc/init.d/nginx restart
macOS:
sudo nginx -s stop && sudo nginx
Windows:
nginx -s reload
Once this is done, you can go to http://localhost to see our proxy in action. Although you’re accessing the NGINX web server, you’ll get the actual response from the Node.js server.
Note: you’ll need to make sure there isn’t anything else (such as Apache) running on port 80.
Setting Up SSL
In order to create a secure connection with a user’s browser, we’ll need to obtain a digital certificate. Normally, you get one of these from a certificate authority such as Let’s Encrypt. If you go the Let’s Encrypt route, be sure to install the certificate using Certbot, which will take care of reconfiguring NGINX for you.
For local development (and for following along with this tutorial) you can also create a self-signed certificate. The only problem is that browsers will show a warning that the “Certificate is not Trusted” when someone visits your website. But for testing on your local machine that’s perfectly fine.
Once you have a certificate and a private key, you can set up SSL in NGINX. You need to modify our previous server block to the following:
server {
listen 80;
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
That’s it!
Now, if you access https://localhost, your connection will be secure. The configuration above assumes that the certificate and private key are located at /etc/nginx/ssl/server.crt
and /etc/nginx/ssl/server.key
respectively, but you can change these locations if you wish.
Bonus: Serving Static Assets
An additional benefit of having NGINX set up in front of our Node.js server is that we can easily configure it to serve up any static assets our app requires. This will save the overhead of passing through these requests for Node to handle.
To do this, we need to add a new location
block to the server configuration:
server {
listen 80;
server_name localhost;
location / {
...
}
location /public {
root /usr/local/var/www;
}
}
Inside this location
block we set the root to /usr/local/var/www
, but you can choose a different directory if you like. As a result, whenever there’s a request to something like http://localhost/public/somepath/file.html
, NGINX will serve the file from /usr/local/var/www/public/somepath/file.html
directly.
Conclusion
In this brief tutorial, we’ve seen how to use NGINX as a reverse proxy for our Node.js app and configure SSL. By using NGINX to handle the static resources, you can also take some load off your Node application.