Host Multiple Meteor, and Ghost Instances on DigitalOcean

I currently have a couple of Ghost Blogs and Meteor instances running all on the same ($5) droplet on DigitalOcean. Yes I can be cheap, and since I know I'm not the only one, I thought I would share the knowledge.

I was able to accomplish this using Meteor Up for easy configuration and deploy, Nginx for reverse proxy, and Forever to start/stop Ghost.

Let's get started.

DigitalOcean Droplets

Head over to DigitalOcean and create a droplet with the Ubuntu 12 image. Create > Select Image > Linux Distribution > Ubuntu 12.04. The size of the Droplet is up to you, but I have found that even the $5 droplet goes a long way.

Meteor Up (MUP)

To install Meteor Up, simply do the following command in your terminal:

$ npm install mup -g

Once the installation is over, cd into your meteor application directory, and create a new director where we will create a MUP project.

$ mkdir .deploy/
$ cd .deploy
$ mup init

This will create 2 files, settings.json and mup.json, inside the .deploy/ directory.

If you are using version control, you may not want to check in .deploy/. If this is the case, simply add it to your .gitignore.

$ echo '.deploy/*' >> .gitignore

settings.json is where you put your meteor settings. if you don't have any, leave it empty:

{
 "public": {}
}

mup.json is where the configuration settings for our droplet goes. It should look a bit like this:

{
  // Server authentication info
  "servers": [
    {
      "host": "DROPLET_IP_ADDRESS",
      "username": "root",
      "password": "YOUR_PASSWORD_WAS_EMAILED_TO_YOU"
      // or pem file (ssh based authentication)
      "pem": "~/.ssh/id_rsa"
    }
  ],

  // Install MongoDB in the server, does not destroy local MongoDB on future setup
  "setupMongo": true,

  // WARNING: Node.js is required! Only skip if you already have Node.js installed on server.
  "setupNode": true,

  // WARNING: If nodeVersion omitted will setup 0.10.28 by default. Do not use v, only version number.
  "nodeVersion": "0.10.31",

  // Install PhantomJS in the server
  "setupPhantom": true,

  // Application name (No spaces)
  "appName": "YOUR_APP_NAME",

  // Location of app (local directory)
  "app": "../",

  // Configure environment
  "env": {
    "ROOT_URL": "http://YOUR_DOMAIN_NAME.com",
    "PORT": 3000
  },

  // Meteor Up checks if the app comes online just after the deployment
  // before mup checks that, it will wait for no. of seconds configured below
  "deployCheckWaitTime": 15
}

If you are using password-based authentication, you will need to install sshpass.

Once you have filled mup.json according to your droplet settings, and installed sshpass, we can start deployment.

You will need two commands for the first time deploy. Run these commands inside your .deploy/ directory, and that is it.

$ mup setup

and

$ mup deploy

If you have to deploy a second meteor app, repeat the process above (you don't have to re-run mup setup) but make sure to use a different port (i.e 3001).

At this point, you should be able to see your app running under http://YOUR_DOMAIN.com:3000. But I doubt any of you want to refer to your app that way "awesome app dot com colon 3000". So we are going to use Nginx to reverse proxy.

Nginx Reverse Proxy (meteor)

If you don't already have Nginx installed on your droplet, check out this great tutorial from DigitalOcean on how to install it.

If you do already have Nginx installed, ssh into your droplet and make sure it's at least version 1.3. Earlier version do not support websockets, and they are critical for your meteor app to run correctly.

$ nginx -v

Proceed once you have the correct version of Nginx.

Create a configuration file for each meteor application. I recommend you name them something meaningful, like your domain name.

$ cd /etc/nginx/conf.d/
$ vi your-domain-name.conf

Inside the configuration file, add the following:

server {  
 listen 80;
 server_name your-domain-name.com;

 location / {
    proxy_pass http://localhost:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
 }
}

Update the port accordingly.

Ghost

If you'd also like to host your ghost blog on the same droplet, you simply need to download and install ghost, and set up another nginx configuration file for the reverse proxying.

$ mkdir /var/www/
$ cd /var/www/
$ sudo wget https://ghost.org/zip/ghost-latest.zip  
$ unzip -d ghost ghost-latest.zip    
$ cd ghost/
$ sudo npm install --production

Once it is done installing, you need to setup ghost. Copy the config.example.js file as config.js and change the host to your droplet's IP.

$ cp config.example.js config.js  
$ sudo vi config.js

On your new Nginx configuration file, add this:

server {  
    listen 80;
    server_name BLOG_DOMAIN_NAME.com;
    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://DROPLET_IP_ADDRESS:2368;
    }
}

Make sure that the proxy_pass address port matches the port in your ghost config.js under production.

Forever to start & stop Ghost

Install Forever with npm install forever -g. cd into your ghost directory, and start ghost with NODE_ENV=production forever start index.js. You can stop ghost with forever stop index.js

If you power cycle your droplet, you will have to start ghost manual again - if anyone knows of a way about that, I would love to hear it. Mup will handle your meteor instances however.

That's all

I hope these information were useful to some of you. I would love to read your comments below.