Setting up Nginx with SSL as a static server and reverse proxy for NodeJs


2020-08-04 20:36:36

Yesterday I've set up a new Web project that contains a static file server for html and Javascript for the front end, as well as a NodeJs server for the backend. Both are secured via SSL and have their own subdomains. The whole setup wasn't super simple, so I wanted to write the whole process down in case I ever have to do it again. Let's first look at the different parts:

  • Ubuntu 16.04 server running Node and Nginx
  • NodeJS server
  • Nginx with two servers set up, one as a reverse proxy for NodeJS and one for static files
  • Amazon Route 53 Domain

Server setup

On the Ubuntu server I first created a deploy user useradd --create-home -s /bin/bash deploy and added him to the sudoers group adduser deploy sudo. All the following steps are done with the deploy user and not the root user!

NodeJS setup

This was the simplest part. I first installed NPM sudo apt install npm, then the 'n' package for managing node versions sudo npm install -g n, and then the latest nodejs release sudo n latest. The next step was to upload my NodeJS app to the server I used flightplan here, but any other way to upload files to a server works as well) and to make sure it starts with the machine and restarts after crashes. I use 'pm2' for that, a node process manager. the basic usage was pm2 startup systemd to make sure pm2 starts with the system, then pm2 start app.js to start my node app followed by pm2 save to save the running apps so they're restored after a reboot.

The NodeJS server itself is a simple express App that just listens for ordinary HTTP (not HTTPS) traffic on port 8080 on localhost. This is important, start the app with app.listen(8080, "") so that it can't be accessed from outside. We only want HTTPS to be able to access this, through Nginx.

Amazon Route 53

I bought my domain at Amazon, but you can use any other domain reseller. I think their control panel gives great flexibility, but the real reason why I got the domain from them was that I originally planned on using Amazon Elastic Beanstalk to deploy my node app. Anyways, I routed my Domain ( via an A record to my server IP. Then I created two subdomain A records for and and routed them to the same IP as well.


This was the most challenging part. I first installed nginx with sudo apt install nginx and also installed letsencrypt for my SSL certificates sudo apt install letsencrypt. Then I had to use the standalone mode for letsencrypt to get a vlid certificate for my (sub-)domain. I also set up a cronjob to regularly systemctl stop nginx, refresh the certificates letsencrypt autorenew and then systemctl start nginx again. Then I had to set up HTTP in nginx (which just forwards via a 301: moved permanently to the HTTPS site) and the HTTPS reverse proxies for the node applications.