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.


Installing Dependencies

Prep your server by installing the latest updates:

$ apt-get update
$ apt-get upgrade -y
Update packages


Installing NodeJS is a bit tricky on Debian-based systems (like Ubuntu). NodeJS is best built from nodesource, which provides access to binary distributions of Node for free. Find the version of Node you'd like to install from the nodesource Github repository and install as such:

$ curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
$ sudo apt-get install -y nodejs
$ sudo apt-get install gcc g++ make
$ sudo npm install -g npm@latest
Install Node and NPM

We also run sudo npm install -g npm@latest to get the latest version of NPM for our version of Node, which means we're all set up from the Node side.


Nginx will be our webserver of choice to serve our app to users over HTTP. Well install this now, but come back to configuring this later:

$ sudo apt-get install nginx
Install NGINX

Express & Express Generator

The Express NPM package contains the entirety of the ExpressJS framework, which we'll install globally on our system by passing the -g flag. We'll also install Express-Generator, which is a useful CLI for starting up Express apps:

$ npm install -g express
$ npm install -g express-generator
Install Express

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.

We're going to start our app in /var/www/ by navigating to that directory and kicking off express-generator:

$ cd /var/www
$ express --view=hbs --css=less myapp
Start myapp project

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 LESS as my weapons of choice, but your choice of templating engine and style preprocessor is entirely up to you. Running $ express -h will give you a full breakdown of these options, as well as a few other helpful commands such as adding a .gitignore file:

$ 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
express-generator options

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 don't recognize node as an alias for nodejs. To alleviate this, create the following symbolic link:

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

Start Building Your 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 /var/www/myapp
$ npm install
Install NPM libraries

The contest of your app's directory should be structured as so:

├── 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

Configuring Nginx

You now have a neat little Javascript app that you can go nuts in, but there's one small problem: nobody from the outside world will actually be able to access your app until you configure a webserver like Nginx to serve your app. Nginx listens for incoming traffic to your server and and serves apps depending on which domain users are hitting your server on.  

Before creating your Nginx config, it is best to verify which port express will be running on. The entry point of modern ExpressJS apps is a file known as /bin/www, which is the file Nginx looks for to kickstart your app. Check out that file and look for the port variable, so we know which port our app is listening on:

vim /var/www/myapp/bin/www

Near the top of the file, you should see something like this:


 * Get port from environment and store in Express.

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


This tells us that our app will be running on port 3000, which is typically the standard. Now that we have this information, we can configure Nginx by creating a config file for our app:

vim /etc/nginx/sites-available/myapp.conf
NGINX config

Express is best served by Nginx via a reverse proxy, but don't worry about what that means: just make sure server_name reflects your actual domain name, and that proxy_pass contains the correct port number:

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;

With that file saved, there are only two commands left to have Nginx fully set up. I'm not sure how much you care to learn about Nginx or understand what's actually happening below, but I'll assume most people don't:

$ sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/myapp.conf 
$ sudo service nginx restart
Restart Nginx

Nginx is now ready and pointing to your app! Your app isn't running yet though, so let's take care of that.

Run Your App

The most simple way to run your app immediately is by running npm run start in your project folder, but this won't do the trick if we want a persistent application. Starting your app with npm run start will only keep your app running as long as you're active in the terminal, as opposed to running it in the background forever. To keep your app running continuously, we'll use a tool called PM2:

$ npm install pm2 -g
Install PM2

PM2 allows you to run as many NodeJS apps as you want at once, and they won't end unless you force them to (or some fatal crash happens). Start your app with PM2:

$ pm2 start /var/www/myapp/bin/www
Start app with PM2 daemon

Your app should now be running and accessible on your server! To check which apps PM2 has running, enter $ pm2 list:

│ 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 │

Final items

Congrats on setting up your first ExpressJS app! If you're new to this sort of thing, the next logical step for you would be to look into tools for preparing your code for production, such as grunt or webpack. Otherwise, you're good to go to serve static files directly out of the /public folder.