Single Blog Page Content

Single Blog Page Content

<!-- Page content-->
<div class="container mt-5">
    <div class="row">
        <div class="col-lg-8">
            <!-- Post content-->
            <article>
                <!-- Post header-->
                <header class="mb-4">
                    <!-- Post title-->
                    <h1 class="fw-bolder mb-1">Welcome to Blog Post!</h1>
                    <!-- Post meta content-->
                    <div class="text-muted fst-italic mb-2">Posted on January 1, 2023 by admin</div>
                    <!-- Post category-->
                    <a class="badge bg-primary text-decoration-none text-light" href="#!">Web Design</a>
                </header>
                <!-- Preview image figure-->
                <figure class="mb-4"><img class="img-fluid rounded" src="https://dummyimage.com/900x400/ced4da/6c757d.jpg" alt="..." /></figure>
                <!-- Post content-->
                <section class="mb-5">
                    <p class="fs-5 mb-4">Science is an enterprise that should be cherished as an activity of the free human mind. Because it transforms who we are, how we live, and it gives us an understanding of our place in the universe.</p>
                    </section>
            </article>
        </div>
        <!-- Side widgets-->
        <div class="col-lg-4">
            <!-- Search widget-->
            <div class="card mb-4">
                <div class="card-header">Search</div>
                <div class="card-body">
                    <div class="input-group">
                        <input class="form-control" type="text" placeholder="Enter search term..." aria-label="Enter search term..." aria-describedby="button-search" />
                        <button class="btn btn-primary" id="button-search" type="button">Go!</button>
                    </div>
                </div>
            </div>
            <!-- Categories widget-->
            <div class="card mb-4 p-3">
                <h4 class="font-italic">Categories</h4>
                <div class="card-body">
                    <div class="row">
                        <div class="col-sm-6">
                            <ul class="list-unstyled mb-0">
                                <li><a href="#!">Web Design</a></li>
                                <li><a href="#!">HTML</a></li>
                                <li><a href="#!">Freebies</a></li>
                            </ul>
                        </div>
                        <div class="col-sm-6">
                            <ul class="list-unstyled mb-0">
                                <li><a href="#!">JavaScript</a></li>
                                <li><a href="#!">CSS</a></li>
                                <li><a href="#!">Tutorials</a></li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
            <!-- Side widget-->
            <div class="card mb-4 p-3">
                <h4 class="font-italic">Follow Us</h4>
                <ol class="list-unstyled">
                    <li><a href="#">GitHub</a></li>
                    <li><a href="#">LinkedIn</a></li>
                </ol>
            </div>
        </div>
    </div>
</div>

Food Online Deployment

Food Online Deployment

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

Food Online Deployment

FoodOnline Sample Email Template

FoodOnline Sample Email Template

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml" lang="en">

<head><link rel="stylesheet" type="text/css" hs-webfonts="true" href="https://fonts.googleapis.com/css?family=Lato|Lato:i,b,bi">
    <meta property="og:title" content="Email template">  
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">    
    <style type="text/css">
      #email {
        margin: auto;
        width: 600px;
        background-color: white;
      }  
      .activate-btn{
        font: inherit;
        background-color: #C33332;
        border: none;
        padding: 10px;
        text-transform: uppercase;
        letter-spacing: 2px;
        font-weight: 900;
        border-radius: 5px; 
        text-decoration: none;
      }      
    </style>    
  </head>    
<body bgcolor="#F5F8FA" style="width: 100%; margin: auto 0; padding:0; font-family:Lato, sans-serif; font-size:16px; color:#33475B; word-break:break-word">
  
<div id="email">
  <table role="presentation" width="100%">
    <tr>
    <td  align="center" style="color: white;">
     <img alt="Logo" src="https://rathank.com/foodonline/logo/logo.png" width="400px" align="middle">
      </td>
  </table>

  <table bgcolor="#EAF0F6" width="100%" role="presentation" border="0" cellpadding="0" cellspacing="10px" style="padding: 30px 30px 60px 60px;">
    <tr>
      <td>
        <h2 style="text-align: center;">Activate Your Account</h2>
        <p style="text-align: center;">Please verify your email address to activate your account.</p>
        <div style="text-align: center;">
          <a href="" class="activate-btn" style="color: #fff;">Activate Now</a>
        </div>
      </td> 
    </tr>
  </table>

  <table role="presentation" bgcolor="#C33332" width="100%">
      <tr>
        <td align="center" style="padding: 15px 15px; color: #fff;">
          <p>© 2022 FoodOnline Marketplace, All Rights Reserved.</p>
          <a href="#" style="color:#fff;">Visit Website</a>      
        </td>
      </tr>
  </table> 
</div>
</body>
</html>

Food Online Deployment

Install PostGIS and GDAL

Install PostGIS

This post considers that you have already installed PostgreSQL & pgAdmin on your windows computer. So, you should already have the Application Stack Builder software on your system. Application Stack Builder is actually used to download and install add-ons to our Postgres databases.

Goto Application Stack Builder and install PostGIS extension.

install postgis rathank.com

Go to Pgadmin 4 and create a PostGIS extension for your database

Click on the Query tool and run the below query

CREATE EXTENSION postgis;

Install GDAL on Windows

Download GDAL wheel file that is supported for your platform from here

Cut the wheel file and paste it inside your project’s root directory. Make sure your virtual environment is activated.

Install the wheel using command  pip install name_of_the_file

You will see osgeo folder has been created in the location ‘..envLibsite-packages’ .

Go to osgeo folder and copy the path of your gdalxxx.dll file and add it to the settings.py file as gdal library path.

os.environ['PATH'] = os.path.join(BASE_DIR, 'venvLibsite-packagesosgeo') + ';' + os.environ['PATH']
os.environ['PROJ_LIB'] = os.path.join(BASE_DIR, 'venvLibsite-packagesosgeodataproj') + ';' + os.environ['PATH']
GDAL_LIBRARY_PATH = os.path.join(BASE_DIR, 'venvLibsite-packagesosgeogdal303.dll')

Install GDAL on Mac OS

Install GDAL on your system

brew install gdal

To be sure that GDAL is installed in your system, just type:

gdal-config --version

Now we have GDAL installed, we proceed to setup a GDAL Python binding. Just upgrade your version of pip before to install the library in python environment.

pip3 install — upgrade pip

Once updated, just type:

pip3 install gdal==x.x.x

Replace x.x.x with the gdal version, it must be the same as the one obtained in the step above using gdal-config. To avoid conflicts or any further issues, it’s important to install and use the exact versions that any component will require.
Sometimes you could experiment ModuleNotFoundError trying to install the GDAL python binding, you can solve this issue by installing the needed modules. The most required module is Numpy, and you can install it just by typing:

pip3 install numpy # only if you get Numpy ModuleNotFoundError 

Check out your GDAL python binding

python3 -c "from osgeo import gdal"

You won’t see anything if everything is well installed.