Yes, this is possible.  DigitalOcean is a great and cost effective way to upgrade from hobby services like Heroku.  However, be aware that a good amount of DevOps work involved to do this.  

The DigitalOcean documents are really great, but they didn't fully cover everything that I was trying to achieve (i.e. multiple node apps, 1 droplet, and Cloudflare).

Hence, here's a tutorial for how to set this up.



Prerequisites



Installing Node.js

DigitalOcean has a nice tutorial for this, and taking a look can be helpful: https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-16-04

However, I needed to do things a little differently, as I was not making a new Node.js app and instead was migrating existing apps.  

First, install the NodeSource PPA.  From the home directory run:

cd ~
curl -sL https://deb.nodesource.com/setup_6.x -o nodesource_setup.sh

Run the script as sudo:

sudo bash nodesource_setup.sh

Next, install the Node.js package (with NPM):

sudo apt-get install nodejs

You will need to install the build-essential package:

sudo apt-get install build-essential

Now Node.js is installed!



Migrating Your App

Start by cloning your app to the remote server:

git clone [your app]

Check to make sure your ports are defined in your Nodejs main server file (they may not be as Heroku CLI does not need them).  Your server file should have the following lines added somewhere after your Express app is defined:

var app = express(); // You probably have this line

// You may not have these lines.  If not, add them
var https = require('https');
var http = require('http');
http.createServer(app).listen(process.env.PORT, 'localhost');

I'm using environment variables to set the PORT for each app, and will share where to store your environment variables in the next section.



Install PM2

PM2 is a process manager for Node.js that can be used to run your apps.

Install PM2 with the following command:

sudo npm install -g pm2

PM2 will let you run you app with simple start and stop commands:

pm2 start your-node-app.js //Starts your app
pm2 stop your-node-app.js //Stops your app

It's also worth getting familiar with all that PM2 can do.  You can review the docs here: http://pm2.keymetrics.io/

Before starting your app, we need to setup the PM2 environment.  You can generate a default environment file with the below command:

pm2 ecosystem

This will create a generic ecosystem.config.js file.  Most of what's inside can be deleted, but nice to view.  

Important: This file will house all of your environment variables, so you'll definitely want to gitignore it:

nano .gitignore

Add ecosystem.config.js to the ignore list and save the file.

Now let's open the config file:

nano ecosystem.config.js

You will want to at least define the app name, script, and environment variables.  You'll also likely want to set auto-restart to true in case your app crashes.  Here's a basic setup:


module.exports = {
        apps : [{
                name: 'Your App Name',
                script: 'your-node-app.js',
                autorestart: true,
                watch: false,
                max_memory_restart: '1G',
                env: {
                        NODE_ENV: 'development',
                        // Add all development environment variables here
                        PORT: '8080' // will be different for each app
                },
                env_production: {
                        NODE_ENV: 'production',
                        // Add all production environment variables here
                        PORT: '8080' // will be different for each app
                }
        }]
};

Note, in the above file that you will add all of your environment variables here.  

Also, note that each app will have a unique port, and you will setup this file for each app.  Hence, when you transfer your next app, you can use port 8081, for example.

Save the file after adding all of your environment variables.

You can now start your app in production mode with the following command:

pm2 start ecosystem.config.js --env production

Note --env production will start the app using the production environment variables.  Without this, your app will default to running in development mode.



Configuring Nginx

Nginx will route your local ports to your DNS.  The default configuration can be viewed with the following:

sudo nano /etc/nginx/sites-available/default

You will want to setup similar config files for each of your domains.  Let's make one for your first app (replace "your-app" with your app name):

sudo nano /etc/nginx/sites-available/your-app.com

Below is how to configure this for Nodejs (without SSL). We'll setup SSL in the next section.  

Note, the server_name which should be set to your domains.  Also, the proxy_pass has your port number for this app.  You will create a config file for each of your apps, and these values will change for each app to match the domain and port for your apps.

# Your App Config
server {
        listen 80;
        listen [::]:80;
        server_name your-app.com www.your-app.com;

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

Save your file when done.

Next, enable the file with the following command (again, replacing "your-app" with your app name):

sudo ln -s /etc/nginx/sites-available/your-app.com /etc/nginx/sites-enabled/


Setup Your DNS on Cloudflare

In order to host through cloudflare, you will us A names to route your hosting.

Log into Cloudflare and go to the "DNS" tab.  Delete any old records for where you want to host the app, and add new A name entries:

Name:  ex your-app.com ,  www , or  your-subdomain

Value: Your DigitalOcean droplet IP - ex 68.180.000.000

Next, to setup SSL we'll need to verify your server.  In order to do this, ensure that Cloudflare can temporarily accept non-SSL traffic.  Navigate to the "Crypto" tab and ensure SSL is set to "Flexible" or "Off".



Install Certbot

DigitalOcean also has a nice tutorial for SSL here, however I had to do this a little differently as well.  For reference, you can check out their tutorial here: https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04

Here's how I setup my SSL certs:

Install certbot with the following command:

sudo add-apt-repository ppa:certbot/certbot

You'll need to press ENTER to accept.

sudo apt-get update

Next, install Certbot's Nginx package with apt-get.

sudo apt-get install python-certbot-nginx

Certbot is now installed.



Setup Your Firewall

Next we'll need to setup your firewall for all traffic.  Check your firewall with the following command:

sudo ufw status

From the prerequisite setup, it may look like this, meaning that only HTTP traffic is allowed to the web server:

OutputStatus: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
Nginx HTTP                 ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
Nginx HTTP (v6)            ALLOW       Anywhere (v6)

We'll want to add HTTPS traffic, by running the following:

sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'

Check your status again.  It should now look like this:

sudo ufw status
OutputStatus: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)


Setup SSL

Ensure your PM2 process is running.  Certbot will now take care of your certs by simply specifying your domains with a single command:

sudo certbot --nginx -d your-app.com -d www.your-app.com

Simply follow the command prompt to complete your cert.  Certbot is awesome as it will also automatically renew your certs!

You can verify that your app is now setup for SSL traffic by reviewing your Nginx configuration by typing the below command.  You should now see added lines provided by Certbot to listen over Port 443.

sudo nano /etc/nginx/sites-available/your-app.com

You should now reset Cloudflare Crypto SSL to "Full."



Final Wrap Up

Restart Nginx and pm2 for good measure:

sudo systemctl restart nginx
pm2 restart ecosystem.config.js --env production

Your first app should now be up and running!

For your remaining apps, you will need to re-follow several of the steps in this tutorial (skipping all of the installation steps).  In summary:

  • Clone your next app to your droplet
  • Create and enable a new Nginx configuration file for your app
  • Setup your app's DNS on Cloudflare
  • Create a new SSL cert for your app's domains with Certbot
  • Restart Nginx & PM2


Hope this helps. Happy Coding!