# Passenger apps

Passenger is an embedded server that assists in securely managing Node, Python, and Ruby apps. Passenger may launch directly from Apache, proxy through to a separate Nginx server, or proxy through to itself in standalone mode.

# Configuration

An .htaccess (opens new window) file instructs Apache how to map this request. Passenger applications must be explicitly defined

A few directives are used. All directives below are prefixed with Passenger. Values specified as this are to be taken literally.

Directive Values Description
Enabled on Enable Passenger support
AppRoot path Required when StartupFile is not located in .htaccess directory.
StartupFile path Entry script relative to app root
AppType node, python, or ruby Application type
Nodejs optional full path to node executable Used when AppType is node
Python optional full path to python executable Used when AppType is python
Ruby optional full path to ruby executable Used when AppType is ruby
FriendlyErrorPages default is on, off hides errors Shows errors in browser. Set to off for production.

Integrating these facts above let's install Nodejs 12.16.3, on a subdomain whose document root (opens new window) is /var/www/hq/public. The application resides in /var/www/hq and its entry script (startup file) is /var/www/hq/current/index.js.

First, determine which Node, Python, or Ruby interpreter you'd like to use.

# Install Nodejs v12.16.3
nvm install 12.16.3
# Get the path to this file
nvm which 12.16.3
# Returns "/home/myadmin/.nvm/versions/node/v12.16.3/bin/node"

Lastly, create a .htaccess file in /var/www/hq/public with the following lines:

PassengerEnabled on
PassengerStartupFile current/index.js
PassengerAppType node
PassengerAppRoot /var/www/hq
PassengerNodejs /home/myadmin/.nvm/versions/node/v12.16.3/bin/node

# Restarting

Create a directory named tmp within the application root. touch either file to restart one time or before every request:

File Purpose
restart.txt Restart once
always_restart.txt Restart before each request
cd /var/www/ghost
mkdir tmp
touch tmp/restart.txt

Passenger will restart automatically once the timer has elapsed (~2 minutes).

# Idle shutdowns

All apps spindown processes if no activity is received after a fixed time (5 minutes). This behavior is consistent with PHP-FPM pool management. Unlike PHP however, there is no warm cache to resume code from making initialization sometimes expensive.

Global idle shutdown may be modified by overriding PassengerPoolIdleTime in /etc/httpd/conf/httpd-custom.conf (see Apache.md).

# Disable idle shutdowns
PassengerPoolIdleTime 0

# Direct proxy

An application may wire in additional services that make automatic startup/shutdown by Passenger cumbersome, such as Discourse. A Passenger-based application can be manually started, then connected to using mod_rewrite (opens new window).

If an application is running on port 8082, then the following rules in the document root of the subdomain or domain will suffice:

DirectoryIndex disabled
RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}

RewriteEngine On
# This may be removed to send ALL requests to the app
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]

RewriteCond %{HTTP:Connection} =upgrade [NC]
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^(.*)$ ws://localhost:8082/$1 [L,QSA,P]
RewriteRule ^(.*)$ http://localhost:8082/$1 [L,QSA,P]

First, no directory index (opens new window) will be assumed (index.html, index.php) for the location.

The request scheme (http, https) is passed to the proxy as X-Forwarded-Proto. This standard, recognized in RFC 7239 (opens new window), informs the application if the request was made securely.

If the request matches a file in the document root, such as media or JavaScript, then that file is served directly.

If the client solicits a request to upgrade to WebSockets, then the ws protocol is used.

Otherwise the request is sent locally, unencrypted, to the application listening on port 8082.

# Standalone mode

Passenger includes a standalone mode (opens new window) that facilitates launching an application directly, such as in the case of Discourse. Standalone mode is controlled using Passengerfile.json typically located in the application root for the app.

Use of this requires the passenger gem in Ruby.

gem install passenger

The following annotated configuration illustrates how it comes together. The document root is /var/www/forums/public while the application root is /var/www/forums.

See "Configuration reference (opens new window)" for a comprehensive listing of directives.

{
    /* Use rbenv shim loader, allows .ruby-version per-directory */
    "ruby": "/usr/local/share/ruby/rbenv/shims/ruby",
    /* can be node, wsgi, rack, or meteor */
    "app_type": "rack",
    "startup_file": "/var/www/forums/config.ru",
    "environment": "production",
    // Use Rack, bundled with Discourse as the HTTP server
    "engine": "builtin",
    // Statically set 6 workers at all times.
    "min_instances": 6,
    "max_pool_size": 6,
    "daemonize": true,
    "spawn_method": "smart",
    // Listen on 127.0.0.1:40011
    "address": "127.0.0.1",
    "port": 40011,
    // Necessary for reliable WebSocket operation in Ruby
    "force_max_concurrent_requests_per_process": 0,
    // Additional env variables to pass to Ruby at startup
    "envvars": {
        "RUBY_GC_HEAP_GROWTH_MAX_SLOTS": "40000",
        "RUBY_GC_HEAP_INIT_SLOTS": "400000",
        "RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR": "1.5",
        "LD_PRELOAD": "/usr/lib64/libjemalloc.so.1"
    }
}

Once configured it may be started using passenger start and stopped using passenger stop.

# See also