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[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 :
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 ]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", }, }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,localhostSECRET_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(',')])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'""" 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.



