Tuesday, August 16, 2011

How to Install django on Debian using nginx uwsgi

Here we are going install a basic django application using uwsgi application server and nginx as load balancer. Requirements:
  • django code location: /usr/local/lib
  • django project: hello
Let install few packages we need:
apt-get -y install nginx uwsgi \
    uwsgi-plugin-python python-django
Create a simple django application:
cd /usr/local/lib
django-admin startproject hello

uWSGI

Create uWSGI configuration (file /etc/uwsgi/apps-available/hello.yaml):
uwsgi:
    uid: www-data
    gid: www-data
    socket: /tmp/uwsgi-hello.sock
    plugins: http, python
    module: django.core.handlers.wsgi:WSGIHandler()
    pythonpath: /usr/local/lib
    chdir: /usr/local/lib/hello
    env: DJANGO_SETTINGS_MODULE=hello.settings 
Enable this configuration and restart uwsgi server:
ln -s /etc/uwsgi/apps-available/hello.yaml \
    /etc/uwsgi/apps-enabled/hello.yaml
/etc/init.d/uwsgi restart

nginx

Create nginx site configuration (file /etc/nginx/sites-available/hello):
upstream backend {
    server unix:///tmp/uwsgi-hello.sock;
}

server {
    location / { 
        uwsgi_pass  backend;
        include     uwsgi_params;
    }   

    location /static/admin/ {
        alias /usr/lib/pymodules/python2.6/django/contrib/admin/media/;
        access_log off;
        expires 7d;
    }

    location  /static/ {
        alias  /usr/local/lib/hello/static/;
        access_log off;
        expires 7d;
    }
}
Remove default site, enable this configuration and restart nginx server:
rm /etc/nginx/sites-enabled/default
ln -s /etc/nginx/sites-available/hello \
    /etc/nginx/sites-enabled/hello
/etc/init.d/nginx restart

nginx - uwsgi_cache

Web sites that serve almost static content (updated let say every 15 mins) can benefit by utilizing content caching:
   ...
uwsgi_cache_path   /var/cache/hello levels=1:2
                   keys_zone=NAME:15m
                   inactive=5m;
server {
   location / {
       uwsgi_pass  backend;
       include     uwsgi_params;
       uwsgi_cache   NAME;
       uwsgi_cache_valid   200 302 15m;
       uwsgi_cache_key $request_uri;
       expires 15m;
   }
   ...
}
If you experience performance issue with content rendering, overhead of framework internal time, have a willing to fine control content caching consider take a look at the following post and this one.

Simple Load Balancing with nginx on Debian

Suppose you need distribute http workload across multiple computers/processes. Here we will be using nginx to implement load balancing (using round-robin scheduling). Let start by installing nginx package:
apt-get -y install nginx
Place the following into /etc/nginx/sites-available/my-site:
upstream backend {
    // every 7 requests: 5 requests to s1 server 
    // and one request to the second and the third
    server s1 weight=5;
    // after 3 unsuccessful attempts within 
    // the 30 seconds s2 is considered 
    // inoperative
    server unix:/tmp/s2 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:8080;
}   
 
server {
    location / {
       proxy_pass http://backend;
    }   
}  
Now disable default site configuration, enable a new one and restart nginx:
rm /etc/nginx/sites-enabled/default
ln -s /etc/nginx/sites-available/my-site \
    /etc/nginx/sites-enabled/my-site
/etc/init.d/nginx restart
Read more about nginx upstream module here.

Monday, August 15, 2011

How to Serve Django Static Files by Apache

Serving static files out from python is not good idea since there is more effective way to do that. Why not let apache do this? Suppose you followed one of two previous posts that let you configure apache to server django application using mod_python or mod_wsgi. The idea is simple, we define an alias for the media directory of the django application and set it handler to none. Here is a partial example of apache site configuration file:
    ...

    Alias "/static/admin/" "/usr/lib/pymodules/python2.7/django/contrib/admin/media/"
    <Location "/static/admin/">
        SetHandler None
    </Location>

    Alias "/static/" "/usr/local/lib/hello/static/"
    <Location "/static/">
        SetHandler None
    </Location>
And finally let turn on static content expiration.
    ...

    <IfModule mod_expires.c>
        <FilesMatch "\.(jpg|gif|png|css|js)$">
            ExpiresActive on
            ExpiresDefault "access plus 7 days"
        </FilesMatch>
    </IfModule>
Enable expires module and restart apache2.
a2enmod expires
/etc/init.d/apache2 restart

How to Install Django on Debian using Apache mod_wsgi

Here we are going install a basic django application using apache2 mod_wsgi module. Requirements:
  • server dns: web01.dev.local
  • django code location: /usr/local/lib
  • django project: hello
Let install few packages we need:
apt-get -y install apache2 libapache2-mod-wsgi \
    python-django 
Once you ensure apache is up and running. Let create a simple django application:
cd /usr/local/lib
django-admin startproject hello
Create a /usr/local/lib/django-hello.wsgi file:
import sys
import os
import os.path

sys.path.append(os.path.dirname(__file__))
os.environ['DJANGO_SETTINGS_MODULE'] = 'hello.settings'

from django.core.handlers.wsgi import WSGIHandler
application = WSGIHandler()
Add apache site configuration that will serve the django wsgi site. Add the following to /etc/apache2/sites-available/django-hello:
<VirtualHost *:80>
        ServerName web01.dev.local
        DocumentRoot /var/www/

        ErrorLog ${APACHE_LOG_DIR}/error.log
        # Possible values include: debug, info, notice, 
        # warn, error, crit, alert, emerg.
        LogLevel warn
        CustomLog ${APACHE_LOG_DIR}/access.log combined
    
        WSGIScriptAlias / /usr/local/lib/django-hello.wsgi
        WSGIProcessGroup hello-site
        WSGIDaemonProcess hello-site processes=2 threads=16 maximum-requests=1000 display-name=apache-hello-wsgi
</VirtualHost>
Now we are going disable default apache site and enable django-hello site:
a2dissite default
a2ensite django-hello
/etc/init.d/apache2 restart
Once you navigate to http://web01.dev.local/ you should be able to see the default django welcome screen.

If you experience performance issue with content rendering, overhead of framework internal time, have a willing to fine control content caching consider take a look at the following post.

How to Install Django on Debian using Apache mod_python

Here we are going install a basic django application using apache2 mod_python module. Requirements:
  1. server dns: web01.dev.local
  2. django code location: /usr/local/lib
  3. django project: hello
Let install few packages we need:
apt-get -y install apache2 libapache2-mod-python \
    python-django 
Once you ensure apache is up and running. Let create a simple django application:
cd /usr/local/lib
django-admin startproject hello
Add apache site configuration that will serve the django site. Add the following to /etc/apache2/sites-available/django-hello:
<VirtualHost *:80>
        ServerName web01.dev.local
        DocumentRoot /var/www/

        ErrorLog ${APACHE_LOG_DIR}/error.log
        # Possible values include: debug, info, notice, 
        # warn, error, crit, alert, emerg.
        LogLevel warn
        CustomLog ${APACHE_LOG_DIR}/access.log combined
    
        SetHandler python-program
        PythonHandler django.core.handlers.modpython
        SetEnv DJANGO_SETTINGS_MODULE hello.settings
        PythonDebug On
        PythonPath "['/usr/local/lib'] + sys.path"
</VirtualHost>
Now we are going disable default apache site and enable django-hello site:
a2dissite default
a2ensite django-hello
/etc/init.d/apache2 restart
Once you navigate to http://web01.dev.local/ you should be able to see the default django welcome screen.

Troubleshooting

If you unable navigate to the apache this could be related to ipv6 support (that is turned on by default). You can verify that issuing the following command:
netstat -tunlp | grep :80
If the apache process is not listening on ipv4 address (e.g. 0.0.0.0:80) just follow the following post to disable ipv6 in apache.