Zwei Websites mit Cloudflare + kostenlosem R2 + Beschleunigung per optimierter Domain: ein Rückblick, der alle Stolperfallen auf einmal klärt

Eine Fortsetzungsserie über Bildbeschleunigung: Wie wir zwei Sites von „erreichbar“ zu „wirklich schnell“ gefixt haben

Erst das Fazit:

  • d3v und aiya können jetzt stabil über die Cloudflare- + R2-Strecke laufen.
  • Alte und neue Bilder lassen sich beide öffnen.
  • Lokale historische Uploads können nach dem Backup bereinigt werden, wir sind nicht länger von der Festplatte als Geisel abhängig.

Dann der Prozess:

Akt 1: Wir dachten, es ist ein Netzwerkproblem – am Ende war es ein „systematischer Umweg“

Am Anfang haben alle nur auf die Latenz gestarrt:

  • China nach Singapur, ping sieht nach 300 ms aus.
  • SSH ruckelt so sehr, dass man am Leben zweifelt.
  • Die Business-Sites fühlten sich wegen CF-Reverse-Proxy und „optimierten“ Domains noch okay an.

Also kam die Frage aller Fragen:

„Kann man SSH auch so beschleunigen?“

Die Antwort: Man kann dran herumbasteln, aber das ist nicht einfach die HTTP-Beschleunigungs-Nummer, die man 1:1 übertragen kann. Später haben wir den Fokus erst mal auf die Bild-Route eingegrenzt – weil das der große, für Nutzer spürbare Brocken ist.

Akt 2: 404 heißt nicht, dass das Objekt weg ist – sondern dass beim Origin die falsche Heimat getroffen wurde

Der klassischste Fallstrick:

  • Der Link uploads.aiya.de5.net/... öffnet sich mit 404.
  • Aber in R2 per head_object ist das Objekt offensichtlich da.

Was heißt das?

Dass „die Storage-Schicht okay ist, aber die Traffic-Schicht nicht“.

Die finale Ursache:

  • Beim SaaS-Custom-Hostname von uploads.aiya zeigte der Origin zeitweise auf den Eingang eines anderen Buckets.
  • Origin-Host/SNI und das Nginx-Matching waren zeitweise ebenfalls gegeneinander verrutscht.
  • Dazu kam, dass Cloudflare das alte 404 gecacht hat – es sah dadurch aus wie „gefixt und doch nicht gefixt“.

Kurz gesagt:

Das Objekt ist im Bucket, heißt nicht, dass der Nutzer es bekommt.

Akt 3: Du denkst, es ist DNS – tatsächlich ist es „Multi-Layer-Konfigurations-Kopplung“

Diese Strecke hatte in Wirklichkeit vier Layer:

  1. Huawei Cloud Line-based Routing (Inland/Ausland)
  2. Cloudflare SaaS custom hostname
  3. Nginx Origin-Orchestrierung
  4. R2-Bucket: public/managed/custom domain

Jede Schicht, deren Konfiguration „ungefähr passt“, kann Requests in den falschen Bucket oder auf den falschen Host leiten.

Darum war unser Fix nicht „aus dem Bauch eine Zeile ändern“, sondern:

  • Erst ein Backup machen.
  • Dann Schicht für Schicht verifizieren (DNS → SaaS → Origin → Bucket-Objekt).
  • Jede Schicht mit curl -I und Objekt-HEAD faktisch verifizieren.

Akt 4: Warum alte Threads so gern „aussehen, als wäre nichts geändert“

Viele brechen hier mental zusammen:

„Ich bin doch schon auf S3/R2 – warum sind die alten Threads immer noch aiya.de5.net/uploads/...?“

Weil Discourse zwei Welten hat:

  • raw: der Originaltext des Posts (oft upload://...)
  • cooked: das gerenderte HTML (hier liegen img/src/srcset)

posts:rebake berechnet cooked aus raw neu.

Wenn du also nur cooked geändert hast, kann ein späteres Rebake dich wieder „zur Standard-Schreibweise zurückprügeln“.

Das ist kein R2-Ausfall, sondern normales Verhalten der Render-Strategie.

Akt 5: Was wir diesmal genau gemacht haben

Am Ende ist Folgendes live gegangen:

  • uploads.aiya so korrigiert, dass der Origin auf den richtigen Bucket zeigt.
  • Alte 404-Caches bereinigt.
  • Historisch fehlende Objekte nach R2 synchronisiert.
  • Für alte Posts cooked massenhaft auf https://uploads.aiya.de5.net/... ersetzt (damit die Darstellung auch konsistent ist).

Ergebnis:

  • Alle kaputten Bilder, die du gepostet hast, sind komplett wieder da.
  • Neue und alte Bilder treffen beide die Beschleunigungs-Strecke.

Eine „Weniger-Umwege“-Checkliste für Nachfolger

  1. Nicht zuerst Objektverlust vermuten – erst HEAD object machen.
  2. Bei 404 zuerst den Cache-Status prüfen: cf-cache-status: HIT kann einfach ein alter Cache sein.
  3. Nach Origin-Änderungen am SaaS custom hostname unbedingt das tatsächliche Host-Matching verifizieren.
  4. Pro Schritt nur eine Schicht ändern, Schicht für Schicht verifizieren – nicht überall gleichzeitig drehen und dann beten.
  5. Erst backupen, dann migrieren – besonders bei /shared/uploads/*.
  6. Den „Rollback-Pfad“ aufzuschreiben ist wichtiger als „diesmal hat’s endlich geklappt“.

Easter Egg: Das ehrlichste Bauchgefühl diesmal

Das ist nicht das Problem „ein DNS-Record war falsch“.

Das ist „eine halbunternehmerische Architektur, aus kostenlosen Bausteinen zusammengebaut“:

  • Sie kann Geld sparen, beschleunigen und laufen;
  • aber du musst die Geduld eines SRE mitbringen und akzeptieren, dass sie dich in Randfällen erzieht.

Bastelei hin oder her, am Ende war’s das wert:

  • Kosten nicht explodiert;
  • Geschwindigkeit ist da;
  • und die Architektur ist endlich von „geht irgendwie“ zu „erklärbar, wartbar“ geworden.

Hoffentlich hilft dieser Beitrag Nachfolgenden, ein paar Nächte weniger durchzumachen.