The Internet of Things (IoT) has revolutionized the way we collect, transmit, and process data from a wide range of applications. LoRa (Long-Range) technology has emerged as a popular choice for building low-power, long-range wireless IoT networks.
ChirpStack is one of the powerful open-source LoRaWAN software that provides the infrastructure for managing, collecting LoRa IoT devices’ data from the gateway and sending it to any client’s desired visualization software.
RENU is currently one of the providers of this service in Uganda, with over 6 LoRAWAN gateways, and more than 12 sensors connected in different regions.
Deploying a Django application is a crucial step in taking your web project from development to production. While Django’s built-in development server is great for testing and debugging, it’s not suitable for handling the demands of a live production environment. To ensure your Django application can handle real-world traffic and serve as a reliable, performant, and secure web application, you’ll need to set up a production-ready server stack.
In this guide, we’ll walk you through the process of deploying a Django application on an Ubuntu server using Gunicorn as the application server, Apache as the reverse proxy server, and MySQL as the database management system. This stack is a popular choice for deploying Django applications due to its stability, scalability, and security features.
Setting up the software
1. Update Ubuntu software repository
# sudo apt update
2. Install
i. apache2 – Serve our website
# sudo apt install apache2
ii. mysql-server and libmysqlclient-dev – For database
v. virtualenv – Virtual environment for our django application
# sudo apt install virtualenv
Clone your django repo
$ git clone <link to the repo>
$ cd <project folder>
$ git checkout <active branch>
Installing Python libraries
1. Create virtual env (e.g env)
$ python3 -m venv env
2. Activate virtualenv
$ source env/bin/activate
3. Install project dependencies and packages
$ pip install -r requirements.txt
4. Install mysql client for python
$ pip install mysqlclient
5. Install gunicorn to interact with our python code
$ pip install gunicorn
6. Install white noise to serve our static files
$ pip install whitenoise
Setting up the firewall
We’ll disable access to the server on all ports except 8000 and OpenSSH for now. Later on, we’ll remove this and give access to all the ports that Apache needs.
2. Create a database and a user for the application.
mysql> CREATE DATABASE '<app database name>' CHARACTER SET 'utf8';
mysql> CREATE USER '<app user name>'@'localhost' IDENTIFIED BY '<app user password>';
mysql> GRANT ALL PRIVILEGES ON <app database name>.* TO '<app user name>'@'localhost';
mysql> quit;
Setting up the Django project
In your project folder, modify the settings.py file
1. Include the newly created database access configurations.
2. Include the IP address of your server and domain name (if any) in the allowed hosts.
3. Include CORS_ALLOWED_ORIGINS, CSRF_TRUSTED_ORIGINS, and CORS_ORIGIN_WHITELIST if you have a domain name set already.
4. In your installed apps, include ‘whitenoise.runserver_nostatic’ just above ‘django.contrib.staticfiles’.
5. In your MIDDLEWARE, include ‘whitenoise.middleware.WhiteNoiseMiddleware’ just below, ‘django.middleware.security.SecurityMiddleware’.
DEBUG = False # We have turned DeBUG to False since we’re in production
ALLOWED_HOSTS = ['127.0.0.1', 'domain name', 'ip-address'] # ip address and domain name
INSTALLED_APPS = [
'whitenoise.runserver_nostatic',
'django.contrib.staticfiles', ]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
"whitenoise.middleware.WhiteNoiseMiddleware", ]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'OPTIONS': {
'sql_mode': 'traditional',
},
'NAME': '<app database name>',
'USER': '<app username>',
'PASSWORD': '<app user password>',
'HOST': 'localhost',
'PORT': '3306',
}
}
CORS_ALLOWED_ORIGINS = [
"http://localhost:8000",
'domain name' ]
CSRF_TRUSTED_ORIGINS = [
'http://localhost:8000',
'domain name' ]
CORS_ORIGIN_WHITELIST = [
'http://localhost:8000',
'domain name' ]
STATIC_URL = '/static/'
STATIC_ROOT=os.path.join(BASE_DIR, 'static/')
MEDIA_URL='/media/'
MEDIA_ROOT=os.path.join(BASE_DIR, 'media/')
6. Make database migrations to create all the required tables in the new database and collect all static files to a static folder under the django_project directory.
2. Test the app in your browser on the server ip while mapping the port <server ip>:8000 e.g http://137.63.128.239:8000 . (Notice that you can access static files because we set up whotenoise.)
3. Kill gunicorn and exit the virtual environment.
4. Lets daemonize the gunicorn
i. Open a new gunicorn.service file using any text editor your comfortable with.
#vim /etc/systemd/system/gunicorn.service
[Unit]
Description=Gunicorn instance to serve the django app
After=network.target
[Service]
# Replace with your system user
User=root
# Replace with your system group
Group=root
WorkingDirectory=/home/<user>/<project folder>/
#ExecStart=path to gunicorn_config.py your_app_module.wsgi:application
ExecStart=/home/<user>/<project folder>/<virtual env>/bin/gunicorn_start.sh
[Install]
WantedBy=multi-user.target
#This is the systemd file, which can be called: gunicorn.service
5. Create a script to start the server
i. Create gunicorn_start.sh in your virtualenv bin directory
ii. Edit the file as follows:
vim /home/<user>/<project folder>/<virtualenv>/bin/gunicorn_start.sh
#!/bin/bash
#This is the Gunicorn script used to automatically launch the application through Gunicorn
NAME="django-application"
#path to the folder containing the manage.py file
DIR=/home/<user>/<project folder>
# Replace with your system user
USER=root
# Replace with your system group
GROUP=root
WORKERS=3
#bind to port 8000
BIND=<server ip>:8000
# Put your project name
DJANGO_SETTINGS_MODULE=<Project name>.settings
DJANGO_WSGI_MODULE=<Project name>.wsgi
LOG_LEVEL=error
cd $DIR
#activating the virtual environment
source /home/<user>/<project folder>/<virtualenv>/bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DIR:$PYTHONPATH
exec gunicorn ${DJANGO_WSGI_MODULE}:application \
--name $NAME \
--workers $WORKERS \
--user=$USER \
--group=$GROUP \
--bind=$BIND \
--log-level=$LOG_LEVEL \
--log-file=-
If everything works fine, you should be able to access your Django application on <server ip> or <domain name (if you registered one)>
Setting up SSLs for our domain
1. To set up SSL/TLS certificates for a domain (e.g., uc23.devops.renu.ac.ug), We’re going to use Certbot (a tool for obtaining and renewing Let’s Encrypt SSL certificates)
Creating a Pipeline (CI/CD) on GitLab, using Docker on an Ubuntu Server.
Introduction:
Continuous Integration (CI):
Continuous Integration is the practice of frequently and automatically integrating code changes from multiple contributors into a shared repository. Developers regularly submit their code changes, which are then automatically built, tested, and integrated into the main codebase. This helps identify and address integration issues early in the development process.
Continuous Delivery (CD):
Continuous Delivery is an extension of CI and focuses on automating the delivery of software to various environments, such as testing, staging, and production. The goal is to ensure that the software is always in a deployable state, allowing for reliable and efficient releases. CD includes automation of testing, deployment, and monitoring, enabling rapid and consistent software delivery.
Docker:
Docker is a technology that packages applications and all their necessary components into self-contained containers, making it easy to develop, test, and run applications consistently across different environments. It simplifies application management and promotes consistency and portability.