389 lines
11 KiB
Markdown
389 lines
11 KiB
Markdown
# Guide de déploiement — Groupe Méditation
|
|
|
|
## Debian Bookworm + NGINX + PostgreSQL
|
|
|
|
Testé sur Debian 12 (Bookworm) avec un utilisateur `ansible` ayant accès sudo.
|
|
|
|
Principe : on utilise ce que Debian fournit. Pas de dépôt externe.
|
|
|
|
---
|
|
|
|
## 0. Prérequis système
|
|
|
|
```bash
|
|
# Définir un mot de passe pour l'utilisateur ansible (indispensable pour récupération console)
|
|
sudo passwd ansible
|
|
|
|
sudo apt update && sudo apt upgrade -y
|
|
sudo apt install -y curl ca-certificates gnupg
|
|
```
|
|
|
|
---
|
|
|
|
## 1. Installer PostgreSQL
|
|
|
|
On installe le PostgreSQL fourni par Debian Bookworm (version 15) :
|
|
|
|
```bash
|
|
sudo apt install -y postgresql postgresql-client
|
|
sudo systemctl enable postgresql
|
|
sudo systemctl start postgresql
|
|
```
|
|
|
|
Créer l'utilisateur et la base. **Choisissez votre mot de passe maintenant** — il sera réutilisé à l'étape 6 :
|
|
|
|
```bash
|
|
sudo -u postgres psql << 'SQL'
|
|
CREATE USER grpmed WITH PASSWORD 'votre_mot_de_passe_ici';
|
|
CREATE DATABASE groupe_meditation OWNER grpmed;
|
|
GRANT ALL PRIVILEGES ON DATABASE groupe_meditation TO grpmed;
|
|
\c groupe_meditation
|
|
GRANT ALL ON SCHEMA public TO grpmed;
|
|
SQL
|
|
```
|
|
|
|
Vérifier la connexion. **Important : utiliser `127.0.0.1`, pas `localhost`** (asyncpg résout `localhost` en IPv6 `::1` sur Debian Bookworm, tandis que PostgreSQL n'écoute que sur `127.0.0.1`) :
|
|
|
|
```bash
|
|
PGPASSWORD='votre_mot_de_passe_ici' psql -U grpmed -h 127.0.0.1 -d groupe_meditation -c "SELECT 1;"
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Installer Node.js
|
|
|
|
On installe le Node.js fourni par Debian Bookworm (version 18) :
|
|
|
|
```bash
|
|
sudo apt install -y nodejs npm
|
|
```
|
|
|
|
Vérifier :
|
|
|
|
```bash
|
|
node --version
|
|
npm --version
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Installer Python et les dépendances système
|
|
|
|
```bash
|
|
sudo apt install -y python3 python3-pip python3-venv
|
|
|
|
# Dépendances système pour WeasyPrint (rapports PDF)
|
|
sudo apt install -y libpango-1.0-0 libpangocairo-1.0-0 \
|
|
libgdk-pixbuf2.0-0 libffi-dev libcairo2
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Installer NGINX
|
|
|
|
```bash
|
|
sudo apt install -y nginx
|
|
sudo systemctl enable nginx
|
|
sudo systemctl start nginx
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Déployer le code source
|
|
|
|
```bash
|
|
# Copier l'archive sur le serveur, puis :
|
|
cd ~
|
|
unzip groupe-meditation-v12.zip
|
|
|
|
# Backend
|
|
sudo mkdir -p /opt/groupe-meditation
|
|
sudo cp -r ~/groupe-meditation/backend/ /opt/groupe-meditation/backend/
|
|
sudo cp -r ~/groupe-meditation/deploy/ /opt/groupe-meditation/deploy/
|
|
|
|
# Environnement virtuel Python
|
|
cd /opt/groupe-meditation/backend
|
|
sudo python3 -m venv venv
|
|
sudo /opt/groupe-meditation/backend/venv/bin/pip install -r requirements.txt
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Configurer le backend
|
|
|
|
Générer le secret JWT :
|
|
|
|
```bash
|
|
openssl rand -base64 48
|
|
```
|
|
|
|
Créer le `.env` :
|
|
|
|
```bash
|
|
cd /opt/groupe-meditation/backend
|
|
sudo cp .env.example .env
|
|
sudo nano .env
|
|
```
|
|
|
|
Modifier `.env` avec le **même mot de passe** que l'étape 1.
|
|
|
|
**⚠️ Utiliser `127.0.0.1`, jamais `localhost`** dans `DATABASE_URL` :
|
|
|
|
```
|
|
DATABASE_URL=postgresql+asyncpg://grpmed:votre_mot_de_passe_ici@127.0.0.1:5432/groupe_meditation
|
|
JWT_SECRET=valeur_generee_ci-dessus
|
|
CORS_ORIGINS=["https://groupe-meditation.87-16.org"]
|
|
INVITATION_EXPIRE_HOURS=48
|
|
```
|
|
|
|
**Permissions du `.env` — obligatoire** (le service tourne en `www-data`) :
|
|
|
|
```bash
|
|
sudo chown www-data:www-data /opt/groupe-meditation/backend/.env
|
|
sudo chmod 640 /opt/groupe-meditation/backend/.env
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Initialiser la base de données
|
|
|
|
**Le seed doit être lancé depuis le dossier `backend/`** pour que le fichier `.env` soit trouvé :
|
|
|
|
```bash
|
|
cd /opt/groupe-meditation/backend
|
|
/opt/groupe-meditation/backend/venv/bin/python ../deploy/seed.py
|
|
```
|
|
|
|
Si le `.env` n'est pas trouvé, le script utilisera les valeurs par défaut de `config.py` (qui ont un autre mot de passe) et la connexion échouera.
|
|
|
|
Le script crée **interactivement** :
|
|
- Les tables (23+)
|
|
- Les 10 postes prédéfinis
|
|
- La littérature de base (5 titres)
|
|
- Le premier groupe et le premier membre
|
|
- Un code d'invitation valide 7 jours
|
|
|
|
---
|
|
|
|
## 7b. Mise à jour d'une base existante (v11 → v12)
|
|
|
|
Si la base existe déjà, exécuter ces commandes SQL **avant** de relancer le service :
|
|
|
|
```bash
|
|
PGPASSWORD='votre_mot_de_passe_ici' psql -U grpmed -h 127.0.0.1 -d groupe_meditation << 'SQL'
|
|
-- ══ Membre : courriel obligatoire, nom optionnel, téléphone obligatoire ══
|
|
-- Remplir les courriels manquants avant de rendre NOT NULL
|
|
UPDATE membres SET courriel = CONCAT(LOWER(prenom), '_', LEFT(id::text, 4), '@temp.local')
|
|
WHERE courriel IS NULL OR courriel = '';
|
|
UPDATE membres SET telephone = '000-000-0000'
|
|
WHERE telephone IS NULL OR telephone = '';
|
|
ALTER TABLE membres ALTER COLUMN courriel SET NOT NULL;
|
|
ALTER TABLE membres ALTER COLUMN telephone SET NOT NULL;
|
|
ALTER TABLE membres ALTER COLUMN nom DROP NOT NULL;
|
|
-- Contrainte d'unicité courriel+groupe
|
|
ALTER TABLE membres ADD CONSTRAINT uq_courriel_groupe UNIQUE (courriel, groupe_id);
|
|
|
|
-- ══ Tâches ══
|
|
CREATE TABLE IF NOT EXISTS taches (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
nom VARCHAR(200) NOT NULL,
|
|
informations TEXT,
|
|
ordre_affichage INTEGER DEFAULT 99,
|
|
cree_le TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
CREATE TABLE IF NOT EXISTS postes_taches (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
poste_id UUID NOT NULL REFERENCES postes(id),
|
|
tache_id UUID NOT NULL REFERENCES taches(id),
|
|
cree_le TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
-- ══ Poste : champ informations ══
|
|
ALTER TABLE postes ADD COLUMN IF NOT EXISTS informations TEXT;
|
|
|
|
-- ══ Dépenses : preuve, methode nullable ══
|
|
ALTER TABLE depenses ADD COLUMN IF NOT EXISTS preuve_nom VARCHAR(255);
|
|
ALTER TABLE depenses ALTER COLUMN methode DROP NOT NULL;
|
|
|
|
-- ══ Candidatures : type, nomination, retrait ══
|
|
-- Ajouter les nouvelles valeurs au type ENUM
|
|
DO $$ BEGIN
|
|
ALTER TYPE statut_candidature ADD VALUE IF NOT EXISTS 'retiree';
|
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
END $$;
|
|
DO $$ BEGIN
|
|
CREATE TYPE type_candidature AS ENUM ('candidature', 'nomination');
|
|
EXCEPTION WHEN duplicate_object THEN NULL;
|
|
END $$;
|
|
ALTER TABLE candidatures ADD COLUMN IF NOT EXISTS type VARCHAR(20) DEFAULT 'candidature';
|
|
ALTER TABLE candidatures ADD COLUMN IF NOT EXISTS nomme_par UUID REFERENCES membres(id);
|
|
ALTER TABLE candidatures ADD COLUMN IF NOT EXISTS acceptee_par_membre BOOLEAN;
|
|
ALTER TABLE candidatures ADD COLUMN IF NOT EXISTS proposition_id UUID REFERENCES propositions(id);
|
|
|
|
-- ══ Envoi contributions : résolution, engagement ══
|
|
ALTER TABLE envois_contributions ADD COLUMN IF NOT EXISTS resolution_id UUID REFERENCES propositions(id);
|
|
ALTER TABLE envois_contributions ADD COLUMN IF NOT EXISTS engagee BOOLEAN DEFAULT false;
|
|
ALTER TABLE envois_contributions ADD COLUMN IF NOT EXISTS debitee BOOLEAN DEFAULT false;
|
|
|
|
-- ══ Propositions : type et lien candidature ══
|
|
ALTER TABLE propositions ADD COLUMN IF NOT EXISTS type_proposition VARCHAR(20) DEFAULT 'generale';
|
|
ALTER TABLE propositions ADD COLUMN IF NOT EXISTS candidature_id UUID REFERENCES candidatures(id);
|
|
|
|
-- ══ Répertoire des preuves ══
|
|
-- Créer le répertoire manuellement :
|
|
-- sudo mkdir -p /opt/groupe-meditation/uploads/preuves
|
|
-- sudo chown www-data:www-data /opt/groupe-meditation/uploads/preuves
|
|
SQL
|
|
```
|
|
|
|
Ensuite créer le répertoire des preuves et relancer :
|
|
|
|
```bash
|
|
sudo mkdir -p /opt/groupe-meditation/uploads/preuves
|
|
sudo chown www-data:www-data /opt/groupe-meditation/uploads/preuves
|
|
sudo systemctl restart groupe-meditation
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Créer le service systemd
|
|
|
|
```bash
|
|
sudo cp /opt/groupe-meditation/deploy/groupe-meditation.service /etc/systemd/system/
|
|
sudo chown -R www-data:www-data /opt/groupe-meditation
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable groupe-meditation
|
|
sudo systemctl start groupe-meditation
|
|
```
|
|
|
|
Vérifier :
|
|
|
|
```bash
|
|
sudo systemctl status groupe-meditation
|
|
curl -s http://127.0.0.1:8000/api/health
|
|
```
|
|
|
|
Doit retourner `{"status":"ok","app":"Groupe Méditation","version":"0.1.0"}`
|
|
|
|
---
|
|
|
|
## 9. Construire et déployer le frontend
|
|
|
|
```bash
|
|
cd ~/groupe-meditation/frontend
|
|
npm install
|
|
npm run build
|
|
|
|
sudo mkdir -p /var/www/groupe-meditation
|
|
sudo cp -r dist/* /var/www/groupe-meditation/
|
|
sudo chown -R www-data:www-data /var/www/groupe-meditation
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Configurer NGINX
|
|
|
|
NGINX fait tout : fichiers statiques du frontend + reverse proxy vers FastAPI.
|
|
|
|
```bash
|
|
sudo cp ~/groupe-meditation/deploy/nginx-groupe-meditation.conf \
|
|
/etc/nginx/sites-available/groupe-meditation
|
|
sudo ln -sf /etc/nginx/sites-available/groupe-meditation /etc/nginx/sites-enabled/
|
|
sudo rm -f /etc/nginx/sites-enabled/default
|
|
|
|
sudo nginx -t
|
|
sudo systemctl reload nginx
|
|
```
|
|
|
|
Tester en HTTP :
|
|
|
|
```bash
|
|
curl -s http://groupe-meditation.87-16.org/api/health
|
|
```
|
|
|
|
---
|
|
|
|
## 11. Certificat TLS (Let's Encrypt)
|
|
|
|
```bash
|
|
sudo apt install -y certbot python3-certbot-nginx
|
|
sudo certbot --nginx -d groupe-meditation.87-16.org
|
|
```
|
|
|
|
Certbot modifie automatiquement la config NGINX pour ajouter HTTPS et la redirection 80→443.
|
|
|
|
---
|
|
|
|
## 12. Sauvegarde automatique
|
|
|
|
```bash
|
|
sudo cp ~/groupe-meditation/deploy/backup.sh /etc/cron.daily/groupe-meditation-backup
|
|
sudo chmod +x /etc/cron.daily/groupe-meditation-backup
|
|
```
|
|
|
|
---
|
|
|
|
## 13. Vérification finale
|
|
|
|
```bash
|
|
# API
|
|
curl -s https://groupe-meditation.87-16.org/api/health | python3 -m json.tool
|
|
|
|
# Documentation OpenAPI
|
|
# https://groupe-meditation.87-16.org/api/docs
|
|
|
|
# Frontend
|
|
# https://groupe-meditation.87-16.org
|
|
```
|
|
|
|
---
|
|
|
|
## Mise à jour de l'application
|
|
|
|
```bash
|
|
# 1. Copier les nouveaux fichiers
|
|
cd ~
|
|
unzip groupe-meditation-vXX.zip
|
|
|
|
# 2. Backend
|
|
sudo cp -r ~/groupe-meditation/backend/ /opt/groupe-meditation/backend/
|
|
cd /opt/groupe-meditation/backend
|
|
sudo venv/bin/pip install -r requirements.txt
|
|
|
|
# 3. Migrations SQL si nécessaire (voir section 7b)
|
|
|
|
# 4. Permissions
|
|
sudo chown -R www-data:www-data /opt/groupe-meditation
|
|
sudo chown www-data:www-data /opt/groupe-meditation/backend/.env
|
|
sudo chmod 640 /opt/groupe-meditation/backend/.env
|
|
|
|
# 5. Relancer le service
|
|
sudo systemctl restart groupe-meditation
|
|
|
|
# 6. Frontend
|
|
cd ~/groupe-meditation/frontend
|
|
npm install && npm run build
|
|
sudo cp -r dist/* /var/www/groupe-meditation/
|
|
```
|
|
|
|
---
|
|
|
|
## Dépannage
|
|
|
|
| Problème | Commande / Solution |
|
|
|----------|---------------------|
|
|
| API ne démarre pas | `sudo journalctl -u groupe-meditation -f` |
|
|
| Workers bloqués au démarrage | `DATABASE_URL` doit utiliser `127.0.0.1` (pas `localhost`) |
|
|
| `InvalidPasswordError` au seed | Lancer depuis `backend/`, vérifier `.env` lisible |
|
|
| `InvalidPasswordError` à l'API | `sudo chown www-data:www-data .env && sudo chmod 640 .env` |
|
|
| NGINX 502 Bad Gateway | `sudo systemctl status groupe-meditation` — Uvicorn démarré ? |
|
|
| NGINX 504 Gateway Timeout | Worker bloqué DB — vérifier `127.0.0.1` dans `DATABASE_URL` |
|
|
| WeasyPrint échoue | `sudo apt install libpango-1.0-0 libpangocairo-1.0-0` |
|
|
| `seed.py ImportError` | Vérifier les noms de classes dans `models/` |
|
|
| Console inaccessible | `sudo passwd ansible` — à faire en tout début |
|
|
| `type "..." does not exist` après ALTER | Relancer le service pour que `create_all` crée les types manquants |
|
|
| Nouvelle colonne absente | Exécuter les ALTER TABLE de la section 7b |
|
|
|
|
---
|
|
|
|
**Hébergé au Québec · 100 % logiciel libre · Zéro traçage**
|