Web sunucunuzu internete açtığınız anda güvenlik sorumluluğunuz da başlıyor. Özellikle kullanıcı verisi işleyen, form alan ya da oturum yöneten her uygulama için HTTPS artık bir tercih değil, zorunluluk. Nginx, bu konuda hem performans hem de esneklik açısından en güçlü seçeneklerden biri. Bu yazıda sıfırdan SSL/TLS yapılandırması yapacak, modern şifreleme standartlarını uygulayacak ve HTTP trafiğini HTTPS’e zorla yönlendireceksiniz.
SSL Sertifikası Edinme
Yapılandırmaya geçmeden önce elinizde geçerli bir SSL sertifikasının olması gerekiyor. İki ana yol var: Let’s Encrypt ile ücretsiz sertifika almak ya da ticari bir CA’dan satın almak. Büyük çoğunluk için Let’s Encrypt yeterli, hatta ideal.
Certbot ile Let’s Encrypt Sertifikası
# Ubuntu/Debian
sudo apt update
sudo apt install certbot python3-certbot-nginx
# CentOS/RHEL
sudo dnf install certbot python3-certbot-nginx
# Sertifika alma (Nginx eklentisi ile otomatik yapılandırma)
sudo certbot --nginx -d example.com -d www.example.com
# Sadece sertifika al, Nginx'i elle yapılandır
sudo certbot certonly --nginx -d example.com -d www.example.com
# Webroot yöntemi (çalışan bir HTTP sunucusu varsa)
sudo certbot certonly --webroot -w /var/www/html -d example.com
Certbot başarılı olursa sertifikalarınız /etc/letsencrypt/live/example.com/ altına yerleşir. Bu dizinde dört dosya bulunur:
- fullchain.pem: Sertifikanız + ara CA sertifikaları (Nginx’e bu dosyayı verirsiniz)
- privkey.pem: Özel anahtarınız (kimseyle paylaşmayın, izinleri kontrol edin)
- cert.pem: Sadece domain sertifikanız
- chain.pem: Sadece ara CA zinciri
Ticari Sertifika için CSR Oluşturma
Let’s Encrypt yerine ticari sertifika kullanacaksanız önce bir CSR (Certificate Signing Request) oluşturmanız gerekiyor:
# Özel anahtar oluştur
openssl genrsa -out /etc/nginx/ssl/example.com.key 4096
# CSR oluştur
openssl req -new -key /etc/nginx/ssl/example.com.key
-out /etc/nginx/ssl/example.com.csr
-subj "/C=TR/ST=Istanbul/L=Istanbul/O=Sirket Adi/CN=example.com"
# CSR içeriğini kontrol et
openssl req -text -noout -verify -in /etc/nginx/ssl/example.com.csr
CSR dosyasını CA’ya gönderiyorsunuz, onlar size .crt uzantılı sertifikayı geri dönüyor. Ara sertifikaları da birleştirmeniz gerekebilir:
# Sertifikaları birleştir (önce domain sertifikası, sonra zincir)
cat example.com.crt intermediate.crt root.crt > /etc/nginx/ssl/example.com_fullchain.crt
Temel HTTPS Yapılandırması
Sertifikalarınız hazırsa Nginx konfigürasyonuna geçelim. Tipik bir yapılandırma iki server bloğundan oluşur: biri HTTP’yi HTTPS’e yönlendirmek için, diğeri gerçek HTTPS trafiğini işlemek için.
# /etc/nginx/sites-available/example.com
# HTTP -> HTTPS yönlendirme
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# Let's Encrypt doğrulama için izin ver
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# Geri kalan her şeyi HTTPS'e yönlendir
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS ana blok
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name example.com www.example.com;
# Sertifika dosyaları
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example.com;
index index.html index.php;
location / {
try_files $uri $uri/ =404;
}
}
Konfigürasyonu test edip yükleyin:
sudo nginx -t
sudo systemctl reload nginx
Bu temel yapılandırma çalışır ama henüz güvenli değil. TLS sürüm kısıtlaması, şifreleme suite seçimi ve güvenlik başlıkları olmadan bu yapılandırma birçok güvenlik açığına karşı savunmasız kalır.
Güçlü TLS Yapılandırması
Modern bir TLS yapılandırması için önerilen ayarları ayrı bir include dosyasına almak, birden fazla site yönetirken hayat kurtarır. SSL parametrelerini merkezi bir dosyada tutup her server bloğunda include edersiniz.
sudo mkdir -p /etc/nginx/ssl
sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096
DH parametresi oluşturma biraz uzun sürebilir, bu normal. Şimdi merkezi SSL yapılandırma dosyasını oluşturalım:
# /etc/nginx/ssl/ssl_params.conf
# TLS protokol sürümleri - TLS 1.0 ve 1.1 kesinlikle devre dışı
ssl_protocols TLSv1.2 TLSv1.3;
# Şifreleme suite'leri - zayıf algoritmalar dışarıda
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
# Sunucu şifreleme tercihini aktif et
ssl_prefer_server_ciphers off;
# DH parametreleri (Forward Secrecy için)
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# SSL session cache (performans için)
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
Bu dosyayı her site konfigürasyonuna dahil edin:
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Merkezi SSL parametrelerini dahil et
include /etc/nginx/ssl/ssl_params.conf;
# Güvenlik başlıkları
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
HSTS ve Preload
Strict-Transport-Security başlığı, tarayıcıya “bu siteye bir daha HTTP ile bağlanma” mesajı verir. Yanlış yapılandırılırsa sitenize erişimi engelleyebilir, dikkatli olun.
HSTS’yi aşamalı olarak devreye alın:
- İlk aşama:
max-age=300ile test edin, 5 dakika - İkinci aşama:
max-age=86400(1 gün), sorun yoksa devam - Üçüncü aşama:
max-age=2592000(30 gün) - Final:
max-age=31536000; includeSubDomains; preload
preload direktifini eklemeden önce tüm subdomain’lerinizin HTTPS desteğinin olduğundan emin olun. Sonra [hstspreload.org](https://hstspreload.org) adresine başvurarak sitenizi tarayıcıların HSTS preload listesine ekletebilirsiniz.
OCSP Stapling
OCSP Stapling, sertifika iptal kontrolünü hızlandırır. Normalde tarayıcı her bağlantıda CA’nın OCSP sunucusuna gidip sertifikanın geçerli olup olmadığını sorar. OCSP Stapling ile Nginx bu kontrolü periyodik olarak kendisi yapar ve yanıtı “zımbalar”, tarayıcıya doğrudan sunar. Hem gizlilik hem de performans açısından avantajlı.
# OCSP Stapling'in çalışıp çalışmadığını test et
echo | openssl s_client -connect example.com:443 -status 2>/dev/null | grep -A 10 "OCSP Response"
# Daha detaylı test
openssl s_client -connect example.com:443 -tls1_2 -tlsextdebug -status < /dev/null 2>&1 | grep -i ocsp
Sertifika Yenileme Otomasyonu
Let’s Encrypt sertifikaları 90 günde bir yenilenmesi gerekiyor. Manuel yapmak istemiyorsunuz, Certbot’un timer’ı zaten yenilemeyi hallediyor ama Nginx’i de yenileme sonrası reload etmeniz lazım.
# Mevcut otomatik yenileme timer'ını kontrol et
sudo systemctl status certbot.timer
# Yenileme hook'u oluştur
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo tee /etc/letsencrypt/renewal-hooks/deploy/nginx-reload.sh << 'EOF'
#!/bin/bash
systemctl reload nginx
echo "$(date): Nginx reloaded after cert renewal" >> /var/log/letsencrypt/nginx-reload.log
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/nginx-reload.sh
# Yenileme işlemini simüle et (gerçek yenileme yapmaz)
sudo certbot renew --dry-run
Cron ile de yönetmek isterseniz:
# Crontab'a ekle
sudo crontab -e
# Her gün sabah 3'te kontrol et
0 3 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"
Çoklu Domain Yapılandırması
Birden fazla domain yönetiyorsanız her biri için ayrı server bloğu oluşturup aynı SSL parametrelerini include edin. Wildcard sertifika kullanıyorsanız DNS doğrulaması gerekiyor:
# Wildcard sertifika (DNS doğrulaması gerekli)
sudo certbot certonly --manual --preferred-challenges dns
-d example.com -d "*.example.com"
Wildcard sertifika ile birden fazla subdomain’i tek yapılandırmada yönetebilirsiniz:
# /etc/nginx/sites-available/subdomains.conf
# api.example.com
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/nginx/ssl/ssl_params.conf;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://localhost:3000;
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;
}
}
# app.example.com
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/nginx/ssl/ssl_params.conf;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://localhost:8080;
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;
}
}
SSL Yapılandırmasını Test Etme
Yapılandırmanızı canlıya almadan ve aldıktan sonra mutlaka test edin. Hem komut satırından hem de online araçlarla kontrol yapabilirsiniz.
# Temel SSL bağlantı testi
openssl s_client -connect example.com:443 -servername example.com
# Desteklenen protokolleri test et
openssl s_client -connect example.com:443 -tls1
openssl s_client -connect example.com:443 -tls1_1
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3
# Sertifika geçerlilik tarihi
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
# Şifreleme suite'ini görüntüle
echo | openssl s_client -connect example.com:443 2>/dev/null | grep Cipher
# nmap ile kapsamlı SSL taraması
nmap --script ssl-enum-ciphers -p 443 example.com
# HTTP güvenlik başlıklarını kontrol et
curl -I https://example.com
Online test araçları arasında SSL Labs (ssllabs.com/ssltest) en kapsamlı olanı. A+ puan almak için HSTS, güçlü şifreleme suite’leri ve güncel TLS sürümleri yeterli. Ayrıca securityheaders.com güvenlik başlıklarınızı değerlendiriyor.
Gerçek Dünya Senaryosu: E-ticaret Sitesi
Bir e-ticaret projesi üzerinde çalıştığımı ve PCI-DSS uyumluluğu gerektiren bir yapılandırma kurmam gerektiğini düşünelim. TLS 1.0 ve 1.1 kesinlikle yasak, session ticket’lar kapalı olmalı, forward secrecy zorunlu.
# /etc/nginx/sites-available/shop.example.com
server {
listen 80;
server_name shop.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name shop.example.com;
ssl_certificate /etc/letsencrypt/live/shop.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/shop.example.com/privkey.pem;
include /etc/nginx/ssl/ssl_params.conf;
# PCI-DSS uyumlu güvenlik başlıkları
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://js.stripe.com; frame-src https://js.stripe.com; connect-src 'self' https://api.stripe.com;" always;
# Hassas dosyaları gizle
location ~ /. {
deny all;
}
location ~* .(env|log|sql|bak)$ {
deny all;
}
# Uygulama
location / {
proxy_pass http://localhost:5000;
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 https;
proxy_set_header X-Forwarded-Port 443;
}
}
Yaygın Sorunlar ve Çözümleri
Mixed Content Uyarısı: Sayfa HTTPS üzerinden geliyor ama içindeki resimler, scriptler HTTP’den yükleniyorsa tarayıcı uyarı verir. Nginx seviyesinde Content-Security-Policy: upgrade-insecure-requests başlığı ekleyerek bunu kısmen aşabilirsiniz. Asıl çözüm uygulama seviyesinde kaynakları düzeltmek.
Sertifika Zinciri Eksikliği: Tarayıcı “sertifika güvenilir değil” diyorsa büyük ihtimalle fullchain.pem yerine sadece cert.pem kullanıyorsunuzdur. Daima fullchain.pem kullanın.
SNI Sorunları: Aynı IP’de birden fazla SSL domain çalıştırıyorsanız ve eski istemci sorunları yaşıyorsanız, SNI (Server Name Indication) desteği olmayan eski SSL istemciler var demektir. Nginx varsayılan olarak SNI destekliyor, sorun istemci tarafında.
# Hangi sertifikanın sunulduğunu kontrol et
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject
# Nginx'in SSL modülünü doğrula
nginx -V 2>&1 | grep ssl
Sertifika Süresi Dolmuş Uyarısı: Otomatik yenileme çalışmıyorsa şunu kontrol edin:
# Timer aktif mi?
systemctl is-active certbot.timer
# Son yenileme ne zaman olmuş?
sudo certbot renew --dry-run
# Sertifika bitiş tarihlerini listele
sudo certbot certificates
Nginx SSL Performans Optimizasyonu
SSL handshake işlemi CPU yoğun bir işlemdir. Binlerce eş zamanlı bağlantı söz konusu olduğunda birkaç optimizasyon büyük fark yaratır.
# nginx.conf içinde http bloğuna ekle
http {
# SSL session cache (birden fazla worker arasında paylaşılan)
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# Keep-alive bağlantıları (her request için yeni handshake yapmamak için)
keepalive_timeout 65;
keepalive_requests 100;
# Buffer boyutları
ssl_buffer_size 4k;
}
TLS 1.3’ün 0-RTT (Zero Round Trip Time Resumption) özelliği ilk bağlantı kurma süresini ciddi ölçüde azaltıyor. Nginx 1.15.4+ sürümünde TLS 1.3 tam desteği var, sisteminizi güncel tutun.
Sonuç
Nginx ile SSL/TLS yapılandırması göründüğü kadar karmaşık değil ama detaylar önemli. Sadece sertifika ekleyip 443 portu açmak yetmiyor; TLS protokol sürümlerini kısıtlamak, güçlü şifreleme suite’leri seçmek, güvenlik başlıklarını doğru yapılandırmak ve otomatik yenilemeyi kurmak da işin parçası.
Özetle yapmanız gerekenler şunlar: TLS 1.0/1.1’i devre dışı bırakın, TLS 1.2 ve 1.3 kullanın, zayıf şifreleme algoritmaları olan RC4, DES, 3DES’i dışlayın, HSTS başlığını ekleyin, OCSP Stapling’i aktif edin, sertifika yenilemeyi otomatikleştirin ve düzenli olarak SSL Labs ile test edin. Bu adımları tamamladığınızda hem A+ puanı alacak hem de gerçekten güvenli bir yapıya sahip olacaksınız.
Yapılandırmayı bir kez kurmak yetmez. Sertifika tarihlerini, TLS protokol güncellemelerini ve yeni güvenlik açıklarını takip etmek de sysadmin rutininizin parçası olmalı. ssl_protocols satırını bir kez yazıp unutmak yerine, her birkaç ayda bir güncel tavsiyelere bakın, OpenSSL sürümünüzü güncel tutun.