Project

General

Profile

Actions

Déploiement de COIN en production chez Illyse

COIN est actuellement déployé sur pallando, sous Wheezy.

Cette doc reprend chaque point du déploiement chez Illyse, pas à pas. C'est évidemment à adapter.

Le serveur web utilisé est nginx, il y a quelques trucs à adapter pour apache ou lighttpd (le support de sendfile/XSendfile est différent selon les serveurs web, voir ci-dessous).

Installation

sudo apt-get install python-virtualenv gunicorn postgresql python-dev python-pip libldap2-dev libpq-dev libsasl2-dev git
sudo adduser --disabled-login --disabled-password --gecos coin coin
sudo su - coin
git clone https://code.ffdn.org/FFDN/coin.git
virtualenv COIN
. COIN/bin/activate
pip install -r coin/requirements.txt
# Debian version of gunicorn (wheezy)
pip install gunicorn==0.14.5
# For jessie-backports or stretch
pip install gunicorn==19.6.0

Configuration

Coin lui-même

Dans /home/coin/coin/coin/settings_locals.py (oui, ça fait beaucoup de canards...) :

# -*- coding: utf-8 -*-
import os
import ldap

BASE_DIR = os.path.dirname(os.path.dirname(__file__))

PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))

ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)

DATABASES = {
    # Base de donnée du SI
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'illyse_coin',
        'USER': 'illyse_coin',
        'PASSWORD': 'monmotdepassepostgresql',
        'HOST': 'localhost',  # Empty for localhost through domain sockets
        'PORT': '',  # Empty for default
    },
    # LDAP backend pour stockage et mise à jour de données
    'ldap': {
        'ENGINE': 'ldapdb.backends.ldap',
        'NAME': 'ldap://ldap6.illyse.org:389/',
        'TLS': True,
        'GLOBAL_OPTIONS': {ldap.OPT_X_TLS_REQUIRE_CERT: ldap.OPT_X_TLS_NEVER},
        'USER': 'cn=coin,ou=services,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR',
        'PASSWORD': 'monmotdepasseldap'
    }
}

# Backend to use when sending private files to client
# In production, must be sendfile.backends.xsendfile with Apache xsend file mod
# Or failing xsendfile, use : sendfile.backends.simple
# https://github.com/johnsensible/django-sendfile
SENDFILE_BACKEND = 'sendfile.backends.nginx'
SENDFILE_ROOT = '/home/coin/coin/smedia'
SENDFILE_URL = '/protected'

GRAPHITE_SERVER = "http://graphite.illyse.org" 

ALLOWED_HOSTS = ["coin.illyse.org"]

SERVER_EMAIL = 'coin@coin.illyse.org'

ADMINS = (
  ('alertes', 'alertes@illyse.org'),
)

MANAGERS = ADMINS

STATIC_ROOT = os.path.join(BASE_DIR, 'coin/static/')

SECRET_KEY = 'SECRET_KEY_CHANGEME'

# Do we use LDAP or not
LDAP_ACTIVATE = True

# LDAP Base DNs
LDAP_USER_BASE_DN = "ou=users,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR" 
LDAP_GROUP_BASE_DN = "ou=groups,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR" 
VPN_CONF_BASE_DN = "ou=vpn,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR" 
DSL_CONF_BASE_DN = "ou=radius,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR" 

# First UID to use for users
LDAP_USER_FIRST_UID = 2000

DATABASE_ROUTERS = ['ldapdb.router.Router']

DEFAULT_FROM_EMAIL = "support@illyse.org" 

# Membership configuration
# Default cotisation in €, per year
MEMBER_DEFAULT_COTISATION = 20

MEMBER_MEMBERSHIP_INFO_URL = 'https://www.illyse.org/projects/failocal/wiki/Cotisation'

# feed name (used in template), url, max entries to display
FEEDS = (('isp', 'http://www.illyse.net/feed/', 3),
         ('ffdn', 'http://www.ffdn.org/fr/rss.xml', 3))

Permissions Unix pour la génération de factures

Les PDF des factures sont générés dans smedia/invoices, et il faut donc que l'utilisateur sous lequel tourne Django puisse écrire dedans.

mkdir -p /home/coin/coin/smedia/invoices
chown coin:www-data /home/coin/coin/smedia/invoices
chmod 775 /home/coin/coin/smedia/invoices

Fichiers statiques

Il faut mettre tous les fichiers statiques à un seul endroit, où ils seront servis par Nginx. Pour faire ça, en tant qu'utilisateur coin :

. COIN/bin/activate
cd coin
python manage.py collectstatic

Postgresql

Création de l'utilisateur postgresql et de la base

sudo su - postgres
createuser -D -E -P -R -S illyse_coin
# Enter password (same as in coin config)
createdb -O illyse_coin illyse_coin

Création des tables

sudo su - coin
. COIN/bin/activate
cd coin
python manage.py migrate

Import des données initiales dans la base

# Infos spécifiques à Illyse, pour la personnalisation de l'interface ainsi que pour isp.json
python manage.py loaddata illyse
# Pool d'IP d'Illyse
python manage.py loaddata ip_pool

Nginx

Dans

/etc/nginx/site-available/coin.illyse.org
:

server {
        listen [::]:80;
        server_name coin.illyse.org;
        rewrite ^(.*) https://$server_name$1 permanent;
}

server {
        listen [::]:443 ssl;
        server_name coin.illyse.org;

        ssl on;
        ssl_certificate /etc/ssl/certs/illyse-pallando-cert-cacert.pem;
        ssl_certificate_key /etc/ssl/private/illyse-pallando-privkey.pem;
        root /var/www/;
        access_log /var/log/nginx/coin.illyse.org.access.log;
        error_log /var/log/nginx/coin.illyse.org.error.log;

        proxy_redirect off;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;

        location /static/ {
                alias /home/coin/coin/coin/static/;
        }
        # Invoices, see SENDFILE_* options in coin
        location /protected/ {
                internal;
                alias /home/coin/coin/smedia/;
        }
        location / {
                proxy_pass http://localhost:8282;
        }
}

Gunicorn

Dans /etc/gunicorn.d/coin :

CONFIG = {
    'working_dir': '/home/coin/coin',
    'python': '/home/coin/COIN/bin/python',
    'user': 'www-data',
    'group': 'www-data',
    'args': (
        '--bind=127.0.0.1:8282',
        '--workers=3',
        # '--worker-class=egg:gunicorn#sync',
        # '--timeout=30',
    #'--preload',
    'coin.wsgi',
    ),
}

Crontab

En tant qu'utilisateur coin, on ajoute des tâches cron : générer des factures, et envoyer des mails de rappel de cotisation.

MAILTO=tresorier@illyse.org

# m h  dom mon dow   command
59 23 * * * /home/coin/COIN/bin/python /home/coin/coin/manage.py charge_subscriptions
42 3 * * * /home/coin/COIN/bin/python /home/coin/coin/manage.py call_for_membership_fees

Migration de la base de données

Pour migrer la base de données complète d'une machine à une autre, le plus simple est de la dumper en JSON d'un côté et de la recharger de l'autre côté.

python manage.py dumpdata --indent 2 --natural-foreign --natural-primary > ../dump-20150530-natural.json

Attention, les options --natural-foreign --natural-primary sont nécessaires, voir https://docs.djangoproject.com/en/1.8/topics/serialization/#topics-serialization-natural-keys

Pour charger le dump de l'autre côté :

python manage.py loaddata dump-20150530-natural.json

Au passage, en cas de déménagement de serveur, bien penser à copier les PDF qui sont dans smedia...

Installation de graphite

Graphite est utilisé pour tracer les graphes de trafic. Graphite est interrogé uniquement par COIN, et est alimenté par le serveur VPN.

Installation en utilisant les packages debian:

sudo apt install graphite-web graphite-carbon
   Effacer les fichiers de base de données lors de la suppression de graphite-carbon ? >> Non

Par défaut, Graphite utilise une BDD SQLLite, pour une utilisation en production, on préfère une base postgres, qui gère les instances multiples.
sudo apt install postgresql libpq-dev python-psycopg2
su - postgres
psql
CREATE USER graphite WITH PASSWORD 'miaou';
CREATE DATABASE graphite WITH OWNER graphite;
\q

sudo vim  /etc/graphite/local_settings.py
SECRET_KEY = 'a_secret_miaou_key'
TIME_ZONE = 'Europe/Paris'
USE_REMOTE_USER_AUTHENTICATION = True 

DATABASES = {
    'default': {
        'NAME': 'graphite',
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'USER': 'graphite',
        'PASSWORD': 'miaou',
        'HOST': '::1',
        'PORT': ''
    }
}

sudo graphite-manage syncdb
  Would you like to create one now? (yes/no): no (oui pour avoir un user pour se loguer sur l'interface web)

sudo vim /etc/default/graphite-carbon
CARBON_CACHE_ENABLED=true

sudo vim /etc/carbon/carbon.conf
ENABLE_LOGROTATION = True
CARBON_METRIC_PREFIX = vpn1
PICKLE_RECEIVER_INTERFACE = @ip_listen

sudo vim /etc/carbon/storage-schemas.conf
[vpn1]
pattern = ^vpn1\.
retentions = 5m:31d,30m:1y  #A vérifier/adapter : On conserve 1 point pour 5minutes sur 31jours, et 1 point pour 30minutes sur 1an.

sudo cp /usr/share/doc/graphite-carbon/examples/storage-aggregation.conf.example /etc/carbon/storage-aggregation.conf

service carbon-cache start

A ce stade, le serveur VPN doit être capable d'envoyer les metrics à Carbon. (communication en TCP sur le port 2004 par défaut)

Installation d'un serveur web pour graphite-web et servir les images de graphes à COIN.

Avec nginx + uwsgi :

sudo apt install nginx uwsgi uwsgi-plugin-python

vim /etc/nginx/sites-available/graphite
upstream graphite {
    server unix:/run/uwsgi/app/graphite/socket;
}
server {
        listen [::]:80;
        server_name     graphite.toto.tld;
        access_log  /var/log/nginx/graphite.access.log;
        error_log   /var/log/nginx/graphite.error.log;

        location / {
                include uwsgi_params;
                uwsgi_pass graphite;
        }
}
sudo ln -s /etc/nginx/sites-available/graphite /etc/nginx/sites-enabled/graphite

vim /etc/uwsgi/apps-available/graphite.ini
[uwsgi]
processes = 2
socket = /run/uwsgi/app/graphite/socket
chdir = /usr/share/graphite-web
mount = /graphite=/usr/share/graphite-web/graphite.wsgi
file = graphite.wsgi
gid = www-data
uid = _graphite

sudo ln -s /etc/uwsgi/apps-available/graphite.ini /etc/uwsgi/apps-enabled/

Sous debian 10, python3 et conf uwsgi légèrment différente:

sudo apt install uwsgi-plugin-python3
vim /etc/uwsgi/apps-available/graphite.ini
[uwsgi]
uid = _graphite
gid = _graphite
buffer-size = 32768
chdir = /usr/share/graphite-web
env = DJANGO_SETTINGS_MODULE=graphite.settings
max-requests = 100
module = graphite.wsgi:application
plugins = python3
processes = 5
socket = /run/uwsgi/app/graphite/socket
touch-reload = /usr/lib/python3/dist-packages/graphite/wsgi.py

Ou bien avec apache :

sudo apt-get install apache2 libapache2-mod-wsgi

sudo a2dissite 000-default

sudo cp /usr/share/graphite-web/apache2-graphite.conf /etc/apache2/sites-available 

sudo a2ensite apache2-graphite

sudo service apache2 reload

Dans le firewall de la machine du graphite, on autorise:
  • La machine qui héberge COIN à attaquer sur le port tcp 80 (pour servir les graphes)
  • Le serveur VPN à attaquer sur le port tcp 2004 (pour alimenter les graphes en données)

Updated by Baptiste Berton over 2 years ago · 9 revisions