
Configuration d'un site avec Apache, Django & Gunicorn
Bonjour !
Aujourd'hui je vais expliquer un peu comment configurer apache2 et un site Django sur une machine tournant sous Debian pour avoir un joli site web tout beau tout propre.
Un petit peu de contexte ?
Je bosse avec Django au boulot. On met nos sites en ligne via l'hébergeur Alwaysdata (qui offre un pack gratuit à vie avec 100Mo de stockage, c'est vraiment cool si vous voulez vous lancer dans la création de votre site web), mais de mon côté je préfère auto-héberger mes sites.
Pour ce faire, je dispose d'un magnifique Dell Optiplex fx160 acheté 50€ en 2017 sur Ebay. Il fait tourner le site sur lequel vous êtes, mon instance Nextcloud perso (synchronise mes photos entre mon smartphone et mon ordi, héberge un calendrier et mes notes), et quelques autres sites.
Ce serveur n'a rien d'impressionnant :
- Processeur Intel Atom 330 @ 1.6GHz
- 3 Go de RAM
- Un vieux disque dur de 500Go
Et c'est tout !
Mais ça suffit pour ce que je veux faire : héberger quelques sites web peu visités, tout en sachant où sont stockées les données. C'est pas grave si lors d'une coupure de courant le serveur n'est plus alimenté : mes sites web ne sont plus disponibles pendant quelques heures, c'est tout. Personne n'en est encore mort.
DONC ! Je fais du Django au boulot, je voulais partager des photos avec des gens simplement sur internet, je me suis donc dit que j'allais faire mon propre site de galerie.
Long story short, je l'ai créé, il marche, c'est cool.
Mais comment qu'on fait pour l'héberger ? Alwaysdata dispose d'une interface d'administration où on peut créer un projet de type "Python", et remplir des variables d'environnement/choisir le script à lancer avec uwsgi. Mais moi sur mon pov' ptit Debian tout lent, comment que je peux faire pour lancer mon site (et le relancer automatiquement lors d'un reboot) ?
C'est ce qu'on va voir :)
Installation du site Django
Le repo étant bien fait (je parle pas des tests inexistants mais plutôt du fichier README qui est assez explicite), je lance les commandes indiquées dans le tuto DEPOY.md (le fichier est présent dans un autre projet mais c'est la même chose faut juste changer deux/trois trucs) sur mon serveur :
cd <dossier où installer django-simple-gallery> # dans mon cas, dans /var/www
git clone https://gitlab.com/sodimel/django-simple-gallery.git
cd django-simple-gallery
sudo apt install pymemcache
echo """
export DJANGO_SETTINGS_MODULE=website.settings.base
export DJANGO_SIMPLE_GALLERY_SECRET_KEY="your secret key"
export DJANGO_SIMPLE_GALLERY_ALLOWED_HOSTS="your.url.here"
export DJANGO_SIMPLE_GALLERY_STATIC_ROOT="/var/www/django-simple-gallery/static/"
export DJANGO_SIMPLE_GALLERY_MEDIA_ROOT="/var/www/django-simple-gallery/media/"
export DJANGO_SIMPLE_GALLERY_SITE_NAME="Le nom du site ici"
export DJANGO_SIMPLE_GALLERY_TIME_ZONE="CET"
""" >> .env
source .env
python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install -r requirements.txt
python3 manage.py migrate
python3 manage.py createsuperuser
python3 -m pip install gunicorn
Voilà, ce tas de commandes a permis de faire tout ça :
- télécharger le repo contenant le site sur le serveur
- installer
pymemcache
(une dépendance d'un truc que j'utilise pour créer des thumbnails pour les vues en liste) - créer un fichier
.env
contenant les variables d'environnement dont le site a besoin - créer un "environnement virtuel" (virtualenvironment), qui permet d'installer les packages Python dedans plutôt que dans le dossier de l'utilisateur (ou pire, du système). Ça permet de pas mélanger les packages ; si j'a un autre site Django avec une autre version de Django, bah j'aurais les deux versions de Django installées dans deux dossiers différents et il n'y aura pas de problème.
- Installer les dépendances (les packages Python) dans le virtualenvironment.
- Lancer les migrations (crée un fichier
db.sqlite
et crée les tables qui vont servir à stocker les données). - Créer un super utilisateur (ce compte a tous les droits sur le site, il vous permettra de vous connecter à l'interface d'administration du site Django).
- Installer
gunicorn
, qui est un package permettant de lancer un serveur web (il supporte des tas de frameworks out of the box, comme Django par exemple :)).
Notre site est donc installé et on a tout ce qu'il nous faut.
On peut tester que le site démarre bien en lançant la commande suivante :
python3 -m gunicorn website.wsgi
Configuration Apache
Voici la liste des choses qu'il va falloir que Apache apprenne à gérer :
- Communiquer avec
gunicorn
. - Permettre un accès aux fichiers statiques et aux médias.
- Rediriger l'accès http vers l'accès https (facultatif).
Et voici comment faire :
D'abord, activer le module proxy_http
qui permettra d'accéder directement aux fichiers statiques et aux médias :
sudo a2enmod proxy_http
Puis, créer un fichier de config à mettre dans /etc/apache2/sites-enabled/
:
<VirtualHost *:80>
ServerName XXX
Redirect permanent / https://XXX/
</VirtualHost>
<VirtualHost *:443>
ServerName XXX
ServerAdmin XXX
ProxyPreserveHost On
ProxyPass /static/ !
ProxyPass /media/ !
ProxyPass / http://localhost:8000/
ProxyPassReverse / http://localhost:8000/
RequestHeader set X-FORWARDED-PROTOCOL ssl
RequestHeader set X-FORWARDED-SSL on
</VirtualHost>
Nice. On a une config qui fonctionne, il nous reste à pouvoir lancer le site automatiquement lors du démarrage de l'ordi (et à pouvoir le démarrer/stopper manuellement aussi).
Lancer le site via un service
On va pouvoir créer un joli petit fichier gallery.service
dans /lib/systemd/system/
:
[Unit]
Description=Start gunicorn daemon, run django simple gallery instance.
After=network.target
[Service]
Type=simple
User=username
ExecStart=/path/to/your/file/launch_server.sh
PrivateTmp=true
[Install]
WantedBy=multi-user.target
On recharge ensuite la liste des services pour que l'ordi découvre ce nouveau fichier qu'on vient de créer : sudo systemctl daemon-reload
, et on active le service pour faire en sorte qu'il démarre automatiquement lors d'un reboot : sudo systemctl enable gallery.service
.
Mais vous voyez le path dans ExecStart
?
Oui ?
Bah c'est le chemin vers un fichier bash
qu'il vous faut également créer, et qui se chargera de démarrer le site en faisant tout bien comme il faut (sourcer le .venv, sourcer le .env, lancer le site sur le bon port).
Un dernier fichier pour la route (en bash)
Voici sans plus tarder le contenu de ce fichier launch_server.sh
:
#!/bin/bash
# Edit LOGFILE path if you want, do not forget to create the folder before launching this file.
# Also, you can set your number of workers (the -w 3 below) to [nb of physical cores * 2 + 1] (source: https://docs.gunicorn.org/en/stable/design.html#how-many-workers).
cd /path/to/your/project/
LOGFILE=/var/log/gunicorn/gallery.log
. .venv/bin/activate
source .env
python3 -m gunicorn website.wsgi -w 3 --bind=localhost:8000 --log-level=info --log-file=$LOGFILE 2>>$LOGFILE
Et voici ce que ce fichier réalise pour vous automatiquement :
- se rend dans le dossier où est situé votre projet
- source le
.venv
- source le
.env
- lance une commande méga compliquée qu'on peut résumer ainsi :
- lancer un serveur web avec gunicorn
- à partir d'un fichier présent dans le repo et situé au path suivant :
website/wsgi.py
- utilisant 3 workers (
-w 3
) qui vont servir les requêtes - accessible sur
localhost
et le port8000
(heureusement la ligneProxyPass / http://localhost:8000/
de la config Apache permet justement de joindre cette URL depuis l'extérieur) - lister les erreurs de type
info
et plus (on n'affiche pas les logs de debug, mais on affiche info, warning, error & critical) - et les stocker dans un fichier situé ici :
/var/log/gunicorn/gallery.log
Voilà. On a tout.
On peut démarrer notre site :
sudo systemctl start gallery.service
Et si tout va bien, la magie opère et votre site est accessible via votre ip (il vous faut ajouter une entrée dans votre fichier de zone DNS du type gallery 3600 IN A <MY_IP>
pour avoir un accès au site via gallery.monsite.ext
).
J'espère que ce petit tuto rapide vous a plu, je l'ai fait parce que je trouvais pas de manière de faire "artisanale" (à la main) pour déployer un site Django avec Apache2 & Gunicorn, et que j'aime bien faire des trucs à la main pour comprendre comment ça marche (avant qu'un jour peut-être je ressente le besoin d'automatiser tout ça si ça devient trop compliqué).
N'hésitez pas à laisser vos commentaires sur le journal du hacker ou directement sur mastodon, où j'ai posté des liens vers ce billet.
À bientôt :)