I've been playing around with deploying/migrating some Django projects to a Rackspace Cloud Server with Nginx and uWSGI. These are my notes on getting started with uWSGI.
It should be noted that I am a developer and not a sys admin. Moreover, I am still learning and experimenting with uWSGI. This setup is being tested and tweaked on a few small projects that only handle a few thousand visitors per day. Rapid scalability and heavy loads are not a concern for these projects.
Comments from "real" system administrators would be appreciated.
My Setup
This setup uses...
- Ubuntu LTS
- Nginx >= 0.8.4
- Django >= 1.4
Installing uWSGI
I installed uWSGI using pip, however, I believe it is included in the Ubuntu
repositories starting with Ubuntu 12.04.
sudo pip install uWSGI
Emperor Upstart Script
Since I am serving several Django websites on one server, I created an
Upstart script to run the
uWSGI Emperor. This way, uWSGI
will watch the /etc/uwsgi/apps-enabled directory for new configuration files
and automatically spawn instances on demand. I simply symlink a project-specific
uWSGI configuration file to /etc/uwsgi/apps-enabled.
The following Upstart script is created at /etc/init/uwsgi.conf
description "uWSGI Emperor"
start on (filesystem and net-device-up IFACE=lo)
stop on runlevel [!2345]
respawn
env LOGTO=/var/log/uwsgi.log
env BINPATH=/usr/local/bin/uwsgi
exec $BINPATH --emperor /etc/uwsgi/apps-enabled --logto $LOGTO
Force a reload of the configuration directory.
sudo initctl reload
Start the uWSGI Emperor.
sudo service uwsgi start
At this point, the uWSGI emperor process can be seen running with top -c. If
not, check the error log at /var/log/uwsgi.log.
uWSGI Configuration File
I layout my projects such that project-level server configuration files are version controlled, every project has it's own virtual environment, and each project has it's own server logs.
mywebsite.com/
config/ <-- server configs
logs/ <-- project-level server logs
mywebsite/ <-- Django 1.4+ project
venv/ <-- virtual environment
The server configuration files in the config/ directory are symlinked into the
filesystem to "enable" a site.
The uWSGI configuration file has a ton of
configuration options and I still
have a lot of experimenting to do. But, the following configuration seems to
get me up and running. It is created in my project's config/ directory and
then symlinked to /etc/uwsgi/apps-enabled/mywebsite.ini (where
"mywebsite" is the name of the project).
[uwsgi]
; define variables to use in this script
project = mywebsite
base_dir = /home/micah/www/%(project).com
; don't forget user and group have write access to MEDIA_ROOT
uid = www-data
gid = www-data
; process name for easy identification in top
procname = %(project)
; number of worker processes
processes = 2
; project-level logging to the logs/ folder
logto = %(base_dir)/logs/uwsgi.log
; django >= 1.4 project
chdir = %(base_dir)/%(project)
module = %(project).wsgi
; add virtual environment to path
virtualenv = %(base_dir)/venv
; unix socket (referenced in nginx configuration)
socket = /var/run/%(project).sock
chmod-socket = 666
; run master process as root
master = true
master-as-root = true
Once this file is symlinked to /etc/uwsgi/apps-enabled/mywebsite.ini, the
uWSGI Emperor should pick it up and spawn new processes. In this case, there
would be 3 new processes. One master process running as root and 2 worker
processes running as www-data. They would show up in top -c as
"mywebsite".
Nginx Configuration
While my Nginx configurations are quite a bit more complicated than this, the following simplification shows the bits that are relevant to uWSGI.
server {
listen 80;
server_name mywebsite.com;
root /home/micah/www/mywebsite.com/;
access_log /home/micah/www/mywebsite.com/logs/nginx_access.log;
error_log /home/micah/www/mywebsite.com/logs/nginx_error.log;
location / {
include uwsgi_params;
uwsgi_pass unix:/var/run/mywebsite.sock;
}
}
Once the nginx configuration is in place the Nginx web server needs to be restarted.
