This is a common example to set up and running a personal Wiggum application. We are assuming that we have these services.

http://mycompany.io
http://documents.mycompany.io
http://backoffice.mycompany.com
http://deployments.mycompany.com
http://logs.mycompany.com

Installation

We are setting on /home/wiggumuser/apps to do all the stuff.

System dependencies

Wiggum is a Python3 application so you will need a python3 installation. Apart from this, you will need some dependecies: node, gettext, libffi, libssl and libpq. In apt based systems you will do:

# apt-get update
# apt-get install -y libffi-dev libssl-dev libpq-dev postgresql-client gettext node

Database

We need a ready PostgreSQL with a database, user and stuff.

JWT keys

We are going to use asymmetric keys this time, exactly we will use RS256 algorithm to sign the Token. We create the keys.

$ mkdir ./wiggum-keys && cd ./wiggum-keys
$ ssh-keygen  -t rsa -b 2048 -q -N "" -f ./wiggu

Now we have the private wiggum and the public wiggum.pub keys

Warning

Private keys mean private! Don't share :)

Get Wiggum

$ cd ..
$ git clone https://github.com/qdqmedia/wiggum.git

At this moment we have wiggum and wiggum-keys directories.

App dependencies

We install the dependencies in the system or in a virtualenv, for this example we will create a virtualenv named wiggumapp

$ mkvirtualenv wiggumapp

And install wiggum dependencies in this virtualenv

$ pip install -r ./wiggum/requirements/base.txt

Install node depdencies from wiggum project

$ cd ./wiggum
$ npm install
$ node_modules/.bin/bower install

Create own settings

We need to create our own settings, we will set the least neccessary settings to have a Personal wiggum app. We will create a directory where we will place all of our custom configuration

$ cd -
$ mkdir ./wiggum-prod && ./wiggum-prod
$ touch ./conf.py

And start putting the settings on the conf.py file

Import from base settings

Inherit from wiggum default settings

import os
from wiggum.settings.wiggum import *

Common Django stuff

We set the Django sessión key to a random hash and Debug to false

SECRET_KEY = "32f&7^ih2&lc0&)enip3e_i^@8v2!(n1z4sx9fe@0shh2*e)=*"
DEBUG = False

The place the static and media files will be generated and placed

MEDIA_ROOT = "/home/wiggumuser/media"
STATIC_ROOT = "/home/wiggumuser/static"

Database & caches

Set the database settings to point to our postgres and use the local memory cache Wiggum doesn't need to cache so we don't need something like Redis or memcached.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': os.getenv('PG_DATABASE'),
        'USER': os.getenv('PG_USER'),
        'PASSWORD': os.getenv('PG_PASSWORD',),
        'HOST': os.getenv('PG_HOST', "127.0.0.1"),
        'PORT': os.getenv('PG_PORT', '5432'),
    }
}

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'wiggum',
    }
}

Static stuff

Wiggum uses [Django pipeline] to manage the assets so we need to point where these binaries are

PIPELINE_LESS_BINARY = os.path.join(NODE_MODULES_PATH, "less")
PIPELINE_UGLIFYJS_BINARY = os.path.join(NODE_MODULES_PATH, "uglifyjs")
PIPELINE_YUGLIFY_BINARY = os.path.join(NODE_MODULES_PATH, "yuglify")

Wiggum

We set the issuer to our company wiggum and the name of the cookie

JWT_ISSUER = "wiggum-mycompany"
JWT_COOKIE_NAME = "wiggum-mycompany"

Disable the transition keys, only need one key valid at a time.

JWT_TRANSITION_ENABLE = False

As we saw at the beginning, we have apps on mycompany.io and mycompany.com domains So we will need to clone the cookie. We are placing wiggum on https://login.mycompany.com and https://login.mycompany.io, so this would use a level 2 autodomain:

JWT_COOKIE_DOMAIN_AUTO = True
JWT_COOKIE_DOMAIN_AUTO_LEVEL = 2
JWT_COOKIE_CLONE = True
JWT_COOKIE_CLONE_DOMAINS_ENDPOINT = (
    "login.mycompany.io",
    "login.mycompany.com",
)

We set some default redirects.

LOGIN_SUCCESS_REDIRECT = "http://mycompany.io"
LOGOUT_SUCCESS_REDIRECT = "/a/login"

Finally set the generated keys

First we set the content of the public key from wiggum-keys/wiggum.pub

JWT_VERIFICATION_KEY = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCmFPuwTx+EsF5BOoFVqcVgDUdszogmk9yGsJFATdZZr3eYXIeZYJJOqOL2VZsepJfTjVJn6hNl57cpCjB39JpBja+GrSS1LRexIyPpyIkswhulSWOcb6rnIpIXuWpWXW/syT0jBOdRJZIH6HBIqC/et2IAoCtjHRZrsoympECQfk40tjUBctTv0RrmC8ouiWMyR67nhPJCcZFNVqtvR6BRrlg2iQOwj0h59/Z3hFNPZVPeAi0TwPDhs3HF3Gv/q84w5auFx7B3m32eHvMqzYVatUcRbkPskQVCh2Qbp2wFLraPaiHLHPXKMdVcUvoMpmjfi24HP6EeLBF2qy3kVWez wiggum@59448fc67e05"

Then the private key from wiggum-keys/wiggum

JWT_SECRET_KEY = """-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAphT7sE8fhLBeQTqBVanFYA1HbM6IJpPchrCRQE3WWa93mFyH
mWCSTqji9lWbHqSX041SZ+oTZee3KQowd/SaQY2vhq0ktS0XsSMj6ciJLMIbpUlj
nG+q5yKSF7lqVl1v7Mk9IwTnUSWSB+hwSKgv3rdiAKArYx0Wa7KMpqRAkH5ONLY1
AXLU79Ea5gvKLoljMkeu54TyQnGRTVarb0egUa5YNokDsI9Ieff2d4RTT2VT3gIt
E8Dw4bNxxdxr/6vOMOWrhcewd5t9nh7zKs2FWrVHEW5D7JEFQodkG6dsBS62j2oh
yxz1yjHVXFL6DKZo34tuBz+hHiwRdqst5FVnswIDAQABAoIBAQCP3g9k3DWeWLVd
ZdPRo/4RRY+AxqwUVvOqTVuVy5eKG0DLYCQqjghPUWdCIkf8VHIc1Qf0ckWZeg8k
4um3j9DsRlMto+DvfP9P9/PNOWTyu7b9CETcp7LxA/ZvzLM72zbwdCacpkvG9He6
l/RkTCUjldG0XwsWkYTxiDrkw9YWE55Mbm/5dHPGj75oaJZWhJRPV/g0S+okKLlR
7y/uBB8ZgmdobTkN0XkR2vjLtCr8u+y4GPVcO/9JdjPsXxZbDD4GosAWoTR2oVR9
/MnbtwoECf0aVb22LAuE0wIrTIXIFIj+/I5/K7gan/6RucM2nqZq/og8iH9Kjnba
eu8ZqOXRAoGBANNeNzVnKMyS3S2wPjY6BMiLdEPhWJgtdw+t/b01c1Cq52aEYh0X
vcO6AqdERxH6IKF/fnOJ1bf5JeiZdZKDChfRlwhGylw7duNxe5JMw3DG/y7BgxFT
7P7AO0X4IKmhROS0+cPfVD/DxRiC183IBmZdrDB+PTy1vAIB1e4vXv8ZAoGBAMkm
xKORRMF1Rh5aMYdZ3tGe9K5XyY8m73Onb1MYMaP5LuFgmiTYAED//aF04cjYBY4L
3BZ638HXc4PiyonzTlD1Ks/rHUudIqmk/chM6BXsyMyROCGgw13kQq4A5omWfkWC
16kGgDxQ+1hHZRmWsPOD7bNnl3++TR/oHq9341KrAoGATHcwJ9yrEN8sruOsjfeN
VXPF2uzCHUONaBm8yt90WUGKtza7O+Uj3JQFc7eqsmE3vtUdzPSXYZf709r4gslv
NFC5f+AEQzur9fpPBw1IQxtqo+KT5QfknAC1MMnkHxndj5O9K9Q2aV8MhaKIKcTs
M8o9icmRo83nNx6s4x82EbkCgYAKqm6UybgelexQ4bFsntxMuyP4NpluaL8bn84s
VsUTD7xnoOqrd3ST/b7iF8N9Fc89l+1kl8FTkuwCGz1oESme61EI00urXbqfyirW
uxU3TGXdSvnx9odFbDwI4+1VcFBjuStcQAb+q8CYDrkSoUXis6Uf9Sc4U8vdHD68
SRwZnwKBgEb9WeG2faQ2z/yVS/GackxoOu1Iuva2Mm6iRjW5RN+aKoz9j1S/1///
baIuTGlMpuHGwD+E8t1OPZ4ePCtHBKBogNefwBt+2bB40nZTzON+SX2JgdOEmo8z
DryNZ5s3VOt7bQrz97xSM8II7JuUVHCf5vB1DXGeDVccY2N+Bj+6
-----END RSA PRIVATE KEY-----"""

The sign algorithm and verification one, they are the same

JWT_SIGN_ALGORITHM = "RS256"
JWT_SIGN_VALID_ALGORITHMS =[JWT_SIGN_ALGORITHM, ]

Allowed hosts

We said that wiggum will be on https://login.mycompany.com and https://login.mycompany.io, we enable seving on this hosts:

ALLOWED_HOSTS = [
                 "login.mycompany.com",
                 "login.mycompany.io",
                 "127.0.0.1",
                 "localhost"]

All in one file

This is the result of our configuration

import os
from wiggum.settings.wiggum import *


SECRET_KEY = "32f&7^ih2&lc0&)enip3e_i^@8v2!(n1z4sx9fe@0shh2*e)=*"
DEBUG = False

MEDIA_ROOT = "/media"
STATIC_ROOT = "/static"

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': os.getenv('PG_DATABASE'),
        'USER': os.getenv('PG_USER'),
        'PASSWORD': os.getenv('PG_PASSWORD',),
        'HOST': os.getenv('PG_HOST', "127.0.0.1"),
        'PORT': os.getenv('PG_PORT', '5432'),
    }
}

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'wiggum',
    }
}

PIPELINE_LESS_BINARY = os.path.join(NODE_MODULES_PATH, "less")
PIPELINE_UGLIFYJS_BINARY = os.path.join(NODE_MODULES_PATH, "uglifyjs")
PIPELINE_YUGLIFY_BINARY = os.path.join(NODE_MODULES_PATH, "yuglify")

JWT_ISSUER = "wiggum-mycompany"
JWT_COOKIE_NAME = "wiggum-mycompany"
JWT_TRANSITION_ENABLE = False
JWT_COOKIE_DOMAIN_AUTO = True
JWT_COOKIE_DOMAIN_AUTO_LEVEL = 2
JWT_COOKIE_CLONE = True
JWT_COOKIE_CLONE_DOMAINS_ENDPOINT = (
    "login.mycompany.io",
    "login.mycompany.com",
)

LOGIN_SUCCESS_REDIRECT = "http://mycompany.io"
LOGOUT_SUCCESS_REDIRECT = "/a/login"

JWT_VERIFICATION_KEY = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCmFPuwTx+EsF5BOoFVqcVgDUdszogmk9yGsJFATdZZr3eYXIeZYJJOqOL2VZsepJfTjVJn6hNl57cpCjB39JpBja+GrSS1LRexIyPpyIkswhulSWOcb6rnIpIXuWpWXW/syT0jBOdRJZIH6HBIqC/et2IAoCtjHRZrsoympECQfk40tjUBctTv0RrmC8ouiWMyR67nhPJCcZFNVqtvR6BRrlg2iQOwj0h59/Z3hFNPZVPeAi0TwPDhs3HF3Gv/q84w5auFx7B3m32eHvMqzYVatUcRbkPskQVCh2Qbp2wFLraPaiHLHPXKMdVcUvoMpmjfi24HP6EeLBF2qy3kVWez wiggum@59448fc67e05"
JWT_SECRET_KEY = """-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAphT7sE8fhLBeQTqBVanFYA1HbM6IJpPchrCRQE3WWa93mFyH
mWCSTqji9lWbHqSX041SZ+oTZee3KQowd/SaQY2vhq0ktS0XsSMj6ciJLMIbpUlj
nG+q5yKSF7lqVl1v7Mk9IwTnUSWSB+hwSKgv3rdiAKArYx0Wa7KMpqRAkH5ONLY1
AXLU79Ea5gvKLoljMkeu54TyQnGRTVarb0egUa5YNokDsI9Ieff2d4RTT2VT3gIt
E8Dw4bNxxdxr/6vOMOWrhcewd5t9nh7zKs2FWrVHEW5D7JEFQodkG6dsBS62j2oh
yxz1yjHVXFL6DKZo34tuBz+hHiwRdqst5FVnswIDAQABAoIBAQCP3g9k3DWeWLVd
ZdPRo/4RRY+AxqwUVvOqTVuVy5eKG0DLYCQqjghPUWdCIkf8VHIc1Qf0ckWZeg8k
4um3j9DsRlMto+DvfP9P9/PNOWTyu7b9CETcp7LxA/ZvzLM72zbwdCacpkvG9He6
l/RkTCUjldG0XwsWkYTxiDrkw9YWE55Mbm/5dHPGj75oaJZWhJRPV/g0S+okKLlR
7y/uBB8ZgmdobTkN0XkR2vjLtCr8u+y4GPVcO/9JdjPsXxZbDD4GosAWoTR2oVR9
/MnbtwoECf0aVb22LAuE0wIrTIXIFIj+/I5/K7gan/6RucM2nqZq/og8iH9Kjnba
eu8ZqOXRAoGBANNeNzVnKMyS3S2wPjY6BMiLdEPhWJgtdw+t/b01c1Cq52aEYh0X
vcO6AqdERxH6IKF/fnOJ1bf5JeiZdZKDChfRlwhGylw7duNxe5JMw3DG/y7BgxFT
7P7AO0X4IKmhROS0+cPfVD/DxRiC183IBmZdrDB+PTy1vAIB1e4vXv8ZAoGBAMkm
xKORRMF1Rh5aMYdZ3tGe9K5XyY8m73Onb1MYMaP5LuFgmiTYAED//aF04cjYBY4L
3BZ638HXc4PiyonzTlD1Ks/rHUudIqmk/chM6BXsyMyROCGgw13kQq4A5omWfkWC
16kGgDxQ+1hHZRmWsPOD7bNnl3++TR/oHq9341KrAoGATHcwJ9yrEN8sruOsjfeN
VXPF2uzCHUONaBm8yt90WUGKtza7O+Uj3JQFc7eqsmE3vtUdzPSXYZf709r4gslv
NFC5f+AEQzur9fpPBw1IQxtqo+KT5QfknAC1MMnkHxndj5O9K9Q2aV8MhaKIKcTs
M8o9icmRo83nNx6s4x82EbkCgYAKqm6UybgelexQ4bFsntxMuyP4NpluaL8bn84s
VsUTD7xnoOqrd3ST/b7iF8N9Fc89l+1kl8FTkuwCGz1oESme61EI00urXbqfyirW
uxU3TGXdSvnx9odFbDwI4+1VcFBjuStcQAb+q8CYDrkSoUXis6Uf9Sc4U8vdHD68
SRwZnwKBgEb9WeG2faQ2z/yVS/GackxoOu1Iuva2Mm6iRjW5RN+aKoz9j1S/1///
baIuTGlMpuHGwD+E8t1OPZ4ePCtHBKBogNefwBt+2bB40nZTzON+SX2JgdOEmo8z
DryNZ5s3VOt7bQrz97xSM8II7JuUVHCf5vB1DXGeDVccY2N+Bj+6
-----END RSA PRIVATE KEY-----"""

JWT_SIGN_ALGORITHM = "RS256"
JWT_SIGN_VALID_ALGORITHMS =[JWT_SIGN_ALGORITHM, ]

ALLOWED_HOSTS = [
                 "login.mycompany.com",
                 "login.mycompany.io",
                 "127.0.0.1",
                 "localhost"]

Python path

we are using django-admin command, to get this command working we will need to add wiggum project path and configuration path to the PYTHONPATH

export PYTHONPATH=$PYTHONPATH:/home/wiggumuser/apps/wiggum-prod:/home/wiggumuser/apps/wiggum/wiggum

Migrations and admin user

Apply database migrations.

$ django-admin migrate --settings="conf"

Create the admin user

$ django-admin createsuperuser --settings="conf"

Generate statics and translations

Generate statics

$ mkdir /home/wiggumuser/static
$ mkdir /home/wiggumuser/media
$ django-admin collectstatic --settings="conf"

Generate translations The translations are placed by default in wiggum project root in locale directory this would be: /home/wiggumuser/wiggum/wiggum/locale

$ mkdir -p home/wiggumuser/wiggum/wiggum/locale
$ django-admin compilemessages --settings="conf"

uwsgi

We are using uwsgi to run wiggum, and whitenoise to serve the few statics from uwsgi, this could be done with an Nginx, but this is out of the scope. Install both dependencies

$ pip install uwsgi whitenoise

We create the Django wsgi module in /home/wiggumuser/apps/wiggum-prod

$ touch /home/wiggumuser/apps/wiggum-prod/wsgi.py

with the content

from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise

application = get_wsgi_application()

application = DjangoWhiteNoise(application)

We create a uwsgi.ini in /home/wiggumuser/apps/wiggum-prod file with the configuration

[uwsgi]
pythonpath = "/home/wiggumuser/apps/wiggum-prod:/home/wiggumuser/apps/wiggum/wiggum"
http = 0.0.0.0:8000
module = wsgi
stats = /tmp/uwsig_stats.socket

# Delete all sockets created
vacuum = true

# Do not let block our process if an external service is taking to much time
harakiri = 10

Lets run wiggum!

DJANGO_SETTINGS_MODULE="conf" uwsgi --ini /home/wiggumuser/apps/wiggum-prod/uwsgi.ini

Warning

You should set HAProxy, Nginx or similar in front of the uwsgi, but again this is out of the scope

Warning

Wiggum always uses https, if DEBUG=True http is enabled. To keep things simple I would suggest setting an HAProxy or similar in front of wiggum to handle the TLS connection.