Phusion white papers Phusion overview

Phusion Blog

Turbocaching security changes

By Hongli Lai on February 9th, 2015

Phusion Passenger version 5.0.0 beta 3 was released today, with a number of changes to the turbocache. The turbocache is a component in Passenger 5 that automatically caches HTTP responses in an effort to speed up the application. The turbocache is not a feature-rich HTTP cache like Varnish, but instead it’s more like a “CPU L1 cache for the web” — small and fast, requires little configuration, but has fewer features by design.

The turbocache was implemented with HTTP caching standards in mind, namely RFC 7234 (HTTP 1.1 Caching) and RFC 2109 (HTTP State Management Mechanism). Our initial mindset in implementing the turbocache was like that of compiler implementors: if something is allowed by the standards, then we’ll implement it in order pursue maximum possible performance.

But it turns out that following the standards strictly may raise security concerns. A while ago, we were contacted by Chris Heald, who provided convincing cases on why the turbocache’s behavior is problematic from a security standpoint. Chris is a veteran Varnish user and has a lot of experience on the subject of HTTP caching.

The gist is that the turbocache made it too easy to accidentally cache responses which should not be cached. Imagine that a certain response contains sensitive information and is only meant to be served to one user. Such sensitive information may include security credentials or session cookies. If the application sets HTTP caching headers incorrectly, then the turbocache may serve that response to other users, resulting in an information leak.

Such problems are technically bugs in the application. After all, Passenger is just following the standards. But Chris asserted that such mistakes are very easily made. Indeed, he has seen quite a number of applications that send out incorrect HTTP caching headers. For this reason, he believes that the turbocache should be more conservative by default.

Cookies also deserve special attention. RFC 2109 mentions that cookies may only be cached when they are intended to be shared by multiple users. But it is impossible for Passenger to know the intention of the cookies without configuration from the application developer. At the same time, providing such configuration goes against the spirit of the turbocache, namely that it should be easy and automatic.

It was clear that something had to be done.

Turbocache changes

More conservative

After contemplating the issues, we’ve decided to make the turbocache more conservative in order to avoid the most common security issues.

In beta 1 and beta 2, the turbocache caches all “default cacheable responses”, as defined by RFC 7234. These are responses to GET requests; with status code 200, 203, 204, 300, 301, 400, 405, 410, 414 or 501; and for which no headers are set that prevent caching, e.g. “Cache-Control: no-store”. This means that a GET request which yields a 200 response with no caching headers, is actually cacheable per the standards, and so it was cached by the turbocache.

In beta 3, responses are no longer cached unless the application explicitly sends caching headers. That means that a GET request which yields a 200 response is only cached if the application sends an “Expires” or a “Cache-Control” header (which must not contain “private”, “no-store”, etc).

While it is still possible for some application responses to be unintentionally cached, this change solves the majority of the issues. The only way to avoid these issues out of the box is by disabling caching completely, which has the downside of not being able to leverage said caching features. Instead, we believe it is reasonable that we only cache requests in case the application asks for this explicitly. A potential caveat is that even though the application and Passenger respect the specifications, an application developer may not have a full understanding of how caching behaves according to said specs. A developer should choose to disable caching entirely in such cases.

Bugs fixed

While investigating Chris’s case, we also uncovered some bugs in the turbocache, such as the incorrect handling of certain headers. These bugs have been fixed. The full details can be found in the Passenger 5 beta 3 release notes.

Using the turbocache and speeding up applications

Now that the turbocache has changed in behavior, here are some practical tips on what you can do to make good use of the turbocache.

Learn about HTTP caching headers

The first thing you should do is to learn how to use HTTP caching headers. It’s pretty simple and straightforward. Since the turbocache is just a normal HTTP shared cache, it respects all the HTTP caching rules.

Set an Expires or Cache-Control header

To activate the turbocache, the response must contain either an “Expires” header or a “Cache-Control” header.

The “Expires” header tells the turbocache how long to cache a response. Its value is an HTTP timestamp, e.g. “Thu, 01 Dec 1994 16:00:00 GMT”.

The Cache-Control header is a more advanced header that not only allows you to set the caching time, but also how the cache should behave. The easiest way to use it is to set the max-age flag, which has the same effect as setting “Expires”. For example, this tells the turbocache that the response is cacheable for at most 60 seconds:

Cache-Control: max-age=60

As you can see, a “Cache-Control” header is much easier to generate than an “Expires” header. Furthermore, “Expires” doesn’t work if the visitor’s computer’s clock is wrongly configured, while “Cache-Control” does. This is why we recommend using “Cache-Control”.

Another flag to be aware of is the private flag. This flag tells any shared caches — caches which are meant to store responses for many users — not to cache the response. The turbocache is a shared cache. However, the browser’s cache is not, so the browser can still cache the response. You should set the “private” flag on responses which are meant for a single user, as you will learn later in this article.

And finally, there is the no-store flag, which tells all caches — even the browser’s — not to cache the response.

Here is an example of a response which is cacheable for 60 seconds by the browser’s cache, but not by the turbocache:

Cache-Control: max-age=60,private

The HTTP specification specifies a bunch of other flags, but they’re not relevant for the turbocache.

Only GET requests are cacheable

The turbocache currently only caches GET requests. POST, PUT, DELETE and other requests are never cached. If you want your response to be cacheable by the turbocache, be sure to use GET requests, but also be sure that your request is idempotent.

Avoid using the “Vary” header

The “Vary” header is used to tell caches that the response depends on one or more request headers. But the turbocache does not implement support for the “Vary” header, so if you output a “Vary” header then the turbocache will not cache your response at all. Avoid using the “Vary” header where possible.

Common application caching bugs

Even though the turbocache has become more conservative now, it is still possible for application responses to be unintentionally cached if the application outputs incorrect caching headers. Here are a few tips on preventing common caching bugs.

Varying response by Ajax

A common pattern is to return a different response depending on whether or not it was an Ajax call. For example, consider this Rails app, which returns a JSON response for Ajax calls, HTML response otherwise:

def show
  headers["Cache-Control"] = "max-age: 600"
  if request.xhr?
    render json: "show"
  else
    render
  end
end

This can cause the turbocache to return the JSON response for non-Ajax calls, or to return the HTML response for Ajax calls.

There are two ways to solve this problem:

  1. Set the “Vary: X-Requested-With” header so that the cache knows the response depends on this header. Rails’s request.xhr? method checks this header. Note that the turbocache currently disables caching altogether upon encountering a “Vary” header.
  2. Do not vary the response based on whether or not it is an Ajax call. Instead, vary the response based on the URI. For example, you can return JSON responses only if the URI ends with “.json”.

Be careful with caching when setting cookies

If your application outputs cookies then you should be careful with your caching headers. You should only allow the turbocache to cache the response if all cookies may be cacheable by multiple users. If any of your cookies contain user-specific information, or if you’re not sure, then you should set the “private” flag in “Cache-Control” to prevent the turbocache from caching it.

We realize that lots of responses can output cookies, so we’re working on ways to improve the cacheability of responses with cookies.

Set “Cache-Control: private” when working with sessions

If your application works with sessions then you must ensure that all your “Cache-Control” headers set the “private” flag so that the turbocache does not cache it.

Note that your app may work with sessions indirectly. Any Rails page which outputs a form will result in Rails setting a CSRF token in the session. Luckily Rails sets “Cache-Control: private” by default.

Performance considerations

The turbocache plays a major role in the performance of Passenger 5. The performance claims we made are with turbocaching enabled. Now that the turbocache has become more conservative, the performance claims still stand, but may require more application modifications than before.

By strictly following the caching standards, we had hoped that we’d be able to deliver performance for most apps out-of-the-box without modifications. But we also value security, and we value that more so than performance, which is why we made the turbocache more conservative.

But this raises a question: suppose that we can’t rely on the turbocache anymore as a major factor in performance, what else can we do to improve Passenger 5’s performance, and is it worth it?

There is in fact one more thing we can do. and that is by introducing a new operational mode which bypasses a layer. In the current Passenger 5 architecture, all requests go through a process called the HelperAgent. This extra process introduces some context switching overhead and processing overhead. The overhead is negligible in most real-world scenarios, but the overhead is very apparent in hello world benchmarks. It is possible to bypass this process, allowing clients to directly communicate with application processes. But doing so comes at a cost:

  • Some features — e.g. load balancing, multitenancy, out-of-band garbage collection, memory checking and statistics collection — are best implemented in the HelperAgent. Reimplementing them inside application processes is either difficult or less efficient.
  • Rearchitecting Passenger this way requires a non-trivial amount of development time.

So it remains to be seen whether bypassing the HelperAgent is worth it. Investing time in this means that we’ll have less time available to pursue other goals on the roadmap. What do you think about this? Just post a comment and let us know.

Conclusion

Passenger 5 beta 3 is the first “more or less usable in production” release of the Passenger 5 series. Previous releases were not ready for production, but with beta 3 we are confident enough that the most important issues are solved. The turbocache issue as described in this article is one of them. If you were on a previous Passenger 5 release, then we strongly recommend you to upgrade.

We would like to thank Chris Heald for his excellent feedback. We couldn’t have done this without him.

We expect the Passenger 5 final stable version to be released in February. Beta 3 is supposed to be the last beta. Next up will be Release Candidate 1, followed by the final stable release.

But the story doesn’t end there. We will publish a roadmap in the near future, which describes all the ambitious plans we have in store for Passenger. Passenger is constantly improving and evolving, so please stay tuned for updates.

Phusion Passenger 5 beta 3: more stable, turbocaching updates

By Hongli Lai on February 9th, 2015

We’ve just released version 5.0.0 beta 3 of the Phusion Passenger application server for Ruby, Python and Node.js. The 5.x series is also unofficially known under the codename “Raptor”, and introduces many major improvements such as performance enhancements, better tools for application-level visibility and a new HTTP JSON API for accessing Passenger’s internals.

So far, we’ve discouraged using 5.0 in production because it’s still in beta and because it was known to be unstable. But this changes with beta 3, which we consider “more or less ready for production”. This means that we’re confident that most of the major issues have been solved, but you should still exercise caution if you roll it out to production.

Final stable

In February, we will release the first Release Candidate version. If everything goes well, 5.0 final — which is officially ready for production — will also be released in February.

Changes in this version

Turbocaching updates

Main article: Turbocaching security changes

One of the major features in Phusion Passenger 5 is the turbocache, an integrated and high-performance HTTP response cache. It is responsible for a large part of the performance improvements in version 5. In beta 3, we’ve given the turbocache a few major updates:

We’ve been researching ways to improve the turbocache. Based on community feedback on the turbocache, we’ve found that the turbocache in its previous form wasn’t so useful. So we’ve come up with a few ways to allow apps to be better cacheable. These techniques are well-established and have been extensively used in advanced Varnish setups.

We’ve made the turbocache more secure and more conservative, based on excellent feedback from Chris Heald and the community. In previous versions, default cacheable responses (as defined by RFC 7234) were cached unless caching headers tell us not to. Now, default cacheable responses are only cached if caching headers explicitly tell us to. This change was introduced because there are many applications that set incorrect caching headers on private responses. This new behavior is currently not configurable, but there are plans to make it configurable in 5.0.0 release candidate 1.

Learn more about this change here.

Heroku support restored

Beta 1 and beta 2 didn’t work on Heroku because of bugs. With beta 3, Heroku support has been fixed. This closes GH-1329.

Nginx < 1.6 support dropped

Nginx versions earlier than 1.6 are no longer supported.

Bug fixes

Many major bugs have been fixed. These bugs include crashers, cookie handling issues, connection handling issues, etc:

  • Fixed various turbocache header handling issues.
  • Fixed cookie handling issues. Closes GH-1310.
  • Fixed various WebSocket issues. Closes GH-1306.
  • Fixed some crashes caused by race conditions. Closes GH-1326.
  • Fixed issues with handling POST data. Closes GH-1331.
  • Fixed some integer overflows. Fix contributed by Go Maeda. Closes GH-1357.
  • Fixed the passenger-status --show=union_station command. Closes GH-1336.

Miscellaneous

A new configuration option, passenger_response_buffer_high_watermark (Nginx) and PassengerResponseBufferHighWatermark (Apache), has been introduced. This allows for configuring the behavior of the response buffering system. Closes GH-1300.

State introspection has been improved. This means that passenger-status --show=requests shows better and more detailed output now.

Installing or upgrading

Here’s a quickstart:

gem install passenger --pre -v 5.0.0.beta3
cd /path-to-your-app
passenger start

The above is a very short excerpt of how to install or upgrade Phusion Passenger. For detailed instructions (which, for example, take users and permissions into account), please refer to the “RubyGems” section of the installation manuals:

Please note:

  • 5.0.0 beta 3 is a beta release. There are no major bugs left, but please exercise caution and report any issues.
  • There are no Homebrew or Debian packages for this release, because this release is still in beta!
  • There is also a 5.0.0 beta 3 release of Phusion Passenger Enterprise available. Please refer to the Customer Area.

Researching a potential new form of HTTP caching optimization

By Hongli Lai on January 6th, 2015

PIe in the sky

It’s been a while since we released the first beta of Phusion Passenger 5 (codename “Raptor”), the application server for Ruby, Python and Node.js web apps. We have received a lot of great feedback from the community regarding its performance, stability and features.

Passenger 5 isn’t production-ready yet, but we are getting close because 5.0 beta 3 will soon be released. But in the mean time, we would like to share a major new idea with you.

While Passenger 5 introduced many performance optimizations and is much faster than Passenger 4, the impact on real-world application performance varies greatly per application. This is because in many cases the overall performance is more dependent on the application than on the app server.

It’s obvious that just making the app server itself fast is not enough to improve overall performance. So what else can the app server do? After contemplating this question for some time, we believe we have found an answer in the form of a modified HTTP caching mechanism. Its potential is huge.

Update: Over the course of the day, readers have made us aware that some of the functionality can also be achieved through Varnish and through the use of Edge Side Includes, but there are also some ideas which cannot be achieved using only Varnish. These ideas require support from the app. Please read this article until the end before drawing conclusions.

Please also note that the point of this article is not to show we can “beat” Varnish. The point is to share our ideas with the community, to have a discussion about these ideas and to explore the possibilities and feasibility.

Turbocaching

One of the main new features in Passenger 5 is turbocaching. This is an HTTP cache built directly in Passenger so that it can achieve much higher performance than external HTTP caches like Varnish (update: no, we’re not claiming to be better than Varnish). It is fast and small, specifically designed to handle large amounts of traffic to a limited number of end points. For that reason, we described it as a “CPU L1 cache for the web”.


Turbocaching is a major contributor of Passenger 5’s performance

The turbocache has the potential to improve app performance dramatically, no matter how much work the app does. This is seen in the chart above. A peculiar property is that the relative speedup is inversely proportional to the app’s native performance. That is, the slower your app is, the bigger the speedup multiplier you can get from caching. At worst, caching does not hurt. In extreme cases — if the app is really slow — you can see a hundred fold performance improvement.

The limits of caching

So far for the potential of caching, but reality is more nuanced. We have received a lot of feedback from the community about the Passenger 5 beta, including feedback about its turbocache.

As expected, the turbocache performs extremely well in applications that serve data that is publicly cacheable by everyone, i.e. they do not serve data that is login-specific. This includes blogs and other sites that consist mostly of static content. The Phusion Passenger website itself is also an example of a mostly static site. But needless to say, this still makes the turbocache’s usefulness rather limited. Most sites serve some login-specific data, even if it’s just a navigation bar displaying the username.

However, these limitations apply to all other HTTP caches too. For example, the Varnish HTTP cache has been used very successfully to speed up WordPress. But Varnish doesn’t help a lot with logged-in traffic.

Even the CloudFlare CDN — which is essentially a geographically distributed HTTP cache — does not help a lot with logged-in traffic. Although CloudFlare can reduce the bandwidth between the origin server and the cache server through its Railgun technology, it doesn’t reduce the load on the origin server, which is what we are after.

Update: some readers have pointed out that Varnish supports Edge Side Include (ESI), which is like a text postprocessor at the web server/cache level. But using ESI only solves half of the problem. Read on for more information.

A glimmer of hope

Hope is not all lost though. We have identified two classes of apps for which there is hope:

  1. Apps which have more anonymous traffic than logged in traffic. Examples of such apps include Ted.com, Wikipedia, Imgur, blogs, news sites, video sites, etc. Let’s call these mostly-anonymous apps. What if we can cache responses by user, so that anonymous users share a single cache entry?
  2. Apps which serve public data for the most part. Examples of such apps include: Twitter, Reddit, Discourse, discussion forums. Let’s call these mostly-public apps. Most of the data that they serve is the same for everyone. There are only minor variations, e.g. the a navigation bar that displays the username, and secured pages. What if we can cache the cacheable content, and skip the rest?

Class 1: caching mostly-anonymous apps

There is almost a perfect solution for making apps in the first class cacheable: the HTTP Vary header. This header allows you to send a different cached response, based on the value of some header that is sent by the client.

For example, suppose that your app…

  • …serves gzip-compressed responses to browsers that support gzip compression.
  • …serves regular responses to browsers that don’t support gzip compression.

You don’t want a cache to serve gzipped responses to browsers that don’t support gzip. Browsers tell the server whether they support gzip by sending the Accept-Encoding: gzip header. If the application sets the Vary: Accept-Encoding header in its responses, then the cache will know that that particular response should only be served to clients with the particular Accept-Encoding value that it has received now.

HTTP caching Vary header effect
The Vary response header makes HTTP caches serve different cached responses based on the headers the browsers send.

In theory, we would be able to cache responses differently based on cookies (Vary: Cookie). Each logged in user would get its own cached version. And because most traffic is anonymous, all anonymous users can share cache entries.

Unfortunately, on the modern web, cookies are not only set by the main site, but also by third-party services which the site uses. This includes Google Analytics, Youtube and Twitter share buttons. The values of their cookies can change very often and often differ on a per-user basis, probably for the purpose of user tracking. Because these widely different values are also included in the cache variation key, they make it impossible for anonymous users to share cache entries if we were to try to vary the cache by the Cookie header. The situation is so bad that Varnish has decided not to cache any requests containing cookies by default.

Even using Edge Side Include doesn’t seem to help here. The value of the cookie header can change quickly even for the same user, so when using Edge Side Include the cache may not even be able to cache the previous user-specific response.

The eureka moment: modifying Vary

While the Vary header is almost useless in practice, the idea of varying isn’t so bad. What we actually want is to vary the cache by user, not by the raw cookie value. What if the cache can parse cookies and vary the cached response by the value of a specific cookie, not the entire header?

And this is exactly what we are researching for Passenger 5 beta 3. Initial tests with a real-world application — the Discourse forum software — show promising results. Discourse is written in Ruby. We have modified Discourse to set a user_id cookie on login.

# lib/auth/default_current_user_provider.rb

TURBOCACHE_COOKIE = "user_id"

def log_on_user(user, session, cookies)
  ...
  cookies.permanent[TURBOCACHE_COOKIE] = { value: user.id, httponly: true }
  ...
end

We modified Passenger to parse cookies, and to vary turbocache responses based on the value of this user_id cookie. We invoke Passenger like this:

passenger start --vary-turbocache-by-cookie user_id

This changeset can be seen in Github commit a760649cd7.

The result is a Discourse where all anonymous users share the same cache entry. Uncached, Discourse performance is pretty constant at 97 req/sec no matter which app server you use. But with turbocaching, performance is 19 000 req/sec.

This is caching that Varnish and other “normal” HTTP caches (including CloudFlare) could not have done*. The benefit that turbocaching adds in this scenario is exactly in line with our vision of a “CPU L1 cache” for the web. You can still throw in Varnish for extra caching on top of Passenger’s turbocaching, but Passenger’s turbocaching’s provides an irreplaceable service.

* Maybe Varnish’s VCL allows it, but we have not been able to find a way so far. If we’re wrong, please let us know in the comments section.

Class 2: caching mostly-public apps

Apps that serve pages where most data is publicly cacheable, except for small fragments, appear not to be cacheable at the HTTP level at all. Currently these apps utilize caching at the application level, e.g. using Rails fragment caching or Redis. View rendering typically follows this sort of pseudo-algorithm:

send_response("<nav>Welcome " + current_user_name "!</nav>")
cached_fragment = fetch_from_cache("rest_of_page")
if cached_fragment != null
    send_response(cached_fragment)
else
    fragment = render_rest_of_page()
    store_in_cache("rest_of_page", fragment)
    send_response(fragment)

However, this still means the request has to go through the application. If there is a way to cache this at the Passenger level then we can omit the entire application, boosting the performance even further.

We’ve come to the realization that this is possible, if we change the app into a “semi single page app”:

  1. Instead of rendering pages on the server side, render them on the client side, e.g. using Ember. This way, the view templates can be simple static HTML files, which are easily HTTP cacheable.
  2. PushState is then used to manipulate the location bar, making it feel like a regular server-side web app.
  3. The templates are populated using JSON data from the server. We can categorize this JSON data in two categories:
    1. User-independent JSON data, which is HTTP-level cacheable. For example, the list of subforums.
    2. User-specific JSON data, which is not HTTP-level cacheable. For example, information about the logged in user, such as the username and profile information.

      And here lies the trick: we only load this data once, when the user loads the page. When the user clicks on any links, instead of letting the browser navigate there, the Javascript loads the user-independent JSON data (which is easily cacheable), updates the views and updates the location bar using PushState.

By using this approach, we reduce the performance impact of non-cacheable fragments tremendously. Normally, non-cacheable page fragments would make every page uncacheable. But by using the approach we described, you would only pay the uncacheability penalty once, during the initial page load. Any further requests are fully cacheable.

And because of the use of HTML PushState, each page has a well-defined URL. This means that, despite the app being a semi-single-page app, it’s indexable by crawlers as long as they support Javascript. GoogleBot supports Javascript.

Discourse is a perfect example of an app that’s already architected this way. Discourse displays the typical “navigation bar with username”, but this is only populated on the first page load. When the user clicks on any of the links, Discourse queries JSON from the server and updates the views, but does not update the navbar username.

An alternative to this semi-single page app approach is by using Edge Side Include technology, but adoption of the technology is fairly low at this point. Most developers don’t run Varnish in their development environment. In any case, ESI doesn’t solve the whole problem: just half of it. Passenger’s cookie varying turbocaching feature is still necessary.

Even when there are some protected/secured subforums, the turbocache cookie varying feature is powerful enough make even this scenario cacheable. Suppose that the Discourse content depends on the user’s access level, and that there are 3 access levels: anonymous users, regular registered members, staff. You can put the access level in a cookie, and vary the cache by that:

cookies.permanent[TURBOCACHE_COOKIE] = { value: user.access_level, httponly: true }

That way, all users with the same access level share the same cache entry.

Due to time constraints we have not yet fully researched modifying Discourse this way, but that leads us to the following point.

Call for help: please participate in our research

The concepts we proposed in this blog post are ideas. Until tested in practice, they remain theory. This is why we are looking for people willing to participate in this research. We want to test these ideas in real-world applications, and we want to look for further ways to improve the turbocache’s usefulness.

Participation means:

  • Implementing the changes necessary to make your app turbo-cache friendly.
  • Benchmarking or testing whether performance has improved, and by how much.
  • Actively working with Phusion to test ideas and to look for further room for improvements. We will happily assist active participants should they need any help.

If you are interested, please send us an email at info@phusion.nl and let’s talk.

Discuss this on Hacker News

Also, if you liked this article then maybe you would be interested in our newsletter. It’s low volume, but we regularly post interested updates there. Just enter your email address and name. No spam, we promise.



Phusion Passenger now supports the new Ruby 2.1 Out-Of-Band GC

By Hongli Lai on January 31st, 2014


Phusion Passenger is a fast and robust web server and application server for Ruby, Python, Node.js and Meteor. Passenger takes a lot of complexity out of deploying web apps, and adds powerful enterprise-grade features that are useful in production. High-profile companies such as Apple, New York Times, AirBnB, Juniper, American Express, etc are already using it, as well as over 350.000 websites.

Yesterday, Aman Gupta announced an Out-Of-Band garbage collector for Ruby 2.1. What is an “Out-Of-Band garbage collector”? It means that the garbage collector is run in between requests, instead of during a request. While the garbage collector is running, other processes can serve requests. This way visitors will never experience the slight delay that is caused by the garbage collector, much improving response times. We just implemented support for this in Phusion Passenger.

Classical out-of-band garbage collection

Out-of-band garbage collection is not a new idea. The idea was first introduced in Unicorn several years ago. Its mechanism was simple: disable automatic garbage collection, and manually run the garbage collector at the end of every N requests.

Last year, we introduced a much improved version of Unicorn’s out-of-band garbage collection mechanism in Phusion Passenger 4. This feature was originally contributed by AppFolio, and since then many further improvements have been made.

  • Unicorn’s out-of-band garbage collection doesn’t work well with multithreaded servers, because a garbage collection is a stop-the-world action that blocks all threads. Phusion Passenger’s mechanism lifts this limit by intelligently coordinating the garbage collector and threads.
  • Unicorn’s mechanism is susceptible to occasional pathological behavior. It is possible for many, or all, Unicorn processes to be simultaneously running the out-of-band garbage collector. During that short period of time, no requests can be served, and visitors will experience a delay. Phusion Passenger’s mechanism ensures that only 1 process can run the garbage collector at a time, thereby eliminating this problem.
  • Phusion Passenger’s mechanism is more flexible, and can be used for work other than just garbage collection.

The results were impressive. AppFolio observed an average response time reduction of 100 ms.

Before Out-Of-Band GC After Out-Of-Band GC
Before and after applying out of band GC at AppFolio

Unfortunately, this Out-Of-Band GC mechanism (running the GC every few requests) is still suboptimal, as we had pointed out last year:

  • If a request generates a lot of garbage, then delaying the GC for a few more request can result in high peak memory usage.
  • If the garbage collector doesn’t actually need to be run yet, then running it anyway wastes CPU cycles.

The new Ruby 2.1 Out-Of-Band GC

Fortunately, Ruby has recently introduced many useful garbage collector improvements. Ruby 2.1 introduced a semi-generational garbage collector. Aman Gupta built an Out-Of-Band GC mechanism on top of the recent improvements, which is almost exactly what we needed in Phusion Passenger.

Today, we’ve submitted a pull request to make his Out-Of-Band GC mechanism work well with Phusion Passenger, and we’ve introduced support in Phusion Passenger for his Out-Of-Band GC mechanism. Using it is very easy. First, add our patched gctools to your Gemfile:

gem "gctools", :github => "FooBarWidget/gctools", :require => false

Next, put this in your config.ru:

require "gctools/oobgc"
GC::OOB.setup

Now you can enable the Out-Of-Band GC feature in Phusion Passenger by using the :gctools_oobgc strategy:

PhusionPassenger.require_passenger_lib 'rack/out_of_band_gc'
use PhusionPassenger::Rack::OutOfBandGc, :strategy => :gctools_oobgc

Aman Gupta’s improvements are very impressive indeed. With Ruby 2.1, his average OOBGC pause time (oobgc.mean) “went from 125ms to 50ms thanks to RGenGC”. And “the number of out-of-band collections (oobgc.count) also went down, since the new OOBGC only runs when necessary”.

From Aman Gupta’s blog: “The overall result is much less CPU time (oobgc.sum) spent doing GC work between requests”:

Conclusion

Support for Aman Gupta’s Ruby 2.1 Out-Of-Band GC mechanism will be included in the next release of Phusion Passenger. It’s not completely finished yet: as seen in our pull request, there are still some issues to be fleshed out. But the results are very promising indeed. Although the Ruby hype is over, there are still plenty of improvements going on.

Discuss this on Hacker News.

Like our articles? Consider subscribing to our newsletter. You can unsubscribe any time.



Meteor support for Phusion Passenger has been open sourced

By Hongli Lai on November 1st, 2013

Meteor

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.

Are “traditional”[1] frameworks like Rails in danger? We at Phusion tend to believe that each framework has its own strengths and weaknesses, with no single framework being a silver bullet for all possible use cases. But there are many Meteor advocates out there who believe differently. Josh Owens from from Differential claims that Rails has seen its last days.

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

Announcing Phusion Passenger + Meteor

Whatever the result will be, the Phusion Passenger application server will be around to help you simplify your deployments and keeping your systems running smoothly.

Meteor support was previously an Enterprise-only feature. But just like we open sourced Node.js support a week ago, we are now open sourcing Meteor support. We are strong open source supporters at heart, and we believe that it’s time to give back to the community. The source code is already available on Github.

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.

Getting started

Update: for the most recent version of this tutorial, please refer to Phusion Passenger: Meteor tutorial.

Installing

Visit the Phusion Passenger download page. There are tailor-made, polished installation methods for OS X, Debian/Ubuntu, Heroku, etc. 🙂 You need at least version 4.0.23.

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:

server {
    server_name www.foo.com;
    root /webapps/leaderboard/public;
    passenger_enabled on;
    passenger_app_env development;
}

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.

There are many configuration options that you can tweak. Please refer to the Phusion Passenger manuals.

Deploying to Nginx during production

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

Deploying a Meteor bundle

When deploying a Meteor bundle, we’re treating Meteor as a regular Node.js app. You do not need to have Meteor installed, just Node.js.

Create a bundle first and upload it to your production server:

meteor bundle leaderboard.tar.gz
scp leaderboard.tar.gz someserver:/webapps/leaderboard

On your production server, extract the bundle and install NPM modules:

cd /webapps/leaderboard
# This will create a directory /webapps/leaderboard/bundle
tar xzvf leaderboard.tar.gz
cd bundle
# Install whatever NPM modules your app needs. See the bundle README.
npm install fibers@1.0.1

You need to rename the main.js file in the bundle to app.js, and create a public directory, as per the Phusion Passenger requirements for Node.js.

mv main.js app.js
mkdir public

Now that the directory structure has been setup, create a virtual host in Nginx:

http {
    ...
    server {
       server_name www.foo.com;
       root /webapps/leaderboard/bundle/public;
       passenger_enabled on;
       passenger_set_cgi_param MONGO_URL mongodb://localhost:3002/meteor;
       passenger_set_cgi_param ROOT_URL http://www.foo.com;
    }
}

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

Phusion Passenger comes with an extensive manual.

Running into any trouble? Please check out the troubleshooting section of the documentation.

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!

Discuss this on Hacker News.

Want to stay up to date with the latest Phusion news, including news about our Meteor support? Please sign up for our newsletter. You can unsubscribe any time.



Phusion Passenger’s Node.js support has been open sourced

By Hongli Lai on October 23rd, 2013

Node.js

Phusion Passenger‘s Node.js support was originally an Enterprise-only feature. Since the introduction of Node.js support, we’ve received awesome feedback from Enterprise customers. Having said that, we are strong open source supporters at heart, and we believe that it’s time to give back to the community.

Today, we are pleased to announce that we are open sourcing Node.js support. Everybody can freely use, modify and distribute this, as in freedom and as in beer.

For those who are not familiar with Phusion Passenger: it is a fast and robust web server and application server for Ruby, Python, Node.js and Meteor. Passenger takes a lot of complexity out of deploying web apps, and adds powerful enterprise-grade features that are useful in production. High-profile companies such as Apple, New York Times, AirBnB, Juniper, American Express, etc are already using it, as well as over 350.000 websites.

The source code for the Node.js support is already available on Github. We’ve also written a detailed Phusion Passenger + Node.js tutorial.

More information about Node.js support will follow soon, so please keep an eye on this blog for the announcement, or subscribe to our newsletter using the form below.

Discuss this on Hacker News.



Debian and Ubuntu packages for Phusion Passenger

By Hongli Lai on September 11th, 2013

Update: this is the original announcement for our APT repository. For the latest instructions, please visit the download page.

We are pleased to announce the availability of the official Phusion Passenger APT repository. This APT repository contains Phusion Passenger packages for multiple versions of Debian and Ubuntu. These packages are automatically built by our build server after we push out a source release, and thus are always up to date with the official source releases. Phusion Passenger Enterprise is also packaged.

The repository even includes an up-to-date version of Nginx (1.4.2 at the time of writing), compiled with Phusion Passenger support. Even if you do not use Phusion Passenger, this repository is an excellent way to get the latest version of Nginx. This Nginx package works even if Phusion Passenger is not installed. We will regularly update the Nginx package so that it stays up-to-date with upstream Nginx releases.

Distributions and architectures

Packages are built for x86 and x86_64. Currently supported distributions are:

  • Ubuntu 10.04 “Lucid”
  • Ubuntu 12.04 “Precise”
  • Ubuntu 13.04 “Raring”
  • Debian 6 “Squeeze”
  • Debian 7 “Wheezy”

Our policy is to support all Ubuntu LTS releases that are still supported by Canonical, plus the latest non-LTS Ubuntu release, plus all Debian releases that are still supported by Debian.

Adding our APT repository

Packages are signed by “Phusion Automated Software Signing (auto-software-signing@phusion.nl)”, fingerprint 1637 8A33 A6EF 1676 2922 526E 561F 9B9C AC40 B2F7. Install our PGP key:

gpg --keyserver keyserver.ubuntu.com --recv-keys 561F9B9CAC40B2F7
gpg --armor --export 561F9B9CAC40B2F7 | sudo apt-key add -

Our APT repository is stored on an HTTPS server so you may need to add HTTPS support for APT:

sudo apt-get install apt-transport-https

Next, create a file /etc/apt/sources.list.d/passenger.list and insert one of the following lines, depending on your distribution.

Phusion Passenger open source:

deb https://oss-binaries.phusionpassenger.com/apt/passenger lucid main
deb https://oss-binaries.phusionpassenger.com/apt/passenger precise main
deb https://oss-binaries.phusionpassenger.com/apt/passenger raring main
deb https://oss-binaries.phusionpassenger.com/apt/passenger squeeze main
deb https://oss-binaries.phusionpassenger.com/apt/passenger wheezy main

Phusion Passenger Enterprise:

deb https://download:YOUR_DOWNLOAD_TOKEN@www.phusionpassenger.com/enterprise_apt lucid main
deb https://download:YOUR_DOWNLOAD_TOKEN@www.phusionpassenger.com/enterprise_apt precise main
deb https://download:YOUR_DOWNLOAD_TOKEN@www.phusionpassenger.com/enterprise_apt raring main
deb https://download:YOUR_DOWNLOAD_TOKEN@www.phusionpassenger.com/enterprise_apt squeeze main
deb https://download:YOUR_DOWNLOAD_TOKEN@www.phusionpassenger.com/enterprise_apt wheezy main

You can find the correct value for ‘YOUR_DOWNLOAD_TOKEN’ in the Customer Area.

After creating /etc/apt/sources.list.d/passenger.list, run:

sudo chown root: /etc/apt/sources.list.d/passenger.list
sudo chmod 600 /etc/apt/sources.list.d/passenger.list
sudo apt-get update

Installing packages

Open source

To install Phusion Passenger for Nginx:

sudo apt-get install nginx-full passenger

Then edit /etc/nginx/nginx.conf, and uncomment passenger_root and passenger_ruby. Finally, run sudo service nginx restart.

To install Phusion Passenger for Apache:

sudo apt-get install libapache2-mod-passenger

To install Phusion Passenger Standalone:

sudo apt-get install passenger

Enterprise

Before installing packages, download your license key from the Customer Area and save it as /etc/passenger-enterprise-license.

To install Phusion Passenger for Nginx:

sudo apt-get install nginx-full passenger-enterprise

Then edit /etc/nginx/nginx.conf, and uncomment passenger_root and passenger_ruby. Finally, run sudo service nginx restart.

To install Phusion Passenger for Apache:

sudo apt-get install libapache2-mod-passenger-enterprise

To install Phusion Passenger Standalone:

sudo apt-get install passenger-enterprise

Credits

Special thanks go to John Leach from Brightbox for helping us. John has been maintaining third-party Ubuntu packages for Phusion Passenger for years. It is with his help and knowledge of Debian packaging that we were able to setup this official APT repository. oss-binaries.phusionpassenger.com is hosted on a server by Brightbox.

Discuss this on Hacker News

If you would like to stay up to date with Phusion news, please fill in your name and email address below and sign up for our newsletter. We won’t spam you, we promise.



Phusion Passenger Enterprise gem server

By Hongli Lai on September 6th, 2013

It is now possible to install Phusion Passenger Enterprise through our gem server. Previously, customers were able to download the gem from the Customer Area and using HTTP basic authentication to automate gem downloads. As of today, customers can use the gem command, and even use gem tools such as Bundler to install Phusion Passenger Enterprise. This should also make installation automation a lot easier.

To install the Phusion Passenger Enterprise gem, run the following commands:

gem source --add https://download:YOUR_DOWNLOAD_TOKEN@www.phusionpassenger.com/enterprise_gems/
gem install passenger-enterprise-server

Here, you must substitute YOUR_DOWNLOAD_TOKEN with the one you find in the Customer Area.
And notice the trailing slash in the URL! It is very important.

Future plans and conclusion

We’ve been working a lot on packaging and distribution lately. Our goal is to make the installation of both of the open source and the Enterprise variant as easy as possible.

In the past few weeks, we’ve been working on eliminating the need to compile Phusion Passenger for all Linux users. This goal consists of multiple steps, but the first goal has already been met: installation Phusion Passenger Standalone no longer requires compilation for most Linux users. This is also the first step towards making Phusion Passenger work on Heroku.

In order to make installation easier for OS X users, we’ve also introduced a Homebrew recipe for Phusion Passenger. Every time we release a new Phusion Passenger version, the Homebrew recipe is automatically updated!

Our next step is to publish Debian/Ubuntu APT repositories for both the open source and the Enterprise variants of Phusion Passenger. The basic toolchain is now in place, and we are working on integrating the toolchain on our servers.

We would like to thank all our customers for using Phusion Passenger Enterprise and for supporting the continuous development of Phusion Passenger.

No more compiling Phusion Passenger

By Hongli Lai on August 15th, 2013

On Unix systems, compiling software to install it is often the norm. However compiling takes CPU time and memory, and on some systems it is preferable not to have a compiler installed for security reasons. Especially compiling C++ code is memory-intensive, and could require as much as 700 MB of RAM. Since Phusion Passenger is written largely in C++, the need to compile Phusion Passenger could be problematic for some users, e.g. users on small VPSes with little memory.

Another problem is the need to compile Nginx. Unlike Apache, Nginx does not support dynamically loadable modules. So to add Phusion Passenger support, Nginx must be recompiled. Some users do not like doing this.

Today’s solutions

There are some solutions for this problem that you can already use with the current version of Phusion Passenger:

  1. You can use our Debian and Ubuntu packages, kindly contributed by John Leach from Brightbox. John Leach has been helping us with Debian packaging for years now, and he often updates his packages within a few days after an official release. Packages for both the Apache mode and the Nginx mode of Phusion Passenger are available.
    debian-square ubuntu-logo

    If you didn’t already know about this, you should. Strongly recommended. It solves nearly every problem users have with installing Phusion Passenger. Just run apt-get install libapache2-mod-passenger or apt-get install nginx-full, and you’re done. The provided Nginx package is the exact same as the one in Debian/Ubuntu, but with Phusion Passenger support added. This means you get to keep your /etc/init.d/nginx init script and other nice things.

    There are just two drawbacks at the moment: Phusion Passenger Standalone (described later in this article) is not packaged, and Phusion Passenger Enterprise is not packaged.

  2. You can precompile Phusion Passenger on one of your machines, and copy over the binaries to another machine.
  3. Users who do not mind compiling Phusion Passenger but do mind compiling Nginx, can use a reverse proxy setup with Phusion Passenger Standalone.

Tomorrow’s solution: binaries for Phusion Passenger Standalone

While the current Debian packages are great, we haven’t been standing still. There is still room for improvement. One of the things that we’ve been working on is a generic binary building infrastructure for Phusion Passenger. The end goal is to eliminate the need to compile Phusion Passenger, for all users that are using Linux on the x86 and x86_64 architectures, regardless of the distribution that they’re using.

This infrastructure automatically builds generic, multi-distribution-compatible Linux binaries for x86 and x86_64 every time we push commits to our Git repository. The Phusion Passenger installers can then just download binaries from the Phusion server instead of compiling them from source. The installers automatically check whether the downloaded binaries work on the current system, and if not, falls back to compiling. For 95%-99% of the users, this system effectively eliminates the need to compile Phusion Passenger. Furthermore, this infrastructure compiles binaries for both the open source variant and the Enterprise variant.

Rome was not built in one day, so we’re tackling this problem iteratively. Starting from the next version of Phusion Passenger, these automatically built binaries will be used in Phusion Passenger Standalone.

What is Phusion Passenger Standalone, and how is it related to compiling?

For those of you who are not familiar with Phusion Passenger Standalone: it is a third mode of Phusion Passenger, alongside with the Apache mode and the Nginx mode, introduced in 2010. In Standalone mode, Phusion Passenger does not require an external web server, and can be started with just a single command: passenger start. This command starts a fully-featured Phusion Passenger instance. In fact, it is powered by an Nginx core, making it very fast and lightweight, and extremely good at serving static assets. You can even expose Phusion Passenger Standalone immediately on the public Internet without using a reverse proxy, something e.g. Unicorn cannot safely do (“Slow Clients Are Problematic”). Therefore, Phusion Passenger Standalone is the easiest way to get a Ruby web app up and running with minimal hassle and with great performance. It can also be installed in a reverse proxy setup behind Nginx, for those who do not want to or cannot compile Nginx.

The following video, originally created in 2010, demonstrates Phusion Passenger Standalone. Note that back then it was still called “Phusion Passenger Lite”. As you can see, Phusion Passenger Standalone compiles its own runtime when it is run for the first time. Compiling can take a few minutes. Starting from the next version, starting Phusion Passenger Standalone for the first time takes a few seconds.

Day after tomorrow’s solutions: fully-automated binary building and package building

We have two goals for the futher future:

  1. Automatically download binaries when installing Phusion Passenger for Apache and Phusion Passenger for Nginx.
  2. To fully automate the building of Debian packages. Although the generic binaries should work for most of our users, installing Debian packages is easier still, and integrates better with the OS. We’re working on a system that will publish 100% working Debian packages 15 minutes after we publish the source code for a new release, so that no human intervention is required to publish Debian packages. This will greatly increase ease of installation and upgrade for users. There will also be automatically built Debian packages for Enterprise customers.

    We’ve already begun working on integrating Debian packaging scripts into our main Git repository. We’ve also written an automated set of tests for checking whether packages built with these scripts work correctly. These tests are run by our continuous integration server on every commit, so you could say that we’re employing “continuous packaging”.

Conclusion

We’re working hard on making Phusion Passenger as easy to install as possible. We take usability very seriously, and we invite everyone to review our generic binary building system, our Debian packaging scripts, as well as our packaging tests. All code is open source and available on Github.

If you would like to stay up to date with Phusion news, please fill in your name and email address below and sign up for our newsletter. We won’t spam you, we promise.



Technology Preview: Introducing Flying Passenger

By Hongli Lai on July 3rd, 2013

Phusion Passenger is software that deploys Ruby and Python web apps, by integrating into Apache and Nginx and turning them into a fully-featured application server. It is very fast, stable and robust and thus used by the likes of New York Times, AirBnB, Symantec, Pixar, etc. It comes with many features that make your life easier and your application perform better.

“Flying Passenger” is a technology which allows one to decouple Phusion Passenger’s life time from the web server’s life time, so that the web server can be independently restarted from Phusion Passenger, and from any of the application processes served by Phusion Passenger.

Normally, Phusion Passenger starts together with the web server, and shuts down together with the web server. The advantages of this default behavior is that it makes Phusion Passenger easy to administer: one only has to deal with the web server process and can expect all relevant processes to be cleaned up after a web server shut down. However this also brings about a disadvantage: every time one restarts the web server (e.g. to make a minor configuration change), Phusion Passenger and all its application processes also get restarted.

This problem is solved by “Flying Passenger”, which is an advanced mode of operation in Phusion Passenger that allows the web server to be indepedently restarted from Phusion Passenger. When this mode is enabled:

  • One must start Phusion Passenger separately from the web server, namely by starting the Flying Passenger daemon. This daemon must — to an extent — be separately configured and managed from the web server.
  • The web server must be configured to forward requests to the Flying Passenger daemon.
  • You should beware of the caveats and limitations, which will be described in this article.

Flying Passenger is fully documented in the Phusion Passenger manual. This article serves as an introduction.

Differences with existing reverse proxy setups

You may be wondering how this differs from existing reverse proxy setups with other application servers, e.g. Nginx+(G)Unicorn, Nginx+Puma, or Nginx+uWSGI. Most other application servers can serve only one application per instance. Flying Passenger works just like Phusion Passenger for Nginx: it can serve multiple applications. Almost all Phusion Passenger for Nginx features are preserved in the Flying Passenger mode: dynamic process scaling, process supervision, user switching, real-time response buffering, etc all work as one is used to in Phusion Passenger for Nginx. However, Flying Passenger is only partially configured through the Nginx configuration file; some configuration is set through command line options.

Python users may see parallels between Flying Passenger’s mode of operation and uWSGI Emperor’s.

Availability

Flying Passenger will become available in the Enterprise variant of the next Phusion Passenger release, namely version 4.0.6.

At this time, this feature is only available in Phusion Passenger for Nginx. You must have Phusion Passenger for Nginx properly installed. Flying Passenger is not available in Phusion Passenger for Apache, and also not in Phusion Passenger Standalone.

Basic usage

Start the Flying Passenger daemon by invoking the flying-passenger command. The only required option is --socket-file. Depending on whether you wish to enable User Switching, you have to start flying-passenger with root privileges or not.

$ sudo flying-passenger --socket-file=/var/run/flying-passenger.sock
I, [2013-06-14T09:10:13.095339 #77179]  INFO -- : Welcome to Flying Passenger 4.1.0
I, [2013-06-14T09:10:13.095339 #77179]  INFO -- : Starting PassengerWatchdog...
I, [2013-06-14T09:10:13.097036 #77179]  INFO -- : PassengerWatchdog started on PID 77181
...
I, [2013-06-14T09:10:13.129017 #77179]  INFO -- : PassengerWatchdog initialized properly
I, [2013-06-14T09:10:13.129127 #77179]  INFO -- : Flying Passenger up and listening on /var/run/flying-passenger.sock!

Now configure Phusion Passenger for Nginx to make use of the Flying Passenger daemon, by setting the passenger_fly_with option to the socket filename:

http {
    ...
    passenger_fly_with /var/run/flying-passenger.sock;
    ...
}

After (re)starting Nginx, Nginx + Flying Passenger is fully operational:

$ sudo /path-to/nginx

You can test it by adding a virtual host for a web app:

http {
    ...

    server {
        listen 80;
        server_name www.foo.local;
        root /webapps/foo/public;
        passenger_enabled on;
    }
}

Verify that it works by making an HTTP request to it:

$ curl http://www.foo.local/

Now let’s verify that restarting the web server does not restart the just-spawned application process. Run passenger-status to obtain the PID of the application process:

$ sudo passenger-status
Version: 4.1.0
Date   : 2013-06-14 09:21:51 -0400
----------- General information -----------
Max pool size : 6
Processes     : 1
Requests in top-level queue : 0

----------- Application groups -----------
/webapps/foo#default:
  App root: /webapps/foo
  Requests in queue: 0
  * PID: 77283   Sessions: 0       Processed: 1       Uptime: 2s
    CPU: 1%      Memory  : 8M      Last used: 2s ago

As you can see, the PID of the application process is 77283. Now let’s see what happens if we restart Nginx:

$ sudo /path-to/nginx -s stop
$ sudo /path-to/nginx
$ sudo passenger-status

The application process should remain there, unchanged:

$ sudo passenger-status
Version: 4.1.0
Date   : 2013-06-14 09:21:51 -0400
----------- General information -----------
Max pool size : 6
Processes     : 1
Requests in top-level queue : 0

----------- Application groups -----------
/webapps/foo#default:
  App root: /webapps/foo
  Requests in queue: 0
  * PID: 77283   Sessions: 0       Processed: 1       Uptime: 18s
    CPU: 1%      Memory  : 8M      Last used: 18s ago

Configuring Flying Passenger

Flying Passenger gets some configuration from the web server, but not all. In particular, most web server directives that are only valid in the http context, e.g. passenger_log_level, have no effect when using Flying Passenger. Instead, you are supposed to pass these configuration directives through command line options to the Flying Passenger daemon. Configuration directives that have no effect on Flying Passenger are documented as such. You can assume that configuration directives that are not documented as such, work fine on Flying Passenger.

For example, to achieve the same effect as setting passenger_log_level to 2, run the Flying Passenger daemon as follows:

$ sudo flying-passenger --socket-file=/var/run/flying-passenger.sock --log-level=2

Currently, not all configuration directives have a Flying Passenger equivalent. Run the following command to see an overview of available options:

$ flying-passenger --help

Managing the Flying Passenger daemon

The Flying Passenger daemon runs in the foreground by default. This is undesirable on server environments. You can make it go into the background by passing --daemonize, --log-file and --pid-file:

$ sudo flying-passenger --socket-file=/var/run/flying-passenger.sock \
    --daemonize --log-file=/var/log/flying-passenger.log \
    --pid-file=/var/run/flying-passenger.pid

You can shut down a Flying Passenger daemon by sending SIGINT or SIGTERM to it:

$ kill `cat /var/run/flying-passenger.pid`

We recommend using daemontools or runit for managing the Flying Passenger daemon. These tools will automatically start the Flying Passenger daemon at boot, and will automatically restart the daemon if it crashes. You can create and enable a daemontools/runit service as folows:

$ sudo mkdir /etc/service/flying-passenger
$ sudo tee /etc/service/flying-passenger/run <<EOF
#!/bin/sh
exec /path-to/flying-passenger \
    --socket-file=/var/run/flying-passenger.sock \
    --log-file=/var/log/flying-passenger.log \
    --pid-file=/var/run/flying-passenger.pid
EOF

Immediately after creating the run file, daemontools/runit automatically runs it to start the daemon. Note that the location (/etc/service) depends on the OS or Linux distros. Sometimes it’s /service. Also note that we start the Flying Passenger daemon without --daemonize.

To shut down a daemontools/runit-managed daemon, you need to use svc -d /etc/service/flying-passenger (daemontools) or sv stop /etc/service/flying-passenger (runit) instead of sending a signal to the process.

Caveats and limitations

Beware of the following caveats and limitations when using Flying Passenger:

  • The Nginx executable must be compiled with the same version of Phusion Passenger as the Flying Passenger daemon. Failing to meet this requirement may result in cryptic errors, or may result in certain features not working, until you’ve fixed the situation. When upgrading Phusion Passenger, you must restart both Nginx and the Flying Passenger daemon.
  • The passenger_root directive has no effect. When using Flying Passenger, you are not supposed to set passenger_root.
  • When you add a new application to the web server configuration, Flying Passenger will automatically pick up the application’s settings and spawn this new application upon the first request to it. However it is not capable of automatically starting the new app before a request has been sent to it (i.e. passenger_pre_start-like behavior is not available in this case). As a workaround, you can send an HTTP request to your application after starting the daemon, which forces it to spawn application processes.
  • When you remove an application from the web server configuration, Flying Passenger will not detect the removal and will not shut down the associated application processes. Killing the application processes will also not help, because Flying Passenger will restart them per the (now-removed, but still in the Flying Passenger daemon’s memory) passenger_min_instances settings. At the moment, there are two ways to get rid of those processes:
    • Before removing the application from the web server configuration, explicitly set its passenger_min_instances to 0. Next, send a request to it, which will cause the Flying Passenger daemon to take over the new passenger_min_instances 0 option. You can then proceed with removing the application from the web server configuration, and restarting the web server. Finally, kill the PIDs associated to those application processes and remove the application configuration.
    • Restart the Flying Passenger daemon.

Conclusion

Flying Passenger should especially be useful for those who have to modify Nginx configuration on a regular basis, without modifying application configuration. Flying Passenger is still a young feature, so we encourage users to provide feedback and bug reports.

We at Phusion are continuously developing and improving Phusion Passenger. If you would like to stay up to date with Phusion news, please fill in your name and email address below and sign up for our newsletter. We won’t spam you, we promise.