xpeditis2.0/docs/mise-en-prod/01-prerequis.md
David b22f4e0b74 docs: procedure de mise en production pas a pas
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
2026-09-07 21:40:50 +02:00

6.5 KiB

01 — Prérequis

Durée : 2 à 3 h. Rien de technique ici, mais tout bloque si un élément manque au moment où vous en avez besoin.


1. Comptes à créer ou vérifier

Service Rôle À faire Coût
Hetzner Cloud Serveurs, réseau, firewalls, volume Créer un projet dédié xpeditis-prod, séparé de la preprod. Activer la 2FA. ~50 €/mois
Hetzner Storage Box Seconde copie des dumps Commander une BX11 (1 To). Commande séparée de Hetzner Cloud. 3,90 €/mois
Hetzner Object Storage Documents + archives WAL-G Activer dans le projet, région fsn1. ~6 €/mois
Cloudflare DNS, WAF, anti-DDoS Zone xpeditis.com déléguée. Plan Free suffisant. 2FA obligatoire. 0 €
Registrar du domaine xpeditis.com Pointer les serveurs de noms vers Cloudflare. Activer le verrou de transfert. ~10 €/an
Scaleway Container Registry Images Docker Déjà utilisé par la preprod. Vérifier que REGISTRY_TOKEN est encore valide. ~1 €/mois
Brevo E-mails transactionnels Créer une nouvelle clé SMTP de production (celle de preprod est compromise). Vérifier le domaine expéditeur. 0 → 19 €/mois
Stripe Paiements Passer le compte en mode Live. Récupérer sk_live_…, créer le webhook de production, noter les 6 identifiants de tarif. % du volume
Sentry Erreurs applicatives Projet xpeditis-prod distinct de la preprod. 0 → 26 €/mois
Pappers Vérification SIRET Clé API. Facultatif : sans clé, la vérification est simplement ignorée. ~3 €/mois
Discord Alertes et déploiements Deux webhooks : #deploiements et #alertes. 0 €
healthchecks.io ou BetterStack Surveillance externe Un heartbeat pour les sauvegardes, un contrôle d'uptime sur https://app.xpeditis.com. 0 €

Pourquoi un projet Hetzner séparé — le token API est valable pour tout un projet. Un token de preprod compromis ne doit pas pouvoir détruire la production. La séparation est aussi ce qui isole les deux réseaux privés.


2. Décisions à trancher maintenant

2.1 Adresse e-mail d'exploitation

Une adresse relevée est nécessaire pour :

  • Let's Encrypt (avertissements d'expiration si le renouvellement casse) ;
  • Hetzner (incidents, maintenances) ;
  • Cloudflare et le registrar.

Recommandé : ops@xpeditis.com, redirigée vers votre boîte personnelle. Remplacez ops@xpeditis.com dans infra/prod/k8s/cluster/cluster-issuer.yaml si vous choisissez autre chose.

2.2 IP d'administration

Terraform refuse 0.0.0.0/0 pour SSH. Il vous faut une IP publique stable.

curl -s https://ifconfig.me
  • IP fixe (fibre pro, bureau) → parfait.
  • IP dynamique → deux options :
    • relancer terraform apply quand elle change (acceptable si c'est rare) ;
    • passer par un VPN à IP fixe (Mullvad, un petit serveur Hetzner CX22 à 4 €).

2.3 Noms de domaine

La configuration livrée suppose :

Domaine Sert
xpeditis.com, www.xpeditis.com vitrine (pages publiques du frontend)
app.xpeditis.com application (origine des cookies d'authentification)
api.xpeditis.com API
grafana.xpeditis.com supervision

Pour un autre découpage, modifiez k8s/base/02-configmap-backend.yaml (APP_URL, CORS_ORIGIN, COOKIE_DOMAIN) et k8s/base/09-ingress.yaml.

COOKIE_DOMAIN=.xpeditis.com (avec le point initial) est indispensable : l'API pose le cookie sur api.xpeditis.com, le middleware Next.js le lit sur app.xpeditis.com. Sans le point, la connexion réussit mais l'utilisateur est renvoyé sur /login — le symptôme est déroutant, la cause est ici.


3. Outils sur votre poste

# macOS
brew install terraform kubectl sops age hcloud jq rsync
brew install --cask docker          # pour construire des images localement

# Vérification
terraform version   # >= 1.6
kubectl version --client
sops --version      # >= 3.8
age --version
hcloud version
jq --version

shellcheck est facultatif mais utilisé par make validate :

brew install shellcheck

4. Clés SSH

Trois clés distinctes, jamais interchangeables :

# 1. Administration (vous, sur les deux serveurs)
ssh-keygen -t ed25519 -a 100 -C "xpeditis-prod-admin" -f ~/.ssh/xpeditis_prod

# 2. Déploiement CI (GitHub Actions → app-01, restreinte à un script)
ssh-keygen -t ed25519 -a 100 -C "github-actions-prod" -f ~/.ssh/xpeditis_ci

# 3. Storage Box (db-01 → Storage Box, pour les dumps)
ssh-keygen -t ed25519 -a 100 -C "xpeditis-storagebox" -f ~/.ssh/xpeditis_storagebox

Protégez la clé d'administration par une phrase de passe. Celles de la CI et de la Storage Box sont utilisées par des automates : elles ne peuvent pas en avoir, c'est justement pourquoi leurs privilèges sont limités.

Sauvegardez les trois clés privées dans votre gestionnaire de mots de passe. Perdre la clé d'administration signifie repasser par la console Hetzner en mode secours.


5. Clé de chiffrement des secrets

C'est la clé à ne pas perdre : elle déchiffre tous les secrets de production. Sa création est détaillée dans 06-secrets-sops.md, mais générez-la maintenant, vous en aurez besoin partout :

mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
chmod 600 ~/.config/sops/age/keys.txt
grep 'public key' ~/.config/sops/age/keys.txt

Générez aussi une clé de secours, stockée hors ligne (papier dans un coffre, ou clé USB chiffrée rangée ailleurs). Les deux clés publiques iront dans infra/prod/.sops.yaml. Sans clé de secours, la perte de votre poste = la perte définitive de tous les secrets de production.


6. Contrôle avant de passer à la suite

[ ] Projet Hetzner Cloud `xpeditis-prod` créé, 2FA activée
[ ] Storage Box BX11 commandée (l'activation prend jusqu'à 1 h)
[ ] Zone Cloudflare active pour xpeditis.com, 2FA activée
[ ] Compte Stripe en mode Live, webhook de production créé
[ ] Nouvelle clé SMTP Brevo de production créée
[ ] Domaine expéditeur vérifié chez Brevo (SPF/DKIM prêts à publier)
[ ] ops@xpeditis.com relevée
[ ] IP d'administration connue et stable
[ ] Outils installés (terraform, kubectl, sops, age, hcloud, jq)
[ ] 3 clés SSH générées et sauvegardées
[ ] Clé age principale + clé de secours générées
[ ] Webhooks Discord créés

→ Suite : 02 — Provisioning Hetzner