How to deploy Django App on Apache with SSL using Let’sEncrypt

neotam Avatar

Django App Deployed on Apache with HTTP

On debian based linux or ubuntu, install the apache server

sudo apt update
sudo apt install apache2

remove the default page using command

a2dissite 000-default
systemctl reload apache2

To configure Django application with apache, you need the mod_wsgi module installed for apache

sudo apt-get install libapache2-mod-wsgi

or

apt install libapache2-mod-wsgi-py3

To enable the module

 a2enmod wsgi

You can configure the virtualhost that way you can run multiple sites differentiated by domain name, host and port. You can run multiple websites on same port by configuring apache virtualhosts using ServerName

To get started first create your configuration file at ‘/etc/apache2/sites-available/example.conf’

<VirtualHost *:80>
        ServerName www.example.com

        ServerAdmin webmaster@example.com


        WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py
        WSGIDaemonProcess example.com python-home=/path/to/venv python-path=/path/to/mysite.com
        WSGIProcessGroup example.com

        <Directory /path/to/mysite.com/mysite>
                <Files wsgi.py>
                        Require all granted
                </Files>
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

To enable the configured virtualhost or site

 a2ensite example
systemctl reload apache2

Note that when you specify the conf/site to the a2ensite you don’t need to include the extension (conf)

After configuration, restart the apache then try to hit the URL (which would be according to ServerName configured) while error log is opend to trouble shoot if any

tail -f /var/log/apache2/error.log

Configure Static Content

Well great, at this point you should see you site working but, you might see site running fuzzy due to missing static files such as CSS and JavaScript.

To collect all static files into single directory djang offers the management command “python manage.py collectstatic” so that you can configure it on web server or serve them from AWS s3. Before using this command you must configure the “STATIC_ROOT” in settings.py

python manage.py collectstatic

After running this command all static files will collected to folder specified in STATIC_ROOT setting

You can update the apache conf to serve these static files on specific path configured using Alias directive

Alias /media/ /path/to/mysite.com/media/
Alias /static/ /path/to/mysite.com/static/

If you are getting “403 Forbidden” tweak the apache configuration to provide the enough permissions. Typicall you will see error like “client denied by server configuration” in apache error logs

Assuming you are using the apache2 version 2.4, you need to configure

<Directory /path/to/site.com/static>
                Require all granted
</Directory>

Here is the final configuration that would look like

<VirtualHost *:80>
        ServerName example.com
        ServerAdmin webmaster@example.com

        Alias /static/ /opt/mysite.com/static/

        WSGIScriptAlias /  /opt/mysite.com/mysite.com/wsgi.py
        WSGIDaemonProcess example.com python-home=/opt/empenv python-path=/opt/mysite.com
        WSGIProcessGroup example.com

        <Directory  /opt/mysite.com/mysite>
                <Files wsgi.py>
                        Require all granted
                </Files>
        </Directory>

        <Directory /opt/mysite.com/static>
                Require all granted
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

Configure HTTPS using Let’sEncrypt

To enable the HTTPS for deployed Django application on Apache we need to the private key and SSL certificate. Where SSL certificate is the public key and information about website signed by well known certificate authority. Usually SSL certificate authority or provider like comodo, giticert, Thawte charge to issue the certificate of validity 1 year or 2 years. But, in this tutorial we will use the Let’sEncrypt which certificate authority issues certificates for free but for 3 months only.

certbot is the command line application which assists us to get certficate from Let’sEncrypt authority. Let’s install certbot for apache

sudo apt install certbot python3-certbot-apache

By this point you should have the Django web application configured using VirtualHost over port 80 (HTTP). After certbot is installed run the following command to acquire the SSL certficates and auto configure the apache for HTTPS with redirections

sudo certbot --apache

If multiple websites are configured on Apache, and you wanted to configure certificates for only specified one. Run the certbot with -d option

certbot --apache -d example.com

Start the auto-renewal timer using following command

sudo systemctl enable certbot.timer

Here is the final auto configured, apahce ssl configuration file of website by certbot

<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerName example.com
        ServerAdmin webmaster@example.com

    	Alias /static/ /opt/mysite.com/static/

        WSGIScriptAlias /  /opt/mysite.com/mysite/wsgi.py
        WSGIDaemonProcess example.com python-home=/opt/empenv python-path=/opt/mysite.com
        WSGIProcessGroup example.com

        <Directory  /opt/mysite.com/mysite>
                <Files wsgi.py>
                        Require all granted
                </Files>
        </Directory>

	<Directory /opt/mysite.com/static>
		Require all granted
	</Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined


    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

Certificate Renewal

You can renew the certficate using following command

certbot --nginx -d exmaple.com  --force-renewal

Or

certbot -d example.com --force-renewal

Troubleshooting

WSGIPythonHome cannot occur within <VirtualHost>

Error: WSGIPythonHome cannot occur within <VirtualHost> section

AH00526: Syntax error on line 9 of /etc/apache2/sites-enabled/example.conf:
WSGIPythonHome cannot occur within <VirtualHost> section
Action 'start' failed.
The Apache error log may have more information.

To resolve this error you must use the WSGIDaemonProcess inside the VirtualHost instead of WSGIPythonHome

Certbot failure due to duplicate WSGI daemon

Error while configuring the SSL using certbot

Error while running apache2ctl configtest.
Action 'configtest' failed.
The Apache error log may have more information.

AH00526: Syntax error on line 11 of /etc/apache2/sites-enabled/mysite.conf:
Name duplicates previous WSGI daemon definition

As a workaround for this issue when using certbot, you can comment the following while using certbot and then uncommend after certficates are deployed.

WSGIScriptAlias 
WSGIDaemonProcess 
WSGIProcessGroup

This issue is due to the bug of certbot issue 4880 . Once certficates are installed successfully, uncomment the above 3 directives from ssl configuration added by certbot

Leave a Reply

Your email address will not be published. Required fields are marked *