Le calvaire de l'erreur 502 mystérieuse
Vous savez ce moment où vous déployez fièrement votre application Flask sur votre serveur Alma Linux ? Tout fonctionne à merveille en développement, vous configurez nginx, Gunicorn, vous tapez votre URL et... BAM ! Erreur 502 Bad Gateway.
Vous passez des heures à vérifier vos configurations, vos permissions, vos logs. Rien. Puis, par hasard (ou désespoir), vous tapez sudo setenforce 0 et... miracle ! Ça fonctionne ! 🎉
Sauf que maintenant, vous êtes coincé. Votre site tourne avec SELinux désactivé, et au fond de vous, vous savez que ce n'est pas la solution. Vous avez juste repoussé le problème.
Bonne nouvelle : vous n'êtes pas seul dans cette galère, et il existe une vraie solution !
Pourquoi SELinux vous déteste (spoiler : c'est faux)
Bon, soyons honnêtes deux minutes. SELinux, c'est un peu comme ce prof de maths ultra-strict au lycée. Il dit non à tout par défaut, et vous devez prouver que vous méritez chaque permission. Frustrant ? Oui. Utile ? Absolument !
SELinux (Security-Enhanced Linux) n'est pas là pour vous rendre la vie difficile. C'est une couche de sécurité qui protège votre serveur contre les attaques, même si quelqu'un réussit à compromettre votre application. Le problème, c'est qu'il a ses propres règles, et notre stack Flask/Gunicorn/nginx les enfreint royalement.
Par défaut, SELinux va bloquer :
-
nginx qui essaie de causer avec votre socket Unix Gunicorn (comme si c'était louche 🙄)
-
Votre service systemd qui veut lancer Gunicorn depuis
/home(zone interdite !) -
Vos emails qui tentent de partir via SMTP (suspect, non ?)
Bref, tout ce qui fait qu'une application web moderne fonctionne. Sympa, non ?
Étape 0 : Comprendre ce qui se passe vraiment
Avant de foncer tête baissée dans les commandes, prenons 2 minutes pour comprendre ce qui coince.
Jouer au détective avec les logs SELinux
sudo ausearch -m avc -ts recent
Cette commande magique vous montre exactement ce que SELinux a bloqué récemment. Vous allez voir plein de lignes avec avc: denied, et c'est ça votre mine d'or. Chaque ligne vous dit ce que SELinux a refusé et pourquoi.
Vérifier ce que votre service raconte
sudo journalctl -u votre-service -n 50 --no-pager
Si vous voyez des Permission denied avec un code 203/EXEC, bingo ! C'est SELinux qui fait le garde du corps trop zélé.
La vraie solution : étape par étape
Allez, on arrête de tourner autour du pot. Voici comment régler le problème une bonne fois pour toutes.
Étape 1 : Déménager votre application (oui, vraiment)
Écoutez, je sais que vous aimez bien votre petit /home/votre-user/mon-app. C'est pratique, c'est là que vous développez, c'est familier. Mais SELinux déteste ce dossier pour les applications web.
La solution ? Déménager vers /var/www. C'est l'emplacement standard, SELinux est configuré pour le gérer, et vous allez économiser des heures de galère.
# Stop tout
sudo systemctl stop votre-service
# Créer le nouveau chez-vous de votre app
sudo mkdir -p /var/www
sudo mv /home/user/mon-app /var/www/mon-app
# Remettre les bonnes permissions
sudo chown -R user:user /var/www/mon-app
# Magie SELinux : restaurer les contextes
sudo restorecon -Rv /var/www/mon-app
Ce dernier restorecon ? C'est votre meilleur ami. Il dit à SELinux : "Hé, regarde, c'est une appli web légitime ici, sois cool avec elle."
Étape 2 : Configurer systemd comme un pro
Maintenant qu'on a déménagé, il faut dire à systemd où trouver notre app. Ouvrez (ou créez) /etc/systemd/system/votre-service.service :
[Unit]
Description=Gunicorn qui fait tourner votre super app Flask
After=network.target
[Service]
User=votre-user
Group=votre-groupe
WorkingDirectory=/var/www/mon-app
# Préparer le terrain pour le socket
ExecStartPre=/usr/bin/mkdir -p /var/run/mon-app
ExecStartPre=/usr/bin/chown votre-user:nginx /var/run/mon-app
ExecStartPre=/usr/bin/chmod 755 /var/run/mon-app
# Le chemin vers votre venv Python
Environment="PATH=/var/www/mon-app/venv/bin"
# Let's go !
ExecStart=/var/www/mon-app/venv/bin/gunicorn \
--workers 4 \
--worker-class sync \
--bind unix:/var/run/mon-app/mon-app.sock \
--umask 007 \
wsgi:app
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Petit détail important : le socket Unix va dans /var/run, pas dans votre dossier d'application. C'est l'emplacement standard pour ce genre de fichiers temporaires.
Rechargez systemd pour qu'il prenne en compte les changements :
sudo systemctl daemon-reload
Étape 3 : Apprendre à parler SELinux
Maintenant, on va dire à SELinux de se détendre un peu avec notre socket.
# Dire à SELinux que /var/run/mon-app contient des trucs httpd légitimes
sudo semanage fcontext -a -t httpd_var_run_t "/var/run/mon-app(/.*)?"
sudo restorecon -Rv /var/run/mon-app
# Autoriser nginx à se connecter (genre, c'est son job quoi)
sudo setsebool -P httpd_can_network_connect 1
Ces setsebool, ce sont des interrupteurs SELinux. Avec -P, le changement est permanent (sinon ça se réinitialise au reboot, et bonjour la surprise 😱).
Étape 4 : La politique personnalisée (le game changer)
OK, c'est LE truc qui va tout régler. On va créer une politique SELinux sur mesure pour votre app. Restez concentré, c'est simple mais faut suivre l'ordre :
# 1. Mode permissif temporaire (juste pour générer les erreurs)
sudo setenforce 0
# 2. Démarrer votre app pour qu'elle fasse ses bêtises
sudo systemctl restart votre-service
# 3. Laisser tourner quelques secondes
sleep 5
# 4. Tester votre site (pour déclencher toutes les violations possibles)
curl http://localhost
# 5. La magie : générer la politique à partir des violations
sudo ausearch -m avc -ts recent | audit2allow -M ma_politique
# 6. Jeter un œil à ce qui a été généré (optionnel mais instructif)
cat ma_politique.te
# 7. Installer la politique
sudo semodule -i ma_politique.pp
# 8. Remettre SELinux en mode strict
sudo setenforce 1
# 9. Redémarrer et croiser les doigts !
sudo systemctl restart votre-service
Ce qui se passe ici ? audit2allow analyse toutes les violations SELinux et crée automatiquement une politique qui les autorise. C'est comme si SELinux apprenait ce que votre app a le droit de faire.
Étape 5 : Configurer nginx (la cerise sur le gâteau)
Votre fichier nginx (/etc/nginx/conf.d/mon-app.conf) devrait ressembler à ça :
upstream app_server {
server unix:/var/run/mon-app/mon-app.sock fail_timeout=0;
}
server {
listen 80;
server_name mon-domaine.com;
location / {
proxy_pass http://app_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Testez et rechargez :
sudo nginx -t
sudo systemctl reload nginx
Les problèmes spécifiques qui vont vous rendre dingue
"Mes emails partent pas !"
Ah, celui-là, je l'ai vu venir. Votre app essaie d'envoyer un email de bienvenue et... rien. SELinux bloque le port SMTP.
# Autoriser les emails sortants
sudo setsebool -P httpd_can_sendmail 1
# Vérifier que c'est bien activé
getsebool httpd_can_sendmail
Si ça ne suffit pas (SELinux est têtu parfois) :
sudo ausearch -m avc -ts today | grep smtp | audit2allow -M politique_smtp
sudo semodule -i politique_smtp.pp
Pro tip : Utilisez le port 587 (STARTTLS) plutôt que 465. C'est plus moderne et SELinux l'aime mieux.
"Ma base de données externe refuse de se connecter !"
Pareil, SELinux bloque.
# Pour PostgreSQL ou MySQL/MariaDB distant
sudo setsebool -P httpd_can_network_connect_db 1
"Mon API externe me dit non !"
# Autoriser toutes les connexions réseau sortantes
sudo setsebool -P httpd_can_network_connect 1
Le moment de vérité : est-ce que ça marche ?
Checklist de victoire
# 1. SELinux est bien en mode strict ?
getenforce
# Doit afficher "Enforcing"
# 2. Votre service tourne ?
sudo systemctl status votre-service
# Doit être "active (running)" en vert
# 3. Le socket existe et a le bon contexte ?
ls -lZ /var/run/mon-app/
# Doit montrer httpd_var_run_t
# 4. Plus de violations SELinux ?
sudo ausearch -m avc -ts recent
# Devrait être vide (ou presque)
# 5. Le site répond ?
curl -I http://votre-domaine.com
# Doit retourner un beau 200 OK
Si tout est vert, félicitations ! 🎉 Vous avez dompté SELinux !
La boîte à outils du debugger SELinux
Pour les fois où ça ne marchera pas du premier coup (soyons réalistes) :
# Voir le mode actuel
getenforce
# Passer en permissif (JUSTE pour débugger, hein !)
sudo setenforce 0
# Revenir en mode strict
sudo setenforce 1
# Voir toutes les violations du jour
sudo ausearch -m avc -ts today
# Statut complet de SELinux
sestatus
# Tous les booléens httpd (pratique pour trouver ce qui manque)
getsebool -a | grep httpd
# Vos modules de politique personnalisés
sudo semodule -l | grep votre-app
# Supprimer un module (si vous avez fait une bêtise)
sudo semodule -r nom_du_module
L'architecture finale (ce à quoi vous devez arriver)
/var/www/mon-app/
├── venv/ # Votre environnement virtuel Python
├── app/ # Le code de votre app
├── wsgi.py # Le point d'entrée
├── requirements.txt
└── .env # Vos variables d'environnement
/var/run/mon-app/
└── mon-app.sock # Le socket Unix (créé au démarrage)
/etc/systemd/system/
└── mon-app.service # Votre fichier service
/etc/nginx/conf.d/
└── mon-app.conf # La config nginx
Propre, organisé, et surtout : compatible SELinux ! 🎯
Les règles d'or à ne jamais oublier
-
JAMAIS de
setenforce 0en production - C'est pour débugger seulement -
Toujours dans
/var/www- Votre app n'a rien à faire dans/home -
Sauvegardez vos fichiers
.te- Si vous devez recréer votre serveur, vous me remercierez -
Testez en permissif d'abord - Puis créez la politique, puis passez en enforcing
-
restoreconaprès chaque modif de fichiers - Ça prend 2 secondes et ça évite 2 heures de debug -
Préférez les booléens aux politiques custom - Quand c'est possible
-
Surveillez vos logs régulièrement - Les surprises, c'est bien pour les anniversaires, pas pour les serveurs
Automatiser tout ça (parce qu'on est fainéants, et c'est bien)
Créez un petit script deploy.sh pour vos futurs déploiements :
#!/bin/bash
APP_DIR="/var/www/mon-app"
SERVICE_NAME="mon-app"
echo "🚀 C'est parti pour le déploiement !"
cd $APP_DIR
# Pull les derniers changements
git pull origin main
# Activer le venv
source venv/bin/activate
# MAJ des dépendances
pip install -r requirements.txt
# Remettre les contextes SELinux en place
sudo restorecon -Rv $APP_DIR
# Redémarrer
sudo systemctl restart $SERVICE_NAME
# Vérifier que tout roule
sudo systemctl status $SERVICE_NAME
echo "✅ C'est dans la boîte !"
Rendez-le exécutable :
chmod +x deploy.sh
Et hop, déploiement en une commande ! 🚀
Conclusion : vous avez survécu à SELinux !
Voilà, vous savez maintenant comment faire cohabiter Flask, Gunicorn, nginx et SELinux sans vous arracher les cheveux. Oui, c'est un peu technique. Oui, ça prend du temps au début. Mais une fois que c'est en place, vous avez une application sécurisée qui tourne sur un serveur correctement configuré.
SELinux n'est pas votre ennemi. C'est juste un garde du corps hyper-parano qui a besoin qu'on lui explique qui a le droit de faire quoi. Une fois qu'il a compris, il fait son job en silence et protège votre serveur comme un chef.
Les points essentiels à retenir :
-
Déménagez vers
/var/www(vraiment, faites-le) -
Configurez les contextes SELinux correctement
-
Utilisez
audit2allowpour créer des politiques sur mesure -
Activez les booléens nécessaires
-
Ne désactivez JAMAIS SELinux en prod (je l'ai déjà dit mais ça mérite d'être répété)
Et rappelez-vous : chaque application est différente. Vous aurez peut-être besoin d'ajustements spécifiques. C'est normal. Gardez ausearch sous la main, générez des politiques au fur et à mesure, et documentez ce que vous faites.
Vous avez galéré avec SELinux ? Partagez votre expérience en commentaire ! Et si cet article vous a sauvé la mise, n'hésitez pas à le partager avec vos collègues qui rament avec la même erreur 502 mystérieuse. 😉
Bon courage, et que le SELinux soit avec vous ! 🐧✨

Laisser un commentaire