bc6bd3f9d7
Supprimés : - replit.md — doc Replit obsolète - docs/GITEA_TUTO.md — tuto push Replit → Gitea (obsolète) - artifacts/api-server/ — serveur TypeScript mort, remplacé par Flask - artifacts/voix-du-peuple/vite.config.selfhost.ts — fusionné dans vite.config.ts Nettoyés : - ai_agent.py — fallback Replit AI supprimé (Mistral + OpenAI-compatible suffisent) - vite.config.ts — plugins @replit/* retirés, PORT optionnel (défaut 5173) - package.json + pnpm-workspace.yaml — @replit/* retirés du catalog et des deps - badge.tsx + button.tsx — commentaires // @replit supprimés - README.md, DEPLOIEMENT.md, DAT.md, DEX.md, WIKI.md — références Replit remplacées Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
10 KiB
10 KiB
Guide d'auto-hébergement — La Voix du Peuple
RockyLinux 9 (ou RHEL 9, AlmaLinux 9)
Architecture
Internet
│
▼
[Nginx] ─── /api/* ──► [Gunicorn + Flask] ──► [PostgreSQL]
│ │
└─── /* ──► [React SPA] └──► [OpenAI API]
(fichiers statiques)
- Frontend : React + Vite, servi comme fichiers statiques par Nginx
- Backend : Flask + Gunicorn (4 workers), accessible uniquement via Nginx
- Base de données : PostgreSQL 15+
- IA : Mistral AI (MISTRAL_API_KEY requis)
Prérequis
# Mettre à jour le système
sudo dnf update -y
# Outils de base
sudo dnf install -y git curl wget epel-release
1. Installer les dépendances système
Python 3.11
sudo dnf install -y python3.11 python3.11-pip python3.11-devel
python3.11 --version # doit afficher Python 3.11.x
Node.js 20 (LTS)
curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
sudo dnf install -y nodejs
node --version # doit afficher v20.x.x
pnpm
npm install -g pnpm
pnpm --version
PostgreSQL 15
sudo dnf install -y postgresql15-server postgresql15
sudo /usr/pgsql-15/bin/postgresql-15-setup initdb
sudo systemctl enable --now postgresql-15
Nginx
sudo dnf install -y nginx
sudo systemctl enable nginx
2. Configurer PostgreSQL
# Connexion en tant que postgres
sudo -u postgres psql
-- Dans psql :
CREATE USER voixdupeuple WITH PASSWORD 'CHANGEME_MOT_DE_PASSE_FORT';
CREATE DATABASE voixdupeuple OWNER voixdupeuple;
GRANT ALL PRIVILEGES ON DATABASE voixdupeuple TO voixdupeuple;
\q
Éditez /var/lib/pgsql/15/data/pg_hba.conf pour autoriser la connexion locale par mot de passe :
# Remplacez "ident" par "md5" sur la ligne 127.0.0.1/32 :
host all all 127.0.0.1/32 md5
sudo systemctl restart postgresql-15
# Test de connexion
psql -U voixdupeuple -h 127.0.0.1 -d voixdupeuple -c "\dt"
3. Créer l'utilisateur système
sudo useradd -r -s /bin/bash -d /opt/voix-du-peuple voixdupeuple
sudo mkdir -p /opt/voix-du-peuple
sudo chown voixdupeuple:voixdupeuple /opt/voix-du-peuple
4. Cloner le dépôt depuis Gitea
sudo -u voixdupeuple bash -c "
cd /opt
git clone https://votre-gitea.example.com/utilisateur/voix-du-peuple.git voix-du-peuple
"
5. Configurer les variables d'environnement
sudo -u voixdupeuple bash -c "
cp /opt/voix-du-peuple/.env.example /opt/voix-du-peuple/.env
"
# Éditer le fichier .env
sudo nano /opt/voix-du-peuple/.env
Remplissez au minimum :
DATABASE_URL=postgresql://voixdupeuple:CHANGEME_MOT_DE_PASSE_FORT@127.0.0.1:5432/voixdupeuple
OPENAI_API_KEY=sk-VOTRE_CLE_OPENAI
SESSION_SECRET=GENEREZ_UNE_VALEUR_ALEATOIRE_ICI
PORT=8000
FLASK_ENV=production
Générez le SESSION_SECRET :
python3.11 -c "import secrets; print(secrets.token_hex(32))"
Sécurisez le fichier :
sudo chmod 600 /opt/voix-du-peuple/.env
sudo chown voixdupeuple:voixdupeuple /opt/voix-du-peuple/.env
6. Installer les dépendances Python
sudo -u voixdupeuple bash -c "
cd /opt/voix-du-peuple
python3.11 -m venv .venv
.venv/bin/pip install --upgrade pip
.venv/bin/pip install -r artifacts/flask-api/requirements.txt
"
7. Initialiser la base de données
sudo -u voixdupeuple bash -c "
cd /opt/voix-du-peuple/artifacts/flask-api
source /opt/voix-du-peuple/.env
export DATABASE_URL OPENAI_API_KEY SESSION_SECRET FLASK_ENV PORT
/opt/voix-du-peuple/.venv/bin/python3 -c '
from database import init_db
init_db()
print(\"Base de données initialisée.\")
'
"
8. Construire le frontend React
sudo -u voixdupeuple bash -c "
cd /opt/voix-du-peuple
pnpm install --frozen-lockfile
cd artifacts/voix-du-peuple
pnpm exec vite build --config vite.config.selfhost.ts
"
Les fichiers statiques sont générés dans artifacts/voix-du-peuple/dist/public/.
9. Configurer le service systemd (Gunicorn)
# Créer le répertoire de logs
sudo mkdir -p /var/log/voix-du-peuple
sudo chown voixdupeuple:voixdupeuple /var/log/voix-du-peuple
# Copier le fichier de service
sudo cp /opt/voix-du-peuple/deploy/voix-du-peuple-api.service \
/etc/systemd/system/voix-du-peuple-api.service
# Activer et démarrer
sudo systemctl daemon-reload
sudo systemctl enable --now voix-du-peuple-api
# Vérifier
sudo systemctl status voix-du-peuple-api
Test de l'API :
curl http://127.0.0.1:8000/api/healthz
# {"status": "ok"}
10. Configurer Nginx
# Copier la config Nginx
sudo cp /opt/voix-du-peuple/deploy/nginx.conf \
/etc/nginx/conf.d/voix-du-peuple.conf
# Éditez le fichier pour mettre votre nom de domaine
sudo nano /etc/nginx/conf.d/voix-du-peuple.conf
# Remplacez voix-du-peuple.example.com par votre domaine
# Tester la configuration
sudo nginx -t
# Recharger Nginx
sudo systemctl reload nginx
11. Ouvrir le pare-feu
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
SELinux — autoriser Nginx à se connecter à Gunicorn :
sudo setsebool -P httpd_can_network_connect 1
12. (Recommandé) HTTPS avec Let's Encrypt
sudo dnf install -y certbot python3-certbot-nginx
sudo certbot --nginx -d voix-du-peuple.example.com \
--email admin@example.com --agree-tos --no-eff-email
# Renouvellement automatique (déjà configuré par certbot)
sudo systemctl status certbot-renew.timer
Puis décommentez le bloc HTTPS dans /etc/nginx/conf.d/voix-du-peuple.conf.
Structure du projet
voix-du-peuple/
├── artifacts/
│ ├── flask-api/ # Backend Python Flask
│ │ ├── app.py # Application principale + routes
│ │ ├── ai_agent.py # Agent IA (filtrage + synthèse)
│ │ ├── legal_framework.py # Prompts ancrés dans le droit international
│ │ ├── database.py # Accès PostgreSQL (psycopg2)
│ │ ├── requirements.txt # Dépendances Python
│ │ └── start.sh # Démarrage développement
│ └── voix-du-peuple/ # Frontend React + Vite
│ ├── src/
│ │ ├── pages/ # home.tsx, about.tsx
│ │ ├── components/ # Composants UI (shadcn/ui + radix)
│ │ └── App.tsx # Routing principal
│ └── vite.config.ts # Config Vite (développement + production)
├── lib/
│ ├── api-spec/ # Spécification OpenAPI
│ ├── api-client-react/ # Hooks React Query générés
│ └── db/ # Schéma Drizzle (référence)
├── deploy/
│ ├── voix-du-peuple-api.service # Service systemd Gunicorn
│ └── nginx.conf # Configuration Nginx
├── .env.example # Variables d'environnement (modèle)
└── DEPLOIEMENT.md # Ce fichier
Variables d'environnement complètes
| Variable | Obligatoire | Description |
|---|---|---|
DATABASE_URL |
Oui | URL PostgreSQL complète |
OPENAI_API_KEY |
Oui | Clé API OpenAI (sk-...) |
OPENAI_BASE_URL |
Non | Proxy OpenAI compatible (Ollama, Azure, etc.) |
OPENAI_FILTER_MODEL |
Non | Modèle de filtrage (défaut : gpt-4o-mini) |
OPENAI_SYNTHESIS_MODEL |
Non | Modèle de synthèse (défaut : gpt-4o) |
SESSION_SECRET |
Oui | Clé secrète Flask (min 32 caractères aléatoires) |
PORT |
Non | Port Gunicorn (défaut : 8000) |
FLASK_ENV |
Non | production ou development |
Modèles IA utilisés
| Fonction | Modèle par défaut | Variable d'environnement |
|---|---|---|
| Filtrage des idées | mistral-small-latest |
FILTER_MODEL |
| Synthèse collective | mistral-large-latest |
SYNTHESIS_MODEL |
Pour changer les modèles, éditez artifacts/flask-api/ai_agent.py :
# Filtrage (ligne ~56)
model="gpt-4o-mini", # ou tout modèle OpenAI compatible
# Synthèse (ligne ~104)
model="gpt-4o", # ou tout modèle OpenAI compatible
Mise à jour
sudo -u voixdupeuple bash -c "
cd /opt/voix-du-peuple
git pull origin main
# Mise à jour des dépendances Python si nécessaire
.venv/bin/pip install -r artifacts/flask-api/requirements.txt
# Mise à jour des dépendances Node et rebuild frontend
pnpm install --frozen-lockfile
cd artifacts/voix-du-peuple
pnpm exec vite build --config vite.config.selfhost.ts
"
# Redémarrer le service
sudo systemctl restart voix-du-peuple-api
sudo systemctl reload nginx
Logs et supervision
# Logs API Flask
sudo journalctl -u voix-du-peuple-api -f
tail -f /var/log/voix-du-peuple/api-error.log
tail -f /var/log/voix-du-peuple/api-access.log
# Logs Nginx
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log
# Statut des services
sudo systemctl status voix-du-peuple-api
sudo systemctl status nginx
sudo systemctl status postgresql-15
Dépannage fréquent
L'API répond 502 Bad Gateway
# Vérifier que Gunicorn tourne
sudo systemctl status voix-du-peuple-api
# Vérifier SELinux
sudo setsebool -P httpd_can_network_connect 1
Erreur "could not connect to server" (PostgreSQL)
# Vérifier que PostgreSQL tourne
sudo systemctl status postgresql-15
# Vérifier l'URL de connexion dans .env
psql -U voixdupeuple -h 127.0.0.1 -d voixdupeuple
Erreur OpenAI API
# Vérifier la clé dans .env
grep OPENAI_API_KEY /opt/voix-du-peuple/.env
# Tester directement
curl https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY"
Le frontend affiche une page blanche
# Vérifier que le build existe
ls /opt/voix-du-peuple/artifacts/voix-du-peuple/dist/public/
# Vérifier les droits
sudo chown -R voixdupeuple:voixdupeuple /opt/voix-du-peuple/artifacts/voix-du-peuple/dist/