Cloudflare R2 ile S3 Uyumlu Nesne Depolama Kullanımı

Bulut depolama maliyetleri son yıllarda ciddi bir sorun haline geldi. AWS S3’ün egress (çıkış bandgenişliği) ücretleri özellikle büyük miktarda veri dışarı çıkarmanız gerektiğinde faturanızı patlatabilir. Cloudflare R2 tam da bu noktada devreye giriyor: sıfır egress ücreti ile S3 uyumlu bir depolama çözümü sunuyor. Eğer S3 API’sine zaten alışkınsanız, R2’ye geçiş düşündüğünüzden çok daha kolay.

Bu yazıda R2’yi sıfırdan kuracağız, AWS CLI ve rclone ile nasıl kullanacağımızı göreceğiz, bucket politikaları ve erişim yönetimini ele alacağız, ardından gerçek dünya senaryolarında nasıl işe yaradığını inceleyeceğiz.

Cloudflare R2 Nedir ve S3’ten Ne Farkı Var?

R2, Cloudflare’in 2022’de genel kullanıma açtığı nesne depolama hizmetidir. S3 API’si ile birebir uyumlu olduğu için mevcut araçlarınızı, kütüphanelerinizi ve iş akışlarınızı büyük ölçüde değiştirmeden kullanabilirsiniz.

Asıl fark ücretlendirme modelinde:

  • Egress ücreti yok: R2’den veri çekerken bant genişliği ücreti ödemezsiniz. Bu, özellikle medya dosyaları, yedekleme arşivleri veya sık erişilen büyük dosyalar için muazzam bir tasarruf demek.
  • Depolama ücreti: Aylık 10 GB ücretsiz, sonrası GB başına 0.015 dolar.
  • İşlem ücreti: Sınıf A işlemleri (yazma) milyonda 4.50 dolar, Sınıf B işlemleri (okuma) milyonda 0.36 dolar. Aylık 1 milyon okuma/yazma ücretsiz.
  • Bölge seçimi yok: R2 otomatik olarak kullanıcıya en yakın konuma veri servis eder. Bucket oluştururken bölge belirtmek zorunda değilsiniz, bu hem kolaylık hem de küresel dağıtım açısından avantajlı.

S3 ile tam uyumlu olmayan birkaç nokta da var: object lock, requester-pays gibi bazı gelişmiş özellikler henüz tam destek almıyor. Ama büyük çoğunluğu için bu bir sorun teşkil etmiyor.

Cloudflare R2 Kurulumu ve API Token Oluşturma

Önce Cloudflare dashboard’una gidin ve R2 Object Storage bölümünü açın. Hesabınızda R2’yi etkinleştirmeniz gerekiyor, bu işlem kredi kartı bilgisi istiyor ama ilk kullanımda ücret çıkmıyor.

Bucket oluşturma:

Dashboard üzerinden “Create bucket” diyerek yeni bir bucket oluşturabilirsiniz. İsim olarak DNS uyumlu, küçük harf ve tire içeren bir isim seçin. Örneğin: myapp-assets-prod.

API Token oluşturma:

R2 API token’ları, Cloudflare’in genel API token sisteminden ayrı bir yerden yönetiliyor. R2 sayfasında sağ üstteki “Manage R2 API Tokens” bağlantısına tıklayın.

Token oluştururken şu izinlere dikkat edin:

  • Admin Read & Write: Tüm bucket’lara tam erişim
  • Object Read & Write: Belirli bucket’lara nesne düzeyinde erişim
  • Object Read only: Salt okuma erişimi

Üretim ortamları için her uygulama veya servis için ayrı token oluşturun ve minimum gerekli izni verin. Token oluşturduktan sonra size şu bilgiler gösterilecek:

  • Access Key ID
  • Secret Access Key
  • Endpoint URL (hesap ID’nize özgü, örn: https://.r2.cloudflarestorage.com)

Bu bilgileri güvenli bir yere kaydedin. Secret Key sadece bir kez gösteriliyor.

AWS CLI ile R2 Kullanımı

AWS CLI, S3 uyumlu herhangi bir endpoint ile çalışabilir. R2 için özel bir endpoint belirtmeniz yeterli.

AWS CLI yapılandırması:

# R2 için özel profil oluştur
aws configure --profile r2

# Sorulacak bilgileri girin:
# AWS Access Key ID: <R2_ACCESS_KEY_ID>
# AWS Secret Access Key: <R2_SECRET_ACCESS_KEY>
# Default region name: auto
# Default output format: json

Sonrasında her komutta --endpoint-url ve --profile parametrelerini kullanmanız gerekiyor:

# Bucket listele
aws s3 ls --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com --profile r2

# Dosya yükle
aws s3 cp ./myfile.tar.gz s3://myapp-assets-prod/ 
  --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com 
  --profile r2

# Dizin senkronize et
aws s3 sync ./dist/ s3://myapp-assets-prod/dist/ 
  --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com 
  --profile r2 
  --delete

# Dosya indir
aws s3 cp s3://myapp-assets-prod/backup.tar.gz ./backup.tar.gz 
  --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com 
  --profile r2

Her seferinde --endpoint-url yazmak zahmetli. Bunu kolaylaştırmak için bir bash alias veya fonksiyon oluşturabilirsiniz:

# ~/.bashrc veya ~/.bash_aliases dosyasına ekle
export R2_ENDPOINT="https://<ACCOUNT_ID>.r2.cloudflarestorage.com"
alias r2="aws s3 --endpoint-url $R2_ENDPOINT --profile r2"
alias r2api="aws s3api --endpoint-url $R2_ENDPOINT --profile r2"

# Artık şöyle kullanabilirsiniz:
# r2 ls
# r2 cp dosya.zip s3://mybucket/
# r2api list-objects-v2 --bucket mybucket

rclone ile R2 Entegrasyonu

rclone, R2 gibi S3 uyumlu sistemlerle çalışırken AWS CLI’den çok daha esnek ve güçlü bir araçtır. Özellikle büyük miktarda veri transferi ve senkronizasyon işlemleri için tercih edin.

rclone R2 yapılandırması:

# Interaktif yapılandırma
rclone config

# Adımlar:
# n) New remote
# name> r2-prod
# Storage> s3 (veya numara ile seçin)
# provider> Cloudflare
# env_auth> false
# access_key_id> <R2_ACCESS_KEY_ID>
# secret_access_key> <R2_SECRET_ACCESS_KEY>
# region> auto
# endpoint> https://<ACCOUNT_ID>.r2.cloudflarestorage.com
# Diğer ayarlar için enter ile geçin

Ya da ~/.config/rclone/rclone.conf dosyasını doğrudan düzenleyin:

[r2-prod]
type = s3
provider = Cloudflare
access_key_id = <R2_ACCESS_KEY_ID>
secret_access_key = <R2_SECRET_ACCESS_KEY>
region = auto
endpoint = https://<ACCOUNT_ID>.r2.cloudflarestorage.com
acl = private

rclone temel komutları:

# Bucket içeriğini listele
rclone ls r2-prod:myapp-assets-prod

# Dizin senkronizasyonu (tek yönlü, silme dahil)
rclone sync ./local-backup/ r2-prod:myapp-backups/ 
  --progress 
  --transfers 20 
  --checkers 40 
  --fast-list

# İki R2 bucket arasında kopyalama
rclone copy r2-prod:source-bucket r2-prod:destination-bucket 
  --progress 
  --transfers 16

# Büyük dosyaları parça parça yükle (multipart upload)
rclone copy ./large-archive.tar.gz r2-prod:myapp-backups/ 
  --s3-chunk-size 64M 
  --s3-upload-concurrency 8 
  --progress

# Uzak bucket'ı mount et (FUSE gerekli)
mkdir -p /mnt/r2-assets
rclone mount r2-prod:myapp-assets-prod /mnt/r2-assets 
  --daemon 
  --vfs-cache-mode writes 
  --vfs-cache-max-size 2G

Bucket Politikaları ve Erişim Yönetimi

R2, S3 benzeri bucket politikalarını destekler. Halka açık okuma erişimi, IP kısıtlamaları veya belirli işlem tiplerini sınırlamak için politika JSON’ları kullanabilirsiniz.

Halka açık okuma politikası:

# bucket-policy.json dosyası oluştur
cat > /tmp/bucket-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::myapp-assets-prod/*"
    }
  ]
}
EOF

# Politikayı uygula
aws s3api put-bucket-policy 
  --bucket myapp-assets-prod 
  --policy file:///tmp/bucket-policy.json 
  --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com 
  --profile r2

Belirli prefix’e kısıtlı yazma politikası:

cat > /tmp/restricted-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowReadAll",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::myapp-assets-prod/public/*"
    },
    {
      "Sid": "DenyDeleteAll",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:DeleteObject",
      "Resource": "arn:aws:s3:::myapp-assets-prod/*"
    }
  ]
}
EOF

R2’nin Custom Domain özelliği de son derece işlevsel. Bucket’ınıza kendi alan adınızı bağlayabilir ve Cloudflare CDN üzerinden servis edebilirsiniz. Dashboard’da R2 > bucket adınız > Settings > Custom Domains bölümünden bu ayarı yapabilirsiniz. Alan adınız Cloudflare’de yönetiliyorsa bu işlem birkaç tıkla tamamlanıyor.

Gerçek Dünya Senaryosu 1: Uygulama Yedeklemelerini R2’ye Taşıma

Bir PostgreSQL veritabanı yedekleme scripti düşünün. Şu anda yedekleri yerel diske yazıyor ve belki bir S3 bucket’ına gönderiyorsunuz. Bunu R2’ye taşımak için şöyle bir script yazabilirsiniz:

#!/bin/bash
# /usr/local/bin/backup-to-r2.sh

set -euo pipefail

# Değişkenler
DB_NAME="myapp_production"
DB_USER="postgres"
BACKUP_DIR="/tmp/pg_backups"
R2_BUCKET="myapp-db-backups"
R2_ENDPOINT="https://<ACCOUNT_ID>.r2.cloudflarestorage.com"
RETENTION_DAYS=30
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.sql.gz"

# Gerekli dizini oluştur
mkdir -p "$BACKUP_DIR"

echo "[$(date)] Yedekleme başlıyor: $DB_NAME"

# PostgreSQL dump al ve sıkıştır
pg_dump -U "$DB_USER" "$DB_NAME" | gzip -9 > "$BACKUP_FILE"

BACKUP_SIZE=$(du -sh "$BACKUP_FILE" | cut -f1)
echo "[$(date)] Yedekleme tamamlandı: $BACKUP_FILE ($BACKUP_SIZE)"

# R2'ye yükle
aws s3 cp "$BACKUP_FILE" 
  "s3://${R2_BUCKET}/daily/${DATE:0:8}/${DB_NAME}_${DATE}.sql.gz" 
  --endpoint-url "$R2_ENDPOINT" 
  --profile r2 
  --metadata "db-name=${DB_NAME},backup-date=${DATE}"

echo "[$(date)] R2'ye yüklendi"

# Yerel geçici dosyayı sil
rm -f "$BACKUP_FILE"

# R2'deki eski yedekleri temizle (30 günden eski)
CUTOFF_DATE=$(date -d "$RETENTION_DAYS days ago" +%Y%m%d)
echo "[$(date)] $CUTOFF_DATE öncesi yedekler temizleniyor..."

aws s3 ls "s3://${R2_BUCKET}/daily/" 
  --endpoint-url "$R2_ENDPOINT" 
  --profile r2 | 
  awk '{print $2}' | 
  grep -E '^[0-9]{8}/$' | 
  sed 's|/$||' | 
  while read dir_date; do
    if [[ "$dir_date" < "$CUTOFF_DATE" ]]; then
      echo "[$(date)] Siliniyor: daily/$dir_date/"
      aws s3 rm "s3://${R2_BUCKET}/daily/${dir_date}/" 
        --recursive 
        --endpoint-url "$R2_ENDPOINT" 
        --profile r2
    fi
  done

echo "[$(date)] Yedekleme süreci tamamlandı"

Bu scripti crontab’a ekleyin:

# Her gece 02:00'de çalıştır
0 2 * * * /usr/local/bin/backup-to-r2.sh >> /var/log/r2-backup.log 2>&1

Gerçek Dünya Senaryosu 2: Statik Site Varlıklarını R2’den Servis Etme

Bir web uygulamasının build çıktısını R2’ye deploy edip Cloudflare CDN üzerinden servis etmek son derece yaygın bir kullanım senaryosu. CI/CD pipeline’ınıza şöyle bir adım ekleyebilirsiniz:

#!/bin/bash
# deploy-assets.sh - CI/CD pipeline için

set -euo pipefail

BUILD_DIR="./dist"
R2_BUCKET="myapp-assets-prod"
R2_ENDPOINT="https://<ACCOUNT_ID>.r2.cloudflarestorage.com"
DEPLOY_ENV="${DEPLOY_ENV:-staging}"

echo "=== $DEPLOY_ENV ortamına deploy başlıyor ==="

# Build klasörünün var olduğunu kontrol et
if [[ ! -d "$BUILD_DIR" ]]; then
  echo "HATA: Build dizini bulunamadı: $BUILD_DIR"
  exit 1
fi

# Cache-Control başlıklarıyla birlikte yükle
# HTML dosyaları için kısa cache süresi
aws s3 sync "$BUILD_DIR" "s3://${R2_BUCKET}/" 
  --endpoint-url "$R2_ENDPOINT" 
  --profile r2 
  --delete 
  --exclude "*.html" 
  --cache-control "public, max-age=31536000, immutable"

# HTML dosyaları için cache'siz
aws s3 sync "$BUILD_DIR" "s3://${R2_BUCKET}/" 
  --endpoint-url "$R2_ENDPOINT" 
  --profile r2 
  --exclude "*" 
  --include "*.html" 
  --cache-control "no-cache, no-store, must-revalidate"

echo "=== Deploy tamamlandı ==="

# Toplam boyutu raporla
TOTAL_OBJECTS=$(aws s3 ls "s3://${R2_BUCKET}/" 
  --endpoint-url "$R2_ENDPOINT" 
  --profile r2 
  --recursive 
  --summarize | grep "Total Objects" | awk '{print $3}')

echo "Toplam nesne sayısı: $TOTAL_OBJECTS"

Python SDK ile R2 Kullanımı

Uygulama kodunuzdan R2’ye bağlanmak için boto3 kütüphanesi ideal. S3 ile aynı kod, sadece endpoint ve credentials değişiyor:

import boto3
from botocore.config import Config

# R2 client oluştur
r2_client = boto3.client(
    's3',
    endpoint_url='https://<ACCOUNT_ID>.r2.cloudflarestorage.com',
    aws_access_key_id='<R2_ACCESS_KEY_ID>',
    aws_secret_access_key='<R2_SECRET_ACCESS_KEY>',
    config=Config(
        signature_version='s3v4',
        retries={'max_attempts': 3, 'mode': 'adaptive'}
    ),
    region_name='auto'
)

# Presigned URL oluştur (geçici indirme linki)
presigned_url = r2_client.generate_presigned_url(
    'get_object',
    Params={
        'Bucket': 'myapp-assets-prod',
        'Key': 'reports/monthly-report-2024-01.pdf'
    },
    ExpiresIn=3600  # 1 saat geçerli
)

print(f"İndirme linki: {presigned_url}")

# Dosya yükle
def upload_file(local_path: str, bucket: str, key: str, content_type: str = None):
    extra_args = {}
    if content_type:
        extra_args['ContentType'] = content_type
    
    r2_client.upload_file(
        local_path,
        bucket,
        key,
        ExtraArgs=extra_args
    )
    print(f"Yüklendi: {key}")

# Örnek kullanım
upload_file(
    './exports/data-export.csv',
    'myapp-assets-prod',
    'exports/data-export-2024.csv',
    'text/csv'
)

R2’ye Geçişte Dikkat Edilecek Noktalar

Endpoint URL yönetimi: R2 endpoint URL’si hesabınıza özgüdür ve değişmez. Bunu ortam değişkeni olarak tutun, kod içine gömmekten kaçının.

Çok parçalı yükleme sınırları: R2, S3 ile aynı multipart upload limitlerini destekler. 5 GB üzeri dosyalar için multipart upload zorunludur. rclone bunu otomatik hallediyor ama kendi kodunuzu yazıyorsanız buna dikkat edin.

Geçiş stratejisi: S3’ten R2’ye büyük veri taşırken şu yaklaşımı izleyin:

  • Önce rclone ile mevcut S3 bucket’ını R2’ye kopyalayın
  • Uygulamanızı R2 endpoint’ini kullanacak şekilde güncelleyin
  • Bir süre her iki bucket’a da yazın (dual-write)
  • S3 bucket’ını okuma yükü kalmayınca kaldırın

CORS yapılandırması: Tarayıcıdan doğrudan R2’ye yükleme yapacaksanız CORS ayarlarını yapmayı unutmayın. Dashboard üzerinden ya da AWS CLI aracılığıyla yapabilirsiniz:

cat > /tmp/cors.json << 'EOF'
{
  "CORSRules": [
    {
      "AllowedOrigins": ["https://myapp.com", "https://www.myapp.com"],
      "AllowedMethods": ["GET", "PUT", "POST"],
      "AllowedHeaders": ["*"],
      "MaxAgeSeconds": 3000
    }
  ]
}
EOF

aws s3api put-bucket-cors 
  --bucket myapp-assets-prod 
  --cors-configuration file:///tmp/cors.json 
  --endpoint-url https://<ACCOUNT_ID>.r2.cloudflarestorage.com 
  --profile r2

Monitoring ve log: R2, Cloudflare dashboard üzerinden temel metrikler sunuyor. Daha detaylı log için R2’nin event notification özelliğini kullanabilir veya uygulama seviyesinde kendi loglama mekanizmanızı kurabilirsiniz. Cloudflare Workers ile R2 event’larını yakalamak da mümkün.

Terraform ile R2 yönetimi: Altyapınızı kod olarak yönetiyorsanız Cloudflare Terraform provider’ı R2 bucket’larını destekliyor. cloudflare_r2_bucket kaynağını kullanarak bucket’larınızı, politikalarınızı ve CORS ayarlarınızı kodla yönetebilirsiniz.

Sonuç

Cloudflare R2, özellikle egress maliyetinin sorun olduğu durumlarda S3’e ciddi bir alternatif sunuyor. Sıfır egress ücreti, S3 API uyumluluğu ve Cloudflare’in global ağıyla entegrasyon bir arada düşününce özellikle medya depolama, yedekleme arşivleri, statik site varlıkları ve kullanıcıya sık sık büyük dosya sunan uygulamalar için son derece cazip bir seçenek.

Geçiş süreci de sanıldığı kadar karmaşık değil. AWS CLI, rclone veya boto3 gibi zaten kullandığınız araçlar minimum konfigürasyon değişikliğiyle R2 ile çalışıyor. Küçük bir pilot bucket ile başlayın, maliyetlerinizi karşılaştırın ve uygun gördüğünüz iş yüklerini aşamalı olarak taşıyın. Büyük hacimli ve sık erişilen veriler için hesaplayacağınız maliyet farkı sizi şaşırtabilir.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir