I have a lot of little Meteor projects. Here’s the exact steps that I take to deploy them on a VPS in a resource-efficient manner. A cheap VPS with 1GB of RAM costs about $10/month and can support dozens of small Meteor deployments on its own.
I use a shared MongoDB instance and run the Meteor projects in Docker containers. nginx sits at the front end (port 80) and directs traffic to the appropriate Meteor project.
I’m starting with an Ubuntu 14.04 LTS 64-bit server running on DigitalOcean. The same should work for any recent Debian-like distribution and any VPS host (e.g. Amazon EC2). I assume that you are running as root
.
aptitude update
aptitude upgrade -y
aptitude install nginx mongodb
Follow the instructions to install Docker. If you don’t want to read all of that, paste the following into your terminal:
apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" | sudo tee /etc/apt/sources.list.d/docker.list
aptitude update
aptitude install docker-engine
docker pull meteorhacks/meteord:base
In /etc/mongodb.conf
, change:
bind_ip = 127.0.0.1
to
bind_ip = 127.0.0.1,10.0.3.1
Run mongo
and enter the following.
use <databasename>
db.addUser( { user: "<username>",
pwd: "<password>",
roles: [ "readWrite", "dbAdmin" ]
} )
Replace <databasename>, <username> and <password> as appropriate.
Note that this uses Mongo polling, not the oplog.
Yes, polling sucks. Remember that this setup is meant for small deployments and multiple deployments where you have many applications sharing the same MongoDB. I haven’t figured out (yet!) how to securely share the oplog between applications – you don’t want one insecure application to compromise the others. If this installation started to grow, you might notice that your machine load was high (maybe due to polling, maybe something else) and you’d be best moving to a dedicated MongoDB server with oplog access. But you’re small for now, so don’t sweat it. Premature optimisation is the root of all evil, etc.
In /etc/nginx/sites-enabled/<sitename>
:
server {
server_name <hostname>;
access_log on;
location / {
proxy_pass http://localhost:9001;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Replace <sitename> with a shortname for your project (e.g. todolist) and <hostname> with the URL that you want to access your project at (e.g. todolist.example.com).
Within the Meteor project directory:
meteor build --architecture=os.linux.x86_64 ./
This will create a new .tar.gz file in your project directory.
(The minification process is a little stricter than the standard meteor run
, so you might run into new syntax errors and the like.)
You need a directory to store the bundles; all of the .tar.gz files in the directory will be decompressed by the Docker image.
rsync --inplace -vP <bundlename>.tar.gz [email protected]:/opt/whatever/whatever.tar.gz
Each bundle either needs to go into a unique directory, or you need to clear out old ones when you upload new ones.
docker run -d \
-e ROOT_URL=http://<app-url> \
-e MONGO_URL=mongodb://<user>:<password>@10.0.3.1/<database-name> \
-v /<bundle-dir>:/bundle \
-p 9001:80 \
meteorhacks/meteord:base
Note that 10.0.3.1 is the default IP address of the host where we are running the MongoDB server.