blog: The Beautiful Simplicity of an nginx and uWSGI Deployment
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:
- To gracefully reload a site on a new deployment of code, you can simply touch
the vassal file, e.g.
touch /etc/uwsgi/vassals/example.ini - I highly recommend viewing the configuration options for uWSGI to see what you have available. From my understandings with the creator of uWSGI, the default setup for uWSGI is generally favourable for the majority of sites.
- You can read all about the Emperor mode at the official docs
- For troubleshooting, ensure to view the logs output by the Emperor and each vassal you have. Even simple issues like not having write access to the log directory can hurt the functionality of your deployment.
- The IRC channel is #uwsgi on irc.freenode.net and is most excellent. The author is also frequently on there and is very friendly and helpful.
I hope you had a great time setting up uWSGI. Comments and questions always welcome below!