Hosting Django sites with Apache

Metal Toad is an AWS Managed Services provider.

Filed under:

Metal Toad is an AWS Managed Services provider. In addition to Django & Apache work we recommend checking out our article on how to host a website on AWS in 5 minutes.

Django is a fantastic, powerful web development framework. It's great for development, but hosting it can be a bit of a puzzle. WSGI? Daemon mode? What's going on here?

This article will show you the basics of getting your Django sites running on an Ubuntu server running Apache 2.4.x, using WSGI.


In this article, we will see how to:

  • Set up a Django site on an Apache virtualhost, using WSGI
  • Use virtualenv to give each site its unique set of Python packages
  • Use WSGI in Daemon mode
  • Run multiple Django sites on one server
  • Deploy new code once we have a site running

WSGI? Great, another acronym!

The Web Server Gateway Interface (WSGI) is a fast CGI interface for Python, similar to PHP's FPM or classic cgi-bin. It provides an interface where Apache can send requests for any URL that requires Python server-side processing.

Using Virtualenv

This tutorial assumes you're using the excellent virtualenv package to keep the dependencies for each project separate. That's great in development, but Apache doesn't know how to "source" a virtual environment before starting the WSGI process. Thus, you need to supply the full path to the Python executable inside the virtual environment.

You'll notice the string "venv" in some of the Python paths. That's a common name for the virtual environment folder. If you chose a different name when you created your virtual environment, replace the instances of "venv" below with the name you chose.

This post is not intended to be a tutorial on setting up virtualenv. You can find that at the Hitchhiker's Guide to Python, among other places.

Installing packages

You'll need to install the following packages using your operating system's package manager:


  • apache2
  • python and python-dev, or python3 and python3-dev (required to install some packages with pip)
  • libapache2-mod-wsgi (Python 2) or libapache2-mod-wsgi-py3 (for Python 3)


  • httpd version 2.4
  • python and python-dev, or python3 and python3-dev (required to install some packages with pip)
  • mod_wsgi (for Python 2) or python3-mod_wsgi (for Python 3)

You may need some additional packages, depending on which Python packages your site uses. I've needed things like libssl-dev/openssl-devel

Set up the Apache virtualhost

Running a site through WSGI takes a few more steps than the typical Apache virtualhost configuration. You need to specify paths to your WSGI file and to Python itself. Note that we use the paths to the virtual environment here, rather than the paths to the global install of Python.


<VirtualHost *:80> 
 DocumentRoot /var/www/vhosts/mysite 
 WSGIScriptAlias / /var/www/vhosts/mysite/myproject/ 
 # adjust the following line to match your Python path 
 WSGIDaemonProcess processes=2 threads=15 display-name=%{GROUP} python-home=/var/www/vhosts/mysite/venv/lib/python3.5 
 <directory /var/www/vhosts/mysite> 
   AllowOverride all 
   Require all granted 
   Options FollowSymlinks 
 Alias /static/ /var/www/vhosts/mysite/static/ 
 <Directory /var/www/vhosts/mysite/static> 
  Require all granted 

Notice the WSGIDaemonProcess and WSGIProcessGroup settings, which provide the daemon configuration for the site. Also notice the "Alias /static/" line, which points at the "static" folder inside your site. This must match the folder where python collectstatic aggregates the static files from your apps. If you miss this step, you'll see a site full of broken images and missing CSS files.

After creating the virtualhost file, you need to enable it. If you're using a Debian or Ubuntu or a related distro, run:

sudo a2ensite mysite
sudo apachectl restart

Other distributions like CentOS might need to copy a file or create a symlink manually to enable the site.

Configuring WSGI

Your Django application comes with a file out of the box. It's in the main project directory, next to your file. I've found that the standard needs a few updates to work cleanly with Apache. Edit your so it looks like the following:

exposes the WSGI callable as a module-level variable named ``application``. 
For more information on this file, see 
import os 
import time 
import traceback 
import signal 
import sys 
from django.core.wsgi import get_wsgi_application 
# adjust the Python version in the line below as needed 
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings") 
    application = get_wsgi_application() 
except Exception: 
    # Error loading applications 
    if 'mod_wsgi' in sys.modules: 
        os.kill(os.getpid(), signal.SIGINT) 

Note the file paths, which need to match the paths on your server, including the Python version. You also need to put your project's name in the value of DJANGO_SETTINGS_MODULE. That's the project name, not the name of one of your apps.

Setting up a second virtual host

The second Virtual Host is set up very similarly to the first. The main differences are the server names, paths, and the location of the file.


<VirtualHost *:80> 
 DocumentRoot /var/www/vhosts/myothersite 
 WSGIScriptAlias / /var/www/vhosts/myothersite/myotherproject/ 
 WSGIDaemonProcess processes=2 threads=15 display-name=%{GROUP} python-home=/var/www/vhosts/myothersite/venv/bin/python3.5 
 <directory /var/www/vhosts/myothersite> 
   AllowOverride all 
   Require all granted 
   Options FollowSymlinks 
 Alias /static/ /var/www/vhosts/myothersite/static/ 
 <Directory /var/www/vhosts/myothersite/static> 
  Require all granted 

As before, you need to enable the new site and restart Apache before the site is usable.

Deploying code

This article doesn't intend to provide opinions on how to deploy your code. Whether you're using a CI process or a simple "git pull", you only need to know one special thing about deploying Django sites on Apache:

Restart Apache after updating any Python code!

This one gets me sometimes. The WSGI process only interprets the Python code once, when you start Apache. Any time you change Python code, run apachectl restart or the appropriate restart command for your server. Then you'll see your new code working. This only applies to changes in the actual Python code. Deploying HTML, CSS, JavaScript, and images doesn't require an Apache restart.


Don't mix major Python versions

This setup does not allow hosting Python 2 and Python 3 sites on the same server. True, each project can have its own Python executable using virtualenv. But Apache doesn't make this quite as simple as Python does.

During your package install, you'll need to choose either the Python 2 or Python 3 version of the Apache2 WSGI module. (On Debian/Ubuntu, these are called libapache2-mod-wsgi or libapache2-mod-wsgi-py3.) If you install the Python 2 version, you'll only be able to host Python 2 sites with Apache. If you install the Python 3 version, you'll only be able to host Python 3 sites.

Windows support

Python itself runs great on Windows. But, I haven't gotten WSGI to work on Windows yet. It's theoretically possible, but you'd have to be very careful about getting a version of Apache and a version of Python that were compiled using the same compiler (VC11, VC14, etc.).

If you used a package like XAMPP or WampServer to install Apache, these come with a specific pre-compiled version of Apache. It may be difficult to find a binary of mod_wsgi that matches the same compiler used to build the Apache binary. You may need to install a standalone copy of Apache on your Windows machine in order to get WSGI working.

Similar posts

Get notified on new marketing insights

Be the first to know about new B2B SaaS Marketing insights to build or refine your marketing function with the tools and knowledge of today’s industry.