Cloudflare Images ile Görsel Optimizasyonu
Bir web sitesi yönetiyorsanız, görsel optimizasyonu muhtemelen en çok zaman harcadığınız konulardan biri. ImageMagick scriptleri, WebP dönüşümleri, farklı ekran boyutları için responsive görseller… Bunların hepsini elle yönetmek gerçekten yorucu. Cloudflare Images tam da bu noktada devreye giriyor ve işleri ciddi anlamda kolaylaştırıyor.
Cloudflare Images Nedir ve Neden Kullanmalısınız?
Cloudflare Images, görselleri depolamak, optimize etmek ve dağıtmak için tasarlanmış bir CDN tabanlı görsel yönetim servisidir. Temel mantığı şu: görselinizi bir kez yüklüyorsunuz, Cloudflare gerisini hallediyor. Format dönüşümü, boyutlandırma, sıkıştırma ve dağıtım tamamen otomatik.
Peki bunu diğer çözümlerden ayıran ne? Fiyatlandırma modeli ve entegrasyon kolaylığı. Cloudflare’i zaten DNS için kullanıyorsanız, Images servisini etkinleştirmek dakikalar alıyor. Üstelik 100.000 görsel için aylık 5 dolar gibi oldukça uygun bir fiyatla başlıyor.
Gerçek dünya senaryosunu anlatayım: 50.000 ürün görseli olan bir e-ticaret sitesi düşünün. Her ürünün liste sayfası için küçük thumbnail, ürün detay sayfası için orta boy ve zoom için tam çözünürlük gerekiyor. Bunları ayrı ayrı oluşturmak yerine orijinal görseli bir kez yükleyip URL parametreleriyle anlık dönüşüm yapabiliyorsunuz.
Cloudflare Images’ı Aktif Etmek
Dashboard üzerinden aktivasyon oldukça basit ama API üzerinden yönetmek çok daha verimli. Önce hesabınızı kontrol edelim:
# Cloudflare API token ile hesap bilgilerini kontrol et
curl -X GET "https://api.cloudflare.com/client/v4/accounts"
-H "Authorization: Bearer YOUR_API_TOKEN"
-H "Content-Type: application/json"
API token oluştururken Cloudflare Images: Edit iznini vermeniz gerekiyor. Read yetkisi yeterli olmayacak, bunu atlamamaya dikkat edin.
Account ID’nizi aldıktan sonra Images endpoint’ine istek atabilirsiniz. Basit bir test yapalım:
# Images servisinin aktif olup olmadığını kontrol et
curl -X GET "https://api.cloudflare.com/client/v4/accounts/YOUR_ACCOUNT_ID/images/v1"
-H "Authorization: Bearer YOUR_API_TOKEN"
-H "Content-Type: application/json"
Eğer "success": true dönüyorsa servis aktif demektir. "errors" içinde yetki hatası görüyorsanız token izinlerini tekrar gözden geçirin.
Görsel Yükleme: API ile Toplu İşlemler
Tek tek yüklemek yerine bir script yazalım. Diyelim ki sunucunuzda /var/www/images dizininde yüzlerce görsel var ve hepsini Cloudflare’e taşımak istiyorsunuz.
#!/bin/bash
# bulk_upload.sh - Toplu görsel yükleme scripti
ACCOUNT_ID="your_account_id"
API_TOKEN="your_api_token"
IMAGE_DIR="/var/www/images"
LOG_FILE="/var/log/cf_images_upload.log"
echo "Yükleme başladı: $(date)" >> $LOG_FILE
for image in "$IMAGE_DIR"/*.{jpg,jpeg,png,webp,gif}; do
if [ -f "$image" ]; then
filename=$(basename "$image")
# Görseli yükle ve sonucu kaydet
response=$(curl -s -X POST
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/images/v1"
-H "Authorization: Bearer $API_TOKEN"
-F "file=@$image"
-F "metadata={"original_name": "$filename"}"
-F "requireSignedURLs=false")
# Başarı kontrolü
success=$(echo $response | python3 -c "import sys, json; print(json.load(sys.stdin)['success'])")
image_id=$(echo $response | python3 -c "import sys, json; print(json.load(sys.stdin)['result']['id'])" 2>/dev/null)
if [ "$success" = "True" ]; then
echo "BAŞARILI: $filename -> ID: $image_id" >> $LOG_FILE
echo "OK: $filename"
else
echo "HATA: $filename" >> $LOG_FILE
echo $response >> $LOG_FILE
fi
# Rate limiting için kısa bekleme
sleep 0.1
fi
done
echo "Yükleme tamamlandı: $(date)" >> $LOG_FILE
Bu scripti çalıştırmadan önce chmod +x bulk_upload.sh yapmayı unutmayın. Rate limit aşımını önlemek için 100ms bekleme koydum, büyük dosyalar için bunu artırabilirsiniz.
Variants: Görsel Boyutlandırma Şablonları
Cloudflare Images’ın en güçlü özelliklerinden biri Variants sistemi. Bir variant, görselin nasıl gösterileceğini tanımlayan bir şablon. Thumbnail, orta boy, tam ekran gibi farklı kullanım senaryoları için önceden variant oluşturabilirsiniz.
# Thumbnail variant oluştur
curl -X POST
"https://api.cloudflare.com/client/v4/accounts/YOUR_ACCOUNT_ID/images/v1/variants"
-H "Authorization: Bearer YOUR_API_TOKEN"
-H "Content-Type: application/json"
--data '{
"id": "thumbnail",
"options": {
"width": 150,
"height": 150,
"fit": "cover",
"quality": 80,
"format": "auto"
},
"neverRequireSignedURLs": true
}'
Şimdi ürün kartları için biraz daha büyük bir variant:
# Ürün listesi için orta boy variant
curl -X POST
"https://api.cloudflare.com/client/v4/accounts/YOUR_ACCOUNT_ID/images/v1/variants"
-H "Authorization: Bearer YOUR_API_TOKEN"
-H "Content-Type: application/json"
--data '{
"id": "product_card",
"options": {
"width": 400,
"height": 400,
"fit": "contain",
"background": "#ffffff",
"quality": 85,
"format": "auto"
},
"neverRequireSignedURLs": true
}'
fit parametresinin alabileceği değerler önemli:
- cover: Alanı tamamen kaplar, taşan kısımları keser
- contain: Tüm görsel görünür, boşluklar arka plan rengiyle doldurulur
- crop: Belirtilen boyuta crop eder
- scale-down: Sadece küçültür, büyütmez
- pad: Contain gibi davranır ama padding ekler
E-ticaret sitelerinde genellikle ürün görselleri için contain + beyaz arka plan kombinasyonu kullanılır. Bu sayede farklı oranlardaki görseller tutarlı görünür.
URL Yapısı ve Dinamik Dönüşümler
Variant oluşturduktan sonra URL yapısı şu şekilde oluyor:
https://imagedelivery.net/HASH/IMAGE_ID/VARIANT_NAME
Örnek bir URL:
https://imagedelivery.net/abc123xyz/urun-gorseli-uuid/thumbnail
https://imagedelivery.net/abc123xyz/urun-gorseli-uuid/product_card
https://imagedelivery.net/abc123xyz/urun-gorseli-uuid/public
public variant varsayılan olarak geliyor ve orijinal görseli döndürüyor.
Eğer uygulamanızda dinamik boyutlandırma gerekiyorsa ve her boyut için variant açmak istemiyorsanız, Flexible Variants özelliğini kullanabilirsiniz. Bu özelliği dashboard’dan etkinleştirmeniz gerekiyor ama bir kez açınca URL parametreleriyle anlık dönüşüm yapabiliyorsunuz:
https://imagedelivery.net/HASH/IMAGE_ID/w=800,h=600,fit=cover,format=webp,quality=90
Bu yaklaşım özellikle içerik yönetim sistemleri ve headless CMS kullananlar için çok kullanışlı.
WordPress ile Entegrasyon
Cloudflare Images’ı WordPress sitesine entegre etmek için birkaç yol var. En temiz yöntem kendi küçük bir eklentisi yazmak. Şöyle bir yaklaşım kullanabilirsiniz:
# WordPress eklenti dizinine git
cd /var/www/html/wp-content/plugins/
mkdir cloudflare-images-helper
PHP kısmını da gösterelim ama asıl konumuz sysadmin tarafı olduğu için WordPress’in medya yükleme hook’unu nasıl yakalayacağımıza bakalım. Yüklenen görseli Cloudflare’e push eden bir cron job daha pratik:
#!/bin/bash
# wp_images_sync.sh - WordPress uploads'ı Cloudflare'e senkronize et
ACCOUNT_ID="your_account_id"
API_TOKEN="your_api_token"
WP_UPLOADS="/var/www/html/wp-content/uploads"
SYNCED_LIST="/var/log/cf_synced_images.txt"
YEAR=$(date +%Y)
MONTH=$(date +%m)
# Bu ay yüklenen görselleri bul
find "$WP_UPLOADS/$YEAR/$MONTH" -type f ( -name "*.jpg" -o -name "*.png" -o -name "*.webp" ) | while read -r image; do
# Daha önce senkronize edilmiş mi kontrol et
if grep -qF "$image" "$SYNCED_LIST" 2>/dev/null; then
continue
fi
# Yükle
response=$(curl -s -X POST
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/images/v1"
-H "Authorization: Bearer $API_TOKEN"
-F "file=@$image")
if echo $response | grep -q '"success":true'; then
echo "$image" >> "$SYNCED_LIST"
cf_id=$(echo $response | python3 -c "import sys, json; print(json.load(sys.stdin)['result']['id'])")
echo "Senkronize edildi: $image -> $cf_id"
fi
done
Bu scripti cron’a ekleyin:
# Her gece 02:00'da çalışsın
echo "0 2 * * * /usr/local/bin/wp_images_sync.sh >> /var/log/wp_cf_sync.log 2>&1" | crontab -
Görsel Silme ve Yönetim API’si
Yükleme kadar silme ve listeleme işlemleri de önemli. Özellikle kullanıcıların kendi içeriklerini silebildiği platformlarda bunu otomatize etmeniz gerekiyor.
# Tüm görselleri listele (sayfalı)
curl -X GET
"https://api.cloudflare.com/client/v4/accounts/YOUR_ACCOUNT_ID/images/v1?page=1&per_page=100"
-H "Authorization: Bearer YOUR_API_TOKEN"
-H "Content-Type: application/json"
# Belirli bir görseli sil
curl -X DELETE
"https://api.cloudflare.com/client/v4/accounts/YOUR_ACCOUNT_ID/images/v1/IMAGE_ID"
-H "Authorization: Bearer YOUR_API_TOKEN"
-H "Content-Type: application/json"
Toplu silme için bir script daha yazalım. Mesela 6 aydan eski ve hiç erişilmemiş görselleri temizlemek istiyorsunuz:
#!/bin/bash
# cleanup_old_images.sh - Eski görselleri temizle
ACCOUNT_ID="your_account_id"
API_TOKEN="your_api_token"
CUTOFF_DATE=$(date -d "6 months ago" +%Y-%m-%dT%H:%M:%SZ)
PAGE=1
DELETED=0
echo "Temizleme başlıyor. Kesim tarihi: $CUTOFF_DATE"
while true; do
# Görselleri al
response=$(curl -s -X GET
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/images/v1?page=$PAGE&per_page=100"
-H "Authorization: Bearer $API_TOKEN")
# Görsel sayısını kontrol et
count=$(echo $response | python3 -c "import sys, json; data=json.load(sys.stdin); print(len(data['result']['images']))" 2>/dev/null)
if [ "$count" = "0" ] || [ -z "$count" ]; then
echo "Tüm sayfalar işlendi."
break
fi
# Her görseli kontrol et ve eski olanları sil
echo $response | python3 -c "
import sys, json
from datetime import datetime
data = json.load(sys.stdin)
cutoff = datetime.fromisoformat('$CUTOFF_DATE'.replace('Z', '+00:00'))
for img in data['result']['images']:
uploaded = datetime.fromisoformat(img['uploaded'].replace('Z', '+00:00'))
if uploaded < cutoff:
print(img['id'])
" | while read -r image_id; do
curl -s -X DELETE
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/images/v1/$image_id"
-H "Authorization: Bearer $API_TOKEN" > /dev/null
echo "Silindi: $image_id"
DELETED=$((DELETED + 1))
sleep 0.05
done
PAGE=$((PAGE + 1))
done
echo "Toplam silinen görsel: $DELETED"
Signed URLs ile Güvenlik
Özel içerikler için, yani herkese açık olmayan görseller için Signed URLs kullanmanız gerekiyor. Örneğin premium üyelere özel içerik veya kullanıcıların kişisel belgeleri gibi durumlar.
Signed URL mantığı şu: görseli yüklerken requireSignedURLs: true ayarlıyorsunuz. Sonra her erişim için zamanlı ve imzalı bir URL üretiyorsunuz.
# Signed URL gerektiren görsel yükle
curl -X POST
"https://api.cloudflare.com/client/v4/accounts/YOUR_ACCOUNT_ID/images/v1"
-H "Authorization: Bearer YOUR_API_TOKEN"
-F "file=@/path/to/private-document.jpg"
-F "requireSignedURLs=true"
# Signing key oluştur (bir kez yapılır)
curl -X POST
"https://api.cloudflare.com/client/v4/accounts/YOUR_ACCOUNT_ID/images/v1/keys"
-H "Authorization: Bearer YOUR_API_TOKEN"
-H "Content-Type: application/json"
Signing key’i aldıktan sonra uygulamanızda imzalı URL üretmeniz gerekiyor. Bash ile basit bir örnek:
#!/bin/bash
# generate_signed_url.sh
IMAGE_ID="your-image-id"
VARIANT="thumbnail"
SIGNING_KEY="your-signing-key"
EXPIRY=$(($(date +%s) + 3600)) # 1 saat geçerli
URL="https://imagedelivery.net/YOUR_HASH/$IMAGE_ID/$VARIANT?exp=$EXPIRY"
# HMAC-SHA256 ile imzala
SIGNATURE=$(echo -n "$URL" | openssl dgst -sha256 -hmac "$SIGNING_KEY" -binary | xxd -p -c 256)
SIGNED_URL="${URL}&sig=${SIGNATURE}"
echo $SIGNED_URL
Gerçek üretim ortamında bu imzalamayı uygulamanızın backend tarafında yapmanız gerekiyor. Node.js, Python veya PHP ile çok daha temiz implementation mümkün.
Cache ve Performans Optimizasyonu
Cloudflare Images, görselleri otomatik olarak cache’liyor ama bunu nasıl yapılandırabileceğinizi bilmek önemli. Özellikle marka güncellemesi veya içerik değişikliği durumunda cache’i temizlemeniz gerekebilir.
Görsel güncelleme yaptığınızda URL değişmediği için eski görsel cache’de kalabilir. Bu sorunu aşmanın yolu görseli güncellemek yerine silip yeni ID ile yüklemek:
# Görsel güncelleme scripti
#!/bin/bash
OLD_IMAGE_ID="eski-gorsel-id"
NEW_IMAGE_PATH="/path/to/new-image.jpg"
ACCOUNT_ID="your_account_id"
API_TOKEN="your_api_token"
# Önce yeni görseli yükle
echo "Yeni görsel yükleniyor..."
NEW_RESPONSE=$(curl -s -X POST
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/images/v1"
-H "Authorization: Bearer $API_TOKEN"
-F "file=@$NEW_IMAGE_PATH")
NEW_ID=$(echo $NEW_RESPONSE | python3 -c "import sys, json; print(json.load(sys.stdin)['result']['id'])")
if [ -n "$NEW_ID" ]; then
echo "Yeni görsel ID: $NEW_ID"
# Eski görseli sil
curl -s -X DELETE
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/images/v1/$OLD_IMAGE_ID"
-H "Authorization: Bearer $API_TOKEN"
echo "Eski görsel silindi: $OLD_IMAGE_ID"
echo "Veritabanında ID'yi güncellemeyi unutmayın: $NEW_ID"
else
echo "HATA: Yeni görsel yüklenemedi!"
echo $NEW_RESPONSE
fi
Monitoring ve Kullanım Takibi
Aylık kotanızı takip etmek için düzenli kontrol yapmanız gerekiyor. 100.000 görsel limitinin yaklaşıp yaklaşmadığını izleyen bir script:
#!/bin/bash
# cf_images_monitor.sh
ACCOUNT_ID="your_account_id"
API_TOKEN="your_api_token"
THRESHOLD=80 # Yüzde eşik değeri
# İstatistikleri al
stats=$(curl -s -X GET
"https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/images/v1/stats"
-H "Authorization: Bearer $API_TOKEN")
current=$(echo $stats | python3 -c "import sys, json; print(json.load(sys.stdin)['result']['count']['current'])")
allowed=$(echo $stats | python3 -c "import sys, json; print(json.load(sys.stdin)['result']['count']['allowed'])")
percentage=$((current * 100 / allowed))
echo "Kullanım: $current / $allowed (%$percentage)"
if [ $percentage -ge $THRESHOLD ]; then
echo "UYARI: Görsel kotasının %$percentage'ı kullanılmış!"
# Slack veya email bildirimi eklenebilir
# curl -X POST -H 'Content-type: application/json'
# --data '{"text":"CF Images kota uyarısı: %'$percentage' kullanılmış"}'
# YOUR_SLACK_WEBHOOK_URL
fi
Bu scripti de cron’a ekleyin, günlük çalıştırmak yeterli:
echo "0 9 * * * /usr/local/bin/cf_images_monitor.sh >> /var/log/cf_monitor.log 2>&1" | crontab -
Gerçek Dünya Performans Kazanımları
Cloudflare Images’a geçiş yaptıktan sonra gözlemlediğim ortalama iyileştirmeler şunlar:
- Orta ölçekli e-ticaret sitelerinde sayfa yükleme süresinde yüzde 40-60 düşüş, özellikle ürün listeleme sayfalarında
- Görsel boyutlarında yüzde 60-80 küçülme (özellikle JPEG’den WebP’ye geçişte)
- Bandwidth maliyetinde ciddi düşüş, geleneksel CDN ile karşılaştırıldığında
- Geliştirici zamanında büyük tasarruf, artık resize scriptleri yazmaya gerek yok
En çarpıcı örnek 80.000 ürün görseli olan bir müşteriydi. Her ürün için 4 farklı boyut üretiyorlardı, toplam 320.000 görsel. Cloudflare Images’a geçince sadece 80.000 orijinal görsel saklıyorlar, geri kalanı anlık üretiliyor. Depolama maliyeti dörtte bire düştü.
Yaygın Hatalar ve Çözümleri
Rate limit aşımı: API’yi çok hızlı kullandığınızda 429 hatası alırsınız. Script’lerinize mutlaka sleep ekleyin, saniyede en fazla 10-20 istek yapın.
Büyük dosya reddi: Cloudflare Images maksimum 10MB ve 10 megapiksel destekliyor. Yüklemeden önce görselleri kontrol etmek için:
# 10MB'dan büyük görselleri listele
find /var/www/images -size +10M -name "*.jpg" -o -size +10M -name "*.png"
Token yetki hatası: Images API için ayrı token oluşturmanız ve sadece gerekli izinleri vermeniz önemli. Genel API token kullanmayın, güvenlik riski oluşturuyor.
Variant bulunamadı hatası: URL’de variant adını yanlış yazmak çok yaygın. Büyük/küçük harf duyarlı, Thumbnail ile thumbnail farklı şeyler.
Sonuç
Cloudflare Images, görsel yönetimini gerçekten basitleştiren bir servis. Özellikle zaten Cloudflare kullanan sitelerde entegrasyonu son derece hızlı ve sorunsuz. En büyük avantajı format optimizasyonunu tamamen otomatikleştirmesi: ziyaretçinin tarayıcısına göre otomatik WebP veya AVIF gönderme özelliği tek başına bile geçiş yapmaya değer.
Küçük ve orta ölçekli projeler için fiyat-performans dengesi mükemmel. Büyük hacimli operasyonlarda (milyonlarca görsel) alternatif çözümlerle kıyaslama yapmanız faydalı olabilir, ama o ölçeğe gelene kadar Cloudflare Images büyük ihtimalle ihtiyaçlarınızı karşılıyor.
Yukarıdaki scriptleri kendi ortamınıza uyarlayın, production’a almadan önce mutlaka test ortamında deneyin ve her zaman yedek stratejinizi belirleyin. Görselleri Cloudflare’e taşımadan önce orijinallerini kendi depolama alanınızda tutmaya devam edin.
