#Meteor and Self-hosted Infrastructure
Meteor is an eye-opening JavaScript framework that runs on both the client and the server, giving developers a revolutionary take on software engineering. If you are not familiar with Meteor, I urge you to visit their website.
##An overview
In this brief gist, I am going to discuss the process of setting up a server (in my case, a VPS) to host Meteor applications.
My experience with Meteor has been brief, however it has not taken much demonstration for me to realise the significance of this stellar framework. Let's jump right in!
Disclaimer: This is by no means a production-ready guide for deploying Meteor applications to self-hosted infrastructure. It should get you started, though.
##The application stack
There are a number of key software components that will run on both your computer (i.e. a development machine) and the server that will be hosting your Meteor applications. These components include:
- Node Version Manager (NVM)
- Node.js
- Meteor
- Meteorite (if your application requires it)
- Git
On the server, I will be using Ubuntu Server 13.04 x86_64. In addition to the components above, the following will also run on Ubuntu:
On your development machine, in addition to the components above, you'll also be running:
##Our application
In this example, we'll be deploying a copy of the Leaderboard example on the Meteor website to your custom infrastructure.
##Preparing the server
###Package updates and additions
Assuming a fresh installation of Ubuntu Server 13.04 x86_64, the first thing to do is ensure that our system is completely up-to-date. SSH into the server as root
and run the following commands:
$ apt-get update && apt-get upgrade
Next, let's uninstall some packages that are included with Ubuntu by default that we don't need:
$ apt-get remove apache2 apache2-doc apache2-mpm-prefork apache2-utils apache2.2-bin apache2.2-common
Now that that's done, let's install some packages that we'll be using:
$ apt-get install curl nginx git mongodb
###Add a new user for deployment
It is definitely a good idea for us to run our Node.js instance as a non-root user. Let's create a new user with the username meteor
for our purposes:
$ adduser meteor
###Give our new user some power
Upstart, the service manager that we'll be relying on to keep Node.js running, provides a number of system commands for administering services. We're interested in start
, stop
and restart
.
These are the commands that Meteor Deployment Manager uses to manage the Node.js service, so the meteor
user should have limited access to use them. We don't want meteor
to be able to administer other system services, so let's specify exactly which commands the meteor
user is able to execute.
In order to do this, we are going to permit the meteor
user to run certain commands using the sudoers
file. The sudoers
file includes any files that are found within /etc/sudoers.d/
, so let's add a new file there. Since we'll be hosting and deploying the Leaderboard example, let's call the file leaderboard
.
$ touch /etc/sudoers.d/leaderboard
Next, let's add a rule to this file, explicitly allowing the meteor
user to access the following commands:
start leaderboard
stop leaderboard
restart leaderboard
start
, stop
and restart
are all located in the /sbin/
directory.
$ echo "meteor ALL = (root) NOPASSWD: /sbin/start leaderboard, /sbin/stop leaderboard, /sbin/restart leaderboard" > /etc/sudoers.d/leaderboard
###MongoDB
After running apt-get install mongodb
above, MongoDB should already be running. All we need to do is add the URL of the local MongoDB instance to the system path so that it is accessible by Meteor.
Run the following command to add the relevant URL to the system path:
$ echo 'MONGO_URL="mongodb://localhost:27017"' >> /etc/environment
###Nginx
Non-root users may not bind to ports lower than 1025. This means that in order to run Node.js directly, we'd need to build it to port 80 as the root
user. This poses a number of security threats that are beyond the scope of this gist.
One solution, which offers some other benefits, is to use nginx as a proxy. This solution involves binding nginx to port 80, running as root. Node.js is bound to a port above 1024, and nginx is configured to transparently route any traffic to port 80 through to Node.js.
Decide on a port for your application. I've used port 2000 in this example.
Nginx should be installed and running after we ran apt-get install nginx
above. Let's replace the configuration file to suit our requirements. I've uploaded a sample configuration file here. The nginx system configration file is located at /etc/nginx/nginx.conf
. After replacing the configration file, we'll restart nginx.
Run the following commands to back up your existing nginx.conf
file and download the sample:
$ mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf_backup
$ curl https://gist.github.com/chriswessels/6515786/raw/18f14dc33284e1231055ee632f3ae780d4e4af1b/nginx.conf >> /etc/nginx/nginx.conf
Edit the new configuration file to suit your requirements, then run:
$ service nginx restart
###Adding the Upstart configuration script
Upstart is the service manager that we're going to be using to monitor Node.js. Upstart jobs are configured as files in /etc/init/
. I've uploaded a sample configuration script here.
To download it, issue the following command:
$ curl https://gist.github.com/chriswessels/6515635/raw/b5e6ddab49cc465c06b4282734e34d5781fd27f3/leaderboard.conf >> /etc/init/leaderboard.conf
Looking near the top of the file, you will see the following lines:
env APP_NAME='leaderboard'
env PORT='2000'
env ROOT_URL='http://www.your-app.com'
env NODE_BIN='/home/meteor/.nvm/v0.8.24/bin'
You should edit these lines to match your requirements. These configure the instance of Node.js. This sample script will attempt to launch an instance of your application located at /home/meteor/leaderboard/builds/current
. This is where Meteor Deployment Manager (MDM) places the latest build.
###Log in as the meteor user
At this point you can logout
of your SSH session and log in as the meteor
user we just created. This is to prevent unwanted, unintentional file permissions when touching files as root.
###Install Node Version Manager and Node.js
Back? Great. Let's install Node Version Manager (NVM) so that we can maintain multiple versions of Node.js on the server. The install script NVM provides is not sufficient for our purposes, so install NVM using the following commands:
$ git clone https://github.com/creationix/nvm.git ~/.nvm
$ sed -i -e '1i [[ -s $HOME/.nvm/nvm.sh ]] && . $HOME/.nvm/nvm.sh' ~/.bashrc
$ source ~/.bashrc
Now that we've got NVM, let's install Node.js. We're going to install version 0.8.24, because that's what Meteor is tested against at this point. We're also going to make version 0.8.24 the default Node.js.
$ nvm install 0.8.24 && nvm alias default 0.8.24
###Install Meteor and add it to the user PATH
Let's install Meteor:
$ curl https://install.meteor.com | sh
This will succeed, however it will display a warning saying that the meteor
user doesn't have privileges to copy the meteor executable into a folder that is in the PATH environment variable. This is fine, because we can add it into the PATH environment variable for the meteor
user, rather than adding it system wide.
Run the following command to append /home/meteor/.meteor
to your PATH for the meteor
user:
$ sed -i -e '1i PATH="$PATH:/home/meteor/.meteor"' ~/.bashrc
$ source ~/.bashrc
At this point you should be able to run the command below with successful output:
$ meteor --version
If you're using Meteorite, now would be a good time to run:
$ npm install -g meteorite
Now that the server is prepared to run Node.js (and therefore Meteor) applications, let's set up the project for hosting and automated deployment.
###Create the project's directory structure
Since we're going to be using MDM on our development computers for automated deployment, we need to set up a server-side directory structure that conforms to what MDM is expecting.
NB: MDM is still in alpha stages, so please look at the project's README file for the latest information.
Using the commands below, we're going to create the directory structure expected by MDM. We're also going to create a log directory that we can use later:
$ cd ~ && pwd
-> /home/meteor
$ mkdir leaderboard && cd leaderboard && pwd
-> /home/meteor/leaderboard
$ mkdir builds log source working && ls
-> builds log source working
Now that we have the directory structure in place, we can check out the source code code for our project. This should be done in the source
directory. MDM expects an origin
remote to be present.
$ cd source
$ git init
$ git remote add origin https://github.com/chriswessels/meteor-leaderboard-example
$ git pull origin master
...and that's it!
##Setting up your development machine
I'm going to assume that you have the following up and running on your local development machine:
- Node.js (recommended: via NVM)
- Git
- Meteor
- Meteorite (if your application requires it)
Navigate to your project folder and install MDM using the following commands:
$ cd ~/meteor-leaderboard-example
$ npm install -g meteor-deployment-manager
This will install Meteor Deployment Manager and make it available in your system path as the mdm
command.
###MDM deployment configuration file
Once MDM is installed, execute:
$ mdm generate
This will generate a sample deploy.json
deployment configuration file in the current working directory.
Edit the file to suit your requirements. Mine looked something like this after I edited it:
{
"options": {
"meteorite": false,
"insecure": false,
"meteorRelease": "0.6.5.1"
},
"environments": {
"staging": {
"hostname": "staging.your-app.com",
"port": 22,
"username": "meteor",
"password": "secure-password",
"deploymentDirectory": "leaderboard",
"gitBranch": "master",
"taskName": "leaderboard"
}
}
}
taskName
should match the Upstart configuration file name (without the .conf
extension). deploymentDirectory
should be the directory to deploy to relative to ~
.
###Deploying with MDM
Whether you're deploying for the first time, or making updates to an application that is already online, MDM makes deploying easy!
- Make sure that your latest changes have been pushed to the
origin
remote via Git. - Run
mdm deploy
.
$ pwd
-> /Users/chriswessels/meteor-leadership-example
$ git push origin master
$ mdm deploy
MDM will now attempt to connect to your server via SSH and perform the necessary actions to deploy your latest changes. If you get an error when MDM attempts to restart Node.js, try running:
$ mdm start
##Todo
The following sections of this gist need creation or improvement:
- Blocking port 2000 with UFW on Ubuntu.
- A more comprehensive todo list.
##Contributions
- Fork this gist.
- Submit a pull request with a sane commit message.
where do we install mdm? in local machine or remote?
I installed in local machine and it throught "mdm: command no found" error