Add a comprehensive Rocky Linux installation guide and streamline domain configuration
Add a detailed guide for installing the application on Rocky Linux, including systemd service setup and Nginx configuration. Streamline domain setting by introducing a script to update environment variables and rebuild the frontend, and remove the URL input from the flyer component. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 923ae0e3-a363-4db8-b04a-e8baca2a1330 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 3d999b96-66af-4728-92b9-3a39ade05f44 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8af7d2ec-2cc3-4ece-8af3-9f071488d072/923ae0e3-a363-4db8-b04a-e8baca2a1330/qCk7LE3 Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -30,3 +30,9 @@ id = "kJNXgVnYp_LQmPcWr6Osb"
|
||||
uri = "file://docs/WIKI.md"
|
||||
type = "text"
|
||||
title = "Wiki v1.3"
|
||||
|
||||
[[outputs]]
|
||||
id = "4toQ5OnXtI6PicOZHDKnP"
|
||||
uri = "file://docs/INSTALL_ROCKY.md"
|
||||
type = "text"
|
||||
title = "Guide d’installation RockyLinux"
|
||||
|
||||
@@ -1,53 +1,27 @@
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import { QRCodeSVG } from "qrcode.react";
|
||||
import { Printer, ExternalLink } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Link } from "wouter";
|
||||
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// URL encodée dans le QR code — modifiez cette ligne
|
||||
const DEFAULT_QR_URL = "https://lavoixdupeuple.fr";
|
||||
// ══════════════════════════════════════════════════════════
|
||||
// URL du QR code — définie via VITE_APP_URL dans le fichier .env
|
||||
// Modifier .env puis exécuter : bash scripts/set-domain.sh https://votredomaine.fr
|
||||
const QR_URL = (new URLSearchParams(window.location.search).get("url"))
|
||||
|| import.meta.env.VITE_APP_URL
|
||||
|| "https://lavoixdupeuple.fr";
|
||||
|
||||
export default function Flyer() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const [qrUrl, setQrUrl] = useState(params.get("url") || DEFAULT_QR_URL);
|
||||
const [inputValue, setInputValue] = useState(qrUrl);
|
||||
|
||||
const applyUrl = () => {
|
||||
const trimmed = inputValue.trim();
|
||||
if (trimmed) setQrUrl(trimmed);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-muted/20 flex flex-col items-center py-8 px-4 gap-6">
|
||||
|
||||
{/* Barre de contrôle — masquée à l'impression */}
|
||||
<div className="no-print w-full max-w-xl bg-white border border-border/50 p-4 rounded-sm space-y-3">
|
||||
<p className="text-xs font-mono text-muted-foreground uppercase tracking-widest">
|
||||
Destination du QR code
|
||||
</p>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
onKeyDown={(e) => e.key === "Enter" && applyUrl()}
|
||||
placeholder="https://lavoixdupeuple.fr"
|
||||
className="font-mono text-sm"
|
||||
/>
|
||||
<Button onClick={applyUrl} variant="outline" size="sm">
|
||||
Appliquer
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={() => window.print()} size="sm" className="gap-2">
|
||||
<Printer className="h-3.5 w-3.5" /> Imprimer / Exporter PDF
|
||||
</Button>
|
||||
<Link href="/">
|
||||
<Button variant="ghost" size="sm">← Retour</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="no-print w-full max-w-xl bg-white border border-border/50 p-4 rounded-sm flex gap-2">
|
||||
<Button onClick={() => window.print()} size="sm" className="gap-2">
|
||||
<Printer className="h-3.5 w-3.5" /> Imprimer / Exporter PDF
|
||||
</Button>
|
||||
<Link href="/">
|
||||
<Button variant="ghost" size="sm">← Retour</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Flyer imprimable */}
|
||||
@@ -83,7 +57,7 @@ export default function Flyer() {
|
||||
<div className="flex flex-col items-center gap-4 my-4">
|
||||
<div className="p-4 border border-border/40 bg-white">
|
||||
<QRCodeSVG
|
||||
value={qrUrl}
|
||||
value={QR_URL}
|
||||
size={220}
|
||||
bgColor="#ffffff"
|
||||
fgColor="#1a1a2e"
|
||||
@@ -93,7 +67,7 @@ export default function Flyer() {
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 text-xs font-mono text-muted-foreground">
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
<span>{qrUrl}</span>
|
||||
<span>{QR_URL}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -106,7 +80,7 @@ export default function Flyer() {
|
||||
className="text-lg font-bold text-primary tracking-wide"
|
||||
style={{ fontFamily: "'Bahnschrift', 'DIN Alternate', sans-serif" }}
|
||||
>
|
||||
{qrUrl.replace(/^https?:\/\//, "")}
|
||||
{QR_URL.replace(/^https?:\/\//, "")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
+12
-45
@@ -1,9 +1,6 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name voix-du-peuple.example.com;
|
||||
|
||||
# Redirection HTTPS (décommentez après avoir configuré Certbot)
|
||||
# return 301 https://$host$request_uri;
|
||||
listen 8080;
|
||||
server_name _; # remplacer par votre nom de domaine si nécessaire
|
||||
|
||||
root /opt/voix-du-peuple/artifacts/voix-du-peuple/dist/public;
|
||||
index index.html;
|
||||
@@ -14,7 +11,13 @@ server {
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
# API Flask — proxy vers Gunicorn
|
||||
# Health check
|
||||
location /health {
|
||||
proxy_pass http://127.0.0.1:8000/health;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
# API Flask — proxy vers Gunicorn (interne)
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
proxy_set_header Host $host;
|
||||
@@ -24,7 +27,7 @@ server {
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
# Frontend React — Single Page Application
|
||||
# Frontend React — SPA
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
@@ -34,42 +37,6 @@ server {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS — décommentez et adaptez après avoir obtenu votre certificat SSL
|
||||
# server {
|
||||
# listen 443 ssl http2;
|
||||
# server_name voix-du-peuple.example.com;
|
||||
#
|
||||
# ssl_certificate /etc/letsencrypt/live/voix-du-peuple.example.com/fullchain.pem;
|
||||
# ssl_certificate_key /etc/letsencrypt/live/voix-du-peuple.example.com/privkey.pem;
|
||||
# ssl_protocols TLSv1.2 TLSv1.3;
|
||||
# ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
#
|
||||
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
# add_header X-Content-Type-Options "nosniff" always;
|
||||
# add_header X-Frame-Options "DENY" always;
|
||||
# add_header X-XSS-Protection "1; mode=block" always;
|
||||
# add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
#
|
||||
# root /opt/voix-du-peuple/artifacts/voix-du-peuple/dist/public;
|
||||
# index index.html;
|
||||
#
|
||||
# location /api/ {
|
||||
# proxy_pass http://127.0.0.1:8000;
|
||||
# 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;
|
||||
# proxy_read_timeout 60s;
|
||||
# }
|
||||
#
|
||||
# location / {
|
||||
# try_files $uri $uri/ /index.html;
|
||||
# }
|
||||
#
|
||||
# location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
|
||||
# expires 1y;
|
||||
# add_header Cache-Control "public, immutable";
|
||||
# }
|
||||
# }
|
||||
client_max_body_size 1m;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,538 @@
|
||||
# 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 <<EOF
|
||||
CREATE USER voix_user WITH PASSWORD 'MOT_DE_PASSE_FORT';
|
||||
CREATE DATABASE voix_du_peuple OWNER voix_user;
|
||||
GRANT ALL PRIVILEGES ON DATABASE voix_du_peuple TO voix_user;
|
||||
EOF
|
||||
|
||||
exit # revenir à root
|
||||
```
|
||||
|
||||
Tester la connexion :
|
||||
|
||||
```bash
|
||||
psql -U voix_user -d voix_du_peuple -h 127.0.0.1 -c '\l'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Environnement Python
|
||||
|
||||
```bash
|
||||
cd /opt/voix-du-peuple
|
||||
|
||||
# Créer le virtualenv
|
||||
python3.11 -m venv .venv
|
||||
|
||||
# Installer les dépendances
|
||||
.venv/bin/pip install --upgrade pip
|
||||
.venv/bin/pip install -r artifacts/flask-api/requirements.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Configuration du domaine et variables d'environnement
|
||||
|
||||
### 8.1 Créer le fichier `.env`
|
||||
|
||||
```bash
|
||||
cp .env.example .env # si le fichier exemple existe, sinon créer manuellement
|
||||
vim .env
|
||||
```
|
||||
|
||||
Contenu minimal du `.env` :
|
||||
|
||||
```bash
|
||||
# Base de données
|
||||
DATABASE_URL=postgresql://voix_user:MOT_DE_PASSE_FORT@127.0.0.1:5432/voix_du_peuple
|
||||
|
||||
# IA Mistral
|
||||
MISTRAL_API_KEY=votre_cle_mistral_ici
|
||||
|
||||
# Sécurité Flask
|
||||
SESSION_SECRET=generez-une-chaine-aleatoire-longue-ici
|
||||
|
||||
# Modèles IA (valeurs par défaut si omis)
|
||||
# FILTER_MODEL=mistral-small-latest
|
||||
# SYNTHESIS_MODEL=mistral-large-latest
|
||||
|
||||
# Domaine public — utilisé par le QR code du flyer
|
||||
VITE_APP_URL=https://votredomaine.fr
|
||||
```
|
||||
|
||||
Générer un SESSION_SECRET :
|
||||
|
||||
```bash
|
||||
python3 -c "import secrets; print(secrets.token_hex(32))"
|
||||
```
|
||||
|
||||
### 8.2 Changer le domaine (QR code)
|
||||
|
||||
Le flyer génère automatiquement son QR code à partir de `VITE_APP_URL`. Pour changer le domaine :
|
||||
|
||||
```bash
|
||||
# Depuis /opt/voix-du-peuple
|
||||
bash scripts/set-domain.sh https://votredomaine.fr
|
||||
```
|
||||
|
||||
Ce script met à jour `VITE_APP_URL` dans `.env` et reconstruit le frontend.
|
||||
Appliquer ensuite : `systemctl reload nginx`
|
||||
|
||||
---
|
||||
|
||||
## 9. Build du frontend
|
||||
|
||||
```bash
|
||||
cd /opt/voix-du-peuple
|
||||
|
||||
# Installer les dépendances Node
|
||||
pnpm install
|
||||
|
||||
# Construire le frontend (lit VITE_APP_URL depuis .env)
|
||||
source .env
|
||||
export VITE_APP_URL
|
||||
pnpm --filter @workspace/voix-du-peuple run build --config vite.config.selfhost.ts
|
||||
|
||||
# Vérifier que le build est présent
|
||||
ls artifacts/voix-du-peuple/dist/public/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Service Gunicorn (systemd)
|
||||
|
||||
```bash
|
||||
# Copier le fichier de service
|
||||
cp deploy/voix-du-peuple-api.service /etc/systemd/system/
|
||||
|
||||
# Recharger systemd et activer le service
|
||||
systemctl daemon-reload
|
||||
systemctl enable voix-du-peuple-api
|
||||
systemctl start voix-du-peuple-api
|
||||
systemctl status voix-du-peuple-api
|
||||
```
|
||||
|
||||
Vérifier que Gunicorn écoute bien sur le port interne :
|
||||
|
||||
```bash
|
||||
ss -tlnp | grep 8000
|
||||
# doit afficher : 127.0.0.1:8000
|
||||
```
|
||||
|
||||
Tester l'API directement :
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8000/health
|
||||
# réponse attendue : {"status": "ok"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Nginx
|
||||
|
||||
### 11.1 Installer la configuration
|
||||
|
||||
```bash
|
||||
# Copier la config fournie
|
||||
cp deploy/nginx.conf /etc/nginx/conf.d/voix-du-peuple.conf
|
||||
|
||||
# (Optionnel) Ajuster le nom de serveur dans la config
|
||||
vim /etc/nginx/conf.d/voix-du-peuple.conf
|
||||
# Modifier : server_name _;
|
||||
# En : server_name votredomaine.fr;
|
||||
|
||||
# Tester la configuration
|
||||
nginx -t
|
||||
|
||||
# Démarrer Nginx
|
||||
systemctl start nginx
|
||||
systemctl status nginx
|
||||
```
|
||||
|
||||
### 11.2 Vérifier que Nginx écoute sur 8080
|
||||
|
||||
```bash
|
||||
ss -tlnp | grep 8080
|
||||
# doit afficher : 0.0.0.0:8080
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Firewall
|
||||
|
||||
```bash
|
||||
# Autoriser le port 8080 (HTTP)
|
||||
firewall-cmd --permanent --add-port=8080/tcp
|
||||
firewall-cmd --reload
|
||||
|
||||
# Vérifier
|
||||
firewall-cmd --list-ports
|
||||
```
|
||||
|
||||
> 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 <COMMIT_HASH>
|
||||
|
||||
# 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 <<EOF
|
||||
/var/log/voix-du-peuple/*.log {
|
||||
daily
|
||||
rotate 14
|
||||
compress
|
||||
missingok
|
||||
notifempty
|
||||
postrotate
|
||||
systemctl kill -s USR1 voix-du-peuple-api
|
||||
endscript
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
### 15.7 Vérification de santé (cron)
|
||||
|
||||
```bash
|
||||
# Ajouter un health check toutes les 5 minutes
|
||||
crontab -e
|
||||
# Ajouter :
|
||||
# */5 * * * * curl -sf http://127.0.0.1:8080/health || systemctl restart voix-du-peuple-api
|
||||
```
|
||||
|
||||
### 15.8 Tableau de bord des commandes rapides
|
||||
|
||||
| Opération | Commande |
|
||||
|-----------|----------|
|
||||
| Statut global | `systemctl status voix-du-peuple-api nginx postgresql-15` |
|
||||
| Relancer l'API | `systemctl restart voix-du-peuple-api` |
|
||||
| Recharger Nginx | `systemctl reload nginx` |
|
||||
| Logs API live | `journalctl -u voix-du-peuple-api -f` |
|
||||
| Mise à jour complète | `git pull && bash scripts/set-domain.sh $VITE_APP_URL && systemctl restart voix-du-peuple-api && systemctl reload nginx` |
|
||||
| Changer de domaine | `bash scripts/set-domain.sh https://domaine.fr` |
|
||||
| Backup BDD | `pg_dump -U voix_user -h 127.0.0.1 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` |
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
# set-domain.sh — Configure le nom de domaine et reconstruit le frontend
|
||||
#
|
||||
# Usage : bash scripts/set-domain.sh https://votredomaine.fr
|
||||
#
|
||||
# Ce script :
|
||||
# 1. Met à jour la variable VITE_APP_URL dans .env
|
||||
# 2. Reconstruit le frontend (le QR code sera mis à jour)
|
||||
#
|
||||
# Prérequis : pnpm installé, être à la racine du projet
|
||||
|
||||
set -e
|
||||
|
||||
DOMAIN="${1:-}"
|
||||
|
||||
if [ -z "$DOMAIN" ]; then
|
||||
echo "Usage : bash scripts/set-domain.sh https://votredomaine.fr"
|
||||
echo ""
|
||||
echo "Exemples :"
|
||||
echo " bash scripts/set-domain.sh https://lavoixdupeuple.fr"
|
||||
echo " bash scripts/set-domain.sh http://192.168.1.10:8080"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ENV_FILE=".env"
|
||||
|
||||
# Créer .env si absent
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
touch "$ENV_FILE"
|
||||
echo "Fichier .env créé."
|
||||
fi
|
||||
|
||||
# Mettre à jour ou ajouter VITE_APP_URL
|
||||
if grep -q "^VITE_APP_URL=" "$ENV_FILE"; then
|
||||
sed -i "s|^VITE_APP_URL=.*|VITE_APP_URL=${DOMAIN}|" "$ENV_FILE"
|
||||
echo "VITE_APP_URL mis à jour : ${DOMAIN}"
|
||||
else
|
||||
echo "VITE_APP_URL=${DOMAIN}" >> "$ENV_FILE"
|
||||
echo "VITE_APP_URL ajouté : ${DOMAIN}"
|
||||
fi
|
||||
|
||||
# Exporter pour que Vite le lise pendant le build
|
||||
export VITE_APP_URL="${DOMAIN}"
|
||||
|
||||
echo ""
|
||||
echo "Reconstruction du frontend..."
|
||||
pnpm --filter @workspace/voix-du-peuple run build --config vite.config.selfhost.ts
|
||||
|
||||
echo ""
|
||||
echo "Terminé. Le QR code pointe maintenant vers : ${DOMAIN}"
|
||||
echo "Redémarrez Nginx si le build est en production : systemctl reload nginx"
|
||||
Reference in New Issue
Block a user