This commit is contained in:
Bastien COIGNOUX
2026-04-26 22:50:35 +02:00
parent 1813603bb3
commit 89c37cf28d
8 changed files with 362 additions and 0 deletions

14
.dockerignore Normal file
View File

@ -0,0 +1,14 @@
node_modules
dist
.git
.github
*.md
.env
.env.*
!.env.example
!.env.deploy.example
coverage
.vscode
.cursor
terminals
**/*.log

1
.gitignore vendored
View File

@ -14,6 +14,7 @@ dist-ssr
.env .env
.env.* .env.*
!.env.example !.env.example
.env.deploy
# Editor directories and files # Editor directories and files
.vscode/* .vscode/*

40
Dockerfile Normal file
View File

@ -0,0 +1,40 @@
# Build front Vite (variables VITE_* et JIRA_DOMAIN figées au build)
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
# Origine Jira pour les liens « ouvrir le ticket » (__JIRA_ORIGIN__ dans vite.config.js)
ARG JIRA_DOMAIN=
ENV JIRA_DOMAIN=$JIRA_DOMAIN
# Obligatoire en prod : URL de ton proxy HTTPS vers Jira (même origine ou sous-chemin)
ARG VITE_JIRA_BASE_URL=
ENV VITE_JIRA_BASE_URL=$VITE_JIRA_BASE_URL
ARG VITE_JIRA_BROWSE_BASE_URL=
ENV VITE_JIRA_BROWSE_BASE_URL=$VITE_JIRA_BROWSE_BASE_URL
ARG VITE_JIRA_EPIC_KEY=
ENV VITE_JIRA_EPIC_KEY=$VITE_JIRA_EPIC_KEY
ARG VITE_JIRA_PAGE_SIZE=
ENV VITE_JIRA_PAGE_SIZE=$VITE_JIRA_PAGE_SIZE
ARG VITE_JIRA_BOARD_ID=
ENV VITE_JIRA_BOARD_ID=$VITE_JIRA_BOARD_ID
ARG VITE_JIRA_SPRINT_FIELD=
ENV VITE_JIRA_SPRINT_FIELD=$VITE_JIRA_SPRINT_FIELD
ARG VITE_JIRA_STORY_POINTS_FIELD=
ENV VITE_JIRA_STORY_POINTS_FIELD=$VITE_JIRA_STORY_POINTS_FIELD
ARG VITE_MY_JIRA_ACCOUNT_ID=
ENV VITE_MY_JIRA_ACCOUNT_ID=$VITE_MY_JIRA_ACCOUNT_ID
ARG VITE_MY_JIRA_EMAIL=
ENV VITE_MY_JIRA_EMAIL=$VITE_MY_JIRA_EMAIL
RUN npm run build
FROM nginx:alpine
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80

31
deploy/hooks.json.example Normal file
View File

@ -0,0 +1,31 @@
[
{
"id": "jira-descours-deploy",
"execute-command": "/config/deploy.sh",
"command-working-directory": "/",
"trigger-rule": {
"and": [
{
"match": {
"type": "value",
"value": "refs/heads/main",
"parameter": {
"source": "payload",
"name": "ref"
}
}
},
{
"match": {
"type": "value",
"value": "CHANGEME_SECRET_TOKEN",
"parameter": {
"source": "url",
"name": "token"
}
}
}
]
}
}
]

View File

@ -0,0 +1,8 @@
#!/bin/sh
# Copier vers le NAS (ex. /volume1/docker/jira-descours/deploy.sh), chmod +x,
# adapter APP_DIR et redémarrer le conteneur « webhook » qui linvoque.
set -e
APP_DIR="/volume1/docker/jira-descours/src"
cd "$APP_DIR"
git pull --ff-only
docker compose --env-file .env.deploy -f docker-compose.yml up -d --build

23
docker-compose.yml Normal file
View File

@ -0,0 +1,23 @@
# Déploiement NAS : variables dans un fichier `.env.deploy` à côté de ce fichier (non versionné).
# Voir docs/DEPLOY_SYNOLOGY_GITEA.md
services:
web:
build:
context: .
dockerfile: Dockerfile
args:
JIRA_DOMAIN: ${JIRA_DOMAIN:-}
VITE_JIRA_BASE_URL: ${VITE_JIRA_BASE_URL:-}
VITE_JIRA_BROWSE_BASE_URL: ${VITE_JIRA_BROWSE_BASE_URL:-}
VITE_JIRA_EPIC_KEY: ${VITE_JIRA_EPIC_KEY:-}
VITE_JIRA_PAGE_SIZE: ${VITE_JIRA_PAGE_SIZE:-}
VITE_JIRA_BOARD_ID: ${VITE_JIRA_BOARD_ID:-}
VITE_JIRA_SPRINT_FIELD: ${VITE_JIRA_SPRINT_FIELD:-}
VITE_JIRA_STORY_POINTS_FIELD: ${VITE_JIRA_STORY_POINTS_FIELD:-}
VITE_MY_JIRA_ACCOUNT_ID: ${VITE_MY_JIRA_ACCOUNT_ID:-}
VITE_MY_JIRA_EMAIL: ${VITE_MY_JIRA_EMAIL:-}
image: jira-descours:local
ports:
- "${HOST_PORT:-8080}:80"
restart: unless-stopped

18
docker/nginx.conf Normal file
View File

@ -0,0 +1,18 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
gzip on;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 7d;
add_header Cache-Control "public, immutable";
}
}

View File

@ -0,0 +1,227 @@
# Déploiement automatique : Gitea + Docker sur Synology NAS
Ce dépôt contient un **`Dockerfile`** et un **`docker-compose.yml`** pour servir le build Vite avec **Nginx**.
Lobjectif : à chaque **push sur `main`**, le NAS **tire** le code et **reconstruit** le conteneur.
---
## Vue densemble
| Étape | Rôle |
|--------|------|
| 13 | Cloner le dépôt sur le NAS, créer `.env.deploy` |
| 4 | Premier déploiement manuel (`docker compose up`) |
| 57 | Conteneur **webhook** qui exécute un script au push Gitea |
| 8 | Configurer le **webhook** dans Gitea (URL + secret en query) |
| 910 | **Proxy inverse** Synology + HTTPS pour laccès extérieur |
| 1112 | Vérifications et dépannage |
Chemins dexemple : `/volume1/docker/jira-descours/` — à adapter à ton volume DSM.
---
## 1. Préparer un dossier sur le NAS
En **SSH** (utilisateur admin ou compte avec droits `docker`) :
```sh
mkdir -p /volume1/docker/jira-descours
cd /volume1/docker/jira-descours
```
---
## 2. Cloner le dépôt Gitea (une fois)
Utilise lURL **SSH** ou **HTTPS** de ton Gitea.
**Dépôt privé (recommandé)** : créer une **clé SSH** sur le NAS, enregistrer la clé **publique** dans Gitea
(*Paramètres du dépôt → Clés de déploiement* ou compte utilisateur → Clés SSH).
```sh
cd /volume1/docker/jira-descours
git clone git@GITEA_HOST:UTILISATEUR/jira-descours.git src
cd src
```
Le dossier `src` contiendra le `docker-compose.yml` à la racine du dépôt après clone.
---
## 3. Fichier denvironnement de build `.env.deploy`
Sur le NAS, dans **`src/`** (racine du clone) :
```sh
cp .env.deploy.example .env.deploy
nano .env.deploy
```
Renseigne au minimum :
- **`JIRA_DOMAIN`** — sous-domaine Atlassian (comme en dev).
- **`VITE_JIRA_BASE_URL`** — URL **HTTPS** de ton **proxy Jira** (obligatoire en prod : le navigateur nutilise pas le proxy Vite du `npm run dev`).
Optionnel : `VITE_JIRA_*` comme dans `.env.example`.
**`HOST_PORT`** : port sur lequel le NAS écoute (ex. `8080`). Tu le brancheras ensuite sur le **proxy inverse** DSM.
Ne **commit pas** `.env.deploy` (déjà ignoré par `.gitignore`).
---
## 4. Premier build manuel
Toujours dans `src/` :
```sh
docker compose --env-file .env.deploy up -d --build
```
Teste en local (LAN) : `http://IP_DU_NAS:8080` (ou le port choisi).
---
## 5. Script de déploiement appelé par le webhook
Toujours sur le NAS, crée un script **hors** du dépôt (pour ne pas lécraser au `git pull`), par ex. :
```sh
sudo tee /volume1/docker/jira-descours/deploy.sh <<'EOF'
#!/bin/sh
set -e
APP_DIR="/volume1/docker/jira-descours/src"
cd "$APP_DIR"
git pull --ff-only
docker compose --env-file .env.deploy -f docker-compose.yml up -d --build
EOF
sudo chmod +x /volume1/docker/jira-descours/deploy.sh
```
Adapte **`APP_DIR`** si ton chemin diffère.
---
## 6. Fichier `hooks.json` pour [adnanh/webhook](https://github.com/adnanh/webhook)
Copie `deploy/hooks.json.example` vers le NAS, par ex. :
`/volume1/docker/jira-descours/hooks.json`
1. Remplace **`CHANGEME_SECRET_TOKEN`** par un **secret long** (génère-en un et garde-le pour Gitea).
2. Vérifie que **`refs/heads/main`** correspond à ta branche de prod (sinon change la valeur).
---
## 7. Lancer le récepteur webhook (Docker)
Le conteneur webhook doit pouvoir exécuter **`docker`** : montage du socket Docker.
**Choisir une IP joignable depuis le conteneur Gitea** :
- Gitea **hors Docker** sur le NAS → souvent `http://127.0.0.1:PORT` depuis le NAS… mais le webhook doit écouter sur une interface que Gitea peut appeler.
- Gitea **dans Docker** sur le même hôte → souvent `http://172.17.0.1:9888` (bridge Docker vers lhôte) ou **lIP LAN du NAS** (`http://192.168.x.x:9888`).
Exemple (adapter chemins et tag dimage) :
```sh
docker run -d --name gitea-deploy-hook --restart unless-stopped \
-p 127.0.0.1:9888:9000 \
-v /volume1/docker/jira-descours/hooks.json:/etc/webhook/hooks.json:ro \
-v /volume1/docker/jira-descours/deploy.sh:/config/deploy.sh:ro \
-v /var/run/docker.sock:/var/run/docker.sock \
ghcr.io/adnanh/webhook:2.8.2 \
-verbose -hooks=/etc/webhook/hooks.json
```
- **`-p 127.0.0.1:9888:9000`** : le hook nest pas exposé sur toute la carte réseau (plus sûr). Gitea sur le **même hôte** doit joindre `127.0.0.1:9888` **depuis lhôte** ; si Gitea est **dans un autre conteneur**, utilise plutôt lIP LAN du NAS et `-p 9888:9000` **avec pare-feu** ou réseau Docker partagé.
Vérifie la doc de ton image `webhook` pour le chemin des hooks (`-hooks=...`).
Test manuel (depuis le NAS) :
```sh
curl "http://127.0.0.1:9888/hooks/jira-descours-deploy?token=CHANGEME_SECRET_TOKEN" \
-X POST -H "Content-Type: application/json" \
-d '{"ref":"refs/heads/main"}'
```
Le hook doit sexécuter (voir logs du conteneur `gitea-deploy-hook`).
---
## 8. Webhook dans Gitea
1. Ouvre le dépôt → **Paramètres****Webhooks****Ajouter un webhook****Gitea**.
2. **URL cible** (exemple si hook sur le NAS, port 9888, secret en query) :
`http://IP_LAN_DU_NAS:9888/hooks/jira-descours-deploy?token=TON_SECRET_LONG`
Si Gitea et le hook sont sur le **même** OS Docker, teste dabord avec lIP LAN ; ajuste selon ce qui fonctionne chez toi.
3. **Déclencher sur** : « Push » (événements de push).
4. Branche : si lUI le permet, limite à **`main`** ; sinon le filtre est déjà dans `hooks.json` (`ref`).
Enregistre, puis **« Test de livraison »** ou un **push** sur `main` : le site doit se reconstruire après quelques minutes.
---
## 9. Accès depuis lextérieur (HTTPS)
1. **Nom de domaine** ou **DDNS Synology** pointant vers lIP publique de ta box.
2. **Box internet** : redirection **TCP 443** (et éventuellement **80**) vers l**IP du NAS** (même ports ou ceux de ton reverse proxy).
3. Sur DSM : **Panneau de configuration****Portail de connexion****Proxy inverse** :
- **Nom dhôte** : ex. `jira-descours.mondomaine.fr`
- **Destination** : `http://127.0.0.1:8080` (ou le `HOST_PORT` défini dans `.env.deploy`)
- **HTTPS** activé, certificat Lets Encrypt pour ce nom dhôte.
4. Accès : `https://jira-descours.mondomaine.fr`
**Alternative sans ouvrir les ports** : [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) sur le NAS (très courant en homelab).
---
## 10. Sécurité (rappel court)
- Secret **long** dans lURL du webhook ; ne le commite pas.
- Préférer le hook en **127.0.0.1** si Gitea appelle depuis la même machine ; sinon **pare-feu** DSM limitant le port du hook aux IP de confiance.
- Mettre à jour DSM, Gitea et les images Docker régulièrement.
---
## 11. Check-list après un push
- Gitea → **Paramètres du dépôt****Webhooks** : dernière livraison en vert.
- Sur le NAS : `docker logs gitea-deploy-hook` puis `docker ps` : conteneur `web` à jour.
- Site public : hard refresh (Ctrl+F5) pour éviter le cache du navigateur.
---
## 12. Dépannage
| Problème | Piste |
|----------|--------|
| `git pull` échoue | Clé SSH / droits dépôt ; URL du `origin`. |
| Build Docker OOM | NAS peu de RAM : build sur une machine CI puis `docker pull` (évolution). |
| Page blanche / erreur Jira | `VITE_JIRA_BASE_URL` absent ou incorrect au **build** ; refaire `up --build` après correction de `.env.deploy`. |
| Webhook jamais reçu | URL depuis le conteneur Gitea (test `curl` depuis **dedans** le conteneur Gitea vers lURL du hook). |
| 403 Lets Encrypt | Ports 80/443 bien redirigés ; nom DNS correct. |
---
## Fichiers utiles dans ce dépôt
| Fichier | Rôle |
|---------|------|
| `Dockerfile` | Build Node + image Nginx |
| `docker-compose.yml` | Service `web` + args de build |
| `docker/nginx.conf` | SPA `try_files``index.html` |
| `.env.deploy.example` | Modèle pour le NAS |
| `deploy/hooks.json.example` | Modèle webhook |
| `deploy/nas-deploy.sh.example` | Ancienne variante (script dans le dépôt) ; le guide privilégie `deploy.sh` **sur le NAS** |
---
## Variante : Gitea Actions + runner sur le NAS
Si tu préfères tout voir dans lUI Gitea : active **Actions**, installe **act_runner** sur le NAS, enregistre-le sur ton instance, puis ajoute un workflow `.gitea/workflows/deploy.yml` qui exécute les mêmes commandes que `deploy.sh`. Cest plus lourd à configurer (dont laccès sécurisé à `docker.sock`) mais très propre à long terme.