Phusion Passenger: Meteor tutorial

Dan Dascalescu edited this page Apr 8, 2015 · 36 revisions

Phusion Passenger™ is an open source, polyglot (multi-language) application server. It takes a lot of complexity out of deploying Meteor, and adds powerful enterprise-grade features that are useful in production. It also makes it 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 as well as over 350.000 websites.

5 minute intro: Making node.js deployment enjoyable (DotJS Paris 2013)

Learn more: Website | Documentation | Support resources | Github | Twitter | Blog

Meteor Phusion Passenger

Table of contents

  1. Understanding Phusion Passenger
  2. Getting started
  3. Understanding what happened
  4. Deploying to production
  5. Using Passenger in development
  6. Caveats
  7. Management and inspection
  8. Troubleshooting
  9. Conclusion

1. Understanding Passenger


Phusion Passenger wraps Meteor, makes it simpler to deploy,
adds management tools and other useful production features.

Why use Meteor on Passenger?

Here are some of the benefits that you will gain:

  • 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. It will even allow you to use SSL without having to code explicit SSL support in your Node app.

    Nginx isn't the only thing supported though. Passenger also supports Apache, and can even run standalone without needing an existing web server.

  • 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.

  • 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 processes. The load balancing mechanism utilizes a smart "first-available" selection algorithm to avoid problems caused by slow requests. Although Node.js - and thus Meteor - is single-threaded, this approach allows you to utilize multiple CPU cores.

  • I/O security
    Meteor is automatically put behind a buffering web server, such as Nginx or Apache, which preprocesses and postprocesses HTTP requests and responses. This protects the Meteor app against slow-client attacks such as Slowloris. It also provides a secure environment which sanitizes HTTP headers, to protect against vulnerabilities in the app's HTTP parser.

  • System security
    Meteor processes are automatically started as the user which owns the app. This allows the OS to separate their privileges, so that a vulnerability in one app does not affect another.

  • Static file acceleration
    Static files are directly served by the web server (Nginx/Apache), not by Meteor. This offloads the Meteor application from handling those things.

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. The result probably does not even 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.

How does it work?

Instead of using Meteor directly, you use Phusion Passenger, which in turn manages Meteor.

Passenger and Nginx form an integrated whole. As a user, you don't deal with Passenger and Nginx separately: you deal with both of them at the same time. This makes the system considerably easier to administer. You configure Passenger by editing the Nginx configuration file. You start and shutdown Passenger by starting and shutting down Nginx.

Passenger and Nginx receive requests and forwards them to Meteor. Passenger internally sets up Nginx reverse proxy rules. This reverse proxy layer sanitizes HTTP headers and provides buffering, which protects Meteor against slow clients.

Further under the hood, Passenger manages multiple Meteor processes and load balances traffic amongst them. If a process crashes, it is restarted. By using multiple processes, Passenger allows you to take advantage of multiple CPU cores (1 process can use 1 core), even though Meteor is single-threaded. Again, you never have to deal with all the Meteor processes individually. You only deal with Passenger, which takes care of all this for you.

Any requests that can be mapped to a static file on disk, will be handled immediately by Nginx, and the request never reaches Meteor. Nginx is highly optimized at serving static files, and does a much better job at it than Meteor. This offloads Meteor for only the most important requests, namely the dynamic ones.

Passenger also introduces a management and inspection console. Normally it's very hard to see what your Meteor app is doing. What request is it handling? How much CPU and memory is it using? Is it maybe stuck or malfunctioning? Is it under heavy load? Because Passenger keeps score of statistics, all these questions can be answered with the Passenger management and inspection tools.

Some readers may immediately recognize that Passenger is Unix. This is a traditional Unix process supervision architecture. The architecture leverages a lot of powerful Unix features. The supervision code utilizes POSIX process management APIs.

Multiple integration modes

Note that "Nginx" in the previous diagram can be replaced by "Apache". This is because Passenger supports three modes:

  • An Nginx integration mode, which works as previously described.
  • An Apache integration mode, which is exactly like the Nginx integration mode, but with Apache.
  • A Standalone mode. Whereas the Nginx integration mode requires you to install and configure Nginx, the Standalone mode works as a single standalone server. Under the hood it still uses Nginx and things still work like in the previous diagram, but all the complexity is encapsulated in a single command on the command line.

The manual documents the differences between the multiple integration modes. In this tutorial, we'll first introduce you to the Standalone mode because it's the easiest to work with. Then we'll slowly cover the other modes as well.

What Passenger doesn't do

Passenger follows the Unix philosophy of doing a small number of things, but doing them well. So there are a number of things that are (currently) outside Passenger's scope. Passenger may or may not take care of some of these some time in the future.

  • Setting up a server with an operating system
    Passenger assumes that you already have a server with an working operating system on it. Passenger is not a hosting service. It is software that is to be installed on a server.
  • Installing Meteor and Node.js
    To run Meteor apps on Passenger, you must already have either Node.js installed or Meteor installed (the details depends on whether you're using Meteor in bundled form or not; more about this later). Passenger doesn't do that for you. Passenger doesn't care how you install Node.js/Meteor though; you sometimes just need to tell Passenger where Node.js is.
  • Transferring the application code and files to the server
    Passenger does not transfer the application code and files to the server for you. To do this, you must use tools like Git, scp, FTP, Capistrano, Fabric, etc. Passenger assumes that the application code and files are already on the server, and does not care which tool you use to make that so.
  • Installing application dependencies
    Passenger does not install your application's dependencies for you.
  • Managing the database
    If your application requires a database, then Passenger does not install that database for you, nor does it sets up database accounts and tables for you. They must already be set up by the time you deploy your application to Passenger.
  • Managing auxiliary daemons and services
    If your application requires additional daemons and services, e.g. Memcached or Redis, then Passenger does not manage those. They must already be running.
## 2. Getting started

Installing

Visit the Phusion Passenger download page. There are tailor-made, polished installation methods for OS X, Debian/Ubuntu, Heroku, etc. :)

Make sure you get a version that is recent enough. This tutorial assumes at least version 4.0.45.

Prepare your app

One of the philosophies behind Phusion Passenger is convention over configuration. In practice, many web apps share many structural commonalities. For example, most web apps have a directory in which they store static assets.

Phusion Passenger leverages this property to make your life easier. It assumes this convention by default so that you don't have to write so much configuration. If your app does not follow the convention then there are configuration options to tell Phusion Passenger about the structure.

According to Phusion Passenger's convention, you will need two extra directories in your Meteor app directory:

  • public/ - The same directory used by Meteor for static files. All files in this directory will automatically be served by the web server, bypassing Meteor. 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.
  • tmp/ - This 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.

For simplicity reasons, this tutorial assumes that your app follows this convention. If you prefer to put the public and tmp directories elsewhere then that's entirely possible. The manuals tell you how to configure their locations.

Example app

Let's create an example Meteor app directory structure. We use the builtin Meteor leaderboard example app.

meteor create --example leaderboard
cd leaderboard
mkdir public tmp

Now start your application inside Phusion Passenger's Standalone mode:

$ passenger start
=============== Phusion Passenger Standalone web server started ===============
PID file: /Users/phusion/leaderboard/passenger.3000.pid
Log file: /Users/phusion/leaderboard/passenger.3000.log
Environment: development
Accessible via: http://0.0.0.0:3000/

You can stop Phusion Passenger Standalone by pressing Ctrl-C.
Problems? Check http://www.modrails.com/documentation/Users%20guide%20Standalone.html#troubleshooting
===============================================================================
App 85125 stdout: [[[[[ ~/leaderboard ]]]]]
App 85125 stdout: 
App 85125 stdout: => Meteor server running on: http://localhost:9822/

We see a couple of things here:

  • Passenger reports that it has started a server, which is accessible via http://0.0.0.0:3000/. It also tells you where it has placed its PID file and log file.
  • Internally, Passenger runs your Meteor app by invoking the command meteor run (this is only done during development, not during production). You can see the output of that command in the lines that are marked with "App xxx stdout". The xxx is the PID of the meteor run command.
  • meteor run starts its own server at http://localhost:9822/. But that's not the URL we want to access. Passenger listens on its own port, manages Meteor, and forwards requests to Meteor through the address http://localhost:9822/. So you should ignore this line.

So open http://0.0.0.0:3000/ in your browser, and verify that it works!

Understanding what happened

The previous instructions worked like magic, but what happened? Under the hood, Passenger took care of a lot of stuff for you, and there's a lot of complexity that Passenger is hiding for you. However you should have a good understanding of what Passenger does, so that you know what to do when there are problems.

So here's a rundown of what happened earlier:

  • You created a Meteor application directory structure in the format Phusion Passenger expects it.
  • Instead of running meteor run, you ran passenger start. This command starts Phusion Passenger in its Standalone mode. The Standalone mode does not require Nginx or Apache.
  • Passenger is now serving and managing your application on its default port, 3000.

Instead of using the meteor command to control your application, you're now supposed to use Passenger to control your application. And in case of Passenger Standalone, that means using the passenger command.

For example, to change the port that your application runs on, you don't run meteor run --port. You run passenger start --port. Let's try that out. Press Ctrl-C to stop your existing Passenger Standalone instance, and run:

$ passenger start --port 3001
=============== Phusion Passenger Standalone web server started ===============
PID file: /Users/phusion/leaderboard/passenger.3001.pid
Log file: /Users/phusion/leaderboard/passenger.3001.log
Environment: development
Accessible via: http://0.0.0.0:3001/

You can stop Phusion Passenger Standalone by pressing Ctrl-C.
Problems? Check http://www.modrails.com/documentation/Users%20guide%20Standalone.html#troubleshooting
===============================================================================
...

Now open http://0.0.0.0:3001/ in your browser, and verify that it works.

Process spawning

Remember the diagram from How does it work? At its core, Passenger is a process manager and starts and stops Meteor processes for you. How can you see what processes are running? There's a tool for that! passenger-status gives you an overview of all your processes, how much CPU and memory they're using, etc.

$ passenger-status
Version : 4.0.45
Date    : 2013-11-14 21:55:30 +0100
Instance: 25002
----------- General information -----------
Max pool size : 6
Processes     : 1
Requests in top-level queue : 0

----------- Application groups -----------
/Users/phusion/leaderboard#default:
  App root: /Users/phusion/leaderboard
  Requests in queue: 0
  * PID: 25012   Sessions: 0       Processed: 2       Uptime: 9s
    CPU: 0%      Memory  : 14M     Last used: 3s ago

By default, Passenger only starts a single Meteor process per application. We can use the --min-instances option to tell it to spawn more. A bunch of other options must also turned on in order to make Meteor work properly in multi-process mode.

So press Ctrl-C to stop your existing Passenger Standalone instance, and run:

$ passenger start --port 3001 --min-instances 2 --sticky-sessions
=============== Phusion Passenger Standalone web server started ===============
PID file: /Users/hongli/Sites/leaderboard/tmp/pids/passenger.3000.pid
Log file: /Users/hongli/Sites/leaderboard/log/passenger.3000.log
Environment: development
Accessible via: http://0.0.0.0:3000/

You can stop Phusion Passenger Standalone by pressing Ctrl-C.
Problems? Check http://www.modrails.com/documentation/Users%20guide%20Standalone.html#troubleshooting
===============================================================================
...
App 34627 stdout: Unexpected mongo exit code 100. Restarting.
App 34627 stdout:
App 34627 stdout: Can't start mongod
App 34627 stdout:
App 34627 stdout: MongoDB had an unspecified uncaught exception.
App 34627 stdout: This can be caused by MongoDB being unable to write to a local database.
App 34627 stdout: Check that you have permissions to write to .meteor/local. MongoDB does
App 34627 stdout: not support filesystems like NFS that do not allow file locking.
...

Hey, it looks like there are errors! What's going on?

During development, Passenger starts your Meteor processes by invoking the command meteor run, which in turns starts MongoDB. Thus, MongoDB is started twice. Because there can be only one MongoDB instance, one of the attempts fails, resulting in the above error messages.

When using multiple Meteor processes you need to start MongoDB separately, and tell all your Meteor processes to use that single MongoDB instance instead of each trying to start it by themselves.

You might also wonder, what's with that --sticky-sessions option? It's to tell Phusion Passenger to use so "sticky routing", which is necessary to make long polling in Meteor work over multi processes. The details are a bit boring, but you can read about them if you want to. For now, just remember to always use --sticky-sessions if you have more than 1 process, otherwise bad things will happen.

So let's do that in a short while. But first we need to clean up some mess. Because of the error, Meteor is currently a little confused about the state of MongoDB. We fix the state by:

  1. Stopping the current Passenger instance (that has 2 processes). Press Ctrl-C:

    (...press Ctrl-C...)
    Stopping web server... done
    
  2. Waiting 5 seconds, then starting Passenger again with just 1 process:

    $ sleep 5 && passenger start --port 3001
    
  3. Waiting 5 seconds, stopping Passenger again, and waiting 5 seconds.

    (...wait 5 seconds...)
    (...press Ctrl-C...)
    Stopping web server... done
    $ sleep 5
    

Now that we've cleaned things up, let's start a MongoDB instance. Open another terminal at and run:

cd ~/leaderboard
MONGO_PORT=$(cat .meteor/local/db/METEOR-PORT)
~/.meteor/tools/latest/mongodb/bin/mongod --bind_ip 127.0.0.1 --smallfiles --nohttpinterface --port $MONGO_PORT --dbpath .meteor/local/db --oplogSize 8 --replSet meteor

This command is rather long, but it's how meteor run starts MongoDB, as you were able to see in the ps output. MongoDB will now be listening at the port that Meteor previously started it on. Return to the previous terminal and run:

MONGO_PORT=$(cat .meteor/local/db/METEOR-PORT)
export MONGO_URL=mongodb://localhost:$MONGO_PORT/meteor
export MONGO_OPLOG_URL=mongodb://localhost:$MONGO_PORT/local
passenger start --port 3001 --min-instances 2 --sticky-sessions

The MONGO_URL environment variable is used by Meteor to determine whether it should start MongoDB by itself, and if not, which MongoDB instance to use. The MONGO_OPLOG_URL environment variable tells Meteor to enable the oplog observe driver, which allows real-time updates between multiple Meteor processes.

It appears that there are no errors this time. Let's verify that the two processes are running. Open yet another terminal and run:

$ passenger-status
Version : 4.0.45
Date    : 2013-11-14 21:58:20 +0100
Instance: 25019
----------- General information -----------
Max pool size : 6
Processes     : 1
Requests in top-level queue : 0

----------- Application groups -----------
/Users/phusion/leaderboard#default:
  App root: /Users/phusion/leaderboard
  Requests in queue: 0
  * PID: 25024   Sessions: 0       Processed: 1       Uptime: 9s
    CPU: 0%      Memory  : 14M     Last used: 3s ago
  * PID: 25025   Sessions: 0       Processed: 0       Uptime: 9s
    CPU: 0%      Memory  : 14M     Last used: 3s ago

As you can see, there are now two Meteor processes. Passenger automatically balances requests between the two of them.

Let's clean things up once more. Press Ctrl-C at the terminal where passenger start is running. Then run the following command to unset the MONGO_URL and MONGO_OPLOG_URL environment variables:

unset MONGO_URL
unset MONGO_OPLOG_URL

Now go to the terminal where mongod is running and press Ctrl-C there as well.

Maximum number of processes

Passenger is designed to be safe and robust as well. That means it tries very hard not to overuse your server's resources and make it crash. For this reason, Passenger has a setting which controls the maximum number of application processes it may spawn. It will never spawn more than this number of processes unless you explicitly increase the limit. The limit is controlled with --max-pool-size, and at the time of writing (version 4.0.45) the default is 6.

For example, try running:

passenger start --min-instances 8 --sticky-sessions

(don't forget to start MongoDB separately and setting MONGO_URL and MONGO_OPLOG_URL, as mentioned in the previous section)

You will see that Passenger only spawns 6 processes, no more. The following lifts the limit:

passenger start --min-instances 8 --sticky-sessions --max-pool-size 8

So what does this mean for you?

  • Each process can leverage a different CPU core. So spawning more processes allows you to leverage more cores.
  • It does not make sense to have more Meteor processes than the number of CPU cores.
  • If you spawn too many processes, your server may run out of memory, and processes will start becoming slow or start crashing. So keep an eye on your memory usage and decrease the number of processes if you notice that it's eating away your RAM.

You might especially be interested in this article: Tuning Phusion Passenger's concurrency settings.

The characteristics of having multiple processes

You've most likely only ever worked with a single Meteor process so far. Having multiple Meteor processes changes things somewhat. There are some strong caveats that you should be aware about.

First, what is a process anyway other than an entry in ps or passenger-status? A process is an instance of a computer program that is isolated from other processes. "Isolated" means that processes don't share memory with each other. Suppose that your program has a variable A with initial value A == 1. If you run two instances of your program -- two processes -- and you tell one process to set A = 2, then the value 2 is only visible to that process. The other process still thinks A == 1!

This is in contrast to threads. A thread runs inside a process, so if a thread changes a value, all other threads in the same process see the change.

But you can't change variables in your program and expect all processes to see the changes. They don't. So how do you communicate changes to all your processes? By using a shared data store, which can be:

  • The database (e.g. MongoDB).
  • Redis.
  • Memcached.

Another characteristic about processes is that, if one process crashes, others are unaffected. This is also in contrast to threads: if a thread crashes and is unable to recover from the crash, then the entire process crashes with all its threads in it.

This is why Passenger likes having multiple processes. If one process crashes, no problem, the other can (temporarily) take over while Passenger spawns a new one. This is also why Passenger itself is its own process: so that Meteor and Node.js can't take down Passenger.

Development vs production mode

Meteor has the concept of a development mode and a production mode. In development mode, Meteor automatically starts and manages a MongoDB server, as well as providing other kinds of nice features such as reloading your code whenever it has changed. These features are not, and should not, be available during production.

Phusion Passenger's Standalone mode is primarily meant to be a development tool, so it starts your Meteor app in development mode by default. You can tell Passenger Standalone to start Meteor in production mode with --environment:

passenger start --environment production

As you will learn later, the Nginx integration mode and Apache integration mode are primarily meant for production, so they start Meteor in production mode by default. You will also later learn how to change that.

There is also this meteor bundle thing. How Phusion Passenger works with that is covered in detail in Deploying to production.

Further configuration

There are many more configuration options. Configuration depends on the integration mode. So far we've only covered the Standalone mode. You can learn more about configuring the Standalone mode in the Passenger Standalone manual.

The Nginx integration mode and the Apache integration mode, which we're going to cover later in this tutorial, are configured differently. They too have their own manuals which cover configuration.

4. Deploying to production

There are two options when deploying a Meteor app in production mode. You can either deploy a raw Meteor application directory, or you can deploy a Meteor bundle.

If you deploy a raw Meteor application directory on Phusion Passenger, then Passenger will start your Meteor app using the meteor command. Therefore, Meteor must be installed on the same server.

A Meteor bundle is created by the meteor bundle command. This command transforms your Meteor app into a normal Node.js app and will bundle the Meteor runtime into the application. Therefore, if you deploy the resulting bundle, Phusion Passenger will treat your Meteor app as a normal Node.js app, and does not require Meteor to be installed on the same server.

Deploying a bundle is the preferred option when in production.

Uploading your app to production

The first step is to upload your app the production server. The simplest way is to create a tarball and using scp to upload the tarball to your server. In this tutorial, we're going to assume that have a web app called leaderboard and that you've uploaded it to /webapps/leaderboard on the production server.

Uploading a raw Meteor app directory:

Go to the app directory's parent directory, create a tarball and upload it to your server:

cd /Users/phusion/webapps
tar -czf leaderboard.tar.gz leaderboard
scp leaderboard.tar.gz yourserver:

Login to your server, and extract the tarball to a directory of your choice:

sudo mkdir -p /webapps
cd /webapps
sudo tar xzvf ~/leaderboard.tar.gz
sudo chown -R $USER: leaderboard

Uploading a Meteor bundle:

Go to the app directory's directory, create a Meteor bundle and upload it to your server:

cd /Users/phusion/webapps/leaderboard
meteor bundle leaderboard.tar.gz
scp leaderboard.tar.gz yourserver:

Login to your server, and extract the tarball to a directory of your choice:

sudo mkdir -p /webapps
cd /webapps
sudo tar xzvf ~/leaderboard.tar.gz
mv bundle leaderboard
sudo chown -R $USER: leaderboard

Since your Meteor bundle does not have the public and tmp subdirectories, let's create them:

mkdir -p /webapps/leaderboard/public
mkdir -p /webapps/leaderboard/tmp

Installing dependencies

The next step is to install your app's dependencies on your server using NPM. Meteor currently has no system for keeping track of your dependencies, so you need to know by yourself what your dependencies are. Once you know, run the right npm install commands:

cd /webapps/leaderboard
npm install something
npm install something-else

If your web app is a Meteor bundle, then there are certain dependencies that you must install. Please consult the README file that Meteor has placed in your application directory. One of the dependencies is fibers:

npm install fibers@1.0.1

After installing dependencies, your app is fully prepared. As mentioned before, Passenger has multiple integration modes. You've only worked with the Standalone mode so far. All modes are fit for production, but you might prefer a specific mode in production. So let's go over them.

Deploying Standalone

If you have no experience with Nginx and Apache, then deploying the Standalone mode directly is by far the easiest. This way you don't have to deal with Nginx and Apache at all.

On the downside - unless you're using the Mass Deployment feature in the Enterprise variant - Passenger Standalone can only serve 1 Meteor application at the same time. Serving multiple applications at the same time requires you to start multiple Passenger Standalone instances, and to attach them to a reverse proxy. That makes things quite complicated, so if you want to serve multiple applications then you should use the Nginx or Apache integration mode.

  1. Install Phusion Passenger on your server.

  2. Login to your server and change the working directory to your application.

  3. Set the MONGO_URL, MONGO_OPLOG_URL and ROOT_URL environment variables, as per the Meteor deployment instructions.

     export MONGO_URL=mongodb://localhost:27017/meteor
     export MONGO_OPLOG_URL=mongodb://localhost:27017/local
     export ROOT_URL=http://www.foo.com
    
  4. Run Passenger Standalone on port 80, and after binding to port 80, drop its privileges. Also tell it to start the Meteor in production mode, and to daemonize into the background.

    If your app is a raw Meteor app directory:

    sudo -E passenger start --port 80 --user someusername --environment production --daemonize --sticky-sessions
    

    If your app is a Meteor bundle, we need to set some environment variables and pass a few more options:

    sudo -E passenger start --port 80 --user someusername --environment production --daemonize --sticky-sessions --app-type node --startup-file main.js
    

    someusername should be the user that you want to run your application as. As a rule, never run your application as root. That is insecure!

  5. Configure Passenger Standalone to start at boot. Don't forget to set the proper environment variables in your startup script.

Deploying on Nginx or Apache

In the Nginx and Apache integration modes, Phusion Passenger acts as an Nginx or Apache module, so it is automatically started along with the web server. If you already have experience with Nginx or Apache then these modes are better suited for you. These modes make it trivial to serve multiple Meteor applications.

First, install Phusion Passenger in Nginx or in Apache mode. Deploying an app is then 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.

Note that the document root must point to the public directory of the app!

Nginx:

server {
    server_name www.foo.com;
    root /webapps/leaderboard/public;
    passenger_enabled on;
    passenger_sticky_sessions on;
    passenger_env_var MONGO_URL mongodb://localhost:27017/meteor;
    passenger_env_var MONGO_OPLOG_URL mongodb://localhost:27017/local;
    passenger_env_var ROOT_URL http://www.foo.com;

    # Set these ONLY if your app is a Meteor bundle!
    #passenger_app_type node;
    #passenger_startup_file main.js;
}

Apache:

<VirtualHost *:80>
    ServerName www.foo.com
    DocumentRoot /webapps/leaderboard/public
    PassengerStickySessions On
    SetEnv MONGO_URL mongodb://localhost:27017/meteor
    SetEnv MONGO_OPLOG_URL mongodb://localhost:27017/meteor
    SetEnv ROOT_URL http://www.foo.com

    # Set these ONLY if your app is a Meteor bundle!
    #PassengerAppType node
    #PassengerStartupFile main.js
    #PassengerAppRoot /webapps/leaderboard
</VirtualHost>

If you 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.

The first request is slower

Notice that the first request that you made to http://www.foo.com/ is slower than usual? That's because when run in the Nginx or Apache integration mode, your application is not started until the first request. You can make Passenger start your application during web server startup by using these configuration options:

Configuration

While the Standalone mode is usually configured through command line options, the Nginx/Apache integration modes are configured through the Nginx/Apache configuration files. There are many configuration options that you can tweak. For example you can set the number of processes you want, you can set a memory limit, etc. Please refer to the Phusion Passenger manuals.

Redeploying (restarting) an application

Suppose that you've deployed a new version of your application. The old version is still running, so how do you make it restart?

As explained in Prepare your app, you can trigger a restart by touching the file tmp/restart.txt. On the next request, your application will be restarted: the old processes will be gone, and Passenger will spawn new processes.

Automatic user switching

Nginx and Apache are usually configured to run as the www user. Does that mean your Meteor applications are also run as that user? The answer is no. Since Passenger was designed to be multitenant, we wouldn't want one application to be able to modify and mess with the files of another application on the same machine, especially not because of a vulnerability in the application. So running all applications under the same user as the web server would open a huge security hole.

Passenger has had a remedy for this problem since version 1.0, through the Automatic User Switching feature. Simply put, your Meteor application is run as the owner of the .meteor directory (when deploying a raw Meteor app directory) or the owner of the main.js file (when deploying a Meteor bundle), unless you configure it otherwise. Of course you still have to make sure that each of your applications is owned by another user.

Note that Automatic User Switching is only supported in the Nginx and Apache integration modes, not in Standalone.

5. Using Passenger in development

Should Passenger be used in development as well?

With all the focus on production, should Passenger be used during development as well? Yes it should!

Let me be clear: you are in no way obliged to use Passenger in development. You can develop in pure Meteor, then deploy with Passenger. But it is generally a good idea to let your development environment match the production environment as closely as possible. Otherwise you may run into unexpected problems during production.

Meteor settings

Meteor supports two ways to set the Meteor.settings property. In development, you are supposed to pass --settings FILENAME to meteor run. In production (when using Meteor in bundled mode), you are supposed to set the METEOR_SETTINGS environment variable.

Since version 5.0.3, Passenger allows you to set Meteor settings through the METEOR_SETTINGS environment variable, even when your Meteor app is not bundled. It does this by automatically passing the contents to meteor run using --settings.

6. Caveats

Don't mess with stdout or stderr

Phusion Passenger uses stdout and stderr to communicate with the application. It is safe for you to log messages to stdout and stderr, but don't do things like redirecting them to a file. Doing so will make Phusion Passenger think your app froze during startup, because it never receives a message back.

CPU and memory statistics are only accurate for Meteor bundles

The application CPU and memory statistics reported by passenger-status and passenger-memory-stats are only accurate when the app is deployed as a Meteor bundle. This is because when the app is run through the meteor command, Meteor adds an extra process management layer that prevents Phusion Passenger from properly querying process statistics.

7. Management and inspection

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. You've already been introduced to this tool in section Understanding what happened.

Passenger-status has another mode, one for showing what requests are active and by which process. Run passenger-status --show=requests to see all requests that are currently being handled.

And there is another tool: passenger-memory-stats. This 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.

Note that the CPU and memory statistics are only accurate when Meteor is deployed as a bundle! Please learn more at Caveats.

8. Troubleshooting

If something doesn't work properly then the first place to look at is the global web server error log. This is because Phusion Passenger's stdout and stderr, as well as the stdout/stderr of all spawned applications, are redirected to the error log. You may find the error reason there.

You can find the web server error log as follows:

  • On Apache, this is the file that is configured in the global (not per-vhost) ErrorLog directive, and on most systems the default is /var/log/apache2/error.log.
  • On Nginx, this is the file that is configured in the global error_log directive. The error_log directive may also appear in the http section, but beware: that one is not the global error log. The default filename is $PREFIX/logs/error.log on self-compiled Nginx installations, where $PREFIX is the prefix on which you configured Nginx. For example, if you configured Nginx with --prefix=/opt/nginx, then the default error log location is /opt/nginx/logs/error.log. If you installed Nginx with a native package (e.g. through APT or YUM) then the default filename is probably /var/log/nginx/error.log.

Do you not see a useful message in the log file? Raise PassengerLogLevel or passenger_log_level to see more verbose messages.

If things still don't work, try consulting the Troubleshooting section in the manual. Or you can consult one of the support resources.

9. Conclusion

Passenger's background: where did it come from?

Phusion Passenger began in early 2008 was originally made to serve Ruby web applications. Since then, it has grown to be the most popular application server for Ruby. Unlike most Ruby application servers, both now and then, Phusion Passenger is designed to integrate with the web server, to take as much management work out of the administrator's hands, and generally to be "zero-maintenance".

But from the start, it was designed not to be Ruby-only. It was a little-known fact that Phusion Passenger also supported Python as early as mid-2008. Although we never marketed Python support and although we've always called our Python support "experimental", hosting providers such as Dreamhost were already successfully using it in production for serving Django and other Python apps.

In late 2012 we decided to raise Python support to a more official status, namely the beta status. In 2013, Python support was made production-ready, and Node.js and Meteor support were introduced.

Further reading

Please take a look at the extensive documentation. To stay up to date with the latest developments, please follow us on Twitter or follow the Phusion blog.

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!

Please enjoy Phusion Passenger, a product by Phusion. :-)