← tous les articles

Servir un site depuis R2 : trois pièges et un 404 qui ment

15 juin 2026 · 3 min de lecture

cloudflare-r2nginxs3debuggingarm64

Le plan : servir cette vitrine statique depuis un bucket Cloudflare R2, via l’image nginxinc/nginx-s3-gateway (un nginx qui authentifie + cache un bucket S3-compatible), derrière l’ingress du cluster. Sur le papier, dix minutes. En vrai, trois pièges — dont un 404 qui ment effrontément.

Piège 1 — zone "s3_backends" is too small

Premier déploiement : crash-loop immédiat.

nginx: [emerg] zone “s3_backends” is too small

Le gateway déclare une zone de mémoire partagée zone s3_backends 64k. Sur le worker (Raspberry Pi 5, arm64), la taille de page mémoire est de 16 Kio — et l’allocateur slab de nginx refuse une zone qui ne tient pas sur assez de pages. 64k = 4 pages : trop peu. Sur des pages 4 Kio classiques (x86), 64k = 16 pages, ça passe ; d’où le bug spécifique arm64.

Correctif : on monte un template upstreams.conf patché (zone 512k) en config Swarm.

Piège 2 — un resolver qui part en IPv6

Zone réglée, nouveau symptôme : 404 sur tout, et dans les logs :

connect() to [2606:4700:…]:443 failed (101: Network is unreachable)

Le cluster n’a pas d’IPv6 sortant, mais le resolver de nginx récupère l’enregistrement AAAA de R2 et tente l’IPv6 → injoignable. Une ligne suffit :

resolver 127.0.0.11 ipv6=off;

Piège 3 — le 404 qui ment (en fait c’est la signature)

Toujours 404. Mais cette fois aucune erreur réseau : nginx joint R2 en IPv4, et R2 répond 404. L’objet existe pourtant (aws s3 ls le voit). Un 404, normalement, c’est “clé absente”… sauf qu’ici, ce n’en est pas un.

DEBUG=true sur le gateway, et on lit la requête canonique SigV4 envoyée à R2 :

host:5dbfd0…r2.cloudflarestorage.com:443      ← le :443 est signé

Voilà le coupable. La signature AWS v4 inclut le header Host, et le gateway y colle :443. R2 calcule la signature sans le port (comme aws-cli, qui marche), les deux ne correspondent pas — et R2 répond… 404, pas 403. Trompeur au possible.

La cause : le S3_STYLE. Le gateway expose trois styles d’adressage, et un seul construit un Host sans le port :

S3_STYLEHeader Host signéR2
virtual-v2bucket.endpoint:443
pathendpoint:443
virtual (legacy)bucket.endpoint

Correctif : S3_STYLE=virtual. Connexion à l’endpoint compte (qui a bien des enregistrements A), Host sans port, signature alignée sur aws-cli. 200.

La leçon

Un 404 de R2 ne veut pas toujours dire “objet manquant”. Ici, c’était une signature SigV4 invalide (un :443 de trop dans le Host). Quand le code HTTP n’a pas de sens, activez le debug et lisez la requête canonique : la vérité est dans ce que vous signez, pas dans ce que vous croyez envoyer.

Trois pièges, trois lignes de config. Et un site servi depuis un bucket, derrière le même ingress que le reste du cluster.


📬 La newsletter homelab

Les nouveaux articles + retours d'expérience self-hosting, sans spam. Désinscription en un clic.