# Installation sur RockyLinux — La Voix du Peuple **Cible** : VM RockyLinux 9.x **Port public** : HTTP 8080 (vous gérez le HTTPS en amont) **Port interne** : Gunicorn 8000 (localhost uniquement) **Répertoire d'installation** : `/opt/voix-du-peuple` **Utilisateur système** : `voixdupeuple` --- ## Table des matières 1. [Prérequis](#1-prérequis) 2. [Préparation du serveur](#2-préparation-du-serveur) 3. [Installation des paquets](#3-installation-des-paquets) 4. [Utilisateur système](#4-utilisateur-système) 5. [Clonage du dépôt](#5-clonage-du-dépôt) 6. [Base de données PostgreSQL](#6-base-de-données-postgresql) 7. [Environnement Python](#7-environnement-python) 8. [Configuration du domaine et variables d'environnement](#8-configuration-du-domaine-et-variables-denvironnement) 9. [Build du frontend](#9-build-du-frontend) 10. [Service Gunicorn (systemd)](#10-service-gunicorn-systemd) 11. [Nginx](#11-nginx) 12. [Firewall](#12-firewall) 13. [Vérification finale](#13-vérification-finale) 14. [Disaster Recovery](#14-disaster-recovery) 15. [Maintenance et mises à jour](#15-maintenance-et-mises-à-jour) --- ## 1. Prérequis - VM RockyLinux 9.x avec accès root (ou sudo) - 1 vCPU minimum, 1 Go RAM (2 Go recommandés) - 10 Go de disque - Accès réseau sortant (pour cloner le dépôt et télécharger les paquets) - Nom de domaine configuré (enregistrement DNS A pointant vers l'IP de la VM) - Clé SSH ou accès console --- ## 2. Préparation du serveur ```bash # Mise à jour complète du système dnf update -y # Outils de base dnf install -y curl wget git tar unzip vim # Activer le dépôt EPEL (nécessaire pour certains paquets) dnf install -y epel-release ``` --- ## 3. Installation des paquets ### Python 3.11 ```bash dnf install -y python3.11 python3.11-pip python3.11-devel python3.11 --version # doit afficher 3.11.x ``` ### Node.js 20 et pnpm ```bash # Dépôt Node.js 20 LTS curl -fsSL https://rpm.nodesource.com/setup_20.x | bash - dnf install -y nodejs # pnpm npm install -g pnpm pnpm --version node --version # doit afficher 20.x ``` ### PostgreSQL 15 ```bash # Dépôt officiel PostgreSQL dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm dnf -qy module disable postgresql dnf install -y postgresql15-server postgresql15 # Initialisation et démarrage postgresql-15-setup initdb systemctl enable postgresql-15 systemctl start postgresql-15 systemctl status postgresql-15 # doit afficher "active (running)" ``` ### Nginx ```bash dnf install -y nginx systemctl enable nginx ``` --- ## 4. Utilisateur système ```bash # Créer un utilisateur dédié sans shell de connexion useradd -r -s /sbin/nologin -d /opt/voix-du-peuple voixdupeuple # Répertoire de logs mkdir -p /var/log/voix-du-peuple chown voixdupeuple:voixdupeuple /var/log/voix-du-peuple ``` --- ## 5. Clonage du dépôt ```bash # Créer le répertoire d'installation mkdir -p /opt/voix-du-peuple cd /opt/voix-du-peuple # Cloner depuis votre Gitea git clone https://homegit.gyozamancave.fr/billisdead/la-voix-du-peuple.git . # (ou via SSH si une clé est configurée sur votre serveur Gitea) # Rendre le répertoire accessible à l'utilisateur système chown -R voixdupeuple:voixdupeuple /opt/voix-du-peuple ``` --- ## 6. Base de données PostgreSQL ```bash # Se connecter en tant que postgres su - postgres # Créer l'utilisateur et la base psql < Le port 8000 (Gunicorn) ne doit PAS être ouvert — il n'est accessible que depuis localhost via Nginx. --- ## 13. Vérification finale ```bash # Health check API (via Nginx) curl http://localhost:8080/health # {"status": "ok"} # Page principale curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/ # 200 # Depuis l'extérieur (remplacer par l'IP de votre VM) curl http://IP_DE_LA_VM:8080/health ``` **Checklist** : - [ ] `systemctl status postgresql-15` → active - [ ] `systemctl status voix-du-peuple-api` → active - [ ] `systemctl status nginx` → active - [ ] `curl http://localhost:8080/health` → `{"status":"ok"}` - [ ] L'interface s'affiche dans le navigateur sur `http://IP:8080` - [ ] Le flyer `/flyer` affiche le bon nom de domaine dans le QR code --- ## 14. Disaster Recovery ### 14.1 Sauvegarde de la base de données ```bash # Dump complet (à planifier via cron) pg_dump -U voix_user -h 127.0.0.1 voix_du_peuple > /opt/backups/voix_$(date +%Y%m%d_%H%M).sql # Automatiser avec cron (tous les jours à 3h) crontab -e # Ajouter : # 0 3 * * * pg_dump -U voix_user -h 127.0.0.1 voix_du_peuple > /opt/backups/voix_$(date +\%Y\%m\%d).sql ``` ```bash mkdir -p /opt/backups ``` ### 14.2 Restauration de la base de données ```bash # Stopper l'API pendant la restauration systemctl stop voix-du-peuple-api # Vider et restaurer la base psql -U voix_user -h 127.0.0.1 voix_du_peuple -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" psql -U voix_user -h 127.0.0.1 voix_du_peuple < /opt/backups/voix_20260401.sql # Redémarrer systemctl start voix-du-peuple-api ``` ### 14.3 Réinstallation complète depuis zéro Si la VM est perdue, répéter les étapes 1 à 13 puis restaurer la base depuis le dernier backup : ```bash psql -U voix_user -h 127.0.0.1 voix_du_peuple < /opt/backups/voix_DERNIER.sql ``` Les backups doivent être stockés **hors de la VM** (NFS, S3, objet distant…). ### 14.4 Rollback de code ```bash cd /opt/voix-du-peuple # Voir l'historique des commits git log --oneline -10 # Revenir à un commit précédent git checkout # Reconstruire le frontend si nécessaire bash scripts/set-domain.sh https://votredomaine.fr # Redémarrer l'API systemctl restart voix-du-peuple-api systemctl reload nginx ``` ### 14.5 En cas de service hors ligne ```bash # Diagnostic rapide systemctl status voix-du-peuple-api journalctl -u voix-du-peuple-api -n 50 systemctl status nginx journalctl -u nginx -n 20 systemctl status postgresql-15 # Relance forcée systemctl restart voix-du-peuple-api systemctl restart nginx ``` --- ## 15. Maintenance et mises à jour ### 15.1 Mise à jour du code ```bash cd /opt/voix-du-peuple # Récupérer les derniers commits depuis Gitea git pull origin main # Si les dépendances Python ont changé (requirements.txt modifié) .venv/bin/pip install -r artifacts/flask-api/requirements.txt # Si les dépendances Node ont changé (package.json modifié) pnpm install # Reconstruire le frontend (toujours faire après un pull) source .env && export VITE_APP_URL pnpm --filter @workspace/voix-du-peuple run build --config vite.config.selfhost.ts # Appliquer systemctl restart voix-du-peuple-api systemctl reload nginx ``` ### 15.2 Changer de nom de domaine ```bash cd /opt/voix-du-peuple bash scripts/set-domain.sh https://nouveaudomaine.fr systemctl reload nginx ``` Le QR code est régénéré automatiquement dans le build. ### 15.3 Changer la clé API Mistral ```bash vim /opt/voix-du-peuple/.env # Modifier MISTRAL_API_KEY systemctl restart voix-du-peuple-api ``` ### 15.4 Purger les contributions ```bash psql -U voix_user -h 127.0.0.1 voix_du_peuple ``` ```sql -- Tout purger (irréversible sans backup) TRUNCATE ideas; TRUNCATE synthesis; -- Supprimer seulement les refusées DELETE FROM ideas WHERE accepted = false; -- Forcer une re-synthèse au prochain envoi DELETE FROM synthesis; ``` ### 15.5 Consulter les logs ```bash # Logs de l'API en temps réel journalctl -u voix-du-peuple-api -f # Logs d'accès Gunicorn tail -f /var/log/voix-du-peuple/api-access.log # Logs d'erreur Gunicorn tail -f /var/log/voix-du-peuple/api-error.log # Logs Nginx tail -f /var/log/nginx/access.log tail -f /var/log/nginx/error.log ``` ### 15.6 Rotation des logs ```bash # Créer un fichier logrotate cat > /etc/logrotate.d/voix-du-peuple < backup.sql` | | Purger les données | `psql -U voix_user -h 127.0.0.1 voix_du_peuple -c "TRUNCATE ideas; TRUNCATE synthesis;"` | | Health check | `curl http://127.0.0.1:8080/health` |