Vai al contenuto

Un bucket R2 per tenant serve quando contano residenza e cancellazione

Infra · 9 novembre 2026 · 9 min di lettura

Loops winding across a grid of tiles in black, white and grey

Lo storage per tenant su Cloudflare R2 è la scelta tra dare a ogni cliente di un SaaS un bucket tutto suo e dargli un prefisso di chiavi dentro un bucket condiviso. Da questa scelta dipendono la registrazione, il modo in cui fatturi lo spazio occupato, il luogo fisico in cui stanno i file di un cliente e la prova che li hai cancellati quando se ne va.

La domanda arriva il giorno in cui il prodotto lascia caricare file agli utenti. Il primo istinto, spesso, è un bucket per cliente, creato via API all'apertura dell'account. Funziona, e oggi R2 lo rende economico fino a un certo punto. Però mette dentro il flusso di registrazione una chiamata alle API di Cloudflare, una regola sui nomi e un limite di frequenza. Qui confrontiamo i due modelli con i limiti pubblicati da R2 a novembre 2026, e vediamo come automatizzare l'uno e l'altro.

Da quale modello conviene partire?

Dal prefisso per tenant, in un bucket condiviso per ogni giurisdizione dei dati. Un bucket dedicato serve quando un contratto chiede qualcosa che solo un bucket dà: file conservati nell'Unione europea, una voce di spazio in fattura presa dai numeri di Cloudflare, un dominio personalizzato per cliente, o una cancellazione che puoi dimostrare con un bucket che non esiste più. Quasi tutti i prodotti usano il primo modello per tutti i clienti e il secondo per pochi.

I due modelli a confronto

  • Registrazione. Prefisso: niente da creare, il primo caricamento scrive sotto tenants/<tenant-id>/. Bucket: una chiamata CreateBucket, poi la configurazione di CORS e lifecycle.
  • Tetto. Prefisso: oggetti illimitati per bucket. Bucket: 100.000 inclusi per account, poi 0,10 $ al mese per ogni bucket in più.
  • Isolamento. Prefisso: lo garantiscono il codice e credenziali limitate al prefisso. Bucket: lo garantisce il confine del bucket.
  • Consumo per cliente. Prefisso: un registro tenuto da te. Bucket: i dati di storage di R2, letti per nome del bucket.
  • Posizione dei dati. Prefisso: decisa una volta per bucket condiviso. Bucket: decisa per cliente alla creazione, poi non cambia.
  • Uscita del cliente. Prefisso: cancelli ogni chiave sotto il prefisso. Bucket: lo svuoti, poi lo elimini.

Cosa consente R2 per account nel 2026?

Quattro numeri della documentazione di Cloudflare pesano sulla scelta.

  • Bucket. Non c'è un tetto rigido: il limite predefinito è di 100.000 bucket per account, e ogni bucket oltre quella soglia costa 0,10 $ al mese (limiti di R2, prezzi di R2). Con 250.000 tenant e un bucket ciascuno, questa sola voce vale 15.000 $ al mese prima di salvare un byte.
  • Frequenza delle API REST. Le API REST di Cloudflare accettano 1.200 richieste ogni cinque minuti, sommando tutte le operazioni R2 dell'account. Chi supera la soglia si vede bloccare ogni chiamata per i cinque minuti successivi, dashboard compresa (limiti delle API di Cloudflare). Un picco di registrazioni che crea bucket via REST può chiuderti fuori dalla tua stessa dashboard.
  • Gestione dei bucket. Creare, eliminare, elencare e configurare hanno un tetto di 50 operazioni al secondo per bucket. Letture e scritture di oggetti non contano.
  • Token API. Un account ha al massimo 500 token API di account. Una chiave S3 permanente per ogni cliente smette di funzionare al cliente numero 501.

I nomi dei bucket aggiungono un vincolo: lettere minuscole, cifre e trattini, da 3 a 63 caratteri, senza trattino all'inizio o alla fine (creare un bucket). Un id tenant in formato UUID ci sta, con i suoi 36 caratteri. Il nome di un'azienda va ripulito prima, e due aziende possono finire sulla stessa stringa.

Quando vince il prefisso per tenant

La registrazione resta nel database

All'apertura dell'account su R2 non si crea niente. Il primo caricamento scrive in tenants/<tenant-id>/ e da quel momento il prefisso esiste. Nessuna chiamata esterna può fallire a metà onboarding, quindi non resta nessun cliente creato a metà da sistemare.

Nessun tetto, nessun costo per bucket

Un bucket contiene oggetti illimitati. Un prodotto con un piano gratuito e tanti account dormienti paga solo i byte che quegli account occupano, 0,015 $ per GB al mese sullo storage Standard, con il traffico in uscita gratuito in entrambi i modelli.

L'accesso limitato funziona lo stesso

L'isolamento passa dal confine del bucket alla credenziale. Le credenziali temporanee di R2 partono da un token padre, valgono per un solo bucket con un livello di permessi e, se vuoi, una lista di prefissi, e scadono al massimo dopo 604.800 secondi, cioè sette giorni (credenziali temporanee). Una credenziale limitata a tenants/acme/ non legge tenants/globex/. Per un singolo caricamento o download dal browser basta un URL prefirmato: un'operazione su un oggetto, valida da un secondo a sette giorni (URL prefirmati).

POST /accounts/{account_id}/r2/temp-access-credentials
{
  "bucket": "tenants-default",
  "parentAccessKeyId": "<parent key id>",
  "permission": "object-read-write",
  "prefixes": ["tenants/acme/"],
  "ttlSeconds": 900
}

Ogni chiamata a questo endpoint consuma una delle 1.200 richieste dei cinque minuti. Per emettere tante credenziali brevi, Cloudflare documenta una strada locale: il backend firma un JWT con il segreto del token padre e ricava la credenziale da solo, senza chiamare Cloudflare. Se revochi il token padre, tutte le credenziali derivate smettono di funzionare subito.

Quando vince il bucket per tenant

Residenza dei dati per cliente

La giurisdizione è una proprietà del bucket. R2 offre eu, us e fedramp, garantisce che gli oggetti restino nella giurisdizione scelta e non permette di cambiarla dopo la creazione (posizione dei dati). Con i prefissi, i clienti europei condividono un bucket UE. Con i bucket, ogni cliente ha la giurisdizione scritta nel suo contratto. In tutti e due i casi serve un client S3 per giurisdizione: un bucket con giurisdizione risponde solo al suo endpoint, https://<ACCOUNT_ID>.eu.r2.cloudflarestorage.com per l'UE (autenticazione R2).

Consumo per cliente dai numeri di Cloudflare

Le metriche di storage di R2 riportano dimensione e numero di oggetti per nome del bucket, tramite la GraphQL Analytics API, su intervalli fino a 31 giorni (metriche di R2). Con un bucket per cliente, la voce di spazio in fattura nasce dagli stessi numeri su cui Cloudflare fattura te. Con i prefissi il registro lo tieni tu: salvi la dimensione di ogni oggetto quando lo scrivi e la sottrai quando lo cancelli.

Configurazione per cliente

Regole CORS, regole di lifecycle, notifiche di eventi e fino a 100 domini personalizzati si impostano sul bucket. Un cliente che serve i file dal proprio dominio, o che vuole un periodo di conservazione diverso da tutti gli altri, si gestisce meglio con un bucket suo.

Una cancellazione dimostrabile

L'uscita di un cliente costa più o meno uguale nei due modelli, perché R2 elimina solo bucket vuoti. Prima vanno via tutti gli oggetti, con il comando Empty della dashboard, un ciclo da client o una regola di lifecycle che fa scadere tutto dopo un giorno (eliminare un bucket). DeleteObject e DeleteBucket sono gratuite, mentre elencare le chiavi è un'operazione di Classe A da 4,50 $ al milione. La differenza sta nella traccia che resta. «Bucket eliminato in questa data» risponde in una riga a una richiesta di cancellazione. Un prefisso ti lascia un registro di chiavi cancellate.

Come si automatizza la creazione di un bucket R2 alla registrazione?

Quando un cliente ha davvero bisogno di un bucket, la creazione va in un job in background, mai dentro la richiesta di registrazione.

  1. Ricava il nome dall'id del tenant. Per esempio t- seguito dall'UUID del tenant, in minuscolo. Salvalo sulla riga del tenant prima di chiamare Cloudflare, così un nuovo tentativo punta allo stesso nome.
  2. Crealo con l'API compatibile S3. CreateBucket, con un token Admin Read & Write, sull'endpoint della giurisdizione che serve al cliente. Cloudflare applica il tetto di 1.200 richieste alla sua API REST e indica l'API S3 per i volumi alti. Ogni PutBucket si paga come operazione di Classe A.
  3. Applica la configurazione nello stesso job. CORS per le origini dell'app e le regole di lifecycle previste dal piano. Anche queste sono operazioni di Classe A.
  4. Metti i job in coda e limita il ritmo. Una coda a velocità fissa, e su un 429 aspetti i secondi indicati nell'header retry-after prima di riprovare.
  5. Dai l'accesso per sessione. Un solo token padre, da cui emetti credenziali temporanee legate al bucket del cliente. Un token per cliente si scontra con il limite dei 500.
  6. Segna il tenant come pronto. I caricamenti restano disattivati finché il job non ha salvato sulla riga del tenant il nome del bucket e un flag di pronto.

I nomi ricavati dall'id evitano anche una trappola poco visibile. R2 rispetta un Location Hint solo la prima volta che un nome di bucket viene creato: se elimini un bucket e lo ricrei con lo stesso nome, torna nella posizione originale.

Cosa usiamo e perché

Sui prodotti multi-tenant che sviluppiamo, la scelta di partenza è un bucket condiviso per giurisdizione, per esempio tenants-default e tenants-eu, con un prefisso per cliente e la giurisdizione salvata sulla riga del tenant. Il backend firma gli URL prefirmati per caricamenti e download, e al momento del caricamento scrive la dimensione di ogni oggetto in una tabella dei consumi. Il bucket dedicato lo riserviamo ai clienti che vogliono un dominio proprio, una regola di conservazione propria o una cancellazione verificabile, e lo crea il job descritto sopra.

Il compromesso che accettiamo è che l'isolamento sta nel codice. Basta un controllo sul tenant mancante in una route che firma URL per esporre i file di un altro cliente. Per questo ogni firma legge il tenant dalla sessione, mai dal corpo della richiesta, e un test prova a firmare una chiave sotto il prefisso di un altro tenant e si aspetta un rifiuto. La stessa disciplina vale per le righe del database, di cui abbiamo parlato in Supabase RLS in scala; le ragioni per costruire multi-tenant fin dall'inizio sono in Multi-tenant dal primo giorno. Se la scelta di R2 rispetto a S3 o Supabase Storage è ancora aperta, parti dal nostro confronto fra i tre.

Domande frequenti

Preferisci che lo facciamo noi?

Progettiamo e sviluppiamo questo tipo di lavoro per i clienti. Raccontaci di cosa hai bisogno.