I recently attempted to deploy my Django projects on Amazon Lightsail and took notes for myself on the issues that came up for me. For starters, the AWS documentation for deploying a plain Django app without any database can be found here.
On the AWS console, we will find many Bitnami applications to choose from, including Django. If we run into any trouble deploying Django that is Bitnami-related, we can find support from Bitnami.
Since the AWS tutorial is for a barebones Django app, it doesn't provide documentation for apps with database. If our project uses a database like mine, we will most likely encounter this error -- Attempt to write a readonly database
while the DEBUG=True
setting is enabled in settings.py.
Running a production server using Apache requires a different command than python manage.py runserver
. As noted in the AWS tutorial, the command would be:
$ sudo /opt/bitnami/ctlscript.sh restart apache
If we were to locate the apache
process on our terminal with ps -ef | grep apache
we will see something like this:
bitnami@ip-xxx-xx-x-xx:/opt/bitnami/projects/iplan$ ps -ef | gre
p apache
root 26520 1 0 16:17 ? 00:00:00 /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf
daemon 26523 26520 0 16:17 ? 00:00:01 /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf
daemon 26524 26520 0 16:17 ? 00:00:01 /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf
daemon 26525 26520 0 16:17 ? 00:00:01 /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf
daemon 26526 26520 0 16:17 ? 00:00:00 /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf
daemon 26527 26520 0 16:17 ? 00:00:00 /opt/bitnami/apache/bin/httpd -f /opt/bitnami/apache/conf/httpd.conf
Since we ran the apache server as sudo
, we will find multiple server processes - One that is owned by root
and the others by the user daemon
. daemon
as defined by Linux is a service process that operates in the background servicing other processes. There is also a daemon
user and group associated with this process.
When we deployed Django on AWS, we were logged in as the user, bitnami
. To enable the daemon
process to read from and write to our default database, we need to configure the read and write permissions to the database file. To get to the database file, the daemon
process also needs the same permissions for the project root directory. So, we will have to do two things:
- Change group ownership of the project root directory and the database file to
daemon
. For example:
$ sudo chgrp daemon project_directory project_directory/database_file
- Make the project root directory and the database file writable by the
daemon
group. For example:
$ sudo chmod g+w project_directory project_directory/database_file
To see if the database error goes away, try reloading the Django app on the browser.
The Apache server's default timezone is in UTC
. This may not be what we want. It's helpful to align the server timezone with our local timezone to make debugging easier. I would refer you to this link to change the timezone.
Recall a section of the AWS tutorial that addresses configuring our project wsgi.py file which looks like this.
import os
import sys
sys.path.append('/opt/bitnami/projects/tutorial')
os.environ.setdefault("PYTHON_EGG_CACHE", "/opt/bitnami/projects/tutorial/egg_cache")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tutorial.settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
If we want to run multiple projects on the same server, it's best to not set the default DJANGO_SETTINGS_MODULE
and PYTHON_EGG_CACHE
to point to a particular project. Doing so for multiple projects will lead to unexpected results.
Instead of this:
os.environ.setdefault("PYTHON_EGG_CACHE", "/opt/bitnami/projects/tutorial/egg_cache")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tutorial.settings")
do this:
os.environ["PYTHON_EGG_CACHE"] = "/opt/bitnami/projects/tutorial/egg_cache"
os.environ["DJANGO_SETTINGS_MODULE"] = "tutorial.settings"
We can extend the bitnami configuration found in /opt/bitnami/apache2/conf/bitnami/bitnami.conf, to include other projects. For example:
<VirtualHost _default_:80>
WSGIScriptAlias /project1 /opt/bitnami/projects/project1/project1/wsgi.py
<Directory /opt/bitnami/projects/project1>
AllowOverride all
Require all granted
Options FollowSymlinks
</Directory>
WSGIScriptAlias /project2 /opt/bitnami/projects/project2/project2/wsgi.py
<Directory /opt/bitnami/projects/project2>
AllowOverride all
Require all granted
Options FollowSymlinks
</Directory>
</VirtualHost>
Include "/opt/bitnami/apache/conf/bitnami/bitnami-ssl.conf"
Notice the last line that includes the bitnami-ssl.conf file. If we secure our production server with SSL
(a good recommendation), we will need to add the same multiple-project configuration in bitnami-ssl.conf under <VirtualHost _default_:443>
.
When we first created a Lightsail instance on AWS, we were given an IP address, for example, 192.0.2.143.
Note that this IP address is temporary and will change each time we reboot the instance. This would mean we have to update the ALLOWED_HOSTS
variable in our project settings.py file each time the IP address changes per reboot.
It is best to create a static IP address that we can use throughout the lifetime of the hosted Django apps.
For example, instead of this:
ALLOWED_HOSTS = ['192.0.2.143']
we can do this:
ALLOWED_HOSTS = 'awesomedjango.com'
Consult this other AWS tutorial to set up a static IP address.
Unlike the development Django server, the production Apache server does not automatically detect changes that we make in the Django configuration or application. We need to restart the Apache server for our changes to take effect. For example:
$ sudo /opt/bitnami/ctlscript.sh restart apache
When we disable debugging for our app by setting DEBUG=False
in our project settings.py file, we can no longer see Django's detailed traceback on the web page when an error occurs.
But we can find a shortened traceback in the log files generated by Apache. There are two log files of interest:
- /opt/bitnami/apache/logs/access_log
- /opt/bitnami/apache/logs/error_log
A sample error log file from Bitnami contains this:
bitnami@ip-xxx-xx-x-xx:~$ File "/opt/bitnami/python/lib/python
3.8/site-packages/asgiref/local.py", line 96, in __del__
NameError: name 'TypeError' is not defined
Exception ignored in: <function Local.__del__ at 0x7f1ecee3c550>
Traceback (most recent call last):
File "/opt/bitnami/python/lib/python3.8/site-packages/asgiref/
local.py", line 96, in __del__
NameError: name 'TypeError' is not defined
These log files can get really big, but we are mostly interested in the latest access and error messages. Dedicate a terminal to display only the last several lines. For example, type:
$ tail -f /opt/bitnami/apache/logs/error_log
and optionally run it in the background, by typing CtrlZ followed by bg
in the terminal.
Depending on your projects and apps, you may need to provide additional configuration for your production server. For additional helpful tips in deploying Django in a production environment, we can consult this documentation.
As you can see, deploying our Django app on a production server on the cloud such as AWS requires a lot of work. But don't let that deter you as once you have successfully overcome the hurdles, you will be proud of what you have accomplished and learn a lot that may earn you a ticket to a satisfying career. Happy Django!