Regningen fra Amazon S3 pleier å komme som en overraskelse først når trafikken tar av. Hver gigabyte som forlater bøtta koster penger, og for et nordisk mediehus, en indie-utvikler eller en bedrift som serverer bilder og video til brukere i hele Norden, spiser egress-avgiften raskt opp marginene. Cloudflare R2 løser akkurat det problemet: lagringen er S3-kompatibel, men du betaler aldri for datatrafikk ut til internett. I denne guiden setter vi opp R2 fra bunnen, kobler det til en Cloudflare Worker, migrerer eksisterende S3-data og bygger et komplett bilde-opplastingsprosjekt du kan sette i produksjon samme dag.
Du trenger ingen forkunnskaper om Cloudflares plattform for å følge denne guiden. Vi går gjennom alt fra kontooppsett til overvåking av kostnader, og du ender opp med en fungerende tjeneste, ikke bare teori.
Guiden er delt i tolv konkrete steg, pluss et samlet prosjekt mot slutten som binder alt sammen. Underveis dekker vi også de fallgruvene og feilmeldingene som oftest dukker opp første gang noen flytter en arbeidslast fra S3 til R2, slik at du slipper å finne dem ut selv gjennom prøving og feiling i produksjon.
Hva er Cloudflare R2, og hvorfor bryr nordiske utviklere seg?
Cloudflare R2 er objektlagring bygget på samme infrastruktur som resten av Cloudflares nettverk. Navnet er en spøk med S3: R2, altså “S3 minus én bokstav, minus egress-kostnaden”. Tjenesten eksponerer et S3-kompatibelt API, så eksisterende verktøy som AWS SDK, s3cmd, rclone og Terraform-providere for S3 fungerer stort sett uten endringer, bortsett fra at du peker dem mot en annen endepunkt-URL.
Det som skiller R2 fra S3, Google Cloud Storage og Backblaze B2, er prismodellen. R2 har null kroner i egress-avgift, uansett hvor mye data som lastes ned, og uansett om trafikken går til sluttbrukere eller til andre tjenester. Cloudflare tar betalt for lagringsplass og for operasjoner (skriving, lesing, listing), men aldri for båndbredden ut. For et selskap som serverer produktbilder, video eller nedlastbare filer til et publikum i Norge, Sverige, Danmark og Finland, betyr det at kostnaden holder seg forutsigbar selv når trafikken vokser kraftig i en kampanjeperiode.
Egress-avgifter hos andre skyleverandører henger historisk sammen med at det koster reelle penger å flytte data ut av et datasenter, spesielt når trafikken krysser mellom ulike nettverk. Cloudflare argumenterer for at siden selskapet uansett driver et av verdens største CDN-nettverk med direkte forbindelser (peering) til de fleste internettleverandører, er marginalkostnaden for R2-egress lav nok til at den kan tilbys gratis som en del av den generelle plattformavtalen. Konsekvensen for deg som utvikler er at et prosjekt du regnet ut kostnaden for på papiret, faktisk stemmer med regningen du får uansett hvor mye trafikk tjenesten din tiltrekker seg.
R2 er også tett integrert med Cloudflare Workers, slik at en serverless-funksjon kan lese og skrive direkte til en bøtte uten at data noen gang forlater Cloudflares nettverk internt. Det gjør R2 til et naturlig valg for alt fra statiske nettsteder til bilde-API-er og dataplattformer som må holde seg innenfor et stramt cloud-budsjett.
Prisstrukturen er delt i to operasjonsklasser, hentet direkte fra Cloudflares egen R2-prisdokumentasjon. Class A-operasjoner dekker skrivehandlinger som PutObject, DeleteObject og ListBucket, altså handlinger som endrer eller lister innholdet i bøtta. Class B-operasjoner dekker lesehandlinger som GetObject og HeadObject. Skillet er verdt å huske på gjennom hele denne guiden, siden det er nettopp blandingen av disse to operasjonstypene som avgjør den faktiske regningen din, ikke lagringsvolumet alene.
Slik er R2 bygget: global distribusjon uten regional prising
Der AWS S3 og Google Cloud Storage krever at du velger en spesifikk region for bøtta, og der overføring mellom regioner koster ekstra, kjører R2 på Cloudflares globale anycast-nettverk. Objektene dine blir tilgjengelige fra samme URL uansett hvor i verden forespørselen kommer fra, og Cloudflare håndterer selv hvilken fysisk lokasjon som svarer raskest. For et nordisk publikum betyr det at brukere i Tromsø og Helsingfors får omtrent samme responstid som brukere i Oslo, uten at du selv trenger å sette opp regional replikering.
Denne arkitekturen henger sammen med resten av Cloudflares plattforminvesteringer. I løpet av 2026 har selskapet blant annet økt maksimal CPU-tid per Worker-forespørsel og hevet grensen for hvor store WebSocket-meldinger en Worker kan behandle, ifølge selskapets egen endringslogg. Det er ikke R2-spesifikke endringer i seg selv, men de viser at Cloudflare bygger R2, Workers og resten av edge-plattformen som én sammenhengende stack, ikke som separate produkter som tilfeldigvis deler merkevare.
Forutsetninger: dette trenger du før du starter
Sett av rundt 60 minutter til hele oppsettet, inkludert testing. Du trenger følgende verktøy og tilganger klare før du går videre:
- En Cloudflare-konto (gratisplanen holder for hele denne guiden)
- Node.js 20 LTS eller nyere, samt npm 10 eller nyere, for å kjøre Wrangler-kommandoene
- Wrangler CLI i nyeste versjon, installert via
npm install -g wranglereller kjørt direkte mednpx wrangler - AWS CLI versjon 2, for å teste S3-kompatibiliteten direkte fra terminalen
- En kredittkort-tilknytning på Cloudflare-kontoen dersom du planlegger å gå forbi gratis-grensen (selve oppsettet krever det ikke)
- Grunnleggende kjennskap til kommandolinjen og JSON
Hvis du skal skrive Workers i Python i stedet for JavaScript, er det verdt å vite at Cloudflare i 2026 satte Python 3.14 som standard kjøretid for Python Workers. Denne guiden bruker JavaScript for kodeeksemplene, siden det er det mest brukte oppsettet mot R2 i praksis.
Cloudflare R2 mot AWS S3 og Backblaze B2: hva koster det egentlig?
Før du bygger noe, er det verdt å forstå hvorfor R2 faktisk er billigere for de fleste arbeidslaster med mye nedlasting. Tabellen under viser offentlig prisdata for standardlagring, slik den er publisert av Cloudflare, AWS og Backblaze i 2026.
| Komponent | Cloudflare R2 (Standard) | AWS S3 (Standard) | Backblaze B2 |
|---|---|---|---|
| Lagring per GB/måned | $0,015 | ca. $0,023 | ca. $0,005–0,006 |
| Egress til internett | $0,00 (ingen grense) | ca. $0,09/GB (første 10 TB) | $0,01/GB (gratis egress opp til 3x gjennomsnittlig lagret volum) |
| Class A / skriveoperasjoner | $4,50 per million | ca. $5,00 per million | gratis |
| Class B / leseoperasjoner | $0,36 per million | ca. $0,40 per million | gratis |
| Gratis lagring/måned | 10 GB | 5 GB i 12 måneder | 10 GB |
Legg merke til at Backblaze B2 vinner på ren lagringspris, men R2 vinner totalt så snart nedlastingsvolumet blir stort, fordi egress alltid er gratis. For en tjeneste som serverer mye video eller store nedlastingsfiler til nordiske brukere, er dette ofte den avgjørende faktoren, ikke lagringsprisen alene.
R2 har også en egen Infrequent Access-klasse for data du sjelden henter. Den koster $0,010 per GB i lagring, men $9,00 per million Class A-operasjoner og $0,90 per million Class B-operasjoner, altså dobbelt så mye som Standard-klassen for operasjoner. I tillegg kommer en hentekostnad på rundt $0,01 per GB når du faktisk leser dataen. Infrequent Access lønner seg kun for arkivdata du sjelden rører, ikke for filer brukerne henter jevnlig.
Steg 1: Opprett Cloudflare-konto og aktiver R2
Gå til Cloudflare-dashbordet og opprett en konto hvis du ikke allerede har en. Naviger til R2 i venstremenyen. Første gang du åpner R2-seksjonen ber Cloudflare deg bekrefte at du forstår prismodellen for lagring og operasjoner. Du trenger ikke legge inn betalingskort for å komme i gang med gratisnivået, men du må aktivere R2 eksplisitt på kontoen før bøtter kan opprettes.
Noter deg konto-ID-en din, som vises øverst til høyre i R2-dashbordet eller under “Account Home”. Denne strengen trenger du i nesten alle kommandoer senere, siden R2-endepunktet alltid inneholder konto-ID-en.
Steg 2: Opprett din første R2-bøtte med Wrangler
Du kan opprette bøtter både i dashbordet og via kommandolinjen. Kommandolinjen er raskere å gjenta og enklere å sette i et skript, så vi bruker Wrangler gjennom hele guiden.
npx wrangler login
npx wrangler r2 bucket create minbutikk-bilder --location eu
# Bekreft at bøtta finnes
npx wrangler r2 bucket list
Flagget --location eu er en anbefaling til Cloudflare om hvor de primære kopiene av dataen bør ligge. Det er nyttig når du har krav til datalokasjon i Norden eller EU, selv om selve R2-nettverket er globalt distribuert for lesehastighet.
Steg 3: Generer S3-kompatible API-nøkler
For at eksterne verktøy som AWS CLI skal kunne snakke med R2, må du generere et API-nøkkelpar. Gå til R2 → Manage R2 API Tokens i dashbordet og opprett en ny token med lese- og skrivetilgang, begrenset til den spesifikke bøtta du nettopp opprettet. Cloudflare viser deg da tre verdier: en Access Key ID, en Secret Access Key, og et endepunkt som ser slik ut:
https://KONTO_ID.r2.cloudflarestorage.com
Skriv ned alle tre verdiene med det samme. Secret Access Key vises kun én gang, og hvis du mister den må du generere en ny nøkkel fra bunnen.
Steg 4: Konfigurer AWS CLI til å snakke med R2
Siden R2 er S3-kompatibelt, kan du bruke standard AWS CLI ved å legge til en egen profil og peke den mot Cloudflares endepunkt i stedet for Amazons.
aws configure set aws_access_key_id DIN_ACCESS_KEY_ID --profile r2
aws configure set aws_secret_access_key DIN_SECRET_KEY --profile r2
aws configure set region auto --profile r2
# Test tilkoblingen
aws s3 ls --profile r2 --endpoint-url https://KONTO_ID.r2.cloudflarestorage.com
Forventet output er en tom liste eller navnet på bøtta du opprettet i steg 2, uten feilmeldinger:
2026-09-10 09:12:03 minbutikk-bilder
Får du i stedet SignatureDoesNotMatch, dobbeltsjekk at du ikke har mellomrom eller linjeskift i nøklene, og at regionen står som auto, ikke en faktisk AWS-region.
Steg 5: Last opp og hent objekter via S3-API-et
Med profilen på plass kan du bruke akkurat de samme kommandoene som mot ekte S3.
aws s3 cp ./produkt-1.jpg s3://minbutikk-bilder/produkter/produkt-1.jpg \
--profile r2 --endpoint-url https://KONTO_ID.r2.cloudflarestorage.com
aws s3 cp s3://minbutikk-bilder/produkter/produkt-1.jpg ./nedlastet.jpg \
--profile r2 --endpoint-url https://KONTO_ID.r2.cloudflarestorage.com
Legg merke til at hver cp-opplasting telles som én Class A-operasjon, mens nedlasting via cp telles som Class B. Kjører du dette i en løkke mot tusenvis av små filer, er det operasjonskostnaden, ikke lagringen, som vokser raskest.
For store filer, som videoklipp eller ZIP-arkiver, bør du la AWS CLI håndtere multipart-opplasting automatisk i stedet for å sende hele filen i ett kall. AWS CLI gjør dette selv når filstørrelsen passerer en intern terskel, men du kan justere oppførselen eksplisitt:
aws configure set default.s3.multipart_threshold 64MB --profile r2
aws configure set default.s3.multipart_chunksize 16MB --profile r2
aws s3 cp ./produktvideo.mp4 s3://minbutikk-bilder/video/produktvideo.mp4 \
--profile r2 --endpoint-url https://KONTO_ID.r2.cloudflarestorage.com
Hver del i en multipart-opplasting telles som en egen Class A-operasjon, så en fil delt i 20 biter genererer 20 skriveoperasjoner pluss selve fullføringskallet. For de fleste bruksområder er det fortsatt langt billigere enn å la en opplasting time ut og måtte startes på nytt fra begynnelsen.
Steg 6: Koble en R2-bøtte direkte til en Cloudflare Worker
Den virkelige styrken til R2 kommer når en Worker leser og skriver til bøtta uten å gå via det offentlige S3-API-et i det hele tatt. Da bruker du en binding i stedet for nøkler. Opprett et nytt Worker-prosjekt og legg til bindingen i wrangler.toml:
name = "bilde-api"
main = "src/index.js"
compatibility_date = "2026-09-01"
[[r2_buckets]]
binding = "BILDER"
bucket_name = "minbutikk-bilder"
Selve Worker-koden får nå tilgang til bøtta gjennom env.BILDER, uten Access Key eller Secret i det hele tatt. Det er både enklere og tryggere enn å håndtere S3-nøkler i produksjonskode.
export default {
async fetch(request, env) {
const url = new URL(request.url);
const key = url.pathname.slice(1);
if (request.method === "PUT") {
await env.BILDER.put(key, request.body);
return new Response(`Lastet opp: ${key}`, { status: 201 });
}
if (request.method === "GET") {
const object = await env.BILDER.get(key);
if (!object) return new Response("Fant ikke filen", { status: 404 });
const headers = new Headers();
object.writeHttpMetadata(headers);
headers.set("etag", object.httpEtag);
return new Response(object.body, { headers });
}
return new Response("Metode ikke støttet", { status: 405 });
},
};
Deploy med npx wrangler deploy, og test med en enkel PUT-forespørsel:
curl -X PUT https://bilde-api.din-konto.workers.dev/test.txt --data "hallo r2"
curl https://bilde-api.din-konto.workers.dev/test.txt
Andre kommando skal returnere hallo r2 direkte i terminalen. Fungerer ikke dette, sjekk at bucket-navnet i wrangler.toml er stavet nøyaktig som i steg 2, inkludert store og små bokstaver.
Steg 7: Sett opp offentlig tilgang med egendefinert domene
Som standard er en R2-bøtte privat. Skal filene være tilgjengelige direkte i nettleseren uten å gå via en Worker, må du enten aktivere den midlertidige r2.dev-adressen (kun til testing, ikke produksjon) eller koble bøtta til et eget underdomene du eier gjennom Cloudflare.
- Gå til bøtta → Settings → Public access
- Velg Connect Domain og oppgi et underdomene, for eksempel
bilder.dinbutikk.no - Cloudflare oppretter automatisk riktig DNS-oppføring hvis domenet allerede ligger i samme konto
Etter noen minutter kan du åpne https://bilder.dinbutikk.no/produkter/produkt-1.jpg direkte i nettleseren. Trafikken går gjennom Cloudflares CDN, så du får caching og DDoS-beskyttelse på kjøpet, uten ekstra konfigurasjon.
Steg 8: Konfigurer CORS for opplasting direkte fra nettleseren
Skal brukere laste opp filer direkte fra en nettside, uten at filen går innom serveren din først, må bøtta ha en CORS-policy. Uten dette vil nettleseren blokkere opplastingen med en generisk feilmelding i konsollen.
[
{
"AllowedOrigins": ["https://dinbutikk.no"],
"AllowedMethods": ["GET", "PUT", "POST"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3600
}
]
Last opp policyen med AWS CLI mot samme endepunkt som før:
aws s3api put-bucket-cors --bucket minbutikk-bilder \
--cors-configuration file://cors.json \
--profile r2 --endpoint-url https://KONTO_ID.r2.cloudflarestorage.com
Steg 9: Bruk lifecycle-regler og Infrequent Access riktig
R2 støtter lifecycle-regler som automatisk flytter eller sletter objekter etter en gitt alder, akkurat som S3. Dette er stedet der mange lar lagringskostnaden vokse unødvendig, fordi gamle opplastinger, midlertidige filer og testdata aldri ryddes bort.
npx wrangler r2 bucket lifecycle add minbutikk-bilder \
--prefix "midlertidig/" \
--expire-days 7
Vurder Infrequent Access kun for data du er sikker på ikke hentes ofte, som gamle sikkerhetskopier. For alt annet, la Standard-klassen stå som default, siden ekstrakostnaden per operasjon på Infrequent Access lett spiser opp besparelsen på lagring hvis filene faktisk blir hentet med jevne mellomrom.
Steg 10: Migrer eksisterende data fra AWS S3 med Super Slurper
Har du allerede en produksjonsbøtte i AWS S3, tilbyr Cloudflare et eget migreringsverktøy, internt kalt Super Slurper, som kopierer objekter i bulk fra en S3-kompatibel kilde til R2 uten at du må skrive egne skript. Verktøyet ligger under R2 → Data Migration i dashbordet, og du oppgir kilde-bøtte, IAM-nøkler med lesetilgang til S3-bøtta, og målbøtten i R2. Migreringen kjører i bakgrunnen og bevarer mappestrukturen fra kildekontoen.
For store datasett anbefales det å kjøre migreringen i en periode med lavere trafikk, og å verifisere objektantall og totalstørrelse i begge bøtter etterpå, ikke bare stole på at jobben rapporterte suksess. Cloudflare beskriver selve verktøyet og forutsetningene i detalj i dokumentasjonen for datamigrering, inkludert hvilke S3-kompatible leverandører som støttes som kilde utover AWS S3 selv.
Steg 11: Sett opp hendelsesvarsling for nye objekter
R2 kan sende en hendelse til en Cloudflare Queue hver gang et objekt opprettes, oppdateres eller slettes i en bøtte. Dette er nyttig når du vil trigge bildeprosessering, virussjekk eller indeksering automatisk, uten å polle bøtta manuelt.
npx wrangler r2 bucket notification create minbutikk-bilder \
--event-type object-create \
--queue bilde-prosessering-ko
Deretter kan en separat Worker konsumere køen og for eksempel generere en miniatyrbilde-versjon av hver ny opplasting, uten at brukeren som lastet opp filen må vente på at prosesseringen er ferdig.
Steg 12: Overvåk bruk og sett opp kostnadskontroll
Siste steg er å unngå overraskelser på fakturaen. Under R2 → Metrics ser du lagringsvolum og antall Class A- og Class B-operasjoner brutt ned per bøtte og per dag. Sett en kalenderpåminnelse om å sjekke dette den første uken etter lansering, siden det er da du oppdager om noe i koden gjør unødvendig mange små forespørsler, for eksempel en Worker som lister hele bøtteinnholdet ved hver forespørsel i stedet for å slå opp én nøkkel om gangen.
Cloudflare tilbyr også fakturavarsler på kontonivå som kan settes til å sende e-post når forbruket krysser en terskel du selv definerer under Billing → Notifications. Sett terskelen lavt i starten, gjerne på et beløp som er langt under det du faktisk forventer å bruke, slik at et varsel utløses tidlig nok til at du rekker å undersøke årsaken før kostnaden får vokse seg stor. Det er langt bedre å få tre unødvendige varsler den første måneden enn å oppdage et kostbart mønster først når fakturaen kommer.
Komplett prosjekt: en fungerende bilde-opplastingstjeneste
Sett sammen blir stegene over til et fullverdig prosjekt: en Worker som tar imot opplastinger, lagrer dem i R2, og serverer dem tilbake via et eget domene, med en enkel API-nøkkel som beskyttelse mot uautoriserte opplastinger.
export default {
async fetch(request, env) {
const url = new URL(request.url);
const key = url.pathname.slice(1);
if (request.method === "PUT") {
const auth = request.headers.get("X-Api-Key");
if (auth !== env.UPLOAD_KEY) {
return new Response("Ugyldig API-nokkel", { status: 401 });
}
await env.BILDER.put(key, request.body, {
httpMetadata: { contentType: request.headers.get("content-type") || "application/octet-stream" },
});
return new Response(JSON.stringify({ status: "lagret", key }), {
status: 201,
headers: { "content-type": "application/json" },
});
}
if (request.method === "GET") {
const object = await env.BILDER.get(key);
if (!object) return new Response("Fant ikke filen", { status: 404 });
const headers = new Headers();
object.writeHttpMetadata(headers);
headers.set("cache-control", "public, max-age=86400");
return new Response(object.body, { headers });
}
if (request.method === "DELETE") {
const auth = request.headers.get("X-Api-Key");
if (auth !== env.UPLOAD_KEY) {
return new Response("Ugyldig API-nokkel", { status: 401 });
}
await env.BILDER.delete(key);
return new Response(null, { status: 204 });
}
return new Response("Metode ikke stottet", { status: 405 });
},
};
Lagre UPLOAD_KEY som en Worker-secret, ikke i klartekst i wrangler.toml:
npx wrangler secret put UPLOAD_KEY
npx wrangler deploy
Med dette har du en tjeneste som kan brukes fra en hvilken som helst nettside eller app: PUT for å laste opp, GET for å hente, DELETE for å rydde opp, alt uten en tradisjonell backend-server og uten egress-kostnad når filene serveres til brukerne.
Mål responstid mot R2 fra en nordisk tilkobling
Før du stoler på oppsettet i produksjon, er det verdt å måle faktisk responstid fra der brukerne dine sitter. Cloudflares anycast-nettverk gjør at du normalt treffer et nærliggende utleveringspunkt automatisk, men det er likevel lurt å verifisere med tall i stedet for å anta. Bruk curl sin innebygde timing-funksjon:
curl -o /dev/null -s -w "DNS: %{time_namelookup}s Tilkobling: %{time_connect}s Total: %{time_total}s\n" \
https://bilder.dinbutikk.no/produkter/produkt-1.jpg
Kjør kommandoen flere ganger fra ulike nettverk, gjerne både fra en hjemme-tilkobling og fra en mobil-tilkobling, siden svartiden kan variere avhengig av hvilken internettleverandør som ruter trafikken. Et typisk resultat for statiske filer via R2 og Cloudflares CDN bør ligge på under 100 millisekunder i total-tid for en bruker i Norden, forutsatt at filen allerede er bufret nær kanten. Første forespørsel etter en cache-tømming vil naturlig nok ta lengre tid, siden Cloudflare da må hente objektet fra selve R2-lagringslaget før det kan bufres videre.
Bruk R2 som mål for databasesikkerhetskopier
Utover bilder og statiske filer er R2 også et naturlig mål for automatiserte databasebackup-er, nettopp fordi du slipper å bekymre deg for egress-kostnad når backupen senere må lastes ned for gjenoppretting. Et enkelt cronjob-mønster for en PostgreSQL- eller MySQL-database kan se slik ut:
#!/bin/bash
set -e
FILNAVN="backup-$(date +%Y%m%d-%H%M).sql.gz"
pg_dump minbutikk_db | gzip > "/tmp/$FILNAVN"
aws s3 cp "/tmp/$FILNAVN" "s3://minbutikk-backup/postgres/$FILNAVN" \
--profile r2 --endpoint-url https://KONTO_ID.r2.cloudflarestorage.com
rm "/tmp/$FILNAVN"
Kombiner dette med en egen lifecycle-regel som sletter backup-filer eldre enn for eksempel 30 dager, slik du satte opp i steg 9, så vokser ikke lagringskostnaden ukontrollert bare fordi cronjobben kjører hver natt. Legg gjerne backup-bøtta i en egen konto eller med en egen API-token med begrenset omfang, slik at en kompromittert nøkkel andre steder i systemet ikke automatisk gir tilgang til sikkerhetskopiene dine også.
Vanlige fallgruver du bør unngå
De fleste problemene med R2 kommer ikke fra selve tjenesten, men fra vaner overført direkte fra S3 uten justering. Siden API-et er så likt, er det fristende å kopiere inn eksisterende S3-kode uendret, men noen av forutsetningene som gjaldt i det gamle oppsettet stemmer ikke lenger når prismodellen og infrastrukturen er annerledes under panseret.
- Å glemme å aktivere offentlig tilgang før du kobler på et egendefinert domene, som gir en forvirrende 401- eller 403-feil selv om DNS ser riktig ut.
- Å bruke Infrequent Access på data som faktisk hentes ofte, slik at operasjonskostnaden blir dobbelt så høy som nødvendig.
- Å liste hele bøtteinnholdet i en løkke i stedet for å slå opp enkeltnøkler, noe som driver Class A- og Class B-kostnaden opp uten at lagringsvolumet endrer seg.
- Å legge nøklene i klartekst i wrangler.toml eller i frontend-kode i stedet for å bruke bindings og Worker-secrets.
- Å anta at hele S3-API-overflaten er identisk. R2 dekker de vanligste operasjonene, men enkelte avanserte S3-funksjoner må testes eksplisitt før du stoler på dem i produksjon.
- Å ikke sette opp lifecycle-regler for midlertidige filer, slik at lagringskostnaden vokser stille i bakgrunnen måned etter måned.
Feilsøking: de vanligste feilmeldingene og løsningen
| Feilmelding / symptom | Sannsynlig årsak | Løsning |
|---|---|---|
| SignatureDoesNotMatch | Feil Secret Access Key eller ekstra mellomrom i nøkkelen | Generer en ny API-token og lim inn nøklene uten formatering |
| 403 Forbidden ved GET fra nettleser | Bøtta har ikke offentlig tilgang aktivert | Aktiver Public Access eller server filen via en Worker-binding |
| CORS-feil i konsollen ved opplasting | Manglende eller feil CORS-policy på bøtta | Last opp korrekt cors.json med put-bucket-cors |
| Bucket-navnet er allerede i bruk | Bøttenavn er globalt unike innenfor kontoen | Velg et mer spesifikt navn, for eksempel med prefiks for miljø |
| NoSuchBucket ved API-kall | Feil skrevet bucket-navn i koden eller wrangler.toml | Sjekk stavemåte og store/små bokstaver mot wrangler r2 bucket list |
| Uventet høy regning på Class A-operasjoner | Kode som lister eller skriver i løkke unødvendig ofte | Bytt til enkeltoppslag med get/put på spesifikk nøkkel |
| Worker returnerer 500 ved binding-tilgang | Feil navn på binding i koden kontra wrangler.toml | Match env.NAVN nøyaktig med binding-feltet i konfigurasjonen |
| Opplasting av store filer henger eller feiler | Manglende multipart-håndtering i klientkoden | Bruk AWS SDK sin innebygde multipart-opplasting i stedet for én enkelt PUT |
Et generelt triks som løser overraskende mange av feilene i tabellen over, er å legge til --debug på AWS CLI-kommandoen du feilsøker, slik at du ser hele HTTP-forespørselen og -responsen mot R2-endepunktet. Da ser du ofte umiddelbart om problemet ligger i selve signeringen, i en feil URL, eller i en tilgangsrettighet som mangler på API-tokenet. Sammenlign gjerne output fra en fungerende kommando mot en feilende kommando side om side, siden det som regel er en liten, konkret forskjell i header eller region-verdi som forårsaker problemet, ikke en dyp konfigurasjonsfeil.
Avanserte tips: R2 SQL og R2 Data Catalog
Når prosjektet vokser forbi enkel fil-lagring, er det verdt å kjenne til Cloudflare Data Platform, som ble lansert under Cloudflares utviklerkonferanse i 2025. Plattformen bygger videre på R2 med to nye komponenter: R2 Data Catalog, en administrert Apache Iceberg-katalog bygget direkte inn i en R2-bøtte, og R2 SQL, en distribuert spørremotor som lar deg kjøre SQL-spørringer direkte mot Iceberg-tabeller lagret i R2, uten å flytte dataen til en separat database først.
For team som logger hendelser, klikkdata eller sensordata til R2, betyr dette at rådataen kan gjøres spørrbar uten et separat data warehouse. Du kan lese mer om selve arkitekturen i Cloudflares egen dypdykk-artikkel om R2 SQL. Det er verdt å presisere at R2 SQL ikke er ment å erstatte en operasjonell database for en applikasjon som trenger raske, hyppige oppdateringer av enkeltrader. Styrken ligger heller i analytiske spørringer mot store, relativt statiske datamengder, altså det motsatte bruksmønsteret av en vanlig Postgres-database som håndterer transaksjoner i sanntid.
Et annet avansert grep er å kombinere R2 med Workers som mellomlagringslag foran en eksisterende Postgres- eller MySQL-database, slik at kun metadata ligger i databasen mens selve filene ligger i R2. Det holder databasen liten og rask, samtidig som filene fortsatt er søkbare gjennom metadata-oppslag.
Bruker teamet ditt allerede infrastruktur-som-kode, kan R2-bøtter og tilhørende CORS-policyer defineres i samme Terraform-oppsett som resten av skyressursene, via Cloudflares offisielle Terraform-provider. Det gjør det enklere å holde bøttenavn, lifecycle-regler og API-tokens versjonskontrollert sammen med resten av arkitekturen, i stedet for å administrere R2 manuelt i dashbordet ved siden av alt annet.
Sikkerhet, datalokasjon og hensyn for norske og nordiske brukere
For virksomheter som håndterer persondata om nordiske brukere, er datalokasjon ofte et krav fra egen personvernpolicy eller fra kunder. Bruk --location eu ved opprettelse av bøtta, slik vist i steg 2, for å signalisere at de primære datakopiene bør holdes innenfor EU/EØS. Kombiner dette med å begrense API-tokens til kun de bøttene og rettighetene som faktisk trengs, i stedet for å dele ut kontovide nøkler til hvert enkelt prosjekt.
Sørg også for at eventuelle offentlige bøtter aldri eksponerer filnavn eller mappestrukturer som i seg selv røper sensitiv informasjon, siden en feilkonfigurert bøtte med forutsigbare filnavn er en klassisk vei til datalekkasje uavhengig av hvilken skyleverandør som brukes. Samme prinsipp gjelder for sikker S3-konfigurasjon og Google Cloud Storage, så kunnskapen er overførbar mellom skyene.
Hvis virksomheten din er underlagt GDPR-krav, er det verdt å lese seg opp på hva regelverket faktisk krever av dokumentert databehandling og databehandleravtaler, slik det er forklart på gdpr.eu. Å velge en lokasjonsinnstilling som holder data innenfor EU/EØS løser kun én del av kravet. Du må fortsatt ha en databehandleravtale med Cloudflare på plass, og du må dokumentere hvilke data som lagres i hvilke bøtter, uavhengig av hvor rask og billig selve lagringsteknologien er.
Kostnadseksempel: hva koster R2 i praksis for et nordisk nettsted?
Tall på et prisark er abstrakte helt til du setter dem inn i et konkret scenario. Sett derfor at en nettbutikk lagrer 50 GB produktbilder, mottar 20 000 opplastinger i måneden (Class A) og serverer 2 millioner bildevisninger i måneden (Class B), i tillegg til at bildene lastes ned totalt 300 GB i måneden av besøkende. Slik ser regnestykket ut på Standard-klassen:
| Post | Forbruk | Enhetspris | Kostnad |
|---|---|---|---|
| Lagring | 50 GB | $0,015/GB | $0,75 |
| Class A-operasjoner | 20 000 | $4,50/million | $0,09 |
| Class B-operasjoner | 2 000 000 | $0,36/million | $0,72 |
| Egress (300 GB) | 300 GB | $0,00 | $0,00 |
| Sum per måned | ca. $1,56 |
Kjører du det samme scenarioet mot AWS S3, ville egress-kostnaden alene på 300 GB landet på rundt $27 med S3s offisielle satser på cirka $0,09 per GB for de første 10 TB, ifølge AWS sin egen prisside, før du i det hele tatt har lagt til lagring og operasjoner. Det er nettopp denne forskjellen, ikke lagringsprisen, som gjør R2 til et opplagt valg for nedlastingstunge tjenester som betjener et nordisk publikum.
Backblaze B2 er fortsatt rimeligere på ren lagring, med satser fra rundt $0,005 til $0,006 per GB per måned ifølge Backblazes offisielle prisoversikt, og med én gratis gigabyte egress per dag. For et arkiv med lite trafikk kan B2 fortsatt være billigst i kroner og øre. Men så snart nedlastingsvolumet passerer noen titalls gigabyte i måneden, snur regnestykket i R2s favør, siden Backblaze begynner å ta betalt per gigabyte utover den daglige gratis-kvoten.
Vil du sammenligne total kostnad for et helt CDN-oppsett, ikke bare lagringen, kan det også være nyttig å se på hvordan Cloudflares nettverk stiller seg mot Google Cloud CDN på antall utleveringspunkter i Norden.
Sett opp en enkel røyktest i CI-pipelinen din
Et prosjekt som avhenger av R2 bør ha en automatisert sjekk som bekrefter at bøtta faktisk er tilgjengelig før hver utrulling, ikke bare at koden kompilerer. En enkel røyktest kan legges rett inn i CI-pipelinen som en av de siste stegene før produksjonsutrulling:
#!/bin/bash
set -e
TESTNOKKEL="ci-helsesjekk/$(date +%s).txt"
echo "R2 fungerer, sjekket $(date -u)" | aws s3 cp - "s3://minbutikk-bilder/$TESTNOKKEL" \
--profile r2 --endpoint-url https://KONTO_ID.r2.cloudflarestorage.com
aws s3 rm "s3://minbutikk-bilder/$TESTNOKKEL" \
--profile r2 --endpoint-url https://KONTO_ID.r2.cloudflarestorage.com
echo "R2-tilkobling verifisert"
Skriptet laster opp en liten test-fil, sletter den umiddelbart, og feiler hele pipelinen dersom noen av kommandoene returnerer en feilkode. Kjør dette som en egen jobb i GitHub Actions, GitLab CI eller tilsvarende, og la bygget stoppe automatisk dersom API-tokenet er utløpt, bøtta har blitt slettet ved en feil, eller kontoen har nådd en midlertidig begrensning. Denne typen billige, raske sjekker fanger opp konfigurasjonsfeil lenge før en bruker opplever dem som en ødelagt bilde-URL i produksjon.
Ofte stilte spørsmål om Cloudflare R2
Er Cloudflare R2 helt gratis å bruke?
Gratisnivået dekker 10 GB lagring, 1 million Class A-operasjoner og 10 millioner Class B-operasjoner per måned. Går du over dette, betaler du kun for det som overstiger grensene, ikke for hele forbruket.
Kan jeg bruke AWS SDK direkte mot R2?
Ja. R2 eksponerer et S3-kompatibelt API, så AWS SDK, AWS CLI og de fleste S3-klienter fungerer ved å bytte endepunkt-URL og sette region til auto.
Betaler jeg for datatrafikk mellom en Worker og R2?
Nei. Trafikk mellom en Cloudflare Worker og en R2-bøtte i samme konto regnes ikke som egress, siden den aldri forlater Cloudflares interne nettverk.
Hvordan migrerer jeg eksisterende data fra AWS S3 til R2?
Bruk Cloudflares innebygde migreringsverktøy under R2 → Data Migration, som kopierer objekter i bulk fra en S3-kompatibel kilde uten at du må skrive egne skript.
Kan jeg koble en R2-bøtte til mitt eget domene?
Ja, under bøttens Settings-fane kan du koble et underdomene du allerede administrerer i samme Cloudflare-konto, slik at filene serveres direkte fra ditt eget domenenavn.
Hva er forskjellen mellom Standard og Infrequent Access?
Standard har lavere kostnad per operasjon og passer for data som hentes jevnlig. Infrequent Access har lavere lagringspris, men dobbelt så høy operasjonskostnad og en egen hentekostnad, og passer kun for sjelden brukt arkivdata.
Støtter R2 SQL-spørringer direkte mot lagrede filer?
Ja, gjennom R2 SQL og R2 Data Catalog kan du registrere data som Apache Iceberg-tabeller og kjøre SQL-spørringer direkte mot dem uten å flytte dataen til en separat database.
Er R2 et godt valg for et lite prosjekt, eller kun for store bedrifter?
R2 passer godt for begge deler. Gratisnivået er romslig nok for de fleste sideprosjekter, og prismodellen skalerer lineært uten overraskende terskler når trafikken vokser.
Kan jeg bruke R2 sammen med Cloudflare Pages for et statisk nettsted?
Ja. R2 fungerer godt som lagringssted for nedlastbare vedlegg, bilder og andre store filer som et Cloudflare Pages-nettsted refererer til, mens selve HTML/CSS/JS-filene fortsatt serveres via Pages sin egen utrullingsmekanisme.
Hva skjer hvis jeg sletter en bøtte ved en feil?
Sletting av en bøtte er permanent og kan ikke angres fra dashbordet. Cloudflare krever at bøtta er tom før den kan slettes, noe som gir deg en ekstra sikkerhetsmargin sammenlignet med et rent enkeltklikk, men du bør likevel alltid ha en egen backup-rutine for data du ikke har råd til å miste.




