Friday, November 4, 2011

Running nginx + supervisor + uwsgi + django

Running nginx + supervisor + uwsgi + django is a great way to run your django apps. Supervisor is a great tool for running foreground applications in background. It does not stop you from running background (daemon) applications too as long as you can run them in "no-fork" mode. It makes it fairly easy to manage all your applications, not only django websites. You can download the latest version from http://supervisord.org/ It has a great documentation and is very easy to configure. You just add your program in the configuration file and reload the supervisor (strangely enough, reload is called update) and voila, your new application is registered in the supervisor pool, up and running. You can add all programs in one big file - /etc/supervisor.conf, but I prefer the very handy "include" section. There, you can specify a directory that will contain your programs .ini files
---cut---
[include]
files = supervisord.d/*.ini
UWSGI is an "application container server" as they call it themselves. It is used to provide a "gateway" between your web server and web application. It has a million configuration options, most of which are well documented. You can get it from http://projects.unbit.it/uwsgi/. You migh can pip install uwsgi ,but I prefer compiling from source to RPM. So, I wont get into much details, because there are thousands of tutorials about django and uwsgi. I assume that you already have your already installed django, nginx and your django website put somewhere, for example /srv/www/djsite So the supervisord config for your app will look like this:
[program:djsite]
command=/usr/bin/uwsgi 
        --socket /var/run/django-sites/sock/djsite.sock #This is the socket that will be used for connection between nginx and you django site 
        --processes 4 #This is the number of sub-processes that uwsgi will spawn
        --max-requests 1024 #The max number of request your site can handle
        --vacuum #This will delete the socket on shutdown
        --harakiri 20 #This is where UWSGI shines! This will kill an uwsgi sub-process if a request is send to it and it does return response for 20 second
        --post-buffering 4096 #This is required for harakiri to work properly. You should have it, even if you did not set harakiri mode
        --pp /srv/www/djsite # If your project is not on the PYTHONPATH put the project dir here. You can specify additional resources with multiple --pp options
        --module django.core.handlers.wsgi:WSGIHandler()  #This is the django WSGI handler, that will handle the communication of your application

environment=DJANGO_SETTINGS_MODULE='djsite.settings' # Your site settings module
--cut-- # Some additional options you can specify depending on your needs
stopwaitsecs=16 # Supervisor expects the process to stop in 16s, if it doesn't it sends him KILL signal
stopsignal=INT # This is very important! Explained bellow.

#User and group is nginx, so nginx can write into the defined socket
user=nginx
group=nginx
It is very important to set the stop signal to INT or QUIT, because the default signal that supervisor sends is TERM. UWSGI handles TERM, and restarts the master process and the subprocesses. After 16 seconds of not exiting, supervisor thinks your process is hanging and sends KILL, which kills the master process, but the sub-processes are inherited by INIT. This causes a lot of troubles. Dont forget to create /var/run/django-sites/sock/ with the appropriate permissions. Configure nginx:
server {
#configure your server
 --cut--
include uwsgi_params; #ncludes the parameters used by the uwsgi nginx module
 --cut--
#Add a location for your django site
 location / {
     uwsgi_pass unix:/var/run/django-sites/sock/djsite.sock; # This should point to your uwsgi socket.
  }
#Serve your static content with nginx!
 location ~ ^/(images|javascript|js|css|flash|media|static)/  {
      root /srv/www/static/djsite;
 }
}
Don't forget to include your uwsgi_params in the server config. Reload your server
service nginx reload
If supervisor is running, you should make it reread its configuration. $supervisorctl update should do that
supervisorctl update
And that is about it, you should have a running nginx-supervisor-uwsgi-django.

No comments:

Post a Comment