Deploy a Meteor App to Digital Ocean in 8 Steps — Ubuntu 14.04

William JC. Lee
Oct 11, 2015 · 7 min read

If you type quick.

Image for post
Image for post

We will be using Phusion Passenger.

Scroll down if you want to skip to the tutorial

Bulid : Ubuntu 14.04

Host : Digital Ocean

Phusion Passenger™ is an open source, polyglot (multi-language) application server. It takes a lot of complexity out of deploying Meteor, and adds powerful enterprise-grade features that are useful in production. It also makes it administering Meteor apps much easier. It has already done this for Ruby, Python and Node.js, and is being used by high-profile companies such as Apple, Pixar, New York Times, AirBnB, Juniper etc as well as over 350.000 websites.

Why use Meteor on Passenger?

The power of Nginx
Phusion Passenger combines Meteor with the increasingly popular Nginx web server. By combining them, Nginx will offload Meteor from serving static assets. This also adds a buffering reverse proxy layer which provides I/O security and protects Meteor against invalid HTTP requests, slow clients, etc. It will even allow you to use SSL without having to code explicit SSL support in your Node app.

Nginx isn’t the only thing supported though. Passenger also supports Apache, and can even run standalone without needing an existing web server.

Run multiple Meteor applications on a single server easily and without hassle.

Process management and supervision
Meteor processes are automatically started, and automatically restarted when they crash.

Statistics and insight
Phusion Passenger provides tools for inspecting the applications’ status, such what requests they’re currently processing, how many requests they’ve processed.

Scaling and load balancing
Based on current traffic, Phusion Passenger can spawn more Meteor processes to handle the load, or spin down some existing Meteor processes to conserve resources. Phusion Passenger automatically load balances traffic across Meteor processes. The load balancing mechanism utilizes a smart “first-available” selection algorithm to avoid problems caused by slow requests. Although Node.js — and thus Meteor — is single-threaded, this approach allows you to utilize multiple CPU cores.

I/O security
Meteor is automatically put behind a buffering web server, such as Nginx or Apache, which preprocesses and postprocesses HTTP requests and responses. This protects the Meteor app against slow-client attacks such as Slowloris. It also provides a secure environment which sanitizes HTTP headers, to protect against vulnerabilities in the app’s HTTP parser.

System security
Meteor processes are automatically started as the user which owns the app. This allows the OS to separate their privileges, so that a vulnerability in one app does not affect another.

Static file acceleration
Static files are directly served by the web server (Nginx/Apache), not by Meteor. This offloads the Meteor application from handling those things.

How does Passenger work?

Image for post
Image for post

Now the step-by-step instructions to bring your Meteor to life!

STEP 1 — Install Node.js

$ sudo apt-get update$ sudo apt-get install -y curl apt-transport-https ca-certificates &&
curl --fail -ssL -o setup-nodejs &&
sudo bash setup-nodejs &&
$ sudo apt-get install -y nodejs build-essential

STEP 2 — Install Passenger

$ sudo apt-key adv --keyserver hkp:// --recv-keys 561F9B9CAC40B2F7$ sudo apt-get install -y apt-transport-https ca-certificates
# Add our APT repository
$ sudo sh -c 'echo deb trusty main > /etc/apt/sources.list.d/passenger.list'
$ sudo apt-get update
# Install Passenger + Nginx
$ sudo apt-get install -y nginx-extras passenger

STEP 3—Enable Passenger

$ Nano /etc/nginx/nginx.conf

Then, uncomment passenger_root and passenger_ruby. For example, you may see this:

# passenger_root /some-filename/locations.ini;
# passenger_ruby /usr/bin/passenger_free_ruby;

remove the “# ” characters like this

passenger_root /some-filename/locations.ini;
passenger_ruby /usr/bin/passenger_free_ruby;

restart nginx

$ sudo service nginx restart

STEP 4— Build a meteor bundle of your app

$ meteor bundle package.tar.gz

Meteor will probably tell you that meteor bundle is deprecated in favor of meteor build. Please ignore that message, because for the purpose of running a Meteor web application on Passenger, only `meteor bundle` does what we want.

Copy the package to your production server, for example using scp:

local-computer$ scp package.tar.gz

Login to your server with SSH and create a user for your app.

$ ssh

Replace adminuser with the name of an account with administrator privileges or sudo privileges.

STEP 5— Upload package to server

Starting from this point, unless stated otherwise, all commands that we instruct you to run should be run on the server, not on your local computer!

You should give the user account the same name as your app. But for demonstration purposes, this tutorial names the user account myappuser.

$ sudo adduser myappuser

Make sure the user has your SSH key installed:

$ sudo mkdir -p ~myappuser/.ssh$ sudo sh -c "cat $HOME/.ssh/authorized_keys >> ~myappuser/.ssh/authorized_keys"$ sudo chown -R myappuser: ~myappuser/.ssh$ sudo chmod 700 ~myappuser/.ssh$ sudo sh -c "chmod 600 ~myappuser/.ssh/*"

Now, extract your package to a permanent location on your server.

A good location is/var/www/APP_NAME. Let us create that directory.

$ sudo mkdir -p /var/www/myapp$ cd /var/www/myapp$ tar xzf ~/package.tar.gz$ chown -R myappuser: .

Your extract app package directory now lives on the server at /var/www/myapp/bundle.

STEP 6 — Preparing the app’s environment

$ sudo apt-get install -y mongodb

Login as the app’s user

$ sudo -u myappuser -H bash -l

Install app dependencies

$ cd /var/www/myapp/bundle/programs/server$ npm install --production

Step 7 — Configuring Nginx and Passenger


# Type `exit` to go back to the account you were before
myappuser$ exit
admin$ _

Edit Nginx configuration file

$ sudo nano /etc/nginx/sites-enabled/myapp.conf

Remember to replace myapp to your app’s name

Put this inside the file:

server {
listen 80;

# Tell Nginx and Passenger where your app's 'public' directory is
root /var/www/myapp/bundle/public;

# Turn on Passenger
passenger_enabled on;
# Tell Passenger that your app is a Meteor app
passenger_app_type node;
passenger_startup_file main.js;

# Tell your app where MongoDB is
passenger_env_var MONGO_URL mongodb://localhost:27017/myappdb;
# Tell your app what its root URL is
passenger_env_var ROOT_URL;

Replace with your server’s host name and replace /var/www/myapp/bundle with your application’s package directory path. Replace myappdb with an appropriate MongoDB database name. Also be sure to set ROOT_URL to an appropriate value.

Restart nginx

$ sudo service nginx restart

Step 8 — Test!

$ curl

If you do not see your app’s front page HTML, then these are the most likely causes:

  1. You did not correctly configure your server_name directive. The server_name must exactly match the host name in the URL. For example, if you use the command curl to access your app, then the server_name must be
  2. You did not setup DNS records. Setting up DNS is outside the scope of this walkthrough. In the mean time, we recommend that you use your server’s IP address as the server name.

Congratulations, you have successfully deployed your Meteor app on to Digital Ocean.

Deploying Updates — Transferring latest code

Inside your application’s code directory, on your local computer, use the meteor bundle command to create a Meteor package tarball of the latest application code.

local-computer$ meteor bundle package.tar.gz

Copy the package to your production server, for example using scp:

local-computer$ scp package.tar.gz

Replace myappuser with name of the application’s OS user account.

Login to the server as the application’s user

Login to your server with SSH:

local-computer$ ssh

Replace myappuser with name of the application’s OS user account.

Starting from this point, unless stated otherwise, all commands that we instruct you to run should be run on the server, not on your local computer!

Extract package

Extract the package to a temporary location, for example /var/www/yourapp/tmp.

$ mkdir -p /var/www/myapp/tmp$ cd /var/www/myapp/tmp$ tar xzf ~/package.tar.gz

Replace myapp and myappuser with your app’s name and your app user account’s name.

The extracted package is now located in /var/www/myapp/tmp/bundle.

Prepare application

Your application’s npm dependencies may have changed, so we should install any updated npm dependencies while removing any now-extraneous dependencies. Run:

$ cd /var/www/myapp/tmp/bundle/programs/server$ npm install --production$ npm prune --production

Activate application updates

Rename the old application directory to something different, and move the new application directory to where the old application directory was:

$ mv /var/www/myapp/bundle /var/www/myapp/bundle.old
$ mv /var/www/myapp/tmp/bundle /var/www/myapp/bundle

Tell Passenger to restart the application so that the updates take effect.

$ passenger-config restart-app /var/www/myapp/bundle

Wait a few seconds (for Passenger to do its job), then remove the old application directory:

$ rm -rf /var/www/myapp/bundle.old

Congratulations! You did it!

Now to celebrate, spread the Meteor!

Sourced from Phusion Passenger and Various other Tutorials and Guides.

More Stuff!!!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store