In today’s tutorial, we will go through the process of deploying a Django project with Apache and mod_wsgi. This will also cover the basics of working with WSGI, Apache and Django.
What is WSGI?
The Web Server Gateway Interface (WSGI pronounced as whiskey) describes how a web server such as Apache or Nginx communicates with web applications, and how the web applications processes or executes a request. Django primarily uses WSGI for the deployment of web applications. Django uses different WSGI servers which include:
- Gunicorn
- uWSGI
- mod_wsgi
Install Apache and mod_wsgi
To install apache and mod_wsgi, execute the following commands. The mod_wsgi is used to serve the Django scripts and is specifically created for apache.
sudo yum -y update
sudo yum -y install epel-release
sudo yum -y install httpd mod_wsgi
Open port 80 for http
Although I am enabling port 80, you can use another port e.g. 8000 to access your project.
sudo firewall-cmd --zone=public --permanent --add-port=80/tcp
sudo firewall-cmd reload
Enable Software Collections
Software Collections will enable us to build, install, and use multiple versions of software on the same system, without affecting system default packages. In this case, python3. This is because CentOS 7 ships with python version 2 but our projet uses version 3. Let’s enable software collections and install python3.
sudo yum -y install centos-release-scl
sudo yum -y install rh-python36 python36-devel httpd-devel rh-python36-mod_wsgi
scl enable rh-python36 bash
python --version
Please note that Python 3.6 is set as the default Python version for this shell session. Closing the session or opening a new session from another terminal will yield Python 2.7 as the default Python version.
Prepare your project
Mostly when deploying your project to production we will use a git repository, so we will start from this scenario. Let us now clone the project and set up everything else like migrations and preparing static files.
$ cd /var/www/
$ sudo git clone <myproject>.git
Create a custom directory called logs for our specific project access and error logs from apache:
$ sudo mkdir logs
Create a virtual environment and activate it. The virtual environment will be used to make some configurations such as database migrations and static files collection:
$ virtualenv venv
$ source venv/bin/activate
We now need to install our project dependencies and requirements using pip from the requirements.txt file:
$ pip install -r requirements.txt
Let us now make migrations and server our any static files as per the Django deployment requirements on static files:
$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py collectstatic
Deactivate the virtual environment and change the project folder ownership to apache. The ownership ensures that apache can make the necessary executions, writes and reads on the project.
$ deactivate
$ sudo chown -R apache:apache /var/www/
The mod_wsgi daemon mode
On UNIX servers, it is recommended to use the daemon mode using mod_wsgi. This will create a daemon process group and delegate the Django instance to run in it. Our apache configuration file will, therefore, require us to define aWSGIDaemonProcess
and WSGIProcessGroup
directives.
Configure apache conf file for the project
Now configure apache conf file for our project. Please note that in this case, my project’s name is awesomedjango.
sudo vim /etc/httpd/conf.d/django.conf
Paste this configuration, ensure to replace your project name and path where necessary!
<VirtualHost *:80>
ServerAdmin [email protected]
ServerName awesomedjango.com
DocumentRoot /var/www/
Alias /static /var/www/awesomedjango/static
<Directory "/var/www/awesomedjango/static">
Options FollowSymLinks
Order allow,deny
Allow from all
Require all granted
</Directory>
Alias /media /var/www/awesomedjango/media
<Directory "/var/www/awesomedjango/media">
Options FollowSymLinks
Order allow,deny
Allow from all
Require all granted
</Directory>
ErrorLog /var/www/awesomedjango/logs/apis_error.log
CustomLog /var/www/awesomedjango/logs/apis_access.log combined
WSGIPassAuthorization On
WSGIDaemonProcess awesomedjango python-path=/var/www/awesomedjango:/var/www/awesomedjango/venv/lib/python3.6/site-packages
WSGIProcessGroup awesomedjango
WSGIScriptAlias / /var/www/awesomedjango/v/wsgi.py
<Directory /var/www/awesomedjango/awesomedjango>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
</VirtualHost>
If you are using a version of Apache older than 2.4, replace Require all granted
with Allow from all
and also add the line Order deny,allow
above it.
Apache mod_wsgi specific conf for djangorestframework
If you are using
djangorestframework here is a tip from them:
If you get the error: AttributeError: ‘module’ object has no attribute ‘lru_cache’
This error found on the apache error logs occurs when you are using python3 mod_wsgi. To rectify this execute the following:
$ sudo cp /opt/rh/httpd24/root/usr/lib64/httpd/modules/mod_rh-python36-wsgi.so /lib64/httpd/modules
$ sudo cp /opt/rh/httpd24/root/etc/httpd/conf.modules.d/10-rh-python36-wsgi.conf /etc/httpd/conf.modules.d
Restart apache server:
$ sudo systemctl restart httpd
Navigate to your domain name or IP address to view your site!. More reading.
Managing Docker Containers with Docker Compose
How To Dockerize Django Application With PostgreSQL Database
How To Dockerize a Django Application on Linux
Thanks, peace out.