Django Mod WSGI Apache and Virtualhost on Fedora 17


Here is a steps for setup Django with modwsgi + httpd + Virtualhost in Fedora 17.

1. Install Apache and Mod WSGI

1
sudo yum install -u httpd* mod_wsgi

2. Load modwsgi
To avoid error :

1
invalid command ‘WSGIScriptAlias’, perhaps misspelled

We need to check whether this line exists in “/etc/httpd/conf/httpd.conf”:

1
LoadModule wsgi_module modules/mod_wsgi.so

3. Create wsgi
We need to create WSGI handler which contain configuration of our web path, python interpreter and settings. In this example, I will point into virtualenvironment for python interpreter.

django_wsgi.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import os, sys
import site

sys.stdout = sys.stderr # for mod_wsgi versions < 3.0, logging to stdout will trigger an IOError exception

ALLDIRS = [‘/home/yodi/.virtualenvs/django/lib/python2.7/site-packages’] # path to virtualenv lib folder on server

# Remember original sys.path.
prev_sys_path = list(sys.path)

# Add each new site-packages directory.
for directory in ALLDIRS:
    site.addsitedir(directory)

site.addsitedir("/home/yodi/htdocs/web/") # django project folder

sys.path.append(os.path.dirname(os.path.abspath(__file__)) + ‘/..’)
os.environ[‘DJANGO_SETTINGS_MODULE’] = ‘web.settings’

import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()

4. Create Django Virtualhost on Apache
Open “/etc/httpd/conf/httpd.conf” and add this configuration. Please change the value with yours django path.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
NameVirtualHost *:8001
Listen 8001

<virtualhost *:8001>
    ServerAdmin yodi@localhost
    ServerName yodi

    # Django settings
    WSGIScriptAlias / /home/yodi/htdocs/web/django_wsgi.py
    <Directory /home/yodi/htdocs/web>
        Order deny,allow
        Allow from all
    </Directory>
    WSGIDaemonProcess tripvillas user=yodi group=yodi processes=10 threads=5 python-path=/home/yodi/.virtualenv/django/lib/python2.7/site-packages/
    WSGIProcessGroup yodi
</virtualhost>

WSGISocketPrefix /var/run/wsgi

5. Check permission and SELINUX problem in Fedora
If you’re want to setup this for development, you can remove “SELINUX” that might give you headache because several permission problem in httpd:

1
sudo yum remove -y selinux*

The last step you need is just restart httpd service and check on http://localhost:8001

If you got this errors:

1
[Thu Mar 07 12:01:50 2013] [error] [client 127.0.0.1] (13)Permission denied: access to / denied (filesystem path ‘/home/yodi/htdocs/web’) because search permissions are missing on a component of the path

Maybe your httpd.conf is already modified before. Just save it into somewhere and re-install apache.

1
2
sudo yum remove -y httpd*
sudo yum install -y httpd* mod_wsgi

6. Add monitor to restart Apache whenever code changes
Add monitor.py in same level with your projects :

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
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()

And add this into last line of django_wsgi.py:

1
2
import monitor
monitor.start(interval=1.0)

Restart your apache to apply this monitor settings.


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.