Deploying Angular Using http-server, Nginx, and PM2

3 minute read

Since it took about an hour to put all the pieces together correctly I thought it best to document how I deployed an Angular (version 2) app using http-server, pm2, and nginx. In my case I deployed to an Ubuntu server hosted on DigitalOcean, but these instructions should work the same as long as you have the other components installed correctly.

I am not an expert on this topic. Like most people, I am learning as I go. If you think I am doing something stupid please let me know.

Pre-reqs

Let’s get the easy stuff out of the way…

http-server

First, I installed http-server to serve my Angular app. I already had node/npm installed on my remote server, so I simply ran the follow command and was done.

npm install http-server -g

Angular

I used the angular-cli to create an app. When the app was done1, I created a build using:

ng build -prod

After the build was complete, I copied the contents of the dist/ directory to my remote server. Easy part, done.

Nginx

I am going to assume that the only reason you have made it this far is because you already have nginx installed on your server.

Nginx requires a server block for the Angular app so for me, this meant adding a file to the /etc/nginx/sites-available/ directory on my remote server. I am running multiple web sites so I created a new file called: ng2.cooldomain.com. Before I forgot, I also created a symbolic link to the sites-enabled directory:

ln -s /etc/nginx/sites-available/ng2.cooldomain.com /etc/nginx/sites-enabled/ng2.cooldomain.com

This is the configuration I ended up with2:

server {
    listen 80;
    server_name ng2.cooldomain.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}

Two points of interest:

  1. You may use an IP address or some other convention for the server_name depending on your setup.
  2. Depending on how you serve (e.g., different port) the Angular app you may have a different proxy_pass as well.

Pro Tip two commands to remember when messing with nginx: sudo nginx -t will test your configuration and run sudo service nginx restart after saving changes.

PM2

Finally, I wanted to use pm2 to keep the new Angular site up and running. Over time I have created a collection of apps. Executing a pm2 command each time I finished an app has not been a big deal. Knowing if something goes wrong I would have to start them all again however is a different story. I went looking for a way to configure all the apps in a single config file. Of course pm2 has such a feature and I found the Application declaration documentation. Below are the important bits, including a snippet for another app just to demonstrate how you can configure multiple apps. I added the JSON below in a file called process.json.

{
    "apps": [
        {
            "name": "angular",
            "cwd": "/var/www/ng2.cooldomain.com",
            "args": "-p 8080 -d false",
            "script": "/root/.nvm/v4.2.6/bin/http-server"
        },
        {
            "name": "api",
            "cwd": "/var/www/api.cooldomain.com",
            "script": "app.js",
            "watch": true
        }
    ]
}

With all that out of the way I was finally able to test it all out:

pm2 start /path/to/process.json

Wrap-up

I am happy everything is up and running, but please ping me with suggestions on improving my setup. It’s not like I’m running anything important, so a true production setup isn’t required. However, I will say that I went through all this just to deploy a simple flash card game for my nine-year-old son. The app took me less than 30-minutes to write. The server setup and this post took me considerably longer.


  1. Are apps ever done?

  2. I am sure I can add some more clever bits to do some caching and gzip’ing, but I have to save something to learn later.