Linux VPS Üzerinde Node.js ile Daemon Yazmak: Kapsamlı Bir Rehber
Linux tabanlı bir Sanal Özel Sunucu (VPS) üzerinde Node.js kullanarak arka planda sürekli çalışan, kullanıcı etkileşimi gerektirmeyen uygulamalar yani “daemon”lar geliştirmek, modern web ve sistem yönetimi görevleri için oldukça yaygın ve güçlü bir yaklaşımdır. Bu makale, Node.js’in asenkron doğasını Linux’un sağlam süreç yönetimi özellikleriyle birleştirerek, güvenilir ve sürdürülebilir daemon’lar oluşturmanın tüm adımlarını detaylı bir şekilde ele alacaktır. Temel bir Node.js uygulamasının nasıl yazılacağından, Linux’un systemd servis yöneticisi ile nasıl entegre edileceğine ve bir VPS üzerinde nasıl dağıtılacağına kadar her aşamayı kapsayacağız.
I. Daemon Kavramı ve Neden Gereklidir?
Daemon, Unix benzeri işletim sistemlerinde arka planda çalışan, doğrudan bir kullanıcı arayüzü veya etkileşimi olmayan bir bilgisayar programıdır. Bu programlar genellikle sistem başlatıldığında otomatik olarak başlar ve sistem kapanana kadar sürekli olarak çalışır. “Daemon” terimi, bilgisayar bilimleri literatüründe, kullanıcının doğrudan kontrolü dışında çalışan “cin” benzeri süreçleri tanımlamak için kullanılır.
Peki, daemon’lara neden ihtiyacımız var? Birçok kritik sistem görevi ve uygulama, sürekli çalışma gerektirir. Örneğin, bir web sunucusu (Apache, Nginx), veritabanı sunucusu (MySQL, PostgreSQL), e-posta sunucusu (Postfix), SSH sunucusu veya bir sistem izleme aracı gibi uygulamalar, kullanıcı oturumu açık olsun veya olmasın, sürekli olarak hizmet vermelidir. Daemon’lar, bu tür uygulamaların güvenilir bir şekilde arka planda çalışmasını sağlayarak sistemin genel işlevselliğini ve kararlılığını temin eder. Kaynakları verimli kullanır, belirli olayları dinler veya düzenli aralıklarla görevleri yerine getirirler. Linux’ta daemon’lar genellikle init (eski sistemlerde) veya systemd (modern sistemlerde) gibi sistem yöneticileri tarafından başlatılır, durdurulur ve yönetilir.
II. Node.js Neden Daemon Geliştirmek İçin İyi Bir Seçimdir?
Node.js, sunucu tarafı uygulamalar ve özellikle I/O yoğun iş yükleri için tasarlanmış, olay odaklı, asenkron bir çalışma zamanı ortamıdır. Bu özellikleri, onu daemon geliştirmek için oldukça cazip bir seçenek haline getirir:
* Asenkron ve Olay Odaklı Mimari: Node.js’in tek iş parçacıklı, olay döngüsü tabanlı yapısı, eşzamanlı bağlantıları veya görevleri bloklamadan verimli bir şekilde yönetmesini sağlar. Bu, özellikle bir ağ portunu dinleyen veya dosya sistemi olaylarını izleyen daemon’lar için idealdir.
* Hızlı Geliştirme ve Geniş Ekosistem: JavaScript’in hızlı geliştirme yetenekleri ve npm (Node Package Manager) aracılığıyla erişilebilen binlerce hazır kütüphane, daemon geliştirme sürecini önemli ölçüde hızlandırır. Logging, konfigürasyon yönetimi, süreç kontrolü gibi birçok yaygın ihtiyaç için hazır çözümler mevcuttur.
* Platform Bağımsızlık: Node.js, Linux, Windows ve macOS dahil olmak üzere çeşitli işletim sistemlerinde çalışabilir. Bu, geliştirme ortamınız ile üretim ortamınız arasında tutarlılık sağlar.
* Düşük Kaynak Tüketimi (Doğru Kullanıldığında): Node.js, doğru tasarımla, özellikle I/O bekleme sürelerinin uzun olduğu durumlarda, diğer bazı dillerden daha az bellek ve CPU kullanabilir.
* Geniş Topluluk ve Destek: Node.js’in büyük ve aktif bir topluluğu vardır. Bu, karşılaşılan sorunlar için hızlı destek bulmayı ve sürekli gelişen araç ve kütüphanelerden faydalanmayı kolaylaştırır.
III. Temel Bir Node.js Daemon Uygulaması Geliştirme
Bir Node.js daemon’ı geliştirmeye başlamadan önce, temel bir proje yapısı oluşturmak ve gerekli araçları kurmak önemlidir.
A. Proje Yapısı ve Bağımlılıklar
Öncelikle projemiz için bir dizin oluşturup içine girelim:
mkdir my-nodejs-daemon
cd my-nodejs-daemon
npm init -y
Bu komutlar, projemiz için package.json dosyasını oluşturacaktır. Şimdi, daemon’ımız için faydalı olabilecek bazı NPM paketlerini kuralım:
* winston: Profesyonel ve esnek günlükleme (logging) için.
* dotenv: Ortam değişkenlerini .env dosyasından yüklemek için.
* commander: Komut satırı argümanlarını kolayca ayrıştırmak için (isteğe bağlı, ancak faydalı).
npm install winston dotenv commander
B. Basit Bir “Hello Daemon” Uygulaması
Şimdi index.js adında bir dosya oluşturalım ve temel daemon mantığını yazalım. Bu örnek, her 5 saniyede bir log yazan ve düzgün kapanmayı ele alan basit bir uygulama olacaktır.
// index.js
require('dotenv').config(); // Ortam değişkenlerini yükle
const winston = require('winston');
const { Command } = require('commander');
const program = new Command();
// Commander ile komut satırı argümanlarını tanımla
program
.option('-p, --port ', 'Uygulamanın çalışacağı port', '3000')
.option('-e, --env ', 'Çalışma ortamı (development, production)', 'development')
.parse(process.argv);
const options = program.opts();
// Winston logger konfigürasyonu
const logger = winston.createLogger({
level: options.env === 'production' ? 'info' : 'debug',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
],
});
let counter = 0;
let intervalId;
function startDaemon() {
logger.info(Daemon başlatılıyor. Ortam: ${options.env}, Port: ${options.port});
intervalId = setInterval(() => {
counter++;
logger.info(Daemon çalışıyor. Sayaç: ${counter});
// Burada gerçek daemon iş mantığı yer alacak
// Örneğin, bir API çağrısı, dosya okuma, veritabanı sorgusu vb.
}, 5000); // Her 5 saniyede bir çalışır
}
function stopDaemon() {
logger.info('Daemon durduruluyor...');
if (intervalId) {
clearInterval(intervalId);
}
logger.info('Daemon başarıyla durduruldu.');
process.exit(0); // Uygulamadan çık
}
// SIGTERM ve SIGINT sinyallerini yakalayarak düzgün kapanma sağla
process.on('SIGTERM', () => {
logger.warn('SIGTERM sinyali alındı. Daemon durduruluyor...');
stopDaemon();
});
process.on('SIGINT', () => {
logger.warn('SIGINT sinyali alındı. Daemon durduruluyor...');
stopDaemon();
});
// Yakalanmayan istisnaları ve reddedilen Promise'ları ele al
process.on('uncaughtException', (err) => {
logger.error('Yakalanmayan istisna:', err);
// Hata durumunda daemon'ı durdurabilir veya yeniden başlatma sinyali gönderebiliriz
stopDaemon();
});
process.on('unhandledRejection', (reason, promise) => {
logger.error('Yakalanmayan Promise Reddi:', { reason, promise });
// Hata durumunda daemon'ı durdurabilir veya yeniden başlatma sinyali gönderebiliriz
stopDaemon();
});
startDaemon();
Bu kod parçası, bir Node.js daemon’ının temel bileşenlerini gösterir:
* Başlatma: startDaemon fonksiyonu, daemon’ın ana iş mantığını başlatan bir setInterval döngüsü içerir.
* Düzgün Kapanma: process.on('SIGTERM') ve process.on('SIGINT') kullanımı, sistem tarafından gönderilen durdurma sinyallerini (örneğin kill komutu veya systemctl stop) yakalayarak uygulamanın temiz bir şekilde kapanmasını sağlar. Bu, açık dosya tanımlayıcılarını, veritabanı bağlantılarını vb. kapatmak için kritik öneme sahiptir.
* Hata Yönetimi: uncaughtException ve unhandledRejection olayları, beklenmedik hataların uygulamanın çökmesine neden olmasını engellemek ve bu hataları loglamak için kullanılır.
C. Konfigürasyon Yönetimi
Daemon’lar genellikle farklı ortamlarda (geliştirme, test, üretim) farklı ayarlarla çalışır. Bu ayarları yönetmek için çeşitli yöntemler vardır:
* Ortam Değişkenleri (.env ve dotenv): Hassas bilgiler (API anahtarları, veritabanı şifreleri) için en iyi yöntemdir. dotenv paketi, .env dosyasındaki değişkenleri process.env‘e yükler.
# .env dosyası örneği
DATABASE_URL="mongodb://localhost:27017/my_daemon_db"
API_KEY="your_secret_api_key"
* Komut Satırı Argümanları (commander): Uygulama başlatılırken dinamik ayarlar geçirmek için kullanılır. Yukarıdaki örnekte port ve env argümanlarını tanımladık.
* JSON/YAML Konfigürasyon Dosyaları: Daha karmaşık yapılandırılmış ayarlar için bir config.json veya config.yaml dosyası oluşturulabilir ve uygulama başlatılırken bu dosyadan okunabilir.
D. Günlükleme (Logging)
Daemon’lar arka planda çalıştığı için, ne yaptıklarını, ne zaman hata verdiklerini veya ne zaman önemli olayların gerçekleştiğini anlamak için kapsamlı günlükleme (logging) hayati öneme sahiptir. console.log yeterli değildir çünkü log seviyeleri, dosya rotasyonu veya farklı taşıyıcılar (konsol, dosya, uzak sunucu) gibi gelişmiş özellikler sunmaz.
winston gibi bir kütüphane, bu ihtiyaçları karşılar:
* Log Seviyeleri: debug, info, warn, error gibi seviyelerle logların önem derecesini belirtir. Üretimde sadece info ve üzeri logları göstermek, geliştirme ortamında ise tüm debug loglarını görmek isteyebilirsiniz.
* Taşıyıcılar (Transports): Logları farklı hedeflere (konsol, dosya, veritabanı, uzak log sunucusu) gönderme yeteneği.
* Formatlama: Log mesajlarının JSON, düz metin veya özel formatlarda olmasını sağlar.
Yukarıdaki index.js örneğinde winston kullanımını görebilirsiniz. combined.log tüm logları, error.log ise sadece hata loglarını tutar.
E. Hata Yönetimi
Sağlam bir daemon, hataları sadece loglamakla kalmamalı, aynı zamanda onları düzgün bir şekilde ele almalı ve uygulamanın çökmesini engellemelidir.
* try...catch Blokları: Asenkron olmayan kodlarda veya async/await yapılarında senkron hataları yakalamak için kullanılır.
* process.on('uncaughtException'): Node.js olay döngüsünü tıkayan ve yakalanmayan senkron istisnaları yakalar. Bu olay tetiklendiğinde uygulamanın tutarsız bir durumda olabileceği unutulmamalıdır. Genellikle uygulamayı temiz bir şekilde kapatıp yeniden başlatmak en iyi yaklaşımdır.
* process.on('unhandledRejection'): Bir Promise’in reddedilmesi durumunda ve bu reddedilmenin hiçbir catch bloğu tarafından yakalanmaması durumunda tetiklenir. uncaughtException gibi, bu da uygulamanın potansiyel olarak tutarsız bir duruma girmesine neden olabilir.
Hata durumunda uygulamanın ne yapacağına karar vermek önemlidir. Basit bir yeniden başlatma, genellikle geçici sorunları çözebilir. Ancak sürekli hatalar, daha derinlemesine bir inceleme gerektirir.
IV. Daemon’ı Linux Ortamına Uygun Hale Getirme
Bir Node.js uygulamasını bir daemon olarak çalıştırmak için, onu arka plana atma, PID (Process ID) dosyası oluşturma gibi Linux’a özgü bazı kavramları anlamak gerekir.
A. Arka Plana Atma (Backgrounding)
Bir uygulamayı doğrudan terminalden node index.js komutuyla başlattığınızda, terminal oturumu kapandığında uygulama da kapanır. Bunu önlemek için uygulamayı arka plana atmak gerekir.
* nohup ve &: En basit yöntemdir ancak profesyonel bir daemon yönetimi için önerilmez.
nohup node index.js &
nohup, terminal oturumu kapansa bile sürecin çalışmaya devam etmesini sağlar. & ise süreci arka plana atar. Ancak bu yöntem, sürecin durumunu izleme, otomatik yeniden başlatma gibi özellikler sunmaz.
* Süreç Yöneticileri (pm2, forever): Daha profesyonel ve önerilen yöntemdir. Bu araçlar, uygulamanızı daemonize eder, çöktüğünde otomatik olarak yeniden başlatır, logları yönetir ve kümeleme (clustering) gibi gelişmiş özellikler sunar. pm2 bu konuda en popüler olanlardan biridir. Ancak bu makalede systemd entegrasyonuna odaklanacağımız için pm2‘yi daha sonra, gelişmiş konularda ele alacağız.
B. Çift Çatallanma (Double Fork) Prensibi
Geleneksel Linux daemon’ları, ebeveyn süreçten bağımsız hale gelmek ve arka planda çalışmak için “çift çatallanma” (double fork) adı verilen bir mekanizma kullanır. Bu süreç özetle şöyledir:
1. Orijinal süreç bir çocuk süreç çatallanır.
2. Ebeveyn süreç hemen çıkar.
3. Çocuk süreç bir oturum lideri olur.
4. Çocuk süreç bir kez daha çatallanır.
5. İkinci çocuk süreç, yeni oturumun lideri olmayan tek süreçtir ve bu sayede bir terminalden tamamen bağımsız hale gelir.
6. İkinci çocuk süreç, standart giriş/çıkış/hata akışlarını /dev/null‘a yönlendirir.
Node.js geliştiricileri olarak, genellikle bu düşük seviyeli detaylarla doğrudan uğraşmamıza gerek kalmaz. systemd gibi servis yöneticileri veya pm2 gibi süreç yöneticileri, bu adımları bizim için otomatik olarak halleder.
C. Process ID (PID) Dosyası
Bir daemon çalıştığında, genellikle bir PID dosyası (.pid uzantılı bir metin dosyası) oluşturulur. Bu dosya, çalışan daemon’ın süreç kimliğini (PID) içerir. Bu PID, daemon’ı durdurmak, yeniden başlatmak veya durumunu kontrol etmek için kullanılır. Örneğin:
kill $(cat /var/run/my-daemon.pid)
PID dosyası genellikle /var/run/ dizininde veya uygulamanın kendi çalışma dizininde saklanır. systemd kullanırken, genellikle systemd bu dosyayı sizin için yönetir ve manuel olarak oluşturmanıza gerek kalmaz.
V. systemd ile Daemon Yönetimi
Modern Linux dağıtımlarında (Ubuntu, CentOS, Debian vb.), systemd sistem ve servis yöneticisi olarak kullanılır. systemd, daemon’ları yönetmek, otomatik başlatma sağlamak, yeniden başlatma stratejileri belirlemek ve logları toplamak için güçlü ve esnek bir yol sunar.
A. systemd Nedir ve Neden Kullanılır?
systemd, Linux çekirdeği tarafından başlatılan ilk süreç olan init sürecinin yerini alan bir sistem ve servis yöneticisidir. Görevleri şunları içerir:
* Servis Yönetimi: Sistem servislerini (daemon’ları) başlatma, durdurma, yeniden başlatma, durumunu sorgulama.
* Otomatik Başlatma: Sistem açılışında servisleri otomatik olarak başlatma.
* Bağımlılık Yönetimi: Servislerin doğru sırayla başlatılmasını sağlama (örneğin, bir web sunucusu veritabanı başlamadan başlamamalıdır).
* Kaynak Kontrolü: CGroup’lar aracılığıyla servislere kaynak limitleri atama.
* Log Toplama: Tüm servislerin standart çıktı ve hata çıktılarını journald aracılığıyla merkezi olarak toplama.
systemd kullanmak, Node.js daemon’ınızın güvenilirliğini ve yönetilebilirliğini önemli ölçüde artırır.
B. Bir systemd Servis Dosyası Oluşturma
Bir Node.js uygulamasını systemd servisi olarak çalıştırmak için, /etc/systemd/system/ dizininde bir .service dosyası oluşturmamız gerekir. Bu dosya, systemd‘ye uygulamamızı nasıl başlatacağını, durduracağını ve yöneteceğini söyler.
Örnek olarak, my-nodejs-daemon.service adında bir dosya oluşturalım:
# /etc/systemd/system/my-nodejs-daemon.service
[Unit]
Description=My Node.js Daemon Service
After=network.target
[Service]
ExecStart=/usr/bin/node /home/your_user/my-nodejs-daemon/index.js --env production --port 4000
WorkingDirectory=/home/your_user/my-nodejs-daemon
Restart=always
RestartSec=5
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=my-nodejs-daemon
User=your_user
Group=your_user
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
Bu dosyadaki bölümleri inceleyelim:
* [Unit]: Servis hakkında genel bilgiler ve bağımlılıklar.
* Description: Servisin kısa açıklaması.
* After=network.target: Servisin ağ servisi başladıktan sonra başlamasını sağlar. Diğer bağımlılıklar (örneğin veritabanı) buraya eklenebilir.
* [Service]: Servisin nasıl çalıştırılacağıyla ilgili komutlar ve ayarlar.
* ExecStart: Servisi başlatmak için çalıştırılacak komut. Burada Node.js yorumlayıcısı (/usr/bin/node) ve uygulama dosyamızın tam yolu (/home/your_user/my-nodejs-daemon/index.js) belirtilir. Komut satırı argümanları (--env production --port 4000) da buraya eklenebilir.
* WorkingDirectory: Uygulamanın çalışacağı dizin. Bu, göreceli yollarla dosyalara erişim için önemlidir.
* Restart=always: Servis beklenmedik bir şekilde çökerse veya kapanırsa otomatik olarak yeniden başlatılmasını sağlar. Diğer seçenekler on-failure, on-abnormal, no olabilir.
* RestartSec=5: Yeniden başlatma denemeleri arasında 5 saniye bekler.
* StandardOutput=syslog, StandardError=syslog: Uygulamanın standart çıktı ve hata çıktılarını syslog‘a (yani journald‘ye) yönlendirir. Bu, logları journalctl ile izlemeyi sağlar. Alternatif olarak file:/path/to/log.log da kullanılabilir.
* SyslogIdentifier=my-nodejs-daemon: Loglarda bu servisi tanımlamak için kullanılan etiket.
* User=your_user, Group=your_user: Servisin hangi kullanıcı ve grup altında çalışacağını belirtir. Güvenlik nedeniyle, root kullanıcısı yerine ayrıcalıksız bir kullanıcı kullanmak şiddetle tavsiye edilir.
* Environment=NODE_ENV=production: Uygulama için ortam değişkeni tanımlar. .env dosyası kullanıyorsanız bu gerekli olmayabilir veya ek ortam değişkenleri tanımlayabilirsiniz.
* [Install]: Servisin nasıl etkinleştirileceğiyle ilgili bilgiler.
* WantedBy=multi-user.target: Servisin çok kullanıcılı sistem durumunda (normal çalışma modu) etkinleştirilmesi gerektiğini belirtir.
Önemli: your_user ve /home/your_user/my-nodejs-daemon/ yollarını kendi kullanıcı adınıza ve projenizin dizinine göre güncellemeyi unutmayın. Node.js yorumlayıcısının yolu da sisteminize göre değişebilir (örneğin /usr/local/bin/node veya nvm kullanıyorsanız belirli bir sürümün yolu). which node komutuyla doğru yolu bulabilirsiniz.
C. systemd Servisini Yönetme
Servis dosyasını oluşturduktan sonra, systemctl komutuyla onu yönetebiliriz:
1. systemd’yi Yeniden Yükle: Yeni servis dosyasını okuması için systemd‘yi bilgilendirin.
sudo systemctl daemon-reload
2. Servisi Etkinleştir (Enable): Sistem açılışında otomatik olarak başlaması için servisi etkinleştirin.
sudo systemctl enable my-nodejs-daemon.service
3. Servisi Başlat: Servisi manuel olarak başlatın.
sudo systemctl start my-nodejs-daemon.service
4. Servisin Durumunu Kontrol Et: Servisin çalışıp çalışmadığını, son loglarını ve varsa hatalarını görün.
sudo systemctl status my-nodejs-daemon.service
5. Servisi Durdur: Servisi durdurun.
sudo systemctl stop my-nodejs-daemon.service
6. Servisi Yeniden Başlat: Servisi durdurup tekrar başlatın.
sudo systemctl restart my-nodejs-daemon.service
7. Logları İzle: Servisin syslog‘a gönderdiği logları journalctl ile görüntüleyin.
sudo journalctl -u my-nodejs-daemon.service -f
-f (follow) bayrağı, logları gerçek zamanlı olarak izlemenizi sağlar.
VI. Node.js Daemon’ını Bir VPS Üzerinde Dağıtma ve Yönetme
Şimdiye kadar geliştirdiğimiz Node.js daemon’ını bir VPS üzerine nasıl dağıtacağımızı ve yöneteceğimizi ele alalım.
A. Geliştirme Ortamı Kurulumu
VPS’nize SSH ile bağlandıktan sonra, Node.js ve npm’i kurmanız gerekir. nvm (Node Version Manager) kullanmak, farklı Node.js sürümleri arasında kolayca geçiş yapmanızı sağladığı için önerilir.
# nvm kurulumu (eğer yüklü değilse)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
source ~/.bashrc # veya ~/.zshrc
En son LTS Node.js sürümünü kur
nvm install --lts
nvm use --lts
nvm alias default 'lts/*' # Varsayılan olarak LTS sürümünü kullan
Node.js ve npm'in kurulduğunu doğrula
node -v
npm -v
Git kurulumu (eğer yüklü değilse)
sudo apt update
sudo apt install git # Debian/Ubuntu için
sudo yum install git # CentOS/RHEL için
B. Kodun VPS’e Aktarılması
Projenizi VPS’e aktarmak için birkaç yöntem vardır:
* Git ile Klonlama (Önerilen): Kodunuzu bir Git deposunda (GitHub, GitLab, Bitbucket) tutuyorsanız, VPS’te klonlamak en kolay yöntemdir.
cd /home/your_user/
git clone https://github.com/your_username/my-nodejs-daemon.git
Bu, /home/your_user/my-nodejs-daemon dizinini oluşturacaktır.
* SCP veya SFTP ile Manuel Aktarım: Eğer kodunuz bir Git deposunda değilse veya özel dosyalarınız varsa, scp (Secure Copy Protocol) veya bir SFTP istemcisi (FileZilla gibi) kullanabilirsiniz.
# Yerel makinenizden VPS'e
scp -r /path/to/local/my-nodejs-daemon your_user@your_vps_ip:/home/your_user/
C. Bağımlılıkların Kurulumu
Proje dizininize gidin ve bağımlılıkları yükleyin:
cd /home/your_user/my-nodejs-daemon
npm install --production
--production bayrağı, sadece üretim bağımlılıklarının (dependencies) yüklenmesini sağlar, geliştirme bağımlılıkları (devDependencies) atlanır. Bu, disk alanı ve kurulum süresi açısından faydalıdır.
Eğer .env dosyanız varsa, onu da proje dizininize kopyalamayı unutmayın ve içeriğinin hassas bilgiler içerdiğinden emin olun.
D. Daemon’ın Başlatılması ve Test Edilmesi
1. systemd Servis Dosyasını Oluşturun: Daha önce bahsedilen my-nodejs-daemon.service dosyasını /etc/systemd/system/ dizininde oluşturun ve ExecStart, WorkingDirectory, User, Group gibi yolları ve kullanıcı adlarını VPS’nize göre güncelleyin.
sudo nano /etc/systemd/system/my-nodejs-daemon.service
# İçeriği yapıştırın ve düzenleyin
2. systemd’yi Yeniden Yükle ve Servisi Etkinleştir/Başlat:
sudo systemctl daemon-reload
sudo systemctl enable my-nodejs-daemon.service
sudo systemctl start my-nodejs-daemon.service
3. Durumu Kontrol Edin ve Logları İzleyin:
sudo systemctl status my-nodejs-daemon.service
sudo journalctl -u my-nodejs-daemon.service -f
Loglarda “Daemon başlatılıyor” ve “Daemon çalışıyor” mesajlarını görmelisiniz. Herhangi bir hata durumunda, journalctl çıktısı sorunu gidermenize yardımcı olacaktır.
E. Güvenlik İpuçları
Bir VPS üzerinde daemon çalıştırırken güvenlik her zaman öncelikli olmalıdır:
* Ayrıcalıksız Kullanıcı ile Çalıştırma: Daemon’ınızı root kullanıcısı yerine özel, ayrıcalıksız bir kullanıcı (örneğin nodejsuser veya kendi kullanıcı adınız) altında çalıştırın. Bu, bir güvenlik açığı durumunda sisteminize verilebilecek zararı sınırlar. systemd servis dosyasındaki User ve Group yönergelerini kullanın.
* Ortam Değişkenlerini Gizli Tutma: Hassas bilgileri (API anahtarları, veritabanı şifreleri) doğrudan kod içine yazmak yerine ortam değişkenleri (.env dosyası) veya systemd servis dosyasındaki Environment yönergesi ile yönetin. Bu dosyaların doğru izinlere sahip olduğundan emin olun.
* Firewall Kuralları: Sadece gerekli portları açın. Örneğin, daemon’ınız bir web sunucusu değilse ve dışarıdan erişilmesi gerekmiyorsa, portlarını kapatın veya sadece belirli IP adreslerinden erişime izin verin. ufw (Ubuntu Firewall) veya firewalld (CentOS/RHEL) gibi araçları kullanın.
* Günlük Güncellemeler: İşletim sisteminizi ve Node.js bağımlılıklarınızı düzenli olarak güncelleyin. Bu, bilinen güvenlik açıklarına karşı korunmanızı sağlar.
* Erişim Kontrolü: Proje dizininizin izinlerini doğru ayarlayın. Sadece daemon’ın çalıştığı kullanıcının okuma/yazma erişimi olmalıdır.
VII. Gelişmiş Konular ve En İyi Uygulamalar
Daemon’ınızı daha sağlam, ölçeklenebilir ve yönetilebilir hale getirmek için bazı gelişmiş konuları ve en iyi uygulamaları göz önünde bulundurabilirsiniz.
A. Süreç Yöneticileri (PM2, Forever)
systemd güçlü bir sistem yöneticisi olsa da, Node.js uygulamalarına özel bazı özellikler sunan süreç yöneticileri (process managers) vardır:
* PM2 (Process Manager 2): Node.js uygulamaları için popüler bir süreç yöneticisidir. Özellikleri:
* Otomatik Yeniden Başlatma: Uygulama çöktüğünde veya belleği aştığında otomatik olarak yeniden başlatır.
* Kümeleme (Clustering): Node.js’in tek iş parçacıklı doğasını aşmak için uygulamanızı birden fazla CPU çekirdeğinde çalıştırabilir, yük dengeleme sağlar.
* Sıfır Kesintiyle Yeniden Yükleme: Uygulama güncellemelerini sıfır kesintiyle dağıtmanıza olanak tanır.
* İzleme ve Metrikler: CPU, bellek kullanımı gibi metrikleri izlemenizi sağlar.
* systemd Entegrasyonu: pm2 startup komutu ile pm2‘yi bir systemd servisi olarak kolayca kurabilir ve ardından Node.js uygulamalarınızı pm2 altında yönetebilirsiniz. Bu durumda systemd pm2‘yi, pm2 de Node.js uygulamanızı yönetir.
pm2 kullanmak isterseniz:
npm install -g pm2
pm2 start index.js --name my-nodejs-daemon --output /path/to/log.log --error /path/to/error.log
pm2 startup systemd # pm2'yi systemd servisi olarak kurar
sudo env PATH=$PATH:/usr/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u your_user --hp /home/your_user # Komut çıktısını kullanın
pm2 save # Çalışan süreçleri kaydeder
B. İzleme ve Uyarılar (Monitoring & Alerting)
Daemon’ınızın sağlığını sürekli izlemek ve sorunlar ortaya çıktığında otomatik olarak uyarılmak kritik öneme sahiptir.
* Log Toplama: journald logları toplasa da, daha büyük ölçekli uygulamalar için ELK Stack (Elasticsearch, Logstash, Kibana) veya Grafana Loki gibi merkezi loglama çözümleri kullanılabilir. Bu, tüm servislerinizin loglarını tek bir yerden aramanızı ve analiz etmenizi sağlar.
* Metrik Toplama: Prometheus gibi araçlar, uygulamanızın CPU, bellek kullanımı, istek sayısı, hata oranı gibi metriklerini toplayabilir. Grafana ile bu metrikleri görselleştirebilirsiniz.
* Uyarılar: Prometheus Alertmanager veya doğrudan log izleme araçları (örneğin Logstash’in uyarı eklentileri) aracılığıyla e-posta, Slack veya PagerDuty gibi kanallar üzerinden uyarılar alabilirsiniz.
C. Otomatik Dağıtım (CI/CD)
Manuel dağıtım süreçleri hata yapmaya açıktır ve zaman alıcıdır. CI/CD (Sürekli Entegrasyon/Sürekli Dağıtım) boru hatları, kodunuzu her değişiklikte otomatik olarak test etmenizi ve VPS’inize dağıtmanızı sağlar.
* Araçlar: GitHub Actions, GitLab CI/CD, Jenkins, CircleCI gibi araçlar, kod deponuzdaki değişiklikleri algılayabilir, testleri çalıştırabilir, bağımlılıkları yükleyebilir ve ardından ssh veya scp kullanarak güncellenmiş kodu VPS’inize aktarabilir ve systemctl restart my-nodejs-daemon.service komutunu çalıştırabilir.
D. Veritabanı Bağlantıları ve Kalıcılık
Eğer daemon’ınız bir veritabanı kullanıyorsa:
* Bağlantı Havuzları (Connection Pooling): Her istek veya görev için yeni bir veritabanı bağlantısı açmak yerine, bağlantı havuzları kullanarak bağlantı yönetimini optimize edin. Bu, performansı artırır ve kaynak tüketimini azaltır.
* Yeniden Bağlanma Stratejileri: Veritabanı bağlantısı kesildiğinde, daemon’ınızın otomatik olarak yeniden bağlanmaya çalışması önemlidir. Geriye dönük üstel bekleme (exponential backoff) stratejisi ile denemeler yapmak, veritabanının kurtarma süresi boyunca aşırı yüklenmesini önler.
Sonuç
Bu makalede, bir Linux VPS üzerinde Node.js ile güvenilir ve sürdürülebilir bir daemon uygulamasının nasıl geliştirileceğini ve yönetileceğini kapsamlı bir şekilde inceledik. Node.js’in asenkron ve olay odaklı yapısının, arka plan görevleri için ne kadar uygun olduğunu gördük. Temel bir Node.js daemon uygulamasının nasıl yazılacağını, günlükleme ve hata yönetimi gibi kritik yönlerini ele aldık. Ardından, Linux’un güçlü systemd servis yöneticisi ile Node.js daemon’ını entegre etmenin adımlarını, bir servis dosyasının nasıl oluşturulacağını ve yönetileceğini öğrendik. Son olarak, bir VPS üzerinde dağıtım, güvenlik ipuçları ve pm2 gibi süreç yöneticileri, izleme ve CI/CD gibi gelişmiş konulara değindik.
Artık Node.js’in esnekliği ile Linux’un sağlamlığını birleştirerek kendi arka plan servislerinizi oluşturmak ve yönetmek için gerekli bilgi ve araçlara sahipsiniz. Bu rehberdeki prensipleri uygulayarak, web uygulamalarınızdan sistem izleme araçlarına kadar çeşitli görevleri yerine getiren güvenilir ve yüksek performanslı daemon’lar geliştirebilirsiniz. Unutmayın, iyi bir daemon, sadece çalışmakla kalmaz, aynı zamanda kolayca izlenebilir, yönetilebilir ve hatalara karşı dirençli olmalıdır.
