İçindekiler
- 1 Neden Büyük Medya Dosyaları İçin Ayrı Bir Yükleme Stratejisi Gerekir?
- 2 PHP Limitleri: upload_max_filesize, post_max_size ve max_execution_time
- 3 Nginx ve Apache Zaman Aşımı Ayarları: PHP’den Önce Duvara Toslamak
- 4 Klasik Form Upload Yaklaşımının Sınırları
- 5 Parçalı (Chunked) Upload Mantığı
- 6 CDN ve Object Storage ile Yükleme Mimarisi Nasıl Hafifler?
- 7 Tarayıcı Tarafında Deneyimi İyileştirmek: Yeniden Deneme, Devam Etme, Paralel Chunk
- 8 Güvenlik, Kota ve Kaynak Yönetimi
- 9 Farklı Hosting Senaryoları İçin Örnek Mimariler
- 10 Operasyonel İpuçları: Test, Gözlem ve Kademeli Geçiş
- 11 Özet ve Yol Haritası: Sadece Limitleri Yükseltmek Değil, Mimariyi Güncellemek Gerek
Neden Büyük Medya Dosyaları İçin Ayrı Bir Yükleme Stratejisi Gerekir?
Video dersler, yüksek çözünürlüklü ürün görselleri, podcast kayıtları veya kullanıcıların kendi videolarını yüklediği platformlar… Tüm bu senaryolarda ortak sorun, birkaç yüz MB hatta GB seviyesindeki dosyaların web üzerinden sorunsuz yüklenmesini sağlamaktır. Klasik tek seferde form upload yaklaşımı, PHP limitleri, Nginx/Apache zaman aşımları ve kullanıcı tarafındaki zayıf bağlantılar yüzünden sık sık duvara toslar.
Özellikle PHP tabanlı uygulamalarda; upload_max_filesize, post_max_size, max_execution_time ve memory_limit gibi ayarlar bir yere kadar esnetilebilir. Ama dosya boyutu büyüdükçe, web sunucusunun (Nginx/Apache) timeout ve body size limitleri, ağ dalgalanmaları ve tarayıcı tarafındaki kısıtlar devreye girer. Sonuç: Yüklemenin ortasında hata alan kullanıcılar, boşa giden bant genişliği ve mutsuz destek biletleri.
Bu yazıda, DCHost ekibi olarak sahada en çok karşılaştığımız sorunlara dayanarak, büyük medya dosyaları için uçtan uca yükleme stratejisi anlatacağız. PHP ve web sunucusu limitlerinin mantığını, Nginx/Apache zaman aşımı ayarlarını, CDN + object storage mimarisini ve en önemlisi de parçalı (chunked) upload yaklaşımını adım adım ele alacağız. Hedefimiz, “şu ayarı biraz daha yükseltelim belki düzelir” seviyesinden çıkıp, sürdürülebilir ve ölçeklenebilir bir mimariye geçmenizi sağlamak.
PHP Limitleri: upload_max_filesize, post_max_size ve max_execution_time
Büyük dosya yüklemelerinde ilk çarpışma genellikle PHP tarafında yaşanır. Çünkü klasik form upload akışında, dosya önce web sunucusundan geçer, ardından PHP tarafından işlenir. PHP’nin varsayılan limitlerini bilmeden hareket ederseniz, daha tarayıcı %30’dayken 413 veya 500 hatalarıyla karşılaşmanız çok normal.
Temel PHP upload ayarları
En kritik PHP ayarları şunlardır:
- upload_max_filesize: Tek bir dosyanın maksimum boyutu
- post_max_size: Tüm POST gövdesinin maksimum boyutu (form alanları + dosyalar)
- max_execution_time: PHP scriptinin en fazla çalışabileceği süre (saniye)
- memory_limit: Bir PHP prosesinin kullanabileceği maksimum bellek
Bu ayarları detaylı anlattığımız PHP ayarlarını doğru yapmak için hazırladığımız rehbere mutlaka göz atmanızı öneririm. Burada sadece büyük dosya bağlamında kritik noktaları vurgulayalım.
post_max_size ve upload_max_filesize ilişkisi
Genel kural: post_max_size >= upload_max_filesize olmalıdır. Örneğin 1 GB’lık tek bir dosyayı izinli kılmak istiyorsanız:
upload_max_filesize = 1024M
post_max_size = 1100M
Araya biraz pay bırakmak mantıklıdır; form alanları, ek metadata vs. POST gövdesinin toplam boyutunu artırır. Ancak bu değerleri yükseltmek tek başına yeterli değildir; hem HTTP sunucusu limitleri hem de PHP’nin çalışma süresi devreye girer.
max_execution_time ve yavaş bağlantılar
Örneğin 1 GB’lık bir dosya düşünelim. Kullanıcı 10 Mbps (yaklaşık 1.25 MB/s) efektif hızla yükleme yapabiliyorsa, teorik minimum süre ~13-14 dakika civarındadır. PHP tarafında max_execution_time = 120 (2 dakika) ise, yükleme hiçbir zaman tamamlanamayacaktır.
Bu yüzden, tek seferde büyük dosya upload senaryosunda max_execution_time değerini ciddi şekilde yükseltmeniz gerekir. Fakat bu da şu riskleri doğurur:
- Uzun süre açık kalan PHP prosesleri, PHP-FPM havuzunu doldurur, diğer istekler kuyrukta bekler.
- Paylaşımlı hosting veya zayıf VPS ortamlarında CPU ve RAM tüketimi sıçrar.
- Kullanıcı bağlantısı ortada koparsa, hem süre hem kaynak boşa gider.
PHP-FPM havuzu ayarlarını (özellikle pm, pm.max_children ve pm.max_requests) boyutlandırırken yükleme süreçlerini de hesaba katmanız gerekir. Bu konuda PHP-FPM ayarlarını nasıl hesaplayacağınızı anlattığımız rehber işinize yarayacaktır.
Nginx ve Apache Zaman Aşımı Ayarları: PHP’den Önce Duvara Toslamak
Birçok ekip sadece PHP ayarlarını yükselttiğinde sorunun çözüleceğini düşünür. Fakat HTTP isteği PHP’ye ulaşmadan önce Nginx veya Apache katmanında da çeşitli sınırlar vardır.
Nginx tarafında kritik direktifler
- client_max_body_size: İstek gövdesinin (body) maksimum boyutu
- client_body_timeout: İstek gövdesinin tamamının gelmesi için tanınan süre
- send_timeout: Sunucunun yanıt gönderirken bekleyeceği maksimum süre
- proxy_read_timeout: Nginx’in arka uca (PHP-FPM, upstream) yaptığı isteğin yanıtını bekleyeceği süre
Örnek bir Nginx konfigürasyon parçası şöyle olabilir:
server {
client_max_body_size 1024M;
client_body_timeout 600s;
location ~ .php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_read_timeout 900s;
}
}
Burada client_max_body_size yükseltilmediği durumda, PHP ayarlarını ne kadar büyütürseniz büyütün, Nginx isteği daha baştan 413 Request Entity Too Large hatasıyla reddeder.
Apache tarafında kritik direktifler
- LimitRequestBody: Maksimum istek gövdesi boyutu
- Timeout: Genel istek/yanıt zaman aşımı
- ProxyTimeout veya ProxyPass ile kullanılan timeout parametreleri
- mod_reqtimeout ile
RequestReadTimeout: Gövde okuma zaman aşımları
Basit bir örnek:
<VirtualHost *:80>
LimitRequestBody 1073741824 # 1 GB
Timeout 900
<Proxy "fcgi://php-fpm">
ProxySet connectiontimeout=600 timeout=900
</Proxy>
</VirtualHost>
Burada da benzer şekilde; istek gövdesi çok yavaş geliyorsa, 408 Request Timeout veya arkadaki PHP-FPM yanıt vermekte gecikiyorsa 504 Gateway Timeout hatalarıyla karşılaşırsınız.
Klasik Form Upload Yaklaşımının Sınırları
Tek seferde, dev bir dosyayı <input type="file" /> ile form post ederek yüklemek, ilk bakışta basit görünür. Ancak pratikte şu problemlerle boğuşursunuz:
- Bağlantı dalgalanmaları: Mobil veya zayıf bağlantılarda upload ortada kopar; baştan başlamak gerekir.
- Kötü kullanıcı deneyimi: Tarayıcı bazen uzun süre yanıt vermiyor gibi görünür; net ilerleme barı yoktur.
- Sunucu kaynak tüketimi: Uzun süren upload’lar PHP-FPM slotlarını meşgul eder, diğer istekler gecikir.
- Güvenli hata yönetimi zorluğu: Hangi aşamada hata olduğunu anlamak zorlaşır; log analizi karmaşıklaşır.
Bu yüzden büyük medya dosyaları için artık endüstri standardı diyebileceğimiz yaklaşım, parçalı (chunked) upload mimarisidir.
Parçalı (Chunked) Upload Mantığı
Parçalı upload’ta dosya, istemci tarafında (tarayıcı veya mobil uygulama) mantıksal parçalara ayrılır. Sunucuya onlarca/yüzlerce küçük istekle gönderilir. Her parça bağımsız olarak doğrulanır ve geçici alana yazılır. Tüm parçalar başarıyla geldikten sonra sunucu bu parçaları birleştirir.
Basit bir akış taslağı
- Init isteği: İstemci, sunucuya dosyanın boyutu, adı, tipi ve isteğe bağlı olarak hash bilgisini gönderir. Sunucu bir
upload_idüretir. - Chunk yüklemeleri: İstemci, dosyanın 0,1,2… numaralı parçalarını bu
upload_idile birlikte gönderir. - Tamamlama isteği: Tüm parçalar başarıyla yüklendikten sonra, istemci “tamamla” isteği atar; sunucu parçaları birleştirir ve kalıcı depolamaya taşır.
- Opsiyonel doğrulama: Başlangıçta gönderilen checksum/hash değeriyle birleşmiş dosya kontrol edilir.
API taslağı: /upload/init, /upload/chunk, /upload/complete
Örnek bir REST API taslağı şöyle olabilir:
POST /upload/init
Body (JSON): {
"filename": "video.mp4",
"size": 734003200,
"mime": "video/mp4",
"checksum": "<opsiyonel SHA256>"
}
Response: {
"upload_id": "abc123",
"chunk_size": 5242880 // 5 MB
}
POST /upload/chunk
Headers:
Upload-Id: abc123
Chunk-Index: 0
Body: binary chunk (5 MB)
POST /upload/complete
Body (JSON): {
"upload_id": "abc123"
}
Bu akışta, yükleme süreci hiçbir zaman tek bir devasa HTTP isteğine bağlı değildir. Bağlantı koparsa, istemci en son hangi chunk’a kadar gittiğini bilir ve sadece eksik parçalardan devam eder.
Tarayıcı tarafında dosyayı parçalara ayırmak
Modern tarayıcılarda File ve Blob API’leriyle dosyayı çok kolay parçalara bölebilirsiniz:
const file = input.files[0];
const chunkSize = 5 * 1024 * 1024; // 5 MB
let offset = 0;
let index = 0;
while (offset < file.size) {
const chunk = file.slice(offset, offset + chunkSize);
await fetch('/upload/chunk', {
method: 'POST',
headers: {
'Upload-Id': uploadId,
'Chunk-Index': index.toString(),
},
body: chunk,
});
offset += chunkSize;
index++;
}
Gerçek hayatta elbette async/await yerine daha gelişmiş hata yönetimi, yeniden deneme (retry) mekanizması, hız limitleme ve kullanıcıya yüzde bazlı ilerleme barı gösterimi gibi detaylar da eklenir.
Sunucu tarafında parçaları birleştirmek
Sunucu tarafında yapılması gerekenler özetle:
- Her chunk’ı geçici bir dizine kaydetmek (ör.
/tmp/uploads/<upload_id>/chunk_0001). - Veritabanında veya KV store’da hangi chunk’ların geldiğini tutmak.
- Tüm chunk’lar hazır olduğunda bunları doğru sıralamayla birleştirmek.
- Birleşmiş dosyayı kalıcı depolamaya (disk, object storage) taşımak.
PHP ile çok basit birleştirme örneği:
$uploadId = $_POST['upload_id'];
$target = "/data/final/{$uploadId}.mp4";
$chunksDir = "/tmp/uploads/{$uploadId}/";
$chunks = glob($chunksDir . 'chunk_*');
natsort($chunks);
$dest = fopen($target, 'wb');
foreach ($chunks as $chunk) {
$src = fopen($chunk, 'rb');
stream_copy_to_stream($src, $dest);
fclose($src);
}
fclose($dest);
Gerçek üretim ortamında, dosya adlarını rastgeleleştirmek, yetkisiz erişime izin vermemek, paralel birleştirmelerde yarış koşullarını engellemek ve hatalı yüklemeleri zaman aşımıyla otomatik temizlemek gerekir.
CDN ve Object Storage ile Yükleme Mimarisi Nasıl Hafifler?
Parçalı upload sadece kullanıcı deneyimini değil, sunucu mimarisini de değiştirir. Büyük medya dosyalarını doğrudan web sunucusunun diskinde tutmak yerine, object storage + CDN kombinasyonuna taşımak neredeyse her projede mantıklı bir adımdır.
Object storage (S3 uyumlu) kullanmak
Object storage, büyük dosyalar için tasarlanmış, HTTP/HTTPS üzerinden erişilen bir depolama türüdür. Klasik dosya sistemi (ext4, XFS vb.) yerine bucket ve object kavramlarıyla çalışır. Temel avantajları:
- Uygun maliyetli, neredeyse sınırsız depolama
- Versioning, lifecycle policy ve cross-region replication gibi kurumsal özellikler
- CDN’lerle doğal entegrasyon
Object storage kavramını detaylı anlattığımız S3 depolama nedir rehberimize göz atarak, altyapınızı buna göre konumlandırabilirsiniz. DCHost tarafında da bu tarz mimarilere uygun VPS ve dedicated sunucu çözümleriyle object storage sistemlerini (örneğin S3 uyumlu MinIO) konumlandırmak oldukça yaygın bir senaryo.
CDN ile global dağıtım ve bant genişliği optimizasyonu
Büyük medya dosyalarını her istekte doğrudan uygulama sunucusundan servis etmek, hem maliyetli hem de performans anlamında verimsizdir. Bunun yerine, dosyayı object storage’a koyup, önüne bir CDN koymak en sağlıklı çözümdür.
CDN mantığını ve ne zaman gerçekten ihtiyaç duyduğunuzu anlattığımız CDN nedir ve web siteniz için avantajları nelerdir başlıklı yazı ile bu konuyu derinlemesine inceleyebilirsiniz.
Özetle mimari şöyle olur:
- İstemci, uygulama API’nize parçalı upload ile dosyayı gönderir.
- Uygulama sunucusu, birleştirilmiş dosyayı object storage’a yükler.
- Uygulama, kullanıcılara bu dosyanın CDN üzerinden erişilecek URL’sini döner.
- Kullanıcılar artık dosyayı doğrudan CDN edge noktalarından çeker.
Böylece:
- Uygulama sunucunuzun bant genişliği ve CPU yükü ciddi oranda azalır.
- Farklı lokasyonlardaki kullanıcılara daha düşük TTFB ve daha stabil hızlar sunabilirsiniz.
WordPress gibi hazır sistemlerde medya yüklemelerini taşımak
Eğer altyapınız WordPress gibi hazır bir CMS’e dayanıyorsa, benzer mantığı eklentilerle kurmak mümkündür. WordPress medyanızı S3’e taşıma rehberimizde hem object storage kullanımını, hem de CDN ile imzalı URL ve cache geçersizleştirme stratejilerini adım adım anlattık. Aynı fikirleri özel geliştirilmiş PHP/Laravel veya Node.js projelerinize de kolayca uyarlayabilirsiniz.
Tarayıcı Tarafında Deneyimi İyileştirmek: Yeniden Deneme, Devam Etme, Paralel Chunk
Parçalı upload sadece sunucunun yükünü hafifletmekle kalmaz; kullanıcı deneyimini de dramatik şekilde iyileştirir.
Yeniden deneme (retry) ve devam etme
Her chunk bağımsız bir HTTP isteği olduğu için, bir veya birkaç chunk başarısız olduğunda istemci sadece bu parçaları yeniden deneyebilir. Ayrıca tarayıcı veya uygulama kapanıp açıldığında, upload_id ve gelen chunk listesi sunucudan sorgulanarak kaldığı yerden devam ettirilebilir.
Paralel chunk gönderimi
Tek bir büyük isteğe kıyasla, 4-8 chunk’ı aynı anda göndermek genellikle daha iyi hat kullanımı sağlar. Ancak bu sayıyı aşırıya kaçırmamak gerekir; aksi halde:
- Sunucuya gereksiz sayıda eş zamanlı bağlantı açarsınız.
- Tarayıcı tarafında da bağlantı limitlerine (özellikle HTTP/1.1) takılabilirsiniz.
Pratikte 3-6 paralel chunk isteği çoğu proje için tatlı noktadır. Bu sayıyı kullanıcı bağlantı kalitesine ve sunucu kapasitesine göre dinamik de ayarlayabilirsiniz.
İlerleme çubuğu, tahmini süre ve kullanıcıya net geri bildirim
Parçalı upload ile her chunk’ın boyutu ve başarı durumu bilindiği için, toplam ilerlemeyi yüzde olarak çok net gösterebilirsiniz. Kullanıcıya örneğin “%43 yüklendi, tahmini kalan süre: 2 dakika” gibi bilgiler vermek, uzun süren upload süreçlerinde destek yükünü de ciddi şekilde azaltır.
Güvenlik, Kota ve Kaynak Yönetimi
Büyük dosya yükleme imkanı sunmak, kötü niyetli kullanıcılar için de cazip bir hedef yaratır. Mimarinizde aşağıdaki unsurları mutlaka düşünmelisiniz:
Maksimum dosya boyutu ve kota politikaları
- Kullanıcı başına günlük / aylık toplam upload kotası
- Tek dosya için maksimum boyut
- Projeye göre MIME type / uzantı beyaz listesi
Bu limitleri sadece PHP/Nginx’te değil, uygulama mantığınızda da kontrol edin. Yani kullanıcı, init isteği attığında dosya boyutu ve tipi kabul edilebilir aralıkta değilse henüz ilk chunk gelmeden reddedilmeli.
Virüs taraması ve içerik denetimi
Çok kiracılı (multi-tenant) SaaS projelerinde veya herkese açık yükleme imkanı verdiğiniz platformlarda, dosyaların en azından temel bir antivirüs taramasından geçmesi kritik olabilir. Bunu upload akışından tamamen ayrı, asenkron bir iş kuyruğu ile çözmek en doğrusudur:
- Upload tamamlanır, dosya object storage’a alınır.
- Bir iş kuyruğu (queue) kaydı oluşur: “dosya_id = X, taranacak”.
- Arka planda çalışan worker, dosyayı çekip tarar, sonucu veritabanına işler.
- Şüpheli içerikler otomatik olarak erişime kapatılır veya manuel onaya düşer.
Loglama ve izleme
Büyük dosya upload’larında sorun çıktığında kök nedeni anlamak için iyi loglama şarttır:
- Web sunucusu (Nginx/Apache) access ve error logları
- PHP-FPM logları (slow log dahil)
- Uygulama logları:
upload_id, kullanıcı kimliği, chunk index, hata kodu
Sunucu loglarını daha iyi okumak ve 4xx–5xx hatalarının kaynağını teşhis etmek için hazırladığımız Nginx ve Apache loglarını okuma rehberine mutlaka göz atın. Büyük upload hatalarında oradaki yöntemler doğrudan işinize yarayacaktır.
Farklı Hosting Senaryoları İçin Örnek Mimariler
DCHost tarafında gördüğümüz projelerde, yükleme mimarisi genellikle kullanılan hosting türüne göre şekilleniyor. Birkaç tipik senaryoyu özetleyelim.
Senaryo 1: paylaşımlı hosting + sınırlı sayıda büyük dosya
Küçük bir eğitim sitesi düşünelim; ayda birkaç kez 200–300 MB’lık video yükleniyor, kullanıcı sayısı çok yüksek değil. Burada:
- PHP ve Nginx/Apache limitleri makul seviyede yükseltilebilir.
- Parçalı upload tek endpoint üzerinden bile ciddi fark yaratır.
- Dosyalar başlangıçta lokal diskte tutulup, periyodik olarak daha kalıcı depolamaya taşınabilir.
Paylaşımlı hosting’in CPU/RAM limitlerine çok yaklaşmadan, nispeten basit bir parçalı upload kurgusuyla bu senaryo yürütülebilir.
Senaryo 2: DCHost VPS + Object Storage + CDN
Orta ölçekli bir SaaS veya e-ticaret altyapısı için önerdiğimiz mimari genelde şöyledir:
- Uygulama, bir veya birden fazla DCHost VPS üzerinde çalışır.
- Medya dosyaları, ayrı bir object storage katmanında tutulur.
- Statik içerik ve medyalar CDN üzerinden dağıtılır.
- Upload işlemi, parçalı upload ile API sunucusuna, oradan da object storage’a akar.
Bu mimaride, hem web uygulamasını hem de medya trafiğini ayrı ayrı ölçeklemek çok daha kolaylaşır. Ayrıca CDN ve görüntü optimizasyonu tarafını da devreye almak isterseniz, görüntü optimizasyonu boru hattı rehberimizde AVIF/WebP dönüşümü ve CDN cache stratejilerini ayrıntılı olarak anlattık.
Senaryo 3: Dedicated sunucu + yoğun medya trafiği
Günlük on binlerce büyük dosya yüklemesi ve indirmesi yapan platformlarda, genellikle:
- Upload API’si için ayrı bir dedicated sunucu veya güçlü VPS havuzu
- Arka planda çalışan medya işleme (transcoding, thumbnail üretimi) kuyruğu
- Çok bölgeli CDN ve coğrafi çoğaltmalı object storage
gibi daha karmaşık kurgular kullanıyoruz. Burada en önemli konu, upload trafiğini ana uygulama trafiğinden olabildiğince ayırmak ve her katmanın (uygulama, depolama, CDN) ayrı ayrı ölçeklenebilmesi.
Operasyonel İpuçları: Test, Gözlem ve Kademeli Geçiş
Büyük dosya upload stratejisini bir gecede tamamen değiştirmek zorunda değilsiniz. DCHost tarafında projelerle çalışırken genellikle şu adımlarla ilerliyoruz:
- Önce mevcut sistemdeki en büyük dosya boyutlarını, hata oranlarını ve tipik kullanıcı bağlantı hızlarını ölçüyoruz.
- PHP ve Nginx/Apache limitlerini, yalnızca ihtiyacınız kadar esnetiyoruz.
- Yeni parçalı upload API’sini küçük bir kullanıcı grubuna açıyoruz.
- Log ve metrikleri takip ederek, timeout ve chunk boyutlarını optimize ediyoruz.
- Son aşamada, klasik upload yolunu tamamen kapatıp herkes için parçalı upload’a geçiyoruz.
Böyle bir kademeli geçiş planı, hem teknik riskleri azaltır hem de ekip içindeki öğrenme sürecini daha yönetilebilir hale getirir.
Özet ve Yol Haritası: Sadece Limitleri Yükseltmek Değil, Mimariyi Güncellemek Gerek
Büyük medya dosyaları için sağlıklı bir yükleme deneyimi, sadece upload_max_filesize ve client_max_body_size değerlerini yükseltmekle çözülecek bir konu değil. Tarayıcı, PHP, Nginx/Apache, depolama ve CDN katmanlarının hepsini birlikte düşünmek gerekiyor. Parçalı (chunked) upload yaklaşımı, hem kullanıcı deneyimini hem de sunucu tarafı kaynak kullanımını kökten iyileştiriyor.
Bu yazıda, PHP ve web sunucusu limitlerinin mantığını, Nginx/Apache timeout ayarlarını, object storage + CDN mimarisini ve parçalı upload’ın temel tasarımını özetledik. Bir sonraki adımda, projenizin trafik profilini, medya boyutlarını ve büyüme planını masaya yatırıp, size özel bir yükleme mimarisi tasarlamak en doğrusu olacaktır.
Eğer büyük dosya yükleme süreçleriniz sık sık hata üretiyorsa, kullanıcılarınızdan “yükleme yarıda kaldı” şikayetleri geliyorsa veya mevcut sunucunuz bu trafiği taşımakta zorlanıyorsa, DCHost ekibi olarak uygulama + altyapı tarafını birlikte ele alabileceğimiz bir mimari çalıştay yapabiliriz. Yeni bir VPS, dedicated sunucu ya da mevcut altyapınız üzerinde, sürdürülebilir bir büyük medya dosyaları yükleme stratejisi kurmak için bizimle iletişime geçmeniz yeterli.
