Dans cet article, je vous explique étape par étape comment mettre en production un projet Django sur un serveur privé virtuel (VPS) sur Hostinger.
Un VPS est une solution d'hébergement qui permet une grande flexibilité à vos projets à un coût raisonnable. Il existe plusieurs types d'hébergements :
-
L'hébergement mutualisé, peu cher, mais ses ressources (CPU, bande passante, etc.) sont partagées et vous avez peu de contrôle sur l'environnement. Vous pouvez voir cela comme une colocation où tout est partagé
-
Le serveur dédié, assez cher, demande beaucoup de gestion, mais c'est comme avoir sa propre maison (voire son propre immeuble)
-
Le VPS (notre choix), coût raisonnable, vous avez des ressources dédiées, vous êtes libre de le gérer avec votre OS et de configurer votre environnement. Si un serveur dédié est un immeuble, e VPS, c'est comme avoir son propre appartement
Pour ce guide, nous utiliserons un VPS sur Hostinger. Cependant, les compétences que vous allez acquérir sont universelles, car un VPS reste un VPS, peu importe le fournisseur.
Vous êtes prêt ?
Attention
Pour la suite, il est préférable d'être suffisamment à l'aise avec les commandes Bash et Git, ainsi qu'avec Django.
Projet Django et Git/GitHub
Création du projet Django
Commençons par créer notre projet Django avec son environnement virtuel :
Préparation de l'environnement virtuel
Création du projet
À noter
Pensez aussi à installer Pillow, Django en a besoin pour le traitement des fichiers médias : pip install pillow
Nous allons créer un projet simple, qui va utiliser une base de données MySQL en production et SQLite en développement, ainsi que des fichiers médias et statiques :
- Création d'une application avec un modèle
Postqui permet de publier du texte avec un fichier média (penser à l'enregistrer dansadmin.py)
Application Blog et son modèle
- Création d'une vue pour afficher les articles, avec son template associé dans
blog/templates/blog/index.html
Vue et templates pour notre blog
- Insertion d'un fichier statique dans le template, en l'ajoutant dans l'application blog à l'emplacement suivant :
static/blog/logo/logo.png
Ajout d'un fichier statique
- Configurer les paramètres pour les fichiers statiques et médias
STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "mediafiles"
- Configurer le fichier d'URL du projet pour gérer les médias en local et ajouter la vue d'index
from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from blog.views import index
urlpatterns = [
path('admin/', admin.site.urls),
path('', index, name='index'),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
- Utilisation d'un fichier .env pour plus de flexibilité et ne pas inclure dans Git les données sensibles
Pour cette partie, j'utilise django-environ qui permet de récupérer des variables d'environnement. Nous allons créer le fichier .env, y insérer des variables, et les récupérer depuis les paramètres.
Fichier .env
Dans la capture d'écran ci-dessus, la clé Django n'est pas sécurisée, pensez à en générer une via le shell :
python manage.py shell
from django.core.management.utils import get_random_secret_key get_random_secret_key()
Nous ajouterons les lignes de code pour utiliser MySQL et des mesures de sécurité plus tard dans le guide.
Il est maintenant temps de faire les migrations :
python manage.py makemigrations python manage.py migrate
Testez votre application pour voir si tout fonctionne bien en local.
Il reste une dernière chose à faire avant de versionner notre projet sur GitHub : lister les dépendances en générant le fichier requirements.txt. Ce fichier garantit que nous aurons les mêmes dépendances sur le VPS en les installant toutes en même temps.
Voici la commande pour générer le fichier :
pip freeze > requirements.txt
Versionner votre projet avec Git et GitHub
Assurez-vous que Git soit bien installé sur votre système : git --version.
Créons le fichier .gitignore qui permet de spécifier à Git les fichiers et dossiers à ignorer. Par exemple, on ne voudrait pas versionner le fichier .env avec nos clés secrètes et nos mots de passe, et le dossier venv avec notre environnement virtuel qui n'a d'intérêt que localement.
Voici un exemple de fichier .gitignore basique :
# Ignore les fichiers de journalisation (logs) qui peuvent contenir des informations sensibles. *.log # Ignore le cache de bytecode généré par Python pour améliorer les performances. __pycache__/ # Ignore la base de données SQLite utilisée pour le développement local. db.sqlite3 # Ignore le dossier contenant les fichiers téléversés par les utilisateurs (images, documents...). mediafiles/ # --- Variables d'environnement --- # Ignore le fichier contenant les clés d'API, mots de passe et autres secrets. CRUCIAL pour la sécurité. .env # --- Environnements virtuels --- # Ignore les dossiers d'environnement virtuel qui contiennent les dépendances du projet. .venv/ env/ venv/ ENV/ # --- Fichiers des IDEs / Éditeurs de code --- # Ignore les fichiers de configuration spécifiques à l'éditeur de code (ici, PyCharm et VS Code). .idea/ .vscode/ # --- Système d'exploitation (macOS) --- # Ignore le fichier système invisible créé par le Finder de macOS dans les dossiers. .DS_Store # --- Fichiers compilés Python --- # Une règle plus générale pour ignorer les fichiers Python compilés (.pyc, .pyo, .pyd). *.py[cod]
Fichier .gitignore
Maintenant, il est temps de versionner notre code avec Git et GitHub :
- Créez un dépôt GitHub
Créer un dépôt sur GitHub
Vous pouvez choisir de créer un projet public ou privé, comme vous le souhaitez, dans mon cas, je laisse toutes les options par défaut.
- Ensuite, sur la page suivante vous n'avez plus qu'à copier dans le terminal de votre projet le code donné par GitHub
Code donné par GitHub
- Vous n'avez plus qu'à faire un commit de vos fichiers puis un push vers GitHub, si besoin, voici un bref rappel des commandes de base :
Personnellement, j'utilise l'interface graphique de VS Code pour mon cas 😊.
Git et GitHub avec VsCode
- Une fois cela fait, vous pourrez voir votre projet sur GitHub
Projet GitHub
Déployer sur un VPS
Acheter un VPS
Créez-vous un compte sur Hostinger, puis cliquez sur VPS dans le panel :
Panel Hostinger
Ensuite, vous pouvez suivre la procédure (voir les captures d'écran ci-dessous) :
-
Choisir un serveur KVM
-
Choisir la localisation du serveur (dans mon cas, la France)
-
Choisir l'OS (pour ce guide, je vais opter pour Ubuntu, la dernière version LTS)
-
Créer le mot de passe (ignorez l'option de clé SSH)
-
Cliquer sur suivant. Le scanner de logiciels est gratuit
-
Choisir la formule KVM1
-
Passer à la caisse
Après toutes ces étapes, il suffit de patienter quelques minutes et le VPS est créé.
Choix d'un VPS KVM
Choix de la localisation du serveur
Choix du système d'exploitation
Création d'un mot de passe
Scanner de logiciels malveillants gratuit
Choix du plan
Après toutes ces étapes, votre VPS est disponible depuis votre panel (ne faites pas attention, pour ma part j'ai deux KVM2) :
Panel VPS
Cliquez sur Gérer pour afficher les informations de votre VPS :
Information sur le VPS
Pour ce guide, nous allons nous concentrer sur deux éléments principaux :
-
L'adresse IP (1)
-
Le bouton pour accéder au terminal (2)
En cliquant sur Terminal du navigateur, vous êtes directement connecté en tant que l'utilisateur root :
Terminal du VPS
Mettre à jour et installer les éléments essentiels sur le VPS
Une fois dans le terminal du VPS, mettons-le à jour :
sudo apt update sudo apt upgrade
Il faut ensuite installer tous les outils nécessaires :
sudo apt install python3 python3-venv python3-pip git nginx
À noter
Lorsqu'on utilise sudo apt upgrade ou sudo apt install, le système vous demande de confirmer l'opération en appuyant sur la touche Y puis sur la touche Entrée.
Créer un utilisateur administrateur
À ce stade nous allons créer un utilisateur avec les droits sudo (super utilisateur), ce qui est plus sécurisé que de tout faire avec l'utilisateur root.
Voici la procédure à suivre :
-
Ajouter l'utilisateur avec
adduser tonnom(1) -
Choisir un mot de passe (2)
-
Vous pouvez renseigner vos informations ... ou non (3)
-
Acceptez (4)
-
Donnez les droits sudo à l'utilisateur avec
usermod -aG sudo tonnom(5)
Création d'un utilisateur
Donner les droits sur le répertoire et cloner le projet
Maintenant, en tant que root, donnons les droits à l'utilisateur que nous venons de créer (pour ma part je l'ai appelé gabriel) :
chown -R gabriel:www-data /var/www/
su - gabriel
cd /var/www/
git clone https://github.com/ton-repo/ton-projet.git
ls -la
Nous devons mettre en place le code de notre application. La première étape consiste à configurer les permissions du répertoire /var/www/ avec la commande chown, afin que votre utilisateur (gabriel) puisse y écrire et que le groupe du serveur web (www-data) puisse y lire. Par mesure de sécurité, basculez ensuite sur votre utilisateur non-privilégié avec su - gabriel. Une fois dans le bon répertoire (cd /var/www/), clonez votre projet depuis votre dépôt Git. Un rapide ls -la vous permettra de vérifier que le code source est bien en place avant de passer à la suite.
Dossier du projet Django
Le projet est cloné, mais il appartient uniquement à vous. Le problème est que le serveur nginx tourne sous l'utilisateur www-data. Changeons le groupe propriétaire :
sudo chgrp -R www-data /var/www/votreprojetdjango/ # pour ma part votreprojetdjango sera docvps
Pourquoi utiliser sudo ?
L'action de changer le groupe propriétaire pour un groupe système comme www-data nécessite d'être administrateur. Utiliser sudo, c'est comme mettre notre casquette d'administrateur 🧢.
À noter
Pourquoi créer un utilisateur sudo alors qu'il y a root ?
Un utilisateur qui a les droits sudo peut exécuter les mêmes commandes que root. La différence n'est pas dans le pouvoir final, mais dans la procédure pour l'obtenir.
En tant que root, vous avez les pleins pouvoirs en permanence. Pas besoin d'utiliser sudo, chaque commande est exécutée comme si on faisait sudo, une simple faute de frappe peut endommager le système.
En tant qu'utilisateur sudo (donc ici gabriel), l'état par défaut est inoffensif. Pour effectuer une action "dangereuse" il faut délibérément taper sudo avant la commande.
L'utilisateur root est la cible numéro 1 des pirates, donc en désactivant la connexion de root (ce que nous allons voir juste après) et en utilisant un nom d'utilisateur personnel vous les obligez à deviner le nom d'utilisateur et le mot de passe.
Désactiver la connexion directe de root
Une fois que notre utilisateur est créé, et qu'il fonctionne avec les droits sudo, nous allons interdire la connexion SSH à l'utilisateur root.
Attention
Assurez-vous que la commande fonctionne avec votre utilisateur : sudo whoami doit afficher root.
À partir de maintenant, nous utiliserons exclusivement notre utilisateur, et non plus l'utilisateur root.
Vérifiez si vous avez les droits root
Éditons le fichier de configuration SSH :
-
sudo nano /etc/ssh/sshd_config -
Défilez tout en bas avec la flèche du bas pour modifier la ligne :
PermitRootLogin yesenPermitRootLogin nopuisctrl + x,yetEntrée -
Redémarrez le service ssh :
sudo systemctl restart ssh
À noter
Vous remarquerez qu'après cette configuration, vous pouvez toujours vous connecter en root via la console accessible depuis le navigateur de Hostinger, c'est normal.
La console du navigateur n'est pas une connexion SSH, c'est un accès direct à votre serveur.
La connexion SSH est la porte d'entrée de votre serveur depuis internet. C'est elle qui est sécurisée avec PermitRootLogin no.
Utiliser la connexion ssh
Maintenant, utilisons une méthode de travail standard : la connexion ssh.
Commençons par créer une clé ssh sur votre ordinateur
ssh-keygen -t ed25519 -C "[email protected]"
ssh-keygen c'est l'outil de création, et l’algorithme utilisé est géré par ed. L'adresse mail sert d'étiquette. Appuyez sur Entrée pour l'emplacement par défaut, et créez un mot de passe pour plus de sécurité.
Voir la clé publique
Vous pouvez visualiser la clé publique avec la commande :
cat ~/.ssh/id_ed25519.pub # Puis copiez la clé
Coller la clé sur le vps
-
Retournez sur votre vps, connectez-vous avec votre utilisateur (pas en root !), et faites
mkdir -p ~/.sshpour créer le dossier .ssh s'il n'existe pas -
Ouvrez le fichier
nano ~/.ssh/authorized_keyset copiez l'intégralité de votre clé publique (adresse mail comprise).ctrl + xetypuisEntréepour sauvegarder -
Lancez ces deux commandes :
chmod 700 ~/.sshetchmod 600 ~/.ssh/authorized_keys.
Ces deux dernières commandes appliquent des permissions restrictives pour protéger les clés SSH. Même si je suis le seul utilisateur humain du serveur, de nombreux processus système tournent avec leurs propres comptes utilisateurs. De plus, SSH lui-même pourrait refuser de fonctionner si les permissions ne sont pas suffisamment restrictives, c'est un mécanisme de sécurité intégré et une bonne pratique.
Se connecter via ssh
Vous pouvez maintenant fermer le terminal du navigateur et utiliser votre terminal pour vous connecter via SSH :
-
Ouvrez un terminal sur votre ordinateur
-
Puis exécutez
ssh monutilisateur@adresseip, pour ma part :ssh [email protected](voir les captures ci-dessous) -
Si vous avez créé un mot de passe au moment de la création de la clé ssh, celui-ci vous sera demandé
Exemple pour mon vps
Exemple avec mon terminal
Nous allons pouvoir entrer dans le vif du sujet, et faire tourner notre projet Django !
Installation et configuration de MySQL
Installation et configuration
Une fois connecté en ssh sur votre terminal avec votre utilisateur, installez MySQL :
sudo apt install mysql-server
Une fois installé, exécutez la commande :
sudo mysql_secure_installation
Le script va vous poser une série de questions :
-
Le script vous demande d'activer ou non un composant qui force la création de mots de passe pour les utilisateurs MySQL
yest une bonne pratique pour empêcher de créer un utilisateur de base de données avec un mot de passe faible. Même s'il n'y a que vous sur le VPS, c'est une bonne pratique. -
Le niveau de politique du mot de passe
2(fort) est le meilleur choix, ça va de soi. -
Supprimer les utilisateurs anonymes
ypour supprimer l'utilisateur anonyme, important pour éviter les attaques. -
Interdire la connexion root à distance
Dans la capture d'écran ci-dessous, j'ai misnpar erreur, mais mettezy(j'ai recommencé la configuration de mon côté). On n'a pas besoin de se connecter à la base de données en tant que root depuis l'extérieur.
À noter
Quand nous parlons de root pour la configuration MySQL, il ne s'agit pas de root du VPS Ubuntu. L'utilisateur root de MySQL est le super-administrateur uniquement pour les bases de données, tandis que le root d'Ubuntu est le super-administrateur pour l'ensemble du serveur.
-
Supprimer la base de données de test
y, tout comme l'utilisateur anonyme, elle n'a pas sa place en production -
Recharger les tables de privilèges maintenant
ypour appliquer les règles de sécurité maintenant
Configuration de MySQL
Configuration de MySQL partie 2
-
Maintenant connectons-nous à MySQL :
sudo mysql. Nous sommes directement connectés, et aucun mot de passe n'a été demandé -
Attribuons un mot de passe à notre utilisateur root :
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'MonMotDePasse'; -
Appliquons les changements :
FLUSH PRIVILEGES; -
Quittons MySQL avec
exit; -
Essayons de se connecter comme avant :
sudo mysql. Ce qui ne fonctionne plus -
Connectez-vous avec
sudo mysql -u root -p -
Renseignez votre mot de passe
Attribuer un mot de passe à root
Création de la base de données
Une fois MySQL lancé, lancez cette commande pour créer la base de données : CREATE DATABASE docvps CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
docvpscorrespond au nom de la base de données -
CHARACTER SETetCOLLATEpermettent de dire à la base qu'elle peut stocker tous les types de caractères (accents, symboles, emojis...). C'est l'option qui est normalement par défaut mais ça ne coûte rien d'être explicite 😊
Ensuite, vous pouvez exécuter la commande SHOW DATABASES; pour voir s'afficher votre nouvelle base de données.
Affichage de la base de données
Maintenant, créons un utilisateur que Django utilisera. Appelons-le docvps_user :
CREATE USER 'docvps_user'@'localhost' IDENTIFIED BY 'MonMotDePasse';
L'utilisateur est créé, mais il n'a aucun droit. Attribuons-lui les droits de gérer notre nouvelle base de données :
GRANT ALL PRIVILEGES ON docvps.* TO 'docvps_user'@'localhost';
Pourquoi docvps.* ? On spécifie le nom de la base, puis après le . le nom de la table. Comme je veux donner les droits à l'utilisateur de gérer toutes les tables, on utilise *.
Il n'y a plus qu'à recharger les tables de privilèges, et nous pouvons quitter MySQL :
-
FLUSH PRIVILEGES; -
EXIT;
Notre base de données est fin prête !
Finaliser le projet Django
Il est temps de finaliser le projet Django. En production, nous utilisons toujours DEBUG=False. En sachant cela, modifions la partie base de données de notre fichier settings.py :
if DEBUG: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } else: DATABASES = { "default": { # Indique à Django quel "moteur" utiliser. Chaque SGBD (MySQL, PostgreSQL, etc.) a le sien. "ENGINE": "django.db.backends.mysql", # Le nom exact de la base de données que nous avons créée dans MySQL. "NAME": "docvps", # L'utilisateur que nous avons créé dans MySQL et qui a les droits sur cette base de données. "USER": "docvps_user", # Le mot de passe de l'utilisateur. Ici, on le charge depuis une variable d'environnement pour ne pas l'écrire en clair (bonne pratique de sécurité). "PASSWORD": env("DB_PASSWORD"), # L'adresse du serveur de base de données. Comme MySQL tourne sur le même VPS que Django, on utilise "localhost". "HOST": "localhost", # Le port de communication de MySQL. 3306 est le port par défaut. "PORT": "3306", # Permet de passer des options spécifiques à MySQL. "STRICT_TRANS_TABLES" est une bonne pratique qui rend MySQL plus strict. "OPTIONS": { "sql_mode": "STRICT_TRANS_TABLES", }, } }
De cette manière, en développement, nous utiliserons une base SQlite, et en production la base MySQL.
Enfin, générez le fichier qui liste vos dépendances si ce n'est pas encore fait :
pip freeze > requirements.txt
Il est maintenant temps de faire un commit de nos changements et de faire un push vers GitHub :
Pousser les changements sur GitHub
Retour sur le VPS
Mettre à jour le projet Django
De retour sur le VPS, rendez-vous dans le dossier du projet Django :
Retour dans le projet Django
Exécutez la commande git pull pour récupérer les changements sur le VPS afin d'intégrer la configuration pour la base de données. Il faut aussi penser à créer le fichier .env tout comme on l'a fait en développement, avec les configurations de production.
Tout d'abord, générez une clé secrète sécurisée pour Django depuis le shell si ça n'a pas été fait avant :
python manage.py shell
from django.core.management.utils import get_random_secret_key print(get_random_secret_key())
Ensuite, dans le dossier du projet Django, au même niveau que manage.py, nous allons créer le .env : nano .env.
.env sur le VPS
Pour la SECRET_KEY, j'utilise la clé générée précédemment, DEBUG est bien à False, je laisse ALLOWED_HOSTS vide pour le moment, et j'ai renseigné le mot de passe pour l'utilisateur de la base de données.
ALLOWED_HOSTS est vide pour le moment, car nous allons acheter un nom de domaine 😎 ! En effet, on va faire les choses bien : nom de domaine, et sécurité SSL.
Le but est d'avoir une mise en production complète :
-
Base de données solide
-
Nom de domaine
-
HTTPS
Allons acheter notre nom de domaine.
Acheter un nom de domaine
De retour sur votre panel Hostinger, allez dans Noms de domaine et Ajouter un nom de domaine.
Hostinger : Nom de domaine
Vous pouvez rechercher un nom de domaine disponible. Pour ma part, je tape pythonworkshop, vous pouvez mettre ce que vous voulez tant que c'est disponible. Pour vous entraîner, prenez l'extension la moins chère si vous le souhaitez.
Une fois l'achat terminé, il faut attendre une minute afin que le processus d'enregistrement se termine. Cliquez ensuite sur DNS/Serveurs de noms.
Domaine DNS
Tout en bas de la page, allez effacer la dernière ligne comme sur la capture ci-dessous :
Effacer le dernier enregistrement
Maintenant, revenez un peu plus haut pour ajouter l'adresse IP du VPS :
Ajout de l'adresse IP du VPS
Nous en avons terminé avec le nom de domaine. Facile non ?
Revenons sur notre VPS pour finaliser la configuration et enfin voir notre application Django fonctionner !
Finaliser le .env
nano .env dans le dossier du projet Django, et ajoutez le domaine à ALLOWED_HOSTS.
.env sur le VPS
Sécurisons le fichier pour que seul votre utilisateur puisse le lire et écrire : chmod 600 .env.
Installer les dépendances
Tout d'abord, il faut créer un environnement virtuel sur le VPS à la racine de votre projet : python3 -m venv venv.
Activez-le avec la commande source venv/bin/activate et installez les dépendances depuis le fichier requirements.txt :
pip install -r requirements.txt
Installation des dépendances
Pour l'environnement de production, il reste deux dépendances supplémentaires à installer :
pip install gunicorn mysqlclient
gunicorn est le serveur d'application et mysqlclient le connecteur qui permet à Django de communiquer avec la base MySQL.
À noter
Si jamais une erreur se produit, désactivez l'environnement virtuel et installez ces dépendances : sudo apt install pkg-config python3-dev default-libmysqlclient-dev build-essential.
Ensuite, vous pouvez de nouveau activer l'environnement virtuel et installer les dépendances pour notre projet avec pip install gunicorn mysqlclient.
Configuration de Gunicorn
Comme expliqué précédemment, Gunicorn est le serveur d'application. Nous allons devoir créer deux fichiers :
-
Un fichier gunicorn.service qui définit comment lancer notre application
-
Un fichier gunicorn.socket qui servira de canal de communication entre Gunicorn et Nginx
gunicorn.service
Pour créer le fichier au bon emplacement, lancez la commande :
sudo nano /etc/systemd/system/gunicorn.service
Pour ma part, voici à quoi il ressemble :
[Unit] Description=Gunicorn service for docvps project Requires=gunicorn.socket After=network.target [Service] User=gabriel Group=www-data WorkingDirectory=/var/www/docvps ExecStart=/var/www/docvps/venv/bin/gunicorn \ --workers 3 \ --access-logfile - \ --error-logfile - \ --bind unix:/run/gunicorn.sock \ project.wsgi:application [Install] WantedBy=multi-user.target
Fichier gunicorn.service
Ce fichier explique à Linux comment gérer Gunicorn :
-
Description=Gunicorn service for docvps project, une description simple -
Requires=gunicorn.socket, précise que ce fichier a besoin du fichier gunicorn.socket -
After=network.target, une sécurité banale pour que le service ne démarre qu'après que le réseau du serveur soit entièrement fonctionnel -
User=gabriel, le processus gunicorn sera lancé par l'utilisateur gabriel, ce qui est obligatoire pour lire les fichiers du projet -
Group=www-data, Nginx en aura besoin pour accéder aux fichiers (car Nginx est dans le groupe www-data) -
WorkingDirectory=/var/www/docvps, spécifie le dossier de notre projet -
ExecStart=/var/www/docvps/venv/bin/gunicorn, le chemin complet vers l'exécutable gunicorn qui est dans notre environnement virtuel-
--workers 3le nombre de processus Gunicorn à lancer, la règle générale c'est(2 * nombre de cœurs CPU) + 1 -
--access-logfile -et--error-logfile -indiquent à gunicorn où écrire ses logs, tous les logs seront consultables danssudo journalctl -u gunicorn.service -
--bind unix:/run/gunicorn.sock, crée une écoute sur le fichier socket Unix/run/gunicorn.sock -
project.wsgi:application, utilise le fichier wsgi.py
-
-
WantedBy=multi-user.target, permet de lancer le service automatiquement à chaque démarrage du serveur
gunicorn.socket
Ce fichier, plus simple, sert à créer le point d'écoute. Créons-le :
sudo nano /etc/systemd/system/gunicorn.socket
[Unit] Description=gunicorn socket for docvps project [Socket] ListenStream=/run/gunicorn.sock [Install] WantedBy=sockets.target
gunicorn.socket
-
Description=gunicorn socket for docvps project, une description simple -
ListenStream=/run/gunicorn.sock, écoute les connexions qui arrivent à cet endroit -
WantedBy=sockets.target, active le socket au démarrage du serveur
Nous pouvons maintenant configurer Nginx.
Nginx
Nginx est en première ligne et reçoit toutes les requêtes. C'est aussi lui qui sera chargé de servir les fichiers statiques. Créons-le fichier :
sudo nano /etc/nginx/sites-available/docvps
# Bloc 1: Redirection de WWW vers non-WWW server { listen 80; server_name www.pythonworkshop.fr; return 301 http://pythonworkshop.fr$request_uri; } # Bloc 2: Configuration principale du site server { listen 80; server_name pythonworkshop.fr; # Le domaine principal # Emplacement pour les fichiers statiques gérés par Nginx location /static/ { # 'alias' est correct ici si STATIC_ROOT est bien /var/www/docvps/staticfiles alias /var/www/docvps/staticfiles/; } # Emplacement pour les fichiers média (uploadés par les utilisateurs) location /media/ { alias /var/www/docvps/mediafiles/; } # Pour toutes les autres requêtes, on les passe à Gunicorn via le socket location / { proxy_pass http://unix:/run/gunicorn.sock; include proxy_params; # Contient la plupart des headers utiles } }
-
Le premier bloc sert uniquement à rediriger vers la version sans le www
-
Le bloc serveur principal (dans le bloc 2) gère le trafic pour pythonworkshop.fr
-
Ensuite, il faut spécifier les chemins vers les dossiers mediafiles et staticfiles
-
On spécifie à la fin le chemin vers le socket
nginx
Activer les services
Maintenant, il est temps d'activer les services gunicorn et nginx :
sudo systemctl daemon-reload
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket
Pour finir, activez le service Gunicorn via systemd. Rechargez la configuration avec sudo systemctl daemon-reload, puis démarrez et activez le socket avec sudo systemctl start gunicorn.socket et sudo systemctl enable gunicorn.socket pour le rendre opérationnel immédiatement et à chaque redémarrage du serveur
Pour gunicorn, tout est en ordre :
Le service gunicorn fonctionne
Pour nginx :
sudo ln -s /etc/nginx/sites-available/docvps /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
Pour finaliser la configuration du serveur web, activez votre site Nginx avec sudo ln -s. Validez la syntaxe de vos fichiers avec sudo nginx -t, et si tout est bon, redémarrez Nginx avec sudo systemctl restart nginx.
Configuration nginx
Activez votre environnement virtuel et exécutez la commande :
python manage.py collectstatic
Ensuite, exécutez les migrations :
python manage.py migrate
Tout fonctionne, créons un super utilisateur :
python manage.py createsuperuser
Lorsque je me rend sur le site (en http pour le moment), j'ai bien mon image statique :
Le site fonctionnant en HTTP
Allons écrire un article via l'administration. Pour ma part, l'adresse est la suivante : http://pythonworkshop.fr/admin/.
Administration django
Tout fonctionne comme prévu :
Notre site est en ligne
Activer les sécurités SSL/TLS avec Certbot et Django
Pour le moment, nous accédons à notre application via HTTP, mais ce que l'on veut c'est impérativement du HTTPS.
Ajoutons quelques sécurités pour la production. D'ailleurs, si vous faites cette commande : python manage.py check --deploy, vous aurez quelques avertissements 😅.
python manage.py check --deploy
Pour la production, il faut donc ajouter ces lignes dans le fichier de settings :
if not DEBUG: # HTTPS settings SESSION_COOKIE_SECURE = True # Force les cookies de session à être transmis uniquement via HTTPS CSRF_COOKIE_SECURE = True # Force les cookies CSRF à être transmis uniquement via HTTPS SECURE_SSL_REDIRECT = True # Redirige automatiquement toutes les requêtes HTTP vers HTTPS SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') # Détecte HTTPS derrière un proxy # HSTS settings (HTTP Strict Transport Security) SECURE_HSTS_SECONDS = 31536000 # Durée (1 an) pendant laquelle le navigateur doit utiliser HTTPS uniquement SECURE_HSTS_PRELOAD = True # Permet l'inclusion dans la liste de préchargement HSTS des navigateurs SECURE_HSTS_INCLUDE_SUBDOMAINS = True # Applique la politique HSTS à tous les sous-domaines
Nous allons de nouveau faire un commit pour cette modification, pousser les changements sur GitHub, et sur notre VPS exécuter git pull :
Pousser les changements sur GitHub
Récupérer les changements sur le VPS
Maintenant, installons et activons Certbot pour notre application. Désactivez votre environnement virtuel si ce n'est pas déjà fait.
Nous allons suivre cette partie de la documentation sur Hostinger : https://www.hostinger.com/fr/support/6865487-comment-installer-un-certificat-ssl-sur-un-vps-a-l-aide-de-certbot-chez-hostinger/.
Voici la liste des commandes :
sudo apt install python3 python3-venv libaugeas0
sudo python3 -m venv /opt/certbot/
sudo /opt/certbot/bin/pip install --upgrade pip
sudo /opt/certbot/bin/pip install certbot certbot-nginx
sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot
sudo certbot --nginx # Cette dernière commande va vous demander quelques informations
Demander un certificat SSL
-
Entrez votre adresse email
-
Acceptez les conditions
-
Partagez (ou pas) votre adresse email
-
Appuyez sur Entrée en laissant blanc afin de demander votre certificat SSL pour votre domaine
Le certificat SSL est active pendant 90 jours, mais vous pouvez le renouveller automatiquement avec cette commande :
echo "0 0,12 * * * root /opt/certbot/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && sudo certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
Maintenant, si je retourne sur mon site http://pythonworkshop.fr/, automatiquement je suis redirigé vers la version sécurisé https://pythonworkshop.fr/.
Sécuriser le VPS avec un Pare-feu
Pour davantage de sécurité, activons le pare-feu UFW qui est déjà installé sur le VPS :
sudo apt update
sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 'Nginx Full'
sudo ufw enable
Pour sécuriser le serveur avec UFW, on établit d'abord une politique par défaut : on bloque tout ce qui tente d'entrer (deny incoming) et on laisse sortir ce qui doit sortir (allow outgoing). Puis, on crée des exceptions pour les services nécessaires (allow ssh, allow 'Nginx Full'). Un sudo ufw enable finalise et active la protection.
Vous pouvez ensuite vérifier le statut de votre pare-feu :
sudo ufw status verbose
Pare-feu configuré
Bonne nouvelle, vous avez terminé ! 🧑💻😎