Partie 6 : Mise en Prodution


Serveur Gunicorn

Actuellement, le site fonctionne en passant par le serveur embarqué de Django en tapant, en environnement virtuel, la commande : python manage.py runserver 0.0.0.0:8000 . Il convient de ne plus passer par ce serveur embarqué et d’avoir son propre serveur. Le choix porte sur Gunicorn

Installation de Gunicorn

  • Se mettre en environnement virtuel : $ source /home/pi/djangoTIC/venv/bin/activate
  • Installer Gunicorn : $ pip install gunicorn

Créer un service systemd

  • Créer en écriture le fichier : $ sudo nano /etc/systemd/system/django-ticserver.service
  • Copier/coller le code suivant :
    /etc/systemd/system/django-ticserver.service
    [Unit]
    Description=Django TIC Web Server
    After=network.target
    
    [Service]
    Type=simple
    User=pi
    WorkingDirectory=/home/pi/djangoTIC/ticServer
    Environment="PATH=/home/pi/djangoTIC/venv/bin"
    ExecStart=/home/pi/djangoTIC/venv/bin/gunicorn --bind 0.0.0.0:8000 --workers 2 ticServer.wsgi:application
    Restart=always
    RestartSec=10
    
    [Install]
    WantedBy=multi-user.target
  • Sauvegarder et quitter

Lancer le service

  • Recharger et lancer :
    $ sudo systemctl daemon-reload
    $ sudo systemctl enable django-ticserver
    $ sudo systemctl start django-ticserver
  • Vérifier le service :
    $ sudo systemctl status django-ticserver

Mémento de commandes utiles :

# Voir les logs en temps réel
sudo journalctl -u django-ticserver -f
sudo journalctl -u tic-capture -f

# Arrêter/Démarrer
sudo systemctl stop django-ticserver
sudo systemctl start django-ticserver

# Redémarrer
sudo systemctl restart django-ticserver

# Désactiver le démarrage auto
sudo systemctl disable django-ticserver

Installer WhiteNoise

Avec l’installation de Gunicorn, les fichiers statiques ne vont pas nécessairement être servis correctement. Whitenoise permet de pallier ce problème.

Installation

  • Se mettre en environnement virtuel
  • Installer whitenoise : $ pip install whitenoise

Modifier settings.py

  • Ouvrir le fichier en écriture : $ nano ~/djangoTIC/ticServer/ticServer/settings.py
  • Chercher la liste MIDDLEWARE
  • Ajouter :
    /etc/systemd/system/django-ticserver.service
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'whitenoise.middleware.WhiteNoiseMiddleware',  # ← Ajouter cette ligne juste après SecurityMiddleware
        'django.contrib.sessions.middleware.SessionMiddleware',
        # ... le reste des middlewares
    ]
  • Au niveau de STATIC_URL = 'static/'
  • Ajouter deux entrées supplémentaires :
    /etc/systemd/system/django-ticserver.service
    STATIC_URL = '/static/'     # conserver cette ligne
    
    # à ajouter
    
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')  
    STORAGES = {
        "default": {
            "BACKEND": "django.core.files.storage.FileSystemStorage",
        },
        "staticfiles": {
            "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
        },
    }
  • Enregistrer et fermer
  • Relancer le serveur : $ sudo systemctl restart django-ticserver

Passer en production

En développement, le paramètre DEBUG de settings.py est fixé à True . Cela permet de voir rapidement un dysfonctionnement au cas où une erreur serait renvoyée par le serveur.
Si on ne passe pas la valeur de DEBUG à False , un risque d’intrusion dans le réseau local existe, surtout si on décide d’accéder aux données du Linky depuis l’extérieur du réseau. À la limite, la Raspberry peut être détournée de sa fonction initiale ; un code malveillant peut être installé et la Raspberry servir de relais à d’autres attaques.

Créer une nouvelle SECRET_KEY

  • Installer python-decouple en environnement virtuel : $ pip install python-decouple
  • Créer une nouvelle clé : $ python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'

Créer un fichier d’environnement

  • Afin de ne pas coder en dur la nouvelle clé SECRET_KEY qu’on va créer, on la copie dans un fichier .env à la racine du site
  • Créer et ouvrir en écriture .env : $ nano ~/djangoTIC/ticServer/.env
  • Écire le fichier :
    djangoTIC/ticServer/.env
    SECRET_KEY=votre-cle-generee-ici
    DEBUG=False
    ALLOWED_HOSTS=192.168.x.x,localhost
  • Aucun espace avec les = ou avec les virgules
  • Remplacer x.x par l’adresse IP de la Raspberry (par exemple : 192.168.1.120)

Modifier settings.py

  • Ouvrir en écriture : $ nano ~/djangoTIC/ticServer/ticServer/settings.py
  • Ajouter ou modifier les éléments suivants :
    ticServer/ticServer/settings.py
    from decouple import Config, RepositoryEnv    #pour la production et le masquage des données
    # Spécification du chemin exact de .env
    config = Config(RepositoryEnv(BASE_DIR / '.env'))
    SECRET_KEY = config('SECRET_KEY')
    DEBUG = config('DEBUG', default=False, cast=bool)
    
    ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=lambda v: [s.strip() for s in v.split(',')])
  • Le fichier settings.py final est le suivant :
    djangoTIC/ticServer.env
    """
    Django settings for ticServer project.
    
    Generated by 'django-admin startproject' using Django 5.1.7.
    
    For more information on this file, see
    https://docs.djangoproject.com/en/5.1/topics/settings/
    
    For the full list of settings and their values, see
    https://docs.djangoproject.com/en/5.1/ref/settings/
    """
    
    from pathlib import Path
    import os
    from decouple import Config, RepositoryEnv    #pour la production et le masquage des données
    
    # Build paths inside the project like this: BASE_DIR / 'subdir'.
    BASE_DIR = Path(__file__).resolve().parent.parent
    
    # Spécification du chemin exact de .env
    config = Config(RepositoryEnv(BASE_DIR / '.env'))
    
    # Quick-start development settings - unsuitable for production
    # See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
    
    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = config('SECRET_KEY')
    
    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = config('DEBUG', default=False, cast=bool)
    
    ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=lambda v: [s.strip() for s in v.split(',')])
    
    # Application definition
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'ticapp.apps.TicappConfig',
    ]
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'whitenoise.middleware.WhiteNoiseMiddleware', 
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
    ROOT_URLCONF = 'ticServer.urls'
    
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [BASE_DIR / 'templates'],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    
    WSGI_APPLICATION = 'ticServer.wsgi.application'
    
    
    # Database
    # https://docs.djangoproject.com/en/5.1/ref/settings/#databases
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
            'TIME_ZONE': 'Europe/Paris',
        }
    }
    
    
    # Password validation
    # https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
    
    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]
    
    
    # Internationalization
    # https://docs.djangoproject.com/en/5.1/topics/i18n/
    
    LANGUAGE_CODE = 'fr'
    
    TIME_ZONE = 'Europe/Paris'
    
    USE_I18N = True
    
    USE_TZ = True
    
    
    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/5.1/howto/static-files/
    
    STATIC_URL = '/static/'
    
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    
    STORAGES = {
        "default": {
            "BACKEND": "django.core.files.storage.FileSystemStorage",
        },
        "staticfiles": {
            "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", 
       },
    }
    
    # Default primary key field type
    # https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
    
    DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

Reconfigurer les fichiers statiques

  • Après ces modifications, il faut collecter les fichiers statiques
  • Dans ~/djangoTIC/ticServer lancer la commande : $ python manage.py collectstatic --noinput
  • Cette commande va créer un dossier staticfiles à la racine du site. C’est ce dossier qui va servir les fichiers statiques au site en production.