Deploying Secure Meteor Application with Test stage and Landing Page on Ubuntu and Apache including Continuous Integration deployment based on Gitlab. Part 1.

Deploying your own Meteor application is not so easy task when you have VPS like DigitalOcean. In this article I’m going to go step by step with full deployments steps. My assumptions are the following:

  • Our meteor.js app will be served from new Ubuntu 16 VPS Droplet, all components installation is going to be described here briefly.
  • Application code has repository in git with separation of production and development code, so only features tested and accepted in development branch are merged into production.
  • Continuous Integration is doing deploy to development from develop branch and to production from master branch automatically. In this case whole process is based on GitLab, but any other CI, like Travis or Jenkins can be used.

Whole system is divided into three main components:

  1. Static html page served from main domain, example.com
  2. Development stage server from meteor command on dev subdomain, dev.example.com
  3. Production node.js meteor build served on app subdomain app.example.com

Before We Begin

Thinks we should have:

  • Ubuntu (or other Linux) new instance with root access
  • Meteor application with codebase in git
  • Static landing page with codebase in git
  • Three domains attached to our machine IP number

Step 1 — Setting Up Server

Login to your server as root user.

ssh root@example.com

Firstly we should have updated package lists. Execute command:

apt-get update

Enabling swap

You should have swap space enabled, since meteor build command it quite consuming and event 2GB RAM might not be enough without swap.

Swap is an area on a hard drive that has been designated as a place where the operating system can temporarily store data that it can no longer hold in RAM. Basically, this gives you the ability to increase the amount of information that your server can keep in its working “memory”, with some caveats. The swap space on the hard drive will be used mainly when there is no longer sufficient space in RAM to hold in-use application data.

Here I’ll show briefy how to enable swap, on the bottom of this article I’ll provide links with whole process described. Swap size should be double of current RAM size. I have 2GB RAM, so will enable 4GB swap with executing following commands:

sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Installing Apache Web Server

Install Apache with default command.

sudo apt-get install apache2

Adjust your firewall settings so Apache expose its default ports.

sudo ufw allow ‘Apache Full’

Under all there domains and IP address now you should see default Ubuntu Apache Page

Installing meteor and its dependencies.

Node is essential for meteor, you should have check which version of current meteor is supported.

sudo apt-get install nodejs
sudo apt-get install npm

Update node to latest version

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash — sudo apt-get install -y nodejs

In order to prevent some random build errors we will install nodejs-legacy and for some npm packages that require compiling code from source we need essential-tools as well.

apt-get install nodejs-legacy
npm -g install n node-g
apt-get install build-essential

Install mongo database

apt-get install mongodb-server

Finally install meteor.js

curl https://install.meteor.com | /bin/sh

Most of setting server task is done, now lets switch to deploying meteor.app

Deploying meteor.js development stage application

The goal of this is to have a stage application when we test our features before publishing them on production server. This going to be served as simplemeteor command. Each code git pull will just refresh app with default hot code push.

Meter user

We should not be running meteor as root user, it is a good practice to run Meteor application as a regular user. Lets create a new system user specifically for that purpose:

adduser — disabled-login meteor

and switch to that user

su — meteor

SSH keys

We need SSH keys for pulling repository from git and future Continuous Integration processes.

ssh-keygen -t rsa -b 4096 -C “meteor@example.com”

Add public key to authorised_keys so we can login with that key with ssh and being able to clone our repository.

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

Copy public key to clipboard and put it to deploy keys in git.

cat ~/.ssh/id_rsa.pub

Now we’re ready to run the development version of our application

Meteor

Create an dev folder in meteor user home and clone there your repository

cd ~
mkdir dev
cd dev
git clone example@git.example.com .

Install npm dependencies

meteor npm install

Run meteor command

meteor

Now you should be able to see you application on port:3000 on each of domains, eg dev.example.com:3000

Mongo Database export from other machine.

Most likely your application needs an initial database records. Im going show you how to:

  1. export current database from local machine
  2. copy dump from local machine to remote server
  3. import database

Open your local machine two terminal windows.

For import and export meteor must be run in background, so you need two terminal windows.

Run meteor in one window and export in second terminal window with command

mongodump -h 127.0.0.1 — port 3001 -d meteor

which will create a dump folder on your local machine. Compress whole folder to one archive with tar gz or zip

tar -zcvf dump.tar.gz dump

which creates one file with database dump. Upload it to you remote home folder with command

scp dump.tar.gz root@example.com:~

That’s it, database backup is on remote server. Local machine terminal can be closed now.

Mongo database import

You should be able to see dump on you home folder. To import you must open second terminal window and in first meteor must be running.

In second window untar dump file with

tar -zxvf dump.tar.gz

and import database

mongorestore -h 127.0.0.1 — port 3001 -d meteor — drop dump/meteor

Now your app is filled with data and you can close second terminal window.

Meteor as linux service

We want to have this app to run in background without any fallback like pm2, nohub etc, but to run meteor as linux service, which is quite easy to achieve.

Lets create simplest shell script to run our app. The following examples is simplest by you can create more sophisticated start scripts easily.

cd ~/dev
nano start-dev.sh

and paste there contents

cd /home/meteor/dev
meteor

Add rights for file to be executable

chmod 0755 start-dev.sh

this file is starting script for you service.

Creating a service

Creating a service would require to be either in sudo group or to be root. Switch back to root account with

su — root

and create you service description with

nano /etc/systemd/system/example-dev.service

which open editor, and put there simplest service definition

[Unit]
Description=example-dev
[Service]
User=meteor
Type=simple
WorkingDirectory=/home/meteor/dev
ExecStart=/bin/bash -c “/home/meteor/dev/start-dev.sh”
Environment=”ROOT_URL=https://dev.example.com"
[Install]
WantedBy=multi-user.target

some more sophisticated examples are described by @jaaaco in his article listed in the resource section below.

Install, run and enable service on restart

systemctl daemon-reload
systemctl enable example-dev.service
systemctl start example-dev.service

to stop you app run

systemctl stop example-dev.service

to see current status and output from meter run

systemctl status example-dev.service

Now your application is running as service on port 3000.

VirtualHost and ReverseProxy

Our application runs on port 3000 but we want it to be accessible on dev.example.com on default ports (80 for http and 443 for https). It is achievable with ReverseProxy.

We need to install some additional Apache modules on root account (
su — root).

Add proxy modules to apache

a2enmod proxy
a2enmod proxy_http
a2enmod proxy_ajp
a2enmod rewrite
a2enmod deflate
a2enmod headers
a2enmod proxy_balancer
a2enmod proxy_connect
a2enmod proxy_html

Create a definition of your new virtual host

nano /etc/apache2/sites-available/dev.example.com.conf

with simplest definition of reverse proxy from port 3000 to 80

<VirtualHost *:80>
ServerName dev.example.com
ServerAdmin meteor@example.com
DocumentRoot /home/meteor/dev
ProxyRequests Off
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]
RewriteRule .* ws://localhost:3000%{REQUEST_URI} [P]
</VirtualHost>

Enable your new virtual host

a2ensite dev.example.com

and restart apache

service apache2 restart

your application should be under http://dev.example.com

Secure your app with HTTPS

HTTPS is a must for an application, for production live you should have brought some external signed certificates, but for development version free letsencrypt are just fine.

We need to install some additional Ubuntu modules on root account (
su — root).

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-apache

which installs python cert bot to manage you free certificates. Run it to generate you cerificates.

certbot — apache -d dev.example.com

and change to redirect all traffic to https. In case of generation error, please try to run certbot again.

Now you application appears under https://dev.example.com

Part 2

In Part 2 I’m going to describe

  • Continuous integration process of auto deployment of meteor with Gitlab
  • Deployment of landing page
  • Deployment of production application

Resources

  1. How To Add Swap Space on Ubuntu 16.04 on DigitalOcean
  2. How To Install the Apache Web Server on Ubuntu 16.04 on DigitalOcean
  3. How To Deploy a Meteor.js Application on Ubuntu 14.04 with Nginx on DigitalOcean
  4. Generating a new SSH key and adding it to the ssh-agent on GitHub
  5. GitLab and SSH keys
  6. Run Meteor App as a Service on Ubuntu
  7. How To Use Apache HTTP Server As Reverse-Proxy Using mod_proxy Extension on DigitalOcean
  8. Apache as reverse proxy for letsencrypt free https certificates
  9. How To Secure Apache with Let’s Encrypt on Ubuntu 16.04