Thursday, August 15, 2019

How To Set Up a Node.js Application for Production on Ubuntu 18.04

Introduction

Node.js is an open-source JavaScript runtime environment for building server-side and networking applications. The platform runs on Linux, macOS, FreeBSD, and Windows. Though you can run Node.js applications at the command line, this tutorial will focus on running them as a service. This means that they will restart on reboot or failure and are safe for use in a production environment.
In this tutorial, you will set up a production-ready Node.js environment on a single Ubuntu 18.04 server. This server will run a Node.js application managed by PM2, and provide users with secure access to the application through an Nginx reverse proxy. The Nginx server will offer HTTPS using a free certificate provided by Let's Encrypt.

Prerequisites

This guide assumes that you have the following:
When you've completed the prerequisites, you will have a server serving your domain's default placeholder page at https://example.com/.

Step 1 — Installing Node.js

Let's begin by installing the latest LTS release of Node.js, using the NodeSource package archives.
First, install the NodeSource PPA in order to get access to its contents. Make sure you're in your home directory, and use curl to retrieve the installation script for the Node.js 8.x archives:
  • cd ~
  • curl -sL https://deb.nodesource.com/setup_8.x -o nodesource_setup.sh
You can inspect the contents of this script with nano or your preferred text editor:
  • nano nodesource_setup.sh
When you're done inspecting the script, run it under sudo:
  • sudo bash nodesource_setup.sh
The PPA will be added to your configuration and your local package cache will be updated automatically. After running the setup script from Nodesource, you can install the Node.js package:
  • sudo apt install nodejs
To check which version of Node.js you have installed after these initial steps, type:
  • nodejs -v
Output
v8.11.3
Note: When installing from the NodeSource PPA, the Node.js executable is called nodejs, rather than node.
The nodejs package contains the nodejs binary as well as npm, a package manager for Node modules, so you don't need to install npm separately.
npm uses a configuration file in your home directory to keep track of updates. It will be created the first time you run npm. Execute this command to verify that npm is installed and to create the configuration file:
  • npm -v
Output
5.6.0
In order for some npm packages to work (those that require compiling code from source, for example), you will need to install the build-essential package:
  • sudo apt install build-essential
You now have the necessary tools to work with npm packages that require compiling code from source.
With the Node.js runtime installed, let's move on to writing a Node.js application.

Step 2 — Creating a Node.js Application

Let's write a Hello World application that returns "Hello World" to any HTTP requests. This sample application will help you get Node.js set up. You can replace it with your own application — just make sure that you modify your application to listen on the appropriate IP addresses and ports.
First, let's create a sample application called hello.js:
  • cd ~
  • nano hello.js
Insert the following code into the file:
~/hello.js
const http = require('http');

const hostname = 'localhost';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World!\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
Save the file and exit the editor.
This Node.js application listens on the specified address (localhost) and port (3000), and returns "Hello World!" with a 200 HTTP success code. Since we're listening on localhost, remote clients won't be able to connect to our application.
To test your application, type:
  • node hello.js
You will see the following output:
Output
Server running at http://localhost:3000/
Note: Running a Node.js application in this manner will block additional commands until the application is killed by pressing CTRL+C.
To test the application, open another terminal session on your server, and connect to localhostwith curl:
  • curl http://localhost:3000
If you see the following output, the application is working properly and listening on the correct address and port:
Output
Hello World!
If you do not see the expected output, make sure that your Node.js application is running and configured to listen on the proper address and port.
Once you're sure it's working, kill the application (if you haven't already) by pressing CTRL+C.

Step 3 — Installing PM2

Next let's install PM2, a process manager for Node.js applications. PM2 makes it possible to daemonize applications so that they will run in the background as a service.
Use npm to install the latest version of PM2 on your server:
  • sudo npm install pm2@latest -g
The -g option tells npm to install the module globally, so that it's available system-wide.
Let's first use the pm2 start command to run your application, hello.js, in the background:
  • pm2 start hello.js
This also adds your application to PM2's process list, which is outputted every time you start an application:
Output
[PM2] Spawning PM2 daemon with pm2_home=/home/sammy/.pm2 [PM2] PM2 Successfully daemonized [PM2] Starting /home/sammy/hello.js in fork_mode (1 instance) [PM2] Done. ┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬───────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ ├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼───────┼──────────┤ │ hello │ 0 │ fork │ 1338 │ online │ 0 │ 0s │ 0% │ 23.0 MB │ sammy │ disabled │ └──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴───────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app
As you can see, PM2 automatically assigns an App name (based on the filename, without the .jsextension) and a PM2 id. PM2 also maintains other information, such as the PID of the process, its current status, and memory usage.
Applications that are running under PM2 will be restarted automatically if the application crashes or is killed, but we can take an additional step to get the application to launch on system startup using the startup subcommand. This subcommand generates and configures a startup script to launch PM2 and its managed processes on server boots:
  • pm2 startup systemd
The last line of the resulting output will include a command to run with superuser privileges in order to set PM2 to start on boot:
Output
[PM2] Init System found: systemd [PM2] To setup the Startup Script, copy/paste the following command: sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy
Run the command from the output, with your username in place of sammy:
  • sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy
As an additional step, we can save the PM2 process list and corresponding environments:
  • pm2 save
You have now created a systemd unit that runs pm2 for your user on boot. This pm2 instance, in turn, runs hello.js.
Start the service with systemctl:
  • sudo systemctl start pm2-sammy
Check the status of the systemd unit:
  • systemctl status pm2-sammy
In addition to those we have covered, PM2 provides many subcommands that allow you to manage or look up information about your applications.
Stop an application with this command (specify the PM2 App name or id):
  • pm2 stop app_name_or_id
Restart an application:
  • pm2 restart app_name_or_id
List the applications currently managed by PM2:
  • pm2 list
Get information about a specific application using its App name:
  • pm2 info app_name
The PM2 process monitor can be pulled up with the monit subcommand. This displays the application status, CPU, and memory usage:
  • pm2 monit
Note that running pm2 without any arguments will also display a help page with example usage.
Now that your Node.js application is running and managed by PM2, let's set up the reverse proxy.

Step 4 — Setting Up Nginx as a Reverse Proxy Server

Your application is running and listening on localhost, but you need to set up a way for your users to access it. We will set up the Nginx web server as a reverse proxy for this purpose.
In the prerequisite tutorial, you set up your Nginx configuration in the /etc/nginx/sites-available/example.com file. Open this file for editing:
  • sudo nano /etc/nginx/sites-available/example.com
Within the server block, you should have an existing location / block. Replace the contents of that block with the following configuration. If your application is set to listen on a different port, update the highlighted portion to the correct port number:
/etc/nginx/sites-available/example.com
server {
...
    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;
    }
...
}
This configures the server to respond to requests at its root. Assuming our server is available at example.com, accessing https://example.com/ via a web browser would send the request to hello.js, listening on port 3000 at localhost.
You can add additional location blocks to the same server block to provide access to other applications on the same server. For example, if you were also running another Node.js application on port 3001, you could add this location block to allow access to it via https://example.com/app2:
/etc/nginx/sites-available/example.com — Optional
server {
...
    location /app2 {
        proxy_pass http://localhost:3001;
        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;
    }
...
}
Once you are done adding the location blocks for your applications, save the file and exit your editor.
Make sure you didn't introduce any syntax errors by typing:
  • sudo nginx -t
Restart Nginx:
  • sudo systemctl restart nginx
Assuming that your Node.js application is running, and your application and Nginx configurations are correct, you should now be able to access your application via the Nginx reverse proxy. Try it out by accessing your server's URL (its public IP address or domain name).

Conclusion

Congratulations! You now have your Node.js application running behind an Nginx reverse proxy on an Ubuntu 18.04 server. This reverse proxy setup is flexible enough to provide your users access to other applications or static web content that you want to share.

How To Secure Nginx with Let's Encrypt on Ubuntu 18.04

Introduction

Let's Encrypt is a Certificate Authority (CA) that provides an easy way to obtain and install free TLS/SSL certificates, thereby enabling encrypted HTTPS on web servers. It simplifies the process by providing a software client, Certbot, that attempts to automate most (if not all) of the required steps. Currently, the entire process of obtaining and installing a certificate is fully automated on both Apache and Nginx.
In this tutorial, you will use Certbot to obtain a free SSL certificate for Nginx on Ubuntu 18.04 and set up your certificate to renew automatically.
This tutorial will use a separate Nginx server block file instead of the default file. We recommendcreating new Nginx server block files for each domain because it helps to avoid common mistakes and maintains the default files as a fallback configuration.

Prerequisites

To follow this tutorial, you will need:
  • One Ubuntu 18.04 server set up by following this initial server setup for Ubuntu 18.04 tutorial, including a sudo non-root user and a firewall.
  • A fully registered domain name. This tutorial will use example.com throughout. You can purchase a domain name on Namecheap, get one for free on Freenom, or use the domain registrar of your choice.
  • Both of the following DNS records set up for your server. You can follow this introduction to DigitalOcean DNS for details on how to add them.
    • An A record with example.com pointing to your server's public IP address.
    • An A record with www.example.com pointing to your server's public IP address.
  • Nginx installed by following How To Install Nginx on Ubuntu 18.04. Be sure that you have aserver block for your domain. This tutorial will use /etc/nginx/sites-available/example.com as an example.

Step 1 — Installing Certbot

The first step to using Let's Encrypt to obtain an SSL certificate is to install the Certbot software on your server.
Certbot is in very active development, so the Certbot packages provided by Ubuntu tend to be outdated. However, the Certbot developers maintain a Ubuntu software repository with up-to-date versions, so we'll use that repository instead.
First, add the repository:
  • sudo add-apt-repository ppa:certbot/certbot
You'll need to press ENTER to accept.
Install Certbot's Nginx package with apt:
  • sudo apt install python-certbot-nginx
Certbot is now ready to use, but in order for it to configure SSL for Nginx, we need to verify some of Nginx's configuration.

Step 2 — Confirming Nginx's Configuration

Certbot needs to be able to find the correct server block in your Nginx configuration for it to be able to automatically configure SSL. Specifically, it does this by looking for a server_namedirective that matches the domain you request a certificate for.
If you followed the server block set up step in the Nginx installation tutorial, you should have a server block for your domain at /etc/nginx/sites-available/example.com with the server_name directive already set appropriately.
To check, open the server block file for your domain using nano or your favorite text editor:
  • sudo nano /etc/nginx/sites-available/example.com
Find the existing server_name line. It should look like this:
/etc/nginx/sites-available/example.com
...
server_name example.com www.example.com;
...
If it does, exit your editor and move on to the next step.
If it doesn't, update it to match. Then save the file, quit your editor, and verify the syntax of your configuration edits:
  • sudo nginx -t
If you get an error, reopen the server block file and check for any typos or missing characters. Once your configuration file's syntax is correct, reload Nginx to load the new configuration:
  • sudo systemctl reload nginx
Certbot can now find the correct server block and update it.
Next, let's update the firewall to allow HTTPS traffic.

Step 3 — Allowing HTTPS Through the Firewall

If you have the ufw firewall enabled, as recommended by the prerequisite guides, you'll need to adjust the settings to allow for HTTPS traffic. Luckily, Nginx registers a few profiles with ufw upon installation.
You can see the current setting by typing:
  • sudo ufw status
It will probably look like this, meaning that only HTTP traffic is allowed to the web server:
Output
Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx HTTP ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx HTTP (v6) ALLOW Anywhere (v6)
To additionally let in HTTPS traffic, allow the Nginx Full profile and delete the redundant Nginx HTTP profile allowance:
  • sudo ufw allow 'Nginx Full'
  • sudo ufw delete allow 'Nginx HTTP'
Your status should now look like this:
  • sudo ufw status
Output
Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx Full ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx Full (v6) ALLOW Anywhere (v6)
Next, let's run Certbot and fetch our certificates.

Step 4 — Obtaining an SSL Certificate

Certbot provides a variety of ways to obtain SSL certificates through plugins. The Nginx plugin will take care of reconfiguring Nginx and reloading the config whenever necessary. To use this plugin, type the following:
  • sudo certbot --nginx -d example.com -d www.example.com
This runs certbot with the --nginx plugin, using -d to specify the names we'd like the certificate to be valid for.
If this is your first time running certbot, you will be prompted to enter an email address and agree to the terms of service. After doing so, certbot will communicate with the Let's Encrypt server, then run a challenge to verify that you control the domain you're requesting a certificate for.
If that's successful, certbot will ask how you'd like to configure your HTTPS settings.
Output
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):
Select your choice then hit ENTER. The configuration will be updated, and Nginx will reload to pick up the new settings. certbot will wrap up with a message telling you the process was successful and where your certificates are stored:
Output
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/example.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/example.com/privkey.pem Your cert will expire on 2018-07-23. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew" - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le
Your certificates are downloaded, installed, and loaded. Try reloading your website using https:// and notice your browser's security indicator. It should indicate that the site is properly secured, usually with a green lock icon. If you test your server using the SSL Labs Server Test, it will get an A grade.
Let's finish by testing the renewal process.

Step 5 — Verifying Certbot Auto-Renewal

Let's Encrypt's certificates are only valid for ninety days. This is to encourage users to automate their certificate renewal process. The certbot package we installed takes care of this for us by adding a renew script to /etc/cron.d. This script runs twice a day and will automatically renew any certificate that's within thirty days of expiration.
To test the renewal process, you can do a dry run with certbot:
  • sudo certbot renew --dry-run
If you see no errors, you're all set. When necessary, Certbot will renew your certificates and reload Nginx to pick up the changes. If the automated renewal process ever fails, Let’s Encrypt will send a message to the email you specified, warning you when your certificate is about to expire.

Conclusion

In this tutorial, you installed the Let's Encrypt client certbot, downloaded SSL certificates for your domain, configured Nginx to use these certificates, and set up automatic certificate renewal. If you have further questions about using Certbot, their documentation is a good place to start.