From 5ba69d1e16d7dfa376f5a7e43c688b67cf3a24d8 Mon Sep 17 00:00:00 2001 From: Gato Date: Sat, 6 Jun 2026 21:01:24 +0200 Subject: [PATCH] Rattrapage pb de gitea Signed-off-by: Gato --- CI-CD.md | 125 --------- Changelog.md | 15 - Home.md | 41 --- Installation-Developpement.md | 150 ---------- Installation-Production.md | 212 -------------- Mise-a-jour-Applications.md | 185 ------------- bonsai-api/docker-compose.yml | 54 ++++ bonsai-webapp/docker-compose.yml | 27 ++ gitea/Dockerfile.runner | 9 + gitea/README.md | 13 + gitea/gitea-compose.yml | 3 +- keycloak/.env.example | 3 + keycloak/docker-compose.yml | 67 +++++ .../bonsai/login/login-reset-password.ftl | 61 ++++ keycloak/themes/bonsai/login/login.ftl | 105 +++++++ .../bonsai/login/resources/css/login.css | 262 ++++++++++++++++++ keycloak/themes/bonsai/login/theme.properties | 2 + luz/docker-compose.yml | 27 ++ nextcloud/docker-compose.yml | 95 +++++++ traefik/docker-compose.yml | 45 +++ trilium/docker-compose.yml | 30 ++ watchtower/.env.example | 1 + watchtower/docker-compose.yml | 30 ++ 23 files changed, 832 insertions(+), 730 deletions(-) delete mode 100644 CI-CD.md delete mode 100644 Changelog.md delete mode 100644 Home.md delete mode 100644 Installation-Developpement.md delete mode 100644 Installation-Production.md delete mode 100644 Mise-a-jour-Applications.md create mode 100644 bonsai-api/docker-compose.yml create mode 100644 bonsai-webapp/docker-compose.yml create mode 100644 gitea/Dockerfile.runner create mode 100644 gitea/README.md create mode 100644 keycloak/.env.example create mode 100644 keycloak/docker-compose.yml create mode 100644 keycloak/themes/bonsai/login/login-reset-password.ftl create mode 100644 keycloak/themes/bonsai/login/login.ftl create mode 100644 keycloak/themes/bonsai/login/resources/css/login.css create mode 100644 keycloak/themes/bonsai/login/theme.properties create mode 100644 luz/docker-compose.yml create mode 100644 nextcloud/docker-compose.yml create mode 100644 traefik/docker-compose.yml create mode 100644 trilium/docker-compose.yml create mode 100644 watchtower/.env.example create mode 100644 watchtower/docker-compose.yml diff --git a/CI-CD.md b/CI-CD.md deleted file mode 100644 index 52ad034..0000000 --- a/CI-CD.md +++ /dev/null @@ -1,125 +0,0 @@ -# CI/CD — Pipelines Gitea Actions - -Bonsai API et Bonsai Webapp disposent chacune de trois workflows Gitea Actions : `ci.yml`, `release.yml` et `rollback.yml`. **Luz** dispose d'un workflow `release.yml` à déclencheur automatique sur `main`. Le runner Gitea s'exécute sur le même serveur que les applications et a accès direct au socket Docker (`/var/run/docker.sock`), ce qui lui permet de piloter les conteneurs sans passer par SSH. - ---- - -## Workflow CI (`ci.yml`) - -**Déclencheur** : tout `push` sur n'importe quelle branche, et toute pull request vers `main`. - -### Bonsai API - -| Étape | Ce qu'elle fait | -|---|---| -| **Checkout** | Clone le dépôt | -| **Cache Java 25** | Vérifie si le JDK est déjà présent dans le cache du runner. Si oui, le téléchargement est sauté (~11 min économisées) | -| **Install Java 25** | *(seulement si cache absent)* Télécharge et extrait le JDK 25 (Temurin, build Alpine) dans `/opt/` | -| **Set up Java 25** | Exporte `JAVA_HOME` et ajoute le JDK au `PATH` pour les étapes suivantes | -| **Run tests** | Lance `./gradlew test` — la suite de tests échoue le workflow si un test est rouge | -| **Upload test report** | *(seulement en cas d'échec)* Publie le rapport HTML de Gradle comme artifact téléchargeable dans l'interface Gitea | - -### Bonsai Webapp - -| Étape | Ce qu'elle fait | -|---|---| -| **Checkout** | Clone le dépôt | -| **Setup Node.js** | Installe Node.js 22 et active le cache npm automatique | -| **Install dependencies** | Lance `npm ci` pour une installation reproductible (utilise le cache npm si disponible) | -| **Run tests with coverage** | Lance `npm test -- --watch=false` — exécute Vitest avec rapport de couverture | - ---- - -## Workflow Release (`release.yml`) - -**Déclencheur** : publication d'une release Gitea (bouton "Publish release" sur un tag `vX.Y.Z`). - -### Bonsai API - -| Étape | Ce qu'elle fait | -|---|---| -| **Checkout** | Clone le dépôt avec l'historique complet (`fetch-depth: 0`) — nécessaire pour le merge vers `main` | -| **Cache Java 25** | Même logique que le CI | -| **Install Java 25** | *(si cache absent)* Installe le JDK | -| **Set up Java 25** | Configure `JAVA_HOME` et `PATH` | -| **Bump version in build.gradle** | Remplace la version dans `build.gradle` par le tag de la release (ex. `v1.2.3` → `1.2.3`). Modification locale uniquement, non commitée | -| **Build JAR** | Lance `./gradlew build -x test` pour produire le JAR avec la bonne version. Les tests sont skippés (déjà passés en CI) | -| **Set up Docker Buildx** | Active Buildx pour le build multi-plateforme avec support du cache registry | -| **Login to Gitea registry** | Authentifie le runner sur `git.goutailler-olivier.com` avec le token `RELEASE_TOKEN` | -| **Set lowercase repo name** | Normalise le nom du repo en minuscules (requis par Docker) | -| **Build and push** | Build l'image Docker et la pousse avec deux tags : `vX.Y.Z` (archive) et `latest` (production). Utilise le cache registry pour accélérer les builds suivants | -| **Backup database before deployment** | Via le socket Docker, exécute `pg_dump` dans le conteneur `bonsai-api-db` et sauvegarde le dump compressé dans `/opt/backups/bonsai-api/`. **Bloque le déploiement si le backup échoue.** Conserve les 10 derniers backups | -| **Trigger production deployment** | Appelle le webhook Watchtower — Watchtower détecte la nouvelle image `:latest` et redémarre le conteneur API | -| **Merge release to main** | Restore `build.gradle` (pour annuler la modification locale), puis merge la branche de release dans `main` avec un commit de merge `--no-ff` | -| **Bump version to next SNAPSHOT on develop** | Incrémente le patch sur `develop` (ex. `1.2.3` → `1.2.4-SNAPSHOT`) et pousse le commit | - -### Bonsai Webapp - -| Étape | Ce qu'elle fait | -|---|---| -| **Checkout** | Clone le dépôt | -| **Set up Docker Buildx** | Active Buildx avec cache registry | -| **Login to Gitea registry** | Authentifie le runner | -| **Set lowercase repo name** | Normalise le nom du repo | -| **Bump version in package.json** | Met à jour le champ `version` dans `package.json` avec le tag de release | -| **Build and push** | Build l'image Docker (inclut le `npm run build` via le Dockerfile) et pousse `vX.Y.Z` + `latest` | -| **Trigger production deployment** | Appelle le webhook Watchtower | -| **Merge release to main** | Merge la branche de release dans `main` | -| **Bump version to next SNAPSHOT on develop** | Incrémente le patch sur `develop` dans `package.json` | - ---- - -## Workflow Rollback (`rollback.yml`) - -**Déclencheur** : manuel via **Actions → Rollback → Run workflow** dans l'interface Gitea. - -**Paramètres** : -- `version` *(obligatoire)* — version cible, ex. `v1.2.3` -- `restore_db` *(API seulement, défaut : `no`)* — `yes` pour restaurer aussi la base de données - -| Étape | Ce qu'elle fait | -|---|---| -| **Login to Gitea registry** | Authentifie le runner sur le registry | -| **Set lowercase repo name** | Normalise le nom du repo | -| **Retag version as latest** | Pull l'image `vX.Y.Z`, la retague en `latest` et la repousse — Watchtower déploiera cette version | -| **Restore database backup** | *(si `restore_db=yes`)* Arrête le conteneur API, supprime et recrée la base de données, restaure le dump compressé correspondant à la version cible depuis `/opt/backups/bonsai-api/` | -| **Trigger production deployment** | Appelle le webhook Watchtower pour redéployer avec l'image rétrogradée | - -> **Voir aussi** : [Mise à jour des applications](Mise-a-jour-Applications) pour la procédure de rollback complète et la gestion des backups. - ---- - -## Workflow Release Luz (`release.yml`) - -**Déclencheur** : tout `push` sur `main`. - -**Versionnage automatique** : le workflow lit le dernier tag `vX.Y.Z`, incrémente le patch (`Z+1`) et crée un nouveau tag. Si aucun tag n'existe, démarre à `v0.1.0`. - -| Étape | Ce qu'elle fait | -|---|---| -| **Tests & couverture** | *(job `test`)* Lance `npm ci` puis `npm test -- --watch=false` — bloque la release si les tests échouent | -| **Checkout** | Clone avec `fetch-depth: 0` pour récupérer tous les tags | -| **Calculate next version** | Calcule le prochain tag en incrémentant le patch du dernier tag | -| **Bump version in package.json** | Met à jour le champ `version`, commite et pousse sur `main` | -| **Set up Docker Buildx** | Active Buildx avec cache registry | -| **Login to Gitea registry** | Authentifie le runner sur `git.goutailler-olivier.com` avec `RELEASE_TOKEN` | -| **Build and push** | Build l'image Docker et pousse `vX.Y.Z` + `latest` avec cache registry | -| **Create Gitea release** | Crée la release sur Gitea via l'API avec le tag calculé | - ---- - -## Secrets requis - -| Secret | Utilisé par | Rôle | -|---|---|---| -| `RELEASE_TOKEN` | `release.yml`, `rollback.yml` | Token Gitea avec accès en écriture au registry et au dépôt (push sur `main` et `develop`) | -| `WATCHTOWER_TOKEN` | `release.yml`, `rollback.yml` | Token Bearer pour l'API HTTP de Watchtower | - ---- - -## Infrastructure du runner - -Le runner (`gitea-runner`) est configuré dans `Infra/gitea/gitea-compose.yml` avec : -- **Label** `ubuntu-latest:host` — les jobs s'exécutent directement dans le conteneur runner -- **Socket Docker monté** (`/var/run/docker.sock`) — accès direct aux conteneurs de l'hôte sans SSH -- **Dossier backups monté** (`/opt/backups`) — les backups écrits par le runner sont persistés sur l'hôte diff --git a/Changelog.md b/Changelog.md deleted file mode 100644 index 7b860c0..0000000 --- a/Changelog.md +++ /dev/null @@ -1,15 +0,0 @@ -# Changelog - -## 2026-06-05 — Workflow release automatique pour Luz - -- `CI-CD.md` — documentation du workflow `release.yml` de Luz : déclencheur push main, versionnage automatique, jobs test + release - -## 2026-06-05 — Ajout du projet Luz - -- `Home.md` — ajout de Luz dans l'architecture et le tableau des services -- `Installation-Production.md` — section 7 Luz avec commandes de démarrage et secrets requis -- `Mise-a-jour-Applications.md` — procédure de rollback Luz, Luz ajouté dans la boucle de mise à jour globale - -## 2026-06-02 — Fix CI release Bonsai-webapp : bump version commité avant merge main - -- `Mise-a-jour-Applications.md` — documentation du bug (package.json modifié non commité bloquait git checkout main) et de la correction (commit du bump avant le merge, sauvegarde du RELEASE_HEAD) diff --git a/Home.md b/Home.md deleted file mode 100644 index 5a0001e..0000000 --- a/Home.md +++ /dev/null @@ -1,41 +0,0 @@ -# Infrastructure — Vue d'ensemble - -Ce dépôt contient toutes les configurations Docker Compose de l'infrastructure auto-hébergée. - -## Architecture - -``` -Internet - │ - ▼ - Traefik (reverse proxy, TLS Let's Encrypt) - │ - ├── git.goutailler-olivier.com → Gitea (forge + CI/CD) - ├── auth.goutailler-olivier.com → Keycloak (SSO / OAuth2) - ├── bonsai.goutailler-olivier.com - │ ├── /api → Bonsai API (Spring Boot) - │ └── / → Bonsai Webapp (front-end) - ├── luz.goutailler-olivier.com → Luz (front-end Angular) - ├── cloud.goutailler-olivier.com → Nextcloud - └── notes.goutailler-olivier.com → Trilium -``` - -## Services - -| Service | Dossier | URL | -|---|---|---| -| Traefik | `traefik/` | `traefik.goutailler-olivier.com` | -| Gitea | `gitea/` | `git.goutailler-olivier.com` | -| Keycloak | `keycloak/` | `auth.goutailler-olivier.com` | -| Bonsai API | `bonsai-api/` | `bonsai.goutailler-olivier.com/api` | -| Bonsai Webapp | `bonsai-webapp/` | `bonsai.goutailler-olivier.com` | -| Luz | `luz/` | `luz.goutailler-olivier.com` | -| Nextcloud | `nextcloud/` | `cloud.goutailler-olivier.com` | -| Trilium | `trilium/` | `notes.goutailler-olivier.com` | - -## Pages - -- [Installation Production](Installation-Production) -- [Installation Développement](Installation-Developpement) -- [Mise à jour des applications](Mise-a-jour-Applications) -- [CI/CD — Pipelines Gitea Actions](CI-CD) diff --git a/Installation-Developpement.md b/Installation-Developpement.md deleted file mode 100644 index 54905af..0000000 --- a/Installation-Developpement.md +++ /dev/null @@ -1,150 +0,0 @@ -# Installation Développement - -Cette page décrit comment démarrer l'environnement de développement local pour le projet **Bonsai API**. - -## Prérequis - -| Outil | Version minimale | -|---|---| -| Java JDK | 25 | -| Docker + Docker Compose | 24+ | -| Gradle | 8+ (wrapper inclus dans le dépôt) | - ---- - -## Cloner le dépôt - -```bash -git clone https://git.goutailler-olivier.com/bonsai/bonsai-api.git -cd bonsai-api -``` - ---- - -## Option A — Hot-reload avec Docker Compose (recommandé) - -Cette option monte les sources depuis l'hôte dans le conteneur. Gradle détecte les changements et relance automatiquement l'application. - -```bash -docker compose -f docker-compose.dev.yml up --build -``` - -- L'API est disponible sur `http://localhost:8080` -- PostgreSQL est disponible sur `localhost:5432` -- Le cache Gradle est conservé dans un volume dédié (`gradle_home`) : le premier build télécharge les dépendances, les suivants sont rapides - -Pour arrêter et tout supprimer (y compris les volumes) : - -```bash -docker compose -f docker-compose.dev.yml down -v -``` - ---- - -## Option B — Gradle en local + PostgreSQL Docker - -Démarrer uniquement la base de données : - -```bash -docker compose up db -d -``` - -Lancer l'API avec le wrapper Gradle : - -```bash -./gradlew bootRun -``` - -Flyway applique automatiquement la migration `V1__init.sql` au premier démarrage. - ---- - -## Variables d'environnement - -En développement, les valeurs par défaut sont utilisées automatiquement (définies dans `src/main/resources/application.yml`). Aucun `.env` n'est nécessaire. - -| Variable | Valeur locale | Description | -|---|---|---| -| `DATASOURCE_URL` | `jdbc:postgresql://localhost:5432/bonsai` | URL JDBC | -| `DATASOURCE_USERNAME` | `bonsai` | Utilisateur PostgreSQL | -| `DATASOURCE_PASSWORD` | `bonsai` | Mot de passe PostgreSQL | -| `KEYCLOAK_JWKS_URI` | `https://auth.goutailler-olivier.com/realms/bonsai/protocol/openid-connect/certs` | Endpoint JWKS | -| `CORS_ALLOWED_ORIGIN_PROD` | `https://bonsai.goutailler-olivier.com` | Origine CORS de prod | - -L'origine `http://localhost:4200` est toujours autorisée en CORS (front Angular en dev). - ---- - -## Documentation de l'API - -Swagger UI est disponible à l'adresse suivante une fois l'API démarrée : - -``` -http://localhost:8080/swagger-ui.html -``` - -La spécification OpenAPI (JSON) est accessible sur : - -``` -http://localhost:8080/v3/api-docs -``` - ---- - -## Lancer les tests - -```bash -./gradlew test -``` - -Le rapport HTML est généré dans `build/reports/tests/test/index.html`. - ---- - -## Structure du projet - -``` -src/main/java/fr/bonsai/api/ -├── domain/model/ # Entités métier (sans dépendance Spring) -├── application/ -│ ├── port/in/ # Interfaces des use cases -│ ├── port/out/ # Interface du repository -│ └── usecase/ # Logique métier (IssueService) -├── adapter/ -│ ├── in/web/ # Controllers REST et DTOs -│ └── out/persistence/ # Entités JPA et adaptateur repository -└── config/ # Configuration Spring (Security, CORS, Beans) -``` - ---- - -## Sécurité - -Toutes les routes nécessitent un token JWT Bearer valide émis par Keycloak : - -- **Realm** : `bonsai` -- **Client** : `bonsai-webapp` -- **Issuer** : `https://auth.goutailler-olivier.com/realms/bonsai` - -Pour tester sans Keycloak local, utiliser l'instance de production comme fournisseur JWKS (valeur par défaut). - -```http -Authorization: Bearer -``` - ---- - -## Endpoints disponibles - -| Méthode | Route | Description | -|---|---|---| -| `GET` | `/issues` | Liste toutes les issues | -| `POST` | `/issues` | Crée une issue | -| `PUT` | `/issues/{id}` | Remplace une issue | -| `DELETE` | `/issues/{id}` | Supprime une issue (204) | - ---- - -## CI/CD - -Le pipeline Gitea Actions (`.gitea/workflows/`) construit l'image Docker et la pousse sur le registre interne à chaque push sur `main`. Le runner `ubuntu-latest` est fourni par le conteneur `act_runner` de la stack Gitea. diff --git a/Installation-Production.md b/Installation-Production.md deleted file mode 100644 index b64e29a..0000000 --- a/Installation-Production.md +++ /dev/null @@ -1,212 +0,0 @@ -# Installation Production - -## Prérequis - -- Serveur Linux avec Docker 24+ et Docker Compose V2 -- Domaine DNS pointant vers le serveur (`goutailler-olivier.com`) -- Ports **80**, **443** et **2222** ouverts en entrée - ---- - -## 1. Réseau Docker partagé - -Tous les services communiquent via un réseau externe `proxy`. À créer une seule fois : - -```bash -docker network create proxy -``` - ---- - -## 2. Traefik - -Traefik est le point d'entrée unique : il gère le TLS (Let's Encrypt) et route les requêtes vers chaque service. - -```bash -cd traefik/ -docker compose up -d -``` - -Le dashboard est exposé sur `https://traefik.goutailler-olivier.com` (accès restreint par défaut). - ---- - -## 3. Keycloak - -Keycloak gère l'authentification SSO pour toute l'infrastructure. - -```bash -cd keycloak/ -cp .env.example .env -# Éditer .env avec des mots de passe sécurisés -docker compose up -d -``` - -Variables à définir dans `.env` : - -| Variable | Description | -|---|---| -| `POSTGRES_PASSWORD` | Mot de passe de la base PostgreSQL | -| `KEYCLOAK_ADMIN` | Login administrateur (défaut : `admin`) | -| `KEYCLOAK_ADMIN_PASSWORD` | Mot de passe administrateur | - -**Configuration post-démarrage :** - -1. Se connecter à `https://auth.goutailler-olivier.com/admin` -2. Créer le realm `bonsai` -3. Créer le client `bonsai-webapp` (type *OpenID Connect*, flux *Authorization Code*) -4. Configurer les *Valid redirect URIs* : `https://bonsai.goutailler-olivier.com/*` - ---- - -## 4. Gitea - -Gitea est la forge Git avec le runner CI/CD intégré. - -```bash -cd gitea/ -docker compose -f gitea-compose.yml up -d -``` - -**Configuration post-démarrage :** - -1. Accéder à `https://git.goutailler-olivier.com` et terminer l'installation via l'interface web -2. Créer l'organisation `bonsai` -3. Récupérer un token d'enregistrement pour le runner dans *Administration → Actions → Runners* -4. Mettre à jour `GITEA_RUNNER_REGISTRATION_TOKEN` dans `gitea-compose.yml`, puis redémarrer le service `act_runner` - -Le runner est configuré avec le label `ubuntu-latest` mappé sur `ubuntu:22.04`. - ---- - -## 5. Bonsai API - -L'image est construite par la CI Gitea et poussée sur le registre `git.goutailler-olivier.com/bonsai/bonsai-api:latest`. - -Le registre Gitea requiert une authentification. Se connecter une première fois avec son compte Gitea : - -```bash -docker login git.goutailler-olivier.com -u -``` - -> **Note :** par défaut, Docker stocke le mot de passe en clair dans `~/.docker/config.json`. Pour éviter cela, configurer un [credential helper](https://docs.docker.com/engine/reference/commandline/login/#credentials-store). - -```bash -cd bonsai-api/ -# Créer un fichier .env avec le mot de passe PostgreSQL -echo "POSTGRES_PASSWORD=" > .env -docker compose up -d -``` - -Variables d'environnement : - -| Variable | Description | -|---|---| -| `POSTGRES_PASSWORD` | Mot de passe PostgreSQL (injecté via `.env`) | -| `DATASOURCE_URL` | `jdbc:postgresql://db:5432/bonsai` (défaut réseau interne) | -| `KEYCLOAK_JWKS_URI` | `https://auth.goutailler-olivier.com/realms/bonsai/protocol/openid-connect/certs` | -| `CORS_ALLOWED_ORIGIN_PROD` | `https://bonsai.goutailler-olivier.com` | - -Flyway applique automatiquement les migrations SQL au démarrage. - -**Documentation API (Swagger UI) :** - -| Environnement | URL | -|---|---| -| Production | `https://bonsai.goutailler-olivier.com/api/swagger-ui.html` | -| Développement local | `http://localhost:8080/swagger-ui.html` | - -La définition OpenAPI brute est disponible sur `/v3/api-docs`. - ---- - -## 6. Bonsai Webapp - -```bash -cd bonsai-webapp/ -docker compose up -d -``` - -L'image `git.goutailler-olivier.com/bonsai/bonsai-webapp:latest` est également construite par la CI. Aucune variable d'environnement spécifique n'est requise. - ---- - -## 7. Luz - -```bash -cd luz/ -docker compose up -d -``` - -L'image `git.goutailler-olivier.com/gato/luz:latest` est construite par la CI Gitea lors d'une release. Aucune variable d'environnement spécifique n'est requise. - -**Secrets Gitea à configurer dans le dépôt Luz :** - -| Secret | Description | -|---|---| -| `RELEASE_TOKEN` | Token Gitea avec droits `write:packages` et `write:repository` | -| `WATCHTOWER_TOKEN` | Token HTTP de l'API Watchtower pour déclencher le redéploiement | - ---- - -## 9. Nextcloud - -```bash -cd nextcloud/ -# Adapter les mots de passe dans docker-compose.yml avant le premier démarrage -docker compose up -d -``` - -Variables à personnaliser dans `docker-compose.yml` avant le premier lancement : - -| Variable | Description | -|---|---| -| `POSTGRES_PASSWORD` | Mot de passe PostgreSQL | -| `NEXTCLOUD_ADMIN_USER` | Compte administrateur Nextcloud | -| `NEXTCLOUD_ADMIN_PASSWORD` | Mot de passe administrateur | - ---- - -## 10. Trilium - -```bash -cd trilium/ -docker compose up -d -``` - -Les données sont persistées dans `/home/gato/Applications/Trilium/data` sur l'hôte. S'assurer que ce chemin existe avant le démarrage : - -```bash -mkdir -p /home/gato/Applications/Trilium/data -``` - ---- - -## Ordre de démarrage recommandé - -``` -1. Réseau proxy (une seule fois) -2. Traefik -3. Keycloak -4. Gitea -5. Bonsai API -6. Bonsai Webapp -7. Luz -8. Nextcloud -9. Trilium -``` - ---- - -## Vérifications - -```bash -# État de tous les conteneurs -docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" - -# Logs d'un service -docker logs --tail 50 -f - -# Certificats TLS Traefik -docker logs traefik 2>&1 | grep -i "certificate\|acme" -``` diff --git a/Mise-a-jour-Applications.md b/Mise-a-jour-Applications.md deleted file mode 100644 index 9fda409..0000000 --- a/Mise-a-jour-Applications.md +++ /dev/null @@ -1,185 +0,0 @@ -# Mise à jour des applications - -Chaque application est packagée sous forme d'image Docker publiée sur le registre Gitea (`git.goutailler-olivier.com`) par la CI lors d'une release. La mise à jour en production consiste à récupérer la nouvelle image et à recréer le conteneur. - ---- - -## Principe général - -```bash -cd / -docker compose pull # télécharge la nouvelle image -docker compose up -d # recrée le conteneur si l'image a changé -``` - -`docker compose up -d` détecte automatiquement que l'image locale est différente de celle utilisée par le conteneur en cours et le recrée. Le temps d'indisponibilité est limité à la durée du redémarrage du conteneur (quelques secondes). - ---- - -## Exemple : mettre à jour Bonsai Webapp - -Une nouvelle release a été publiée sur Gitea et l'image `bonsai-webapp:latest` a été mise à jour par la CI. - -```bash -cd bonsai-webapp/ -docker compose pull -docker compose up -d -``` - -Vérifier que le conteneur tourne bien avec la nouvelle image : - -```bash -docker inspect bonsai-webapp --format '{{.Image}}' -# ou -docker compose ps -``` - ---- - -## Mettre à jour une version précise (tag de release) - -Par défaut les `docker-compose.yml` pointent sur `:latest`. Pour épingler une version spécifique, éditer le fichier et remplacer le tag : - -```yaml -image: git.goutailler-olivier.com/bonsai/bonsai-webapp:v1.2.3 -``` - -Puis appliquer : - -```bash -docker compose pull -docker compose up -d -``` - ---- - -## Notes sur le workflow de release (CI) - -### `fetch-depth: 0` requis sur le checkout - -Le job `release.yml` de Bonsai-webapp (et Bonsai-api) effectue un `git merge` du tag de release dans `main` à la fin du pipeline. `actions/checkout@v4` fait par défaut un clone superficiel (`--depth 1`), ce qui empêche git de trouver l'ancêtre commun entre le tag et `main` → erreur `refusing to merge unrelated histories`. - -**Solution appliquée** : ajouter `fetch-depth: 0` sur le step Checkout : - -```yaml -- name: Checkout - uses: https://github.com/actions/checkout@v4 - with: - fetch-depth: 0 -``` - -Sans ce paramètre, tout nouveau runner qui clone le dépôt avec historique limité fera échouer l'étape « Merge release to main ». - -### Bump de version commité avant le merge - -Le step « Bump version in package.json » modifie `package.json` pour y inscrire la version de la release. Ce changement est **commité sur le HEAD détaché** (tag checkout) avant que le build Docker ne commence. Le step « Merge release to main » sauvegarde ensuite le hash de ce commit (`RELEASE_HEAD`) et merge ce commit (et non le tag) sur `main` : - -```yaml -- name: Bump version in package.json - run: | - # ... sed + git config ... - git add package.json - git commit -m "chore: set version to $VERSION" - -- name: Merge release to main - run: | - RELEASE_HEAD=$(git rev-parse HEAD) - git checkout main - git merge --no-ff "$RELEASE_HEAD" -m "chore: release ..." - git push origin main -``` - -**Pourquoi** : sans ce commit préalable, `git checkout main` échoue avec *"Your local changes would be overwritten by checkout"* car `package.json` est modifié mais non commité. - ---- - -## Revenir à une version précédente (rollback) - -Un workflow Gitea Actions dédié permet de déclencher un rollback sans toucher au serveur manuellement. - -### Rollback Bonsai Webapp - -1. Aller dans **Gitea → Bonsai-webapp → Actions → Rollback → Run workflow** -2. Saisir la version cible (ex. `v1.2.3`) -3. Lancer — Watchtower redéploie automatiquement - -### Rollback Bonsai API (avec ou sans restauration BDD) - -1. Aller dans **Gitea → Bonsai-api → Actions → Rollback → Run workflow** -2. Saisir la version cible (ex. `v1.2.3`) -3. Choisir `restore_db` : - - `no` (défaut) — rollback du code uniquement (migrations Flyway compatibles) - - `yes` — rollback du code **et** restauration de la base de données depuis le backup créé avant ce déploiement - -> **Attention** : `restore_db=yes` écrase toutes les données créées depuis le déploiement à annuler. À réserver aux cas où la migration de schéma est incompatible avec l'ancienne version. - -### Ce que fait le workflow en coulisse - -1. Retague l'image `image:vX.Y.Z` en `image:latest` dans le registry Gitea -2. (Si `restore_db=yes`) Via le socket Docker du runner, arrête l'API et restaure le dump PostgreSQL depuis `/opt/backups/bonsai-api/` -3. Déclenche Watchtower → redéploie le conteneur avec la version rétrogradée - ---- - -## Backups de la base de données - -Un backup compressé (`pg_dump | gzip`) est créé automatiquement **avant chaque déploiement** de Bonsai API. - -- **Emplacement sur le serveur** : `/opt/backups/bonsai-api/` -- **Format du nom** : `bonsai_v1.2.3_20260531_143000.sql.gz` -- **Rétention** : les 10 derniers backups sont conservés, les plus anciens sont supprimés automatiquement - -Pour lister les backups disponibles sur le serveur : - -```bash -ls -lh /opt/backups/bonsai-api/ -``` - -Pour restaurer manuellement un backup : - -```bash -VERSION="v1.2.3" -BACKUP_FILE=$(ls -t /opt/backups/bonsai-api/bonsai_${VERSION}_*.sql.gz | head -1) - -docker stop bonsai-api -docker exec bonsai-api-db psql -U bonsai postgres \ - -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname='bonsai' AND pid != pg_backend_pid();" -docker exec bonsai-api-db dropdb -U bonsai bonsai -docker exec bonsai-api-db createdb -U bonsai bonsai -gunzip -c "$BACKUP_FILE" | docker exec -i bonsai-api-db psql -U bonsai bonsai -docker start bonsai-api -``` - ---- - -## Rollback Luz - -1. Aller dans **Gitea → Luz → Actions → Rollback → Run workflow** -2. Saisir la version cible (ex. `v1.2.3`) -3. Lancer — Watchtower redéploie automatiquement - ---- - -## Mettre à jour tous les services d'un coup - -```bash -for dir in traefik keycloak gitea bonsai-api bonsai-webapp luz nextcloud trilium; do - echo "=== $dir ===" - (cd "$dir" && docker compose pull && docker compose up -d) -done -``` - ---- - -## Vérifications après mise à jour - -```bash -# État de tous les conteneurs -docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" - -# Logs du service mis à jour -docker logs bonsai-webapp --tail 50 -f - -# Supprimer les anciennes images devenues inutiles -docker image prune -f -``` diff --git a/bonsai-api/docker-compose.yml b/bonsai-api/docker-compose.yml new file mode 100644 index 0000000..49b30af --- /dev/null +++ b/bonsai-api/docker-compose.yml @@ -0,0 +1,54 @@ +name: bonsai-api-stack + +services: + db: + image: postgres:16-alpine + container_name: bonsai-api-db + restart: unless-stopped + environment: + POSTGRES_DB: bonsai + POSTGRES_USER: bonsai + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + TZ: Europe/Paris + healthcheck: + test: ["CMD-SHELL", "pg_isready -U bonsai -d bonsai"] + interval: 10s + timeout: 5s + retries: 5 + volumes: + - ./db_data:/var/lib/postgresql/data + networks: + - bonsai-api-net + + api: + image: git.goutailler-olivier.com/bonsai/bonsai-api:latest + container_name: bonsai-api + restart: unless-stopped + depends_on: + db: + condition: service_healthy + environment: + DATASOURCE_URL: jdbc:postgresql://db:5432/bonsai + DATASOURCE_USERNAME: bonsai + DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD} + KEYCLOAK_JWKS_URI: https://auth.goutailler-olivier.com/realms/bonsai/protocol/openid-connect/certs + CORS_ALLOWED_ORIGIN_PROD: https://bonsai.goutailler-olivier.com + TZ: Europe/Paris + networks: + - bonsai-api-net + - proxy + labels: + - traefik.enable=true + - traefik.http.routers.bonsai-api.rule=Host(`bonsai.goutailler-olivier.com`) && PathPrefix(`/api`) + - traefik.http.routers.bonsai-api.entrypoints=websecure + - traefik.http.routers.bonsai-api.tls.certresolver=le + - traefik.http.services.bonsai-api.loadbalancer.server.port=8080 + - traefik.docker.network=proxy + - com.centurylinklabs.watchtower.enable=true + +networks: + bonsai-api-net: + driver: bridge + proxy: + external: true + name: proxy diff --git a/bonsai-webapp/docker-compose.yml b/bonsai-webapp/docker-compose.yml new file mode 100644 index 0000000..729b7b9 --- /dev/null +++ b/bonsai-webapp/docker-compose.yml @@ -0,0 +1,27 @@ +name: bonsai-webapp + +services: + bonsai-webapp: + image: git.goutailler-olivier.com/bonsai/bonsai-webapp:latest + container_name: bonsai-webapp + restart: unless-stopped + + environment: + TZ: Europe/Paris + + networks: + - proxy + + labels: + - traefik.enable=true + - traefik.http.routers.bonsai-webapp.rule=Host(`bonsai.goutailler-olivier.com`) + - traefik.http.routers.bonsai-webapp.entrypoints=websecure + - traefik.http.routers.bonsai-webapp.tls.certresolver=le + - traefik.http.services.bonsai-webapp.loadbalancer.server.port=80 + - traefik.docker.network=proxy + - com.centurylinklabs.watchtower.enable=true + +networks: + proxy: + external: true + name: proxy diff --git a/gitea/Dockerfile.runner b/gitea/Dockerfile.runner new file mode 100644 index 0000000..ae2f143 --- /dev/null +++ b/gitea/Dockerfile.runner @@ -0,0 +1,9 @@ +FROM gitea/act_runner:latest + +# Installer Node.js et npm +RUN apk add --no-cache nodejs npm + +# Docker CLI déjà installé via le wget précédent +RUN wget -O /tmp/docker.tgz https://download.docker.com/linux/static/stable/x86_64/docker-26.1.4.tgz \ + && tar -xzf /tmp/docker.tgz --strip-components=1 -C /usr/local/bin docker/docker \ + && rm /tmp/docker.tgz \ No newline at end of file diff --git a/gitea/README.md b/gitea/README.md new file mode 100644 index 0000000..7075e12 --- /dev/null +++ b/gitea/README.md @@ -0,0 +1,13 @@ +## Mise a jours + +```bash +docker compose -f gitea-compose.yml down +tar -czvf gitea_backup_$(date +%Y%m%d).tar.gz ./gitea ./db_data +docker compose -f gitea-compose.yml pull gitea +docker compose -f gitea-compose.yml up -d +docker exec gitea gitea --version +``` +Relancer le runner +```bash +docker compose -f gitea-compose.yml restart act_runner +``` diff --git a/gitea/gitea-compose.yml b/gitea/gitea-compose.yml index 5b93e1e..0947f04 100644 --- a/gitea/gitea-compose.yml +++ b/gitea/gitea-compose.yml @@ -88,7 +88,7 @@ services: - gitea environment: GITEA_INSTANCE_URL: http://gitea:3000 - GITEA_RUNNER_REGISTRATION_TOKEN: IZM8wKkzR4XZogOxsb5or3JKiugXyguFtA0zjNWZ + GITEA_RUNNER_REGISTRATION_TOKEN: Rvi31evVGlyH8o1h2lw200uMjOJyCrBQJXLKQqJk GITEA_RUNNER_NAME: docker-runner GITEA_RUNNER_LABELS: ubuntu-latest:host CONFIG_FILE: /config.yaml @@ -98,7 +98,6 @@ services: - ./runner_data:/data - ./runner_data/config.yaml:/config.yaml - /var/run/docker.sock:/var/run/docker.sock - - /opt/backups:/opt/backups networks: - gitea-net diff --git a/keycloak/.env.example b/keycloak/.env.example new file mode 100644 index 0000000..5879524 --- /dev/null +++ b/keycloak/.env.example @@ -0,0 +1,3 @@ +POSTGRES_PASSWORD=changeme +KEYCLOAK_ADMIN=admin +KEYCLOAK_ADMIN_PASSWORD=changeme diff --git a/keycloak/docker-compose.yml b/keycloak/docker-compose.yml new file mode 100644 index 0000000..cbb452a --- /dev/null +++ b/keycloak/docker-compose.yml @@ -0,0 +1,67 @@ +name: keycloak-stack + +services: + db: + image: postgres:16-alpine + container_name: keycloak-db + restart: unless-stopped + environment: + POSTGRES_DB: keycloak + POSTGRES_USER: keycloak + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + TZ: Europe/Paris + healthcheck: + test: ["CMD-SHELL", "pg_isready -U keycloak -d keycloak"] + interval: 10s + timeout: 5s + retries: 5 + volumes: + - ./db_data:/var/lib/postgresql/data + networks: + - keycloak-net + + keycloak: + image: quay.io/keycloak/keycloak:26.2 + container_name: keycloak + restart: unless-stopped + command: start + depends_on: + db: + condition: service_healthy + environment: + KC_DB: postgres + KC_DB_URL: jdbc:postgresql://db:5432/keycloak + KC_DB_USERNAME: keycloak + KC_DB_PASSWORD: ${POSTGRES_PASSWORD} + + KC_HOSTNAME: auth.goutailler-olivier.com + KC_HOSTNAME_STRICT: "true" + KC_HTTP_ENABLED: "true" + KC_PROXY_HEADERS: xforwarded + + KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN:-admin} + KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD} + + TZ: Europe/Paris + KC_SPI_THEME_STATIC_MAX_AGE: "-1" + KC_SPI_THEME_CACHE_THEMES: "false" + KC_SPI_THEME_CACHE_TEMPLATES: "false" + volumes: + - ./themes:/opt/keycloak/themes + networks: + - keycloak-net + - proxy + labels: + - traefik.enable=true + - traefik.http.routers.keycloak.rule=Host(`auth.goutailler-olivier.com`) + - traefik.http.routers.keycloak.entrypoints=websecure + - traefik.http.routers.keycloak.tls.certresolver=le + - traefik.http.services.keycloak.loadbalancer.server.port=8080 + - traefik.docker.network=proxy + +networks: + keycloak-net: + driver: bridge + proxy: + external: true + name: proxy diff --git a/keycloak/themes/bonsai/login/login-reset-password.ftl b/keycloak/themes/bonsai/login/login-reset-password.ftl new file mode 100644 index 0000000..0d6bb3c --- /dev/null +++ b/keycloak/themes/bonsai/login/login-reset-password.ftl @@ -0,0 +1,61 @@ + + + + + + Bonsai — Réinitialisation du mot de passe + + + +
+
+ + + +

Mot de passe oublié ?

+

Saisissez votre email pour recevoir un lien de réinitialisation.

+ + <#if message?has_content> +
+ ${message.summary} +
+ + +
+
+ + +
+ + +
+ + + +
+
+ + diff --git a/keycloak/themes/bonsai/login/login.ftl b/keycloak/themes/bonsai/login/login.ftl new file mode 100644 index 0000000..6cd264c --- /dev/null +++ b/keycloak/themes/bonsai/login/login.ftl @@ -0,0 +1,105 @@ + + + + + + Bonsai — Connexion + + + +
+
+ + + +

Connexion

+ + <#if message?has_content> +
+ ${message.summary} +
+ + + <#if realm.password> +
+ value="${auth.selectedCredential}"/> + +
+ + disabled + autofocus + /> +
+ +
+
+ + <#if realm.resetPasswordAllowed> + + Mot de passe oublié ? + + +
+ +
+ + <#if realm.rememberMe && !usernameEditDisabled??> +
+ checked> + +
+ + + +
+ + + <#if social.providers?has_content> +
ou
+
+ <#list social.providers as p> + + Continuer avec ${p.displayName!''} + + +
+ + + <#if realm.password && realm.registrationAllowed && !registrationDisabled??> + + + +
+
+ + diff --git a/keycloak/themes/bonsai/login/resources/css/login.css b/keycloak/themes/bonsai/login/resources/css/login.css new file mode 100644 index 0000000..f4ac615 --- /dev/null +++ b/keycloak/themes/bonsai/login/resources/css/login.css @@ -0,0 +1,262 @@ +*, *::before, *::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: system-ui, -apple-system, sans-serif; + font-size: 0.9rem; + color: #111827; + background: #f0fdf4; + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; +} + +/* ── Page ── */ +.page { + width: 100%; + padding: 1.5rem; + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; +} + +/* ── Card ── */ +.card { + background: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 0.75rem; + padding: 2.5rem 2rem; + width: 100%; + max-width: 380px; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06); + display: flex; + flex-direction: column; + gap: 1.25rem; +} + +/* ── Logo ── */ +.logo { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.4rem; +} + +.logo svg { + width: 52px; + height: 60px; +} + +.logo-name { + font-size: 1.3rem; + font-weight: 800; + color: #111827; + letter-spacing: -0.02em; +} + +/* ── Titles ── */ +.title { + font-size: 1.1rem; + font-weight: 700; + color: #111827; + text-align: center; +} + +.subtitle { + font-size: 0.85rem; + color: #6b7280; + text-align: center; + line-height: 1.5; +} + +/* ── Alert ── */ +.alert { + padding: 0.65rem 0.875rem; + border-radius: 0.5rem; + font-size: 0.85rem; + line-height: 1.4; +} + +.alert--error { + background: #fef2f2; + color: #dc2626; + border: 1px solid #fecaca; +} + +.alert--warning { + background: #fffbeb; + color: #d97706; + border: 1px solid #fde68a; +} + +.alert--success { + background: #f0fdf4; + color: #16a34a; + border: 1px solid #bbf7d0; +} + +.alert--info { + background: #eff6ff; + color: #2563eb; + border: 1px solid #bfdbfe; +} + +/* ── Form fields ── */ +.field { + display: flex; + flex-direction: column; + gap: 0.375rem; +} + +.field-label-row { + display: flex; + justify-content: space-between; + align-items: baseline; +} + +.field label { + font-size: 0.85rem; + font-weight: 500; + color: #374151; +} + +.field input { + width: 100%; + padding: 0.55rem 0.75rem; + border: 1px solid #d1d5db; + border-radius: 0.5rem; + font-size: 0.9rem; + color: #111827; + background: #ffffff; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.field input:focus { + border-color: #2F855A; + box-shadow: 0 0 0 3px rgba(47, 133, 90, 0.15); +} + +.field input:disabled { + background: #f3f4f6; + color: #9ca3af; + cursor: not-allowed; +} + +.forgot-link { + font-size: 0.78rem; + color: #2F855A; + text-decoration: none; +} + +.forgot-link:hover { + text-decoration: underline; +} + +/* ── Remember me ── */ +.remember { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.remember input[type="checkbox"] { + width: 1rem; + height: 1rem; + accent-color: #2F855A; + cursor: pointer; + flex-shrink: 0; +} + +.remember label { + font-size: 0.85rem; + color: #374151; + cursor: pointer; +} + +/* ── Primary button ── */ +.btn-primary { + width: 100%; + padding: 0.6rem; + background: #2F855A; + color: #ffffff; + font-size: 0.9rem; + font-weight: 600; + border: none; + border-radius: 0.5rem; + cursor: pointer; + transition: background 0.15s; +} + +.btn-primary:hover { + background: #276749; +} + +.btn-primary:active { + background: #1e5236; +} + +/* ── Divider ── */ +.divider { + display: flex; + align-items: center; + gap: 0.75rem; + color: #9ca3af; + font-size: 0.8rem; +} + +.divider::before, +.divider::after { + content: ''; + flex: 1; + border-top: 1px solid #e5e7eb; +} + +/* ── Social buttons ── */ +.socials { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.btn-social { + display: block; + width: 100%; + padding: 0.55rem; + text-align: center; + font-size: 0.875rem; + font-weight: 500; + color: #374151; + background: #ffffff; + border: 1px solid #d1d5db; + border-radius: 0.5rem; + text-decoration: none; + transition: background 0.1s, border-color 0.1s; +} + +.btn-social:hover { + background: #f3f4f6; + border-color: #9ca3af; +} + +/* ── Register link ── */ +.register-link { + text-align: center; + font-size: 0.83rem; + color: #6b7280; +} + +.register-link a { + color: #2F855A; + text-decoration: none; + font-weight: 500; +} + +.register-link a:hover { + text-decoration: underline; +} diff --git a/keycloak/themes/bonsai/login/theme.properties b/keycloak/themes/bonsai/login/theme.properties new file mode 100644 index 0000000..716356c --- /dev/null +++ b/keycloak/themes/bonsai/login/theme.properties @@ -0,0 +1,2 @@ +parent=keycloak +styles=css/login.css diff --git a/luz/docker-compose.yml b/luz/docker-compose.yml new file mode 100644 index 0000000..7e339fa --- /dev/null +++ b/luz/docker-compose.yml @@ -0,0 +1,27 @@ +name: luz + +services: + luz: + image: git.goutailler-olivier.com/gato/luz:latest + container_name: luz + restart: unless-stopped + + environment: + TZ: Europe/Paris + + networks: + - proxy + + labels: + - traefik.enable=true + - traefik.http.routers.luz.rule=Host(`luz.goutailler-olivier.com`) + - traefik.http.routers.luz.entrypoints=websecure + - traefik.http.routers.luz.tls.certresolver=le + - traefik.http.services.luz.loadbalancer.server.port=80 + - traefik.docker.network=proxy + - com.centurylinklabs.watchtower.enable=true + +networks: + proxy: + external: true + name: proxy diff --git a/nextcloud/docker-compose.yml b/nextcloud/docker-compose.yml new file mode 100644 index 0000000..83af8e4 --- /dev/null +++ b/nextcloud/docker-compose.yml @@ -0,0 +1,95 @@ +# Nextcloud on port 8088 with Postgres and pgAdmin +# ------------------------------------------------ +# Quick start: +# docker compose up -d # (Compose V2 syntax; no `version:` key) + +name: nextcloud-stack + +services: + db: + image: postgres:16-alpine + container_name: nextcloud-db + restart: unless-stopped + environment: + POSTGRES_DB: nextcloud + POSTGRES_USER: nextcloud + POSTGRES_PASSWORD: changeme + TZ: Europe/Paris + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + interval: 10s + timeout: 5s + retries: 5 + volumes: + - ./db_data:/var/lib/postgresql/data + networks: + - nextcloud-net + + nextcloud: + image: nextcloud:latest + container_name: nextcloud-app + restart: unless-stopped + depends_on: + db: + condition: service_healthy + environment: + POSTGRES_HOST: db + POSTGRES_DB: nextcloud + POSTGRES_USER: nextcloud + POSTGRES_PASSWORD: changeme + + NEXTCLOUD_ADMIN_USER: admin + NEXTCLOUD_ADMIN_PASSWORD: adminpass + + NEXTCLOUD_TRUSTED_DOMAINS: cloud.goutailler-olivier.com + NEXTCLOUD_OVERWRITEHOST: cloud.goutailler-olivier.com + NEXTCLOUD_OVERWRITEPROTOCOL: https + + NEXTCLOUD_TRUSTED_PROXIES: 172.23.0.0/16 + + APACHE_DISABLE_REWRITE_IP: "1" + PHP_MEMORY_LIMIT: 1G + PHP_UPLOAD_LIMIT: 2G + TZ: Europe/Paris + volumes: + - ./nextcloud_app:/var/www/html + - ./nextcloud_data:/var/www/html/data + networks: + - nextcloud-net + - proxy + labels: + - traefik.enable=true + - traefik.http.routers.nextcloud.rule=Host(`cloud.goutailler-olivier.com`) + - traefik.http.routers.nextcloud.entrypoints=websecure + - traefik.http.routers.nextcloud.tls.certresolver=le + - traefik.http.services.nextcloud.loadbalancer.server.port=80 + - traefik.docker.network=proxy + # (optionnel) quelques en-têtes de sécurité + - traefik.http.routers.nextcloud.middlewares=nc-sec + - traefik.http.middlewares.nc-sec.headers.stsSeconds=31536000 + - traefik.http.middlewares.nc-sec.headers.stsIncludeSubdomains=true + - traefik.http.middlewares.nc-sec.headers.stsPreload=true + - traefik.http.middlewares.nc-sec.headers.contentTypeNosniff=true + - traefik.http.middlewares.nc-sec.headers.browserXssFilter=true + + pgadmin: + image: dpage/pgadmin4:latest + container_name: nextcloud-pgadmin + restart: unless-stopped + environment: + PGADMIN_DEFAULT_EMAIL: admin@example.com + PGADMIN_DEFAULT_PASSWORD: adminpass + PGADMIN_CONFIG_SERVER_MODE: 'False' + TZ: Europe/Paris + volumes: + - ./pgadmin_data:/var/lib/pgadmin + - ./pgadmin/servers.json:/pgadmin4/servers.json:ro + networks: + - nextcloud-net + +networks: + nextcloud-net: + driver: bridge + proxy: + external: true + name: proxy diff --git a/traefik/docker-compose.yml b/traefik/docker-compose.yml new file mode 100644 index 0000000..ed683e9 --- /dev/null +++ b/traefik/docker-compose.yml @@ -0,0 +1,45 @@ +services: + traefik: + image: traefik:v3.0 + container_name: traefik + restart: unless-stopped + command: + - --providers.docker=true + - --providers.docker.exposedbydefault=false + - --providers.docker.network=proxy + - --entrypoints.web.address=:80 + - --entrypoints.websecure.address=:443 + # Redirection HTTP -> HTTPS + - --entrypoints.web.http.redirections.entryPoint.to=websecure + - --entrypoints.web.http.redirections.entryPoint.scheme=https + # Let's Encrypt (HTTP-01) + - --certificatesresolvers.le.acme.email=cedric@goutailler-olivier.com + - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json + - --certificatesresolvers.le.acme.httpchallenge=true + - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web + - --entrypoints.ssh.address=:2222 + # (Optionnel) Dashboard interne + - --api.dashboard=true + ports: + - "80:80" + - "443:443" + - "2222:2222" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./traefik-letsencrypt:/letsencrypt + networks: + - proxy + environment: + - TZ=Europe/Paris + labels: + - traefik.enable=true + - traefik.http.routers.traefik.rule=Host(`traefik.goutailler-olivier.com`) + - traefik.http.routers.traefik.entrypoints=websecure + - traefik.http.routers.traefik.tls.certresolver=le + - traefik.http.routers.traefik.service=api@internal +networks: + # nextcloud-net: + # driver: bridge + proxy: + external: true + name: proxy diff --git a/trilium/docker-compose.yml b/trilium/docker-compose.yml new file mode 100644 index 0000000..2fa71b7 --- /dev/null +++ b/trilium/docker-compose.yml @@ -0,0 +1,30 @@ +services: + trilium: + image: triliumnext/trilium:latest + container_name: trilium + restart: unless-stopped + + environment: + TRILIUM_DATA_DIR: /home/node/trilium-data + TZ: Europe/Paris + + volumes: + - /home/gato/Applications/Trilium/data:/home/node/trilium-data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + + networks: + - proxy + + labels: + - traefik.enable=true + - traefik.http.routers.trilium.rule=Host(`notes.goutailler-olivier.com`) + - traefik.http.routers.trilium.entrypoints=websecure + - traefik.http.routers.trilium.tls.certresolver=le + - traefik.http.services.trilium.loadbalancer.server.port=8080 + - traefik.docker.network=proxy + +networks: + proxy: + external: true + name: proxy diff --git a/watchtower/.env.example b/watchtower/.env.example new file mode 100644 index 0000000..80b0182 --- /dev/null +++ b/watchtower/.env.example @@ -0,0 +1 @@ +WATCHTOWER_TOKEN=votre_token_secret_ici diff --git a/watchtower/docker-compose.yml b/watchtower/docker-compose.yml new file mode 100644 index 0000000..54fdcd9 --- /dev/null +++ b/watchtower/docker-compose.yml @@ -0,0 +1,30 @@ +name: watchtower + +services: + watchtower: + image: containrrr/watchtower + container_name: watchtower + restart: unless-stopped + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /root/.docker/config.json:/root/.docker/config.json:ro + environment: + WATCHTOWER_HTTP_API_UPDATE: "true" + WATCHTOWER_HTTP_API_TOKEN: ${WATCHTOWER_TOKEN} + WATCHTOWER_LABEL_ENABLE: "true" + WATCHTOWER_CLEANUP: "true" + TZ: Europe/Paris + networks: + - proxy + labels: + - traefik.enable=true + - traefik.http.routers.watchtower.rule=Host(`watchtower.goutailler-olivier.com`) + - traefik.http.routers.watchtower.entrypoints=websecure + - traefik.http.routers.watchtower.tls.certresolver=le + - traefik.http.services.watchtower.loadbalancer.server.port=8080 + - traefik.docker.network=proxy + +networks: + proxy: + external: true + name: proxy