Food Online Deployment

Django Cover

Written by Rathan Kumar

Senior Software Developer | Django Instructor

What is Linode?

Linode is a server hosting company.(Online Deployment)
They offer virtual private server (VPS) at budget-friendly cost which is good if you are just trying to experiment with setting up your own server, installing applications on the server, running your own website, hosting a small to medium sized web application. As your app/website grow, you can expand your plans which might make it ideal for startups, freelancers or students.

Creating Linode account and setting up server

  • Create an account with Linode using https://rathank.com/linode/
    When you sign up to Linode using my referral link, you’ll receive a $100, 60-day credit once you add a valid payment method to your new account. Using the free credits you can setup your server and host your website on Linode, you will not be charged until 60 days or $100 spends. If you keep your website up and running for over 60 days, you will be charged $5 + tax ($5 Nanode as shown in the course)
  • Create Linode with desired plan and configuration
  • Check video to see how to generate SSH Key
  • Purchase your desired domain name. GoDaddy, Namecheap (recommended)
  • From the Linode sidebar, select Domains to add the domain
  • Add the NS Records to respective registrars. GoDaddy, Namecheap
  • Once we have the server up and ready, we will get the IP address of this server, and we will login to our server using SSH
    • ssh root@SERVER_IP_ADDRESS
  • Once logged in, let’s update all the packages that are currently installed in our server.
    • sudo apt update && apt upgrade -y
    • sudo apt install python3-pip python3-dev ufw nginx
  • Create a user on this server and give him a sudo permission. Remaining steps we will be performing as a user, not as root – for security purposes.
    • adduser foodonline
    • adduser foodonline sudo
    • exit
  • Now ssh in to the server as foodonline user
    • ssh foodonline@SERVER_IP_ADDRES
    • sudo ufw allow ssh
    • sudo ufw enable
    • sudo apt update
    • sudo pip3 install virtualenv

Possible Deployment Issues

To avoid deployment errors, we will take following actions:

  • Add allowed host, release media folder, run collectstatic and create requirements.txt from the local project.
    • ALLOWED_HOSTS = ['SERVER_IP_ADDRESS', 'localhost', '127.0.0.1']
    • Remove 'media' from .gitignore file
    • python manage.py collectstatic
    • pip freeze > requirements.txt
  • Remove GDAL from requirements.txt
  • Replace psycopg2 package with psycopg2-binary
  • Install backports.zoneinfo only if the server python version is less than 3.9
  • backports.zoneinfo==0.2.1;python_version<"3.9"
  • Add gunicorn to requirements.txt

Setting up Git to push the code from local server to remote server

Remote server

  • While you are logged in to the server via SSH, create a project directory as foodonline-dir inside /home/foodonline/ folder
    • cd /home/foodonline/
    • mkdir foodonline-dir
    • cd foodonline-dir
    • mkdir site.git
    • cd site.git
    • git init --bare
  • --bare means that our folder will have no source files, just the version control.
  • Run ls to see the files and folders inside the current directory, in our case we are inside site.git, you will see ‘hooks‘ folder
    • ls
  • Let’s get into ‘hooks’ folder
    • cd hooks
  • Now, create the file ‘post-receive’ by typing:
    • sudo nano post-receive
  • Type below code inside post-receive file
#!/bin/sh
git --work-tree=/home/foodonline/foodonline-dir --git-dir=/home/foodonline/foodonline-dir/site.git checkout -f main
  • Save post-receive file by pressing CTRL + X, Y, Enter
  • In order to execute the file, we need to set the proper permissions using:
    • sudo chmod +x post-receive

Local Machine

In FoodOnline project, we have already initialized git on the root folder of our project. Now, we need to configure the remote path of our repository. Tell Git to add a remote called ‘live’:

git remote add live ssh://foodonline@SERVER_IP_ADDRESS/home/foodonline/foodonline-dir/site.git

Now, whenever we make changes in the local project and want to push the changes to live server, we simply run this command

git add -A
git commit -m "new changes to go live"
git push live main

Now check the remote directory, our project is pushed to the server. That’s all, we have set up Git to push the code from local machine to remote server.

Install & Configure PostgreSQL

Install

While you are logged into the server, run following commands to install, start, enable and see the status of postgresql database:
sudo apt-get install postgresql postgresql-contrib
sudo systemctl start postgresql.service
sudo systemctl enable postgresql.service
sudo systemctl status postgresql.service

Configure

  • Set new password for default postgres user
    • sudo passwd postgres
    • sudo su - postgres
  • If you want to reset postgres user’s password, run the following command
    • psql -d postgres -c "ALTER USER postgres WITH PASSWORD 'NEW PASSWORD';"
  • Login to postgres shell
    • psql postgres
  • Create new database
    • CREATE DATABASE foodonline_db;
    • exit
    • exit

Setup Virtual Environment, configure .env file and run the server

In the foodonline-dir folder, create virtual environment and activate it
virtualenv env
source env/bin/activate

Create .env file and provide all the required secret information
sudo nano .env

Optionally, refresh the virtual environement by running deactivate and source env/bin/activate

Install the packages from requirements.txt file
pip install -r requirements.txt

Run makemigrations and migrate commands
python manage.py migrate

You will probably get GDAL and PostGis error as they are necessary to run our project

Install GDAL library and PostGis extension on live server

Run the GDAL path configuration in settings.py only when the site is on windows local server.

if DEBUG == True:
    # GDAL PATH CONFIGURATION

Install GDAL Library

https://mothergeo-py.readthedocs.io/en/latest/development/how-to/gdal-ubuntu-pkg.html

Install PostGis

https://computingforgeeks.com/how-to-install-postgis-on-ubuntu-linux/

Allow port 8000
sudo ufw allow 8000

Check status of ufw
sudo ufw status

Run the server
python manage.py runserver 0.0.0.0:8000

Backup data from local machine and restore in to live database

Local machine

python manage.py dumpdata > backup.json
Comment out post_save signal post_save_create_profile_receiver() function to prevent creating a UserProfile which essentially throws “IntegrityError – duplicate key value violates unique constraint” error
git add -A
git commit -m "database backup"
git push live main

Remote server

python manage.py shell

from django.contrib.contenttypes.models import ContentType
ContentType.objects.all().delete()
quit()
python manage.py loaddata backup.json

Once the loaddata is successful, go to local project and uncomment post_save_create_profile_receiver() function and then push the code to live.

Configuring Gunicorn

Install Gunicorn on our server
sudo apt install gunicorn

Tell gunicorn to bind to our Django application and start running
gunicorn --bind 0.0.0.0:8000 foodOnline_main.wsgi

Test the link and make sure the site is working

exit

Go to this location and paste below code: sudo nano /etc/systemd/system/gunicorn.socket

[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target

Location: sudo nano /etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=foodonline
Group=www-data
WorkingDirectory=/home/foodonline/foodonline-dir
ExecStart=/home/foodonline/foodonline-dir/env/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          foodOnline_main.wsgi:application

[Install]
WantedBy=multi-user.target

Restart and enable Gunicorn socket
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket

Configuring Nginx as a reverse proxy

Location: sudo nano /etc/nginx/sites-available/foodonline

server {
    listen 80;
    server_name djangofoodonline.com www.djangofoodonline.com;

    location ~ ^/.well-known {
        root /home/foodonline/foodonline-dir;
        allow all;
    }
    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/foodonline/foodonline-dir;
    }
    location /media/ {
        root /home/foodonline/foodonline-dir;
    }
    location / {
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}

sudo ln -s /etc/nginx/sites-available/foodonline /etc/nginx/sites-enabled/
sudo systemctl restart nginx

Open port 80 and close 8000
sudo ufw allow 80
sudo ufw allow 'Nginx Full'
sudo ufw allow 586
sudo ufw deny 8000

Go to sites-enabled directory and delete the default site
cd /etc/nginx/sites-enabled/
ls
sudo rm default

Install SSL

sudo apt install certbot python3-certbot-nginx
Verify certbot installation by running which certbot
sudo certbot --nginx -d djangofoodonline.com

Get In Touch with Me!

Book a Call with Rathan - Get Personalized Guidance

Whether you’re just starting with Python, Django or aiming to elevate your skills to the next level, having a mentor can make a world of difference.

You May Also Like…

The AI Tsunami is Here…

The AI Tsunami is Here…

Remember when computers were first invented? People freaked out, thinking their jobs were gone because computers could...