Pain-free Meteor.js App deployment with Digital Ocean & Namecheap
Feb, 2016
8 minutes read

I assume that, like me, you discovered the awesome Meteor framework and spent a few (several?) nights coding away and assembling a working version of a web application, which is now ready to be pushed to the rest of the world.

I also assume that, like me (back in the days) you don’t know much about web servers and domain hosts. I’ll also assume that you don’t want to spend a fortune on it (even if your hard-earned web application probably deserves it).

This guide will guide you through a very simple process of deploying your Meteor.js app to the vastness of the web for a modest price:

  • $5 a month for a Digital Ocean Server
  • $0.8 to $10 a year for a Namecheap domain
  • 30-ish minutes of your time (the most important currency!)

It’s a seemingly simple process and several guides have already being written about this task.

However, I personally faced some annoying issues when deploying my first little web-app trackburnr. I spent a glorious, sunny sunday afternoon to figuring them out — hopefully I can spare you the pain of doing that with this guide.

Create a server Droplet on Digital Ocean

You first need a web server to host your application in (unless you want to leave your computer on until the end of time and pray for no power cut-offs).  My weapon of choice is Digital Ocean. Use this affiliate link to sign up and you’ll get 10$ in credit — the equivalent of two free months of hosting. Neat.

Sign up and create a Droplet (their name for a server machine) with Ubuntu 14.04. The 5$ a month tier will do for now (you can resize the droplet at any moment afterwards — if your app is being used by a decent amount of loyal people it might be a good idea to bump it up to the 10$ one).

You’ll be emailed your droplets info (IP address and password) shortly afterwards. Write those in a napkin and keep it safe.

You can remotely access your new, personal server machine straight from your web browser by clicking the Console Access button in the Digital Ocean user dashboard. It’s a very bare-bone view, thought, and you won’t be able to copy-paste code in it.

I prefer using a SSH connection straight from your home machine. You can do this from a terminal on a Mac or Linux machine, or use the awesome cmder if you’re on Windows.

You can log on your droplet by typing ssh [username]@[droplet_ip_address] and confirm with your password.

Point a Namecheap domain to your server

You’ll likely want a shiny custom domain for your app. I have used Namecheap in the past and I’m happy with it — domains are cheap, the admin interface looks good and I have had no issues whatsoever.

Once you buy your domain, we’ll need to point it to your Droplet’s ID address. Digital Ocean’s guides advises you to move the DNS nameservers (DNS, or “Domain Name System”, is a naming system that is used to convert a server’s host name into an IP address.) from Namecheap to Digital Ocean to be able to manage them from Digital Ocean itself. 

However, this step takes a few days to propagate and I found that Namecheap’s management panel is just as good, and way quicker to see changes with. So we’ll stick with it.

Click on the Manage button of your domain and then Advanced DNS. Click Add New Record, choose A Record, and input @ as the Host and the Droplet’s IP address (xxx.xxx.xxx.xxx) as the Value. Leave TTL to automatic, and save all changes.

Navigate to http://yourdomain.com (this will be whatever domain you bought) and you should see the Droplet’s intro page, confirming that the DNS record is working fine.

Now go back to the Domain tab of your domain management page, and take a look at the Redirect Domain section. You should have a redirect setup, pointing from http://yourdomain.com to www.yourdomain.com. It means that it you visit the www-less address for your domain, you will be automatically redirected to the www one.

We want to reverse this. Change the source url of the redirect to www.yourdomain.com and the destination URL to http://yourdomain.com. This way when visiting the www version of the domain, you will be redirected to the www-less version.

We will shortly see why we need this specific setup. For now, let’s deploy our Meteor application to the server.

Setup and Deploy with mupx

There’s a little awesome package that will automatically deploy any Meteor apps this procedure for you called Meteor-Up.

Provided you have node.js installed on your development machine, you can get Meteor-Up by typing: npm install -g mupx.

Make sure you install the mupx version. You might have heard about Meteor-Up as mup, but that version is deprecated and no longer maintened. mupx is the up-to-date package currently in development. Navigate to your project directory and type mupx init.

This will create two files into your Meteor project directory: * mup.json — the Meteor Up configuration file * settings.json — Settings for Meteor’s settings API (We won’t touch this for now).

Let’s edit the mup.json file to set up our deployment settings:

{
  // Server authentication info
  "servers": [
    {
      "host": "dropletaddress",
      "username": "root",
      "password": "password",
      // or pem file (ssh based authentication)
      // WARNING: Keys protected by a passphrase are not supported
      //"pem": "~/.ssh/id_rsa"
      // Also, for non-standard ssh port use this
      //"sshOptions": { "port" : 49154 },
      // server specific environment variables
      "env": {}
    }
  ],

  // Install MongoDB on the server. Does not destroy the local MongoDB on future setups
  "setupMongo": true,

  // Application name (no spaces).
  "appName": "yourappname",

  // Location of app (local directory). This can reference '~' as the users home directory.
  // i.e., "app": "~/Meteor/my-app",
  // This is the same as the line below.
  "app": ".",

  // Configure environment
  // ROOT_URL must be set to your correct domain (https or http)
  "env": {
    "PORT": 3000,
    "ROOT_URL": "dropletaddress",
    "UPSTART_UID": "meteoruser",
    "ROOT_URL": "http://yourappname.com",
  },

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

  // show a progress bar while uploading.
  // Make it false when you deploy using a CI box.
  "enableUploadProgressBar": true
}

Make sure to change the settings accordingly to your setup, such as “host” and “ROOT_URL” to your Digital Ocean’s droplet IP address (http://xxx.xxx.xxx.xxx), “appName” to your application name, and “password” to your droplet’s password. Afterwards, run mupx setup to setup the server for the upcoming deployment — this step will install node.js, mongo and all the packages required by Meteor on the droplet.

Finally, run mupx deploy to package up your Meteor application and upload it to the server accordingly to to the mup.json settings we specified earlier. This will take a few minutes, so feel free to get a (small) burrito.

If mupx incurs into a Verifying deployment: FAILED error during deployment, it means that the app didn’t start in time for mupx to check if was deployed correctly (chances are it was). You can likely fix this by increasing deployCheckWaitTime to 120:

...
  // Meteor Up checks if the app comes online just after the deployment.
  // Before mup checks that, it will wait for the number of seconds configured below.
  "deployCheckWaitTime": 120,
...

After deploy is finish, navigate to yourdomain.com:3000 and you should be able to see your web app in action. However, we don’t want to type that ugly port number next to your shiny domain address, right? Next we’ll setup a tool called nginx to fix this.

Set up a reverse proxy with nginx

SSH back into your droplet, and type those commands to install nginx:

sudo apt-get update
sudo apt-get install nginx

If you navigate back to your domain, you should see the nginx welcome page. We’ll change nginx settings to set up a proper URL and remove the port addresses. We’ll do this by creating a file in the sites-available nginx folder sudo nano /etc/nginx/sites-available/yourappname.com.conf Then, paste those contents in:

server { 
    listen *:80; 
 
    server_name yourdomain.com; 
 
    access_log /var/log/nginx/app.dev.access.log; 
    error_log /var/log/nginx/app.dev.error.log;
    large_client_header_buffers 4 16k;
    location / { 
        proxy_pass http://127.0.0.1:3000; 
        proxy_http_version 1.1; 
        proxy_set_header Upgrade $http_upgrade; 
        proxy_set_header Connection ‘upgrade’; 
        proxy_set_header X-Forwarded-For $remote_addr; 
    } 
}

What this will do is forwarding any requests to http://yourdomain.com to http://yourdomain.com:3000, taking you to your web app. That’s why it was important to set up the redirection in Namecheap earlier — navigating to http://www.yourdomain.com would not have worked.

Save by the file by pressing Ctrl-X, typing Y and then pressing Enter. Then, enable your site by adding a symbolic link to your configuration in the nginx sites-enabled folder. You can do this by typing ln -s /etc/nginx/sites-available/yourappname.com.conf /etc/nginx/sites-enabled/yourappname.com.conf.

Afterwards, restart the nginx service by typing service nginx restart.

Navigate to http://yourdomain.com. You should be able to see your web app without the need of specifying the port 3000.

You might find yourself incurring in 400 Bad requests errors. It’s a somewhat common issue caused by the cookies data sent to your server being too big.  You can fix this by adding the large_client_header_buffers 4 16k line to the server tag in the nginx configuration file in sites-available:

server { 
    ...
    large_client_header_buffers 4 16k;
    location / { 
        .... 

Conclusion

This is the basic, bare-bone setup for deploying a Meteor app to a Digital Ocean server and going through the most common hiccups. There is a whole world of pain awaiting for you if you want to set up a SSL certificate, or having multiple websites and meteor applications on the same droplet. If I make it through it alive, I might tell you the story another time.


Back to posts


comments powered by Disqus