Building a uWSGI Emperor for multiple python versisons

This is a quick update to my tutorial on hosting Django Apps on Ubuntu with Nginx and uWSGI. I recently wanted to move to a mix of Python 3.4 and Python 2.7 web apps on one of my servers that was set up as described in that tutorial. Here's how to do that.

Normally, I just install uWSGI using pip. The big downside of that approach is that it only builds uWSGI for the version of Python with which you install it. So to get one emperor that can run apps (vassals) with different versions of Python, we need to compile uWSGI. Luckily it's really easy.

Here is an example of the required steps. Just run the following commands as root.

First download and extract uWSGI. Here's an example; check the website for the latest version and update the commands accordingly:

wget http://projects.unbit.it/downloads/uwsgi-2.0.11.1.tar.gz
tar zxvf uwsgi-2.0.11.1.tar.gz
cd uwsgi-2.0.11.1/

One thing before we compile: we need to tell uWSGI where it's going to find the various python plugins. Edit buildconf/base.ini and set plugin_dir = /usr/local/lib/uwsgi/ . You are now ready to compile uWSGI.

We'll compile uWSGI without Python support, then separately compile plugins for each version of Python we want to support:

make PROFILE=nolang
PYTHON=python3.4 ./uwsgi --build-plugin "plugins/python python34"
PYTHON=python2.7 ./uwsgi --build-plugin "plugins/python python27"

Now you could run uWSGI from this folder, but I prefer to install it:

mkdir /usr/local/lib/uwsgi/
cp python*_plugin.so /usr/local/lib/uwsgi/
cp uwsgi /usr/local/bin/uwsgi

Finally, you'll want an upstart or systemd file to boot uwsgi. Here's an upstart example (same as in my previous tutorial), which you would install as /etc/init/uwsgi.conf:

# Emperor uWSGI script

description "uWSGI Emperor"
start on runlevel [2345]
stop on runlevel [06]

exec uwsgi --die-on-term --emperor /etc/uwsgi --emperor-tyrant --logto /var/log/uwsgi.log

For each web app you want to run, create a config file in /etc/uwsgi that's owned by the user you want that app to run under. Include the setting plugin = python27 or plugin = python34 to indicate which python plugin you want to use for that app.

Example of an app config file in /etc/uwsgi/ (note %n mean "the filename without extension" which makes this sort of settings file really easy to re-use):

[uwsgi]
socket = /apps/%n/uwsgi/socket
chmod-socket = 664
master = true
processes = 2
virtualenv = /apps/%n/app/venv
pythonpath = /apps/%n/app/
module = %n.wsgi
pidfile2 = /apps/%n/uwsgi/pid
daemonize = /apps/%n/uwsgi/log
plugin = python27

You now have a shiny new uWSGI emperor, serving multiple python apps with support for python 2.7 and 3.4.

Archived Comments

Mike Tery wrote on November 13, 2017:

Awesome! Thanks so much. Spent way too much time looking at other poor resources.

Muhammed Abad wrote on June 20, 2017:

Solved my issue after many hours of google searches. Thanks a million !

Charlie Gorichanaz wrote on April 9, 2016:

Hey, thank you for this! I've avoided doing too much with Python because every time I had a quick project, I didn't want to spend time figuring out how to easily post a Python page, on usually went with PHP, eeks! I had briefly tried extending my existing Django/emperor setup to do small one page apps, but I ran into the Python version issue and didn't dig enough to realize my uWSGI was not compiled within my virtualenv… anyway, I was lost in the woods and you led me out. Cheers!