Add self-hosting capabilities and deployment guide for the application
Implement self-hosting for RockyLinux by adding systemd and Nginx configurations, updating API models to support standard OpenAI keys, and providing a comprehensive deployment guide. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 923ae0e3-a363-4db8-b04a-e8baca2a1330 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: f8aa455f-f180-4964-94dd-11cfb1a42383 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8af7d2ec-2cc3-4ece-8af3-9f071488d072/923ae0e3-a363-4db8-b04a-e8baca2a1330/VnHW0bR Replit-Helium-Checkpoint-Created: true
This commit is contained in:
+424
@@ -0,0 +1,424 @@
|
||||
# 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** : API OpenAI (clé standard, pas de proxy Replit)
|
||||
|
||||
---
|
||||
|
||||
## Prérequis
|
||||
|
||||
```bash
|
||||
# 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
|
||||
```bash
|
||||
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)
|
||||
```bash
|
||||
curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
|
||||
sudo dnf install -y nodejs
|
||||
node --version # doit afficher v20.x.x
|
||||
```
|
||||
|
||||
### pnpm
|
||||
```bash
|
||||
npm install -g pnpm
|
||||
pnpm --version
|
||||
```
|
||||
|
||||
### PostgreSQL 15
|
||||
```bash
|
||||
sudo dnf install -y postgresql15-server postgresql15
|
||||
sudo /usr/pgsql-15/bin/postgresql-15-setup initdb
|
||||
sudo systemctl enable --now postgresql-15
|
||||
```
|
||||
|
||||
### Nginx
|
||||
```bash
|
||||
sudo dnf install -y nginx
|
||||
sudo systemctl enable nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Configurer PostgreSQL
|
||||
|
||||
```bash
|
||||
# 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
|
||||
```
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
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 :
|
||||
|
||||
```env
|
||||
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` :
|
||||
```bash
|
||||
python3.11 -c "import secrets; print(secrets.token_hex(32))"
|
||||
```
|
||||
|
||||
Sécurisez le fichier :
|
||||
```bash
|
||||
sudo chmod 600 /opt/voix-du-peuple/.env
|
||||
sudo chown voixdupeuple:voixdupeuple /opt/voix-du-peuple/.env
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Installer les dépendances Python
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
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)
|
||||
|
||||
```bash
|
||||
# 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 :
|
||||
```bash
|
||||
curl http://127.0.0.1:8000/api/healthz
|
||||
# {"status": "ok"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Configurer Nginx
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
sudo firewall-cmd --permanent --add-service=http
|
||||
sudo firewall-cmd --permanent --add-service=https
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
SELinux — autoriser Nginx à se connecter à Gunicorn :
|
||||
```bash
|
||||
sudo setsebool -P httpd_can_network_connect 1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. (Recommandé) HTTPS avec Let's Encrypt
|
||||
|
||||
```bash
|
||||
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 Replit (développement)
|
||||
│ └── vite.config.selfhost.ts # Config auto-hébergement (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 | Configurable dans |
|
||||
|----------|-------------------|-------------------|
|
||||
| Filtrage des idées | `gpt-4o-mini` | `ai_agent.py` ligne 56 |
|
||||
| Synthèse collective | `gpt-4o` | `ai_agent.py` ligne 104 |
|
||||
|
||||
> **Note :** Les modèles `gpt-5-mini` et `gpt-5.2` sont les noms utilisés sur la plateforme Replit. En auto-hébergement avec l'API OpenAI standard, utilisez `gpt-4o-mini` et `gpt-4o`.
|
||||
|
||||
Pour changer les modèles, éditez `artifacts/flask-api/ai_agent.py` :
|
||||
```python
|
||||
# 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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
```bash
|
||||
# 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)
|
||||
```bash
|
||||
# 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
|
||||
```bash
|
||||
# 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
|
||||
```bash
|
||||
# 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/
|
||||
```
|
||||
Reference in New Issue
Block a user