Django logo

Hosting Django sites with Apache

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.

Date posted: June 22, 2017


Great article, Keith.
Excuse my ignorance on this, but please can you explain a little more how this leads to the virtual environment being 'activated' on the deployment server ? I can see how the path in the WSGIDaemonProcess picks up the particular python version to use, but does this also somehow activate virtual env ? Also, if this is the case, is it recommended that the 'venv' directory be located within the application code on the development system (and committed to the repository along with all other app code) ?

Yes, when you invoke Python with .../venv/lib/python3.5 it automatically uses that venv for pip packages as well.

It doesn't really matter where you pun the venv, but it's often at or near the root of the repository. Do not commit venv to source control, since the contents are machine-specific. Normally this would be created with build script you run during your deploy process.

Here is a sample build script you could use:

echo "Building virtualenv..."
wget ''
tar -xzf virtualenv-15.0.2.tar.gz
python virtualenv-15.0.2/ --no-site-packages venv
./venv/bin/pip install -r requirements.txt

Pretty promising guide right up until "Set up the Apache virtualhost" and the newbie reader will be utterly lost at sea and cast adrift upon an ocean of uncertainty.

Do I create mysite.conf in that folder? Should it already be there? Should I copy what's provided into a file I create? If WSGIDaemonProcess and WSGIProcessGroup are so important, why no guidance on how to edit them? What does 'aggregates static files' mean? How do I find whether /static/ is pointing towards the correct location?!?!

Once you reach that header the average newbie reader is basically screwed.

For sure, this is a complex subject, and difficult for a first-timer!

If you get totally stuck building your own server solution, you might consider a Platform-as-a-service option like Heroku. They also have paid support and really helpful folks that can walk you through the setup process.

Great post! I have a small question. I have been trying to configure both php and django simultaneously. I have a domain configured already to my server/host. Now to call the new applciations running on django should I use the URL as IP_address/Server_name which is used in the configuration file? Can you give me a small example if its possible.

Great Article! Thank you.
I wish you wrote more.

After setting up the conf file, and the file, what next? How to start using the site? Do I again use runserver?

Hello sir.
First of all this is just amazing tuto..
But i have just a simple question ..
If i run the server i will see on browser?

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <cpp>, <java>, <php>. The supported tag styles are: <foo>, [foo].
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.

Metal Toad is an Advanced AWS Consulting Partner. Learn more about our AWS Managed Services

Have questions?