Cloudflare R2 ile S3 Uyumlu Nesne Depolama Kurulumu ve Yönetimi

Bulut depolama dünyasında AWS S3 uzun yıllar boyunca tartışmasız lider konumundaydı. Ancak Cloudflare’in R2 servisini duyurmasıyla birlikte oyun ciddi anlamda değişti. Özellikle çıkış ücreti (egress fee) sıfır politikası, sistem yöneticilerinin ve geliştiricilerin dikkatini hemen çekti. Bu yazıda R2’yi detaylıca inceleyeceğiz, S3 uyumluluğunu nasıl kullanabileceğimizi göreceğiz ve gerçek dünya senaryolarıyla uygulamalı örnekler üzerinde duracağız.

Cloudflare R2 Nedir ve Neden Önemlidir?

Cloudflare R2, Amazon S3 API’siyle tam uyumlu bir nesne depolama servisidir. Adını Ribonucleic acid-2’den değil, S3’teki “S3” ifadesinden esinlenerek koymuşlar; S3’teki “3” yerine bir önceki asal sayı olan “2” kullanılmış. Bu isimlendirme biraz eğlenceli olsa da servisin sunduğu avantajlar gerçekten ciddi.

En büyük fark şu: AWS S3’te verilerinizi depolamak ucuzdur ama o verileri dışarı çekmek çok pahalıya gelir. Egress ücreti olarak bilinen bu maliyet, büyük ölçekli sistemlerde bütçeleri ciddi şekilde etkileyebilir. R2 ise egress ücreti almıyor. Yani verilerinizi ne kadar indirirseniz indirin, sadece depolama için ödeme yapıyorsunuz.

Ücretsiz katmanda aylık 10 GB depolama, 1 milyon Class-A işlemi (yazma) ve 10 milyon Class-B işlemi (okuma) sunuluyor. Bu rakamlar küçük ve orta ölçekli projeler için oldukça cömert.

R2 Bucket Oluşturma ve Temel Yapılandırma

İlk adım olarak Cloudflare Dashboard üzerinden bucket oluşturmanız gerekiyor. Ancak biz işleri CLI üzerinden yönetmeyi tercih ederiz. Cloudflare’in wrangler aracını kullanabilir ya da doğrudan AWS CLI’ı R2 endpoint ile yapılandırabilirsiniz.

Wrangler ile Kurulum

# Wrangler CLI kurulumu
npm install -g wrangler

# Cloudflare hesabınıza giriş yapın
wrangler login

# Yeni bucket oluşturun
wrangler r2 bucket create my-production-bucket

# Mevcut bucket'ları listeleyin
wrangler r2 bucket list

# Bucket silme (dikkatli olun!)
wrangler r2 bucket delete old-test-bucket

AWS CLI ile R2 Kullanımı

R2’nin en güçlü yanlarından biri S3 API uyumluluğu. Mevcut AWS CLI kurulumunuzu R2 için kullanabilirsiniz. Bunun için önce bir API token oluşturmanız gerekiyor. Cloudflare Dashboard’da “R2” > “Manage R2 API Tokens” bölümünden token alın.

# AWS CLI için R2 profili oluşturma
aws configure --profile cloudflare-r2

# Sorulduğunda şunları 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

# Alternatif olarak credentials dosyasını manuel düzenleyin
cat >> ~/.aws/credentials << 'EOF'
[cloudflare-r2]
aws_access_key_id = YOUR_R2_ACCESS_KEY_ID
aws_secret_access_key = YOUR_R2_SECRET_ACCESS_KEY
EOF

# Config dosyasına endpoint ekleyin
cat >> ~/.aws/config << 'EOF'
[profile cloudflare-r2]
region = auto
EOF

Artık AWS CLI komutlarını R2 ile kullanabilirsiniz:

# R2 endpoint URL'nizi tanımlayın (ACCOUNT_ID Cloudflare dashboard'dan alınır)
R2_ENDPOINT="https://ACCOUNT_ID.r2.cloudflarestorage.com"

# Bucket listeleme
aws s3 ls --endpoint-url $R2_ENDPOINT --profile cloudflare-r2

# Dosya yükleme
aws s3 cp local-file.tar.gz s3://my-production-bucket/ 
  --endpoint-url $R2_ENDPOINT 
  --profile cloudflare-r2

# Dosya indirme
aws s3 cp s3://my-production-bucket/local-file.tar.gz ./restored-file.tar.gz 
  --endpoint-url $R2_ENDPOINT 
  --profile cloudflare-r2

# Bucket içeriğini listeleme
aws s3 ls s3://my-production-bucket/ 
  --endpoint-url $R2_ENDPOINT 
  --profile cloudflare-r2

# Recursive listeleme
aws s3 ls s3://my-production-bucket/ 
  --endpoint-url $R2_ENDPOINT 
  --profile cloudflare-r2 
  --recursive 
  --human-readable

Gerçek Dünya Senaryosu 1: Yedekleme Sistemi

En klasik kullanım senaryolarından biri sunucu yedeklerini R2’ye atmak. PostgreSQL veritabanı yedeği alan ve R2’ye yükleyen bir script yazalım.

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

set -euo pipefail

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

# Log fonksiyonu
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# Yedekleme dizinini oluştur
mkdir -p "$BACKUP_DIR"

log "PostgreSQL yedeği alınıyor: $DB_NAME"
pg_dump -U "$DB_USER" "$DB_NAME" | gzip > "$BACKUP_FILE"

log "Yedek boyutu: $(du -sh $BACKUP_FILE | cut -f1)"

log "R2'ye yükleniyor..."
aws s3 cp "$BACKUP_FILE" 
    "s3://${R2_BUCKET}/postgres/${DATE:0:6}/" 
    --endpoint-url "$R2_ENDPOINT" 
    --profile cloudflare-r2 
    --storage-class STANDARD

log "Yükleme tamamlandı"

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

# R2'de eski yedekleri temizle (30 günden eski)
log "Eski yedekler temizleniyor..."
CUTOFF_DATE=$(date -d "$RETENTION_DAYS days ago" +%Y%m%d)

aws s3 ls "s3://${R2_BUCKET}/postgres/" 
    --endpoint-url "$R2_ENDPOINT" 
    --profile cloudflare-r2 
    --recursive | awk '{print $4}' | while read -r key; do
    FILE_DATE=$(basename "$key" | grep -oP '^d{8}' || echo "00000000")
    if [[ "$FILE_DATE" < "$CUTOFF_DATE" ]]; then
        log "Siliniyor: $key"
        aws s3 rm "s3://${R2_BUCKET}/$key" 
            --endpoint-url "$R2_ENDPOINT" 
            --profile cloudflare-r2
    fi
done

log "Yedekleme işlemi başarıyla tamamlandı"

Bu scripti cron’a ekleyin:

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

Custom Domain ile R2 Bucket Yayınlama

R2’nin DNS ile entegrasyonu gerçekten etkileyici. Cloudflare üzerinde yönettiğiniz bir domain varsa, bucket’ınızı o domain altında yayınlayabilirsiniz. Bu işlem hem CDN avantajı hem de temiz URL yapısı sağlar.

Dashboard üzerinden “R2 Bucket” > “Settings” > “Custom Domains” bölümüne gidin ve domaininizi ekleyin. Cloudflare otomatik olarak gerekli DNS kayıtlarını oluşturacak ve SSL sertifikasını ayarlayacak.

Eğer bu işlemi Cloudflare API üzerinden yapmak istiyorsanız:

# Cloudflare API ile custom domain ekleme
ZONE_ID="your_zone_id"
API_TOKEN="your_api_token"
BUCKET_NAME="my-production-bucket"
CUSTOM_DOMAIN="assets.example.com"

# R2 custom domain yapılandırması
curl -X PUT 
  "https://api.cloudflare.com/client/v4/accounts/ACCOUNT_ID/r2/buckets/${BUCKET_NAME}/domains/custom" 
  -H "Authorization: Bearer ${API_TOKEN}" 
  -H "Content-Type: application/json" 
  -d "{
    "domain": "${CUSTOM_DOMAIN}",
    "zoneId": "${ZONE_ID}",
    "enabled": true
  }"

Custom domain eklendikten sonra bucket’ınızdaki dosyalara şu şekilde erişebilirsiniz:

  • https://assets.example.com/images/logo.png
  • https://assets.example.com/videos/intro.mp4

Python ile R2 Entegrasyonu

Uygulama geliştirme tarafında Python kullanıyorsanız boto3 kütüphanesi doğrudan R2 ile çalışır. Sadece endpoint URL’yi değiştirmeniz yeterli.

import boto3
from botocore.config import Config
import os

# R2 client oluşturma
r2_client = boto3.client(
    's3',
    endpoint_url=f"https://{os.environ['CF_ACCOUNT_ID']}.r2.cloudflarestorage.com",
    aws_access_key_id=os.environ['R2_ACCESS_KEY_ID'],
    aws_secret_access_key=os.environ['R2_SECRET_ACCESS_KEY'],
    config=Config(
        signature_version='s3v4',
        retries={'max_attempts': 3, 'mode': 'adaptive'}
    )
)

BUCKET_NAME = "my-production-bucket"

def upload_file(local_path: str, r2_key: str, content_type: str = None) -> bool:
    """Dosyayı R2'ye yükle"""
    extra_args = {}
    if content_type:
        extra_args['ContentType'] = content_type

    try:
        r2_client.upload_file(
            local_path,
            BUCKET_NAME,
            r2_key,
            ExtraArgs=extra_args
        )
        print(f"Yüklendi: {r2_key}")
        return True
    except Exception as e:
        print(f"Hata: {e}")
        return False

def generate_presigned_url(r2_key: str, expiry: int = 3600) -> str:
    """Geçici erişim URL'si oluştur"""
    url = r2_client.generate_presigned_url(
        'get_object',
        Params={'Bucket': BUCKET_NAME, 'Key': r2_key},
        ExpiresIn=expiry
    )
    return url

def list_objects_with_prefix(prefix: str) -> list:
    """Belirli prefix'e sahip objeleri listele"""
    objects = []
    paginator = r2_client.get_paginator('list_objects_v2')

    for page in paginator.paginate(Bucket=BUCKET_NAME, Prefix=prefix):
        if 'Contents' in page:
            for obj in page['Contents']:
                objects.append({
                    'key': obj['Key'],
                    'size': obj['Size'],
                    'last_modified': obj['LastModified']
                })

    return objects

# Kullanım örneği
if __name__ == "__main__":
    # Dosya yükleme
    upload_file("/tmp/report.pdf", "reports/2024/monthly-report.pdf", "application/pdf")

    # URL oluşturma (1 saatlik geçerli)
    url = generate_presigned_url("reports/2024/monthly-report.pdf", expiry=3600)
    print(f"Erişim URL'si: {url}")

    # Listeleme
    files = list_objects_with_prefix("reports/2024/")
    for f in files:
        print(f"- {f['key']} ({f['size']} bytes)")

Gerçek Dünya Senaryosu 2: Statik Web Sitesi Yayınlama

R2’yi statik web sitesi hosting için kullanmak, özellikle Next.js veya Gatsby gibi frameworklerle build edilen siteler için harika bir seçenek. CDN entegrasyonu otomatik geldiği için performans konusunda endişelenmenize gerek yok.

#!/bin/bash
# deploy-static-site.sh

set -euo pipefail

PROJECT_DIR="/var/www/my-nextjs-app"
BUILD_DIR="$PROJECT_DIR/out"
R2_ENDPOINT="https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com"
R2_BUCKET="my-static-site"

echo "Proje build ediliyor..."
cd "$PROJECT_DIR"
npm run build && npm run export

echo "R2'ye deploy ediliyor..."

# Önce HTML dosyalarını doğru content-type ile yükle
find "$BUILD_DIR" -name "*.html" | while read -r file; do
    key="${file#$BUILD_DIR/}"
    aws s3 cp "$file" "s3://${R2_BUCKET}/${key}" 
        --endpoint-url "$R2_ENDPOINT" 
        --profile cloudflare-r2 
        --content-type "text/html; charset=utf-8" 
        --cache-control "public, max-age=0, must-revalidate"
done

# CSS ve JS dosyaları (uzun cache süresi)
find "$BUILD_DIR" ( -name "*.css" -o -name "*.js" ) | while read -r file; do
    key="${file#$BUILD_DIR/}"
    content_type="text/css"
    [[ "$file" == *.js ]] && content_type="application/javascript"

    aws s3 cp "$file" "s3://${R2_BUCKET}/${key}" 
        --endpoint-url "$R2_ENDPOINT" 
        --profile cloudflare-r2 
        --content-type "$content_type" 
        --cache-control "public, max-age=31536000, immutable"
done

# Görseller
find "$BUILD_DIR" ( -name "*.png" -o -name "*.jpg" -o -name "*.webp" -o -name "*.svg" ) | while read -r file; do
    key="${file#$BUILD_DIR/}"
    aws s3 cp "$file" "s3://${R2_BUCKET}/${key}" 
        --endpoint-url "$R2_ENDPOINT" 
        --profile cloudflare-r2 
        --cache-control "public, max-age=86400"
done

echo "Deploy tamamlandi! Site: https://www.example.com"

R2’de Public Erişim ve Güvenlik Ayarları

R2 bucket’larını public yapabilir veya erişimi tamamen kısıtlayabilirsiniz. Public bucket için Cloudflare Dashboard’dan “Allow Access” seçeneğini aktif etmeniz yeterli. Ancak dikkat edilmesi gereken bazı noktalar var.

# Bucket'taki belirli bir dosyaya CORS ayarı ekleme
aws s3api put-bucket-cors 
    --bucket my-production-bucket 
    --endpoint-url "https://ACCOUNT_ID.r2.cloudflarestorage.com" 
    --profile cloudflare-r2 
    --cors-configuration '{
        "CORSRules": [
            {
                "AllowedHeaders": ["*"],
                "AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
                "AllowedOrigins": ["https://example.com", "https://app.example.com"],
                "ExposeHeaders": ["ETag"],
                "MaxAgeSeconds": 3600
            }
        ]
    }'

# Mevcut CORS ayarlarını görüntüle
aws s3api get-bucket-cors 
    --bucket my-production-bucket 
    --endpoint-url "https://ACCOUNT_ID.r2.cloudflarestorage.com" 
    --profile cloudflare-r2

Güvenlik için önemli notlar:

  • API Token izinleri: Her uygulama için ayrı, minimum yetkili token oluşturun. Okuma yapan bir servis için yazma yetkisi vermeyin.
  • Presigned URL kullanımı: Hassas dosyalar için doğrudan public erişim yerine geçici URL’ler tercih edin.
  • IP kısıtlaması: Cloudflare Workers kullanarak bucket’a erişimi belirli IP’lerle sınırlayabilirsiniz.
  • Bucket adlandırma: Bucket adlarını tahmin edilemez yapın, özellikle semi-public içerikler için.

AWS S3’ten R2’ye Geçiş

Mevcut bir S3 altyapısını R2’ye taşımak düşünüyorsanız, bu süreci rclone ile çok daha kolay yönetebilirsiniz.

# rclone kurulumu
curl https://rclone.org/install.sh | sudo bash

# rclone konfigürasyonu için interaktif mod
rclone config

# Ya da config dosyasını manuel oluşturun
cat >> ~/.config/rclone/rclone.conf << 'EOF'
[r2]
type = s3
provider = Cloudflare
access_key_id = YOUR_R2_ACCESS_KEY
secret_access_key = YOUR_R2_SECRET_KEY
endpoint = https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com
acl = private

[aws]
type = s3
provider = AWS
access_key_id = YOUR_AWS_ACCESS_KEY
secret_access_key = YOUR_AWS_SECRET_KEY
region = eu-west-1
EOF

# S3'ten R2'ye veri transferi (dry-run ile önce test edin)
rclone sync aws:my-aws-bucket r2:my-r2-bucket --dry-run --progress

# Gerçek transfer
rclone sync aws:my-aws-bucket r2:my-r2-bucket 
    --progress 
    --transfers 16 
    --checkers 32 
    --buffer-size 64M 
    --s3-upload-concurrency 16

# Transfer özet raporu
rclone size r2:my-r2-bucket

Büyük veri taşıma işlemlerinde --transfers ve --checkers parametrelerini sunucunuzun bant genişliğine göre ayarlayın. 100 GB üzeri transferlerde screen veya tmux içinde çalıştırmanızı öneririm.

Maliyet Hesaplama ve Optimizasyon

R2’nin fiyatlandırması oldukça şeffaf:

  • Depolama: GB başına aylık 0.015 dolar (ilk 10 GB ücretsiz)
  • Class-A işlemleri (PUT, POST, LIST): Her 1 milyon için 4.50 dolar (ilk 1 milyon ücretsiz)
  • Class-B işlemleri (GET, HEAD): Her 1 milyon için 0.36 dolar (ilk 10 milyon ücretsiz)
  • Egress ücreti: 0 dolar

AWS S3 ile kıyaslandığında, özellikle yüksek okuma trafiği olan sistemlerde R2 ciddi tasarruf sağlıyor. Örneğin aylık 5 TB veri çeken bir medya platformu, AWS’de egress ücreti olarak yaklaşık 460 dolar öderken R2’de bu ücret sıfır.

Maliyet optimizasyon ipuçları:

  • LIST işlemlerini minimize edin: Her LIST çağrısı Class-A sayılır, gereksiz listeleme yapmaktan kaçının.
  • Multipart upload kullanın: 100 MB üzeri dosyalar için multipart upload hem hız hem güvenilirlik açısından daha iyi.
  • Cache-Control header’ları: Doğru cache ayarları tekrarlayan GET isteklerini azaltır.
  • Cloudflare Cache: Custom domain kullandığınızda Cloudflare’in CDN cache’i otomatik devreye girer, R2’ye giden istek sayısını dramatik biçimde düşürür.

Monitoring ve Loglama

R2 işlemlerini takip etmek için Cloudflare Dashboard’daki analitik ekranını kullanabilirsiniz. Ancak daha detaylı monitoring için Cloudflare Workers ile entegrasyon yapabilirsiniz.

# R2 bucket istatistiklerini Cloudflare API ile çekme
API_TOKEN="your_api_token"
ACCOUNT_ID="your_account_id"
BUCKET_NAME="my-production-bucket"

curl -s 
  "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/r2/buckets/${BUCKET_NAME}" 
  -H "Authorization: Bearer ${API_TOKEN}" 
  -H "Content-Type: application/json" | jq '.'

# Bucket listesini ve boyutlarını çek
curl -s 
  "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/r2/buckets" 
  -H "Authorization: Bearer ${API_TOKEN}" | jq '.result[] | {name: .name, creation_date: .creation_date}'

Alerting için önerilen yaklaşım:

  • Cloudflare Dashboard’dan “Notifications” bölümüne gidin.
  • R2 için storage limiti uyarıları oluşturun.
  • Anormal istek sayıları için threshold alert ayarlayın.
  • Önemli bucket’lar için erişim loglarını ayrı bir R2 bucket’a yazın.

Sonuç

Cloudflare R2, özellikle egress ücreti sıfır politikasıyla, nesne depolama alanında gerçek bir alternatif haline geldi. S3 API uyumluluğu sayesinde mevcut araçlarınızı ve kodunuzu neredeyse hiç değiştirmeden kullanabiliyorsunuz. Bu da geçiş maliyetini son derece düşürüyor.

Pratik değerlendirmem şu: Yeni başlayan projeler için R2 neredeyse her zaman mantıklı bir seçim. Mevcut S3 kullanıcıları içinse özellikle yüksek egress trafiği olan sistemlerde geçişin ROI’si çok hızlı geri dönüyor.

Dikkat edilmesi gereken tek nokta, R2’nin S3’e kıyasla daha genç bir servis olması. Bazı gelişmiş özellikler (lifecycle policies, replication gibi) kısmi destek veya farklı implementasyon sunuyor. Ancak Cloudflare’in bu konudaki geliştirme hızına bakılırsa, özellik farkı giderek kapanıyor.

Yedekleme sistemleri, statik site hosting, medya depolama ve kullanıcı içeriklerini barındırma gibi senaryolarda R2’yi çekinmeden production ortamında kullanabilirsiniz. Ücretsiz katmanla başlayın, sisteminizin davranışını izleyin ve ölçeklendikçe maliyeti gerçekçi biçimde hesaplayın.

Bir yanıt yazın

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