Express is probably one of the widely used web frameworks out there. It is incredibly easy to use and extremely powerful. Nginx is one of the most popular web servers and is often used as a reverse proxy. Nginx is super fast and powerful, making it one of the go-to choices when deploying web servers.
In this blog article it is shown how an Express application can be deployed with Nginx as a reverse proxy. The following common problems will be solved:
- How to forward the remote IP address of a client to the web app from Nginx
- How to serve static files with Nginx
- Bonus: Deploy SSL certificates with Let's Encrypt
You can follow each step along in this tutorial.
Important: It is assumed that every step in this tutorial is made on a VPS server that is publicly accessable from the Internet. To be specific, an Ubuntu 18.04 Linux server is used. The instructions should be identical with Ubuntu 20.04.
Setting up the project
You need to have Node.js and npm installed.
Create the project directory and change into it.
mkdir express-with-nginx
cd express-with-nginx/
Install express:
npm install express
And then save the following server code as server.js
:
const express = require('express');
const app = express();
const port = 3000;
function getIp(req) {
let ip = req.connection.remoteAddress;
ip = ip.replace('::ffff:', '');
if (ip == '127.0.0.1') {
ip = req.headers['x-real-ip'];
}
return ip;
}
app.get('/', (req, res) => {
res.send('Hello World from: ' + getIp(req));
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
})
Now you have a functional express server.
Start the server with the command:
node server.js
Configure Nginx
The next step is to setup Nginx as a reverse proxy.
Create the Nginx configuration file in /etc/nginx/sites-available/express_nginx.conf
:
# /etc/nginx/sites-available/express_nginx.conf
server {
listen 80;
server_name test.incolumitas.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
}
}
Please change the domain name test.incolumitas.com to whatever domain you are using.
Note: The directive proxy_pass
tells Nginx to forward all traffic arriving on test.incolumitas.com
to the local server listening on http://localhost:3000
.
The directive proxy_set_header X-Real-IP $remote_addr;
forwards the real IP address of the user in a header X-Real-IP
to our Express application.
Enable the Nginx configuration file with the command:
ln -s /etc/nginx/sites-available/express_nginx.conf /etc/nginx/sites-enabled/
And then restart the server:
service nginx restart
Now visit the URL http://test.incolumitas.com with your browser. You should see something like this in your browser:
Hello World from: 145.54.78.22
Deploy an SSL certificate with Let's Encrypt
In a real production environment, you should of course deploy the webserver with SSL support. This tutorial shows how to do so with Ubuntu and Nginx and Let's Encrypt.
Assuming that certbot
is correctly installed, you can issue the following command to use SSL:
certbot --nginx -d test.incolumitas.com
You will see the following output. Choose the option 2: Redirect when prompted.
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for test.incolumitas.com
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/express_nginx.conf
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/express_nginx.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://test.incolumitas.com
You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=test.incolumitas.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Then restart the nginx server with
service nginx restart
You can now access your Express application with the URL https://test.incolumitas.com.
This will modify your Nginx configuration file to use an SSL certificate. After the command, it will look something like this:
server {
server_name test.incolumitas.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/test.incolumitas.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/test.incolumitas.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = test.incolumitas.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name test.incolumitas.com;
return 404; # managed by Certbot
}