Node.js ile Basit HTTP Sunucusu Kurulumu
Bir web uygulaması geliştiriyorsunuz ya da sadece bir şeyler denemek istiyorsunuz, her iki durumda da Node.js ile HTTP sunucusu kurmak öğrenmesi gereken en temel becerilerden biri. Konuya “merhaba dünya” seviyesinde değil, gerçekten işe yarar bir şeyler yapabileceğiniz noktadan bakacağız. Sıfırdan başlayıp production ortamında kullanılabilecek bir yapıya kadar gideceğiz.
Node.js Kurulumu
Önce temelden başlayalım. Node.js kurulumu için doğrudan resmi siteden indirme yapabilirsiniz ama benim tavsiyem nvm (Node Version Manager) kullanmak. Neden? Çünkü farklı projeler farklı Node.js sürümleri gerektirebilir ve nvm ile bu geçişi saniyeler içinde yapabilirsiniz.
# nvm kurulumu
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# Terminal yeniden başlatılır ya da şu komut çalıştırılır
source ~/.bashrc
# Node.js LTS sürümünü kur
nvm install --lts
# Kurulu sürümü kontrol et
node --version
npm --version
Ubuntu veya Debian tabanlı sistemlerde doğrudan paket yöneticisi ile de kurabilirsiniz ama bu yöntemle genellikle eski sürümler gelir. nvm tercih edin derim.
Windows kullanıyorsanız nvm-windows aracını kullanabilirsiniz ya da doğrudan nodejs.org adresinden MSI paketini indirip kurabilirsiniz. WSL2 üzerinde çalışıyorsanız Linux kurulum adımlarını takip edin, çok daha temiz bir deneyim sunar.
İlk HTTP Sunucusu: Core http Modülü
Node.js’in dahili http modülü ile hiçbir dış bağımlılık olmadan bir HTTP sunucusu ayağa kaldırabilirsiniz. Bu temeli anlamak önemli çünkü Express gibi framework’ler de altında bu modülü kullanıyor.
mkdir http-sunucu-demo
cd http-sunucu-demo
Şimdi sunucu.js adında bir dosya oluşturun:
cat > sunucu.js << 'EOF'
const http = require('http');
const HOST = 'localhost';
const PORT = 3000;
const sunucu = http.createServer((istek, yanit) => {
// Gelen isteğin URL ve metodunu logla
console.log(`[${new Date().toISOString()}] ${istek.method} ${istek.url}`);
// Yanit başlıklarını ayarla
yanit.writeHead(200, {
'Content-Type': 'text/plain; charset=utf-8',
'X-Powered-By': 'Node.js'
});
yanit.end('Merhaba! Sunucu çalışıyor.n');
});
sunucu.listen(PORT, HOST, () => {
console.log(`Sunucu http://${HOST}:${PORT} adresinde çalışıyor`);
});
// Hata yakalama
sunucu.on('error', (hata) => {
if (hata.code === 'EADDRINUSE') {
console.error(`Port ${PORT} zaten kullanımda!`);
process.exit(1);
}
throw hata;
});
EOF
Sunucuyu başlatın:
node sunucu.js
Başka bir terminal açıp test edin:
curl -i http://localhost:3000
Gayet güzel. Ama bu sunucu her isteğe aynı yanıtı veriyor. Gerçek dünyada URL’ye göre farklı içerik döndürmeniz gerekiyor.
URL Routing: Manuel Yönlendirme
Basit bir routing mekanizması ekleyelim. Büyük projelerde Express kullanmak daha mantıklı olsa da küçük araçlar için bu yaklaşım oldukça işe yarıyor.
cat > router.js << 'EOF'
const http = require('http');
const url = require('url');
const PORT = 3000;
// Rotaları tanımla
const rotalar = {
'GET /': (istek, yanit) => {
yanit.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
yanit.end(JSON.stringify({
mesaj: 'Ana sayfa',
zaman: new Date().toISOString()
}));
},
'GET /saglik': (istek, yanit) => {
yanit.writeHead(200, { 'Content-Type': 'application/json' });
yanit.end(JSON.stringify({
durum: 'aktif',
uptime: process.uptime(),
bellek: process.memoryUsage()
}));
},
'GET /hakkinda': (istek, yanit) => {
yanit.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
yanit.end('Bu bir Node.js demo sunucusudur.n');
}
};
const sunucu = http.createServer((istek, yanit) => {
const parcalanmisUrl = url.parse(istek.url);
const rota = `${istek.method} ${parcalanmisUrl.pathname}`;
console.log(`[${new Date().toISOString()}] ${rota}`);
if (rotalar[rota]) {
rotalar[rota](istek, yanit);
} else {
yanit.writeHead(404, { 'Content-Type': 'application/json' });
yanit.end(JSON.stringify({ hata: 'Sayfa bulunamadı', kod: 404 }));
}
});
sunucu.listen(PORT, () => {
console.log(`Router sunucusu port ${PORT}'de çalışıyor`);
});
EOF
node router.js
Test edelim:
# Ana sayfa
curl http://localhost:3000/
# Sağlık kontrolü
curl http://localhost:3000/saglik
# Olmayan bir sayfa
curl http://localhost:3000/olmayan
Express ile Profesyonel Kurulum
Artık ciddi bir iş yapıyorsanız Express kullanmanız şart. npm ile projeyi başlatıp Express kuralım.
# Yeni proje dizini
mkdir express-uygulama
cd express-uygulama
# package.json oluştur
npm init -y
# Express kur
npm install express
# Geliştirme için nodemon kur
npm install --save-dev nodemon
package.json içindeki scripts bölümünü düzenleyin:
cat > package.json << 'EOF'
{
"name": "express-uygulama",
"version": "1.0.0",
"description": "Express ile HTTP sunucusu",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
},
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"nodemon": "^3.0.1"
}
}
EOF
Şimdi app.js dosyasını oluşturalım:
cat > app.js << 'EOF'
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware'ler
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// İstek loglama middleware
app.use((req, res, next) => {
const baslangic = Date.now();
res.on('finish', () => {
const sure = Date.now() - baslangic;
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url} - ${res.statusCode} (${sure}ms)`);
});
next();
});
// Rotalar
app.get('/', (req, res) => {
res.json({
mesaj: 'Express sunucusu çalışıyor',
versiyon: '1.0.0',
zaman: new Date().toISOString()
});
});
app.get('/saglik', (req, res) => {
res.json({
durum: 'OK',
uptime: `${Math.floor(process.uptime())} saniye`,
bellek: {
kullanilan: `${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)} MB`,
toplam: `${Math.round(process.memoryUsage().heapTotal / 1024 / 1024)} MB`
}
});
});
// POST örneği
app.post('/veri', (req, res) => {
const { ad, email } = req.body;
if (!ad || !email) {
return res.status(400).json({
hata: 'Ad ve email alanları zorunludur'
});
}
res.status(201).json({
mesaj: 'Veri alındı',
veri: { ad, email }
});
});
// 404 handler
app.use((req, res) => {
res.status(404).json({
hata: 'Endpoint bulunamadı',
istenenYol: req.url
});
});
// Genel hata handler
app.use((err, req, res, next) => {
console.error('Sunucu hatası:', err.message);
res.status(500).json({
hata: 'Sunucu hatası oluştu'
});
});
app.listen(PORT, () => {
console.log(`Express sunucusu http://localhost:${PORT} adresinde çalışıyor`);
console.log(`Ortam: ${process.env.NODE_ENV || 'development'}`);
});
module.exports = app;
EOF
npm run dev
Statik Dosya Sunumu
Birçok projede HTML, CSS, JavaScript dosyalarını da sunmanız gerekir. Express bunu çok kolaylaştırıyor.
# Statik dosyalar için dizin oluştur
mkdir -p public/css public/js
cat > public/index.html << 'EOF'
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>Node.js Sunucu</title>
<link rel="stylesheet" href="/css/stil.css">
</head>
<body>
<h1>Node.js HTTP Sunucusu Çalışıyor!</h1>
<div id="durum"></div>
<script src="/js/uygulama.js"></script>
</body>
</html>
EOF
cat > public/css/stil.css << 'EOF'
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 50px auto;
padding: 20px;
background: #f5f5f5;
}
h1 { color: #333; }
#durum { padding: 15px; background: #e8f5e9; border-radius: 5px; }
EOF
cat > public/js/uygulama.js << 'EOF'
fetch('/saglik')
.then(r => r.json())
.then(veri => {
document.getElementById('durum').innerHTML =
`Durum: ${veri.durum} | Uptime: ${veri.uptime}`;
});
EOF
app.js dosyasına statik dosya middleware ekleyin. app.use(express.json()) satırından sonra şunu ekleyin:
# app.js'e statik dosya desteği ekle
sed -i "/app.use(express.json())/a app.use(express.static('public'));" app.js
Artık tarayıcıdan http://localhost:3000 adresine girdiğinizde HTML sayfasını göreceksiniz.
Ortam Değişkenleri ile Konfigürasyon
Hardcoded değerler production’da büyük sorun çıkarır. .env dosyası ile konfigürasyonu yönetelim.
npm install dotenv
cat > .env << 'EOF'
PORT=3000
NODE_ENV=development
APP_ADI=Demo Sunucu
LOG_SEVIYESI=debug
EOF
cat > .gitignore << 'EOF'
node_modules/
.env
*.log
EOF
app.js‘in en üstüne şunu ekleyin:
# app.js başına dotenv ekle
sed -i '1s/^/require("dotenv").config();n/' app.js
Artık uygulama içinde process.env.APP_ADI gibi değişkenlere erişebilirsiniz. Production’da bu değerleri sunucu ortam değişkeni olarak tanımlarsınız, .env dosyasını asla versiyona koymaz ve asla production sunucusuna yüklemezsiniz.
PM2 ile Production’da Çalıştırma
Geliştirme ortamında node app.js yeterli. Ama production’da sunucu çöktüğünde otomatik yeniden başlamasını, log yönetimini ve cluster modunu istiyorsunuz. PM2 tam bu iş için var.
# PM2 global kur
npm install -g pm2
# Uygulamayı başlat
pm2 start app.js --name "http-sunucu"
# Durum kontrol
pm2 status
# Logları takip et
pm2 logs http-sunucu
# Sunucu yeniden başladığında PM2'nin de başlaması için
pm2 startup
pm2 save
PM2 ile cluster modu kullanarak tüm CPU çekirdeklerini kullanabilirsiniz:
# Tüm CPU çekirdeklerini kullan
pm2 start app.js --name "http-sunucu" -i max
# Ya da belirli sayıda instance
pm2 start app.js --name "http-sunucu" -i 4
# Uygulamayı yeniden başlat
pm2 restart http-sunucu
# Sıfır downtime ile yeniden yükle
pm2 reload http-sunucu
Bir ecosystem.config.js dosyası oluşturmak daha temiz bir yaklaşım:
cat > ecosystem.config.js << 'EOF'
module.exports = {
apps: [{
name: 'http-sunucu',
script: 'app.js',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'development',
PORT: 3000
},
env_production: {
NODE_ENV: 'production',
PORT: 8080
},
log_date_format: 'YYYY-MM-DD HH:mm:ss',
error_file: './logs/hata.log',
out_file: './logs/cikti.log',
max_memory_restart: '500M'
}]
};
EOF
mkdir -p logs
# Development ortamında başlat
pm2 start ecosystem.config.js
# Production ortamında başlat
pm2 start ecosystem.config.js --env production
Nginx ile Ters Proxy Kurulumu
Node.js’i doğrudan 80 veya 443 portunda çalıştırmak yerine Nginx’i ters proxy olarak kullanmak hem güvenli hem de performans açısından daha iyi.
# Nginx kurulumu (Ubuntu/Debian)
sudo apt update && sudo apt install nginx -y
# Yeni site konfigürasyonu oluştur
sudo nano /etc/nginx/sites-available/nodejs-uygulama
Konfigürasyon içeriği:
cat > /tmp/nginx-nodejs.conf << 'EOF'
server {
listen 80;
server_name example.com www.example.com;
# Gzip sıkıştırma
gzip on;
gzip_types text/plain application/json application/javascript text/css;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
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;
proxy_cache_bypass $http_upgrade;
# Zaman aşımı ayarları
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Statik dosyalar için Nginx'i kullan
location /static/ {
alias /var/www/nodejs-uygulama/public/;
expires 30d;
add_header Cache-Control "public, no-transform";
}
}
EOF
sudo cp /tmp/nginx-nodejs.conf /etc/nginx/sites-available/nodejs-uygulama
sudo ln -s /etc/nginx/sites-available/nodejs-uygulama /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Bu kurulumla Nginx dışarıdan gelen trafiği alır ve Node.js uygulamanıza iletir. SSL sertifikası için Let’s Encrypt kullanıyorsanız Certbot otomatik olarak bu konfigürasyonu güncelleyecektir.
Güvenlik için Temel Önlemler
Production ortamında mutlaka almanız gereken birkaç önlem var.
# Helmet ile HTTP başlıklarını güvenli hale getir
npm install helmet
# Rate limiting için
npm install express-rate-limit
app.js‘e güvenlik middleware’lerini ekleyin:
cat > guvenlik.js << 'EOF'
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
// Helmet middleware - güvenli HTTP başlıkları
const helmetMiddleware = helmet();
// Rate limiting - dakikada en fazla 100 istek
const limiter = rateLimit({
windowMs: 60 * 1000, // 1 dakika
max: 100,
mesaj: { hata: 'Çok fazla istek gönderdiniz, lütfen bekleyin.' },
standardHeaders: true,
legacyHeaders: false,
});
// Yönetim rotaları için daha sıkı limit
const adminLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 dakika
max: 20,
});
module.exports = { helmetMiddleware, limiter, adminLimiter };
EOF
Bunları app.js‘de kullanmak için:
# app.js içine güvenlik modülünü ekle
cat >> app.js << 'EOF'
// NOT: Bu satırları app.use tanımlamalarının en üstüne taşıyın
const { helmetMiddleware, limiter } = require('./guvenlik');
// app.use(helmetMiddleware);
// app.use(limiter);
EOF
Ayrıca NODE_ENV=production olduğunda Express otomatik olarak bazı bilgileri gizler, hata mesajlarını sadeleştirir. Bu yüzden ortam değişkenini her zaman doğru ayarlayın.
Sık Karşılaşılan Sorunlar
Port zaten kullanımda hatası: EADDRINUSE hatası aldığınızda portu hangi uygulamanın kullandığını bulun:
# Portu kullanan süreci bul
lsof -i :3000
# Ya da
ss -tlnp | grep :3000
# Süreci kapat
kill -9 <PID>
node_modules sorunları: Bağımlılıklarda garip hatalar alıyorsanız temiz kurulum yapın:
rm -rf node_modules package-lock.json
npm cache clean --force
npm install
Bellek sızıntısı tespiti: Uygulamanız zamanla yavaşlıyorsa PM2’nin bellek limitini kullanın ya da --inspect flag’i ile Chrome DevTools ile profilleme yapın:
node --inspect app.js
Tarayıcıda chrome://inspect adresine gidip bağlanabilirsiniz.
Sonuç
Node.js ile HTTP sunucusu kurmak birkaç satır kod meselesi ama onu production’a taşımak başlı başına bir süreç. Özetlemek gerekirse: nvm ile Node.js sürüm yönetimini çözün, küçük projeler için core http modülü yeterli ama büyüyen projelerde Express kaçınılmaz, konfigürasyonu mutlaka ortam değişkenleri ile yönetin, production’da PM2 kullanın ve önüne Nginx koyun, güvenlik için en azından helmet ve rate limiting ekleyin.
Anlatılanları adım adım uygularsanız hem yerel geliştirme ortamında hem de production’da rahat çalışan, sorun çıktığında ne yapacağını bilen bir altyapıya sahip olursunuz. Bir sonraki adım olarak MongoDB veya PostgreSQL ile database entegrasyonuna bakabilirsiniz.
