Deployment of Web.py Applications Using uWSGI and Nginx on Ubuntu

The next post contains an advanced version of this guide.


This post is a update to the previous one on the same topic.

The environment is as usual a low-end VPS with freshly installed Ubuntu 10.04.3 Lucid LTS (minimal version). First things first, :

apt-get update
apt-get dist-upgrade -y

for i in busybox-static \
         syslog-ng \
         python-setuptools \
         python-pip \
         python-software-properties \
         ; do
  apt-get install $i -yf
done

Then we install web.py (0.36 at the time of this writing) itself using pip:

pip install web.py

Next comes the servers. Fortunately, there are now ‘official’ ppa for both Nginx and uWSGI on launchpad, which are updated regularly and make the job a lot easier than before:

add-apt-repository ppa:nginx/stable
add-apt-repository ppa:uwsgi/release
apt-get update
apt-get install nginx uwsgi-python -yf

At the time of this writing, the above will install Nginx 1.0.11 and uWSGI 0.9.6.8. Note that in the last line we now have to use ‘uwsgi-python’ instead of ‘uwsgi’. If you have a version of uwsgi previously installed using other repositories, you most likely would need to remove it first.

For this demonstration, we use the minimalist ‘Hello World’ example from web.py tutorial as our web application. Save the following as ‘/var/www/apps/index.py’:

import web

urls = (
  '/', 'index'
)

app = web.application(urls, globals())

class index:
        def GET(self):
                return "Hello, world!"

if __name__ == "__main__": app.run()

We use the web.py built-in web server to test whether the above code is OK. In ‘/var/www/apps’ folder, type this:

python index.py

Point your browser to IP:8080 and you should be greeted with ‘Hello, world!’. Press Ctrl-C to stop the web.py built-in server.

Working upwards, next we set up uWSGI configuration for our demo app. uWSGI in Ubuntu now uses /etc/uwsgi-python/apps-available and /etc/uwsgi-python/apps-enabled folders for application configuration files, similar to Nginx and other servers. We will be using uWSGI in VirtualHosting mode, so that more applications can be added later dynamically without having to change uWSGI configuration. Create ‘/etc/uwsgi-python/apps-enabled/vhosts.ini’ with the following contents:

[uwsgi]
gid = www-data
uid = www-data
vhost = true
logdate
socket = /tmp/uwsgi_vhosts.sock
#socket = 127.0.0.1:3031
master = true
processes = 1
harakiri = 20
limit-as = 128
memory-report
no-orphans

We then set up Nginx by creating a site file in /etc/nginx/sites-enabled with the following contents:

server {
  # Change this if you want to serve your application on another port
  listen 80;

  # Replace this with your domain name
  server_name apps.example.com;

  # You can use virtual directory like '/apps/' here, but remember that
  # this should match 'urls' defined in your web.py application file
  location / {
    include uwsgi_params;

    # This should match the 'socket' entry in your uwsgi configuration
    uwsgi_pass unix:///tmp/uwsgi_vhosts.sock;
    #uwsgi_pass 127.0.0.1:3031;

    # This is the absolute path to the folder containing your application
    uwsgi_param UWSGI_CHDIR /var/www/apps;

    # This is actually not necessary for our simple application,
    # but you may need this in future
    uwsgi_param UWSGI_PYHOME /var/www/apps;

    # This is the name of your application file, minus the '.py' extension
    uwsgi_param UWSGI_SCRIPT index;
  }
}

We are almost done, but there is one last and very important step: uWSGI requires a wsgi application to be defined in the application file (index.py in our case). Just add this line to the end of index.py:

application = app.wsgifunc()

Now that everything is in place, we can (re)start Nginx and uWSGI:

service nginx restart
service uwsgi-python restart

Point your browser to your domain and you will now be greeted by ‘Hello, world!’ served by Nginx through uWSGI. Job done.

This entry was posted in Linux, Web and tagged , , , , . Bookmark the permalink.

5 Responses to Deployment of Web.py Applications Using uWSGI and Nginx on Ubuntu

  1. Oscar says:

    It didn’t work. However this does:

    location /static/ {
    root /var/www;
    if (-f $request_filename) {
    rewrite ^/static/(.*)$ /static/$1 break;
    }
    }

    Found it at http://webpy.org/cookbook/fastcgi-nginx

    Thanks in any case for your help and your excellent walkthrough!

    • farter says:

      It worked in my test, :)

    • Nigel says:

      Don’t use if statements when possible, for static files you definitely shouldn’t need them. Refer to http://wiki.nginx.org/IfIsEvil and http://wiki.nginx.org/Pitfalls

      location /static {
      alias /var/www/apps/static;
      expires 7d;
      }

      or

      location /static {
      root /var/www/apps;
      expires 7d;
      }

      should both work fine for serving static files.

      I always put my named location blocks before my root location block to make sure that they are matched first. I’m not sure whether this is necessary but I had problems with an Nginx config years ago and changing the order of the location blocks fixed it so since then I’ve always put my named locations first.

  2. Oscar says:

    Excellent guide and it’s working fine except the app can’t find static content like js, css and images located in /var/www/apps/static. It’s probably due to some nginx settings but I’m not at all familiar with it. Any ideas?

    • farter says:

      Just define a ‘location’ inside the server context in nginx conf:

      location /static/ {
      alias /var/www/apps/static/;
      expires 7d;
      }