Skip to main content

Django Apache

Introduction

Deploying Django applications to production requires a robust, efficient, and secure web server. Apache HTTP Server, often simply called Apache, is one of the most popular web servers that can be used to deploy Django applications. In this tutorial, we'll explore how to configure Apache to serve Django applications using mod_wsgi, a module that provides a WSGI compliant interface for hosting Python web applications.

Apache offers several advantages for Django deployments:

  • Mature and stable platform with excellent documentation
  • Highly configurable with many modules available
  • Ability to serve multiple applications and static files efficiently
  • Robust security features
  • Wide adoption across hosting providers

Prerequisites

Before we begin, make sure you have:

  1. A working Django application
  2. Ubuntu/Debian or a similar Linux distribution (commands may vary for other distributions)
  3. Basic knowledge of terminal/command line
  4. Administrative access to install packages

Understanding Django-Apache Architecture

When deploying Django with Apache, here's what happens:

  1. Apache receives HTTP requests from clients
  2. The mod_wsgi module passes these requests to your Django application
  3. Django processes the request, generates a response
  4. The response is sent back through Apache to the client
Client ↔ Apache ↔ mod_wsgi ↔ Django Application

Installation Process

Step 1: Install Apache and mod_wsgi

bash
# Update package lists
sudo apt-get update

# Install Apache and related tools
sudo apt-get install apache2 apache2-utils

# Install mod_wsgi for Python 3
sudo apt-get install libapache2-mod-wsgi-py3

After installation, verify that Apache is running:

bash
sudo systemctl status apache2

Expected output:

● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2023-04-10 12:34:56 UTC; 5s ago

Step 2: Prepare Your Django Project

Make sure your Django project is ready for deployment:

  1. Set DEBUG = False in your settings.py
  2. Configure ALLOWED_HOSTS with your domain or IP address
  3. Set up a proper SECRET_KEY (preferably from environment variables)
  4. Configure static and media files properly
python
# settings.py
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com', 'your-server-ip']

# Static files configuration
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

# Media files configuration
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Step 3: Create a WSGI Configuration File

Create a file named django.wsgi (or any name you prefer) in your project directory:

python
import os
import sys

# Add your project directory to the sys.path
path = '/path/to/your/django_project'
if path not in sys.path:
sys.path.insert(0, path)

# Set environment variable to tell Django where your settings.py is
os.environ['DJANGO_SETTINGS_MODULE'] = 'your_project.settings'

# Set up Django
import django
django.setup()

# Import the WSGI application object
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

Step 4: Configure Apache Virtual Host

Create a new virtual host configuration file:

bash
sudo nano /etc/apache2/sites-available/django_project.conf

Add the following configuration (adjust paths according to your setup):

apache
<VirtualHost *:80>
# Set your domain name
ServerName yourdomain.com
ServerAlias www.yourdomain.com

# Set administrator email
ServerAdmin [email protected]

# Set document root
DocumentRoot /path/to/your/django_project

# Configure WSGI
WSGIDaemonProcess django_app python-home=/path/to/your/virtualenv python-path=/path/to/your/django_project
WSGIProcessGroup django_app
WSGIScriptAlias / /path/to/your/django_project/django.wsgi

# Configure static files
Alias /static/ /path/to/your/django_project/staticfiles/
<Directory /path/to/your/django_project/staticfiles>
Require all granted
</Directory>

# Configure media files
Alias /media/ /path/to/your/django_project/media/
<Directory /path/to/your/django_project/media>
Require all granted
</Directory>

# Configure access to the WSGI file
<Directory /path/to/your/django_project>
<Files django.wsgi>
Require all granted
</Files>
</Directory>

# Error log and access log configuration
ErrorLog ${APACHE_LOG_DIR}/django-error.log
CustomLog ${APACHE_LOG_DIR}/django-access.log combined
</VirtualHost>

Step 5: Enable the Site and Restart Apache

bash
# Enable the site
sudo a2ensite django_project.conf

# Enable required Apache modules (if not already enabled)
sudo a2enmod wsgi

# Check Apache configuration for syntax errors
sudo apache2ctl configtest

# Restart Apache
sudo systemctl restart apache2

Common Issues and Troubleshooting

Permissions Problems

One of the most common issues is permission problems. Apache runs as a different user (usually www-data), so it needs proper permissions to access your files.

bash
# Change ownership of project files to Apache user
sudo chown -R www-data:www-data /path/to/your/django_project

# Make sure the directory is accessible
sudo chmod -R 755 /path/to/your/django_project

500 Internal Server Error

If you're getting 500 errors, check Apache's error logs:

bash
sudo tail -f /var/log/apache2/django-error.log

Static Files Not Loading

Make sure you've run Django's collectstatic command:

bash
python manage.py collectstatic

Also, verify that the STATIC_ROOT in your Django settings matches the directory specified in the Apache configuration.

Advanced Configuration

Setting Up HTTPS with Let's Encrypt

For a production site, you'll want to enable HTTPS. Let's Encrypt provides free SSL certificates:

bash
# Install certbot
sudo apt-get install certbot python3-certbot-apache

# Obtain and install a certificate
sudo certbot --apache -d yourdomain.com -d www.yourdomain.com

Virtual Environment Integration

Ensure Apache uses your project's virtual environment:

apache
WSGIDaemonProcess django_app python-home=/path/to/your/virtualenv python-path=/path/to/your/django_project

Load Balancing with mod_wsgi Daemon Mode

For high-traffic sites, configure multiple processes:

apache
WSGIDaemonProcess django_app processes=5 threads=15 python-home=/path/to/your/virtualenv python-path=/path/to/your/django_project

Real-world Example: Complete Deployment

Let's walk through a complete example of deploying a blog application:

  1. Project structure:
/home/user/myblog/
├── blog/
│ ├── __init__.py
│ ├── models.py
│ ├── views.py
│ └── ...
├── myblog/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ ├── wsgi.py
│ └── ...
├── manage.py
└── requirements.txt
  1. Create a virtual environment and install dependencies:
bash
cd /home/user/
python3 -m venv myblog_env
source myblog_env/bin/activate
pip install -r myblog/requirements.txt
  1. Configure Django settings for production:
python
# myblog/settings.py
DEBUG = False
ALLOWED_HOSTS = ['blog.example.com']
STATIC_ROOT = '/home/user/myblog/staticfiles'
  1. Create a WSGI file:
python
# /home/user/myblog/myblog_wsgi.py
import os
import sys

path = '/home/user/myblog'
if path not in sys.path:
sys.path.insert(0, path)

os.environ['DJANGO_SETTINGS_MODULE'] = 'myblog.settings'

import django
django.setup()

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
  1. Configure Apache:
apache
# /etc/apache2/sites-available/myblog.conf
<VirtualHost *:80>
ServerName blog.example.com

WSGIDaemonProcess myblog python-home=/home/user/myblog_env python-path=/home/user/myblog
WSGIProcessGroup myblog
WSGIScriptAlias / /home/user/myblog/myblog_wsgi.py

Alias /static/ /home/user/myblog/staticfiles/
<Directory /home/user/myblog/staticfiles>
Require all granted
</Directory>

<Directory /home/user/myblog>
<Files myblog_wsgi.py>
Require all granted
</Files>
</Directory>

ErrorLog ${APACHE_LOG_DIR}/myblog-error.log
CustomLog ${APACHE_LOG_DIR}/myblog-access.log combined
</VirtualHost>
  1. Collect static files and set permissions:
bash
python manage.py collectstatic
sudo chown -R www-data:www-data /home/user/myblog
sudo chown -R www-data:www-data /home/user/myblog_env
  1. Enable the site and restart Apache:
bash
sudo a2ensite myblog.conf
sudo systemctl restart apache2

Summary

In this tutorial, we've covered how to deploy a Django application with Apache and mod_wsgi. We've gone through:

  1. Installing Apache and mod_wsgi
  2. Configuring Django for production
  3. Creating a WSGI file
  4. Setting up an Apache virtual host
  5. Handling common issues and troubleshooting
  6. Advanced configurations including HTTPS setup
  7. A complete real-world deployment example

Apache with mod_wsgi is a battle-tested, reliable way to deploy Django applications in production environments. While the initial setup may seem complex compared to some newer deployment methods, it provides a high level of control and excellent performance for Django applications.

Additional Resources

Exercises

  1. Deploy a basic Django "Hello World" app using Apache and mod_wsgi.
  2. Configure your deployment to serve both Django and a separate static HTML site under different URLs.
  3. Set up two different Django projects under different subdomains using the same Apache server.
  4. Implement HTTPS on your Django deployment using Let's Encrypt.
  5. Configure Apache to serve a Django application with WebSockets support for features like real-time chat.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)