Publishing a Web site using node, pm2 and nginx
Tags: node, nginx, pm2, parcel
Published: 2020-11-26 12:04:14

---
title: Publishing a Web site using node, pm2 and nginx
published: true
description: Deploying a Node.js website on Ubuntu using simple password authentication for showing intermediate results to your clients.
tags: node, nginx, pm2, parcel
//cover_image: https://direct_url_to_image.jpg
---

During development of a website, I often have the need to share the intermediate results with my clients using basic authentication. On one of my servers, I perform the following steps to get it up and running.

## Publish the site

Assuming you have already created the website, build and deploy it to a folder that can be served by `node.js`. In my case, I often use `parcel` to build the client side, using something along the following lines as part of the `package.json`. As I don't want to hard-code the backend server's location in my client code, it is written in an `.env` file, e.g.

```bash
cat packages/gui/.env
SERVER="http://xxx.xxx.xxx.xxx/bob"
```

And in my GUI code, I reference `process.env.SERVER`, which Parcel will replace with the value found in the `.env` file.

If you use TypeScript, you also need to add a declaration file for this to work, e.g. `env.d.ts`

```ts
declare const process: { env: { SERVER: string } };
```

To actually do the build process, I have something like this in my `package.json` (and `rimraf` and `parcel-bundler` are part of my `devDependencies`), so I can use `npm run build:domain` to deploy the site:

```json
  "scripts": {
    "start": "parcel index.html",
    "clean": "rimraf ./public ./.cache ./dist",
    "build": "parcel build index.html --out-dir ../server/public --public-url ./",
    "build:domain": "npm run clean && npm run build"
  },
```

The most important script is the `build` script: it tells parcel to bundle all my stuff, put it in the `out-dir` folder, and use the `public-url` to make all file references relative to the final location where it will be running. If you do not include the latter, all file references will be hard-coded e.g. `/app.123ved.css` instead of `app.123ved.css`. See also the description [here](https://stackoverflow.com/a/63588756/319711).

## Deploying the service

Since my backend is on Node, I normally use a simple `pm2` service to run it, e.g.

```bash
sudo pm2 start PATH/TO/SERVER.js --name APP_NAME
sudo pm2 ls # to see if it is running
```

For more information about `pm2`, see [here](https://pm2.keymetrics.io/docs/usage/quick-start/).

Other useful commands are `sudo pm2 stop APP_NAME_OR_APP_ID` and `sudo pm2 start APP_NAME_OR_APP_ID`.

As the server is used for many sites, the application needs to run on a dedicated port, preferably one behind a firewall, so it is not reachable from the outside. We use Nginx for that.

## Configuring Nginx

Assuming you have Nginx up-and-running, add a new entry for your server in `/etc/nginx/sites-available` and create a symbolic link to the `/etc/nginx/sites-enabled` folder, e.g. 

```bash
sudo vi bob
ln -s bob ../sites-enabled
```

Where the content of the file is something like the following:

```bash
upstream demoserver {
   # port 55555 not reachable from Internet (firewall) 
   server 127.0.0.1:55555;
}

server {
    location = /bob {
        return 302 /bob/;
    }

    location /bob/ {
        auth_basic "Demonstration area";
        auth_basic_user_file /etc/apache2/.htpasswd;

        allow 127.0.0.1;

        # NOTE: The final / is important, as it will strip the prefix 'bob' from all URLs
        proxy_pass http://demoserver/;
    }
}
```

That means that our service is running on port 55555, and will be reachable via `HOST_IP/bob`. Assuming, of course, that you have setup a password file. Read on...

## Creating a Password File

[Source](https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication)

To create username-password pairs, use a password file creation utility, for example, `apache2-utils` or `httpd-tools`.

Create a password file and a first user. Run the htpasswd utility with the `-c` flag (to create a new file), the file pathname as the first argument, and the username as the second argument:

```bash
$ sudo htpasswd -c /etc/apache2/.htpasswd user1
```

Press Enter and type the password for user1 at the prompts.

Create additional user-password pairs. Omit the `-c` flag because the file already exists:

```bash
$ sudo htpasswd /etc/apache2/.htpasswd user2
```

You can confirm that the file contains paired usernames and encrypted passwords:

```bash
$ cat /etc/apache2/.htpasswd
user1:$apr1$/woC1jnP$KAh0SsVn5qeSMjTtn0E9Q0
user2:$apr1$QdR8fNLT$vbCEEzDj7LyqCMyNpSoBh/
user3:$apr1$Mr5A0e.U$0j39Hp5FfxRkneklXaMrr/
```

## Restarting Nginx

Test your configuration first using

```bash
sudo service nginx configtest
```

And if that returns OK, restart Nginx using

```bash
sudo service nginx restart
```