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! 🙂