The right configuration virtualhost for Apache + ModWSGI run Django


We know that Django doesn’t serve files itself. Django suggest us to run separate Web server for running media and another. We may use NGINX, Lighthttpd, Cheeroke or anothers. But, there it’s not wrong to host Django with Apache + ModWSGI. I use it for development which it have monitoring to our files and auto-reload if there changes ommited. Ref: https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/modwsgi/.

We need to make right configuration for Virtualhost to make our Django instance run perfectly without any problems. If we don’t, then we facing several problem like :
1. Django admin CSS / files not load properly or not found
2. Conflicting with static files
3. Conflicting with media files

Now, I will show my configuration which you can adapt it depend on your path. I have django project called “django_crawl”, located in /var/www/django_crawl. It have django.wsgi. Also, I use Ubuntu 11.10 Oneiric. In case you need it :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Django wsgi for apache
import os
import sys

# django project absolute path
sys.path.append(‘/var/www/django_crawl/’)

import monitor
monitor.start(interval=1.0)
monitor.track(os.path.join(os.path.dirname(__file__), ‘..’))

# django core location
sys.path.append(‘/usr/local/lib/python2.7/dist-packages/django/’)
sys.path.insert(0, os.path.join(os.path.abspath(os.path.dirname(__file__)),’..’))

# Your django settings
os.environ[‘DJANGO_SETTINGS_MODULE’] = ‘django_crawl.settings’

import django.core.handlers.wsgi
_application = django.core.handlers.wsgi.WSGIHandler()

def application(environ, start_response):
    return _application(environ, start_response)

# Logging WSGI middleware.
import pprint

class LoggingMiddleware:

    def __init__(self, application):
        self.__application = application

    def __call__(self, environ, start_response):
        errors = environ[‘wsgi.errors’]
        pprint.pprint((‘REQUEST’, environ), stream=errors)

        def _start_response(status, headers, *args):
            pprint.pprint((‘RESPONSE’, status, headers), stream=errors)
            return start_response(status, headers, *args)

        return self.__application(environ, _start_response)

application = LoggingMiddleware(application)

Also this is monitor.py which may you need :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# Monitor code for changes
# Only works for Apache2 + ModWSGI
# http://code.google.com/p/modwsgi/wiki/ReloadingSourceCode#Restarting_Daemon_Processes

import os
import sys
import time
import signal
import threading
import atexit
import Queue

_interval = 1.0
_times = {}
_files = []

_running = False
_queue = Queue.Queue()
_lock = threading.Lock()

def _restart(path):
    _queue.put(True)
    prefix = ‘monitor (pid=%d):’ % os.getpid()
    print >> sys.stderr, ‘%s Change detected to ‘%s’.’ % (prefix, path)
    print >> sys.stderr, ‘%s Triggering process restart.’ % prefix
    os.kill(os.getpid(), signal.SIGINT)

def _modified(path):
    try:
        # If path doesn’t denote a file and were previously
        # tracking it, then it has been removed or the file type
        # has changed so force a restart. If not previously
        # tracking the file then we can ignore it as probably
        # pseudo reference such as when file extracted from a
        # collection of modules contained in a zip file.

        if not os.path.isfile(path):
            return path in _times

        # Check for when file last modified.

        mtime = os.stat(path).st_mtime
        if path not in _times:
            _times[path] = mtime

        # Force restart when modification time has changed, even
        # if time now older, as that could indicate older file
        # has been restored.

        if mtime != _times[path]:
            return True
    except:
        # If any exception occured, likely that file has been
        # been removed just before stat(), so force a restart.

        return True

    return False

def _monitor():
    while 1:
        # Check modification times on all files in sys.modules.

        for module in sys.modules.values():
            if not hasattr(module, ‘__file__’):
                continue
            path = getattr(module, ‘__file__’)
            if not path:
                continue
            if os.path.splitext(path)[1] in [‘.pyc’, ‘.pyo’, ‘.pyd’]:
                path = path[:-1]
            if _modified(path):
                return _restart(path)

        # Check modification times on files which have
        # specifically been registered for monitoring.

        for path in _files:
            if _modified(path):
                return _restart(path)

        # Go to sleep for specified interval.

        try:
            return _queue.get(timeout=_interval)
        except:
            pass

_thread = threading.Thread(target=_monitor)
_thread.setDaemon(True)

def _exiting():
    try:
        _queue.put(True)
    except:
        pass
    _thread.join()

atexit.register(_exiting)

def track(path):
    if not path in _files:
        _files.append(path)

def start(interval=1.0):
    global _interval
    if interval < _interval:
        _interval = interval

    global _running
    _lock.acquire()
    if not _running:
        prefix = ‘monitor (pid=%d):’ % os.getpid()
        print >> sys.stderr, ‘%s Starting change monitor.’ % prefix
        _running = True
        _thread.start()
    _lock.release()

This is right Virtualhost configuration :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<VirtualHost *:80>
    ServerAdmin ubuntu@django_crawl
    ServerName django_crawl
    DocumentRoot /var/www/django_crawl

    # Django settings
    WSGIScriptAlias / /var/www/django_crawl/django.wsgi
    WSGIDaemonProcess django_crawl user=www-data group=www-data processes=1 threads=10
    WSGIProcessGroup django_crawl

    # Non-Django directories
    Alias /static /var/www/django_crawl/static/
    Alias /media/ /var/www/django_crawl/media/

    <Location "/static">
        SetHandler None
    </Location>
   
    <Directory /var/www/django_crawl/static>
        Order deny,allow
        Allow from all
    </Directory>

    <Directory /var/www/django_crawl/media>
        Order deny,allow
        Allow from all
    </Directory>

    <Directory /var/yodi/django_crawl>
      Order allow,deny
      Allow from all
    </Directory>


    Alias /robots.txt /var/www/django_crawl/robots.txt
    Alias /favicon.ico /var/www/django_crawl/favicon.ico
   
    ErrorLog /var/log/apache2/error.log
    CustomLog /var/log/apache2/access.log combined

</VirtualHost>

Now, it will run Django on “http://django_crawl” perfectly! 🙂


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.