Deploying circuits.web with Nginx/uwsgi

Configuring Nginx

Now we’re going to setup the configuration a little bit. Assuming that you have web files in your usual html folder, for example html/

server {
	root html/;
	location / { 
		error_page 404 403 =200 @backend;
		try_files $uri $uri/ @backend; 
	location @backend {
		uwsgi_param UWSGI_SCRIPT myapp;
		uwsgi_param UWSGI_CHDIR /opt/html/;
		include uwsgi_params;

This is basically what we have going on, in your document folder:

html/          <--- your python app
--/public          <--- public folder where your static files go
    |--favicon.ico <--- a favicon.ico in the public folder

You’ll notice that Nginx has been set to the public folder as the website’s root, but for the backend we have set the UWSGI_CHDIR variable to the root where the python app exists, and set UWSGI_SCRIPT to the name of the script not including the .py extension. Essentially getting ready to try dynamic applications with uWSGI.

The above will try the request against try_files, and if it is an existing file or folder within the /public folder it will serve it. You may have noticed the error_pages line, since / is a valid folder, nginx may attempt to serve it as such, but if there’s no index file in /public it may cause a 403 or 404 error, we want to invoke the backend if this happens, so we revert the code to 200 and send it on it’s way to @backend.

Now lets create the circuits.web demonstration script and save it as (I’ll explain what each part does on the next page).
Remember that for Python 3, responses need to be sent as byte instances.

from circuits.web import Controller
from circuits.web.wsgi import Application
class Root(Controller):
	formpage = """\
            <form action="/submit/" method="POST">
            First Name: <input name="firstName" type="text"> 
            Last Name: <input name="lastName" type="text">
            <input type="submit" value="Submit">
	def index(self):
		return "Hello World!\n"
	def query(self, **data):
		q = ["%s=%s" % (k, v) for k, v in data.items()]
		querystring = ''.join(q)
		return "Values passed: %s" % (querystring)
	def sayyes(self, **data):
		if not "say" in data:
			return "You didn't say anything"
		if not "yes" in data["say"]:
			return "You didn't say 'yes'"
		return "You said yes..."
	def form(self):
		return self.formpage
	def submit(self, firstName, lastName):
		return "Hello %s %s <a href='/form/'>Return</a>" % (firstName, lastName)
class SomeMath(Controller):
	channel = "/math"
	def addtwo(self, firstNum, secondNum):
		if not firstNum:
			return "You need two numbers, missing both"
		if not secondNum:
			return "You need two numbers, missing second"
		newNum = int(firstNum) + int(secondNum)
		return "%d + %d = %d" % (int(firstNum), int(secondNum), newNum)
	def addmulti(self, *args):
			total = sum([int(x) for x in args])
		except ValueError:
			return "One or more number was not valid"
		return "The sum of the numbers you provided was %d" % (total)
application = Application() + Root() + SomeMath()

And now to create a configuration file to be used with uWSGI this will make it easier to start it up in the future:

    <socket></socket>         <!-- this can also be /path/to/socket -->
    <pidfile>/var/run/</pidfile>   <!-- handy for killing the master process later -->
    <processes>4</processes>                <!-- how many 'workers' you want -->
    <master/>                               <!-- launch uWSGI with a self-healing master process -->
    <uid>www-data</uid>                     <!-- the user to run as -->
    <gid>www-data</gid>                     <!-- the group to run as -->
    <chmod-socket>666</chmod-socket>        <!-- Only needed if you're using a .sock file -->
    <daemonize>true</daemonize>             <!-- daemonize, launches uWSGI to the background -->

Now that you have the above configuration you can save it as something like uwsgi.xml, essentially this will cause uWSGI to launch process(es) into the background, with a self-healing master that can respawn workers if needed. You’ll notice we did not specify a python file to be served, thats because it’s being taken care of in the Nginx configuration now.

To launch the above we would run:

uwsgi -x /path/to/uwsgi.xml

Make sure to restart/reload Nginx at this point (also stop/restart uWSGI if you make any changes to your apps)

When you visit your site at you should see a simple “Hello World!”

Onto page 3 where I explain what’s going on.

Comments are closed.