feat: ajout documentation Nginx Proxy Manager et scripts de déploiement

- Documentation complète pour Nginx Proxy Manager (docs/10-configuration-nginx-proxy-manager.md)
- Script get-npm-token.sh pour générer automatiquement les tokens API
- Exemple complet de .woodpecker.yml avec logique inline de déploiement
- Documentation déploiement applications avec URLs dynamiques (docs/09-deploiement-applications.md)
- Script deploy.sh comme alternative optionnelle
- Mise à jour README avec références aux nouvelles documentations
This commit is contained in:
2025-12-24 18:14:48 +01:00
parent 4aa46fbbbb
commit 9132aeb5d1
8 changed files with 1844 additions and 0 deletions

View File

@ -0,0 +1,760 @@
# Déploiement d'applications avec URLs dynamiques
Ce guide explique comment déployer vos applications avec Woodpecker CI en générant automatiquement des URLs dynamiques basées sur le nom de l'application et la branche Git.
## Vue d'ensemble
### Architecture
```
┌─────────────────┐
│ Woodpecker CI │
│ (Pipeline) │
└────────┬────────┘
│ 1. Build & Deploy
┌─────────────────┐
│ Docker Image │
│ mon-app:latest │
└────────┬────────┘
│ 2. Run Container
┌─────────────────┐ ┌──────────────┐
│ Container │──────▶│ Consul │
│ mon-app │ │ (Service │
│ Labels Consul │ │ Discovery) │
└────────┬────────┘ └──────────────┘
│ 3. Auto-register
┌─────────────────┐ ┌──────────────────┐
│ Registrator │──────▶│ Nginx Proxy │
│ (Auto-detect) │ │ Manager │
└─────────────────┘ │ (Reverse Proxy) │
└──────────────────┘
│ 4. Configure Proxy
┌──────────────────┐
│ https:// │
│ mon-app.syoul.fr│
└──────────────────┘
```
### Flux de déploiement
1. **Build** : Woodpecker CI construit l'image Docker de l'application
2. **Deploy** : Le pipeline `.woodpecker.yml` lance le conteneur avec les labels Consul
3. **Discovery** : Registrator détecte automatiquement le conteneur et l'enregistre dans Consul
4. **Proxy** : Nginx Proxy Manager configure automatiquement le reverse proxy
5. **URL** : L'application est accessible via une URL dynamique (ex: `mon-app.syoul.fr`)
## Prérequis
### 1. Infrastructure en place
- ✅ Woodpecker CI configuré et fonctionnel
- ✅ Consul déployé avec ACL activées
- ✅ Registrator déployé et fonctionnel
- ✅ Nginx Proxy Manager installé (optionnel mais recommandé)
### 2. Variables d'environnement
Pour utiliser le déploiement avec Nginx Proxy Manager, configurez ces variables dans Woodpecker :
| Variable | Description | Exemple |
|----------|-------------|---------|
| `DOCKER_NETWORK` | Réseau Docker partagé | `gitgit_syoul_fr_gitea_net` |
| `NPM_API_URL` | URL de l'API Nginx Proxy Manager | `http://npm-manager:81` |
| `NPM_API_TOKEN` | Token d'API Nginx Proxy Manager | `votre-token-api` |
| `DOMAIN_BASE` | Domaine de base pour les URLs | `syoul.fr` |
| `CONSUL_TOKEN` | Token Consul (optionnel) | `votre-token-consul` |
### 3. Obtenir le token Nginx Proxy Manager
1. Connectez-vous à Nginx Proxy Manager
2. Allez dans **Account** > **API Tokens**
3. Créez un nouveau token avec les permissions nécessaires
4. Copiez le token et ajoutez-le dans les secrets Woodpecker
## Configuration du pipeline Woodpecker
### Approche recommandée : Tout dans `.woodpecker.yml`
Toute la logique de déploiement est intégrée directement dans le fichier `.woodpecker.yml` de votre projet. Cela permet d'avoir tout au même endroit et de voir exactement ce qui se passe lors du déploiement.
### Avantages de cette approche
-**Tout au même endroit** : La configuration est visible directement dans le pipeline
-**Pas de dépendances externes** : Pas besoin de copier des scripts
-**Facile à comprendre** : Tout est explicite dans le fichier YAML
-**Personnalisable** : Facile d'adapter pour chaque projet
## Configuration Woodpecker CI
### Pipeline complet avec déploiement inline
Créez un fichier `.woodpecker.yml` à la racine de votre projet :
```yaml
pipeline:
# Étape de build
build:
image: docker:24-dind
privileged: true
environment:
- DOCKER_HOST=tcp://docker:2375
commands:
- docker build -t ${CI_REPO_NAME}:${CI_COMMIT_SHA} .
- docker tag ${CI_REPO_NAME}:${CI_COMMIT_SHA} ${CI_REPO_NAME}:latest
# Déploiement sur la branche main
deploy:
image: docker:24-dind
privileged: true
environment:
- APP_NAME=${CI_REPO_NAME}
- APP_PORT=3000 # Adaptez selon votre application
- DOCKER_NETWORK=${DOCKER_NETWORK:-gitgit_syoul_fr_gitea_net}
- DOMAIN_BASE=${DOMAIN_BASE:-syoul.fr}
- NPM_API_URL=${NPM_API_URL} # Secret Woodpecker
- NPM_API_TOKEN=${NPM_API_TOKEN} # Secret Woodpecker
commands:
# Installer les dépendances
- apk add --no-cache curl jq
# Nettoyer le nom de l'application
- APP_NAME_CLEAN=$(echo "${APP_NAME}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
# Générer l'URL dynamique
- |
if [ "$CI_COMMIT_BRANCH" = "main" ] || [ "$CI_COMMIT_BRANCH" = "master" ]; then
SUBDOMAIN="${APP_NAME_CLEAN}"
else
BRANCH_CLEAN=$(echo "${CI_COMMIT_BRANCH}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
SUBDOMAIN="${APP_NAME_CLEAN}-${BRANCH_CLEAN}"
fi
- APP_URL="${SUBDOMAIN}.${DOMAIN_BASE}"
- echo "🚀 Déploiement sur https://${APP_URL}"
# Vérifier le réseau Docker
- docker network inspect "${DOCKER_NETWORK}" || docker network create "${DOCKER_NETWORK}" || true
# Arrêter l'ancien conteneur
- docker stop "${APP_NAME_CLEAN}" 2>/dev/null || true
- docker rm "${APP_NAME_CLEAN}" 2>/dev/null || true
# Lancer le nouveau conteneur avec labels Consul
- |
CONTAINER_ID=$(docker run -d \
--name "${APP_NAME_CLEAN}" \
--network "${DOCKER_NETWORK}" \
--restart unless-stopped \
--label "SERVICE_NAME=${APP_NAME_CLEAN}" \
--label "SERVICE_TAGS=app,web,${CI_COMMIT_BRANCH}" \
--label "SERVICE_${APP_PORT}_NAME=${APP_NAME_CLEAN}" \
--label "SERVICE_${APP_PORT}_CHECK_HTTP=/" \
--label "SERVICE_${APP_PORT}_CHECK_INTERVAL=15s" \
-p "${APP_PORT}" \
"${APP_NAME_CLEAN}:latest")
- sleep 3
- APP_CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "${APP_NAME_CLEAN}")
# Configurer Nginx Proxy Manager
- |
if [ -n "${NPM_API_URL}" ] && [ -n "${NPM_API_TOKEN}" ]; then
EXISTING_PROXY=$(curl -s -H "Authorization: Bearer ${NPM_API_TOKEN}" \
"${NPM_API_URL}/api/nginx/proxy-hosts" 2>/dev/null | \
jq -r ".[] | select(.domain_names[] == \"${APP_URL}\") | .id" 2>/dev/null | head -1)
PROXY_DATA=$(cat <<EOF
{
"domain_names": ["${APP_URL}"],
"forward_scheme": "http",
"forward_host": "${APP_CONTAINER_IP}",
"forward_port": ${APP_PORT},
"ssl_forced": true,
"hsts_enabled": true,
"hsts_subdomains": true,
"block_exploits": true,
"caching_enabled": true,
"allow_websocket_upgrade": true
}
EOF
)
if [ -n "${EXISTING_PROXY}" ]; then
curl -s -X PUT "${NPM_API_URL}/api/nginx/proxy-hosts/${EXISTING_PROXY}" \
-H "Authorization: Bearer ${NPM_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "${PROXY_DATA}" > /dev/null
echo "✅ Proxy mis à jour"
else
curl -s -X POST "${NPM_API_URL}/api/nginx/proxy-hosts" \
-H "Authorization: Bearer ${NPM_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "${PROXY_DATA}" > /dev/null
echo "✅ Proxy créé"
fi
fi
- echo "✅ Application déployée: https://${APP_URL}"
when:
branch: main
status: success
```
### Pipeline avancé avec tests et déploiement staging
Pour un exemple complet avec tests et déploiement sur plusieurs branches, consultez le fichier `scripts/.woodpecker.yml.example` dans le dépôt infrastructure.
## Exemples par type d'application
### Application Node.js
```yaml
pipeline:
build:
image: node:20-alpine
commands:
- npm ci
- npm run build
- docker build -t ${CI_REPO_NAME}:${CI_COMMIT_SHA} .
- docker tag ${CI_REPO_NAME}:${CI_COMMIT_SHA} ${CI_REPO_NAME}:latest
deploy:
image: docker:24-dind
privileged: true
environment:
- APP_NAME=${CI_REPO_NAME}
- APP_PORT=3000
- DOCKER_NETWORK=${DOCKER_NETWORK:-gitgit_syoul_fr_gitea_net}
- DOMAIN_BASE=${DOMAIN_BASE:-syoul.fr}
- NPM_API_URL=${NPM_API_URL}
- NPM_API_TOKEN=${NPM_API_TOKEN}
commands:
- apk add --no-cache curl jq
- APP_NAME_CLEAN=$(echo "${APP_NAME}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
- |
if [ "$CI_COMMIT_BRANCH" = "main" ]; then
SUBDOMAIN="${APP_NAME_CLEAN}"
else
BRANCH_CLEAN=$(echo "${CI_COMMIT_BRANCH}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
SUBDOMAIN="${APP_NAME_CLEAN}-${BRANCH_CLEAN}"
fi
- APP_URL="${SUBDOMAIN}.${DOMAIN_BASE}"
- docker network inspect "${DOCKER_NETWORK}" || docker network create "${DOCKER_NETWORK}" || true
- docker stop "${APP_NAME_CLEAN}" 2>/dev/null || true
- docker rm "${APP_NAME_CLEAN}" 2>/dev/null || true
- |
docker run -d \
--name "${APP_NAME_CLEAN}" \
--network "${DOCKER_NETWORK}" \
--restart unless-stopped \
--label "SERVICE_NAME=${APP_NAME_CLEAN}" \
--label "SERVICE_TAGS=app,web" \
--label "SERVICE_3000_NAME=${APP_NAME_CLEAN}" \
--label "SERVICE_3000_CHECK_HTTP=/" \
--label "SERVICE_3000_CHECK_INTERVAL=15s" \
-p 3000 \
"${APP_NAME_CLEAN}:latest"
- sleep 3
- APP_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "${APP_NAME_CLEAN}")
# Configuration NPM (voir exemple complet ci-dessus)
- echo "✅ Déployé sur https://${APP_URL}"
```
**Dockerfile exemple** :
```dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
```
### Application Python (Flask/FastAPI)
```yaml
pipeline:
build:
image: python:3.11-alpine
commands:
- pip install -r requirements.txt
- docker build -t ${CI_REPO_NAME}:${CI_COMMIT_SHA} .
- docker tag ${CI_REPO_NAME}:${CI_COMMIT_SHA} ${CI_REPO_NAME}:latest
deploy:
image: docker:24-dind
privileged: true
environment:
- APP_NAME=${CI_REPO_NAME}
- APP_PORT=8000
- DOCKER_NETWORK=${DOCKER_NETWORK:-gitgit_syoul_fr_gitea_net}
- DOMAIN_BASE=${DOMAIN_BASE:-syoul.fr}
- NPM_API_URL=${NPM_API_URL}
- NPM_API_TOKEN=${NPM_API_TOKEN}
commands:
- apk add --no-cache curl jq
- APP_NAME_CLEAN=$(echo "${APP_NAME}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
- |
if [ "$CI_COMMIT_BRANCH" = "main" ]; then
SUBDOMAIN="${APP_NAME_CLEAN}"
else
BRANCH_CLEAN=$(echo "${CI_COMMIT_BRANCH}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
SUBDOMAIN="${APP_NAME_CLEAN}-${BRANCH_CLEAN}"
fi
- APP_URL="${SUBDOMAIN}.${DOMAIN_BASE}"
- docker network inspect "${DOCKER_NETWORK}" || docker network create "${DOCKER_NETWORK}" || true
- docker stop "${APP_NAME_CLEAN}" 2>/dev/null || true
- docker rm "${APP_NAME_CLEAN}" 2>/dev/null || true
- |
docker run -d \
--name "${APP_NAME_CLEAN}" \
--network "${DOCKER_NETWORK}" \
--restart unless-stopped \
--label "SERVICE_NAME=${APP_NAME_CLEAN}" \
--label "SERVICE_TAGS=app,web" \
--label "SERVICE_8000_NAME=${APP_NAME_CLEAN}" \
--label "SERVICE_8000_CHECK_HTTP=/" \
--label "SERVICE_8000_CHECK_INTERVAL=15s" \
-p 8000 \
"${APP_NAME_CLEAN}:latest"
- sleep 3
- APP_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "${APP_NAME_CLEAN}")
# Configuration NPM (voir exemple complet ci-dessus)
- echo "✅ Déployé sur https://${APP_URL}"
```
**Dockerfile exemple** :
```dockerfile
FROM python:3.11-alpine
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```
### Application Go
```yaml
pipeline:
build:
image: golang:1.21-alpine
commands:
- CGO_ENABLED=0 GOOS=linux go build -o app .
- docker build -t ${CI_REPO_NAME}:${CI_COMMIT_SHA} .
- docker tag ${CI_REPO_NAME}:${CI_COMMIT_SHA} ${CI_REPO_NAME}:latest
deploy:
image: docker:24-dind
privileged: true
environment:
- APP_NAME=${CI_REPO_NAME}
- APP_PORT=8080
- DOCKER_NETWORK=${DOCKER_NETWORK:-gitgit_syoul_fr_gitea_net}
- DOMAIN_BASE=${DOMAIN_BASE:-syoul.fr}
- NPM_API_URL=${NPM_API_URL}
- NPM_API_TOKEN=${NPM_API_TOKEN}
commands:
- apk add --no-cache curl jq
- APP_NAME_CLEAN=$(echo "${APP_NAME}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
- |
if [ "$CI_COMMIT_BRANCH" = "main" ]; then
SUBDOMAIN="${APP_NAME_CLEAN}"
else
BRANCH_CLEAN=$(echo "${CI_COMMIT_BRANCH}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
SUBDOMAIN="${APP_NAME_CLEAN}-${BRANCH_CLEAN}"
fi
- APP_URL="${SUBDOMAIN}.${DOMAIN_BASE}"
- docker network inspect "${DOCKER_NETWORK}" || docker network create "${DOCKER_NETWORK}" || true
- docker stop "${APP_NAME_CLEAN}" 2>/dev/null || true
- docker rm "${APP_NAME_CLEAN}" 2>/dev/null || true
- |
docker run -d \
--name "${APP_NAME_CLEAN}" \
--network "${DOCKER_NETWORK}" \
--restart unless-stopped \
--label "SERVICE_NAME=${APP_NAME_CLEAN}" \
--label "SERVICE_TAGS=app,web" \
--label "SERVICE_8080_NAME=${APP_NAME_CLEAN}" \
--label "SERVICE_8080_CHECK_HTTP=/" \
--label "SERVICE_8080_CHECK_INTERVAL=15s" \
-p 8080 \
"${APP_NAME_CLEAN}:latest"
- sleep 3
- APP_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "${APP_NAME_CLEAN}")
# Configuration NPM (voir exemple complet ci-dessus)
- echo "✅ Déployé sur https://${APP_URL}"
```
**Dockerfile exemple** :
```dockerfile
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY app .
EXPOSE 8080
CMD ["./app"]
```
## Génération d'URLs dynamiques
### Règles de génération
Le script génère les URLs selon ces règles :
1. **Branche main/master** : `{app-name}.{domain-base}`
- Exemple: `mon-app.syoul.fr`
2. **Autres branches** : `{app-name}-{branch-name}.{domain-base}`
- Exemple: `mon-app-feature-ui.syoul.fr`
3. **Nettoyage automatique** :
- Conversion en minuscules
- Remplacement des caractères spéciaux par des tirets
- Suppression des caractères invalides
### Exemples
| Application | Branche | URL générée |
|-------------|---------|-------------|
| `mon-app` | `main` | `mon-app.syoul.fr` |
| `mon-app` | `develop` | `mon-app-develop.syoul.fr` |
| `mon-app` | `feature/new-ui` | `mon-app-feature-new-ui.syoul.fr` |
| `MyApp` | `main` | `myapp.syoul.fr` |
| `app_name` | `main` | `app-name.syoul.fr` |
## Découverte de services avec Consul
Une fois déployée, votre application est automatiquement enregistrée dans Consul grâce aux labels Docker.
### Lister les applications déployées
```bash
export CONSUL_TOKEN="votre-token"
curl -H "X-Consul-Token: $CONSUL_TOKEN" \
http://localhost:8500/v1/catalog/services | jq 'keys[] | select(. | contains("app"))'
```
### Obtenir les détails d'une application
```bash
curl -H "X-Consul-Token: $CONSUL_TOKEN" \
http://localhost:8500/v1/catalog/service/mon-app | jq
```
### Vérifier la santé d'une application
```bash
curl -H "X-Consul-Token: $CONSUL_TOKEN" \
http://localhost:8500/v1/health/service/mon-app | jq
```
### Résolution DNS via Consul
Si Consul DNS est configuré, vous pouvez résoudre les services :
```bash
dig @localhost -p 8600 mon-app.service.consul
```
## Configuration Nginx Proxy Manager
### Configuration automatique
Le script configure automatiquement Nginx Proxy Manager si les variables `NPM_API_URL` et `NPM_API_TOKEN` sont définies.
### Configuration manuelle
Si vous préférez configurer manuellement :
1. Connectez-vous à Nginx Proxy Manager
2. Allez dans **Hosts** > **Proxy Hosts**
3. Cliquez sur **Add Proxy Host**
4. Configurez :
- **Domain Names** : `mon-app.syoul.fr`
- **Forward Hostname/IP** : IP du conteneur (récupérée via `docker inspect`)
- **Forward Port** : Port de l'application
- **SSL** : Activer SSL et Let's Encrypt
- **Block Common Exploits** : Activé
- **Websockets Support** : Activé si nécessaire
### Récupérer l'IP du conteneur
```bash
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mon-app
```
## Gestion des secrets
### Secrets Woodpecker
Ajoutez les secrets dans Woodpecker :
1. Allez dans **Settings** > **Secrets**
2. Ajoutez :
- `NPM_API_URL` : URL de l'API Nginx Proxy Manager
- `NPM_API_TOKEN` : Token d'API
- `DOMAIN_BASE` : Domaine de base
- `CONSUL_TOKEN` : Token Consul (optionnel)
### Variables d'environnement par projet
Vous pouvez aussi définir des variables spécifiques à chaque projet dans `.woodpecker.yml` :
```yaml
pipeline:
deploy:
environment:
- APP_PORT=3000 # Port spécifique au projet
- DOMAIN_BASE=syoul.fr
```
## Bonnes pratiques
### 1. Health checks
Assurez-vous que votre application expose un endpoint de health check :
```yaml
# Dans votre Dockerfile ou docker-compose.yml
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:${APP_PORT}/health || exit 1
```
### 2. Variables d'environnement
Utilisez des variables d'environnement pour la configuration :
```yaml
# Dans votre Dockerfile
ENV APP_PORT=3000
ENV NODE_ENV=production
```
### 3. Logs
Configurez la gestion des logs :
```yaml
# Dans docker-compose.yml ou via labels
labels:
- "logging=json-file"
- "logging.max-size=10m"
- "logging.max-file=3"
```
### 4. Ressources
Limitez les ressources des conteneurs :
```bash
docker run -d \
--memory="512m" \
--cpus="0.5" \
--name mon-app \
mon-app:latest
```
### 5. Rollback
Pour faire un rollback, utilisez une image précédente :
```bash
docker tag mon-app:previous-sha mon-app:latest
# Relancer le pipeline Woodpecker ou exécuter manuellement les commandes de déploiement
```
## Dépannage
### Le conteneur ne démarre pas
```bash
# Vérifier les logs
docker logs mon-app
# Vérifier l'état du conteneur
docker ps -a | grep mon-app
```
### L'URL n'est pas accessible
1. Vérifier que le conteneur est en cours d'exécution :
```bash
docker ps | grep mon-app
```
2. Vérifier que le proxy est configuré dans Nginx Proxy Manager
3. Vérifier les DNS :
```bash
dig mon-app.syoul.fr
```
### Le service n'apparaît pas dans Consul
1. Vérifier que Registrator est en cours d'exécution :
```bash
docker ps | grep registrator
```
2. Vérifier les logs de Registrator :
```bash
docker logs registrator | grep mon-app
```
3. Vérifier les labels du conteneur :
```bash
docker inspect mon-app | grep -A 10 Labels
```
### Erreur d'API Nginx Proxy Manager
1. Vérifier que le token est valide
2. Vérifier que l'URL de l'API est correcte
3. Vérifier les permissions du token
## Exemples complets
### Projet complet Node.js
**Structure** :
```
mon-app/
├── .woodpecker.yml
├── Dockerfile
└── package.json
```
**.woodpecker.yml** :
```yaml
pipeline:
test:
image: node:20-alpine
commands:
- npm ci
- npm test
build:
image: docker:24-dind
privileged: true
environment:
- DOCKER_HOST=tcp://docker:2375
commands:
- docker build -t ${CI_REPO_NAME}:${CI_COMMIT_SHA} .
- docker tag ${CI_REPO_NAME}:${CI_COMMIT_SHA} ${CI_REPO_NAME}:latest
deploy:
image: docker:24-dind
privileged: true
environment:
- APP_NAME=${CI_REPO_NAME}
- APP_PORT=3000
- DOCKER_NETWORK=${DOCKER_NETWORK:-gitgit_syoul_fr_gitea_net}
- DOMAIN_BASE=${DOMAIN_BASE:-syoul.fr}
- NPM_API_URL=${NPM_API_URL}
- NPM_API_TOKEN=${NPM_API_TOKEN}
commands:
- apk add --no-cache curl jq
- APP_NAME_CLEAN=$(echo "${APP_NAME}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
- |
if [ "$CI_COMMIT_BRANCH" = "main" ]; then
SUBDOMAIN="${APP_NAME_CLEAN}"
else
BRANCH_CLEAN=$(echo "${CI_COMMIT_BRANCH}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
SUBDOMAIN="${APP_NAME_CLEAN}-${BRANCH_CLEAN}"
fi
- APP_URL="${SUBDOMAIN}.${DOMAIN_BASE}"
- docker network inspect "${DOCKER_NETWORK}" || docker network create "${DOCKER_NETWORK}" || true
- docker stop "${APP_NAME_CLEAN}" 2>/dev/null || true
- docker rm "${APP_NAME_CLEAN}" 2>/dev/null || true
- |
CONTAINER_ID=$(docker run -d \
--name "${APP_NAME_CLEAN}" \
--network "${DOCKER_NETWORK}" \
--restart unless-stopped \
--label "SERVICE_NAME=${APP_NAME_CLEAN}" \
--label "SERVICE_TAGS=app,web" \
--label "SERVICE_3000_NAME=${APP_NAME_CLEAN}" \
--label "SERVICE_3000_CHECK_HTTP=/" \
--label "SERVICE_3000_CHECK_INTERVAL=15s" \
-p 3000 \
"${APP_NAME_CLEAN}:latest")
- sleep 3
- APP_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "${APP_NAME_CLEAN}")
- |
if [ -n "${NPM_API_URL}" ] && [ -n "${NPM_API_TOKEN}" ]; then
EXISTING_PROXY=$(curl -s -H "Authorization: Bearer ${NPM_API_TOKEN}" \
"${NPM_API_URL}/api/nginx/proxy-hosts" 2>/dev/null | \
jq -r ".[] | select(.domain_names[] == \"${APP_URL}\") | .id" 2>/dev/null | head -1)
PROXY_DATA=$(cat <<EOF
{
"domain_names": ["${APP_URL}"],
"forward_scheme": "http",
"forward_host": "${APP_IP}",
"forward_port": 3000,
"ssl_forced": true,
"hsts_enabled": true,
"hsts_subdomains": true,
"block_exploits": true,
"caching_enabled": true,
"allow_websocket_upgrade": true
}
EOF
)
if [ -n "${EXISTING_PROXY}" ]; then
curl -s -X PUT "${NPM_API_URL}/api/nginx/proxy-hosts/${EXISTING_PROXY}" \
-H "Authorization: Bearer ${NPM_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "${PROXY_DATA}" > /dev/null
echo "✅ Proxy mis à jour"
else
curl -s -X POST "${NPM_API_URL}/api/nginx/proxy-hosts" \
-H "Authorization: Bearer ${NPM_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "${PROXY_DATA}" > /dev/null
echo "✅ Proxy créé"
fi
fi
- echo "✅ Application déployée: https://${APP_URL}"
```
**Dockerfile** :
```dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD node healthcheck.js
CMD ["npm", "start"]
```
## Conclusion
Avec ce système, vous pouvez :
- ✅ Déployer automatiquement vos applications avec Woodpecker CI
- ✅ Générer des URLs dynamiques basées sur le nom et la branche
- ✅ Découvrir automatiquement les services via Consul
- ✅ Configurer automatiquement les reverse proxies
- ✅ Surveiller la santé des applications
Pour plus d'informations, consultez :
- [Configuration Woodpecker](04-configuration-woodpecker.md)
- [Configuration Consul](06-configuration-consul.md)
- [Configuration Registrator](07-configuration-registrator.md)

View File

@ -0,0 +1,408 @@
# Configuration Nginx Proxy Manager
Ce guide explique comment configurer Nginx Proxy Manager (NPM) pour l'utiliser avec le déploiement automatique d'applications via Woodpecker CI.
## Vue d'ensemble
Nginx Proxy Manager permet de :
- Gérer facilement les reverse proxies
- Configurer automatiquement les certificats SSL avec Let's Encrypt
- Sécuriser l'accès aux applications avec des Access Lists
- Automatiser la configuration via l'API
## Installation
### Via Docker Compose
```yaml
version: "3.9"
services:
npm:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- '80:80' # HTTP
- '443:443' # HTTPS
- '81:81' # Interface d'administration
volumes:
- npm-data:/data
- npm-letsencrypt:/etc/letsencrypt
networks:
- gitgit_syoul_fr_gitea_net
volumes:
npm-data:
npm-letsencrypt:
networks:
gitgit_syoul_fr_gitea_net:
external: true
```
### Accès initial
1. Accédez à l'interface : `http://[IP-serveur]:81`
2. Identifiants par défaut :
- **Email** : `admin@example.com`
- **Mot de passe** : `changeme`
3. **IMPORTANT** : Changez immédiatement le mot de passe !
## Configuration de l'API
### Obtenir un token API
Nginx Proxy Manager ne propose pas d'interface graphique pour créer des tokens API. Il faut utiliser l'API directement.
#### Méthode 1 : Via curl
```bash
curl -X POST http://192.168.42.144:81/api/tokens \
-H "Content-Type: application/json" \
-d '{
"identity": "votre_email@example.com",
"secret": "votre_mot_de_passe"
}'
```
**Réponse attendue** :
```json
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_name": "API Token",
"expires_at": null
}
```
#### Méthode 2 : Script automatique
Créez un script `get-npm-token.sh` :
```bash
#!/bin/bash
# get-npm-token.sh - Génère un token API pour Nginx Proxy Manager
set -e
NPM_URL=${1:-"http://localhost:81"}
EMAIL=${2:-"admin@example.com"}
echo "Génération du token API pour Nginx Proxy Manager..."
echo "URL: ${NPM_URL}"
echo "Email: ${EMAIL}"
echo ""
# Demander le mot de passe de manière sécurisée
read -sp "Mot de passe: " PASSWORD
echo ""
# Obtenir le token
RESPONSE=$(curl -s -X POST "${NPM_URL}/api/tokens" \
-H "Content-Type: application/json" \
-d "{
\"identity\": \"${EMAIL}\",
\"secret\": \"${PASSWORD}\"
}")
# Extraire le token
TOKEN=$(echo "${RESPONSE}" | jq -r '.token')
if [ "${TOKEN}" = "null" ] || [ -z "${TOKEN}" ]; then
echo "❌ Erreur lors de la génération du token"
echo "Réponse: ${RESPONSE}"
exit 1
fi
echo "✅ Token généré avec succès !"
echo ""
echo "Token: ${TOKEN}"
echo ""
echo "Pour l'utiliser dans Woodpecker CI :"
echo "1. Allez dans Woodpecker > Settings > Secrets"
echo "2. Ajoutez NPM_API_TOKEN avec la valeur ci-dessus"
echo "3. Ajoutez NPM_API_URL avec la valeur: ${NPM_URL}"
```
**Usage** :
```bash
chmod +x get-npm-token.sh
./get-npm-token.sh http://192.168.42.144:81 votre_email@example.com
```
### Tester le token
Vérifiez que le token fonctionne :
```bash
TOKEN="votre-token-ici"
NPM_URL="http://192.168.42.144:81"
# Lister les proxy hosts
curl -H "Authorization: Bearer ${TOKEN}" \
"${NPM_URL}/api/nginx/proxy-hosts"
# Obtenir les détails d'un proxy host
curl -H "Authorization: Bearer ${TOKEN}" \
"${NPM_URL}/api/nginx/proxy-hosts/1"
```
## Configuration dans Woodpecker CI
### Ajouter les secrets
1. Connectez-vous à Woodpecker CI (`https://ci.syoul.fr`)
2. Allez dans **Settings** > **Secrets**
3. Ajoutez les secrets suivants :
| Secret | Valeur | Description |
|--------|--------|-------------|
| `NPM_API_URL` | `http://192.168.42.144:81` | URL de votre Nginx Proxy Manager |
| `NPM_API_TOKEN` | `votre-token-api` | Token obtenu via l'API |
| `DOMAIN_BASE` | `syoul.fr` | Domaine de base pour les URLs (optionnel) |
### URL interne vs externe
Si Nginx Proxy Manager est dans le même réseau Docker que vos applications :
**Utilisez l'URL interne** :
```yaml
NPM_API_URL=http://npm-manager:81 # Nom du conteneur
```
**Ou l'IP interne** :
```yaml
NPM_API_URL=http://172.18.0.X:81 # IP du conteneur
```
Pour trouver le nom/IP du conteneur :
```bash
docker ps | grep nginx-proxy-manager
docker inspect nginx-proxy-manager | grep IPAddress
```
## Utilisation de l'API
### Créer un proxy host
```bash
curl -X POST "${NPM_API_URL}/api/nginx/proxy-hosts" \
-H "Authorization: Bearer ${NPM_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"domain_names": ["mon-app.syoul.fr"],
"forward_scheme": "http",
"forward_host": "172.18.0.10",
"forward_port": 3000,
"ssl_forced": true,
"hsts_enabled": true,
"hsts_subdomains": true,
"block_exploits": true,
"caching_enabled": true,
"allow_websocket_upgrade": true
}'
```
### Mettre à jour un proxy host
```bash
PROXY_ID=1 # ID du proxy host
curl -X PUT "${NPM_API_URL}/api/nginx/proxy-hosts/${PROXY_ID}" \
-H "Authorization: Bearer ${NPM_API_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"forward_host": "172.18.0.11",
"forward_port": 3000
}'
```
### Supprimer un proxy host
```bash
PROXY_ID=1
curl -X DELETE "${NPM_API_URL}/api/nginx/proxy-hosts/${PROXY_ID}" \
-H "Authorization: Bearer ${NPM_API_TOKEN}"
```
### Lister tous les proxy hosts
```bash
curl -H "Authorization: Bearer ${NPM_API_TOKEN}" \
"${NPM_API_URL}/api/nginx/proxy-hosts" | jq
```
## Intégration avec le déploiement automatique
### Dans `.woodpecker.yml`
Le pipeline Woodpecker utilise automatiquement ces secrets pour configurer les reverse proxies :
```yaml
pipeline:
deploy:
environment:
- NPM_API_URL=${NPM_API_URL} # Secret Woodpecker
- NPM_API_TOKEN=${NPM_API_TOKEN} # Secret Woodpecker
- DOMAIN_BASE=${DOMAIN_BASE:-syoul.fr}
commands:
# ... configuration automatique du proxy ...
```
Voir [Déploiement d'applications](09-deploiement-applications.md) pour plus de détails.
## Configuration SSL
### Certificats Let's Encrypt
Nginx Proxy Manager peut automatiquement obtenir des certificats SSL via Let's Encrypt :
1. Allez dans **SSL Certificates**
2. Cliquez sur **Add SSL Certificate**
3. Sélectionnez **Let's Encrypt**
4. Entrez le domaine (ex: `mon-app.syoul.fr`)
5. Cochez **Use a DNS Challenge** si nécessaire
6. Le certificat sera automatiquement renouvelé
### Forcer HTTPS
Dans la configuration du proxy host, activez :
- **SSL** : Certificat SSL
- **Force SSL** : Redirige automatiquement HTTP vers HTTPS
- **HSTS Enabled** : Active HTTP Strict Transport Security
## Access Lists (Listes de contrôle d'accès)
### Créer une Access List
1. Allez dans **Access Lists**
2. Cliquez sur **Add Access List**
3. Configurez :
- **Name** : Nom de la liste
- **Satisfy** : `any` (au moins une règle) ou `all` (toutes les règles)
- **Rules** : Ajoutez des règles d'autorisation
### Types de règles
- **IP Address** : Autoriser/bloquer des IPs spécifiques
- **Basic Auth** : Authentification HTTP basique
- **Client Certificate** : Authentification par certificat client
### Appliquer une Access List
Dans la configuration du proxy host :
1. Allez dans **Advanced** > **Access List**
2. Sélectionnez votre Access List
3. Sauvegardez
## Bonnes pratiques
### 1. Sécurité
- ✅ Changez le mot de passe par défaut immédiatement
- ✅ Utilisez des tokens API avec expiration si possible
- ✅ Limitez l'accès à l'interface d'administration (firewall)
- ✅ Utilisez HTTPS pour l'interface d'administration si exposée
### 2. Organisation
- ✅ Utilisez des noms de domaines cohérents
- ✅ Documentez les proxy hosts créés manuellement
- ✅ Utilisez des Access Lists pour sécuriser les applications sensibles
### 3. Monitoring
- ✅ Surveillez les logs dans **Audit Log**
- ✅ Vérifiez régulièrement les certificats SSL
- ✅ Monitor les performances des reverse proxies
## Dépannage
### Le token API ne fonctionne pas
1. Vérifiez que l'email et le mot de passe sont corrects
2. Vérifiez que l'URL est accessible :
```bash
curl http://192.168.42.144:81/api/nginx/proxy-hosts
```
3. Vérifiez les permissions de l'utilisateur dans NPM
### Erreur "401 Unauthorized"
- Le token est invalide ou expiré
- Régénérez un nouveau token
- Vérifiez que le header `Authorization: Bearer` est correct
### Erreur "Cannot connect to NPM API"
- Vérifiez que NPM est accessible depuis le conteneur Woodpecker
- Utilisez l'URL interne si dans le même réseau Docker
- Vérifiez les règles de firewall
### Le proxy host n'est pas créé
1. Vérifiez les logs de Woodpecker
2. Vérifiez que le domaine n'existe pas déjà
3. Vérifiez les permissions du token API
4. Testez manuellement la création via curl
## Exemples
### Script complet de déploiement avec NPM
```bash
#!/bin/bash
# deploy-with-npm.sh
APP_NAME="mon-app"
APP_PORT=3000
APP_IP="172.18.0.10"
APP_URL="${APP_NAME}.syoul.fr"
NPM_API_URL="http://npm-manager:81"
NPM_API_TOKEN="votre-token"
# Vérifier si le proxy existe
EXISTING_PROXY=$(curl -s -H "Authorization: Bearer ${NPM_API_TOKEN}" \
"${NPM_API_URL}/api/nginx/proxy-hosts" | \
jq -r ".[] | select(.domain_names[] == \"${APP_URL}\") | .id" | head -1)
PROXY_DATA=$(cat <<EOF
{
"domain_names": ["${APP_URL}"],
"forward_scheme": "http",
"forward_host": "${APP_IP}",
"forward_port": ${APP_PORT},
"ssl_forced": true,
"hsts_enabled": true,
"hsts_subdomains": true,
"block_exploits": true,
"caching_enabled": true,
"allow_websocket_upgrade": true
}
EOF
)
if [ -n "${EXISTING_PROXY}" ]; then
echo "Mise à jour du proxy existant..."
curl -X PUT "${NPM_API_URL}/api/nginx/proxy-hosts/${EXISTING_PROXY}" \
-H "Authorization: Bearer ${NPM_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "${PROXY_DATA}"
else
echo "Création d'un nouveau proxy..."
curl -X POST "${NPM_API_URL}/api/nginx/proxy-hosts" \
-H "Authorization: Bearer ${NPM_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "${PROXY_DATA}"
fi
echo "✅ Proxy configuré pour ${APP_URL}"
```
## Références
- [Documentation officielle Nginx Proxy Manager](https://nginxproxymanager.com/)
- [API Documentation](https://nginxproxymanager.com/guide/#api)
- [Déploiement d'applications avec Woodpecker](09-deploiement-applications.md)

View File

@ -21,6 +21,11 @@ Cette documentation couvre l'installation, la configuration et la maintenance de
7. [Registrator](07-configuration-registrator.md) - Auto-registration Docker avec token
8. [Deploiement Consul](08-deploiement-consul-registrator.md) - Guide de deploiement securise
### Deploiement d'applications
9. [Deploiement Applications](09-deploiement-applications.md) - Deploiement avec URLs dynamiques
10. [Nginx Proxy Manager](10-configuration-nginx-proxy-manager.md) - Configuration reverse proxy et API
## Stack technique
| Composant | Version | Description |
@ -30,6 +35,7 @@ Cette documentation couvre l'installation, la configuration et la maintenance de
| PostgreSQL | 14 | Base de donnees |
| Consul | latest | Service discovery avec ACL |
| Registrator | latest | Auto-registration avec token |
| Nginx Proxy Manager | latest | Reverse proxy avec API |
## Mode production