Skip to content
This repository has been archived by the owner on Sep 19, 2024. It is now read-only.

Deployment Guide

Ashwin Shenoy edited this page Nov 24, 2019 · 13 revisions

AWS Deployment Guide

01. Server Configuration

A. Create AWS EC2 Instance & Connect to Server

  • Amazon EC2 Instance - 1GB RAM / Dedicated IP
  • OS: Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-1032-aws x86_64)
  • Download .pem key to access the server.
$ ssh -i "<FILE_NAME>.pem"  ubuntu@ec2-XXX-XXX-XXX-XXX.XX-XXXX-X.compute.amazonaws.com

B. Install Requirments for GNU/Linux

$ sudo apt-get update
$ sudo apt-get install binutils git libpq-dev python3-dev python-setuptools virtualenv python-virtualenv postgresql postgresql-contrib gdal-bin nginx supervisor memcached build-essential

C. Clone the Code

$ cd /var/www/
$ sudo git clone https://github.com/amfoss/cms.git

02. Database Configuration

A. Create Application User

$ sudo su - postgres
postgres@ip-xxx-xx-xx-xxx: ~ $ createuser --interactive -P
Enter name of role to add: amfoss
Enter password for new role:
Enter it again:
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n

B. Create Database

postgres@ip-xxx-xx-xx-xxx: ~ $ createdb --owner=amfoss cms
postgres@ip-xxx-xx-xx-xxx: ~ $ logout

C. Set Directory Permissions

$ sudo groupadd --system amfoss
$ sudo useradd --system --gid amfoss --shell /bin/bash --home /var/www/cms/ amfoss
$ chown amfoss /var/www/cms -R

03. Django Configuration

A. Create Virtual Environment

$ sudo su - amfoss
amfoss@ip-xxx-xx-xx-xxx:~$ cd /var/www/cms/
amfoss@ip-xxx-xx-xx-xxx: /var/www/cms $ virtualenv -p python3 .

B. Install Django Requirements

amfoss@ip-xxx-xx-xx-xxx: /var/www/cms $ source bin/activate
(cms) amfoss@ip-xxx-xx-xx-xxx: /var/www/cms $ pip install -r requirements.txt

C. Create server_settings.py

Add the Database configuration in server_settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'cms',
        'USER': 'amfoss',
        'PASSWORD': '<YOUR PASSWORD HERE>',
        'HOST': 'localhost',
        'PORT': '',  # Set to empty string for default.
    }
}

D. Make Database Migrations

(cms) amfoss@ip-xxx-xx-xx-xxx: /var/www/cms $ python manage.py migrate
(cms) amfoss@ip-xxx-xx-xx-xxx: /var/www/cms $ python manage.py makemigrations activity blog gsoc gallery pages members status
(cms) amfoss@ip-xxx-xx-xx-xxx: /var/www/cms $ python manage.py migrate

E. Collect Static Files

(cms) amfoss@ip-xxx-xx-xx-xxx: /var/www/cms $ python manage.py collectstatic

F. Test Virtual Environment

(cms) amfoss@ip-xxx-xx-xx-xxx: /var/www/cms $ python manage.py runserver 0.0.0.0:8000

04. Gunicorn Configuration

A. Configure gunicorn_start

(cms) amfoss@ip-xxx-xx-xx-xxx: /var/www/cms $ vim /var/www/cms/bin/gunicorn_start
#!/bin/bash
NAME="framework"                          
DJANGODIR=/var/www/cms                   
SOCKFILE=/var/www/cms/run/gunicorn.sock   
USER=amfoss                                         
GROUP=amfoss                                       
NUM_WORKERS=5                                 
DJANGO_SETTINGS_MODULE=framework.settings      
DJANGO_WSGI_MODULE=framework.wsgi               

echo "Starting $NAME as `whoami`"

# Activate the virtual environment
cd $DJANGODIR
source ./bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

# Create the run directory if it doesn't exist
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

# Start your Django Unicorn
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
exec ./bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --log-level=debug \
  --log-file=-

b. Give execution permission to gunicorn_start

(cms) amfoss@ip-xxx-xx-xx-xxx: /var/www/cms $ chmod +x /var/www/cms/bin/gunicorn_start

c. Run gunicorn_start

(cms) amfoss@ip-xxx-xx-xx-xxx: /var/www/cms $ /var/www/cms/bin/gunicorn_start

05. Superviser Configuration

A. Configure Superviser

$ vim /etc/supervisor/conf.d/amfoss.conf
[program:amfoss]
directory = /var/www/cms									 ; Directory of app
command = /var/www/cms/bin/gunicorn_start                    ; Command to start app
user =  amfoss                                               ; User to run as
stdout_logfile = /var/www/cms/logs/gunicorn_supervisor.log   ; Where to write log messages
redirect_stderr = true                                 		 ; Save stderr in the same log
environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8              ; Set UTF-8 as default encoding

[supervisord]
logfile=/var/www/cms/logs/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB        ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10           ; (num of main logfile rotation backups;default 10)
loglevel=info                ; (log level;default info; others: debug,warn,trace)
nodaemon=false               ; (start in foreground if true;default false)
minfds=1024                  ; (min. avail startup file descriptors;default 1024)
minprocs=200                 ; (min. avail process descriptors;default 200)

B. Create the file to store log

$ mkdir -p /var/www/cms/logs/
$ touch /var/www/cms/logs/gunicorn_supervisor.log

C. Start App

$ sudo supervisorctl reread
$ sudo supervisorctl update

06. Nginx Configuration

A. Configure Ngnix

$ sudo service nginx start
$ vim /etc/nginx/sites-available/amfoss
upstream app_server {
    server unix:/var/www/cms/run/gunicorn.sock fail_timeout=0;
}

server {
    listen 80;
    server_name beta.amfoss.in;
    client_max_body_size 4G;
    keepalive_timeout 5;

    add_header Strict-Transport-Security "max-age=15768000; includeSubdomains;";
    add_header X-Frame-Options DENY;

    access_log /var/www/cms/logs/nginx-access.log;
    error_log /var/www/cms/logs/nginx-error.log;

    location /static/ {
        alias   /var/www/cms/static/;
        expires 3d;
    }

    location /  {
        try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
        proxy_buffering off;
        proxy_connect_timeout 60;
        proxy_read_timeout 60;
        proxy_pass   http://app_server;
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /var/www/cms/templates/;
    }
}

Create Symbolic Link

$ cd /etc/nginx/sites-enabled
$ sudo ln -s ../sites-available/amfoss
$ sudo systemctl restart nginx

The amfoss CMS will be live on port 80 now.

Secure SSL with Let's Encrypt

To begin with, ensure that a public ip is set up on the server and that an A Record is created to point the domain to that IP.

Install the certbot client by following the instructions available at Certbot website.

After installation, run the following command to obtain a certificate.

$ sudo certbot --nginx -d api.amfoss.in

This will automatically obtain a certificate and modify the nginx configuration as well.

Bringing the website online

Open the nginx configuration file for the website, /etc/nginx/sites-available/amfoss and enable HTTP/2 support by modifying the following line:

listen 443 server ssl;

to the following

listen 443 server ssl http2;

Restart the nginx server with the command

$ sudo systemctl restart nginx

Check if the service is running in port 443 by running netstat

$ sudo netstat -anltp