Meteor_deployment It's been a while since I last wrote here, hopefully I could get back to my weekly routine.

In the last month or so I've been working heavily with Meteor.

When it came to the stage of deploying to a test server, I decided to use a simple node server, without an extra layer of Nginx/Apache. Normally, to build a Meteor application, you run:

1
meteor build
This generates a tar.gz file with your compiled (-ish) application, which you could later extract to your production server.

After extracting, you'll have to run node main.js to start the application. This approach has 2 problems:

  • Dependencies - Some npm packages will have to be installed via running npm install under programs/server, this adds yet another step that has to be done for deployment.
  • No Logs - If we just run the application with node main.js we get no feedback on logs, there's also a problem of the server being shutdown if the parent shell is closed.

Seeing these potential problems, I've decided to build a script for deploying a Meteor application:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
PATH_TO_APP='../app'
echo "Building Meteor App to a directory..."
( cd ${PATH_TO_APP}; meteor build --directory . )
echo "Getting NPM packages for project"
( cd ${PATH_TO_APP}/bundle/programs/server; npm install )
echo "Copying start_server.sh and stop_server.sh scripts to app"
cp st*.sh ${PATH_TO_APP}/bundle/
echo "Creating tar.gz file (in the parent folder)"
( cd ${PATH_TO_APP}; tar -zcvf ../bundle_$(date +"%d_%m_%Y_T%H_%M_%S").tar.gz bundle )
echo "Removing Bundle Directory..."
rm -rf ${PATH_TO_APP}/bundle

As you can see, some commands are in parentheses, this spawns a sub-shell so we don't actually change the folder globally (more info). Let's go over this line-by-line (excluding the echo messages):

  • PATH_TO_APP='../app' - Define path to application (where the .meteor folder is located)
  • ( cd ${PATH_TO_APP}; meteor build --directory . ) - Build meteor app to a directory instead of a file
  • ( cd ${PATH_TO_APP}/bundle/programs/server; npm install ) - Install dependencies
  • cp st*.sh ${PATH_TO_APP}/bundle/ - Copy the start_server.sh and stop_server.sh scripts (more on those later)
  • ( cd ${PATH_TO_APP}; tar -zcvf ../bundle_$(date +"%d_%m_%Y_T%H_%M_%S").tar.gz bundle ) - Compress the file to a tar.gz, with the date & time added to the filename
  • rm -rf ${PATH_TO_APP}/bundle - Remove the bundle/ directory we generated earlier

This script works pretty well, and you end up having a more complete package. I have a separate scripts folder parallel to the application folder (this is why the PATH_TO_APP is ../app), this folder also holds the 2 running scripts: start_server.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
NODE_EXEC="nodejs"
if [ "$1" = "debug" ]; then
	NODE_EXEC="node-debug"
	echo 'Starting Server in Debug Mode...'
else
	echo 'Starting Server...'
fi
PORT=3000 \
MONGO_URL=mongodb://localhost:27017/meteor \
ROOT_URL=http://localhost:3000/ \
METEOR_SETTINGS="$(cat settings.json)" \
nohup $NODE_EXEC main.js > /var/log/nodejs.log 2>&1 &
echo $! > server_id.txt

Once again, line-by-line (excluding echo):

  • NODE_EXEC="nodejs" - Define the node executable file (could be node/nodejs)
  • if [ "$1" = "debug" ]; then - If the the first argument is "debug" (i.e. sh start_server.sh debug), run node-debug instead
  • PORT=3000 \ - Define port of the application to be 3000
  • MONGO_URL=mongodb://localhost:27017/meteor \ - Define Mongo URL (for DB)
  • ROOT_URL=http://localhost:3000/ \ - Define Root URL
  • METEOR_SETTINGS="$(cat settings.json)" \ - Define a settings file (if you're not using a custom one, feel free to remove this)
  • nohup $NODE_EXEC main.js >/var/log/nodejs.log 2>&1 & - Run the server with nohup (thus not closing if parent shell closes), move all output to /var/log/nodejs.log (make sure you have writing access to the file, otherwise choose another one)
  • echo $! > server_id.txt - Get the Server's Process ID (PID) and write it into server_id.txt (so stop_server.sh knows which PID to kill)

stop_server.sh

1
2
3
#!/bin/bash
echo 'Stopping Server...'
kill `cat server_id.txt`

Not much to explain here, we're basically killing the PID that was written by start_server.sh.

Since this is a pretty complete deployment package, I decided to offer it on a git repository.

I'd love to get some improvements going on, feel free to fork/add issues!