- 1 Overview
- 2 Enabling Passenger on a domain
- 3 Basic operation
- 4 Use of Passenger vs. FastCGI
- 5 A couple of technical notes
- 6 Passenger and Python/WSGI
- 6.1 Setting up Passenger WSGI
- 6.2 Passenger WSGI and Django
- 6.3 Passenger WSGI and virtualenv
- 6.4 Passenger WSGI and Pylons/Pyramid
- 6.5 500 Errors with Passenger WSGI workaround
- 6.6 Local logging alternative
- 6.7 A slightly more robust local logging alternative
- 6.8 Another solution
- 6.9 Tips and tricks
- 7 Troubleshooting
- 8 See also
Passenger is an open source web and application server that greatly simplifies the deployment of Ruby applications, Python, and Node.js. Passenger is the preferred way to deploy and host Ruby on Rails applications across all DreamHost servers and is free on every DreamHost hosting plan.
Enabling Passenger on a domain
- Navigate to the (Panel > 'Domains' > 'Manage Domains') page.
- Click the Edit button to the right of your domain under the 'Web Hosting' column.
- Scroll down to the 'Web Options' section and check the 'Passenger (Ruby/NodeJS/Python apps only):' check box.
- A WARNING dialog box then appears:
- Click the OK button. The panel adds the /public subdirectory for you.
- Click the Change settings button to save your changes.
The "public" subdirectory
- Passenger maps the directory named "public" to be the document root for your domain/subdomain.
- If a static HTML file named "public/index.html" exists, it's then used as the response for requests for the root document (i.e., "/").
- If you want your application to handle requests for the root document, then you must first remove "public/index.html" (if it exists).
- By default, Ruby on Rails creates a static "public/index.html" file.
Likewise, a file inside the "public" subdirectory that is named with one of the suffixes recognized by Apache (e.g., "public/foo.cgi" or "public/foo.pl") will be treated as an executable CGI script in the usual Apache fashion. (See CGI for more information.)
The following are the basic actions that take place once a file is requested from a domain running Passenger and Ruby on Rails:
- When a request is made to a domain/subdomain, the Apache HTTP Server passes the request to Passenger.
- Passenger first looks for an appropriately-named HTML or CGI file in the domain/subdomain's /public subdirectory.
- If no matching file is found, the request is passed to Passenger's Rack interface.
- Note that this use of the /public subdirectory meshes precisely with the way that Ruby on Rails makes use of the same subdirectory.
- In order to generate a response, Rack looks for a file named "config.ru" in the domain/subdomain's root directory (i.e., the parent of the domain's /public subdirectory).
- Rack requires that you place the appropriate Ruby code into "config.ru" to invoke your desired web framework or application to handle the request.
- (See Rack for more information about how information is passed through the Rack interface.)
Under normal circumstances, Ruby on Rails (RoR) will automatically create and initialize all of the files and directories needed to interface with Passenger/Rack. When running a RoR application, the only Rack-related files you are likely to modify are possibly adding GEM_PATH information to "config.ru" and "touching" the "tmp/restart.txt" file.
Use of Passenger vs. FastCGI
Passenger should only be enabled if you intend to run a Ruby on Rails (RoR) or other Ruby/Python-based program as the sole application for the entire domain or subdomain. Passenger directs all requests for the designated domain/subdomain to the associated Rack-compliant application. So it's best to leave Passenger disabled if you do not actually need it.
In other words, you should only enable Passenger if you want to access your application via the following three URLs:
If you want to access your application via www.example.com/path-to-myapp then use FastCGI instead of passenger.
A couple of technical notes
- Output to STDERR for processes run through the Rack interface is directed to the master Apache error log file rather than the domain/subdomain specific log file. You do not have direct access to the master log file. This limitation can make debugging initialization errors (in particular syntax errors and gem resolution issues) tricky. Passenger will often produce an error output webpage including a stack traceback. However, in some cases it does not. If you have a persistent problem and Passenger is not producing sufficiently useful error output, you can try contacting the DreamHost support staff and ask them to examine the master log file for you. Once a framework (such as RoR) is up and running, its error output is typically handled by the framework's own error logging mechanism. For example, RoR records its error output in a file named "log/production.log".
- As of April 2015, Passenger on all shared DreamHost servers uses Ruby 1.8.7. To use a different version of Ruby (and to otherwise gain full control of the operation of your system), you must use a VPS and install RVM.
- Passenger and Mongrel fulfill very much the same roles so you most likely do NOT want to use both of them on the same domain or website.
- Activating Passenger on a domain will break the phpMyAdmin interface on any subdomain under the domain. To use phpMyAdmin and Passenger, you must have a non-Passenger-enabled domain with an active phpMyAdmin.
- In the interest of ease of use and 'Upload and Go' functionality, Passenger disables some mod_rewrite functionality. That means it will automatically override an existing 'dispatch.fcgi' setup you have in place. This is not a problem for your Rails application but it may have other side effects (such as breaking other mod_rewrite rules you have set up). If this causes a problem for your website, try using the FastCGI method.
- Passenger automatically launches applications and leaves them running as long as they are not idle. It also caches the code for Ruby on Rails itself to speed up application launching.
- You can use your local gem repository if you use the following in the config/environment.rb file:
if ENV['RAILS_ENV'] == 'production' # don't bother on dev ENV['GEM_PATH'] = '/home/USERNAME/.gems' #+ ':/usr/lib/ruby/gems/1.8' # Need this or Passenger fails to start end require File.join(File.dirname(__FILE__), 'boot')
The same path should be set in your shell's environment variables GEM_HOME and GEM_PATH so you can use the gem program to install/upgrade your own gems. You can reload the config file by running "touch tmp/restart.txt" in your base directory.
Passenger and Python/WSGI
Passenger is best known for being used with Ruby on Rails applications, however it can also serve up Python web applications which use the WSGI interface, including any application which uses the Django framework. Since Passenger allows your application to temporarily reside in memory while it is being actively used, it will allow your site to respond significantly faster than is otherwise possible.
Passenger's WSGI support works reasonably well, however another available option is Python FastCGI in case you run into problems.
Setting up Passenger WSGI
To start an example Python site using Passenger WSGI, your first step should be to configure the domain to use Passenger using the steps mentioned above. Note that the document root must end in "/public" for a Passenger application as this directory will be used to serve static media.
Once you have set the domain to use Passenger, create a file called
passenger_wsgi.py in the folder above the document root (i.e., if you set your document root to
/home/username/example.com/public, you'd put this file at
/home/username/example.com/passenger_wsgi.py). This file must export a WSGI server with the name
application. Here's a minimal example:
def application(environ, start_response): start_response('200 OK', [('Content-type', 'text/plain')]) return ["Hello, world!"]
This application will return a text file with the content "Hello, world!" for any request.
Passenger WSGI and Django
- See Django for instructions on how to configure Passenger to run Django.
Passenger WSGI and virtualenv
As Passenger loads your
passenger_wsgi.py into a special wrapper (currently
/dh/passenger/lib/phusion_passenger/wsgi/request_handler.py, although this may change), you cannot directly select which Python interpreter is used to run your application. However, you can switch interpreters at runtime by adding the following code to the beginning of your
import sys, os INTERP = "/home/<username>/local/bin/python" #INTERP is present twice so that the new Python interpreter knows the actual executable path if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
Set INTERP to the Python interpreter which you wish to use instead of the default.
Passenger WSGI and Pylons/Pyramid
If you're using a Pyramid-framework supported site, the following should work for your
passenger_wsgi.py, assuming you've setup the Python virtual environment at
import sys, os INTERP = "/home/<username>/local/bin/python" #INTERP is present twice so that the new Python interpreter knows the actual executable path if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv) from paste.deploy import loadapp application = loadapp('config:/home/path/to/site/production.ini')
Note that if you're using a site created from one of the Pyramid starter templates, the
development.ini config file wraps your site in the ErrorMiddleware layer, similar to what's done in the next section. However, ErrorMiddleware does not support environments where
True, so you must use the production config, or modify environ to set
False. (Note: This may cause problems if you manually override the settings). The following link may offer further assistance:
500 Errors with Passenger WSGI workaround
Passenger WSGI at the moment has difficulty dealing with errors. Namely, when your WSGI application (for example, but not limited to, Django) raises an uncaught exception, Passenger dies, a 500 page is displayed in the browser, and the error message is not recorded in the home/username/logs/sitename/http/error.log file. This makes debugging tricky.
One solution is to use Python Paste as a WSGI middleware between passenger and your application:
- Grab Paste from here: http://pypi.python.org/pypi/Paste.
- Unzip the files. All you need is the "paste" directory.
- Put it into your application directory (for example, /home/username/sitename/myapp/paste)
- Edit your passenger_wsgi.py file to include that directory in the Python path, and then load Paste.
- Here is what your passenger_wsgi.py file might look like:
import sys, os cwd = os.getcwd() myapp_directory = cwd + '/myapp' sys.path.insert(0,myapp_directory) sys.path.append(os.getcwd()) os.environ['DJANGO_SETTINGS_MODULE'] = "myapp.settings" from paste.exceptions.errormiddleware import ErrorMiddleware import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler() # To cut django out of the loop, comment the above application = ... line , # and remove "test" from the below function definition. def testapplication(environ, start_response): status = '200 OK' output = 'Hello World! Running Python version ' + sys.version + '\n\n' response_headers = [('Content-type', 'text/plain'), ('Content-Length', str(len(output)))] # to test paste's error catching prowess, uncomment the following line # while this function is the "application" #raise("error") start_response(status, response_headers) return [output] application = ErrorMiddleware(application, debug=True)
Local logging alternative
import os, sys def _get_log(): return file('/home/<username>/passengerwsgi.log', 'a') log = _get_log() print >>log, "Running %s" % (sys.executable) INTERP = "/home/moatra/local/bin/python" if sys.executable != INTERP: print >>log, "Detected wrong interpreter location, swapping to %s" % (INTERP) #swapping interpreters will not flush any files log.flush() log.close() os.execl(INTERP, INTERP, *sys.argv) #Should resume execution from the top of the file log.flush() log.close() from paste.deploy import loadapp def application(environ, start_response): log = _get_log() print >>log, "Application called:" print >>log, "environ: %s" % str(environ) results =  try: app = loadapp('config:/home/path/to/site/production.ini') print >>log, "App loaded, attempting to run" log.flush() results = app(environ, start_response) print >>log, "App executed successfully" except Exception, inst: print >>log, "Error: %s" % str(type(inst)) print >>log, inst.args log.flush() finally: log.close() return results
A slightly more robust local logging alternative
This example uses Python's logging module. It does not contain the alternative interpreter bit or loading the ini file. It does show how to load local modules using
Apart from the name
myappmodule.application, this doesn't make any assumptions about your application.
import os import sys import logging # append current dir to module path cwd = os.getcwd() sys.path.append(cwd) # assuming this module is in the same dir as passenger_wsgi, this now works! import myappmodule # create a logfile in the current directory logfilename = os.path.join(cwd, 'passenger_wsgi.log') # configure the logging logging.basicConfig(filename=logfilename, level=logging.DEBUG) logging.info("Running %s", sys.executable) def application(environ, start_response): logging.info("Application called:") logging.info("environ: %s", str(environ)) results =  try: results = myappmodule.application(environ, start_response) logging.info("App executed successfully") except Exception, inst: logging.exception("Error: %s", str(type(inst))) logging.info("Application call done") return results
This solution is only available on a VPS machine.
Another solution is to start a development server by executing:
Next, open another SSH shell and run:
This opens your application in the lynx web browser, bypassing Passenger by using the Django development server. If you're lucky, it will return some helpful feedback.
|Note:||This solution won't help if the problem is with your Passenger configuration since this method bypasses Passenger entirely.|
Tips and tricks
Try running your
passenger_wsgi.py from your command line which may point out any Python errors.
Passenger seems to use a persistent Python session. After updating
passenger_wsgi.py, make sure to run
pkill python to reset the session and force the server to use your new changes.
For common troubleshooting solutions, please visit the Passenger Troubleshooting article.
- Ruby on Rails
- How to Enable RVM
- Ruby Version Manager
- The Passenger Documentation on Application Deployment – At DreamHost, Ruby on Rails applications are reached through the Rack interface. So the relevant Passenger documentation is in the "Rack Deployment" section, not the "Ruby on Rails Deployment" section. Also, you do not need to concern yourself with the Apache configuration files. DreamHost automatically configures those for you.