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/myapp.example.com

server {
	server_name myapp.example.com;
	root html/myapp.example.com/public;
 
	location / { 
		error_page 404 403 =200 @backend;
		try_files $uri $uri/ @backend; 
	}
 
	location @backend {
		uwsgi_pass 127.0.0.1:3031;
		uwsgi_param UWSGI_SCRIPT wsgi;
		uwsgi_param UWSGI_CHDIR /opt/html/myapp.example.com;
		include uwsgi_params;
	}
}

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

html/myapp.example.com/
--wsgi.py <--- 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 wsgi.py (I’ll explain what each part does on the next page).

from circuits.web import Controller
from circuits.web.wsgi import Application
 
class Root(Controller):
 
	formpage = """\
	<html>
	 <head><title>Basic Form Handling</title></head>
	 <body>
	  <form action="/submit/" method="POST">
			First Name: <input type="text" name="firstName"><br>
			Last Name: <input type="text" name="lastName"><br>
			<input type="submit" value="Submit">
	  </form>
	 </body>
	</html>"""
 
	def index(self):
		return "Hello World!\n"
 
	def query(self, **data):
		q = ["%s=%s" % (k, v) for k, v in data.items()]
		querystring = '<br>'.join(q)
		return "Values passed:<br>%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<br /><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):
		try:
			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:
(Do not copy the <— comments they’re just there for explanation)

<uwsgi>
	<socket>127.0.0.1:3031</socket> <--- this can also be /path/to/socket
	<pidfile>/var/run/uwsgi.pid</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
	<vhost/> <--- sets uWSGI into virtual hosting mode
	<daemonize>true</daemonize> <--- daemonize, launches uWSGI to the background
</uwsgi>

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 http://myapp.example.com/ you should see a simple “Hello World!”

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

Comments are closed.