I assume that you are going to work with:

  • Ubuntu
  • Django
  • Redis
  • Iptables
  • Fail2ban
  • Postgres
  • Git-Auto-Deploy
  • Nginx & Uwsgi

Server Initial Setup

Create Users:

adduser USER1
adduser USER2

Grant root privileges:

visudo

Put this line:

USER1 ALL=(ALL:ALL) ALL
USER2 ALL=(ALL:ALL) ALL

Disable root login:

nano /etc/ssh/sshd_config

Change the line to:

PermitRootLogin no

Change SSH port:

nano /etc/ssh/sshd_config

Find this line:

Port 22

Change 22 to some custom port and then restart the service:

service ssh restart

Test everything:

ssh USER@HOSTNAME -p PORTNUMBER
sudo su

Django and Python Installation & Configuration

Upgrade server:

apt-get update
apt-get upgrade

Install required tools:

apt-get install git htop unzip

Install required python and DB packages:

apt-get install python3 python3-pip python-setuptools python3-setuptools python3-dev build-essential
apt-get install postgresql postgresql-contrib python-psycopg2 libpq-dev

Link pip to pip3:

ln -s /usr/bin/pip3 /usr/bin/pip
pip install --upgrade pip

Add ssh-keys and clone repository

Create key for git-auto-deploy service. Then add it to your gitlab project (not your account).

ssh-keygen -t rsa
cat /etc/git-auto-deploy/.ssh/id_rsa.pub

Clone:

git clone [email protected]:ACCOUNT/REPOSITORY

Install Django and it's packages

Install django and it’s packages:

pip3 install django
pip3 install -r requirements.txt

Configure django after installation by opening this file:

nano /usr/local/lib/python3.5/dist-packages/actstream/urls.py

For some reason remove three “patterns” occurrence in this file.

Update settings in django settings.py:

nano /home/www/PROJECT/PROJECT/settings.py

Specifically these sections:

      'USER': 'DBUSER',
      'PASSWORD': 'DBPASSWORD',
      'HOST': 'HOSTNAME',
      'PORT': '5432',
      HOST_URL = 'http://YOURWEBSITE/'

Database

Open postgres console:

su - postgres
createuser DBUSER
createdb DBNAME
psql
\password DBPASSWORD
GRANT ALL PRIVILEGES ON DATABASE DBNAME TO DBUSER;
\q

Migration

rm -rf Core/migrations/ APP1/migrations/ APP2/migrations/
python3 manage.py makemigrations app1
python3 manage.py makemigrations app2
python3 manage.py makemigrations
python3 manage.py migrate

Create superuser:

python3 manage.py createsuperuser
python3 manage.py collectstatic

WSGI

sudo pip3 install uwsgi

Test

Run and Test Django:

python3 manage.py runserver 0.0.0.0:80

Run and Test uwsgi:

uwsgi --http :80 --chdir /home/www/PROJECT/ -w PROJECT.wsgi

WSGI Configuration

mkdir /etc/uwsgi/
mkdir /etc/uwsgi/sites
nano /etc/uwsgi/sites/PROJECT.ini

Put this configuration:

[uwsgi]
project = PROJECT
uid = SYSTEMUSER
base = /home/%(uid)

chdir = %(base)/%(project)
module = %(project).wsgi:application

master = true
processes = 5

socket = /run/uwsgi/%(project).sock
chown-socket = %(uid):www-data
chmod-socket = 660
vacuum = true

WSGI on systemd

nano /etc/systemd/system/uwsgi.service

Put this configuration in place:

[Unit]
Description=uWSGI Emperor service

[Service]
ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown USER:www-data /run/uwsgi'
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target

Web Server

Install web server:

sudo apt-get install nginx

Config virtualhost:

nano /etc/nginx/sites-available/PROJECT

Put this configuration in place:

  server {
  
    listen 80;
    server_name HOSTNAME;
  
    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/www/PROJECT/Core;
    }
  
    location / {
        include         uwsgi_params;
        uwsgi_pass      unix:/run/uwsgi/PROJECT.sock;
    }
  
  }

Enable your virtualhost:

  ln -s /etc/nginx/sites-available/PROJECT /etc/nginx/sites-enabled

Test nginx configuration files:

nginx -t

IPtables

Open necessary ports:

iptables -A INPUT -i ens3 -p tcp --dport 2233 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i ens3 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i ens3 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT

iptables -A INPUT -i lo -j ACCEPT
iptables -I INPUT 1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Change default behavior of the specific chains to drop all connections:

iptables -P INPUT DROP
iptables -P FORWARD DROP

To make iptable rules persistent install iptables-persistent:

apt-get install iptables-persistent
invoke-rc.d netfilter-persistent save

You are already done.

Use this command to update iptable rules. Note that if you run iptable-save it saves all fail2ban rules and fail2ban add all these rules on boot and it make your iptable a mess.

iptables-save

List IPtable Rules:

iptables --list
iptables -S
iptables -L --line-numbers

Delete specific rule:

iptables -D FORWARD rule_number

Change default behavior of the specific chains to accept all connections:

sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT

This drop connections by a separate rule not the default policy:

iptables -I INPUT -j DROP

Fail2ban

Install the service:

apt-get install fail2ban

Follow how to protect ssh with fail2ban on ubuntu 14.04 to protect ssh.

Follow how to protect an nginx server with fail2ban on ubuntu 14.04 to protect nginx.

Redis

Install Redis. After installation of Redis:

pip3 install django-redis

Start uwsgi and nginx services:

sudo systemctl restart nginx
sudo systemctl start uwsgi

service  redis_6379 stop
service  redis_6379 start
redis-cli

Deploy on Push Service

Install git-auto-deploy program:

add-apt-repository ppa:olipo186/git-auto-deploy
apt-get update
apt-get install git-auto-deploy

Working with service:

/etc/init.d/git-auto-deploy start/stop/status

If it does’nt started see service log:

tail -f /var/log/git-auto-deploy.log

This service listen on 8001 port number by default. If you want to check if it’s started correctly and is listening on this port use telnet:

telnet localhost 8001

If you have telnet on your machine check it from another network.

Change the owner of your project files to it’s created user:

chown -R git-auto-deploy:git-auto-deploy /var/www

Config git-auto-deploy repositories:

nano /etc/git-auto-deploy.conf.json

Add repositories informations:

  {
    "url": "[email protected]:YOURGITLABACCOUNT/REPO1.git",
    "branch": "master",
    "remote": "origin",
    "path": "/home/www/PROJECT/",
    "deploy": "echo deploying"
  },
  {
    "url": "[email protected]:YOURGITLABACCOUNT/REPO2.git",
    "branch": "master",
    "remote": "origin",
    "path": "/home/www/PROJECT/",
    "deploy": "echo deploying"
  },

Restart the service:

sudo service git-auto-deploy restart

Go to repositories web hook section (1,2) and add hooks information:

URL: http://YOURSERVERIPADDRESS:8001
Enable SSL verification? Disabled
Push events? ✓

Use gitlab built-in test to see if your hook works properly.

Fix permissions for git-auto-deploy service:

chown -R git-auto-deploy:git-auto-deploy /etc/git-auto-deploy
cd path/to/project/dir
chown -R git-auto-deploy:www-data *
chown -R git-auto-deploy:www-data .git/
chown -R git-auto-deploy:www-data .gitignore/

Read how to set up automatic deployment with git with a vps and how to use git hooks to automate development and deployment tasks for more information.

Configure Https

Copy certificates:

cp PROJECT.crt PROJECT.key /etc/ssl/

Open the virtualhost file:

/etc/nginx/sites-available/PROJECT

Find this block:

  server {
  
    listen 80;
    server_name HOSTNAME;
  
    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/www/PROJECT;
    }
  
    location / {
        include         uwsgi_params;
        uwsgi_pass      unix:/run/uwsgi/PROJECT.sock;
    }
  
  }

Edit it like this:

server {
    server_name HOSTNAME;
    listen 80;
    return 301 https://HOSTNAME$request_uri;
}

  server {

    listen 443;
    server_name HOSTNAME;

    ssl on;
    ssl_certificate /etc/ssl/PROJECT.crt;
    ssl_certificate_key /etc/ssl/PROJECT.key;
    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/www/PROJECT;
    }

    location / {
        include         uwsgi_params;
        uwsgi_pass      unix:/run/uwsgi/ibmn.sock;
        proxy_set_header X-Forwarded-Proto https;
    }

  }

Restart nginx:

service nginx restart

Add following lines to django settings.py:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True