Setting up Nginx
If you have previously had Nginx installed, and used the same location as before, then there’s a chance you do not need to mess with init.d. However if you need start/stop capability as well as allowing the server to auto start upon a reboot then perform the following steps. (If you installed nginx to a location other than /opt/nginx you may need to edit the file for the correct paths)
cd /etc/init.d wget http://kbeezie.com/examples/nginx chmod +x /etc/init.d/nginx /usr/sbin/update-rc.d -f nginx defaults /etc/init.d/nginx start
Now you can start, stop or restart nginx easily.
Configuring Nginx
By default the Nginx configuration file (/opt/nginx/conf/nginx.conf) looks something like this (commented lines were removed). Remember, Passenger already added the needed lines to the http { } block in your actual nginx.conf file.
worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; gzip on; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
Which would show you something like this when you visit the browser:
So we know it works… but its pretty much just pure static content. Let us change the default localhost into a Python application using Passenger. For this we’re going to use the default web folder provided by Nginx, the only difference is, we’ll need to create a Public folder under it.
cd /opt/nginx/html mkdir public vi passenger_wsgi.py
You don’t have to use vi to create your test Python script, you might even be an emacs guy cursing me for suggesting such monstrosity ^_^. The Python app below will simply output environment variables to the browser.
import sys import os def application(environ, start_response): start_response("200 OK", []) ret = ["%s: %s\n" % (key, value) for key, value in environ.iteritems()] return ret
Do note however, that the file is outside of the /public location, and that it is named passenger_wsgi.py. Placing the file elsewhere, or giving it a different filename will cause it not to be loaded by Passenger.
Now we need to tweak our Nginx configuration to load the Python WSGI application.
worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; gzip on; passenger_root /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.5; passenger_ruby /usr/local/bin/ruby; server { listen 80; server_name localhost; root /opt/nginx/html/public/; #the folder name public must always be used passenger_enabled on; #this actually turns passenger on at this location } }
A couple things you’ll notice, the passenger configuration parameters were already added by Passenger in the http { } block. In the above you’ll notice we don’t even use a location block in the server { } block. At a bare minimum we need the server_name, root path, and passenger_enabled line. (you don’t even need the listen 80; since 80 is the default port unless otherwise specified in the http {} block)
We’ll need to restart nginx for the changes to take effect.
# /etc/init.d/nginx restart
restarting nginx: nginx.
Load up the server in the browser, and you should be presented with enviroment outputs served up by your Python WSGI application:
You are now setup to easily deploy Python WSGI applications from Nginx. If you make a change to the script, you may need to restart nginx, as the application is stored in memory.
Using DJango and Web.py with Passenger
You’re probably wondering how would you deploy a framework such as Django or Web.py, with Passenger, especially since the main file must always be called passenger_wsgi.py. Instead of the test script above, you would simply use the code below and place your Django application in the same folder (above public). For example in the /opt/nginx/html folder you may see the following folders : django, public, and a folder with your django application name with the file passenger_wsgi.py along side them.
import os, sys nginx_configuration= os.path.dirname(__file__) project = os.path.dirname(nginx_configuration) workspace = os.path.dirname(project) sys.path.append(workspace) os.environ['DJANGO_SETTINGS_MODULE'] = 'testapp.settings' import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler()
Detailed Guide : Click for a more detailed guide to setting Django up with Passenger and Nginx
With Web.Py the documentation often calls for web.application which is self-hosted.
app = web.application(urls, globals()) if __name__ == "__main__": app.run()
Below is an example Web.py app as stored in a passenger_wsgi.py file. You’ll note that instead of the two lines above, it is now a single line with the modified function assigned to application. This is covered in Web.py’s documentation regarding Apache and mod_wsgi, so this modification should work with most WSGI servers.
import web urls = ( '/', 'index' ) application = web.application(urls, globals()).wsgifunc() class index: def GET(self): return "Hello, world!"
Further Information
For further information regarding Nginx itself, I strongly recommend taking a look at the Wiki
For more detailed instructions on using Passenger with Nginx, refer to the User Manual. The user manual will be useful if you wish to take it a step further and venture a look at building Ruby applications, of which you already have capabilities installed.
Hi kbeezie, good writeup. 🙂 I just published a blog article about Phusion Passenger and Python today. Maybe you’d care to comment? http://izumi.plan99.net/blog/index.php/2009/11/21/phusion-passenger-for-python/
“WeÂ’ll need to download and compile Ruby version 1.9.1 patch level 129. While this is not the latest, IÂ’ve had unconfirmed reports that anything newer than p129 is not fully compatible with Passenger.”
This is correct. Later versions of 1.9.1 have bugs in the ‘tempfile’ library. These bugs have been fixed in Ruby’s SVN repository but so far there hasn’t been a 1.9.1 release containing the bug fixes.
By the way, it’s not necessary to install Rails in order to use Phusion Passenger. Rails is only required if you deploy Rails apps.
kbeezie, form some reason sudo is not finding ruby
any ideas?
Without using sudo, try executing ruby -v to see if anything shows up at all, if not try ‘which ruby’. If nothing still shows up then either the PATH isn’t configured correctly to Ruby, or Ruby itself isn’t properly installed. ‘sudo’ itself doesn’t find commands per se, but is simply a way of saying ‘I want to run the following command as a super-user or root’.
Hrm? Why, I’ll assuming that you’ve not seen the uwsgi project? This is much better for python/django/pylons – http://projects.unbit.it/uwsgi/
Good Luck
Note the date of Nginx’s support for uwsgi and the date of said article.