Üretimde Node.js için PM2 Süreç Yönetimi
Node.js uygulamanız gece saat 2'de çöktüğünde PM2, uygulamanın otomatik olarak yeniden başlatılması ile kullanıcılarınızın siz uyanana kadar boş bir sayfa görmesi arasındaki farktır. PM2, otomatik yeniden başlatmaları, çok çekirdekli kullanım için kümelemeyi, günlük toplamayı ve sıfır kesinti süreli dağıtımları gerçekleştiren, savaşta test edilmiş bir süreç yöneticisidir; tüm bunları deponuzda yaşayan tek bir yapılandırma dosyasıyla gerçekleştirir.
Bu kılavuz, 5 Node.js işlemini aynı anda yöneten üretim PM2 kurulumunu kapsar: Next.js (ön uç), NestJS (API), Docusaurus (belgeler) ve iki marka sitesi. Desenler, tek işlemli dağıtımlara eşit şekilde uygulanır.
Önemli Çıkarımlar
ecosystem.config.cjsdosyası (CommonJS,.jsdeğil) hem ESModule hem de CommonJS projeleriyle çalışır- Yeni ortam değişkenlerini almak için yeniden başlatma sırasında
--update-envbayrağı gereklidir.env.local'yi güncelledikten sonra aslapm2 restart all'yi--update-envolmadan kullanmayınwatch: falseüretimde — dosya izleme, derleme çıktılarıyla sonsuz yeniden başlatma döngülerine neden olurmax_memory_restart, süreci kalıcı olarak sonlandırmadan otomatik bellek sızıntısına karşı koruma sağlarnode_args: '--max-old-space-size=4096'bellek yoğun işlemlerde OOM'un çökmesini önler- PM2 günlükleri
pm2-logrotatemodülüyle birlikte döner — PM2'den hemen sonra yükleyinpm2 savevepm2 startupsunucu yeniden başlatmalarında işlem listenizi korur
Kurulum
# Install PM2 globally
npm install -g pm2
# Install the log rotation module immediately
pm2 install pm2-logrotate
# Configure log rotation
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 7
pm2 set pm2-logrotate:compress true
pm2 set pm2-logrotate:dateFormat YYYY-MM-DD
Ekosistem Yapılandırma Dosyası
ecosystem.config.cjs dosyası (Hem ESM hem de CJS projeleriyle çalışacak OrtakJS formatı) tüm süreçlerinizi tanımlar:
// ecosystem.config.cjs
module.exports = {
apps: [
// ─── Next.js Frontend ────────────────────────────────────────────
{
name: 'ecosire-web',
script: 'node_modules/.bin/next',
args: 'start',
cwd: '/opt/ecosire/app/apps/web',
instances: 1, // Single instance — Next.js handles its own multi-threading
exec_mode: 'fork',
env: {
NODE_ENV: 'production',
PORT: 3000,
},
// Memory management
max_memory_restart: '1G',
node_args: '--max-old-space-size=1024',
// Logging
out_file: '/var/log/pm2/ecosire-web.out.log',
error_file: '/var/log/pm2/ecosire-web.err.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
// Restart behavior
watch: false,
restart_delay: 3000,
max_restarts: 10,
min_uptime: '30s', // Must stay up 30s to count as successful start
autorestart: true,
// Graceful shutdown
kill_timeout: 30000, // 30 seconds to shut down gracefully
wait_ready: true, // Wait for process.send('ready')
listen_timeout: 60000,
},
// ─── NestJS API ──────────────────────────────────────────────────
{
name: 'ecosire-api',
script: 'dist/main.js',
cwd: '/opt/ecosire/app/apps/api',
instances: 2, // Cluster mode for multi-core utilization
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3001,
},
max_memory_restart: '512M',
node_args: '--max-old-space-size=512',
out_file: '/var/log/pm2/ecosire-api.out.log',
error_file: '/var/log/pm2/ecosire-api.err.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
watch: false,
restart_delay: 2000,
max_restarts: 10,
min_uptime: '20s',
autorestart: true,
kill_timeout: 15000,
// Graceful cluster reload support
listen_timeout: 30000,
},
// ─── Docusaurus Docs ─────────────────────────────────────────────
{
name: 'ecosire-docs',
script: 'node_modules/.bin/docusaurus',
args: 'serve',
cwd: '/opt/ecosire/app/apps/docs',
instances: 1,
exec_mode: 'fork',
env: {
NODE_ENV: 'production',
PORT: 3002,
},
max_memory_restart: '256M',
out_file: '/var/log/pm2/ecosire-docs.out.log',
error_file: '/var/log/pm2/ecosire-docs.err.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
watch: false,
restart_delay: 3000,
max_restarts: 5,
min_uptime: '30s',
autorestart: true,
kill_timeout: 10000,
},
// ─── Brand Site: Odovation ───────────────────────────────────────
{
name: 'odovation-web',
script: 'node_modules/.bin/next',
args: 'start',
cwd: '/opt/ecosire/app/apps/odovation',
instances: 1,
exec_mode: 'fork',
env: {
NODE_ENV: 'production',
PORT: 3010,
},
max_memory_restart: '512M',
out_file: '/var/log/pm2/odovation-web.out.log',
error_file: '/var/log/pm2/odovation-web.err.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
watch: false,
restart_delay: 3000,
max_restarts: 10,
min_uptime: '30s',
autorestart: true,
},
// ─── Brand Site: MuhammadAmir ────────────────────────────────────
{
name: 'muhammadamir-web',
script: 'node_modules/.bin/next',
args: 'start',
cwd: '/opt/ecosire/app/apps/muhammadamir',
instances: 1,
exec_mode: 'fork',
env: {
NODE_ENV: 'production',
PORT: 3020,
},
max_memory_restart: '512M',
out_file: '/var/log/pm2/muhammadamir-web.out.log',
error_file: '/var/log/pm2/muhammadamir-web.err.log',
merge_logs: true,
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
watch: false,
restart_delay: 3000,
max_restarts: 10,
min_uptime: '30s',
autorestart: true,
},
],
};
Temel PM2 Komutları
# Start all processes from ecosystem file
pm2 start ecosystem.config.cjs
# Restart all (with updated environment variables)
pm2 restart ecosystem.config.cjs --update-env
# Graceful reload (zero-downtime for cluster mode)
pm2 reload ecosystem.config.cjs
# Stop all processes
pm2 stop all
# Delete all processes from PM2 registry
pm2 delete all
# Individual process management
pm2 restart ecosire-api
pm2 stop ecosire-docs
pm2 logs ecosire-web --lines 100
# Real-time monitoring dashboard
pm2 monit
# Status overview
pm2 status
pm2 list
Sunucu Yeniden Başlatıldığında Başlangıç
Başlangıç yapılandırması olmadan, sunucu yeniden başlatıldığında tüm PM2 işlemleri kaybolur:
# Generate and install the startup script for your init system
pm2 startup
# Copy the output command and run it (it looks like:)
# sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u ubuntu --hp /home/ubuntu
# Save the current process list
pm2 save
# This creates ~/.pm2/dump.pm2 — processes are restored on reboot
# Verify startup works
pm2 resurrect # Manually restore from dump.pm2
İşlemleri her eklediğinizde veya kaldırdığınızda, döküm dosyasını güncellemek için pm2 save komutunu yeniden çalıştırın.
Sıfır Kesinti Süreli Dağıtımlar
Küme modundaki NestJS için PM2, gerçek sıfır kesinti süreli yeniden yüklemeleri destekler:
# Reload restarts workers one at a time (zero-downtime)
# Old workers handle requests while new ones start
pm2 reload ecosire-api
# vs restart — kills all workers simultaneously (brief downtime)
pm2 restart ecosire-api
Next.js için (çatal modunda, tek örnekte çalışır), sıfır kesinti süresi farklı bir yaklaşım gerektirir. Uygulamanızdan gelen bir başlangıç sinyaliyle wait_ready + listen_timeout yapılandırmasını kullanın:
// apps/web — this is handled automatically by Next.js
// But for NestJS, send the ready signal explicitly:
// apps/api/src/main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3001);
// Signal PM2 that the process is ready
if (process.send) {
process.send('ready');
}
}
bootstrap();
Günlük Yönetimi
PM2 günlükleri yönetilmediği takdirde diskinizi doldurabilir. Günlük rotasyonunu hemen yapılandırın:
# Install log rotation module
pm2 install pm2-logrotate
# Configuration
pm2 set pm2-logrotate:max_size 50M # Rotate when log reaches 50MB
pm2 set pm2-logrotate:retain 7 # Keep 7 days of logs
pm2 set pm2-logrotate:compress true # Gzip rotated logs
pm2 set pm2-logrotate:dateFormat YYYY-MM-DD
pm2 set pm2-logrotate:workerInterval 30 # Check rotation interval (seconds)
pm2 set pm2-logrotate:rotateInterval '0 0 * * *' # Daily at midnight
Yararlı günlük komutları:
# View all logs combined
pm2 logs
# View specific process logs
pm2 logs ecosire-api
# View with timestamps
pm2 logs --timestamp
# Flush all log files
pm2 flush
# Tail error logs only
pm2 logs ecosire-api --err --lines 200
İzleme ve Metrikler
PM2 Plus (eski adıyla Keymetrics) bulut tabanlı izleme sağlar. Kendi kendine barındırılan izleme için:
# Built-in terminal dashboard
pm2 monit
# Get JSON status for scripting/monitoring integration
pm2 jlist # JSON process list
pm2 prettylist # Formatted process list
# Integrate with your monitoring stack
pm2 set pm2-server-monit:interval 5 # Metrics collection interval
Üretim izleme için PM2 ölçümlerini Prometheus'a gösterin:
npm install -g pm2-prometheus-exporter
pm2 set pm2-prometheus-exporter:port 9209
# Scrape in Prometheus config:
# - job_name: pm2
# static_configs:
# - targets: ['localhost:9209']
Dağıtım Komut Dosyası Entegrasyonu
Tipik bir dağıtım sırası:
#!/bin/bash
# scripts/deploy-production.sh
set -e
echo "=== Starting deployment ==="
# 1. Pull latest code
git pull origin main
# 2. Install dependencies
pnpm install --frozen-lockfile
# 3. Build all apps (with Turbo remote cache)
TURBO_TOKEN="$TURBO_TOKEN" TURBO_TEAM="$TURBO_TEAM" \
npx turbo run build
# 4. Run database migrations
pnpm --filter @ecosire/db db:migrate
# 5. Restart PM2 processes
# --update-env picks up changes in .env.local
pm2 restart ecosystem.config.cjs --update-env
# 6. Wait for processes to stabilize
sleep 10
# 7. Health checks
curl -f https://ecosire.com/ -o /dev/null -s || {
echo "Web health check failed — rolling back"
git revert HEAD --no-edit
pm2 restart ecosystem.config.cjs --update-env
exit 1
}
curl -f https://api.ecosire.com/api/health -o /dev/null -s || {
echo "API health check failed — rolling back"
git revert HEAD --no-edit
pm2 restart ecosystem.config.cjs --update-env
exit 1
}
# 8. Save process state
pm2 save
echo "=== Deployment complete ==="
Yaygın Tuzaklar ve Çözümler
Tuzak 1: --update-env unutmak
.env.local güncelleştirildikten sonra pm2 restart all'nin --update-env olmadan çalıştırılması, işlemlerin eski ortam değişkenleriyle yeniden başlatılmasına neden olur. Her zaman pm2 restart ecosystem.config.cjs --update-env kullanın.
2. Tuzak: Üretimde watch: true kullanımı
watch: true herhangi bir dosya değiştiğinde işlemi yeniden başlatır. Üretimde derleme çıktıları her dağıtımda değişir; bu, sonsuz yeniden başlatma döngülerine neden olur. Her zaman watch: false değerini ayarlayın.
3. Tuzak: Sorunsuz kapatma için SIGTERM'in kullanılmaması
PM2, yeniden başlatırken/durdururken SIGTERM gönderir. Uygulamanız bunu işleyemezse PM2 kill_timeout milisaniye bekler ve SIGKILL'i gönderir; bu da isteklerin kaybolmasına neden olabilir. NestJS'de SIGTERM'i kullanın:
// main.ts
const app = await NestFactory.create(AppModule);
await app.listen(3001);
// Graceful shutdown
process.on('SIGTERM', async () => {
await app.close();
process.exit(0);
});
4. Tuzak: PM2 günlük disk alanının tükenmesi
pm2-logrotate olmadan PM2 günlükleri süresiz olarak büyür. Trafiği yoğun olan bir API, günde gigabaytlarca günlük oluşturabilir. pm2-logrotate'yi hemen yükleyin ve makul bir max_size (50MB) ve retain (7 gün) ayarlayın.
Tuzak 5: Yeniden başlatma sonrasında süreçlerin kaybedilmesi
pm2 start yeniden başlatmalarda işlemleri sürdürmez. İlk kurulumdan sonra daima pm2 startup + pm2 save komutunu çalıştırın. Yeniden başlatmanın ardından işlemler kaybolursa, kaydedilen dökümden geri yüklemek için pm2 resurrect komutunu çalıştırın.
Sıkça Sorulan Sorular
Küme modunu ne zaman çatal modunu kullanmalıyım?
CPU'ya bağlı iş yükleri için küme modunu kullanın (yoğun hesaplama ve veri işleme içeren NestJS API'leri). Küme modu, tüm CPU çekirdeklerinden yararlanarak instances çalışan işlemlerini ve bunlar arasındaki PM2 yük dengelemelerini oluşturur. G/Ç bağlantılı iş yükleri için (Next.js, statik dosya sunma) veya süreç kümelemeyi desteklemediğinde (tek iş parçacıklı komut dosyaları, Docusaurus sunma) çatal modunu kullanın. Next.js kendi çalışan iş parçacıklarını dahili olarak işler, dolayısıyla instances: 1 ile çatal modu doğrudur.
PM2'yi Docker kapsayıcısında nasıl çalıştırırım?
Docker'daki PM2, sinyalleri doğru şekilde işlemek için pm2 yerine pm2-docker (veya pm2-runtime) kullanır. Çalışma zamanı sürümü arka plan programı oluşturmaz (bu Docker'ın çıkmasına neden olur), sinyalleri alt işlemlere doğru şekilde iletir ve dosyalar yerine stdout/stderr'e günlük kaydeder. Dockerfile'ınızda CMD ["pm2-runtime", "ecosystem.config.cjs"] kullanın.
PM2 işlemlerini uzak bir makineden nasıl izlerim?
PM2 Plus (işlem başına ödeme bulut hizmeti), bir web kontrol paneli sağlar. Şirket içinde barındırılan izleme için PM2'nin ölçümlerini Prometheus dışa aktarıcı aracılığıyla ortaya çıkarın ve Grafana'da görselleştirin. Basit durum kontrolleri için SSH'yi çalıştırabilir ve pm2 status komutunu çalıştırabilir veya ölçümleri, izleme sisteminizin yokladığı bir HTTP uç noktası aracılığıyla ortaya çıkarabilirsiniz.
pm2'nin yeniden yüklenmesi ile pm2'nin yeniden başlatılması arasındaki fark nedir?
pm2 restart tüm çalışanları aynı anda öldürür ve yeniden başlatır; hiçbir çalışanın olmadığı kısa bir süre vardır (kesinti süresi). pm2 reload zariftir: yeni çalışanları başlatır, hazır olmalarını bekler, ardından eski çalışanları kapatır; sıfır kesinti süresi. Üretim dağıtımları için pm2 reload kullanın. Not: yeniden yükleme yalnızca küme modunda düzgün çalışır; çatal modu yeniden başlatma davranışına geri döner.
Farklı işlemler için farklı ortam değişkenlerini nasıl ayarlarım?
ecosystem.config.cjs içindeki her işlemin kendi env ve env_production bölümleri vardır. env_production bölümü, --env production'ü PM2 komutlarına ilettiğinizde kullanılır. Sırları asla doğrudan ekosistem dosyasına koymayın; sistem ortamına veya .env.local dosyasına yerleştirin ve PM2'nin bunları devralmasına izin verin. --update-env bayrağı, PM2'nin yeniden başlatma sırasında ortam değişkenlerini yeniden okumasını sağlar.
Sonraki Adımlar
PM2, herhangi bir üretim Node.js dağıtımının temel bir parçasıdır. ECOSIRE, üretimdeki 5 PM2 sürecini (Next.js, NestJS, Docusaurus ve iki marka sitesi) otomatik yeniden başlatmalar, günlük rotasyonu ve ana sürüme her geçişte sıfır kesinti süreli dağıtımlarla yönetir.
İster DevOps mühendislik desteğine, üretim dağıtım mimarisine ister kapsayıcılı bir kuruluma geçiş konusunda yardıma ihtiyacınız olsun, nasıl yardımcı olabileceğimizi görmek için hizmetlerimizi keşfedin.
Yazan
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
İlgili Makaleler
AWS EC2 Deployment Guide for Web Applications
Complete AWS EC2 deployment guide: instance selection, security groups, Node.js deployment, Nginx reverse proxy, SSL, auto-scaling, CloudWatch monitoring, and cost optimization.
Zero-Downtime Database Migrations with Drizzle ORM
Run database migrations without downtime using Drizzle ORM. Covers expand-contract pattern, backward-compatible schema changes, rollback strategies, and CI/CD integration for PostgreSQL.
Next.js 16 App Router: Production Patterns and Pitfalls
Production-ready Next.js 16 App Router patterns: server components, caching strategies, metadata API, error boundaries, and performance pitfalls to avoid.