Deploy a Django App on Ubuntu Server with Apache

Deploy a Django App on Ubuntu Server with Apache

Deploying a Django application on a production server can seem daunting at first, but by following a systematic approach you can have a robust, secure, and maintainable setup. In this article, we’ll walk through every step to deploy a Django app on an Ubuntu server using Apache with the mod_wsgi module. We’ll cover prerequisites, server setup, application configuration, security hardening, and best practices for ongoing maintenance. By the end, you will have a fully functional, production-ready Django deployment.

Prerequisites

Before we begin, ensure you have the following:

  • Ubuntu Server (18.04, 20.04, 22.04 LTS or later) with root or sudo access.
  • Domain name pointing to your server’s public IP.
  • Basic knowledge of Django, Linux command line, and Apache.
  • Git repository containing your Django project (optional but recommended).
  • An administrator user with sudo privileges.

Preparing the Ubuntu Server

Updating System Packages

First, update the package lists and upgrade existing packages to the latest versions:

sudo apt update
sudo apt upgrade -y

Keeping the system up to date ensures you have the latest security fixes and features.

Creating a Dedicated System User

For security and manageability, create a system user that will own and run the Django application:

sudo adduser --disabled-login --gecos 'Django App' django

This command creates a user django without login capabilities and sets descriptive GECOS fields.

Installing Apache and mod_wsgi

Installing Apache

Install Apache HTTP Server from Ubuntu’s repositories:

sudo apt install -y apache2

Enable Apache to start on boot:

sudo systemctl enable apache2

Installing mod_wsgi

mod_wsgi is the Apache module that interfaces with Python applications via the WSGI protocol:

sudo apt install -y libapache2-mod-wsgi-py3

This will install mod_wsgi compiled for Python 3.

Enabling Necessary Apache Modules

Enable the mod_wsgi, headers, and rewrite modules, which are commonly needed:

sudo a2enmod wsgi
sudo a2enmod headers
sudo a2enmod rewrite

After enabling modules, reload Apache:

sudo systemctl reload apache2

Setting Up the Python Virtual Environment

Installing Python and pip

Ensure Python 3 and pip are installed:

sudo apt install -y python3 python3-pip python3-venv

Creating and Activating a Virtualenv

Switch to the dedicated user and create a virtual environment inside your project directory:

sudo -i -u django
cd ~
git clone https://github.com/yourusername/your-django-project.git
cd your-django-project

python3 -m venv venv
source venv/bin/activate

Your shell prompt should now show the (venv) prefix.

Installing Django and Application Dependencies

Within the virtualenv, install your project’s dependencies:

pip install --upgrade pip
pip install -r requirements.txt

If you don’t yet have a requirements.txt, generate one locally with:

pip freeze > requirements.txt

Configuring the Django Application

Adjusting Settings for Production

Edit your settings.py to ensure production readiness:

  • DEBUG: set to False.
  • ALLOWED_HOSTS: add your domain name and server IP.
  • SECRET_KEY: load from an environment variable or external file; do not hardcode.
  • Static/Media: configure STATIC_ROOT, MEDIA_ROOT, and corresponding URLs.
  • Database: switch from SQLite (development) to PostgreSQL or MySQL for production.

Example snippet:

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

DEBUG = False

SECRET_KEY = os.getenv('DJANGO_SECRET_KEY', 'fallback-secret')

ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com', 'your.server.ip']

STATIC_ROOT = BASE_DIR / 'staticfiles'
MEDIA_ROOT = BASE_DIR / 'mediafiles'
STATIC_URL = '/static/'
MEDIA_URL = '/media/'

Collecting Static Files

Collect all static assets into the directory defined by STATIC_ROOT:

python manage.py collectstatic --noinput

This command gathers CSS, JavaScript, images, and other static files for efficient serving.

Database Migrations

Apply any pending migrations to set up your production database schema:

python manage.py migrate

You should also create a superuser for admin access:

python manage.py createsuperuser

Apache Virtual Host Configuration

Creating the Virtual Host File

On Ubuntu, Apache site configurations reside in /etc/apache2/sites-available/. Create a new file, e.g. yourproject.conf:

sudo nano /etc/apache2/sites-available/yourproject.conf

Populate it as follows:

<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com

    # Serve static and media directly
    Alias /static/ /home/django/your-django-project/staticfiles/
    <Directory /home/django/your-django-project/staticfiles>
        Require all granted
    </Directory>

    Alias /media/ /home/django/your-django-project/mediafiles/
    <Directory /home/django/your-django-project/mediafiles>
        Require all granted
    </Directory>

    # WSGI configuration
    WSGIDaemonProcess yourproject python-home=/home/django/your-django-project/venv python-path=/home/django/your-django-project
    WSGIProcessGroup yourproject
    WSGIScriptAlias / /home/django/your-django-project/yourproject/wsgi.py

    <Directory /home/django/your-django-project/yourproject>
        <Files wsgi.py>
            Require all granted
        </Files>
    </Directory>

    # Logging
    ErrorLog ${APACHE_LOG_DIR}/yourproject-error.log
    CustomLog ${APACHE_LOG_DIR}/yourproject-access.log combined
</VirtualHost>

Adjust paths to match your project’s directory structure and WSGI module location.

Enabling the Site and Restarting Apache

Enable your new site configuration and disable the default site to avoid conflicts:

sudo a2ensite yourproject.conf
sudo a2dissite 000-default.conf

Reload Apache to apply changes:

sudo systemctl reload apache2

Test that your application is accessible via http://yourdomain.com/. If you see Django’s default “It worked!” page or your application homepage, deployment is successful on HTTP.

Serving Static and Media Files

In our VirtualHost above, we configured Apache to serve static and media files from designated directories. This is efficient, as Apache handles these requests faster than going through Django. Ensure the file permissions allow the Apache user (www-data) to read these directories:

sudo chown -R django:www-data /home/django/your-django-project/staticfiles
sudo chown -R django:www-data /home/django/your-django-project/mediafiles
sudo chmod -R 750 /home/django/your-django-project/staticfiles
sudo chmod -R 750 /home/django/your-django-project/mediafiles

Enabling HTTPS with Let’s Encrypt

Securing your application with TLS is crucial. We’ll use Certbot to obtain a free SSL certificate.

  1. Install Certbot and the Apache plugin:
  2. sudo apt install -y certbot python3-certbot-apache
  3. Obtain and install the certificate:
  4. sudo certbot --apache -d yourdomain.com -d www.yourdomain.com
  5. Follow interactive prompts to agree to terms and configure redirection from HTTP to HTTPS.
  6. Verify Renewal:
  7. Certbot installs a cron job for renewal. Test it:
  8. sudo certbot renew --dry-run

Securing the Server

Firewall Configuration

Use UFW (Uncomplicated Firewall) to allow only necessary traffic:

sudo apt install -y ufw
sudo ufw allow OpenSSH
sudo ufw allow 'Apache Full'
sudo ufw enable

This opens ports 22 (SSH), 80 (HTTP), and 443 (HTTPS).

Fail2Ban Setup

Protect against brute‑force attacks by installing Fail2Ban:

sudo apt install -y fail2ban

Create a local jail configuration:

sudo nano /etc/fail2ban/jail.local

Insert:

[sshd]
enabled = true

[apache-auth]
enabled = true

Restart Fail2Ban:

sudo systemctl restart fail2ban

Automatic Security Updates

Enable unattended security updates:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

This ensures critical security patches install automatically.

Logging and Monitoring

  • Apache Logs: Check /var/log/apache2/yourproject-error.log and -access.log.
  • Django Logs: Configure Django logging in settings.py to capture application-level errors.
  • System Monitoring: Use tools like htop, top, or more advanced solutions (Prometheus + Grafana) for resource monitoring.

Automating Deployment

Manual deployments are error prone. Consider using:

  • Fabric or Invoke: Python-based remote execution.
  • Ansible: Automated provisioning and deployment playbooks.
  • CI/CD Pipelines: GitHub Actions, GitLab CI, or Jenkins to build/test/deploy on push.

Example Fabric snippet (fabfile.py):

from fabric import task

@task
def deploy(c):
    c.run('cd ~/your-django-project && git pull')
    c.run('cd ~/your-django-project && source venv/bin/activate && pip install -r requirements.txt')
    c.run('cd ~/your-django-project && source venv/bin/activate && python manage.py migrate --noinput')
    c.run('cd ~/your-django-project && source venv/bin/activate && python manage.py collectstatic --noinput')
    c.sudo('systemctl restart apache2')

Troubleshooting Common Issues

  • 500 Internal Server Error: Check Apache error log and Django logs; often a Python exception or misconfigured settings.
  • Static files not loading: Verify Alias paths, directory permissions, and that you ran collectstatic.
  • Permission denied: Ensure the Apache user (www-data) can read your project files and the WSGI socket.
  • Certificate issues: Use sudo certbot certificates to inspect and certbot renew --dry-run to test renewals.

Conclusion

Deploying Django with Apache on Ubuntu involves several steps—from server preparation and package installation to configuring Apache virtual hosts and securing your application with HTTPS. While it may seem complex, each step builds on the previous to yield a reliable and maintainable production environment. Once set up, consider automating your deployments and continuously monitoring your server for performance and security.

By following this guide, you can confidently deploy any Django project onto an Ubuntu server using Apache and serve your application to the world in a secure, efficient manner. Happy deploying!

#django deployment #ubuntu server #apache #mod_wsgi #deploy django #django production #django ubuntu apache #virtualenv #let’s encrypt SSL #django security #django best practices

Subscribe to our newsletter

12k+

Subscribers

Weekly

Frequency

Free

Always