blog: The Beautiful Simplicity of an nginx and uWSGI Deployment

Posted on 08 Jul 2012 under code

There are many methods of deploying your Django application. A few years ago, it was primarily an Apache & mod_wsgi deployment, then gunicorn with its ease of configuration, got quite popular. These days, uWSGI is picking up some steam. All of these solutions can work for everyone, but it simply comes down to what works best for your application and team.

For our team, we recently decided to switch to uWSGI. We were quite impressed with the speed of uWSGI, its integration with nginx, the multitude of configuraiton options, and its “suicide as a last resort” process maintenance.

Now, let’s get started. To begin, you’ll need some essentials. nginx, of course, and uwsgi. uWSGI can be installed via pip which you really should have setup if you’re reading this. Setup a virtualenv in whatever way, and install the uwsgi binaries within it.

virtualenv uwsgi-deploy
source uwsgi-deploy/bin/activate
pip install uwsgi

Now, you can deploy a single site quite easily with uWSGI, but that’s been written about over and over again. I want to talk about the uWSGI Emperor, which focuses on deploying multiple applications that are then monitored and respawned as necessary. It also works just fine if you only have a single app, but it gives you the flexibility of easily adding a second applicaiton in the future, so I’m really a fan of it.

Running the uWSGI Emperor is incredibly easy. Activate the virtualenv and run it, simple as this:

uwsgi --emperor /etc/uwsgi/vassals/

Leave that running and open a new tab for now. We will get back to making the emperor a more proper service.

Now since you’re quite the observant reader, you’ll wonder where this path, /etc/uwsgi/vassals/ came from. With uWSGI, instances spawned by the Emperor are simply called vassals. In other words, vassals are the applications you want to deploy, and the path is simply where the Emperor will look for configuration files. So, how does a config file look like? Well, it can vary but I prefer the simple .ini format:

[uwsgi]
master = true
processes = 2 # Simple rule is no. of cores on machine
home = /path/to/virtualenv/example.com
socket = 127.0.0.1:3031 # This can also be a UNIX socket
module = myapp.wsgi
pythonpath = /path/to/django/application
logto = /var/log/uwsgi/example.com
logfile-chown = your_user # You may not need this, based on your setup

If you’re not familiar with WSGI and Django, your myapp.wsgi file should be similar to what is described in the Django documentation

You will store this file in the path defined earlier, where the Emperor will watch over (/etc/uwsgi/vassals from the example). If you flip back to the tab running the Emperor, you should see that it recognized the file and is now serving the site. Make sure to check for any errors in the output as well.

If using UNIX sockets, make sure to read up on the configuration variables of chmod-socket, gid and uid. You may need to adjust these to not suffer from permission issues upon app launch.

Now we need to make this site public. Setting up uwsgi with nginx is incredibly simple since the integration a few versions back.

upstream app_server {
    server 127.0.0.1:3031;
}

server {
    listen 80;
    server_name example.com;

    location / {
        try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
        uwsgi_pass app_server;
        include uwsgi_params;
    }
}

That’s it! It can be further simplified, but I like this as a starting point for most applications. All you need to ensure is that you are using uwsgi_pass on your root location, and you include uwsgi_params. Add this as an available, and enabled site in your nginx config and reload.

sudo ln -s /etc/nginx/sites-available/example.com.app /etc/nginx/sites-enabled/example.com.app
sudo service nginx reload

Use _ (underscore) as the server_name in your nginx config for a simple catch-all block. Great for testing a single site without having to tinker with your local hosts file.

Now hit the address of the box serving this website and the site should appear! Hopefully without errors. If you’re simply deploying a vanilla Django install it should load up no problem.

Before we finish, we need to do some refinements. We don’t want to have that uWSGI Emperor just running in an open tab. Setting up the Emperor with Upstart is very easy. Here’s all you need:

description "uWSGI Emperor"

start on runlevel [2345]
stop on runlevel [!2345]

respawn

exec /path/to/virtualenv/uwsgi-deploy/bin/uwsgi --emperor /etc/uwsgi/vassals/

Save that configuration under /etc/init/uwsgi.conf

Now you should be able to type:

sudo service uwsgi start

And your emperor will be running! The benefit of course, is it’ll respawn on crashes, reboots, etc. Just like you’d expect.

And that’s it. We’re done! You should have a site running under uWSGI, the Emperor watching over its vassals, ensuring everything is going smoothly. Now some final tips and clarifications:

I hope you had a great time setting up uWSGI. Comments and questions always welcome below!

Others Posts You May Enjoy

Thanks for reading. How about leaving a comment?

blog comments powered by Disqus
Fork me on GitHub