/django-docker-nginx-letsencrypt

Create a dockerized django application with nginx and ssl certificate. This project covers how to deploy a django application with docker nginx letsencrypt (ssl certificate) By following this repo, you will be able to publish your django https app in any vm

Primary LanguagePython

django-docker-nginx-letsencrypt

Purpose: Create a dockerized django application with nginx and ssl certificate. This project covers how to deploy a django application with docker nginx letsencrypt (ssl certificate) By following this repo, you will be able to publish your django app in any vm, and you will be able to create a http-secured app

πŸ’» Techs used

  • Django
  • Celery
  • Postgresql
  • Redis
  • Elasticsearch
  • Nginx
  • Certbot

πŸ“‚ Directory structure

---- docker ( Contains Docker Related Config Files )
     --- certbot
         --- Dockerfile
         --- certify.sh
     --- nginx
         --- Dockerfile
         --- nginx.conf ( Contains Both HTTPS and HTTP Config )
         --- nginx_http.conf ( Contains HTTP Config only )
         --- run.sh
     --- worker
         --- ...
         
---- blogs_api ( Django Application | Celery Application )
     --- ...
     --- apps
     --- blogs_api
         --- ...
         --- settings.py

Explanations πŸ“–

In docker/nginx directory there are two files

  • nginx.conf
  • nginx_http.conf

nginx_http.conf will be used first to setup a http nginx server, which is important to get the ssl certificate for the domain. Later after getting ssl certificate nginx.conf will be used which will have https server

πŸŽ‰ Deploy this app in any vm instances

  • What you will need?
  • amazon ec2, Google Compute Engine, DigitalOcean Instance, Azure VM

πŸͺœ Steps

SSH Into your VM

SSH into your vm using ssh tool, you can use third party ssh tool like putty

Download and install Docker πŸ‹

( Example for Ubuntu/Debian Based Systems )

# App Environment 
sudo su

mkdir /home/app -p

cd /home/app

apt-get update

Remove old versions of docker and install latest ( Steps taken from official docker page, View More)

# Uninstall Old Versions
apt-get remove docker docker-engine docker.io containerd runc
apt-get install -y \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

Add Docker Repo

sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Update apt and install docker

# Install docker engine
apt-get update -y
# Install docker
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Install docker-compose package
apt-get install -y docker-compose-plugin docker-compose

For other os visit docker official documentation

Setup Github repo 😺

To get our codebase from github repo we need to generate a ssh deploy key and put the deploy key public key to Github repo deploy key section

ssh-keygen -t ed25519 -C "GitHub Deploy Key"

Cat the public and copy and paste it in the github deploy keys section

Github Repo > Settings > Deploy Keys

cat ~/.ssh/id_ed25519.pub

The following command will cat the public key

ssh-ed25519 AAAAC3NzaD23ZDI1NTE5ABSFGKoH0ASXx2ua/++wZgCUSDGsg6VmPc/ys7vNSDGsd2D6 GitHub Deploy Key

Setting deploy key

alt Image

Put public key ssh-ed25519 AAAAC3NzaD23ZDI1NTE5ABSFGKoH0ASXx2ua/++wZgCUSDGsg6VmPc/ys7vNSDGsd2D6 GitHub Deploy Key In the Key section

alt Image

Pull code from github repo

git init

Add your repo origin git url

git remote add origin <OriginURL>

Here for example I am pulling from main

git pull origin main

Setup environment variable πŸ’²

Create .env file where your environment variables will be stored

nano .env
DOMAIN=<DOMAIN>
ACME_DEFAULT_EMAIL=<EMAIL>
ENV=PROD
SECRET_KEY=<SECRET_KEY>
ENCRYPTION_KEY=<ENCRYPTION_KEY>
POSTGRES_DB=POSTGRES_DB
POSTGRES_USER=POSTGRES_USER
POSTGRES_PASSWORD=POSTGRES_PASSWORD
DATABASE_URL=postgresql://<POSTGRES_USER>:<POSTGRES_PASSWORD>@db:5432/<POSTGRES_DB>
REDIS_URL=redis://redis:6379/1
CELERY_BROKER_URL=redis://redis:6379/0
AWS_STORAGE_BUCKET_NAME=<AWS_STORAGE_BUCKET_NAME>
AWS_S3_REGION_NAME=<AWS_S3_REGION_NAME>
AWS_ACCESS_KEY_ID=<AWS_ACCESS_KEY_ID>
AWS_SECRET_ACCESS_KEY=AWS_SECRET_ACCESS_KEY
AWS_SECRET_ACCESS_KEY_ID=AWS_SECRET_ACCESS_KEY_ID
AWS_S3_ENDPOINT_URL=AWS_S3_ENDPOINT_URL
AWS_LOCATION=static
DEBUG=False
EMAIL_HOST=EMAIL_HOST
EMAIL_HOST_USER=EMAIL_HOST_USER
EMAIL_HOST_PASSWORD=EMAIL_HOST_PASSWORD
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
DEFAULT_FROM_EMAIL=DEFAULT_FROM_EMAIL
ACCESS_TOKEN_LIFETIME=ACCESS_TOKEN_LIFETIME
REFRESH_TOKEN_LIFETIME=REFRESH_TOKEN_LIFETIME
ELASTICSEARCH_HOST=http://elasticsearch:9200

Configure and run docker πŸ‹

Build docker containers

docker-compose -f docker-compose.prod.yaml build 

Run certbot command to get initial ssl certificate

docker-compose -f docker-compose.prod.yaml run -rm certbot /opt/certify.sh

Restart containers

docker-compose -f docker-compose.prod.yaml down
docker-compose -f docker-compose.prod.yaml up -d

Crontab to renew ssl certificate πŸ“œ

The actions mentioned above will produce the first certificate for our project. The certificate will only be valid for three months, therefore you must run the renew command earlier than that.

Create a bash script

nano rewnew.sh

This bash script will renew certificate

#!/bin/sh
set -e

cd /home/app/

/usr/local/bin/docker-compose -f docker-compose.prod.yaml run --rm certbot certbot renew

Give execution permission

chmod +x renew.sh

Open crontab

crontab -e

Add the following in the crontab

0 0 * * 6 sh /home/app/renew.sh

Automated deploy using github actions 🎬

Create an SSH Key

ssh-keygen -t rsa -b 4096

Copy content of the key file

cat /.ssh/id_rsa

Add public key to the authorized key file

cat /.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

Create a bash script to deploy

nano deploy.sh

This bash script will renew certificate

#!/bin/sh
set -e

cd /home/app/

git stash

git pull origin main --force

/usr/local/bin/docker-compose -f docker-compose.prod.yaml up --build -d

Give execution permission

chmod +x deploy.sh

Setup Github Actions

  • Go to β€œSettings > Secrets > Actions”

alt Image

Open the Actions tab and set secrets

alt Image

Create the following secrets: SSH_PRIVATE_KEY: content of the private key file

SSH_USER: user to access the server (root)

SSH_HOST: hostname/ip-address of your server

WORK_DIR: path to the directory containing the repository ( For this /home/app)

MAIN_BRANCH: name of the main branch (mostly main)

alt Image

In your repo create

".github" > "workflows" > "deploy.yaml"

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  run_pull:
    name: run pull
    runs-on: ubuntu-latest

    steps:
    - name: install ssh keys
      # check this thread to understand why its needed:
      # https://stackoverflow.com/a/70447517
      run: |
        install -m 600 -D /dev/null ~/.ssh/id_rsa
        echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
        ssh-keyscan -H ${{ secrets.SSH_HOST }} > ~/.ssh/known_hosts
    - name: connect and pull
      run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd ${{ secrets.WORK_DIR }} && git checkout ${{ secrets.MAIN_BRANCH }} && /home/app/deploy.sh"
    - name: cleanup
      run: rm -rf ~/.ssh