Perché metto tutto dietro a Cloudflare
- cloudflare
- infrastructure
- self-hosting
- cdn
Un VPS Hetzner economico con Cloudflare davanti è uno stack migliore di quello che usano la maggior parte delle startup. Ecco perché lo uso per ogni progetto, e l'unico caso in cui lo salterei.
Ogni sito che pubblico passa dietro a Cloudflare prima di qualsiasi altra cosa. Non per moda. Perché il piano gratuito da solo ti dà una CDN globale, un vero web application firewall, mitigazione DDoS, SSL all'edge e DNS autorevole veloce. È molta infrastruttura che non devi gestire tu. In più, Cloudflare inietta un header con il paese del visitatore su ogni singola richiesta, e quell'header è il pilastro del rilevamento della lingua basato sulla geo-localizzazione su questo sito.
Il piano gratuito fa più di quanto pensi
La maggior parte delle persone conosce Cloudflare come CDN. Mette in cache gli asset statici su nodi edge vicini al visitatore, così la risposta non deve tornare dal server di origine a Norimberga per ogni richiesta. Questo da solo riduce la latenza percepita per i visitatori europei e americani in modo significativo. Ma la CDN è la parte meno interessante.
Il WAF è più interessante. Il piano gratuito include il ruleset gestito da Cloudflare. Blocca i pattern di attacco comuni: SQL injection, cross-site scripting, directory traversal, payload di exploit noti. Ho visto bloccare traffico di scanner automatici prima che raggiunga la mia origine. Su un VPS self-hosted quel traffico consuma comunque larghezza di banda e CPU se lo lasci passare. Cloudflare lo assorbe all'edge.

La protezione DDoS nel piano gratuito non è un giocattolo. Gli attacchi volumetrici L3/L4 vengono assorbiti automaticamente. Gli attacchi L7 a livello applicativo possono essere gestiti con regole di rate-limiting e il toggle Bot Fight Mode. Non ho mai dovuto intervenire manualmente durante un attacco. La dashboard mostra il picco di traffico, entra in azione la mitigazione, e il mio VPS non lo vede mai.
L'header paese che alimenta il routing geo
Questa è la funzionalità che conta di più per questo stack specifico. Cloudflare aggiunge un header cf-ipcountry a ogni richiesta proxata. Il valore è il codice paese ISO 3166-1 alpha-2 per l'IP del visitatore: DE per la Germania, AT per l'Austria, IT per l'Italia, e così via. Il mio middleware Next.js legge questo header e decide quale locale servire.
Il caso interessante è l'Alto Adige. L'Alto Adige è una provincia nel nord Italia dove circa il 70 percento della popolazione parla tedesco come prima lingua. Un visitatore dall'Alto Adige riceve IT dal codice paese. Se facessi il routing solo sul codice paese, riceverebbe il locale italiano. È sbagliato. Il mio middleware controlla l'header accept-language insieme a cf-ipcountry: se il paese è IT ma la preferenza linguistica del browser è de, il sito serve tedesco. Cloudflare fornisce il segnale grezzo. Il mio codice fornisce l'intelligenza.
Senza Cloudflare puoi comunque fare il routing geo, ma hai bisogno di un servizio di geolocalizzazione IP separato o di un database. Il database GeoIP2 di MaxMind è accurato ma è un'altra dipendenza da aggiornare e mantenere. cf-ipcountry è gratuito, sempre aggiornato e già presente sulla richiesta. Non c'è motivo valido per farlo in modo diverso.
Un VPS, il mondo intero
La mia origine è un singolo Hetzner CPX31 a Norimberga. Norimberga va bene per la Germania e la regione DACH. Per un utente a New York o Singapore, raggiungere direttamente quel box aggiunge latenza. Con Cloudflare davanti, le risposte in cache vengono servite dal nodo edge più vicino tra i loro 300 e più. Pagine statiche, post del blog, immagini e l'output Next.js compilato sono tutti cacheable. L'origine vede principalmente chiamate API, invii di moduli e render SSR dinamici che non possono essere messi in cache.
Le regole di cache ti permettono di essere esplicito su cosa viene messo in cache e per quanto tempo. Post del blog: un giorno. Asset statici in /_next/static/: trenta giorni. Route API: bypass. Lo configuri una volta nel dashboard di Cloudflare o tramite la loro API e lo dimentichi. Il Caddy o nginx del server di origine non deve pensare alla cache. Cloudflare la gestisce all'edge.
- CDN globale: 300 e più location edge, contenuto statico servito vicino al visitatore
- WAF: i ruleset gestiti bloccano i pattern di attacco OWASP Top 10 nel piano gratuito
- Protezione DDoS: L3/L4 always-on, L7 configurabile con rate limiting
- SSL all'edge: Cloudflare termina TLS, quindi la tua origine ha bisogno solo di un certificato self-signed o Let's Encrypt
- Bot Fight Mode: blocca i bot malevoli noti all'edge, gratuito
- Analytics: conteggi delle richieste, rapporti cache/non cache, larghezza di banda risparmiata
- Header cf-ipcountry: paese del visitatore iniettato su ogni richiesta, nessun servizio extra necessario
Fidarsi degli IP di Cloudflare sull'origine
Un passaggio di configurazione facile da dimenticare: il tuo server di origine deve fidarsi degli IP proxy di Cloudflare e bloccare le connessioni dirette. Se lo salti, chiunque scopra l'IP della tua origine può aggirare completamente il WAF. Lo blocchi in due modi. Primo, configura il reverse proxy per fidarsi degli IP reali dei visitatori solo quando la richiesta proviene da un range IP Cloudflare noto. Cloudflare pubblica questi range su cloudflare.com/ips. Secondo, su Hetzner, aggiungi una regola firewall che consenta solo la porta 443 in entrata dai range IP di Cloudflare, così il VPS non è raggiungibile direttamente.
Ecco come lo faccio con Caddy. La direttiva trusted_proxies dice a Caddy di quali IP upstream fidarsi per header come X-Forwarded-For e cf-ipcountry. La riga header_up trasferisce il codice paese all'app Node come X-Visitor-Country.
# 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
}Tenere la configurazione della zone in un file markdown di memoria
Uso Claude Code come agente di coding su tutti i miei progetti. Quando un agente aiuta con l'infrastruttura, ha bisogno di contesto che sopravviva a una singola sessione. Impostazioni della zone Cloudflare, quali header fidarsi, logica delle regole di cache, posizione del token API: niente di tutto questo dovrebbe essere rispiegato ogni volta. La mia soluzione è un file CLOUDFLARE.md incluso nel repository alla radice del progetto.
Il file non è documentazione. È un cheat sheet operativo che l'agente legge all'inizio di ogni sessione che tocca networking o deployment. Quando un'impostazione cambia, dico all'agente di aggiornare il file. Diventa la memoria persistente che sopravvive ai reset della finestra di contesto.

Ecco un esempio rappresentativo di come appare quel file. Mantienilo fattuale e breve. Niente prosa. Solo le cose di cui un agente avrebbe bisogno per agire correttamente.
# 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"Con questo nel repository, una nuova sessione parte con contesto. L'agente sa quali header trasferire, quale modalità SSL è impostata, dove vive il token API e qual è la strategia di caching. Non allucienta impostazioni né pone domande di chiarimento su cose che dovrebbero essere fatti noti. Il file è abbastanza corto da incollare per intero come istruzione e abbastanza specifico da essere immediatamente utilizzabile.
Quando salterei Cloudflare
Cloudflare è il default corretto per quasi ogni progetto. Ma ci sono casi limite onesti. Se la tua origine è già su una piattaforma distribuita con la propria rete edge, aggiungere Cloudflare davanti aggiunge un hop senza grandi benefici. Se hai bisogno di TLS end-to-end rigoroso con la tua catena di certificati e nessun proxy intermedio che tocchi il traffico, la posizione di Cloudflare nel mezzo è un problema. Alcuni settori regolamentati hanno requisiti su dove si risolve il DNS e chi proxia il traffico che rendono Cloudflare un rischio di conformità anziché un asset.
Per uno stack self-hosted su un singolo VPS, nessuna di queste eccezioni si applica. Il piano gratuito fa lavoro reale. Il WAF, la CDN, l'assorbimento DDoS, l'header paese, le analytics: dovresti spendere tempo di ingegneria reale per costruire una copertura equivalente da solo. Cloudflare te la dà al costo di puntare i tuoi nameserver. È una decisione facile.
Il caso del routing dell'Alto Adige è una buona illustrazione. Senza cf-ipcountry, avrei bisogno di un database di geolocalizzazione, un cron job per tenerlo aggiornato e una ricerca extra su ogni richiesta. Con Cloudflare è un header. Il sito serve la lingua giusta per l'Alto Adige trilingue perché Cloudflare dice dove si trova il visitatore, e il middleware ha la logica per fare la scelta giusta da lì.