SA
← Retour au blog
TutorielDevOps & Infra2026-04-09· 8 min de lecture

K3s + Nginx Proxy Manager : résoudre le conflit de double certificat TLS

Quand vous déployez une app Kubernetes derrière Nginx Proxy Manager, le challenge ACME HTTP-01 de cert-manager échoue silencieusement — parce que NPM intercepte le port 80 avant que Traefik ne le voit jamais. Voici la cause racine et la solution propre.

#K3s#Kubernetes#Traefik#cert-manager#Nginx Proxy Manager#TLS#Let's Encrypt

Le contexte

Vous avez un cluster K3s self-hosted. Nginx Proxy Manager (NPM) tourne comme conteneur Docker et gère tout le trafic entrant sur les ports 80 et 443. Votre app vit dans K3s, exposée via Traefik comme ingress controller.

Vous ajoutez cert-manager avec un ClusterIssuer pointant sur Let's Encrypt, annotez votre ingress, lancez kubectl apply. Le pod est healthy. Mais le site affiche 404 Not Found — et le certificat TLS ne se crée jamais.

Diagnostic : où atterrit vraiment le port 80 ?

Le premier réflexe : vérifier ce qui écoute.

ss -tlnp | grep ':80'

Vous obtenez quelque chose comme :

LISTEN 0  4096  0.0.0.0:80  0.0.0.0:*

Puis identifiez le process qui l'occupe :

ps aux | grep docker-proxy
root  1476001  docker-proxy -host-port 80 -container-ip 172.18.0.7 ...

NPM est un conteneur Docker avec ports: ["80:80", "443:443"]. C'est lui qui bind les ports 80 et 443 sur l'hôte — pas Traefik.

Traefik, dans une installation K3s standard, est exposé en NodePort :

kubectl get svc -A | grep traefik
traefik  NodePort  10.43.147.1  9000:30900/TCP,8080:30080/TCP,8443:30443/TCP

Traefik n'écoute que sur 30080 (HTTP) et 30443 (HTTPS) côté hôte. Il ne reçoit jamais le trafic extérieur sur le port 80.

La cause racine

Le challenge HTTP-01 de cert-manager fonctionne ainsi :

  1. cert-manager crée un pod temporaire et un ingress solver dans K3s
  2. Il demande à Let's Encrypt de valider : http://mondomaine.com/.well-known/acme-challenge/<token>
  3. Let's Encrypt tape votre serveur sur le port 80

Le problème : cette requête arrive sur NPM, qui n'a aucun proxy host configuré pour votre domaine. NPM répond 404. Let's Encrypt rejette le challenge. Le certificat n'est jamais émis.

Vous pouvez le confirmer directement :

curl -v http://mondomaine.com/.well-known/acme-challenge/sometoken

Les headers de réponse montreront Server: openresty — c'est le nginx de NPM, pas Traefik.

Pendant ce temps, dans le cluster, les logs cert-manager indiquent :

Waiting for HTTP-01 challenge propagation: wrong status code '404', expected '200'

Le problème du double TLS

L'annotation traefik.ingress.kubernetes.io/router.tls: "true" combinée à entrypoints: web,websecure pousse Traefik à vouloir gérer le HTTPS lui-même. Mais :

  • Le certificat TLS n'est pas émis (challenge échoué)
  • Même s'il l'était, le trafic HTTPS arrive chez NPM sur le port 443 — pas sur le NodePort 30443 de Traefik

Vous vous retrouvez avec deux systèmes TLS concurrents :

  • NPM : prêt à gérer le SSL pour votre domaine, mais sans proxy host configuré
  • cert-manager : essaie d'émettre un certificat qu'il ne peut jamais obtenir car le port 80 appartient à NPM

Aucun ne fonctionne. D'où le 404.

La solution

L'architecture doit être :

Internet → NPM (port 80/443, SSL géré par NPM)
               ↓
         Traefik NodePort 30080 (HTTP simple)
               ↓
         Pod de votre app

NPM est le point de terminaison SSL. K3s/Traefik n'a besoin de gérer que le routage HTTP interne.

Étape 1 — Nettoyer l'ingress K8s

Supprimez les annotations cert-manager et la section TLS. Dites à Traefik d'utiliser uniquement l'entrypoint web :

# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: monapp-ingress
  namespace: monapp
  annotations:
    kubernetes.io/ingress.class: traefik
    traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
  ingressClassName: traefik
  rules:
    - host: mondomaine.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: monapp-web
                port:
                  number: 80

Appliquez et nettoyez les ressources cert-manager cassées :

kubectl apply -f k8s/ingress.yaml
kubectl delete certificate,certificaterequest,challenge --all -n monapp

Étape 2 — Vérifier que Traefik route correctement

Testez le routage en interne avant de toucher NPM :

curl -H "Host: mondomaine.com" http://127.0.0.1:30080/
# attendu : 200 ou 307 (redirect vers /fr ou /home)

Si vous obtenez 200, Traefik route correctement.

Étape 3 — Configurer NPM

Dans le panel admin de NPM (port 81), ajoutez un nouveau Proxy Host :

  • Domain Names : mondomaine.com
  • Scheme : http
  • Forward Hostname / IP : 127.0.0.1
  • Forward Port : 30080
  • Onglet SSL : Demandez un certificat Let's Encrypt, activez "Force SSL"

NPM possède le port 80, donc son challenge ACME HTTP-01 réussit du premier coup. Le certificat est émis, le HTTPS fonctionne, et le trafic transite proprement dans la chaîne.

Pourquoi ne pas garder cert-manager ?

cert-manager est le bon outil quand Traefik est exposé directement sur les ports 80/443 — typiquement dans un setup K3s bare-metal sans reverse proxy au niveau de l'hôte. Dès que vous ajoutez NPM en amont, cert-manager perd l'accès direct au port 80 et devient redondant : NPM gère déjà les certificats Let's Encrypt nativement.

Règle d'or : un seul système doit posséder le port 80 sur un hôte. Si c'est NPM, c'est NPM qui gère le TLS. Si c'est Traefik directement, c'est cert-manager qui gère le TLS.

Points clés à retenir

  • Server: openresty dans une réponse curl signifie que c'est NPM qui a répondu, pas Traefik
  • Vérifiez ce qui occupe le port 80 avec ss -tlnp avant de déboguer les certificats
  • Le challenge HTTP-01 de cert-manager nécessite un accès direct au port 80 — NPM le bloque silencieusement
  • La correction est architecturale : supprimez le TLS de K8s, laissez NPM terminer le SSL, proxy vers le NodePort Traefik
  • cert-manager et NPM sont redondants — choisissez une seule stratégie TLS par hôte
SA

Stéphane Agoumé

Architecte Solution IA · Coach & Mentor · Conférencier

Me contacter
K3s + Nginx Proxy Manager : résoudre le conflit de double certificat TLS — Stéphane Agoumé