Bunny Migration

Muzibu.com → Bunny CDN + Storage Zone

Tam Teknik Dokümantasyon v2

İçindekiler

1. Proje Özeti

Amaç

Muzibu.com müzik platformunun ses dosyalarını Cloudflare'den Bunny.net altyapısına taşımak. Bu geçiş ile daha iyi performans, maliyet tasarrufu ve gelişmiş güvenlik hedefleniyor.

Önceki Durum

  • • Cloudflare Pro ($25/ay)
  • • Cloudflare Argo ($5/ay)
  • • Ses dosyaları local sunucuda
  • • HLS streaming local'dan

Yeni Durum

  • • Bunny Storage Zone (ses dosyaları)
  • • Bunny Pull Zone (CDN)
  • • Bunny Shield Advanced ($9.5/ay)
  • • Perma-Cache (kalıcı SSD cache)
  • • Redis Tracking (anlık sync)

Kapsam

33,112
Toplam Şarkı
~2.1 TB
Tahmini Boyut
HLS + MP3
Format
AES-128
Şifreleme

2. Mimari Yapı

Bunny Servisleri

Servis İsim URL / ID Açıklama
Storage Zone muzibu-audio Frankfurt (de) Ses dosyalarının depolandığı yer
Pull Zone (Audio) muzibu-audio-cdn https://muzibu-audio-cdn.b-cdn.net Ses dosyaları için CDN
Pull Zone (Web) muzibuweb https://cdn.muzibu.com Website asset'leri için CDN
Perma-Cache Zone muzibu-perma-cache Frankfurt + London + Stockholm Kalıcı SSD cache storage
Shield Advanced muzibuweb pull zone WAF + DDoS + Rate Limiting

Dosya Yapısı (Bunny Storage)

muzibu-audio/ ├── hls/ │ ├── {song_id}/ │ │ ├── master.m3u8 # Ana playlist │ │ ├── ultralow/ # 32kbps │ │ │ ├── playlist.m3u8 │ │ │ └── segment_*.ts │ │ ├── low/ # 64kbps │ │ ├── mid/ # 128kbps │ │ └── high/ # Orijinal kalite │ └── ... ├── mp3_64/ │ └── {song_id}.mp3 # 64kbps MP3 ├── mp3_128/ │ └── {song_id}.mp3 # 128kbps MP3 └── songs/ └── original/ └── {song_id}.mp3 # Orijinal MP3

Kritik: Şifreleme Dosyaları

enc.bin (AES-128 key) dosyaları ASLA Bunny'ye yüklenmez! Bu dosyalar her zaman local sunucudan serve edilir. HLS player key'i local'dan alır, segment'leri Bunny'den alır.

Konum: /storage/tenant1001/app/public/muzibu/hls/{song_id}/enc.bin

3. Redis Tracking Sistemi YENİ

Basit Anlatım (Herkes İçin)

Redis, hafızada çalışan süper hızlı bir veritabanıdır. Şöyle düşünün:

Senaryo: Kullanıcı şarkı #12345'i dinlemek istiyor.

Sistem "Bu şarkı Bunny'de var mı?" diye sorar → Redis anında cevap verir (evet/hayır) → Varsa Bunny'den, yoksa local'dan çalınır.

❌ Cache dosyası sorunu:

Yeni şarkı yüklenince güncellenmez, silinen şarkılar hâlâ "var" görünür.

✅ Redis çözümü:

Şarkı yüklenince anında eklenir, silinince anında çıkarılır. Her zaman güncel!

Teknik Detaylar (Geliştiriciler İçin)

Redis Key Yapısı

bunny:uploaded_songs → Redis SET (şarkı ID'leri) ├── 12345 → Şarkı #12345 Bunny'de ├── 12346 → Şarkı #12346 Bunny'de └── ... → (33,000+ kayıt)

Temel İşlemler

// Şarkı Bunny'ye yüklenince: Redis::sadd('bunny:uploaded_songs', $songId); // Şarkı silinince: Redis::srem('bunny:uploaded_songs', $songId); // Kontrol (O(1) - anlık): $onBunny = Redis::sismember('bunny:uploaded_songs', $songId);

Performans Karşılaştırması

Yöntem Hız 33,000 şarkı için
HTTP HEAD (Bunny API) ~50ms ~27 dakika
Cache Dosyası (array) ~1ms Tek seferlik yükleme
Redis SISMEMBER ~0.1ms Her zaman güncel!

Neden Redis?

Anlık Güncelleme

Upload/delete anında Redis'e yansır

O(1) Hız

33K şarkıda bile aynı hız

Persistent

Server restart'ta veri kaybolmaz

Mevcut Altyapı

Zaten Redis kullanıyoruz (session, cache)

Uygulama Adımları

1
Cache dosyasını Redis'e aktar

/tmp/bunny-existing-hls.txt → Redis SET (bir kerelik)

2
BunnyStorageService::uploadSong() → Redis ekle

Yükleme sonrası otomatik: Redis::sadd()

3
BunnyStorageService::deleteSong() → Redis çıkar

Silme sonrası otomatik: Redis::srem()

4
SignedUrlService → Redis'ten kontrol

URL oluştururken: Bunny'de var → CDN URL, yok → Local URL

4. Hybrid Serving Akışı YENİ

Basit Anlatım

"Hybrid" = Karışık demek. Şarkılar iki yerden sunulabilir:

🐰 Bunny CDN

Hızlı, dünya genelinde edge sunucular

Migration tamamlanan şarkılar buradan

🖥️ Local Sunucu

Mevcut sunucu (fallback)

Henüz migrate edilmemiş şarkılar + enc.bin

Çalışma Akışı

1. İstek
Kullanıcı şarkı #12345 çalmak istiyor
2. Redis Sorgusu
Redis::sismember('bunny:uploaded_songs', 12345)
~0.1ms - Anlık cevap
✅ Redis: true (Bunny'de var)
3a. Bunny CDN URL
https://muzibu-audio-cdn.b-cdn.net/hls/12345/master.m3u8
❌ Redis: false (Bunny'de yok)
3b. Local URL (Fallback)
/audio/songs/12345/hls/master.m3u8
4. Sonuç
Player şarkıyı çalmaya başlar
Kullanıcı farkı hissetmez - her iki durumda da şarkı çalar

Özel Durum: enc.bin (Şifreleme Key)

HLS şifreleme anahtarı her zaman local sunucudan gelir:

HLS Segment'ler
→ Bunny CDN'den
segment_001.ts, segment_002.ts...
Şifre Çözme Key
→ Local sunucudan
/audio/songs/12345/hls/enc.bin

Güvenlik: Key asla CDN'de tutulmaz. Player key'i alır, segment'leri indirir, client-side decrypt yapar.

Yükleme & Silme Akışı

📤 Yeni Şarkı Yükleme
  1. Şarkı orijinali yüklenir
  2. HLS encode işlemi başlar
  3. HLS + MP3 dosyaları Bunny'ye yüklenir
  4. Redis::sadd() → Şarkı ID eklenir
  5. Artık Bunny'den serve edilir
🗑️ Şarkı Silme
  1. Şarkı silme isteği gelir
  2. Bunny'den dosyalar silinir
  3. Local'dan dosyalar silinir
  4. Redis::srem() → Şarkı ID çıkarılır
  5. Artık 404 döner (doğru davranış)

5. Tamamlanan İşlemler

1

Bunny Storage Zone Oluşturma

TAMAMLANDI

Storage Zone: muzibu-audio

Region: Frankfurt (de)

Replication: Yok (tek bölge)

2

Bunny Pull Zone (Audio CDN)

TAMAMLANDI

Pull Zone: muzibu-audio-cdn

URL: https://muzibu-audio-cdn.b-cdn.net

Origin: Storage Zone (muzibu-audio)

3

SafeHop Aktivasyonu

TAMAMLANDI

SafeHop: Origin bağlantı hatalarında otomatik retry

Pull Zone: muzibuweb

Aktivasyon: Bunny Panel → Pull Zone → General → SafeHop → Enable

4

Perma-Cache Aktivasyonu

TAMAMLANDI

Karar: Origin Shield yerine Perma-Cache tercih edildi (daha hızlı)

Storage Zone: muzibu-perma-cache

Replication: Frankfurt + London + Stockholm

Origin Shield ve Perma-Cache birlikte kullanılamaz. Perma-Cache = kalıcı SSD cache, dosyalar hiç expire olmaz. Origin'e daha az istek = daha hızlı.

5

Bunny Shield Advanced

TAMAMLANDI

Plan: Advanced ($9.5/ay)

Pull Zone: muzibuweb (sadece web, audio CDN'de yok)

Özellikler:

  • • WAF (SQL Injection, XSS koruması)
  • • DDoS koruması (200 Tbps+)
  • • Rate Limiting (10 kural)
  • • Bot Detection
  • • Zero-day koruma
  • • 6 Tehdit listesi

WAF Learning Mode: 7 gün (22-29 Mart 2026)

6

Orijinal MP3 Yükleme

TAMAMLANDI

Yüklenen: 33,110 / 33,112

Konum: songs/original/{song_id}.mp3

Komut: php artisan muzibu:migrate-originals --all

Not: Orijinal MP3'ler farklı path formatlarında olabilir: SONG_*.mp3, song_*.mp3, veya nested path

7

Cloudflare Pro + Argo İptali

TAMAMLANDI

İptal tarihi: 14 Nisan 2026

Cloudflare Pro: $25/ay → İptal

Cloudflare Argo: $5/ay → İptal

Toplam tasarruf: $30/ay

8

Cache Kontrolü

TAMAMLANDI

CDN Cache: %100 HIT

Edge Location: Turkey PoP (TR1-942)

Perma-Cache: Aktif ve çalışıyor

6. Devam Eden İşlemler

9

HLS + MP3 Migration

DEVAM EDİYOR

Her şarkı için yüklenen dosyalar:

  • hls/{song_id}/master.m3u8
  • hls/{song_id}/ultralow/playlist.m3u8 + segment_*.ts
  • hls/{song_id}/low/playlist.m3u8 + segment_*.ts
  • hls/{song_id}/mid/playlist.m3u8 + segment_*.ts
  • hls/{song_id}/high/playlist.m3u8 + segment_*.ts
  • mp3_64/{song_id}.mp3
  • mp3_128/{song_id}.mp3

enc.bin YÜKLENMİYOR! (şifreleme key'i local'da kalır)

Worker Dağılımı (22 Mart 2026)

Eski Worker'lar
  • W1: 51-5300 ✅ Bitti
  • W2: 5301-10500
  • W3: 10501-15700
  • W5: 21001-26200
  • W7: 31501-36700
Yeni Worker'lar (bölünmüş)
  • w4a: 15723-17500
  • w4b: 17501-19250
  • w4c: 19251-21000
  • w6a: 26244-28000
  • w6b: 28001-29750
  • w6c: 29751-31500
  • w8a: 36717-38450
  • w8b: 38451-40165
  • w8c: 40166-41880
GAP Worker'lar (boşlukları kapatmak için)
  • gap1: 15701-15722 (W4 durduğunda atlanan) ✅ Bitti
  • gap2: 26201-26243 (W6 durduğunda atlanan) ✅ Bitti
  • gap3: 36701-36716 (W8 durduğunda atlanan) ✅ Bitti

Canlı Takip Komutu

watch -n 10 /tmp/bunny-status.sh

7. Kalan İşlemler (Migration Sonrası)

10

Redis Tracking Implementasyonu

ÖNCELİK

Migration bitmeden önce yapılabilir - fallback zaten çalışıyor.

Değişiklik yapılacak dosyalar:

  • BunnyStorageService.php (+2 satır)
    // uploadSong() sonuna: Redis::sadd('bunny:uploaded_songs', $songId); // deleteSong() sonuna: Redis::srem('bunny:uploaded_songs', $songId);
  • SignedUrlService.php (+5-10 satır)
    // generateAudioCdnUrl() içinde: $onBunny = Redis::sismember('bunny:uploaded_songs', $songId); if ($onBunny) { return config('bunny.storage_cdn_url') . "/hls/{$songId}/master.m3u8"; } return "/audio/songs/{$songId}/hls/master.m3u8"; // fallback

İlk kurulum: php /tmp/import-cache-to-redis.php ile mevcut cache Redis'e aktarılır

11

Player Kod Güncellemesi

BEKLEMEDE

Player'ın HLS ve MP3 dosyalarını Bunny CDN'den alması sağlanmalı.

Kontrol edilecek dosyalar:

  • public/themes/muzibu/js/player/ içindeki player dosyaları
  • • HLS URL oluşturan backend kodları
  • • MP3 fallback URL'leri

Redis implementasyonu sonrası otomatik çalışacak

12

Test - Farklı Cihazlar

BEKLEMEDE

Test edilmesi gereken senaryolar:

  • • Safari (iOS) - HLS native destek
  • • Chrome (Android) - HLS.js ile
  • • Firefox (Desktop) - HLS.js ile
  • • Eski cihazlar (düşük bant genişliği)
  • • HLS → MP3 fallback senaryosu
  • • Gapless geçiş (şarkılar arası)
  • • 10+ saat açık kalma testi (memory leak)
13

DNS / Cloudflare Ayarları

BEKLEMEDE

14 Nisan 2026'da Cloudflare Pro bitince:

  • • DNS Cloudflare'de kalabilir (ücretsiz plan)
  • • Proxy kapatılmalı (Bunny CDN kullanılacak)
  • • Veya DNS tamamen başka yere taşınabilir
14

WAF Learning Mode Bitişi

29 MART 2026

Bunny Shield 7 gün Learning Mode'da çalışacak.

29 Mart'ta yapılacaklar:

  • • Shield → Event Logs kontrol et
  • • False positive varsa kural ayarla
  • • Learning Mode'u kapat → Tam koruma aktif
15

Opsiyonel: BUNNY_STORAGE_MODE Değişikliği

OPSİYONEL

Şu an: BUNNY_STORAGE_MODE=hybrid

Anlamı: Dosya Bunny'de yoksa local'dan serve et

Migration %100 tamamlandıktan sonra:

  • hybrid modda kalabilir (güvenli, fallback var)
  • • Veya bunny moduna geçilebilir (sadece Bunny)

Öneri: Test tamamlanana kadar hybrid modda kal

8. Konfigürasyon Detayları

.env Dosyası (Bunny Ayarları)

# BUNNY CDN CONFIGURATION (Pull Zone - Website) BUNNY_CDN_ENABLED=false BUNNY_CDN_URL=https://cdn.muzibu.com BUNNY_CDN_TOKEN_KEY=646b6c86-af40-4660-a8b1-e060eb248c36 BUNNY_CDN_ZONE_ID=5347238 # BUNNY STORAGE ZONE (Audio Files) BUNNY_STORAGE_ENABLED=true BUNNY_STORAGE_API_KEY=b9edcf9f-7707-4baf-87ee55fec79a-e7d7-4efe BUNNY_STORAGE_ZONE=muzibu-audio BUNNY_STORAGE_REGION=de BUNNY_STORAGE_CDN_URL=https://muzibu-audio-cdn.b-cdn.net BUNNY_STORAGE_MODE=hybrid BUNNY_FALLBACK_TO_LOCAL=true # REDIS (Mevcut - değişiklik yok) REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379

BUNNY_STORAGE_MODE Değerleri

Mod Açıklama Kullanım
local Sadece local sunucudan serve et Bunny'ye geçmeden önce
hybrid Önce Bunny, yoksa local (fallback) Şu anki mod (önerilen)
bunny Sadece Bunny'den serve et Migration %100 tamamlandıktan sonra

İlgili PHP Dosyaları

  • app/Services/Bunny/BunnyStorageService.php

    Ana Bunny servis sınıfı - upload, exists, getUrl, Redis işlemleri

  • app/Services/SignedUrlService.php

    URL oluşturucu - Redis kontrolü ile hybrid serving

  • app/Console/Commands/MigrateToBunnyCommand.php

    HLS + MP3 migration komutu

  • app/Console/Commands/MigrateOriginalsToBunnyCommand.php

    Sadece orijinal MP3'leri yükleyen komut

9. Kullanılan Komutlar

Migration Komutları

# Tüm şarkıları migrate et php artisan muzibu:migrate-to-bunny --all # Belirli ID aralığı php artisan muzibu:migrate-to-bunny --from=1 --to=1000 # Tek şarkı php artisan muzibu:migrate-to-bunny --song=12345 # Skip existing (cache dosyası ile hızlı) php artisan muzibu:migrate-to-bunny --all --skip-existing --cache-file=/tmp/bunny-existing-hls.txt # Test modu (yüklemez) php artisan muzibu:migrate-to-bunny --all --dry-run # Sadece orijinal MP3'ler php artisan muzibu:migrate-originals --all --skip-existing

Worker Başlatma (Background)

# Timeout limitsiz worker başlat nohup /opt/plesk/php/8.3/bin/php -d max_execution_time=0 \ artisan muzibu:migrate-to-bunny --from=1 --to=10000 \ --skip-existing --cache-file=/tmp/bunny-existing-hls.txt \ > /tmp/bunny-worker1.log 2>&1 &

Redis Komutları

# Mevcut cache'i Redis'e aktar (bir kerelik) php /tmp/import-cache-to-redis.php # Redis'teki şarkı sayısını kontrol et redis-cli SCARD bunny:uploaded_songs # Belirli şarkının Bunny'de olup olmadığını kontrol et redis-cli SISMEMBER bunny:uploaded_songs 12345 # Tüm şarkı ID'lerini listele (dikkat: çok çıktı!) redis-cli SMEMBERS bunny:uploaded_songs | head -20

Cache Dosyası Oluşturma

# Bunny'deki mevcut HLS klasörlerini listele php /tmp/fetch-bunny-list.php # Sonuç: # /tmp/bunny-existing-hls.txt - HLS klasör ID'leri # /tmp/bunny-existing-mp3.txt - MP3 dosya ID'leri

Worker İzleme

# Canlı takip (her 10 saniye) watch -n 10 /tmp/bunny-status.sh # Manuel kontrol for i in 1 2 3 4 5 6 7 8; do echo "W$i: $(tail -1 /tmp/bunny-worker$i.log | grep -oE '[0-9]+/[0-9]+.*%')" done # Çalışan worker sayısı ps aux | grep "migrate-to-bunny" | grep -v grep | wc -l # Worker'ları durdur pkill -f "migrate-to-bunny"

Cache Temizleme (Deploy Sonrası)

# Laravel cache php artisan cache:clear && php artisan view:clear && \ php artisan config:clear && php artisan route:clear && \ php artisan responsecache:clear # Bunny cache (Perma-Cache kullanılıyorsa) # Panel: Pull Zones → muzibuweb → Caching → Purge All

10. Dosya Yapısı

Local Sunucu

/var/www/vhosts/muzibu.com/httpdocs/ ├── storage/ │ └── tenant1001/ │ └── app/public/muzibu/ │ ├── hls/ │ │ └── {song_id}/ │ │ ├── master.m3u8 │ │ ├── enc.bin ← SADECE LOCAL! │ │ ├── ultralow/ │ │ ├── low/ │ │ ├── mid/ │ │ └── high/ │ ├── songs/ │ │ └── {file_path} ← Orijinal MP3 │ ├── mp3_64/ │ │ └── {song_id}.mp3 │ └── mp3_128/ │ └── {song_id}.mp3 ├── app/Services/Bunny/ │ └── BunnyStorageService.php ├── app/Services/ │ └── SignedUrlService.php ← Redis kontrolü └── app/Console/Commands/ ├── MigrateToBunnyCommand.php └── MigrateOriginalsToBunnyCommand.php

Bunny Storage

muzibu-audio/ (Storage Zone) ├── hls/ │ └── {song_id}/ │ ├── master.m3u8 │ ├── ultralow/ │ │ ├── playlist.m3u8 │ │ └── segment_*.ts │ ├── low/ │ ├── mid/ │ └── high/ │ (enc.bin YOK!) ├── mp3_64/ │ └── {song_id}.mp3 ├── mp3_128/ │ └── {song_id}.mp3 └── songs/ └── original/ └── {song_id}.mp3 Redis: └── bunny:uploaded_songs (SET) ├── 12345 ├── 12346 └── ... (33,000+ kayıt)

11. Maliyet Analizi

Eski Maliyet (Cloudflare)

  • Cloudflare Pro $25/ay
  • Cloudflare Argo $5/ay
  • Toplam $30/ay

Yeni Maliyet (Bunny)

  • Bunny Shield Advanced $9.5/ay
  • Storage + Bandwidth Kullanıma göre
  • Sabit Maliyet $9.5/ay

Net Tasarruf

$20.5/ay ($30 - $9.5 = $20.5 tasarruf)

Not: Bunny bandwidth maliyeti kullanıma göre değişir, ancak Cloudflare'den ucuz olması bekleniyor.

12. Önemli Notlar ve Uyarılar

Şifreleme Anahtarları (enc.bin)

HLS şifreleme anahtarları (enc.bin) ASLA Bunny'ye yüklenmez! Bu dosyalar her zaman local sunucudan serve edilir. Player, key'i local'dan alır, şifreli segment'leri Bunny'den alır ve client-side decrypt yapar.

Bunny Shield Sadece muzibuweb'de

Shield koruması sadece muzibuweb pull zone'unda aktif. muzibu-audio-cdn pull zone'unda Shield yok (ses dosyaları için gereksiz). İki pull zone'a da Shield eklemek 2x maliyet demek ($19/ay).

Bunny Stream Kullanılmıyor

Bunny Stream video için tasarlanmış, ses için avantaj sağlamıyor. Bunny destek ekibi de ses içeriği için Stream yerine Storage + CDN önerdi. Mevcut kurulum (Storage Zone + Pull Zone) ses platformu için optimal.

Redis Tracking Avantajları

  • Anlık güncelleme: Yeni şarkı yüklenince anında Redis'e eklenir
  • O(1) performans: 33,000 şarkıda bile ~0.1ms
  • Persistent: Redis restart'ta veri kaybolmaz
  • Fallback güvenliği: Redis'te yoksa = local'dan serve

Perma-Cache vs Origin Shield

İkisi birlikte kullanılamaz. Perma-Cache tercih edildi çünkü:

  • • Dosyalar kalıcı olarak SSD'de cache'lenir
  • • Origin'e neredeyse hiç istek gitmez
  • • İlk istek sonrası her zaman edge'den serve
  • • Müzik dosyaları nadiren değişir, ideal senaryo

Deploy Sonrası Cache Purge

npm run prod sonrası Perma-Cache temizlenmeli:

Bunny Panel → Pull Zones → muzibuweb → Caching → Purge All

Migration Sırasında Dikkat

  • • Worker'lar max_execution_time=0 ile çalışmalı (timeout yok)
  • --skip-existing ile cache dosyası kullan (hızlı)
  • • Cache dosyası olmadan her dosya için HTTP HEAD request atılır (yavaş)
  • • Paralel worker sayısı sisteme göre ayarlanmalı (test: 15 worker OK)

22 Mart 2026 • Muzibu.com

Son güncelleme: 22 Mart 2026, 22:50 (v2 - Redis Tracking eklendi)