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_ADDRESsudo 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 withpsycopg2-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‘ folderls
- 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 itvirtualenv env
source env/bin/activate
Create .env file and provide all the required secret informationsudo nano .env
Optionally, refresh the virtual environement by running deactivate
and source env/bin/activate
Install the packages from requirements.txt filepip install -r requirements.txt
Run makemigrations and migrate commandspython 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 8000sudo ufw allow 8000
Check status of ufwsudo ufw status
Run the serverpython 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” errorgit 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 serversudo apt install gunicorn
Tell gunicorn to bind to our Django application and start runninggunicorn --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 socketsudo 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 8000sudo 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 sitecd /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