Warum ich alles hinter Cloudflare betreibe
- cloudflare
- infrastructure
- self-hosting
- cdn
Ein günstiger Hetzner-VPS mit Cloudflare davor ist ein besserer Stack als den die meisten Startups fahren. Hier ist, warum ich es für jedes Projekt nutze, und der eine Fall, bei dem ich es weglassen würde.
Jede Site, die ich veröffentliche, kommt zuerst hinter Cloudflare. Nicht weil es en vogue ist. Weil der Free-Tier allein ein globales CDN, eine echte Web Application Firewall, DDoS-Mitigation, Edge-SSL und schnelles autoritatives DNS liefert. Das ist viel Infrastruktur, die man nicht selbst betreiben muss. Darüber hinaus injiziert Cloudflare bei jeder einzelnen Anfrage einen Header mit dem Land des Besuchers, und dieser Header ist das Rückgrat der geo-basierten Spracherkennung auf dieser Site.
Der Free-Tier tut mehr, als man denkt
Die meisten kennen Cloudflare als CDN. Es cached statische Assets an Edge-Knoten nahe am Besucher, sodass die Antwort nicht für jede Anfrage zum Origin-Server in Nürnberg zurückreisen muss. Das allein reduziert die wahrgenommene Latenz für europäische und amerikanische Besucher spürbar. Aber das CDN ist der uninteressanteste Teil.
Die WAF ist interessanter. Der Free-Plan enthält das von Cloudflare verwaltete Ruleset. Es blockiert gängige Angriffsmuster: SQL-Injection, Cross-Site-Scripting, Directory Traversal, bekannte Exploit-Payloads. Ich habe erlebt, wie automatisierter Scanner-Traffic abgeblockt wurde, bevor er meinen Origin erreicht. Auf einem selbst gehosteten VPS verbraucht dieser Traffic trotzdem Bandbreite und CPU, wenn man ihn durchlässt. Cloudflare schluckt ihn am Edge.

Der DDoS-Schutz im Free-Tier ist kein Spielzeug. Volumetrische L3/L4-Angriffe werden automatisch absorbiert. L7-Angriffe auf Anwendungsebene können mit Rate-Limiting-Regeln und dem Bot-Fight-Mode-Schalter behandelt werden. Ich musste bei einem Angriff noch nie manuell eingreifen. Das Dashboard zeigt den Traffic-Spike, die Mitigation greift, und mein VPS sieht ihn nie.
Der Länder-Header, der das Geo-Routing antreibt
Das ist die Funktion, die für diesen spezifischen Stack am wichtigsten ist. Cloudflare fügt jeder proxied Anfrage einen cf-ipcountry-Header hinzu. Der Wert ist der ISO-3166-1-Alpha-2-Ländercode für die IP des Besuchers: DE für Deutschland, AT für Österreich, IT für Italien und so weiter. Mein Next.js-Middleware liest diesen Header und entscheidet, welche Locale es ausliefert.
Der interessante Fall ist Südtirol. Südtirol ist eine Provinz in Norditalien, in der etwa 70 Prozent der Bevölkerung Deutsch als Erstsprache sprechen. Ein Besucher aus Südtirol bekommt IT als Ländercode. Wenn man nur auf den Ländercode routen würde, bekäme er die italienische Locale. Das wäre falsch. Mein Middleware prüft den accept-language-Header zusammen mit cf-ipcountry: wenn das Land IT ist, aber die Browser-Sprachpräferenz de, liefert die Site Deutsch aus. Cloudflare liefert das Rohsignal. Mein Code liefert die Intelligenz.
Ohne Cloudflare kann man trotzdem Geo-Routing machen, braucht aber einen separaten IP-Geolokalisierungsdienst oder eine Datenbank. MaxMinds GeoIP2-Datenbank ist präzise, aber eine weitere Abhängigkeit, die man aktualisieren und warten muss. cf-ipcountry ist kostenlos, immer aktuell und bereits in der Anfrage. Es gibt keinen guten Grund, das anders zu lösen.
Ein VPS, die ganze Welt
Mein Origin ist ein einzelner Hetzner CPX31 in Nürnberg. Nürnberg ist in Ordnung für Deutschland und die DACH-Region. Für einen Nutzer in New York oder Singapur fügt das direkte Erreichen dieser Box Latenz hinzu. Mit Cloudflare davor werden gecachte Antworten vom nächsten ihrer 300-plus Edge-Knoten ausgeliefert. Statische Seiten, Blog-Posts, Bilder und der kompilierte Next.js-Output sind alle cachebar. Der Origin sieht hauptsächlich API-Aufrufe, Formularübermittlungen und dynamische SSR-Renders, die nicht gecacht werden können.
Cache-Regeln erlauben es, explizit festzulegen, was wie lange gecacht wird. Blog-Posts: ein Tag. Statische Assets in /_next/static/: dreißig Tage. API-Routen: Bypass. Man konfiguriert das einmal im Cloudflare-Dashboard oder über deren API und vergisst es. Caddy oder nginx auf dem Origin-Server muss überhaupt nicht über Caching nachdenken. Cloudflare erledigt es am Edge.
- Globales CDN: 300-plus Edge-Standorte, statische Inhalte nah am Besucher ausgeliefert
- WAF: verwaltete Rulesets blockieren OWASP-Top-10-Angriffsmuster im Free-Tier
- DDoS-Schutz: L3/L4 immer aktiv, L7 konfigurierbar mit Rate Limiting
- Edge-SSL: Cloudflare terminiert TLS, der Origin braucht nur ein selbst signiertes oder Let's-Encrypt-Zertifikat
- Bot Fight Mode: blockiert bekannte bösartige Bots am Edge, kostenlos
- Analytics: Anfragenanzahl, Cache/Nicht-Cache-Verhältnisse, gesparte Bandbreite
- cf-ipcountry-Header: Besucher-Land bei jeder Anfrage injiziert, kein zusätzlicher Dienst nötig
Cloudflare-IPs auf dem Origin vertrauen
Ein leicht zu übersehender Einrichtungsschritt: Der Origin-Server muss Cloudflares Proxy-IPs vertrauen und direkte Verbindungen blockieren. Wenn man das überspringt, kann jeder, der die Origin-IP entdeckt, die WAF vollständig umgehen. Man sichert das auf zwei Wegen ab. Erstens konfiguriert man den Reverse Proxy so, dass er echten Besucher-IPs nur vertraut, wenn die Anfrage von einem bekannten Cloudflare-IP-Bereich kommt. Cloudflare veröffentlicht diese Bereiche auf cloudflare.com/ips. Zweitens fügt man auf Hetzner eine Firewall-Regel hinzu, die Port 443 eingehend nur von Cloudflare-IP-Bereichen erlaubt, sodass der VPS nicht direkt erreichbar ist.
So mache ich es mit Caddy. Die trusted_proxies-Direktive teilt Caddy mit, welchen Upstream-IPs es für Header wie X-Forwarded-For und cf-ipcountry vertrauen soll. Die header_up-Zeile leitet den Ländercode als X-Visitor-Country an die Node-App weiter.
# Caddyfile — trust Cloudflare IPs, read cf-ipcountry header
{
servers {
trusted_proxies static 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22
104.16.0.0/13 104.24.0.0/14 108.162.192.0/18 131.0.72.0/22
141.101.64.0/18 162.158.0.0/15 172.64.0.0/13 173.245.48.0/20
188.114.96.0/20 190.93.240.0/20 197.234.240.0/22 198.41.128.0/17
}
}
:443 {
tls {
dns cloudflare YOUR_API_TOKEN
}
# Pass the geo country header downstream so your app can read it
header_up X-Visitor-Country '{http.request.header.Cf-Ipcountry}'
reverse_proxy localhost:3000
}Zone-Konfiguration in einer Markdown-Gedächtnisdatei pflegen
Ich nutze Claude Code als Coding-Agenten für alle meine Projekte. Wenn ein Agent bei der Infrastruktur hilft, braucht er Kontext, der eine einzelne Sitzung übersteht. Cloudflare-Zone-Einstellungen, welchen Headern zu vertrauen ist, Cache-Regellogik, Speicherort des API-Tokens: nichts davon sollte jedes Mal neu erklärt werden. Meine Lösung ist eine eingecheckte CLOUDFLARE.md-Datei im Projektstamm.
Die Datei ist keine Dokumentation. Sie ist ein Ops-Spickzettel, den der Agent zu Beginn jeder Sitzung liest, die Networking oder Deployment berührt. Wenn sich eine Einstellung ändert, weise ich den Agenten an, die Datei zu aktualisieren. Sie wird zum persistenten Gedächtnis, das Kontext-Window-Resets übersteht.

Hier ist ein repräsentatives Beispiel, wie diese Datei aussieht. Kurz und faktisch halten. Keine Prosa. Nur die Dinge, die ein Agent braucht, um korrekt zu handeln.
# Cloudflare Ops Memory
## Zone settings (applied in Cloudflare dashboard)
- SSL/TLS mode: Full (strict)
- Always Use HTTPS: on
- Min TLS Version: 1.2
- HSTS: enabled, max-age 31536000, includeSubDomains
## Trusted proxy IPs
Cloudflare publishes its IP ranges at https://www.cloudflare.com/ips/
Update the Caddy/nginx trusted_proxies list whenever Cloudflare rotates ranges.
## Headers we rely on
- cf-ipcountry: ISO 3166-1 alpha-2 country code for the visitor
Used for: South Tyrol (IT) => route to German (de) locale
- cf-ray: Cloudflare request ID, useful in error logs
- cf-connecting-ip: real visitor IP after CF proxy
## Cache rules (Page Rules or Cache Rules)
- /blog/* TTL 1 day, cache everything
- /api/* Bypass cache
- /_next/static/* TTL 30 days, cache everything
## WAF
- OWASP Core Ruleset: enabled, sensitivity medium
- Bot Fight Mode: on
## Notes for agent
- DNS A record for jumpinotech.com => Hetzner VPS IP, proxied (orange cloud)
- When changing origin IP: update Hetzner server, then update DNS A record in CF dashboard
- CF_ZONE_ID and CF_API_TOKEN stored in 1Password under "Cloudflare jumpinotech"Mit dieser Datei im Repository startet eine neue Sitzung mit Kontext. Der Agent weiß, welche Header weitergeleitet werden sollen, welcher SSL-Modus gesetzt ist, wo der API-Token liegt und wie die Caching-Strategie ist. Er halluziniert keine Einstellungen und stellt keine Verständnisfragen zu Dingen, die bekannte Fakten sein sollten. Die Datei ist kurz genug, um sie als vollständige Anweisung einzufügen, und spezifisch genug, um sofort umsetzbar zu sein.
Wann ich Cloudflare weglassen würde
Cloudflare ist der richtige Standard für fast jedes Projekt. Aber es gibt ehrliche Randfälle. Wenn der Origin bereits auf einer verteilten Plattform mit eigenem Edge-Netzwerk liegt, fügt das Vorschalten von Cloudflare einen Hop hinzu ohne großen Nutzen. Wenn man striktes End-to-End-TLS mit einer eigenen Zertifikatskette braucht und kein Zwischenproxy den Traffic berühren soll, ist Cloudflares Position in der Mitte ein Problem. Einige regulierte Branchen haben Anforderungen dazu, wo DNS auflöst und wer Traffic proxied, die Cloudflare zu einem Compliance-Risiko statt einem Asset machen.
Für einen selbst gehosteten Stack auf einem einzelnen VPS trifft keine dieser Ausnahmen zu. Der Free-Tier leistet echte Arbeit. Die WAF, das CDN, die DDoS-Absorption, der Länder-Header, die Analytics: man würde echte Ingenieurzeit aufwenden, um eine gleichwertige Abdeckung selbst zu bauen. Cloudflare liefert sie zum Preis des Umlenkens der Nameserver. Das ist eine leichte Entscheidung.
Der Südtirol-Routing-Fall ist eine gute Illustration. Ohne cf-ipcountry bräuchte ich eine Geolokalisierungsdatenbank, einen Cron-Job um sie aktuell zu halten und eine zusätzliche Abfrage bei jeder Anfrage. Mit Cloudflare ist es ein Header. Die Site liefert die richtige Sprache für das dreisprachige Südtirol, weil Cloudflare mitteilt, wo der Besucher ist, und die Middleware die Logik hat, von dort die richtige Wahl zu treffen.