Over the past few months I've found myself spinning up tons of new servers and walking through the process of pushing express apps live.

Because this process always comes at unexpected times, I've never bothered documenting the steps it takes to get a blank box running express. Surprisingly it seems as though few have bothered to walk through every step involved in a single place, and most express tutorials contain outdated information which likely leads to headaches for newcomers.

I'll be walking through an ExpressJS setup with the tech I always opt for.


  • NodeJS
  • NPM
  • Nginx
  • Express
  • Express-Generator
  • Sass
  • Handlebars
  • PM2
  • Grunt


Prep your server by installing the latest updates:

$ apt-get update
$ apt-get upgrade -y


Of the things we'll be installing prior to development, NodeJS is the trickiest. Unlike other packages, we cannot simply use Ubuntu's apt-get install command for Node. NodeJS for Linux distributions is best installed via NodeSource, which is handled as such:

$ apt update
$ apt upgrade -y
$ curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
$ sudo apt-get install -y nodejs
$ sudo apt-get install gcc g++ make
$ sudo npm install -g npm@latest

Note that this also hooks us up with the latest version of NPM, so we're all good on that front.


Let's install Nginx before we forget. We'll come back to Nginx later to set up the config.

apt-get install nginx


We'll install express globally. This way we can support multiple apps running express, as well as use an express generator to easily create more projects down the line.

npm install -g express

Express generator

Install express generator globally. Express generator is the easiest way to set up a new express app with the standard structure preconfigured.

npm install -g express-generator

Create an App

Now we get to the fun stuff.

$ cd to the directory you'll be using to contain your apps, such as /home or /var/www. When we use express-generator in this directory, we'll be initializing a new express project will most of the common boilerplate setup preconfigured.

This will create your Express app inside /home/myapp:

cd /home

express --view=hbs --css=less myapp

Express-generator prompts you to pass arguments to automatically configure your project for you. We're able to specify which CSS preprocessor and templating system we prefer this way. I'm going to create a project using Handlebars and Sass as my weapons of choice.

These are the options that come with express-generator in case you'd like to customize your installation:

$ express -h

  Usage: express [options] [dir]


    -h, --help          output usage information
        --version       output the version number
    -e, --ejs           add ejs engine support
        --hbs           add handlebars engine support
        --pug           add pug engine support
    -H, --hogan         add hogan.js engine support
    -v, --view <engine> add view <engine> support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
    -c, --css <engine>  add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
        --git           add .gitignore
    -f, --force         force on non-empty directory

Warning: common bug ahead

If your life sucks, running express generator may have given you this error:

/usr/bin/env: ‘node’: No such file or directory

This is an issue with Debian distributions of linux which treat 'node' and 'nodejs' as separate filepaths. To alleviate this, create the following symbolic link:

ln -s /usr/bin/nodejs /usr/bin/node

Start App

Inside your project directory run npm install to install all dependancies for your project. This will look at the package.json file that express-generator created and will install the corresponding node modules.

cd myapp

npm install

Here's the result:

├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.pug
    ├── index.pug
    └── layout.pug

7 directories, 9 files

Set up Nginx Config

Before creating your Nginx config, it is best to verify which port express will be running on. In most recent versions of express, this can be found in the www file. The path to this looks like myapp/bin/www.

Check out that file and see what the value is for var port.

vim bin/www

You should see something like this:

var port = normalizePort(process.env.PORT || '3000');

Thus, the port is 3000. Remember this.

Previously this information was stored in Express's app.js file.

Now, create a Nginx config in sites-available:

vim /etc/nginx/sites-available/myapp

For a basic reverse proxy server configuration, use the configuration below.

Be sure to replace the port with the port you found earlier.

server {
    listen 80;

    server_name example.com www.example.com;

    location / {
        proxy_pass; #Replace port here
        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;

    location ~ /.well-known {
        allow all;

    client_max_body_size 50m;

Save this out. Now create a symbolic link to have this appear in sites enabled, and restart Nginx.

ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp 

service nginx restart

Run your app

Now your web server is pointing to the correct place, but your app isn't actually running. To keep your app running continuously, we'll use PM2.

Install pm2 globally:

npm install pm2 -g

Go to your app's directory, and start your app using PM2:

cd /home/myapp

pm2 start bin/www

If successful, PM2 should then list your app as running.

You can run as many express apps on one server as you like:

│ App name │ id │ mode │ pid   │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
│ www      │ 0  │ fork │ 8953  │ online │ 79      │ 35h    │ 0%  │ 44.6 MB   │ root │ disabled │
│ www      │ 1  │ fork │ 18195 │ online │ 0       │ 3D     │ 0%  │ 22.3 MB   │ root │ disabled │
│ www      │ 2  │ fork │ 19990 │ online │ 0       │ 33h    │ 0%  │ 49.2 MB   │ root │ disabled │

Your app should now be accessible via your domain.

Final items

Your app is up and running, but you're not in the clear yet. To have things fully configured, you'll need to set up grunt or gulp to compress your source for production.

Configuring gulp files is a tutorial in its own right. Otherwise, you're good to go to serve static files directly out of the /public folder.