cover for Configuration d'un site avec Apache, Django & Gunicorn

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 :

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 :

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 :

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 :

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 :)