For those who haven’t heard of Meteor yet: it is a hip new Javascript platform for developing web apps. It’s quite an innovation compared to “traditional” web frameworks: you develop in a single codebase and the code almost magically works in both the browser and the server. The platform also synchronizes data automatically across all connected clients by using long polling, WebSockets etc. It’s definitely worth checking out.

[1] In this article, “traditional” is used very loosely and refers to all non-Meteor-inspired frameworks. There’s nothing wrong with these older frameworks, just different. I still think Rails is revolutionary in many ways.

Why use Meteor on Phusion Passenger?

Phusion Passenger takes a lot of complexity out of deploying Meteor, and adds powerful enterprise-grade features that are useful in production. It also makes administering Meteor apps much easier. It has already done this for Ruby, Python and Node.js and is being used by high-profile companies such as Apple, Pixar, New York Times, AirBnB, Juniper etc.

Here are some of the benefits that Phusion Passenger gives you:

The power of Nginx – Phusion Passenger combines Meteor with the increasingly popular Nginx web server. By combining them, Nginx will offload Meteor from serving static assets. This also adds a buffering reverse proxy layer which provides I/O security and protects Meteor against invalid HTTP requests, slow clients, etc.

Multitenancy – Run multiple Meteor applications on a single server easily and without hassle.

Process management and supervision – Meteor processes are automatically started, and automatically restarted when they crash.

Statistics and insight – Phusion Passenger provides tools for inspecting the applications’ status, such what requests they’re currently processing, how many requests they’ve processed. All relevant information is shown at a glance. Having this in production will help a lot with tracking down problems.

Scaling and load balancing – Based on current traffic, Phusion Passenger can spawn more Meteor processes to handle the load, or spin down some existing Meteor processes to conserve resources. Phusion Passenger automatically load balances traffic across Meteor process. The load balancing mechanism utilizes a smart “first-available” selection algorithm to avoid problems caused by slow requests. Although Node.js and Meteor are single-threaded, this approach allows them to utilize multiple CPU cores.

Phusion Passenger is quite small and fast, being written in optimized C++. It’s a lightweight tool which drastically reduces complexity in your production environments.

How’s this any different from putting Meteor behind an Nginx reverse proxy yourself?

Using Phusion Passenger is much easier. If you do it yourself, you’ll have to write reverse proxy rules, write init scripts, setup process supervision, etc and the result probably does not handle corner cases properly. Phusion Passenger takes care of all this for you and handles virtually all the corner cases. This reduces the number of moving parts and reduces complexity.

Phusion Passenger integrates much deeper into Nginx than a straight reverse proxy does, and as such can leverage Nginx features much better. For example, the load balancing and response buffering in Phusion Passenger is much better than the one you get with manual reverse proxying.

By using Nginx’s proxy module, it’s very hard to see what’s going on with the system right now. Are all connections ok? Are all processes ok? Phusion Passenger provides simple and powerful administration tools that can help you with that.

Installing

Preparing your app

A Meteor app in Phusion Passenger must contain the public and tmp subdirectories.

public directory contains static files. All files in this directory are automatically served by the web server. For example, if there’s a file public/foo.jpg, then any requests to /foo.jpg will be handled by the web server, and never passed to the application.

The tmp directory can be used by the application, but is also used by Phusion Passenger for restarting the application. By touching the file tmp/restart.txt, Phusion Passenger will restart the application on the next request. This seemingly strange mechanism comes from the fact that Phusion Passenger is designed to be friendly to shared hosters which only provide FTP access and no SSH access.

meteor create --example leaderboard
cd leaderboard
mkdir public tmp

Developing Meteor apps on Nginx

Developing on Nginx is a matter of adding a virtual host entry in your web server, and telling the web server that it’s a Phusion Passenger-served app. The meteor command must be installed.

Note that the document root must point to the public directory of the app! Suppose the app is located in /webapps/leaderboard, then:

If you restart Nginx and visit http://www.foo.com/ now (assuming that your system’s DNS or /etc/hosts is configured to route to the web server in question), the request will be handled by your Meteor application.

Caveat (November 1 2013): unfortunately Nginx only allows setting environment variables globally, not per virtual host. We are working on a solution for this, which we expect to roll out in the coming few weeks. Please stay tuned for updates. This problem turns out to be untrue. passenger_set_cgi_param can be used to set environment variables.

Deploying a raw app directory in production

When deploying a raw Meteor app directory, you need to have Meteor installed. The procedure is the same as for developing Meteor apps on Nginx: you need to create a public directory, and you need to point the Nginx virtual host root there.

In this mode, you do not need to set MONGO_URL and other environment variables because Phusion Passenger will start your Meteor app through meteor run --production. Phusion Passenger even automatically finds a free port for it to run on so that you don’t need to worry about it.

cd /webapps/leaderboard
mkdir public

Then:

server {
server_name www.foo.com;
root /webapps/leaderboard/public;
passenger_enabled on;
# The following is not needed because passenger_app_env defaults to production.
# But this example sets it explicitly so that you can see what's going on.
passenger_app_env production;
}

Further reading and troubleshooting

Administration tools

The passenger-status tool allows you to inspect Phusion Passenger and the currently application’s state, such as what processes exist, how much memory and CPU they use, how many requests they’ve processed, etc.

The passenger-memory-stats tool allows you to inspect the memory usage of all processes related to Phusion Passenger, including the web server, Phusion Passenger itself and the applications. The difference with passenger-status is:

passenger-status does not display the web server’s memory usage.

passenger-status does not display the memory usage of internal Phusion Passenger processes.

The metrics displayed by passenger-status are gathered by internal Phusion Passenger processes that run in the background. passenger-memory-stats displays information by querying ps. If the Phusion Passenger internal processes are malfunctioning, then passenger-memory-stats still works.

Your feedback is valuable!

We’d like to hear from you if you’re using Phusion Passenger to host Meteor apps! If there are any problems, or even if there are no problems, we’d like to know. Please send an email to the community discussion forum. Thank you!

I’ve been using Passenger with Nginx for development, but had to stop. On code change, Passenger with its Nginx modification causes my app to fully stop and start which takes up to half a minute whereas without their Nginx modification Meteor restarts normally in only a few seconds.

http://www.phusion.nl/ Hongli Lai

We haven’t seen this behavior before and it isn’t supposed to happen. Could you tell us more about this issue? Any address where we can contact you on?

JayRoe

That was swift. You can reach me at jakobrosenberg at gmail dot com.

asif

This doesnt work for me, could you please check.
I am passing meteor –settings settings.json like what you mentioned
passenger_set_cgi_param METEOR_SETTINGS ‘{“someSettings”:{“someOtherSetting”:”Some value”}}’;

But the package i use is unable to find the id, however when i run meteor –settings settings.json, it works

http://eldog.me.uk/ Lloyd Henning

Perhaps there are problem with characters in your settings string that need escaping?

Although I haven’t used passenger for a while, so can’t confirm whether passenger_set_cgi_param is the way it currently works.

Hello, we are Phusion. We provide amazing products and services
for web apps written in Ruby, Python, Node.js and Meteor.

“Phusion” and “Phusion Passenger” are registered trademarks of Phusion. “Rails”, “Ruby on Rails” and the Rails logo are registered trademarks of David Heinemeier Hansson. All other trademarks are property of their respective owners.