Bir akşam oturup docker compose up -d yazdınız. Nextcloud, Vaultwarden, Uptime Kuma ve bir de fotoğraf arşivi için Immich. Hepsi ayağa kalktı, tarayıcıdan açıldı, mükemmel görünüyor. Ertesi sabah panele girmeye çalıştığınızda sayfa açılmıyor, SSH oturumu bağlanıyor ama komut satırı saniyelerce donuyor. dmesg -T çıktısında bir satır gözünüze çarpıyor: Out of memory: Killed process 1284 (mysqld).
Bu senaryo self-hosted dünyasının en yaygın ilk kazasıdır ve sebebi neredeyse her zaman aynıdır: uygulamaların kurulum anındaki tüketimine bakılarak sunucu seçilmiş, ancak veri büyüdükçe, ilk yedek alındığında ya da ilk küçük resim üretimi başladığında oluşan tepe tüketim hesaba katılmamıştır. "Nextcloud 512 MB ile çalışır" cümlesi teknik olarak yanlış değildir; boş bir Nextcloud gerçekten çalışır. Sorun, boş Nextcloud'un yanına MariaDB, Redis, bir ters vekil sunucu, Docker servisinin kendisi ve işletim sistemi eklendiğinde ortaya çıkan toplamdır.
Bu yazıda tahmin yürütmek yerine katman katman hesap yapacağız: önce işletim sisteminin ve Docker'ın sabit payını çıkaracağız, sonra popüler uygulamaların boştaki ve yük altındaki gerçekçi aralıklarını tablolayacağız, ardından üç farklı sunucu boyutunda (2 GB, 4 GB, 8 GB) neyin sığıp neyin sığmadığını toplama yaparak göstereceğiz. Sonunda kendi kurulumunuzu ölçebileceğiniz komutlar ve OOM Killer'a düşmemek için bırakmanız gereken pay da var.
Sunucunun RAM'i Nereye Gidiyor? Üç Katmanlı Hesap#
Self-hosted bir sunucuda bellek üç katmana ayrılır ve bu katmanların ikisi genellikle unutulur.
1. Taban katman (sabit gider). İşletim sisteminin çekirdeği, systemd birimleri, SSH sunucusu, günlük servisleri ve Docker arka plan süreci. Bu katman uygulamalarınız hiçbir şey yapmasa bile hep oradadır ve masaüstü içermeyen bir Ubuntu 24.04 kurulumunda tipik olarak 250-400 MB civarındadır. Docker arka plan süreci tek başına 80-150 MB ekler.
2. Uygulama katmanı (değişken gider). Container'ların kendisi. Buradaki kritik ayrım, "boştaki" ve "tepe" değerlerin bazen beş-on kat farklı olmasıdır. Bir Immich kurulumu boşta 1,5 GB kullanırken yüz tanıma işi kuyruğa girdiğinde 4 GB'ı zorlayabilir.
3. Sayfa önbelleği (görünürde boş ama gerçekte çalışan bellek). Linux, kullanılmayan RAM'i disk önbelleği olarak değerlendirir. Bu alan teknik olarak geri alınabilir olsa da tamamen sıfıra indiğinde veritabanı sorguları her seferinde diske gider ve sunucu, bellek yetiyor gözükmesine rağmen sürünmeye başlar. Bu yüzden hesabınızda en az yüzde 20-25 boş pay bırakmak bir lüks değil, performansın parçasıdır.
Formül olarak yazarsak:
Gereken RAM = (OS + Docker) + toplam uygulama tepe değerleri + veritabanı payı + %25 pay
Buradaki en sinsi kalem "toplam uygulama tepe değerleri". İyi haber şu ki tüm uygulamalar aynı anda tepe yapmaz; kötü haber şu ki gece 03:00'te çalışan yedekleme görevi, medya tarayıcısı ve OCR kuyruğu genellikle aynı saate ayarlanmıştır. Zamanlanmış görevleri farklı saatlere dağıtmak, tek başına bir-iki GB'lık sunucu farkını kapatabilir.
Popüler Self-Hosted Uygulamaların Gerçek RAM Tüketimi#
Aşağıdaki tablo, Docker ile kurulmuş tipik tek kullanıcılı veya küçük ekip kurulumlarında gözlenen aralıkları verir. Rakamlar container'ın kendi tüketimidir; ayrı çalışan veritabanı bir sonraki bölümde ayrıca sayılır.
| Uygulama | Boşta | Yük altında tepe | Notlar |
|---|---|---|---|
| Vaultwarden | 15-40 MB | 60 MB | Rust ile yazıldığı için sınıfının en hafifi |
| Uptime Kuma | 120-250 MB | 350 MB | İzlenen hedef sayısıyla doğrusal artar |
| Portainer | 50-100 MB | 150 MB | Sadece arayüz, iş yükü taşımaz |
| Grafana | 100-200 MB | 300 MB | Panel sayısı ve sorgu sıklığına bağlı |
| Gitea | 120-300 MB | 600 MB | Büyük klon ve bakım işlerinde sıçrar |
| Nginx Proxy Manager / Traefik | 50-150 MB | 250 MB | Sertifika yenileme anında kısa tepe |
| BookStack / Wiki.js | 150-400 MB | 600 MB | PHP-FPM işçi sayısı ya da Node yığını |
| Nextcloud (PHP-FPM) | 250-500 MB | 1 GB üzeri | Önizleme üretimi ve bakım görevleri en pahalı kısım |
| n8n | 250-450 MB | 800 MB - 1,5 GB | Büyük JSON taşıyan iş akışları belleği zorlar |
| Mattermost | 300-500 MB | 800 MB | Eklenti kullanıyorsanız üst sınırı alın |
| Jellyfin | 200-400 MB | 1 - 1,5 GB | Yazılımsal transkod tek başına 500 MB - 1 GB ekler |
| Home Assistant | 500 MB - 1 GB | 1,5 GB | Entegrasyon sayısı belirleyici |
| Paperless-ngx | 350-500 MB | 1 - 1,5 GB | OCR kuyruğu tepe yapar |
| Prometheus | 200-400 MB | 2 GB üzeri | Zaman serisi sayısıyla neredeyse doğrusal |
| Immich | 1,2 - 2 GB | 3 - 4 GB | Makine öğrenmesi container'ı ayrı bir canavardır |
Tablodan çıkarılacak iki pratik ders var. Birincisi, hafif uygulamalar gerçekten çok hafiftir: Vaultwarden, Uptime Kuma ve Portainer üçlüsü toplamda 400 MB'ı zor bulur. İkincisi, medya ve yapay zekâ işleri kural dışıdır: Immich veya transkod yapan bir Jellyfin kurulumu tek başına, diğer on uygulamanın toplamından fazla bellek isteyebilir.
Bu aralıkları bir kanun gibi değil, planlama başlangıcı olarak kullanın. Aynı uygulama SQLite yerine PostgreSQL ile, ya da ARM yerine x86 üzerinde farklı davranır. Kendi rakamlarınızı nasıl ölçeceğinizi birazdan göstereceğiz.
Veritabanı ve Yardımcı Servislerin Unutulan Payı#
Uygulama listesini toplayıp "tamam, 2 GB yeter" diyen kurulumların çoğu burada tökezler. Veritabanları varsayılan ayarlarıyla göründüğünden fazlasını tutar.
| Servis | Tipik tüketim | Dikkat edilecek ayar |
|---|---|---|
| MariaDB / MySQL | 300-450 MB | Arabellek havuzu varsayılanı küçük olsa da süreç toplamı çok üstündedir |
| PostgreSQL | 60-150 MB + bağlantı başına 5-10 MB | shared_buffers ve max_connections çarpımı gerçek maliyettir |
| Redis | 15-50 MB | maxmemory tanımlanmazsa sınırsız büyür; mutlaka sınırlayın |
| Docker arka plan süreci | 80-150 MB | Container sayısıyla yavaşça artar |
| İşletim sistemi (Ubuntu 24.04 sunucu) | 250-400 MB | Masaüstü paketleri kurulmuşsa 1 GB'ı geçer |
maxmemory tanımlanmamış bir Redis, self-hosted sunucuların en sessiz bellek sızıntısıdır: önbellek olarak kullanıldığı için hiçbir şey bozulmaz, sadece bellek yavaş yavaş dolar ve bir gün OOM Killer başka bir süreci öldürür. Yapılandırma dosyasına iki satır yazmak bu riski tamamen kapatır:
maxmemory 256mb
maxmemory-policy allkeys-lru
Aynı şekilde MariaDB'yi küçük sunucularda dizginlemek isterseniz arabellek havuzunu bilinçli olarak küçültün. Veritabanı ayarlarının performansa etkisini MySQL ve MariaDB performans optimizasyonu yazısında ayrıntılı ele aldık.
[mysqld]
innodb_buffer_pool_size = 256M
max_connections = 40
performance_schema = OFF
performance_schema = OFF satırı tek başına 150-200 MB kazandırır ve küçük kurulumlarda kaybettiğiniz tek şey, muhtemelen hiç bakmayacağınız iç metriklerdir.
Kendi Sunucunuzda RAM'i Nasıl Doğru Ölçersiniz?#
Tahmin tablosundan çıkıp gerçeğe geçmenin yolu üç komuttan geçer. Birincisi genel tablo:
free -h
Buradaki en önemli sütun free değil available sütunudur. Linux boş RAM'i disk önbelleğine ayırdığı için free sütunu neredeyse her zaman düşük görünür; bu bir sorun değildir. Panik butonuna available değeri toplam belleğin yüzde 10'unun altına indiğinde basılır. Bu çıktının satır satır nasıl okunacağını Linux bellek kullanımı ve free analizi yazısında anlattık.
İkincisi container bazında dağılım:
docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}"
Bu komutu bir kez değil, farklı zamanlarda çalıştırın: yedekleme görevinin hemen sonrasında, bir dosya yüklerken, medya kütüphanesi taranırken. Tepe değeri yakalamanın başka yolu yoktur. Uzun süreli izleme istiyorsanız Uptime Kuma yerine Prometheus ve Grafana ikilisi daha uygun bir araçtır, ancak o ikilinin kendisinin de 400-600 MB istediğini hesaba katın.
Üçüncüsü, container dışında kalan süreçleri de gören sistem geneli görünüm:
# Kontrol grubu bazında canlı sıralama
systemd-cgtop -m
# Paylaşılan kütüphaneleri iki kez saymayan gerçekçi süreç raporu
sudo apt install ps_mem -y
sudo ps_mem | tail -20
ps_mem, ps aux çıktısının aksine paylaşılan bellek sayfalarını mükerrer saymaz; bu yüzden "her PHP-FPM işçisi 90 MB kullanıyor, 10 işçi var, demek ki 900 MB" gibi yanlış hesaplardan sizi kurtarır. Gerçek rakam genellikle bunun üçte biri kadardır.
Son olarak geçmişte bir OOM olayı yaşanıp yaşanmadığını kontrol edin:
sudo dmesg -T | grep -iE "out of memory|killed process"
sudo journalctl -k --since "7 days ago" | grep -i oom
Bu komutlar boş dönüyorsa sunucunuz henüz sınıra dayanmamış demektir. Dönüyorsa, hangi sürecin öldürüldüğü satırın içinde yazar ve bu bilgi doğrudan yükseltme kararınızı belirler.
2 GB, 4 GB ve 8 GB Sunucuda Gerçekte Ne Sığar?#
Şimdi toplama yapalım. Her senaryoda taban katman olarak işletim sistemi 350 MB artı Docker 120 MB, toplam 470 MB sabit gider var.
2 GB: Hafif servisler ve tek veritabanı#
| Kalem | Ayrılan |
|---|---|
| Taban katman | 470 MB |
| Vaultwarden + Uptime Kuma + Portainer | 400 MB |
| Nginx Proxy Manager | 120 MB |
| MariaDB (küçültülmüş) | 300 MB |
| Toplam kullanım | 1,3 GB |
| Kalan pay | 700 MB |
Bu kurulum rahat çalışır. Buraya Nextcloud eklemeye kalkarsanız 1,3 GB üzerine 500 MB binerek 1,8 GB'a çıkarsınız ve ilk büyük dosya yüklemesinde tepe değer sınırı aşar. 2 GB, hafif servisler için doğru, dosya ve medya için yanlış tercihtir.
4 GB: Klasik kişisel bulut#
| Kalem | Ayrılan |
|---|---|
| Taban katman | 470 MB |
| Nextcloud (tepe değer) | 900 MB |
| MariaDB | 400 MB |
| Redis (sınırlı) | 150 MB |
| Ters vekil sunucu | 120 MB |
| Gitea + Vaultwarden + Uptime Kuma | 450 MB |
| Toplam kullanım | 2,5 GB |
| Kalan pay | 1,5 GB |
Bu, self-hosted kurulumların tatlı noktasıdır. Nextcloud tepe yaptığında bile 1,5 GB'lık pay onu emer, sayfa önbelleği için de yer kalır. Çoğu ev veya küçük ofis kurulumu için doğru başlangıç 4 GB'dır.
8 GB: Medya, otomasyon veya fotoğraf arşivi girdiğinde#
| Kalem | Ayrılan |
|---|---|
| Taban katman | 470 MB |
| Immich (makine öğrenmesi dahil, tepe) | 3,5 GB |
| PostgreSQL | 400 MB |
| Jellyfin (transkod anı) | 1,2 GB |
| n8n | 700 MB |
| Diğer hafif servisler | 500 MB |
| Toplam kullanım | 6,8 GB |
| Kalan pay | 1,2 GB |
Görüldüğü gibi tek bir Immich, 4 GB'lık bir sunucuyu tek başına tüketir. Fotoğraf arşivi kuracaksanız 8 GB alt sınırdır; Immich makine öğrenmesi modelini kapatırsanız 5-6 GB ile de idare edilebilir ama yüz tanıma ve akıllı arama özelliklerinden vazgeçmiş olursunuz.
Bu senaryolar işlemci tarafını kapsamaz; çekirdek sayısı ve sanal işlemci seçiminin nasıl yapılacağını VDS için kaç CPU ve RAM gerekir yazısında ayrıca ele aldık.
Swap Ne Zaman Kurtarır, Ne Zaman Sunucuyu Yavaşlatır?#
Swap konusunda iki uç görüş dolaşır: "SSD çağında swap gereksiz" ve "swap açarsan RAM sorunun biter". İkisi de yanlıştır.
Swap'ın kurtardığı durum: Uygulamaların uzun süre dokunmadığı bellek sayfaları vardır; başlangıçta bir kez okunan yapılandırma, hiç kullanılmayan bir eklentinin kodu gibi. Çekirdek bunları diske taşıyıp yerini gerçek çalışan verilere bırakır. Bu, ölçülebilir bir kazançtır ve tepe anlarında OOM Killer ile aranıza tampon koyar.
Swap'ın yavaşlattığı durum: Aktif olarak kullanılan veri swap'a inmeye başladığında sistem sürekli sayfa takası yapar. Sunucu ölmez ama SSH bile yanıt vermez hâle gelir; çoğu kişinin "swap kötüymüş" dediği an tam olarak budur. Bu durum swap'ın suçu değil, RAM'in gerçekten yetmediğinin göstergesidir.
Pratik kural: swap'ı emniyet supabı olarak açın, kapasite olarak değil. 4 GB RAM'li bir sunucuda 2 GB swap yeterlidir; 4 GB swap koymak sadece çöküşü uzatır.
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Ardından çekirdeğin swap'a ne kadar istekli olacağını ayarlayın. Varsayılan 60 değeri sunucular için fazla agresiftir:
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swap.conf
sudo sysctl --system
Adım adım anlatım ve kalıcılık kontrolleri için Linux'ta swap alanı oluşturma yazısına bakabilirsiniz. Diskin yavaş olduğu ortamlarda sıkıştırılmış bellek daha iyi bir seçenektir:
sudo apt install systemd-zram-generator -y
sudo tee /etc/systemd/zram-generator.conf > /dev/null <<CONF
[zram0]
zram-size = ram / 4
compression-algorithm = zstd
CONF
sudo systemctl daemon-reload
sudo systemctl start [email protected]
zram, sayfaları diske değil RAM içinde sıkıştırarak saklar; tipik üçte bir sıkıştırma oranıyla 1 GB'lık zram alanı yaklaşık 3 GB'lık veriyi tutabilir ve disk gecikmesi yaşanmaz.
OOM Killer'a Düşmemek İçin Container Sınırları#
Sınırsız bırakılan bir container, hata durumunda tüm sunucuyu aşağı çeker. Çekirdek hangi süreci öldüreceğine karar verirken en çok bellek tüketeni değil, en yüksek OOM puanına sahip olanı seçer ve bu genellikle veritabanınız olur. Yani hatayı n8n yapar, bedelini MariaDB öder.
Çözüm, her servise üst sınır koymaktır. Docker Compose dosyasında:
services:
n8n:
image: n8nio/n8n
mem_limit: 768m
memswap_limit: 768m
restart: unless-stopped
mariadb:
image: mariadb:11
mem_limit: 512m
restart: unless-stopped
memswap_limit değerini mem_limit ile eşitlemek, container'ın swap'a taşmasını tamamen engeller: sınırı aşan container swap'ı doldurup sunucuyu yavaşlatmak yerine kendi içinde başarısız olur ve yeniden başlatma politikasıyla temiz şekilde ayağa kalkar. Bu, "tüm sunucu donuyor" ile "bir servis 20 saniye kesildi" arasındaki farktır.
Veritabanı gibi kritik süreçleri çekirdeğin gözünde daha korunaklı hâle getirmek de mümkündür:
# Çalışan bir süreci OOM seçiminde geri plana at
sudo choom -n -500 -p $(pgrep -o mariadbd)
Kullanıcı bazında süreç ve bellek sınırlarını nasıl koyacağınızı ulimit ile kaynak limitleri yazısında bulabilirsiniz. Container mantığına yeni başlıyorsanız önce Docker temelleri yazısıyla zemini kurmanız işinizi kolaylaştırır.
Hangi Paketi Almalısınız? Karar Tablosu#
| Kuracağınız şey | Önerilen RAM | Neden |
|---|---|---|
| Şifre kasası, izleme, yer imi, küçük wiki | 2 GB | Toplam tepe 1,5 GB'ı geçmez |
| Kişisel bulut (Nextcloud, veritabanı, birkaç hafif servis) | 4 GB | Nextcloud tepesi tek başına 1 GB |
| Git sunucusu ve geliştirme araçları | 4 GB | Depo bakım işleri tampon ister |
| Otomasyon (n8n), veritabanı ve izleme yığını | 6-8 GB | Büyük iş akışları 1,5 GB'a çıkabilir |
| Transkod yapan medya sunucusu | 8 GB | Eşzamanlı iki akış 2 GB'ı bulur |
| Fotoğraf arşivi (yüz tanıma açık) | 8-16 GB | Makine öğrenmesi container'ı tek başına 3-4 GB |
| Yukarıdakilerden üç veya daha fazlası birlikte | 16 GB | Tepe çakışması kaçınılmaz hâle gelir |
Karar verirken iki noktayı hatırlayın. Birincisi, RAM sonradan yükseltilebilir ama veri taşımak zahmetlidir; sınırda bir paket seçip altı ay sonra taşınmaktansa bir kademe yukarıdan başlamak genellikle daha ucuza gelir. İkincisi, disk alanı ve dosya düğümü sayısı da bağımsız bir sınırdır; fotoğraf ve belge arşivlerinde inode ve disk kotası konusunu da hesaba katın.
Sıkça Sorulan Sorular#
4 GB RAM ile kaç Docker container çalıştırabilirim?#
Sayı değil toplam tüketim belirleyicidir. Vaultwarden, Uptime Kuma, Portainer, Gitea gibi hafif servislerden on-on iki tanesi 4 GB'a rahat sığar; buna karşılık tek bir Immich kurulumu aynı sunucuyu tek başına doldurur. Kurulum öncesi her container için tablodaki tepe değeri toplayın, üzerine işletim sistemi ve veritabanı payını ekleyin, çıkan rakamın toplam belleğin yüzde 75'ini geçmediğinden emin olun.
Swap açarsam daha az RAM'li paket alabilir miyim?#
Hayır. Swap, tepe anlarını yumuşatan bir emniyet supabıdır; sürekli kullanılan veri için RAM'in yerini tutmaz. Aktif veri swap'a inmeye başladığında sunucu çökmez ama disk erişimi bellekten yüzlerce kat yavaş olduğu için pratikte kullanılamaz hâle gelir. Swap'ı 2 GB gibi mütevazı bir boyutta tutup asıl kapasiteyi RAM'den satın almak doğru yaklaşımdır.
RAM doluyor ama sunucu yavaş değil, sorun var mı?#
Muhtemelen yok. Linux boşta duran belleği disk önbelleği olarak kullanır ve bu, sunucunuzun hızlanmasını sağlar. free -h çıktısındaki boş bellek sütununun düşük olması normaldir; bakmanız gereken kullanılabilir bellek sütunudur. Bu değer toplam belleğin yüzde 10'unun altına inmişse ve çekirdek günlüklerinde OOM satırları görünüyorsa gerçek bir sorun var demektir.
Container'lara bellek sınırı koymak performansı düşürür mü?#
Sınırı doğru belirlediğiniz sürece hayır. Sınır, container'ın normalde kullandığı tepe değerin biraz üzerinde olmalıdır; bu durumda uygulama sınıra hiç dokunmaz ve hiçbir performans farkı oluşmaz. Sınırın asıl faydası, bir hata veya bellek sızıntısı durumunda sorunun tek container ile sınırlı kalması ve veritabanınızın OOM Killer tarafından öldürülmemesidir.
Aynı sunucuda hem Nextcloud hem Immich çalıştırabilir miyim?#
Teknik olarak evet ama 8 GB'ın altında tavsiye edilmez. Nextcloud tepede 1 GB, Immich makine öğrenmesi container'ıyla birlikte 3-4 GB ister; iki veritabanı, ters vekil sunucu ve işletim sistemi payı eklendiğinde 7 GB civarına çıkarsınız. 8 GB ile çalışır ancak pay dardır. Immich'in makine öğrenmesi bileşenini devre dışı bırakırsanız 6 GB'lık bir sunucuda da idare edebilirsiniz.
Bellek tüketimini hangi aralıklarla ölçmeliyim?#
Kurulumdan hemen sonra bir kez ölçmek yanıltıcıdır çünkü veri henüz birikmemiştir. İlk hafta boyunca günde birkaç kez anlık ölçüm alın, özellikle yedekleme ve tarama görevlerinin çalıştığı saatlerde. Kalıcı çözüm için Prometheus ile sürekli kayıt tutmak en sağlıklısıdır; böylece haftalar içindeki büyüme eğilimini görüp yükseltme kararını sunucu çökmeden önce verebilirsiniz.