Node.js Uygulamasını Ubuntu Üzerinde Üretim Ortamına Kurulum Rehberi
Node.js uygulamalarınızı geliştirme ortamında sorunsuz bir şekilde çalıştırıyor olabilirsiniz, ancak bu, uygulamanızın üretim ortamında da aynı performansı ve güvenilirliği sunacağı anlamına gelmez. Bir Node.js uygulamasını Ubuntu sunucusu üzerinde üretim ortamına taşımak, güvenlikten performansa, kesintisiz çalışmadan kolay yönetilebilirliğe kadar birçok kritik faktörü beraberinde getirir. Bu rehber, uygulamanızın canlıya alınma sürecini adım adım, en iyi uygulamalarla ve pratik örneklerle ele alarak, sıfırdan uzman seviyesine kadar bilgi edinmenizi sağlayacaktır.
Node.js Uygulamanızı Üretim Ortamına Taşımak Neden Hayati Önem Taşır?
Bir Node.js uygulamasını üretim ortamına taşımak, sadece kodunuzu bir sunucuya kopyalayıp çalıştırmakla sınırlı değildir. Geliştirme aşamasında göz ardı edilen birçok detay, canlı ortamda ciddi sorunlara yol açabilir. Bu nedenle, uygulamanızın güvenliğini, performansını ve sürekli erişilebilirliğini sağlamak için özel bir yaklaşım benimsemek zorunludur. Peki, bu süreç neden bu kadar önemlidir ve hangi temel kavramları anlamamız gerekir?
Öncelikle, güvenlik en öncelikli konulardan biridir. Üretim ortamında çalışan bir uygulama, potansiyel siber saldırılara karşı savunmasız kalabilir. Geliştirme ortamında genellikle daha esnek olan güvenlik ayarları, üretimde çok daha sıkı olmalıdır. Örneğin, açık portlar, zayıf parolalar veya güncel olmayan yazılımlar, uygulamanız için ciddi riskler oluşturur. Bu nedenle, sunucu ve uygulama düzeyinde kapsamlı güvenlik önlemleri almak, verilerinizin ve kullanıcılarınızın korunması açısından kritik bir rol oynar.
İkinci olarak, performans ve ölçeklenebilirlik, kullanıcı deneyimini doğrudan etkileyen faktörlerdir. Bir üretim uygulaması, aynı anda binlerce hatta milyonlarca kullanıcıya hizmet verebilir. Geliştirme ortamında tek bir kullanıcıyla test edilen bir uygulama, yüksek yük altında performans sorunları yaşayabilir. Bu bağlamda, uygulamanızın hızlı yanıt vermesi, kaynakları etkin kullanması ve gerektiğinde kolayca ölçeklenebilmesi için doğru yapılandırmalar ve araçlar kullanmak esastır. Ters proxy’ler, süreç yöneticileri ve yük dengeleyiciler gibi teknolojiler, bu hedeflere ulaşmada kilit rol oynar.
Üçüncü ve son olarak, sürekli çalışma (uptime) ve bakım kolaylığı, bir üretim uygulamasının olmazsa olmazıdır. Uygulamanızın her zaman erişilebilir olması, iş sürekliliği için hayati öneme sahiptir. Bir uygulama çöktüğünde veya beklenmedik bir hata oluştuğunda, sistemin otomatik olarak toparlanabilmesi veya yöneticinin hızlıca müdahale edebilmesi gerekir. Süreç yöneticileri, loglama sistemleri ve izleme araçları, bu tür durumları yönetmeyi ve sorun gidermeyi kolaylaştırır. Ayrıca, uygulamanın güncellenmesi veya bakımının yapılması gerektiğinde, kesintileri en aza indiren veya tamamen ortadan kaldıran dağıtım stratejileri benimsemek de büyük önem taşır.
Bu temel kavramları anlamak, Node.js uygulamanızı üretim ortamına başarıyla taşımak için sağlam bir zemin oluşturacaktır. Bu rehberin ilerleyen bölümlerinde, bu prensipleri somut adımlarla nasıl uygulayacağınızı detaylı bir şekilde inceleyeceğiz. Unutmayın, iyi planlanmış bir üretim kurulumu, uygulamanızın başarısı için atılan en önemli adımlardan biridir.
Ubuntu Sunucunuzu Node.js Uygulaması İçin Nasıl Hazırlarsınız?
Node.js uygulamanızı barındıracak bir Ubuntu sunucusunun doğru şekilde hazırlanması, tüm sürecin temelini oluşturur. Bu adımlar, uygulamanızın güvenli, kararlı ve performanslı bir şekilde çalışması için vazgeçilmezdir. İşte adım adım sunucu hazırlığı:
Sistem Güncellemeleri ve Temel Bağımlılıkların Kurulumu
Yeni bir sunucuya başladığınızda yapmanız gereken ilk şey, sisteminizi güncellemektir. Bu, hem güvenlik açıklarını kapatır hem de en yeni yazılım paketlerine erişmenizi sağlar. Terminali açın ve aşağıdaki komutları çalıştırın:
sudo apt update
sudo apt upgrade -y
Bu komutlar, paket listelerinizi güncelleyecek ve mevcut tüm paketleri yükseltecektir. Ayrıca, Node.js uygulamalarının derlenmesi için gerekli olabilecek bazı temel araçları da yüklememiz gerekebilir:
sudo apt install build-essential curl git -y
build-essential paketi, C/C++ derleyicileri ve diğer geliştirme araçlarını içerir; Node.js modüllerinin bazıları yerel kod derlemesi gerektirebilir. curl, web’den dosya indirmek için, git ise uygulama kodunuzu sunucuya çekmek için kullanılacaktır.
Node.js ve npm Kurulumu: NVM Kullanımı Neden Önemlidir?
Node.js’i doğrudan Ubuntu depolarından kurmak yerine, Node Version Manager (NVM) kullanmanızı şiddetle tavsiye ederiz. NVM, aynı sunucuda birden fazla Node.js sürümünü kolayca yönetmenizi sağlar. Bu, farklı uygulamalarınızın farklı Node.js sürümlerine ihtiyaç duyması durumunda büyük esneklik sunar. NVM’yi kurmak için curl kullanabiliriz:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
Kurulum tamamlandıktan sonra, NVM’yi kabuğunuza yüklemek için terminali kapatıp yeniden açmanız veya aşağıdaki komutu çalıştırmanız gerekebilir:
source ~/.bashrc # veya ~/.zshrc eğer zsh kullanıyorsanız
Şimdi NVM ile Node.js’in en son LTS (Uzun Süreli Destek) sürümünü kurabiliriz:
nvm install --lts
nvm use --lts
nvm alias default 'lts/*'
Bu komutlar, LTS sürümünü kuracak, onu varsayılan olarak ayarlayacak ve her yeni terminal oturumunda otomatik olarak kullanılmasını sağlayacaktır. Kurulumu doğrulamak için:
node -v
npm -v
Bu komutlar, kurulu Node.js ve npm sürümlerini göstermelidir.
Uzman İpucu: NVM kullanmak, farklı projeler için farklı Node.js versiyonları gerektiren durumlarda veya Node.js versiyon yükseltmelerinde olası uyumluluk sorunlarını minimize eder. Bu esneklik, uzun vadede size büyük zaman kazandıracaktır.
Uygulama İçin Özel Kullanıcı Oluşturma ve İzinler
Uygulamanızı doğrudan root kullanıcısı altında çalıştırmak büyük bir güvenlik riskidir. Bunun yerine, uygulamanız için özel, yetkisiz bir kullanıcı oluşturmalısınız. Bu kullanıcı, uygulamanın çalışması için gerekli minimum izinlere sahip olmalıdır.
sudo adduser nodeappuser
sudo usermod -aG sudo nodeappuser # İsteğe bağlı: eğer bu kullanıcıya sudo yetkisi vermek isterseniz
nodeappuser adında yeni bir kullanıcı oluşturduk. Şimdi bu kullanıcıya geçiş yaparak uygulama kodunu klonlayabilir ve bağımlılıkları yükleyebiliriz:
sudo su - nodeappuser
Artık nodeappuser olarak oturum açtınız. Uygulama kodunuzu bu kullanıcının ana dizinine (/home/nodeappuser) veya uygun gördüğünüz başka bir dizine klonlayabilirsiniz. Bu adımlar, sunucunuzu Node.js uygulamanız için güvenli ve verimli bir şekilde hazırlamanızı sağlar. Bir sonraki adımda, uygulamanızı sunucuya nasıl dağıtacağımıza odaklanacağız.
Node.js Uygulamanızı Sunucuya Nasıl Dağıtırsınız ve Ortam Değişkenlerini Nasıl Yönetirsiniz?
Sunucunuz hazırlandıktan sonra, sıra Node.js uygulamanızın kodunu sunucuya dağıtmaya gelir. Bu süreç, kodun sunucuya aktarılması, gerekli bağımlılıkların yüklenmesi ve uygulamanın ortam değişkenlerinin doğru şekilde yapılandırılmasını içerir. Bu adımlar, uygulamanızın canlı ortamda beklenen şekilde çalışması için kritik öneme sahiptir.
Uygulama Kodunu Klonlama ve Bağımlılıkları Yükleme
Öncelikle, daha önce oluşturduğumuz nodeappuser kullanıcısına geçiş yaptığınızdan emin olun:
sudo su - nodeappuser
Uygulama kodunuzu genellikle bir Git deposundan klonlayacaksınız. Klonlama işlemini kullanıcının ana dizininde veya özel bir uygulama dizininde yapabilirsiniz. Örneğin, /home/nodeappuser/my-app gibi bir yapı oluşturabiliriz:
mkdir my-app
cd my-app
git clone https://github.com/kullaniciadi/repoadi.git . # . mevcut dizine klonlar
Kodunuz klonlandıktan sonra, uygulamanızın çalışması için gerekli olan npm paketlerini yüklemeniz gerekir. Bu işlem, uygulamanızın package.json dosyasında tanımlanan tüm bağımlılıkları indirir ve kurar:
npm install --production
--production bayrağı, yalnızca üretim bağımlılıklarının (dependencies) yüklenmesini sağlar ve geliştirme bağımlılıklarını (devDependencies) atlar. Bu, gereksiz paketlerin sunucuya kurulmasını önleyerek disk alanından tasarruf sağlar ve potansiyel güvenlik risklerini azaltır. Eğer uygulamanızın derleme adımları (örneğin TypeScript’ten JavaScript’e derleme, frontend build’leri) varsa, bunları da bu aşamada çalıştırmanız gerekebilir:
npm run build # Eğer package.json'ınızda bir 'build' script'i varsa
Ortam Değişkenlerinin Güvenli Yönetimi (.env ve dotenv)
Üretim ortamında, veritabanı bağlantı dizeleri, API anahtarları ve diğer hassas bilgiler gibi ortam değişkenlerini doğrudan kodunuzda tutmak yerine ayrı bir şekilde yönetmek esastır. Bu, güvenliği artırır ve farklı ortamlar (geliştirme, test, üretim) arasında kolayca geçiş yapmanızı sağlar.
Node.js uygulamalarında ortam değişkenlerini yönetmek için en yaygın yöntemlerden biri dotenv kütüphanesini kullanmaktır. Uygulamanızın kök dizininde .env adında bir dosya oluşturun ve hassas bilgilerinizi buraya ekleyin:
# .env dosyası örneği
NODE_ENV=production
PORT=3000
DB_HOST=localhost
DB_USER=myuser
DB_PASS=mypassword
API_KEY=your_secret_api_key
ÖNEMLİ: .env dosyasını kesinlikle Git deposuna eklemeyin! Bu dosyayı .gitignore dosyanıza ekleyerek versiyon kontrolünden hariç tutmalısınız. Hassas bilgilerinizi herkese açık bir depoda tutmak büyük bir güvenlik açığıdır.
# .gitignore dosyası örneği
node_modules/
.env
npm-debug.log*
Uygulamanızın bu değişkenleri okuyabilmesi için, genellikle uygulamanızın ana dosyasının (örneğin app.js veya index.js) en başına dotenv kütüphanesini dahil etmeniz gerekir:
require('dotenv').config(); const express = require('express'); const app = express(); const port = process.env.PORT || 3000; app.get('/', (req, res) => { res.send(Uygulama ${process.env.NODE_ENV} ortamında çalışıyor!); }); app.listen(port, () => { console.log(Sunucu ${port} portunda çalışıyor.); });Bu şekilde, uygulamanız başlatıldığında
.envdosyasındaki değişkenlerprocess.envobjesine yüklenecektir. Bu yaklaşım, ortam değişkenlerini merkezi ve güvenli bir şekilde yönetmenizi sağlar.Uzman İpucu: Çok sayıda ortam değişkeniniz varsa veya birden fazla ortam için farklı yapılandırmalarınız varsa,
dotenv-cligibi araçları veya daha gelişmiş yapılandırma yönetimi çözümlerini (örneğin HashiCorp Vault) düşünebilirsiniz. Küçük ve orta ölçekli uygulamalar için.envdosyası genellikle yeterlidir.Uygulama Testi
Dağıtımın son aşamasında, uygulamanızın sunucuda düzgün bir şekilde çalıştığından emin olmak için basit bir test yapmanız önemlidir. Uygulamanızı doğrudan Node.js ile çalıştırabilirsiniz:
node index.js # veya uygulamanızın ana dosyasının adıUygulamanızın konsolda hata vermeden başladığını ve belirtilen portta çalıştığını görmelisiniz. Eğer bir web uygulaması ise, sunucunun IP adresi ve portu üzerinden (örneğin
http://sunucu_ip_adresi:3000) tarayıcınızdan erişmeyi deneyebilirsiniz. Bu, uygulamanızın temel işlevselliğinin çalıştığını doğrular. Bir sonraki bölümde, uygulamanızın sürekli çalışmasını sağlayacak bir süreç yöneticisi olan PM2’yi nasıl kullanacağımızı öğreneceğiz.Süreç Yöneticisi PM2 ile Node.js Uygulamanızı Nasıl Yönetirsiniz?
Node.js uygulamaları varsayılan olarak tek iş parçacıklı (single-threaded) bir yapıya sahiptir. Bu durum, uygulamanızın çökmesi halinde tamamen durmasına ve erişilemez hale gelmesine neden olabilir. Ayrıca, çok çekirdekli işlemcilerin gücünden tam olarak yararlanamaz. İşte bu noktada PM2 gibi bir süreç yöneticisi devreye girer. PM2 (Process Manager 2), Node.js uygulamalarınızı üretim ortamında sürekli, güvenli ve performanslı bir şekilde çalıştırmak için tasarlanmış kapsamlı bir çözümdür.
PM2 Nedir ve Neden Kullanılmalıdır?
PM2, Node.js uygulamaları için gelişmiş bir üretim süreç yöneticisidir. Temel işlevleri şunlardır:
- Sürekli Çalışma (Uptime): Uygulamanız beklenmedik bir şekilde çöktüğünde veya bir hata oluştuğunda, PM2 uygulamayı otomatik olarak yeniden başlatır ve kesintisiz hizmet sağlar.
- Yük Dengeleme (Clustering): PM2, uygulamanızın birden fazla kopyasını (işlem kümesi) çalıştırarak, çok çekirdekli işlemcilerden tam verim almanızı sağlar. Gelen istekler bu kopyalar arasında dağıtılır, bu da performansı artırır ve tek bir işlemin çökmesi durumunda diğerlerinin çalışmaya devam etmesini sağlar.
- Log Yönetimi: Uygulama loglarını (stdout ve stderr) toplar, saklar ve yönetir. Bu, sorun giderme ve izleme için hayati önem taşır.
- Sistem Başlangıcında Otomatik Başlatma: Sunucu yeniden başlatıldığında uygulamalarınızın otomatik olarak başlamasını sağlar.
- Kolay Yönetim: Uygulamaları başlatma, durdurma, yeniden başlatma, izleme gibi işlemleri basit komutlarla yapmayı kolaylaştırır.
Bu özellikler sayesinde PM2, Node.js uygulamalarınızı üretimde çalıştırırken karşılaşılan birçok zorluğu ortadan kaldırır ve operasyonel yükü önemli ölçüde azaltır.
PM2 Kurulumu ve Temel Komutlar
PM2’yi global olarak npm ile kurabilirsiniz:
npm install pm2@latest -gKurulum tamamlandıktan sonra, uygulamanızı PM2 ile başlatmaya hazırsınız. Uygulamanızın kök dizinine gidin (
cd /home/nodeappuser/my-app) ve aşağıdaki komutu çalıştırın:pm2 start index.js --name "my-node-app" --watch -i max
index.js: Uygulamanızın ana giriş dosyası.--name "my-node-app": Uygulamanıza kolayca tanınabilecek bir isim atar.--watch: Dosya değişikliklerini izler ve değişiklik olduğunda uygulamayı otomatik olarak yeniden başlatır (geliştirme ortamı için kullanışlıdır, üretimde dikkatli kullanılmalıdır).-i max: Uygulamanızın CPU çekirdeği sayısı kadar işlem kümesi oluşturmasını sağlar. Bu, yük dengeleme için idealdir. (-i 0da aynı işlevi görür).
Uygulamanız başlatıldıktan sonra, PM2’nin durumunu kontrol edebilirsiniz:
pm2 list
Bu komut, çalışan tüm PM2 süreçlerini, durumlarını, CPU ve bellek kullanımlarını gösteren bir tablo sunar.
PM2 ile Uygulama Yönetimi ve Ayarları
PM2, uygulamalarınızı yönetmek için çeşitli komutlar sunar:
- Uygulamayı yeniden başlatma:
pm2 restart my-node-app - Uygulamayı durdurma:
pm2 stop my-node-app - Uygulamayı silme (PM2’nin izlemesinden kaldırma):
pm2 delete my-node-app - Logları görüntüleme:
pm2 logs my-node-app(Gerçek zamanlı log takibi içinpm2 logs --follow) - İzleme paneli:
pm2 monit(CPU, bellek ve HTTP isteklerini görsel olarak izler)
Sistem Başlangıcında Otomatik Başlatma
Sunucu yeniden başlatıldığında uygulamalarınızın otomatik olarak başlamasını sağlamak için PM2’nin başlangıç betiğini oluşturmanız gerekir:
pm2 startup systemd
Bu komut, sisteminiz için uygun bir başlangıç betiği oluşturacak ve size çalıştırmanız gereken bir komut satırı çıktısı verecektir (genellikle sudo env PATH=$PATH:/usr/bin /usr/local/bin/pm2 startup systemd -u nodeappuser --hp /home/nodeappuser gibi bir şey). Bu komutu çalıştırdıktan sonra, mevcut PM2 süreçlerinizi kaydetmeniz gerekir:
pm2 save
Bu, PM2’nin mevcut uygulama listesini kaydetmesini ve sunucu yeniden başlatıldığında bu listeyi kullanarak uygulamaları başlatmasını sağlar.
Ortam Değişkenlerini PM2 ile Yönetme
Daha önce .env dosyası ile yönettiğimiz ortam değişkenlerini PM2’ye de tanımlayabiliriz. Bu, genellikle ecosystem.config.js adında bir yapılandırma dosyası ile yapılır:
// ecosystem.config.js
module.exports = {
apps : [{
name : 'my-node-app',
script : 'index.js',
instances : 'max',
exec_mode : 'cluster',
env: {
NODE_ENV: 'development',
PORT: 3000
},
env_production : {
NODE_ENV: 'production',
PORT: 80, // Nginx ile 80 veya 443'e yönlendireceğiz
DB_HOST: 'localhost',
API_KEY: 'your_production_api_key'
}
}]
};
Bu dosyayı uygulamanızın kök dizinine yerleştirdikten sonra, PM2’yi bu yapılandırma dosyasıyla başlatabilirsiniz:
pm2 start ecosystem.config.js --env production
Bu, env_production bloğundaki değişkenleri kullanarak uygulamayı başlatır. Bu yaklaşım, farklı ortamlar için farklı yapılandırmaları tek bir dosyada tutmanızı sağlar.
Uzman İpucu: Hassas ortam değişkenlerini (örneğin veritabanı şifreleri)
ecosystem.config.jsdosyasına doğrudan yazmak yerine, sunucunun ortam değişkenleri olarak ayarlamak (örneğin/etc/environmentveya~/.bashrcdosyasına ekleyipsourceetmek) daha güvenli bir yöntem olabilir. PM2, bu sistem değişkenlerini otomatik olarak uygulamanıza iletecektir.
Vaka Analizi: PM2 ile Kesintisiz Dağıtım
Bir e-ticaret uygulamasını düşünelim. Müşterilerin sürekli alışveriş yapabildiği bir ortamda, uygulama güncellemeleri sırasında dahi kesinti yaşanmaması kritik öneme sahiptir. PM2, bu senaryoda “sıfır kesinti” dağıtımı (zero-downtime deployment) sağlamak için kullanılabilir. Uygulamanızın yeni sürümünü dağıtırken:
- Yeni kodu sunucuya çekin ve bağımlılıkları yükleyin.
pm2 reload my-node-appkomutunu çalıştırın. PM2, yeni kodu yüklerken eski işlemleri çalışır durumda tutar. Yeni kod başarıyla başlatıldığında, eski işlemler sorunsuz bir şekilde sonlandırılır. Bu sayede kullanıcılar, uygulama güncellenirken dahi herhangi bir kesinti hissetmezler.
PM2, Node.js üretim ortamlarının vazgeçilmez bir parçasıdır. Doğru yapılandırıldığında, uygulamanızın kararlılığını, performansını ve yönetilebilirliğini büyük ölçüde artırır. Bir sonraki bölümde, Nginx’i ters proxy olarak nasıl yapılandıracağımızı ve SSL/TLS güvenliğini nasıl sağlayacağımızı inceleyeceğiz.
Nginx Ters Proxy Olarak Nasıl Yapılandırılır ve SSL/TLS Nasıl Sağlanır?
Node.js uygulamalarınızı doğrudan internete açmak, genellikle önerilmeyen bir güvenlik uygulamasıdır. Bunun yerine, bir ters proxy sunucusu kullanmak çok daha güvenli ve performanslı bir yaklaşımdır. Nginx, bu amaçla en popüler ve güçlü web sunucularından biridir. Nginx’i uygulamanızın önüne yerleştirerek, hem güvenliği artırabilir hem de performansı optimize edebilirsiniz.
Nginx Neden Kullanılmalıdır?
Nginx’i Node.js uygulamanızın önünde bir ters proxy olarak kullanmanın birçok avantajı vardır:
- Yük Dengeleme: Nginx, gelen istekleri birden fazla Node.js işlem kümesi arasında dağıtabilir (PM2 ile oluşturduğumuz gibi), bu da uygulamanızın daha fazla trafiği işlemesine olanak tanır.
- SSL/TLS Sonlandırma: SSL/TLS şifrelemesini Nginx’te sonlandırmak, Node.js uygulamanızın bu yükten kurtulmasını sağlar. Nginx, bu işlemi çok daha verimli bir şekilde yapabilir.
- Statik Dosya Sunumu: Resimler, CSS, JavaScript dosyaları gibi statik içerikleri Nginx doğrudan sunabilir. Bu, Node.js uygulamanızın sadece dinamik içerik oluşturmaya odaklanmasını sağlayarak performansını artırır.
- Güvenlik: Nginx, doğrudan erişimi engeller ve uygulamanızı çeşitli saldırılara karşı korur. Ayrıca, istekleri filtreleme ve kötü niyetli trafiği engelleme yeteneğine sahiptir.
- Sıkıştırma (Gzip) ve Önbellekleme: Nginx, içeriği sıkıştırarak bant genişliğini azaltabilir ve sık erişilen içerikleri önbelleğe alarak yanıt sürelerini kısaltabilir.
Nginx Kurulumu
Nginx’i Ubuntu’ya kurmak oldukça basittir:
sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
Kurulumdan sonra, tarayıcınızdan sunucunuzun IP adresine giderek Nginx’in varsayılan karşılama sayfasını görmelisiniz. Bu, Nginx’in başarıyla çalıştığını gösterir.
Nginx Yapılandırması: Ters Proxy ve Statik Dosya Sunumu
Şimdi Nginx’i Node.js uygulamanız için ters proxy olarak yapılandıralım. Yeni bir yapılandırma dosyası oluşturun:
sudo nano /etc/nginx/sites-available/my-node-app
Aşağıdaki içeriği dosyaya yapıştırın ve uygulamanızın çalıştığı portu (örneğin 3000) ve sunucu adınızı (alan adınız veya IP adresiniz) güncelleyin:
server { listen 80; server_name your_domain.com www.your_domain.com; # Alan adınızı buraya yazın location / { proxy_pass http://localhost:3000; # Node.js uygulamanızın çalıştığı port proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # Statik dosyalar için örnek yapılandırma (isteğe bağlı) # location /static/ { # alias /home/nodeappuser/my-app/public/; # Statik dosyalarınızın yolu # expires 30d; # Önbellekleme süresi # add_header Cache-Control "public, no-transform"; # } }Bu yapılandırma, Nginx’in 80 portuna gelen tüm istekleri Node.js uygulamanızın çalıştığı
http://localhost:3000adresine yönlendirmesini sağlar.proxy_set_headerdirektifleri, Node.js uygulamanızın orijinal istemci IP adresi gibi bilgileri alabilmesi için önemlidir.Yapılandırma dosyasını kaydettikten sonra, etkinleştirmek için bir sembolik bağlantı oluşturun ve Nginx yapılandırmasını test edin:
sudo ln -s /etc/nginx/sites-available/my-node-app /etc/nginx/sites-enabled/ sudo nginx -tEğer test başarılı olursa, Nginx’i yeniden başlatın:
sudo systemctl restart nginxArtık alan adınız veya sunucu IP adresiniz üzerinden (port belirtmeden) Node.js uygulamanıza erişebiliyor olmalısınız.
SSL/TLS Kurulumu (Certbot/Let’s Encrypt)
Güvenli bir üretim ortamı için SSL/TLS sertifikası kullanmak zorunludur. Let’s Encrypt, ücretsiz SSL sertifikaları sağlayan popüler bir hizmettir ve Certbot aracı ile kolayca entegre edilebilir. İlk olarak Certbot’u kuralım:
sudo apt install certbot python3-certbot-nginx -yŞimdi Nginx için SSL sertifikası alabiliriz. Certbot, Nginx yapılandırmanızı otomatik olarak algılayacak ve güncelleyecektir:
sudo certbot --nginx -d your_domain.com -d www.your_domain.comCertbot size bazı sorular soracak (e-posta adresi, hizmet şartlarını kabul etme vb.). İşlem tamamlandığında, Nginx yapılandırma dosyanız otomatik olarak 443 portu için SSL ayarlarıyla güncellenecek ve HTTP istekleri HTTPS’e yönlendirilecektir. Sertifikaların otomatik olarak yenilenmesi için Certbot’un bir cron işi oluşturduğunu da unutmayın.
Uzman İpucu: Nginx yapılandırmasında
gzip on;direktifini ekleyerek HTTP yanıtlarını sıkıştırabilir ve bant genişliği kullanımını azaltarak performansı artırabilirsiniz. Ayrıca, statik dosyalar içinexpiresdirektifini kullanarak tarayıcı önbelleklemesini etkinleştirmek, tekrar eden ziyaretlerde yükleme sürelerini önemli ölçüde hızlandırır.Mobil Uyumlu HTML Örneği (Frontend İpuçları)
Bu makale sunucu kurulumuyla ilgili olsa da, dağıttığınız uygulamaların kullanıcı deneyimi açısından mobil uyumlu olması kritik öneme sahiptir. Nginx, bu tür responsive frontend dosyalarını hızlıca sunabilir. İşte basit bir CSS media query örneği:
Node.js Uygulamanız Üretimde!
Tebrikler! Uygulamanız Ubuntu üzerinde Nginx ve PM2 ile başarılı bir şekilde çalışıyor. Bu sayfa, uygulamanızın mobil cihazlarda nasıl görüneceğini gösteren basit bir örnek içeriyor.
Tarayıcınızın boyutunu değiştirerek veya mobil bir cihazdan erişerek responsive tasarımın nasıl çalıştığını görebilirsiniz.
Bu HTML dosyasını Nginx’in statik dosya sunumu için ayarladığınız bir dizine (örneğin
/home/nodeappuser/my-app/public/index.html) yerleştirerek, Nginx’in bu dosyayı doğrudan sunmasını sağlayabilirsiniz. Nginx, bu dosyaları çok hızlı bir şekilde sunarak Node.js uygulamanızın üzerindeki yükü azaltır.Nginx’in doğru yapılandırılması, uygulamanızın hem güvenliğini hem de performansını artırır. SSL/TLS ile şifrelenmiş trafik, kullanıcılarınızın verilerini korurken, Nginx’in ters proxy yetenekleri uygulamanızın daha kararlı ve ölçeklenebilir olmasını sağlar. Artık uygulamanızın temel dağıtım ve yönetim adımlarını tamamladınız. Bir sonraki bölümde, güvenlik ve performans optimizasyonlarına odaklanacağız.
Güvenlik ve Performans Optimizasyonları Nelerdir?
Bir Node.js uygulamasını üretim ortamına dağıtmak, sadece uygulamanın çalışır durumda olmasını sağlamakla kalmaz, aynı zamanda onun güvenli ve mümkün olan en iyi performansı sunmasını da gerektirir. Bu bölümde, sunucu ve uygulama düzeyinde uygulayabileceğiniz temel güvenlik ve performans optimizasyonlarını ele alacağız.
Güvenlik Duvarı (UFW) Yapılandırması
Sunucunuzun güvenliği için ilk ve en önemli adımlardan biri, bir güvenlik duvarı yapılandırmaktır. Ubuntu’da UFW (Uncomplicated Firewall) kullanımı kolay ve etkili bir seçenektir. Yalnızca uygulamanızın ve yönetim araçlarınızın ihtiyaç duyduğu portları açarak, sunucunuza yetkisiz erişimi engelleyebilirsiniz.
sudo ufw allow OpenSSH # SSH erişimine izin ver sudo ufw allow 'Nginx Full' # Nginx'in HTTP ve HTTPS portlarına (80, 443) izin ver sudo ufw enable # Güvenlik duvarını etkinleştir sudo ufw status # Güvenlik duvarı durumunu kontrol etEğer uygulamanız farklı bir portta çalışıyorsa (örneğin PM2’nin izleme paneli için), o portu da açmanız gerekebilir. Ancak, gereksiz portları açık bırakmaktan kaçının. Örneğin, Node.js uygulamanız 3000 portunda çalışsa da, Nginx bu portu dahili olarak kullandığı için dışarıdan erişime açmanıza gerek yoktur.
SSH Güvenliği
SSH, sunucunuza uzaktan erişim için kullandığınız ana protokoldür ve bu nedenle özellikle hedef alınan bir noktadır. SSH güvenliğini artırmak için şu adımları izleyin:
- Parola yerine Anahtar Tabanlı Kimlik Doğrulama Kullanın: Bu, çok daha güvenlidir. Yerel makinenizde bir SSH anahtar çifti oluşturun (
ssh-keygen) ve genel anahtarınızı sunucunuzdaki~/.ssh/authorized_keysdosyasına kopyalayın.- Root Erişimi Kapatın: Root kullanıcısının doğrudan SSH ile giriş yapmasını engelleyin. Bunun yerine, normal bir kullanıcıyla giriş yapın ve gerektiğinde
sudokullanın./etc/ssh/sshd_configdosyasındaPermitRootLogin noayarını yapın.- Varsayılan SSH Portunu Değiştirin: SSH’in varsayılan 22 portunu farklı, rastgele bir porta (örneğin 2222) değiştirerek otomatik saldırıları azaltabilirsiniz.
/etc/ssh/sshd_configdosyasındaPort 2222ayarını yapın.- Fail2ban Kurun: Bu araç, tekrar eden başarısız giriş denemelerini algılar ve saldırgan IP adreslerini geçici olarak engeller.
Bu değişiklikleri yaptıktan sonra
sudo systemctl restart sshdkomutuyla SSH servisini yeniden başlatmayı unutmayın. Yeni portu UFW’de açtığınızdan da emin olun.Ortam Değişkenlerinin Güvenli Yönetimi
Daha önce bahsettiğimiz gibi, hassas bilgileri (API anahtarları, veritabanı şifreleri) kodunuzda veya Git deposunda tutmaktan kaçının.
.envdosyaları iyi bir başlangıç olsa da, daha yüksek güvenlik gerektiren durumlar için:
- Sistem Ortam Değişkenleri: Hassas bilgileri doğrudan sunucunun ortam değişkenleri olarak ayarlayın (örneğin
/etc/environmentdosyasına ekleyerek veya PM2’nin yapılandırma dosyasındaprocess.env.MY_SECRETolarak referans vererek). - Sır Yönetim Sistemleri: Kurumsal düzeyde uygulamalar için HashiCorp Vault, AWS Secrets Manager veya Azure Key Vault gibi özel sır yönetim sistemleri kullanmayı düşünün.
Performans İpuçları ve Optimizasyonları
- Gzip Sıkıştırma: Nginx’i kullanarak HTTP yanıtlarını sıkıştırın. Bu, bant genişliği kullanımını azaltır ve istemciler için yükleme sürelerini hızlandırır. Nginx yapılandırmanızda
gzip on;ve ilgili ayarları ekleyin. - Önbellekleme: Nginx’i statik dosyalar (CSS, JS, resimler) için önbellekleme yapacak şekilde yapılandırın. Ayrıca, Node.js uygulamanızda sık erişilen veriler için Redis veya Memcached gibi bir önbellek katmanı kullanmayı düşünün.
- Veritabanı Optimizasyonu: Veritabanı sorgularınızı optimize edin, uygun indeksler kullanın ve N+1 sorgu sorunlarından kaçının. Veritabanı bağlantı havuzu (connection pooling) kullanmak da performansı artırır.
- Node.js Uygulama Optimizasyonu:
- Asenkron İşlemler: Blocking (engelleyici) işlemleri minimize edin ve asenkron programlamanın avantajlarından tam olarak yararlanın.
- Middleware Optimizasyonu: Gereksiz middleware’lerden kaçının ve middleware sıralamasını optimize edin.
- Hata Yönetimi: Uygulamanızdaki hataları düzgün bir şekilde yönetin, böylece beklenmedik çökmeler tüm uygulamanızı etkilemez.
- Log Yönetimi: PM2 loglarını düzenli olarak kontrol edin. Logların diskte çok fazla yer kaplamaması için log rotasyonu (logrotate) yapılandırın. PM2, kendi log rotasyonunu da destekler.
Uzman İpucu: Uygulamanızın performansını sürekli izlemek için Prometheus, Grafana veya New Relic gibi izleme araçlarını kullanın. Bu araçlar, performans darboğazlarını erken tespit etmenize ve proaktif önlemler almanıza yardımcı olur.
Otomatik Dağıtım (CI/CD) Entegrasyonu Nasıl Yapılır?
Manuel dağıtım süreçleri hata yapmaya açıktır ve zaman alıcıdır. Sürekli Entegrasyon/Sürekli Dağıtım (CI/CD) boru hatları, kod değişikliklerini otomatik olarak test etme ve üretim ortamına dağıtma yeteneği sağlayarak bu sorunları çözer. Bu, geliştirme hızını artırırken hataları azaltır.
Basit bir CI/CD akışı genellikle şunları içerir:
- Geliştirici kodu Git deposuna (GitHub, GitLab, Bitbucket) gönderir.
- CI/CD aracı (GitHub Actions, GitLab CI/CD, Jenkins) bu değişikliği algılar.
- Kod testleri çalıştırılır (birim testleri, entegrasyon testleri).
- Testler başarılı olursa, uygulama derlenir (eğer varsa) ve üretim sunucusuna dağıtılır.
Örnek bir GitHub Actions dağıtım betiği (basitleştirilmiş):
name: Deploy Node.js App to Production on: push: branches: - main # main branch'ine yapılan push'larda tetiklenir jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 - name: Setup Node.js uses: actions/setup-node@v2 with: node-version: '16' # Kullanılan Node.js versiyonu - name: Install dependencies run: npm install --production - name: SSH into server and deploy uses: appleboy/ssh-action@master with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USERNAME }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd /home/nodeappuser/my-app git pull origin main npm install --production pm2 reload my-node-app --env production # PM2 ile uygulamayı kesintisiz yeniden yükleBu örnekte, GitHub Secrets kullanarak hassas bilgileri (SSH host, username, private key) güvenli bir şekilde saklıyoruz. Gerçek dünya senaryolarında, bu betiği daha fazla test, linting ve hata kontrolü adımlarıyla genişletebilirsiniz.
Güvenlik ve performans optimizasyonları, uygulamanızın üretimde uzun ömürlü ve başarılı olmasının anahtarıdır. Sürekli izleme ve proaktif yaklaşımlar, olası sorunları büyümeden çözmenize yardımcı olacaktır. CI/CD entegrasyonu ise bu süreci otomatikleştirerek insan hatasını minimize eder ve dağıtım süreçlerinizi hızlandırır.
Sonuç ve Sıkça Sorulan Sorular
Bu kapsamlı rehber boyunca, bir Node.js uygulamasını Ubuntu sunucusu üzerinde üretim ortamına başarıyla dağıtmak için gereken adımları ve en iyi uygulamaları derinlemesine inceledik. Sunucu hazırlığından başlayarak, Node.js ve PM2 ile uygulama yönetimine, Nginx ile ters proxy yapılandırmasından SSL/TLS güvenliğine ve son olarak güvenlik ile performans optimizasyonlarına kadar birçok kritik konuya değindik. Amacımız, uygulamanızın sadece çalışır durumda olmasını sağlamak değil, aynı zamanda güvenli, kararlı, yüksek performanslı ve kolay yönetilebilir bir yapıya sahip olmasını sağlamaktır.
Unutmayın ki üretim ortamı kurulumu tek seferlik bir işlem değildir. Sürekli izleme, düzenli güncellemeler ve güvenlik denetimleri, uygulamanızın uzun vadeli başarısı için hayati öneme sahiptir. Bu rehberdeki bilgileri uygulayarak, Node.js projelerinizi güvenle canlıya alabilir ve kullanıcılara kesintisiz bir deneyim sunabilirsiniz. Başarılar dileriz!
Sıkça Sorulan Sorular (SSS)
- Node.js uygulamamı PM2 olmadan çalıştırabilir miyim?
- Evet,
node index.jskomutuyla doğrudan çalıştırabilirsiniz. Ancak bu, üretim ortamı için önerilmez. PM2 olmadan uygulamanız çöktüğünde otomatik olarak yeniden başlamaz, çok çekirdekli işlemcilerden faydalanamaz ve log yönetimi gibi kritik özelliklerden mahrum kalırsınız. PM2, üretimde kararlılık ve performans için vazgeçilmezdir. - Güvenlik neden bu kadar önemli, geliştirme ortamındaki gibi bırakamaz mıyım?
- Kesinlikle hayır. Geliştirme ortamı genellikle izole ve düşük riskli bir ortamdır. Üretim ortamı ise herkese açık ve potansiyel saldırılara maruz kalan bir alandır. Zayıf güvenlik, veri ihlallerine, hizmet kesintilerine, kötü amaçlı yazılım bulaşmalarına ve itibar kaybına yol açabilir. Güvenlik duvarı, SSH güçlendirmesi ve ortam değişkeni yönetimi gibi adımlar, uygulamanızı ve verilerinizi korumak için zorunludur.
- Performans için Nginx ve PM2 dışında başka ne yapabilirim?
- Performansı artırmak için birkaç ek adım atabilirsiniz:
- Veritabanı Optimizasyonu: Sorgularınızı optimize edin, doğru indeksleri kullanın ve veritabanı bağlantı havuzu (connection pooling) kullanın.
- Önbellekleme: Redis veya Memcached gibi bir önbellek sunucusu kullanarak sık erişilen verileri önbelleğe alın.
- CDN (Content Delivery Network): Statik dosyalarınızı (resimler, CSS, JS) global bir CDN üzerinden sunarak yükleme sürelerini azaltın.
- Kod Optimizasyonu: Node.js kodunuzdaki darboğazları tespit edin (profilleme araçlarıyla) ve optimize edin. Bellek sızıntılarını kontrol edin.
- HTTP/2 Kullanımı: Nginx ile HTTP/2’yi etkinleştirerek daha hızlı ve verimli iletişim sağlayın.
- Node.js uygulamamı güncellerken kesinti yaşamak istemiyorum, nasıl yapabilirim?
- PM2’nin
pm2 reload my-node-appkomutunu kullanabilirsiniz. Bu komut, uygulamanızın yeni sürümünü başlatırken eski sürümün hala istekleri işlemesine izin verir. Yeni sürüm başarıyla başlatıldığında, eski sürüm gracefully (zarifçe) kapatılır. Bu sayede kullanıcılar, uygulama güncellemesi sırasında herhangi bir kesinti yaşamazlar. CI/CD boru hatlarını kullanarak bu süreci otomatikleştirmeniz de mümkündür.