Django is a powerful Python Web framework that motivates fast development and clean design. Although django provides an easy local development environment to test and run code locally, a strong and secure web server is needed for production purposes.
In this tutorial, we will explore how to install components required to serve(deploy) django applications on Ubuntu(18.04). We will be using mysql database instead of sqlite database which comes as default in django application. We will use ‘Python WSGI HTTP Server’ Gunicorn to interface with our application. After that we will set up Nginx to reverse proxy to Gunicorn.
Installing the Packages from Ubuntu Repo
$sudo apt update
$sudo apt install python3-pip python3-dev nginx mysql-server supervisor
This will install PIP (python package Manager), the Python development files, mysql-server, and Nginx web server.
Creating database and user in mysql
$ Sudo mysql
mysql>GRANT ALL PRIVILEGES ON *.* TO 'username'@'localhost' IDENTIFIED BY 'password';
This command grants the created user with all permissions. To maintain precise control of database , select command can be used
mysql>GRANT SELECT ON *.* TO 'username'@'localhost';
Now to access mysql server
$Mysql -u ‘username’ -p
mysql> create database ‘database_name’
Creating Python Virtual environment
One major advantage of using python is that its requirements can be easily managed inside a virtual environment that we create.
$ pip install --upgrade pip
$ pip install virtualenv
With our ‘virtualenv’ installed now we can create our virtual environment required to run our django application.
Setting up Virtual Environment to satisfy requirements
$mkdir ‘myprojectdir’
$cd myprojectdir
$virtualenv venv
$git clone ‘YOUR_GIT_REPO_URL’
It is assumed that your code is already on the git repository and will be cloned here. After cloning the repo we activate the environment we just created using
$source venv/bin/activate
Requirements of django application are usually freezed in some file while working on local development environment.So we install those requirements using
(venv)$pip install -r requirements.txt
We can write the requirements using
$ pip freeze > requirements.txt
Managing project Setting
(venv)$nano ~/myproject/mysite/settings.py
ALLOWED_HOSTS = [
'Your_server_IP or Domain',
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'db_name',
'USER': 'user_created_using_mysql',
'PASSWORD': 'user’s_password',
'HOST': 'localhost',
'PORT': '',
'CHARSET': 'utf8',
'COLLATION': 'utf8_general_ci',
}
}
As we have completed, configuring allowed hosts and a database, now we configure static files settings so that Nginx can later handle those things.
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
Finishing Project Set Up
We need to create the migrations files which contain information about database migration. Database migration will create the migration files and tables on mysql server which are initially empty.
(venv)$python manage.py makemigrations
(venv)$python manage.py migrate
Now, if we see our sql , there are empty tables. We can create superuser from terminal using
(venv)$python manage.py createsuperuser
To collect the static files in location configured earlier, we can use
(venv)python manage.py collectstatic
All the static files will be collected under the directory as configured above. It is static in our case.
Let’s check our UFW firewall to see if the port we are willing to use is allowed or not.
$sudo ufw status numbered
If the port we need is not listed enable it using
$sudo ufw allow 8000
Now, we can check whether our project is setting is okay with
(venv)$python manage.py runserver 0.0.0.0:8000
If you have not specified anything on your root url you will get django’s default template else your project’s landing page
Using Gunicorn to serve Project
Since our application is running okay with runserver, now it is time to run it with gunicorn. Gunicorn is a python WSGI(Web Server Gateway Interface). It acts as a gateway for sending requests to our django application. As gunicorn is used as pip module here, we have to activate our virtual environment to run gunicorn
(venv)$ gunicorn -b 0.0.0.0:8000 mysite.wsgi:application
Now we will write a bash script to run the application
Inside mysite directory
$mkdir bin
$cd mkdir
$nano gunicorn_start.sh
#!/bin/bash
NAME="mysite"
#path to your django application
DIR=/home/mysite
USER=yourusername
GROUP=yourgroup
WORKERS=3
BIND=0.0.0.0:8000
#bind to port 8000
DJANGO_SETTINGS_MODULE=mysite.settings
DJANGO_WSGI_MODULE=mysite.wsgi
LOG_LEVEL=error
cd $DIR
source /home/mysites/venv/bin/activate
#activating the virtual environment
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DIR:$PYTHONPATH
exec /home/mysite/venv/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
--name $NAME \
--workers $WORKERS \
--user=$USER \
--group=$GROUP \
--bind=$BIND \
--log-level=$LOG_LEVEL \
--log-file=-
You can find ‘path_to_your_virtual_env’ with the pwd command.
(directory where you can see venv with ls)
$pwd
This script will run our django project with gunicorn, Here we have specified fundamental parameters to run our application with gunicorn.Now we have to create the logs directory which contain our log files.
(inside bin directory)
$mkdir logs
$cd logs
$touch gunicorn_err.log
$touch gunicorn_out.log
$chmod +x gunicorn_start.sh
We can run this bash script with
$./gunicorn_start.sh
Again, our application can be seen in action in http://Your_Ip_address::8000
Connecting Supervisor with gunicorn
Now we will run this script with the supervisor.Supervisor is a service used to control and operate processes in a robust way. Now, Remember earlier we have installed a supervisor. If not you can get it by
$ sudo apt-get install supervisor
#if not installed already
Supervisor runs every .conf file inside conf.d directory. We will create a new .conf to run our django application
$nano /etc/supervisor/conf.d/mysite.conf
[program:my_site]
#path_to_your_django_application
directory=/home/mysite/
command=/home/bigsafarhotel/bin/gunicorn_start.sh
#path to your bash script
autostart=true
autorestart=true
#path_to_your_log_files
stderr_logfile=/home/mysite/logs/gunicorn_err.log
stdout_logfile=/home/mysite/logs/gunicorn_out.log
Save and close the file.
Now, supervisor needs to know reread the changes, it can be done by
$sudo supervisorctl reread
$sudo supervisorctl update
$sudo supervisorctl status
Supervisor can run multiple processes.Error and out logs can be seen in the logs files inside our bin directory.
Configuring Nginx
Nginx is one of the most popular web servers. Integration between the nginx and gunicorn is smooth. We will set nginx to send traffic to gunicorn. To do so we will configure nginx as
$sudo nano /etc/nginx/sites-available/mysite.conf
server
{
listen 80;
server_name ‘example.com’ or ‘Your_server_ip’;
index index.php index.html index.htm default.php default.htm default.html;
root /home/mysite;
#path_to_your_directory
# Forbidden files or directories
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
{
return 404;
}
# Directory verification related settings for one-click application for SSL certificate
location ~ \.well-known{
allow all;
}
location /static {
autoindex on;
alias /home/mysite/static ;
}
location /media {
autoindex on;
alias /home/mysite/media ;
}
location /
{
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
#Persistent connection related configuration
add_header X-Cache $upstream_cache_status;
#Set Nginx Cache
add_header Cache-Control no-cache;
expires 12h;
}
access_log /home/mysite/logs/mysite.log;
error_log /home/mysite/logs/mysite.error.log;
}
Here nginx is listening on port 80 and sending traffic to a django application running on port 8000 on our server. Nginx is very useful in serving static files. We have configured the static files directory in the above setting. Similarly, media files can be served.
Now create a soft link this configuration file to sites-enabled using
$ ln -s /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/mysite.conf
To check whether your nginx configuration okay run
$nginx -t
Now restart nginx to reflect changes
$service nginx restart
Now, you will be able to access your application on your server’s IP. The browser uses port 80 as its default port. Nginx is listening on this port so your application is accessible in your Ip.