14 KiB
Infrastructure qpismont.fr
Infrastructure self-hosted complète hébergée sur serveur dédié, fournissant une plateforme DevOps avec Git, CI/CD, reverse proxy, VPN et observabilité.
Domaine : qpismont.fr Stack : Docker Swarm Repository : https://gitea.qpismont.fr/qpismont/infra
Vue d'ensemble
Cette infrastructure héberge l'ensemble des services nécessaires pour le développement et le déploiement de projets personnels :
- Hébergement Git avec interface web (Gitea)
- CI/CD automatisé pour builds et déploiements (Woodpecker)
- Agent IA de review de code sur webhooks Gitea (Herald)
- Reverse proxy avec HTTPS automatique (Caddy)
- Accès VPN sécurisé pour l'administration (WireGuard + CoreDNS)
- Observabilité : métriques, traces et dashboards (Prometheus, Tempo, Perses)
- Alerting temps réel avec notifications push (Alertmanager + ntfy)
Services déployés
Stack core
| Service | Image | Description | Exposition |
|---|---|---|---|
| reverse_caddy | caddy:2.11-alpine |
Reverse proxy, HTTPS auto, HTTP/3 | 80, 443/tcp, 443/udp |
| wireguard_server | linuxserver/wireguard:latest |
VPN d'accès distant + CoreDNS | 51820/udp |
Stack git
| Service | Image | Description | URL |
|---|---|---|---|
| gitea | docker.gitea.com/gitea:28.2 |
Hébergement Git | https://gitea.qpismont.fr · https://git.qpismont.fr |
| woodpecker_server | woodpeckerci/woodpecker-server:v3.19-alpine |
Serveur CI/CD | https://woodpecker.qpismont.fr |
| woodpecker_agent | woodpeckerci/woodpecker-agent:v3.19-alpine |
Agent d'exécution (Docker socket) | (interne) |
| herald | tintounn/herald:1.2 |
Agent IA de review sur webhooks Gitea (Docker socket) | (interne, métriques :9100) |
Stack observability
| Service | Image | Description | Exposition |
|---|---|---|---|
| prometheus | prom/prometheus:v3.13.3 |
TSDB + remote-write receiver | (interne) |
| otel-collector | otel/opentelemetry-collector-contrib:0.164.0 |
Collecte métriques + traces | (interne) |
| docker-proxy-otel | tecnativa/docker-socket-proxy:0.4.0 |
Proxy socket Docker (lecture seule) | (interne) |
| tempo | grafana/tempo:3.0.3 |
Stockage de traces (OTLP) | (interne) |
| perses | persesdev/perses:latest |
Dashboards | (via VPN) |
| alertmanager | prom/alertmanager:v0.34.1 |
Routage des alertes | (interne) |
| blackbox_exporter | prom/blackbox-exporter:v0.28.0 |
Probes HTTP externes | (interne) |
| ntfy | binwiederhier/ntfy:latest |
Notifications push | https://ntfy.qpismont.fr |
Configuration
- Timezone : Europe/Paris
- OAuth : Gitea ↔ Woodpecker intégré
- Admin : qpismont
- Scrape interval : 10 secondes
- Rétention Tempo : 48 h
- Rétention Prometheus : par défaut (15 j), volume persistant
Architecture
Internet
│
┌────────────┼────────────┐
│ │ │
Port 80/443 Port 443/udp Port 51820/udp
│ │ │
▼ ▼ ▼
[Caddy Proxy] [HTTP/3] [WireGuard VPN]
│ │
┌───────────┼───────────┬──────────┐ │
│ │ │ │ │
gitea:3000 woodpecker:8000 │ ntfy:80│
│ │
www.qpismont.fr [CoreDNS]
(portfolio) │
[Perses]
[Prometheus]
[Tempo]
┌──────────────────────────────────────────────────────────────┐
│ Stack git (CI/CD) │
│ │
│ [Gitea] ←──── OAuth ────→ [Woodpecker Server] │
│ │ │ │
│ │ webhook ▼ │
│ ▼ [Woodpecker Agent] │
│ [Herald] │ │
│ (review IA) ▼ │
│ [Docker-in-Docker] │
│ (build containers) │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ Stack observability │
│ │
│ [OTel Collector] ──┬─ hostmetrics (CPU/RAM/disk/net) │
│ │ ├─ docker_stats (métriques containers) │
│ │ ├─ prometheus scrape: │
│ │ │ reverse_caddy:2019 │
│ │ │ herald:9100 │
│ │ │ alertmanager:9093 │
│ │ │ blackbox_exporter:9115 │
│ │ └─ OTLP (4318) │
│ │ │
│ ├── remote_write ──→ [Prometheus] ──→ [Perses] │
│ └── OTLP ──────────→ [Tempo] │
│ │ │
│ [Prometheus] ── alertes ──→ [Alertmanager] ──→ [ntfy] │
└──────────────────────────────────────────────────────────────┘
Stacks Docker Swarm
| Stack | Fichier compose | Services |
|---|---|---|
core |
docker-compose.core.yml |
Caddy, WireGuard |
git |
docker-compose.git.yml |
Gitea, Woodpecker (server + agent), Herald |
observability |
docker-compose.observability.yml |
Prometheus, Perses, Tempo, Alertmanager, Blackbox, OTel Collector, proxy socket, ntfy |
Réseaux Docker Swarm
| Réseau | Type | Services |
|---|---|---|
reverse_network |
overlay | Caddy, Gitea, Woodpecker (server + agent), Herald, ntfy |
wireguard_network |
overlay | WireGuard, Prometheus, Perses, Tempo |
prometheus_network |
overlay | Caddy, Herald, Prometheus, Perses, Tempo, Alertmanager, Blackbox, OTel Collector, docker-proxy-otel, ntfy |
Stack technique
Orchestration
- Docker Engine avec Docker Swarm mode
- Docker Compose v3 (Stack deployment)
- Docker Secrets pour credentials sensibles
- Docker Configs pour configurations versionnées
Infrastructure as Code
- Configuration :
docker-compose.core.yml(Caddy, WireGuard),docker-compose.git.yml(Gitea, Woodpecker, Herald),docker-compose.observability.yml(Prometheus, Perses, Tempo, ntfy…) - Déploiement :
./deploy.sh(génère timestamp pour versioning) - Contexte Docker distant :
prod
Networking
- 3 réseaux overlay isolés
- Reverse proxy : Caddy avec Let's Encrypt automatique
- HTTP/3 (QUIC) activé sur port 443/udp
- VPN : WireGuard pour services internes
Storage
- Volumes Docker :
reversecaddydata,reversecaddyconfig(core) ·giteadata,woodpeckerdata(git) ·prometheusdata,tempodata,persesdata,alertmanagerdata,ntfydata(observability) - Host mounts :
/home/user/wireguard-config,/lib/modules(WireGuard) ·/var/run/docker.sock(Woodpecker agent, Herald,docker-proxy-otel) ·/en lecture seule (OTel Collector)
Monitoring
- Collecte : OTel Collector (hostmetrics + scrape Prometheus + OTLP)
- Stockage métriques : Prometheus (remote-write receiver activé)
- Stockage traces : Tempo (OTLP HTTP
:4318, rétention 48 h) - Dashboards : Perses (accessible via VPN)
- Container metrics : receiver
docker_statsde l'OTel Collector (labels Swarmservice_name/task_name) - Proxy metrics : Caddy admin API (
:2019) - Probes externes : blackbox_exporter (
http_2xxsur les URLs publiques) - Alerting : Prometheus → Alertmanager → ntfy (
http://ntfy:80/alerts)
Backups
- ⚠️ Aucun service de backup n'est déployé actuellement. L'ancien service
docker-volume-backupa été retiré (commit041eb51). Les sauvegardes sont à refaire manuellement ou à réintroduire.
Fonctionnalités
Gitea
- Hébergement de repositories Git illimité
- Issues, Pull Requests, Wikis
- OAuth provider pour Woodpecker
- Interface web complète
- API REST
Woodpecker CI
- Pipelines CI/CD automatisés
- Intégration native avec Gitea
- Agent Docker-in-Docker
- Limite : 1 workflow concurrent, CPU core 1
- Support multi-architectures
Herald
- Agent IA de review de code, déclenché par webhooks Gitea
- Modèle via OpenRouter (
openai/gpt-5.6-luna-pro) - Sandbox d'exécution limitée à 32 itérations
- 5 jobs concurrents max, timeout Gitea 60 s / OpenRouter 600 s
- Métriques Prometheus exposées sur
:9100
Caddy
- HTTPS automatique avec Let's Encrypt
- HTTP/3 (QUIC) support
- Renouvellement automatique des certificats
- Métriques Prometheus exposées
- Configuration simple (Caddyfile)
WireGuard
- VPN moderne et rapide
- Configuration : 1 peer (extensible)
- Accès sécurisé aux services internes
- CoreDNS embarqué pour résoudre
perses.internal,prometheus.internal,tempo.internal - Faible overhead
Monitoring
- OTel Collector : hostmetrics (CPU, RAM, disque, réseau, load, process) +
docker_stats(métriques containers) + scrape Prometheus + réception OTLP - Prometheus : stockage des métriques, remote-write receiver
- Tempo : stockage des traces OTLP
- Perses : visualisation moderne (alternative Grafana)
- blackbox_exporter : probes HTTP sur les URLs publiques
- Alertmanager : routage des alertes vers ntfy
- Scrape automatique toutes les 10 secondes
Alerting
- Règles :
ServiceDown(probe blackbox),OtelCollectorDown,CaddyDown - Seuil : 1 minute
- Inhibition :
CaddyDownsupprime lesServiceDown(évite le bruit) - Notification : webhook ntfy avec template
alertmanager,send_resolved: true
URLs et accès
Services publics
- Gitea : https://gitea.qpismont.fr (alias https://git.qpismont.fr)
- Woodpecker : https://woodpecker.qpismont.fr
- Portfolio : https://www.qpismont.fr (
qpismont.frredirige verswww) - ntfy : https://ntfy.qpismont.fr
Services internes (VPN requis)
- Perses : http://perses.internal:8080 (via WireGuard/CoreDNS)
- Prometheus : http://prometheus.internal:9090
- Tempo : http://tempo.internal:3200
- Caddy Admin : http://reverse_caddy:2019 (métriques)
VPN
- Protocole : WireGuard
- Port : 51820/udp
- Sous-réseau :
10.13.13.0/24 - Config :
/home/user/wireguard-config/peer1/
Déploiement
Le déploiement se fait via un contexte Docker distant vers le serveur de production :
./deploy.sh
Le script génère un timestamp pour versionner les configs et secrets, puis déploie les trois stacks (core, git, observability) sur le contexte prod.
Prérequis :
- Contexte Docker
prodconfiguré - Réseaux overlay créés (
reverse_network,wireguard_network,prometheus_network) - Secrets configurés dans
./secrets/(dossier ignoré par Git)
Configuration
Secrets Docker
| Secret | Fichier source | Usage |
|---|---|---|
woodpecker_agent_secret |
./secrets/woodpecker_agent_secret |
Communication server/agent Woodpecker |
woodpecker_gitea_client |
./secrets/woodpecker_gitea_client |
OAuth client ID Gitea |
woodpecker_gitea_secret |
./secrets/woodpecker_gitea_secret |
OAuth client secret Gitea |
herald_gitea_token |
./secrets/herald/herald_gitea_token |
Token API Gitea pour Herald |
herald_openrouter_token |
./secrets/herald/herald_openrouter_token |
Clé API OpenRouter |
herald_gitea_header_secret |
./secrets/herald/herald_gitea_header_secret |
Vérification signature webhook Gitea |
herald_sentry_dsn |
./secrets/herald/herald_sentry_dsn |
DSN Sentry |
Configs Docker
| Config | Fichier source | Stack |
|---|---|---|
caddy_config |
./Caddyfile |
core |
caddy_portfolio_html |
./portfolio/index.html |
core |
wireguard_coredns_config |
./wireguard/CoreDns |
core |
prometheus_config |
./prometheus/prometheus.yml |
observability |
prometheus_rules_config |
./prometheus/alert.rules.yml |
observability |
alertmanager_config |
./prometheus/alertmanager/alertmanager.yml |
observability |
blackbox_config |
./blackbox/blackbox.yml |
observability |
otel_collector_config |
./otel-collector/config.yaml |
observability |
tempo_config |
./tempo/tempo.yml |
observability |
Les configs et secrets sont versionnés avec ${DATETIME} pour forcer les mises à jour lors du déploiement. Ils s'accumulent donc à chaque déploiement : voir la section Nettoyage.