25 Apr

Installing Django on Ubuntu, uWSGI, PostgreSQL, and Celery+Redis

1. Install Python3 (If not installed)
$ sudo apt-get update
$ sudo apt-get install python3 python3-dev
2. Install PostgreSQL
$ sudo apt-get update
$ sudo apt-get install postgresql postgresql-contrib libpq-dev

During the Postgres installation, an operating system user named postgres was created to correspond to the postgres PostgreSQL administrative user.
We need to change to this user to perform administrative tasks:

$ sudo su - postgres

Log into a Postgres session by typing:

$ psql

First, we will create a database for our Django project. Each project should have its own isolated database for security reasons.
We will call our database myproject in this guide, but it’s always better to select something more descriptive:

> CREATE DATABASE myproject;

Remember to end all commands at an SQL prompt with a semicolon.

Create a database user which we will use to connect to and interact with the database.

> CREATE USER myprojectuser WITH PASSWORD 'password';

Modify a few of the connection parameters for the user just created to speed up database operations.

We are setting the default encoding to UTF-8, and timezone to UTC which Django expects.
We are also setting the default transaction isolation scheme to “read committed”, which blocks reads from uncommitted transactions.

> ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
> ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
> ALTER ROLE myprojectuser SET timezone TO 'UTC';

Give our database user access rights to the database we created:

> GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

Exit the SQL prompt to get back to the postgres user’s shell session:

> \q

Exit out of the postgres user’s shell session to get back to your regular user’s shell session:

$ exit

Optionally Change the

$ sudo nano /etc/postgresql/X/main/pg_hba.conf
local all postgres peer

Should be:

local all postgres md5
  • If you can’t find this file, running ‘locate pg_hba.conf’ should show you where the file is.

After altering this file, restart PostgreSQL server.

$ sudo service postgresql restart.
3. Pull the project from Git store
$ cd ~
$ git clone https://gitlab.com/path/myproject.git
$ cd myproject/

Install Virtualenv

$ python3 -m venv venv
$ source venv/bin/activate
(venv) sudo -H pip3 install --upgrade pip
(venv) pip install -r requirements.txt
4. Configure the Django Database Settings

Now that we have a project, we need to configure it to use the database we created.

Install the psycopg2 package (if not in the requirement.txt) that will allow us to use the database we configured:

$ (venv) pip install psycopg2

Open the main Django project settings file located within the child project directory:

$ nano ~/myproject/myproject/settings.py
. . .

The simplest case: just add the domain name(s) and IP addresses of your Django server

ALLOWED_HOSTS = [ 'example.com', '203.0.113.5']

To respond to ‘example.com’ and any subdomains, start the domain with a dot

ALLOWED_HOSTS = ['.example.com', '203.0.113.5', 127.0.0.1]
ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . .]
. . .
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

Towards the bottom of the file, you will see a DATABASES section, change it to:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'myproject', # Or path to database file if using sqlite3.
# The following settings are not used with sqlite3:
'USER': 'myuser',
'PASSWORD': 'password',
'HOST': '127.0.0.1', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
'PORT': '', # Set to empty string for default.
  }
}

When you are finished, save and close the file.

5. Migrate the Database and Test your Project

Now that the Django settings are configured, we can migrate our data structures to our database and test out the server.

We can begin by creating and applying migrations to our database. Since we don’t have any actual data yet, this will simply set up the initial database structure:

$ cd ~/myproject
$ python manage.py makemigrations
$ python manage.py migrate

After creating the database structure, we can create an administrative account by typing:

$ python manage.py createsuperuser

Select a username, provide an email address, and password for the account.

Once you have an admin account set up, you can test that your database is performing correctly by starting up the Django development server:

$ python manage.py runserver 0.0.0.0:8000

In your web browser, visit your server’s domain name or IP address followed by :8000 to reach default Django root page:

http://server_domain_or_IP:8000
6. Install and Configure uWSGI
$ cd project/path
$ sudo pip3 install uwsgi
Test the uwsgi
$ uwsgi --http :8080 --home /home/myproject --chdir /home/myproject -w myproject.wsgi

Press CTRL+C to stop

Create uwsgi INI file

$ nano /etc/uwsgi/sites/myproject.ini
[uwsgi]
chdir = /home/myproject
home = /home/myproject/venv
module = myproject.wsgi:application
master = true
processes = 5

#socket = /run/uwsgi/myproject.sock
protocol = http # Must be set to use http socket with systemd
socket    = :8080
chmod-socket = 666
vacuum = true

die-on-term = true

To have uWSGI serve HTTP (instead of the binary uwsgi protocol) under Systemd socket activation, set protocol to http; for instance, in an INI, do this:

$ sudo nano /etc/systemd/system/uwsgi.service
[Unit]
Description=uWSGI Emperor
[Service]
ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown www-data: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

Make the file executable.

$ sudo chmod a+x /etc/systemd/system/uwsgi.service

Run the service

$ systemctl start uwsgi.service
$ systemctl status uwsgi.service
7. Install and Configure Nginx as a Reverse Proxy
$ sudo apt-get install nginx
$ sudo nano /etc/nginx/sites-available/myproject
server {
listen 80;
server_name myproject.com www.myproject.com;
    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/myproject;
    }

    location / {
        include         uwsgi_params;
        #uwsgi_pass      unix:/run/uwsgi/myproject.sock;
        proxy_pass      http://127.0.0.1:8080;
    }
}
$ sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
$ sudo nginx -t
$ sudo service nginx restart
8. Troubleshoot

For NGINX errors

$ sudo tail -f /var/log/nginx/error.log

For others errors not in the standard log files

$ sudo tail -f /var/log/syslog
9. Using Celery and Redis for Background Task Processing

Step 1: Add celery.py

Inside the “myproject” directory, create a new file called celery.py:

$ nano ~/myproject/myproject/celery.py
from future import absolute_import
import os
from celery import Celery
from django.conf import settings
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
app = Celery('myproject')

# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))

Step 3: Install Redis as a Celery “Broker”

$ sudo apt update
$ sudo apt install redis-server
$ sudo nano /etc/redis/redis.conf

The supervised directive is set to no by default. Since you are running Ubuntu, which uses the systemd init system, change this to systemd

$ sudo systemctl restart redis.service
$ sudo systemctl status redis
$ redis-cli
127.0.0.1:6379> ping
PONG

Check the redis binding

$ sudo netstat -lnp | grep redis

Once Redis is up, add the following code to your settings.py file:

$ nano ~/myproject/myproject/settings.py

# CELERY STUFF
BROKER_URL = 'redis://localhost:6379'
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'UTC'
CELERY_BEAT_SCHEDULE = {
'task1': {
'task': 'Joliba.tasks.task1',
'schedule': crontab(minute='*/10'),
    },
}

Install the celery and redis package (if not in the requirement.txt)

(venv) $ pip install celery redis

Restart the uwsgi application

$ sudo systemctl restart uwsgi.service
10. Add SSL for the website using letsencrypt.

Adding SSL with Let’s Encrypt and NGINX

03 Oct

SSL/TLS Certificates on Flask Application with Let’s Encrypt and NGINX

Let’s Encrypt is a new certificate authority (CA) offering free and automated SSL/TLS certificates. Certificates issued by Let’s Encrypt are trusted by most browsers in production today, including Internet Explorer on Windows Vista. Simply download and run the Let’s Encrypt client to generate a certificate.

(there are a few more steps than that, of course, though not many)
Step 1: Download LetsEncrypt

Install git if you haven’t done so yet:

# apt-get install git

Use git to get the application and store it somewhere (ie: /opt)

$ sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt

Step 2: Webroot Plugin

The Webroot plugin works by placing a special file in the /.well-known directory within your document root, which can be opened (through your web server) by the Let’s Encrypt service for validation.
Depending on your configuration, you may need to explicitly allow access to the /.well-known directory.

location /.well-known {
alias /home/user/webapps/appname/.well-known;
}

Restart NGNIX

# sudo service nginx status

 

Step 3: Generate your certificate and Strong Diffie-Hellman Group

The first time you run the command below, you will be asked to provide an e-mail address to be associated to the domain or subdomain, in case you should ever need to recover the key or something.
The next time you run the same command (to renew the certificate) it won’t be asked.

So run the following command to generate the certificate:

$ sudo /opt/letsencrypt/letsencrypt-auto certonly -a webroot –agree-tos –renew-by-default \

–webroot-path=/home/user/webapps/appname \

-d website.com [-d sub.website.com] \

–e-mail=email@website.com

Then Generate Strong Diffie-Hellman Group
This may take a few minutes but when it’s done you will have a strong DH group at /etc/ssl/certs/dhparam.pem.
$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Step 4: Configuring Nginx

After running the command that generates the certificates, you should have several files in /etc/letsencrypt/live/website.com/ (replace website.com by your own domain).
We are going to need just two of them for Nginx: fullchain.pem and privkey.pem.
Comment out or delete the lines that configure this server block to listen on port 80.
The beginning of your server block should look like this:

server {

server_name website.com www.website.com;

listen 443 ssl;

ssl_certificate /etc/letsencrypt/live/website.com/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/website.com/privkey.pem;

# For Safari and iOS devices

ssl_session_cache shared:SSL:20m;

 

#Diffie-Hellman Group

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

ssl_prefer_server_ciphers on;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

ssl_ciphers ‘ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA’;

ssl_session_timeout 1d;

ssl_stapling on;

ssl_stapling_verify on;

add_header Strict-Transport-Security max-age=15768000;

Lastly, outside of the original server block (that is listening on HTTPS, port 443), add this server block to redirect HTTP (port 80) to HTTPS.

server {
listen 80;
server_name website.com www.website.com;
return 301 https://$host$request_uri;
}

Put the changes into effect by restarting Nginx:

$ sudo service nginx restart

The Let’s Encrypt TLS/SSL certificate is now in place.

At this point, you should test that the TLS/SSL certificate works by visiting your domain via HTTPS in a web browser.
You can use the Qualys SSL Labs Report to see how your server configuration scores:

https://www.ssllabs.com/ssltest/analyze.html?d=website.com

Step 5: Automate the Certificate Renewal

Edit the crontab to create a new job that will run the renewal command every week.

$ sudo crontab –e

30 2 * * 1 /opt/letsencrypt/letsencrypt-auto renew >> /var/log/le-renew.log

35 2 * * 1 /etc/init.d/nginx reload

02 Nov

Git adventures

I wanted to clean up some Bootstrap files from a project directory. After the cleanup. I pushed the changes to the remote repo (BitBucket).
However, I noticed that the files that should be deleted (and was deleted on local repo), was still existing on the remote repo.
After some head scratching, i released that the problem was that I used the file system delete, instead of the git delete.

$ git rm 
$ git add .
$ git commit -m "changes"
$ git push

Everything was fine now and good, until I come back to see that i deleted an important directory due to a misuse of the “*” during the delete.
Well, that what and DSCM was meant for.. Git come to the rescue…. except that it took me 30mins or trying different command ( and help from Stackoverflow) to find the right combo, thus:

cf361cb is the last commit with the missing directory

$ git revert --no-commit cf361cb..HEAD
$ git commit

This is a safe and easy way to rollback to a previous state. Checks for the missing directory

$ ls -ltr
$ cd static/

Cleanup files

$ git rm *.css
$ git rm *.js

Then commit and push

$ git add .
$ git status
$ 1398 git commit -m "UI file cleanup"
$ git push

And Wossah!!
The git throws up a new error, “fatal: You are not currently on a branch”
I checked on the git

$ git status

And trully, you are not a branch!
I was getting loosing the modification twice after using 2 different command, until i hit on the right combo (also good help from stackoverflow)

$ git checkout -b newbranch
$ git checkout master
$ git merge newbranch
$ git branch -d newbranch
$ git status
$ git push

Hurray!!

23 Jul

Deploying a Flask Project on WebFaction with Git [UPDATED]

I found it tedious having to redo the setup of my application on WebFaction whenever there is a new update of the application. I started looking for way to update the content of the application, without affecting the setup configurations of the application on WebFaction.
Step 1: Add your site to Your WebFaction Account
From your WebFaction console:
1.       Log into your WebFaction Console
2.       Go to your “Websites” tab, click the “Add New Website” button
3.      Enter the website name and domains as needed for your project
4.      Under the Contents section, choose Add an Application > Create a New Application
1.      Name to “myapp” 
2.      Set App Category to “mod_wsgi”
3.      App Type should be the most recent version of mod_wsgi that supports your Python version. Make sure that your Python version matches with your mod_wsgi choice ( “mod_wsgi 3.5/Python 2.7″ for this guide).
4.      Click the Save button to add that application
5.      Click the Save button to save your website
Now your WebFaction account should have a new domain, website, and mod_wsgi application.
Step 2: SSH into your new application
First, you’ll need to SSH into your webfaction account. Once you’re there, cd into your newly created application:
cd ~/webapps/myapp
In this directory, you’ll see two folders:
– apache2/      # This contains all of your Apache config and action files
– htdocs/       # This is the folder Apache to launch your project

Step 3: Upload your Flask project using Git

Upload the project/ folder to the application directory using Git. “myapp” directory is created

git clone https://username@bitbucket.org/uobis0/myapp.git

All following instructions will assume you’re still in this directory.

 virtualenv venv --python=python2.7
$ . venv/bin/activate
$ easy_install-2.7 flask    # Installs flask package for the app
$ pip install -r /myapp/app/requirements.txt  # Installs the packages for the app
$ deactivate

Now, my ~/webapps/myapp directory list looks like the following:

drwxr-xr-x 7 uobis uobis 4096 Nov 11 14:29 apache2/
drwxrwxr-x 5 uobis uobis 4096 Nov 11 14:40 venv/
drwxrwxr-x 6 uobis uobis 4096 Nov 14 16:46 myapp/
drwxr-xr-x 2 uobis uobis 4096 Nov 11 14:29 htdocs/
-rw-rw-r-- 1 uobis uobis 292 Nov 18 15:14 wsgi.py

Step 4: Edit apache2/conf/httpd.conf

Using your favorite command line editor, open up the apache2/conf/httpd.conf file:

vim ~/webapps/myapp/apache2/conf/httpd.conf

Load Alias module (optional)

You’ll see a section where Apache Modules are being loaded. I had to manually add the Alias module to the bottom of the list (shown below).

.
.
LoadModule wsgi_module       modules/mod_wsgi.so
LoadModule alias_module      modules/mod_alias.so    #Your version of mod_wsgi might not need to add this.

Modify Alias and <Directory>

Add the following parameters to your <Directory> section:

WSGIScriptAlias / /home/username/webapps/myapp/wsgi.py

<Directory /home/username/webapps/myapp/htdocs>
    AddHandler wsgi-script .py
    RewriteEngine on
    RewriteBase /
    WSGIScriptReloading On
</Directory>

Now for the final edit of the config file.

Step 5: Make sure your main file is right 

Ensure that, if your structure is package, your project’s __init__.py file is launching your Flask application. This is what the file at ~/webapps/myapp/app/__init__.py should look like:

from flask import Flask

# Setting up the App
app = Flask(__name__)
app.config.from_object('config')

# Importing the views for the rest of our site
from app import views

if __name__ == '__main__':
    app.run()

If you are using modules, the files should contain the app instantiation

app = Flask(__name__)

This will work nicely with our wsgi.py file, which we’ll set up next.

Step 6: Modify the htdocs/wsgi.py file

WebFaction should have created this file. In it are a few scripts, but you can completely remove those. Here is what the ~/webapps/myapp/wsgi.py file should contain:

import sys

# Active your Virtual Environment, which I'm assuming you've already setup
activate_this='/home/username/webapps/myapp/venv/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))

# Appending our Flask project files
sys.path.append('/home/username/webapps/myapp/myapp')

# Launching our app
from main import app as application

 

Step 7: Restart Apache

The last step will be to restart apache, like so:
~/webapps/myapp/apache2/bin/restart

 

Troubleshooting

If you’re having trouble, take a look at your logs in the ~/logs/users/ directory.

Application Updates

The steps above makes updates very easy:
cd ~/webapps/myapp/myapp
git pull https://username@bitbucket.org/accout/myapp.git

~/webapps/myapp/apache2/bin/restart