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.