Skip to content

Instantly share code, notes, and snippets.

@sunlee-newyork
Last active February 2, 2017 14:31
Show Gist options
  • Save sunlee-newyork/b4d2a57fd2bb44fdf5f8b7e0f0a5ff52 to your computer and use it in GitHub Desktop.
Save sunlee-newyork/b4d2a57fd2bb44fdf5f8b7e0f0a5ff52 to your computer and use it in GitHub Desktop.

Deploying A Meteor 1.4 App To DigitalOcean With MUP

Table of Content

  1. Introduction
  2. Droplet Setup
  3. Root/User Setup
  4. Domain Setup
  5. NGINX Setup
  6. HTTP Authentication (OPTIONAL)
  7. MUP Setup
  8. References

Introduction

This is a working instructional to deploy a Meteor 1.4 app with the following (as of January 8th, 2017):

  • DigitalOcean Ubuntu 16.04
  • Meteor 1.4.2.3
  • MUP (not MUPX)
  • MongoDB (local or remote)

The following are missing from this instructional (I aim to tackle these next):

  • SSL setup
  • Subdomains

This is Part 1 of the Meteor/MongoDB deployment instructions where we'll setup a production Meteor application with MongoDB. If you want a remote Mongo database, follow instructions here until Step 7 of Mup Setup at which point you'll break off to these instructions.

I concocted these instructions from a multitude of sources, but they're mostly verbatim from @jamiewilson's amazing gist tutorial with edits to the NGINX/MUP portion and addition of a remote MongoDB server. The purpose of a new instructional is to address some recent issues that stem from Meteor 1.4 + MUPX + default docker image + node version, and also to make myself feel better for the last 15 hours I spent chainsmoking and getting this s%&# to work. Said issues are linked below under References.

Please feel free to leave comments, questions, or edits as you see fit! I am by no means claiming to be an expert in anything. I just wanted to share a truly end-to-end working solution. Cheers!

Droplet Setup

  1. <chainsmoke>
  2. Login to DigitalOcean and create a droplet
  3. Select Ubuntu 16.04 distribution
  4. Add secret PEM key

Root/User Setup

  1. ssh root@xxx.xxx.xx.xxx
  2. adduser username
  3. Enter UNIX password and confirm
  4. gpasswd -a username sudo
  5. sudo visudo
  6. Replace %sudo ALL=(ALL) ALL with %sudo ALL=(ALL) NOPASSWD:ALL
  7. su - username
  8. mkdir .ssh
  9. chmod 700 .ssh
  10. nano .ssh/authorized_keys
  11. Copy your local dev SSH key with cat ~/.ssh/id_rsa.pub | pbcopy
  12. Save edit
  13. Restrict permissions with chmod 600 .ssh/authorized_keys
  14. Configure ssh config with nano /etc/ssh/sshd_config
  15. Change PermitRootLogin to: PermitRootLogin no
  16. exit
  17. Test user connection with ssh username@xxx.xxx.xx.xxx

Domain Setup

  1. Add the following domain registrar
    • ns1.digitalocean.com
    • ns2.digitalocean.com
    • ns3.digitalocean.com
  2. Log back in to DigitalOcean, go to Networking, and click on Domains
  3. Add a domain and select your DigitalOcean droplet in dropdown
  4. Add 2 A Records:
    • @ / xxx.xxx.xx.xxx
    • www / xxx.xxx.xx.xxx
  5. Add swap space (follow these instructions exactly)

NGINX Setup

  1. Log back in to Droplet server

  2. sudo apt-get update

  3. Install NGINX: sudo apt-get install nginx

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

  5. Add the following and save:

    # redirect www to non-www
    server {
        listen 80;
        # to redirect all subdomains use *.yourdomain.com instead of www.yourdomain.com
        server_name www.yourdomain.com;
        return 301 $scheme://yourdomain.com$request_uri;
    }
  6. sudo nano /etc/nginx/sites-available/yourappname.com.conf

  7. Add the following and save:

    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;
        location / {
            proxy_pass http://XXX.XXX.XX.XXX: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;
        }
    }
  8. Link the config file to sites-enabled: sudo ln -s /etc/nginx/sites-available/yourappname.com.conf /etc/nginx/sites-enabled/yourappname.com.conf

  9. Hide NGINX number: sudo nano /etc/nginx/nginx.conf

  10. Uncomment server_tokens off;

  11. Restart NGINX: sudo service nginx restart

  12. Test redirect: curl -I http://www.yourdomain.com

HTTP Authentication (OPTIONAL)

Follow these steps exactly if your app is not ready for public viewing and you want username/password login. When you get to Step 3, edits should occur in the /etc/nginx/sites-available/yourapp.com.conf file from Step 7 under NGINX Setup. See below:

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;
   location / {
       proxy_pass http://XXX.XXX.XX.XXX: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;
       auth_basic "Restricted"; // <-
       auth_basic_user_file /etc/nginx/.htpasswd; // <-
   }
}

MUP Setup

  1. npm install -g mup

  2. mkdir ~/mup-your-project-name (outside/separate from your actual project repo directory!!!)

  3. cd ~/mup-your-project-name

  4. mup init

  5. Copy your project's settings.json into MUP settings.json

  6. Make following edit to your mup.js file

    module.exports = {
      servers: {
        one: {
          host: 'yourdomain.com',
          username: 'your_droplet_username'
          pem: '~/.ssh/id_rsa'
          // password:
          // or leave blank for authenticate from ssh-agent
        }
      },
    
      meteor: {
        name: 'yourappnamewithoutspaces',
        path: '/local/path/to/your/app/repo',
        servers: {
          one: {}
        },
        buildOptions: {
          serverOnly: true,
        },
        env: {
          ROOT_URL: 'http://yourdomain.com',
          MONGO_URL: 'mongodb://localhost/meteor',
          PORT: 3000
        },
    
        docker: {
          image: 'abernix/meteord:base' // <- THIS IS IMPORTANT
        },
        deployCheckWaitTime: 60
      },
    
      mongo: {
        oplog: true,
        port: 27017,
        servers: {
          one: {},
        },
      },
    };
    • There may be an issue with your PEM key if it's passphrase encrypted. Then, do the following:

      eval "$(ssh-agent -s)"
      ssh-add ~/.ssh/id_rsa

      ...and then remove the following line from mup.js: // "pem": "~/.ssh/id_rsa"

    • At this point if you also want a separate remote MongoDB server, follow these instructions before moving on to the next step. Get the server up and running, and then come back and make the following edits to mup.js:

      module.exports = {
        servers: {
          one: {
            host: 'yourdomain.com',
            username: 'your_droplet_username'
            // pem: '~/.ssh/id_rsa'
            // password:
            // or leave blank for authenticate from ssh-agent
          }
        },
      
        meteor: {
          name: 'yourappnamewithoutspaces',
          path: '/local/path/to/your/app/repo',
          servers: {
            one: {}
          },
          buildOptions: {
            serverOnly: true,
          },
          env: {
            ROOT_URL: 'http://yourdomain.com',
            MONGO_URL: 'mongodb://username:password@xxx.xxx.xx.xxx:YOUR_DB_PORT_#/yourappdb',
            PORT: 3000
          },
      
          docker: {
            image: 'abernix/meteord:base'
          },
          deployCheckWaitTime: 60
        }
      };
  7. mup setup

  8. SSH back in to Droplet with username (not root) and run: sudo usermod -aG docker $(whoami)

  9. sudo reboot

  10. Back in MUP directory: mup deploy

  11. </chainsmoke>

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment