DevOps

Node.js Lokalde Çalışıp VPS’de Çökünce Ne Yapmalı?

Geçen ay başıma gelen bir şeyi anlatmam lazım. Bir Node.js uygulaması geliştirdim — lokalde her şey tıkır tıkır çalışıyor, testler geçiyor, API endpoint’leri doğru cevap veriyor, her şey yolunda görünüyor. “Tamam, hazır” dedim ve DigitalOcean’daki VPS’e deploy ettim. Ve… hiçbir şey çalışmıyor. Hata mesajları saçma sapan, loglarda anlamsız stack trace’ler var, ne tarafa baksam farklı bir sorun çıkıyor. Aynı kod, aynı işletim sistemi, aynı Node versiyonu — en azından öyle sanıyordum.

Üç gün boyunca kafayı yedim. Cidden. Üç gün. Sonunda suçluyu buldum: PM2, terminalde gördüğüm Node.js versiyonundan bambaşka bir versiyon kullanıyormuş. Hani şu “bende çalışıyor” meme’ini herkes bilir ya — işte tam o durumun gerçek hayattaki, uykusuz gecelere mal olan, saçları döktüren versiyonu.

Sorunun Kökü: “Aynı Ortam” Diye Bir Şey Yok

Bakın şimdi. Geliştiricilerin en sık düştüğü tuzak şu: “İki makine aynı” varsayımı. Ama değil. Hiçbir zaman tam olarak aynı değil. İşletim sistemi Ubuntu 22.04 olabilir ikisinde de, node -v yazdığında ikisi de v18.17.0 gösterebilir — ama altta dönen süreçler, ortam değişkenleri, PATH sıralaması, hangi kullanıcıyla ne kurulduğu, sistem servislerinin neyi referans aldığı… bunların hepsi bambaşka olabiliyor ve siz farkında bile olmuyorsunuz.

Ben 2023’ün sonlarında bir e-ticaret projesi için tam olarak bu duruma düştüm. İstanbul’daki bir müşterinin ödeme altyapısını Node.js ile yazmıştım. Lokalde gayet düzgün çalışıyor — “mükemmel” demeyeyim, “mükemmel” kelimesi jinx getiriyor sanki (bizzat test ettim). VPS’e atınca? Ödeme callback’leri timeout yiyor, async/await’ler garip davranıyor, hiçbir şey mantıklı gelmiyor. İlk düşüncem network oldu tabi. Firewall ayarları, port yönlendirmeleri… hepsini teker teker kontrol ettim.

Şimdi gelelim işin can alıcı noktasına.

Oysa sorun çok daha basitti. Ama basit olması, kolay bulunacağı anlamına gelmiyor maalesef (ki bu çoğu kişinin gözünden kaçıyor)

PM2 ve NVM: Sessiz Katil İkili

Sorunun kaynağını anlamak için önce şunu bilmek lazım: NVM (Node Version Manager) kullandığınızda, her Node versiyonunun kendine ait bir binary yolu var. Mesela şöyle:

/home/kullanici/.nvm/versions/node/v18.17.0/bin/node
/home/kullanici/.nvm/versions/node/v16.20.0/bin/node

Siz terminalde nvm use 18 dediğinizde, o anki shell oturumunuz v18’i kullanmaya başlıyor. Güzel. Ama PM2’yi daha önce — mesela v16 aktifken — global olarak kurduysanız, PM2 hâlâ v16’nın binary’sini kullanıyor olabilir. Terminal size v18 diyor, PM2 arka planda v16 ile sessiz sedasız çalışıyor. Siz de bunu bilmeden hayatınıza devam ediyorsunuz.

Dur bir saniye, şunu da ekleyeyim: bu sadece NVM ile olan bir sorun değil. Snap ile Node kurduysanız, apt ile ayrı bir versiyon varsa, hatta Docker container’ının içinde farklı bir PATH tanımlıysa… hep aynı tuzak. Ama en yaygın senaryo kesinlikle NVM + PM2 kombinasyonu. Bu ikili, pek çok geliştiricinin hafızasına kötü bir anı olarak kazınmıştır.

Sorunu Teşhis Etmek

İlk yapmanız gereken şey — ve ben bunu üç gün sonra yaptığım için kendime gerçekten kızıyorum — PM2’nin hangi Node versiyonunu kullandığını kontrol etmek:

# Uygulamanızın detaylı bilgilerini görmek için
pm2 show uygulama-adi
# Veya doğrudan ortam değişkenlerini incelemek için
pm2 env 0

Bu komutları çalıştırdığınızda “node version” veya “exec_interpreter” gibi alanları arayın. Orada yazan versiyonla node -v çıktısı farklıysa… tebrikler, sorunu buldunuz.

Bilmem anlatabiliyor muyum, Ben kendi projemde baktığımda şok olmuştum (en azından benim deneyimim böyle). Terminal v18.17.0 diyor, PM2 ise v16.14.2 kullanıyor — ikisi arasında optional chaining, top-level await gibi ciddi özellik farkları var, kodumda kullandığım bazı ES2022 feature’ları v16’da desteklenmiyordu — itiraf edeyim, beklentimin üstündeydi —. İşte tüm o garip hataların sebebi buymuş. Üç günlük uğraşın cevabı buymuş. Hani ne farkı var diyorsunuz, değil mi? Valla insan gülüyor sonunda.

Çözüm: Adım Adım Düzeltme

Tamam, sorunu bulduk. Şimdi nasıl düzelteceğiz? Birkaç farklı yöntem var, en güvenilir olanları sıralıyorum.

Yöntem 1: PM2’yi Doğru Versiyonla Yeniden Kurmak

Bu en temiz çözüm. Lafı gevelemeden direkt adımları veriyorum:

# Önce istediğiniz Node versiyonuna geçin
nvm use 18
# Mevcut PM2 süreçlerini durdurun
pm2 kill
# PM2'yi bu versiyon altında yeniden kurun
npm install -g pm2
# PM2 ortam değişkenlerini güncelleyin
pm2 update
# Uygulamanızı yeniden başlatın
pm2 start app.js --name uygulama-adi
# Doğrulama yapın
pm2 show uygulama-adi

Ha, bu arada pm2 update komutunu atlamayın sakın. Bu komut PM2’nin daemon’ını yeniden başlatıyor ve yeni ortam değişkenlerini almasını sağlıyor. Bunu yapmadan sadece restart atarsanız, eski versiyon hâlâ geçerli olabilir. Küçük ama kritik bir adım.

Yöntem 2: Ecosystem Dosyasında Interpreter Belirtmek

Bu yöntem bence daha sağlam —. Konfigürasyonu dosyaya yazıyorsunuz, yani yarın bir gün sunucuda başka biri bir şey kurarsa veya NVM versiyonu değişirse, PM2 hâlâ doğru Node’u kullanıyor olacak. Belgelenmiş bir yapı bu.

// ecosystem.config.js
module.exports = {
apps: [
{
name: "uygulama-adi",
script: "app.js",
interpreter: "/home/kullanici/.nvm/versions/node/v18.17.0/bin/node",
env: {
NODE_ENV: "production",
PORT: 3000
}
}
]
};

Sonra bunu şu şekilde başlatıyorsunuz:

pm2 start ecosystem.config.js

Şöyle söyleyeyim, Bir arkadaşım — Ankara’da DevOps mühendisi olarak çalışıyor — geçen sene bana dedi ki: “Ecosystem dosyası olmadan PM2 kullanmak, emniyet kemeri takmadan araba sürmek gibi.” Çok haklıymış. O zamandan beri her projede ecosystem dosyası oluşturuyorum, istisnasız.

Yöntem 3: NVM Yerine Doğrudan Node Kurulumu

Hani, Eğer sunucunuzda tek bir Node versiyonu kullanacaksanız — ki prodüksiyon ortamında çoğu zaman böyledir — NVM’e ihtiyacınız olmayabilir (evet, doğru duydunuz). NodeSource repository’sinden direkt kurulum yapabilirsiniz:

# Node.js 18.x kurulumu (Debian/Ubuntu)
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs

Bu şekilde kurduğunuzda sistem genelinde tek bir Node versiyonu olur ve PM2 de onu kullanır. NVM kaynaklı PATH karmaşası neredeyse tamamen ortadan kalkar. Ama tabi birden fazla projeniz varsa ve farklı versiyonlara ihtiyaç duyuyorsanız, bu yöntem uygun değil — o zaman ecosystem dosyası yoluna gidin.

Karşılaştırma: Hangi Yöntem Kime Uygun?

Yöntem Avantaj Dezavantaj Kime Uygun?
PM2 yeniden kurulum Hızlı, basit NVM değişince tekrar bozulabilir Tek seferlik düzeltme
Ecosystem dosyası Kalıcı, versiyon kontrolüne girer Path hardcode edilmeli Ciddi prodüksiyon ortamları
NVM kaldırma + direkt kurulum Temiz, sorunsuz Birden fazla versiyon kullanılamaz Tek proje çalışan VPS’ler

Dikkat Edilmesi Gereken Diğer Tuzaklar

Yani, PM2 + NVM meselesi en yaygın sorun, ama tek sorun değil. VPS’e deploy ederken başınıza gelebilecek birkaç şey daha var — bunları da paylaşayım, zira hepsini bizzat yaşadım.

Dosya İzinleri ve Kullanıcı Farkları

Lokalde genellikle kendi kullanıcınızla çalışıyorsunuz. VPS’de ise bazen root — ki bu tartışılır — ile, bazen ayrı bir deploy kullanıcısıyla işlem yapıyorsunuz — ve PM2’yi root olarak başlatıp uygulamanın ihtiyaç duyduğu dosyalara başka bir kullanıcının sahip olduğu durumlar, inanın çok yaygın. EACCES hataları yağmur gibi yağıyor o zaman, hangi tarafı kapatsan öbür taraf açılıyor.

E bir de şu var: NVM, kullanıcıya özel kuruluyor. Root kullanıcısının NVM’i ile deploy kullanıcısının NVM’i farklı şeyler. Yani sudo pm2 start ile pm2 start farklı Node versiyonlarını kullanabilir. Bu ne anlama geliyor? Bunu da aklınızda tutun, sonradan “nasıl böyle bir şey olur” diye saatlerce bakarsınız (ciddiyim) Daha fazla bilgi için Whisper ve Streamlit ile Sesli AI Ajanı Kurmak: Pratik Rehber yazımıza bakabilirsiniz.

Ortam Değişkenleri

Lokalde .env dosyanız var, içinde DATABASE_URL, API_KEY falan tanımlı. Burada, vPS’e deploy ederken bu dosyayı kopyalamayı unutuyorsunuz — veya kopyalıyorsunuz. PM2 onu okuyamıyor çünkü çalışma dizini farklı. Klasik. Daha fazla bilgi için Flutter’da LLM Maliyeti Nasıl Kırılır: API’siz Yol yazımıza bakabilirsiniz.

PM2 ile uygulama başlatırken --cwd parametresiyle çalışma dizinini açıkça belirtmek, ortam değişkeni sorunlarının büyük çoğunluğunu ortadan kaldırır.

Bellek Limitleri

Hmm, bir düşüneyim… Evet, bu da önemli. Lokalde 16 GB RAM’iniz var, VPS’de 1 GB. Node.js varsayılan heap limiti genelde 1.5-2 GB civarında, ama 1 GB RAM’li bir sunucuda swap da yoksa uygulama OOM (Out of Memory) killer tarafından öldürülebiliyor — hiç uyarı vermeden, log bırakmadan. PM2 loglarında “killed” görüyorsanız, büyük ihtimalle budur. Daha fazla bilgi için Windows 11’de Can Sıkıcı Yavaşlık Bitiyor mu? yazımıza bakabilirsiniz.

💡 Bilgi: PM2’nin --max-memory-restart parametresiyle bellek limitini belirleyebilirsiniz. Örneğin: pm2 start app.js --max-memory-restart 512M. Bu, uygulamanız 512 MB’ı aştığında otomatik restart atar ve sunucunun tamamen kilitlenmesini önler.

Pratik İpuçları: Deploy Öncesi Kontrol Listesi

Bu kadar acı deneyimden sonra kendime bir checklist oluşturdum. Her VPS deploy’ından önce şunları kontrol ediyorum — bazen sıkıcı geliyor. Sonradan “keşke bakmasaydım” demek istemiyorum:

  • node -v ve npm -v çıktılarını not al
  • which node ile hangi binary’nin kullanıldığını doğrula
  • PM2 kuruluysa pm2 show ile interpreter versiyonunu kontrol et
  • .env dosyasının doğru dizinde ve okunabilir olduğunu teyit et
  • Sunucunun RAM ve disk durumunu free -h ve df -h ile kontrol et (bence en önemlisi)
  • pm2 logs ile ilk başlatmadaki hata mesajlarını incele

Bu listeyi uyguladığımdan beri — açık konuşayım — deploy sorunlarım en az %70 azaldı. Abartmıyorum. Önceden yarım günümü alan debug oturumları artık 15 dakikada çözülüyor. Küçük bir alışkanlık, koca bir fark. Daha fazla bilgi için Butterfly CSS: 2026’da Dikkat Çeken Hafif Bir Seçenek yazımıza bakabilirsiniz. Bu konuyla ilgili PDF Dünyasında Bir Nefes: Ücretsiz ve Limitsiz Araçlar yazımıza da göz atmanızı tavsiye ederim.

Durun, bir saniye.

Bak bir de şunu söyleyeyim: eğer kurumsal bir ortamda çalışıyorsanız,. Birden fazla geliştiricinin aynı sunucuya deploy ettiği bir yapınız varsa, Docker kullanmayı ciddi ciddi düşünün. Container içinde Node versiyonu, bağımlılıklar, ortam değişkenleri — her şey izole, her şey tanımlı, “bende çalışıyor. Sende çalışmıyor” diye bir dert kalmıyor. PM2 + NVM tuzağına düşme ihtimaliniz sıfıra iniyor. Küçük bir startup için VPS + PM2 gayet yeterli, ama ölçek büyüdükçe containerize etmek kaçınılmaz oluyor.

Bu konuyla bağlantılı olarak, terminal bazlı geliştirme araçlarını karşılaştırdığımız Claude Code, Codex CLI. Gemini CLI: 2026’nın En İyi AI Terminal Agent’ı Hangisi? yazımıza da göz atabilirsiniz — özellikle sunucu üzerinde hızlı debug yaparken bu araçlar bayağı işe yarıyor.

Garip gelecek ama, Bir de test otomasyonu tarafında, deploy sonrası her şeyin düzgün çalıştığını doğrulamak için Playwright ile Uçtan Uca Test: Tam Kapsamlı Rehber yazımız da ilginizi çekebilir.

Sıkça Sorulan Sorular

PM2 neden terminaldeki Node versiyonundan farklı bir versiyon kullanıyor?

PM2 global olarak kurulduğunda, o an aktif olan Node versiyonunun binary’sine bağlanıyor. Sonradan NVM ile farklı bir versiyona geçseniz bile, PM2’nin daemon’ı eski versiyonla çalışmaya devam ediyor. Bu yüzden pm2 update komutuyla daemon’ı yenilemek veya PM2’yi istenen versiyon altında yeniden kurmak gerekiyor.

PM2 ecosystem dosyasında interpreter yolu nasıl bulunur?

Terminalde which node veya nvm which current komutunu çalıştırarak aktif Node binary’sinin tam yolunu öğrenebilirsiniz. Bu yolu ecosystem.config.js dosyasındaki interpreter alanına yapıştırmanız yeterli. Genellikle /home/kullanici/.nvm/versions/node/vX.Y.Z/bin/node formatında olur.

NVM kullanmadan PM2 ile Node versiyonu sorunu yaşanır mı?

Daha az olasılıkla evet. Snap, apt veya manual derleme gibi farklı yöntemlerle birden fazla Node kurulumu yapılmışsa, PATH sıralamasına göre beklenmedik bir versiyon kullanılabilir. Bakın, ama en yaygın senaryo kesinlikle NVM kaynaklı oluyor.

Docker kullanırsam bu sorun ortadan kalkar mı?

Evet, büyük ölçüde kalkar. Docker container’ında Node versiyonu Dockerfile’da sabitlenir (mesela FROM node:18-alpine) ve container içindeki tüm süreçler bu versiyonu kullanır. PM2 kullanıyor olsanız bile, NVM’e gerek kalmaz ve versiyon uyumsuzluğu riski ortadan kalkar.

Bakın, burayı atlarsanız yazının kalanı anlamsız kalır.

PM2 restart ile PM2 update arasındaki fark nedir?

pm2 restart sadece uygulamayı yeniden başlatır ama aynı daemon. Aynı ortam değişkenleriyle çalışmaya devam eder. pm2 update ise PM2 daemon’ının kendisini yeniden başlatır ve güncel shell ortamını (yeni Node versiyonu dahil) almasını sağlar. Versiyon değişikliği yaptıysanız mutlaka pm2 update kullanmalısınız.

Kaynaklar ve İleri Okuma

PM2 Ecosystem File Dokümantasyonu

NVM GitHub — Önemli Notlar ve Bilinen Sorunlar

Bir şey dikkatimi çekti: Node.js Resmi Kurulum Rehberi (Package Manager ile)

Aşkın KILIÇ

20+ yıl deneyimli Azure Solutions Architect. Microsoft sertifikalı bulut mimari ve DevOps danışmanı. Azure, yapay zekâ ve bulut teknolojileri üzerine Türkçe teknik içerikler üretiyor.

AZ-305AZ-104AZ-500AZ-400DP-203AI-102

Bu içerik işinize yaradı mı?

Benzer içerikleri kaçırmamak için beni sosyal medyada takip edin.

Haftalık Bülten

Her pazar özenle seçilmiş teknoloji yazıları doğrudan e-postanıza gelsin.

← Onceki Yazi
Whisper ve Streamlit ile Sesli AI Ajanı Kurmak: Pratik Rehber
Sonraki Yazi →
Sam Altman’a Saldırı: AI Gerginliği Nereye Gidiyor?

Yorum Yaz

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

Haftalık Bülten

Azure, DevOps ve Yapay Zeka dünyasındaki en güncel içerikleri her hafta doğrudan e-postanıza alın.

Spam yok. İstediğiniz zaman iptal edebilirsiniz.
📱
Uygulamayı Yükle Ana ekrana ekle, çevrimdışı oku
Kategoriler
Ara
Paylaş
İçindekiler
← Whisper ve Streamlit ile Sesli...
Sam Altman’a Saldırı: AI Gergi... →
📩

Gitmeden önce!

Her pazar özenle seçilmiş teknoloji yazıları ve AI haberleri doğrudan e-postanıza gelsin. Ücretsiz, spam yok.

🔒 Bilgileriniz güvende. İstediğiniz zaman ayrılabilirsiniz.

📬 Haftalık bülten: Teknoloji + AI haberleri