Meteor Deployment Our Own Servers


// Meteor - Deployment - Deploying to our own servers:

meteor bundle .

This will package all the necessary files that will be required to run. Then, you'll 
need to setup your MongoDB database and NodeJS dependencies. The Meteor 
team have included a README in the package, when you bundle your application. 
This file will provide exact instructions to get your application up and running.

// Common strategies for implementing sticky sessions:

There are a couple of ways we can implement sticky sessions. We can implement 
sticky sessions with cookies, hashing source IP information or customized URLs. 
There are some other ways, but these are the common ones.

Hashing source IP is the easiest to implement, but it does not balance the load 
properly. We can’t trust the IP information and transparent proxy servers (very 
commonly used by ISPs) hide the original IP information, which means one server 
will get many requests and the others won’t.

A customized URL path is a very good option and it is very well supported by SockJS. 
But for this, we’ll need some custom logic in the load balancer and further 
configuration on Meteor.

The cookie-based solution is ideal for us, since it can balance the load properly and 
it is easy to set up.

//  leastconn instead of roundrobin:

It is very important to choose a good load-balancing algorithm. HaProxy comes with a 
bunch of algorithms. The roundrobin algorithm is recommended in the docs. roundrobin 
is very good for stateless webapps built with Ruby on Rails or PHP.

However, Meteor is stateful and it has long-lasting connections, so it is better to use the 
leastconn algorithm. It sends new connections to the server that has the lowest number 
of connections. This balances the load equally, even if a server goes down and comes 
back. If we use roundrobin, we’ll have an unbalanced load.

// To select MongoDB hosting provider:

If you are using Galaxy (or need a production quality, managed MongoDB for one of the 
other options listed here), it’s usually a good idea to use a MongoDB hosting provider. 
There are a variety of options out there, but a good choice is The 
main things to look for are support for oplog tailing, and a presence in the us-east-1 or 
eu-west-1 AWS region.

How can we do custom deployment?

If you want to figure out your hosting solution completely from scratch, the Meteor tool has a command meteor build that creates a deployment bundle that contains a plain Node.js application. Any npm dependencies must be installed before issuing the meteor build command to be included in the bundle. You can host this application wherever you like and there are many options in terms of how you set it up and configure it.

It’s important that you build your bundle for the correct architecture. If you are building on your development machine, there’s a good chance you are deploying to a different server architecture. You’ll want to specify the correct architecture with --architecture:

# for example if deploying to a Ubuntu linux server:
npm install --production
meteor build /path/to/build --architecture os.linux.x86_64

This will provide you with a bundled application .tar.gz which you can extract and run without the meteor tool. The environment you choose will need the correct version of Node.js and connectivity to a MongoDB server.

Depending on the version of Meteor you are using, you should install the proper version of node using the appropriate installation process for your platform.

  • Node 4.4.7 for Meteor 1.4.x
  • Node 0.10.43 for Meteor 1.3.x and earlier

You can then run the application by invoking node with a ROOT_URL, and MONGO_URL. These instructions are also available in the README file found in the root of the bundle you built above.

cd my_build_bundle_directory
(cd programs/server && npm install)
MONGO_URL=mongodb://localhost:27017/myapp ROOT_URL= node main.js
  1. ROOT_URL is the base URL for your Meteor project
  2. MONGO_URL is a Mongo connection string URI supplied by the MongoDB provider.

Unless you have a specific need to roll your own hosting environment, the other options here are definitely easier, and probably make for a better setup than doing everything from scratch. Operating a Meteor app in a way that it works correctly for everyone can be complex, and Galaxy handles a lot of the specifics like routing clients to the right containers and handling coordinated version updates for you.

How can we move our application from to our own infrastructure?

The free hosting provided by Meteor at is great for deploying prototypes and toys but if your traffic starts to ramp up, you'll eventually have to move on to your own infrastructure.

You'll need to back up the data from the DB on your site. Oli Evans made a dead simple bash script to help you called Meteor Dump

Meteor uses MongoHQ and unless you have some special reason to run your own MongoDB server, I highly recommend doing the same. The sandbox account gives you 512MB of storage for free and the prices are reasonable beyond that.

It's super simple to copy your data directly across to your new MongoHQ database once you've created an account.

You'll need to bundle your app either before or during deploy using meteor bundle (or mrt bundle). This creates a node-friendly bundle that you can run with node directly (i.e. node bundle/main.js)

If you create your bundle locally and then upload to your server, you'll have to be careful to rebuild your node dependencies in the server environment, as noted in the Meteor docs in the red text under Running your own infrastructure.

If you add packages using Meteorite locally then you'll want Meteorite on the server as well. This is bound to change pretty soon as Meteor (as of 0.6.0) now handles its own versioning and codifies package management a bit more and Meteorite is soon to change to catch up.

Meteor expects certain environment variables are set when the app is started:

  1. MONGO_URL: The URL to your MongoDB instance using the mongodb:// protocol.
  2. ROOT_URL: If you serve your site from a domain other than localhost, you'll need to set this so that URLs within your app point to the right place (Meteor.absoluteUrl depends on this variable being set).
  3. PORT: The port the app server should run on. This will vary depending on your environment and setup.
  4. Other packages may require specific environment variables (e.g. MAIL_URL).

How can we use Meteor with a CDN?

It’s not strictly required, but often a good idea to set up a Content Delivery Network (CDN) for your site. A CDN is a network of servers that hosts the static assets of your site (such as JavaScript, CSS, and images) in numerous locations around the world and uses the server closest to your user to provide those files in order to speed up their delivery. For example, if the actual web server for your application is on the east coast of the USA and your user is in Australia, a CDN could host a copy of the JavaScript of the site within Australia or even in the city the user is in. This has huge benefits for the initial loading time of your site.

The basic way to use a CDN is to upload your files to the CDN and change your URLs to point at the CDN (for instance if your Meteor app is at, changing your image URL from <img src=""> to <img src="">). However, this would be hard to do with Meteor, since the largest file – your Javascript bundle – changes every time you edit your app.

For Meteor, we recommend using a CDN with “origin” support (like CloudFront), which means that instead of uploading your files in advance, the CDN automatically fetches them from your server. You put your files in public/ (in this case public/cats.gif), and when your Australian user asks the CDN for, the CDN, behind the scenes, fetches and then delivers it to the user. While this is slightly slower than getting directly, it only happens one time, because the CDN saves the file, and all subsequent Australians who ask for the file get it quickly.

To get Meteor to use the CDN for your Javascript and CSS bundles, call WebAppInternals.setBundledJsCssPrefix("") on the server. This will also take care of relative image URLs inside your CSS files. If you need to use a dynamic prefix, you can return the prefix from a function passed to WebAppInternals.setBundledJsCssUrlRewriteHook().

For all your files in public/, change their URLs to point at the CDN. You can use a helper like assetUrl.


<img src="">


Template.registerHelper("assetUrl", (asset) => {
  return "" + asset
<img src="{{assetUrl 'cats.gif'}}">

If you are hosting a webfont as part of your application and serving it via a CDN, you may need to configure the served headers for the font to allow cross-origin resource sharing (as the webfont is now served from a different origin to your site itself). You can do this easily enough in Meteor by adding a handler (you’ll need to ensure your CDN is passing the header through):

import { WebApp } from 'meteor/webapp';

WebApp.rawConnectHandlers.use(function(req, res, next) {
  if (req._parsedUrl.pathname.match(/\.(ttf|ttc|otf|eot|woff|font\.css|css)$/)) {
    res.setHeader('Access-Control-Allow-Origin', /* your hostname, or just '*' */);

And then for example with Cloudfront, you would:

  1. Select your distribution
  2. Behavior tab
  3. Select your app origin
  4. Edit button
  5. Under “Whitelist Headers”, scroll down to select “Origin”
  6. Add button
  7. “Yes, Edit” button

How can we offload static resources to a proxy server or CDN?

The 'meteor build' command automatically minifies and compiles all CSS and JavaScript files and place them in the folder bundle/programs/web.browser. If NGINX is to serve these files, they must be accessible from the nginx server. If Meteor is deployed to a different server, you can either copy the files to nginx machine or configure a folder share using NFS. If you copy the files, remember that you need to repeat this every time you deploy the application. Because each build command will create new random filenames, there is no need to delete the old files. This allows for smoother transition between deployments.

To configure serving static application files and styles, you must define a new location block in your nginx configuration file:

server {
  location ~* "^/[a-z0-9]{40}\.(css|js)$" {
    root /home/meteor/app/bundle/programs/web.browser/app;
    access_log off;  // Turn access log off for these files to reduce disk I/O
    expires 30d;
    add_header Pragma public
    add_header Cache-Control "public";

The content of the public folder should also be served from nginx. Because the public folder is accessible at the root of your application, you'll use file extension to determine whether a request will be served statically or from Meteor. The configuration is similar to the above block:

server {
  location ~ \.(jpg|jpeg|png|gif|mp3|ico|pdf) {
    root /home/meteor/app/bundle/programs/web.browser/app;
    access_log off;  // Turn access log off for these files to reduce disk I/O
    expires 30d;
    add_header Pragma public
    add_header Cache-Control "public";

The only difference between these 2 blocks is the regular expression in the location line. Perhaps we can combine these block.

What is the purpose of the demeteorizer package?

The demeteorizer package wraps and extends the build command by creating a standard Node.js application. To create a highly portable Node.js bundles with demeteorizer, you first need to install it on your development system. Because it comes in form of a node module, it can be installed via npm:

npm install -g demeteorizer

Once it is installed, go to your application folder and run:

demeteorizer -t myApp.tar.gz

Unlike the build command, demeteorizer creates a build directory by default which is why the -t option is needed to create a tarball. It will also create the .demeteorizer directory. The resulting archive can be uploaded and extracted to the server. Some providers such as will allow you to directly upload the archive via a web interface. Thanks to the presence of the package.json file in the root of the project, all modules will be installed automatically if your provider supports it, or you'll navigate to the root folder of the project on the deployment server and issue the install command:

cd /var/www/myDemeteorizedApp
npm install

What are common environment variables used by Meteor?

  1. PORT: The network port to bind to (default: 3000)
  2. BIND_IP: The IP address to bind to (default: all)
  3. ROOT_URL: The base URL of the application
  4. MONGO_URL: The connection string for MongoDB
  5. MONGO_OPLOG_URL: The connection for MongoDB oplog
  6. MAIL_URL: The SMTP connection string for the mail server (default: STDOUT)
  7. NODE_ENV: Some cloud provider user this, typically set to production

Most cloud provider have a web interface for you to define names and values of environment variables.

In what regards is Meteor deployment different from traditional deployment?

In traditional approach, connections are stateless. It makes no difference which application server respond to any request in a series. With Meteor, each connection maintains state and therefore switching between servers for different requests of the same client will break things because any information regarding the context is lost. Traditional web application use server-side session. Perhaps we can use server-side session in Meteor application as well. However, Meteor also use DDP and WebSocket, which means that if a server is restarted we need to do something on the browser side to re-establish the connection, or the users may experience some problem. It is best to use sticky-load-balancing.

Does Meteor support SSL connection?

No. Although Node.js supports SSL connections, Meteor does not. To provide secure connections, SSL can still be used on the load balancer facing the clients. All traffic between the load balancer and the application server will be unencrypted, which is referred to as SSL offloading.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License