Bu rehber, yeni açılmış bir Ubuntu 24.04 sunucuda Nginx'i kurup ilk sitenizi HTTPS ile yayına almanın en kısa güvenli yolunu anlatıyor. Her komutu yayımlamadan önce test sunucumuzda çalıştırdık; aşağıdaki çıktılar o oturumdan. Toplam süre, alan adınızın DNS kaydı hazırsa on beş dakika civarındadır.
Başlamadan önce
- Ubuntu 24.04 LTS kurulu bir sunucu ve
rootya dasudoyetkili bir kullanıcı. Aşağıdaki komutlar root olarak yazıldı; sudo kullanıyorsanız başınasudoekleyin. - Sunucunun IP adresini gösteren bir A kaydı (ör.
ornek.com.tr→ sunucu IP'si). Kaydın yayıldığınıdig +short ornek.com.trile doğrulayabilirsiniz. DNS kayıtları yeniyse DNS kayıtları rehberimize göz atın. - SSH erişiminin anahtarla yapıldığı, parola girişinin kapatıldığı bir sunucu. Bu adımları Linux sunucu güvenliği: ilk gün yazısında anlattık; Nginx'ten önce yapın.
Örneklerde alan adı yerine ornek.com.tr yazdık; kendi alan adınızla değiştirin.
Neden Ubuntu 24.04? Uzun süreli destek (LTS) sürümüdür: Canonical standart güvenlik güncellemelerini 2029 yılına kadar yayımlar. Sunucuda ara sürümler yerine LTS kullanmak, birkaç ayda bir büyük sürüm yükseltmesi yapma zorunluluğunu ortadan kaldırır.
1. Nginx'i kurun
apt update
apt install -y nginx
nginx -v
systemctl is-active nginx
systemctl is-enabled nginx
nginx version: nginx/1.24.0 (Ubuntu)
active
enabled
Ubuntu paketi servisi kurulumla birlikte başlatır ve açılışta çalışacak şekilde etkinleştirir. 80 numaralı portu dinlediğini doğrulayın:
$ ss -ltnp | grep ":80 "
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1582,fd=5),...)
LISTEN 0 511 [::]:80 [::]:* users:(("nginx",pid=1582,fd=6),...)
2. Güvenlik duvarını açın (UFW)
Ubuntu'da UFW kurulu gelir ama kapalıdır. Nginx paketi UFW'ye hazır uygulama profilleri ekler. Önce SSH'e izin verin, sonra güvenlik duvarını açın; sıra ters olursa bağlantınız kopar.
ufw allow OpenSSH
ufw allow "Nginx Full"
ufw --force enable
ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
Nginx Full ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Nginx Full (v6) ALLOW Anywhere (v6)
Nginx Full profili 80 ve 443 numaralı portları birlikte açar. SSH portunu değiştirdiyseniz OpenSSH profili yerine o portu (ufw allow 2222/tcp gibi) açın.
3. Site dizinini ve server block'u oluşturun
Nginx'te her site bir server bloğudur. Ubuntu düzeninde bloklar /etc/nginx/sites-available/ altında yazılır, sites-enabled/ altına sembolik bağla etkinleştirilir.
mkdir -p /var/www/ornek.com.tr/html
echo '<h1>Nginx çalışıyor</h1>' > /var/www/ornek.com.tr/html/index.html
chown -R www-data:www-data /var/www/ornek.com.tr
/etc/nginx/sites-available/ornek.com.tr dosyasını şu içerikle oluşturun:
server {
listen 80;
listen [::]:80;
server_name ornek.com.tr www.ornek.com.tr;
root /var/www/ornek.com.tr/html;
index index.html index.php;
location / {
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/ornek.com.tr.access.log;
error_log /var/log/nginx/ornek.com.tr.error.log;
}
Etkinleştirin, sözdizimini test edin ve yeniden yükleyin. nginx -t hata verirse yeniden yüklemeyin; çalışan yapılandırma bozulmaz, önce hatayı düzeltin.
ln -s /etc/nginx/sites-available/ornek.com.tr /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Ubuntu'nun varsayılan sitesi (sites-enabled/default) yerinde kalabilir: alan adınızla gelmeyen istekleri o karşılar. İsterseniz bağını silip IP adresiyle gelen istekleri tamamen reddedebilirsiniz.
4. Ücretsiz SSL: Certbot ile Let's Encrypt
Ubuntu deposundaki Certbot ve Nginx eklentisi yeterlidir. Eklenti, sertifikayı alır, server bloğunuza 443 dinleyicisini ekler ve HTTP'den HTTPS'e kalıcı yönlendirmeyi yazar.
apt install -y certbot python3-certbot-nginx
certbot --nginx -d ornek.com.tr -d www.ornek.com.tr \
--agree-tos -m [email protected] --redirect
Deploying certificate
Successfully deployed certificate for ornek.com.tr to /etc/nginx/sites-enabled/ornek.com.tr
Congratulations! You have successfully enabled HTTPS on https://ornek.com.tr
E-posta adresi, sertifika sorunlarına dair Let's Encrypt bildirimleri içindir; geçerli bir adres yazın. İşlem bitince Certbot'un dosyanıza eklediği satırlar # managed by Certbot yorumuyla işaretlenir. Yönlendirme ve sertifikayı dışarıdan kontrol edin:
$ curl -sI http://ornek.com.tr/ | head -1
HTTP/1.1 301 Moved Permanently
$ curl -sI https://ornek.com.tr/ | head -1
HTTP/1.1 200 OK
$ echo | openssl s_client -connect ornek.com.tr:443 -servername ornek.com.tr 2>/dev/null \
| openssl x509 -noout -issuer -dates
issuer=C = US, O = Let's Encrypt, CN = YE1
notBefore=Oct 17 13:04:36 2026 GMT
notAfter=Jan 15 13:04:35 2027 GMT
Sertifikanın bitiş tarihini ve zincirini bir sertifika kontrol aracıyla da görebilirsiniz: SSL sertifika kontrolü. Sertifika türleri arasındaki farklar için SSL sertifikası rehberimize bakın.
5. Otomatik yenilemeyi doğrulayın
Paket, günde iki kez çalışan bir systemd zamanlayıcısı kurar. Hem zamanlayıcının varlığını hem de yenilemenin gerçekten çalıştığını test edin; --dry-run gerçek sertifikaya dokunmaz.
$ systemctl list-timers certbot.timer --no-pager
NEXT LEFT LAST PASSED UNIT ACTIVATES
Sun 2026-10-18 08:33:03 UTC 18h - - certbot.timer certbot.service
$ certbot renew --dry-run
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/ornek.com.tr/fullchain.pem (success)
6. PHP çalıştıracaksanız: PHP-FPM bağlantısı
apt install -y php8.3-fpm
systemctl is-active php8.3-fpm
Server bloğunuzdaki location / bloğunun altına şunları ekleyin. İkinci blok .env, .git gibi gizli dosyaların dışarıya sızmasını engeller; Let's Encrypt doğrulaması için gereken .well-known dizinini ise serbest bırakır.
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~ /\.(?!well-known) {
deny all;
}
$ nginx -t && systemctl reload nginx
$ curl -s https://ornek.com.tr/surum.php
PHP 8.3.6 / fpm-fcgi
$ curl -s -o /dev/null -w "%{http_code}\n" https://ornek.com.tr/.env
403
Test için yazdığınız surum.php gibi dosyaları işiniz bitince silin; sunucu sürümünü ifşa eden her dosya saldırgana ipucudur.
7. Sıkıştırma, önbellek ve güvenlik başlıkları
Ubuntu'nun Nginx paketinde gzip açık gelir ama yalnız HTML'i sıkıştırır; CSS, JavaScript ve SVG için türleri siz belirtmelisiniz. /etc/nginx/conf.d/sikistirma.conf dosyası bütün sitelere uygulanır:
gzip_vary on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_proxied any;
gzip_types text/css application/javascript application/json image/svg+xml text/plain text/xml application/xml;
Site bloğuna da sürüm bilgisini gizleyen, yükleme sınırını belirleyen ve temel güvenlik başlıklarını ekleyen satırları, statik dosyalar için de tarayıcı önbelleği süresini yazın:
client_max_body_size 32m;
server_tokens off;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "SAMEORIGIN" always;
location ~* \.(css|js|svg|woff2|png|jpg|jpeg|webp|avif)$ {
expires 30d;
access_log off;
}
Test sunucumuzda 4.801 baytlık bir CSS dosyası sıkıştırılmış olarak 62 bayt geldi; yanıtta önbellek ve güvenlik başlıklarının hepsi vardı:
$ curl -sI -H "Accept-Encoding: gzip" https://ornek.com.tr/stil.css
Expires: Mon, 16 Nov 2026 14:30:12 GMT
Cache-Control: max-age=2592000
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: SAMEORIGIN
Content-Encoding: gzip
Sık düşülen tuzak: İlk denememizde statik dosya bloğuna add_header Cache-Control "public"; satırı da eklemiştik. Sonuç: CSS yanıtlarından üç güvenlik başlığı da kayboldu. Nginx'te bir location bloğu kendi add_header satırını içeriyorsa üst bloktaki add_header satırlarının hiçbirini devralmaz. Ya alt bloğa add_header yazmayın (expires zaten Cache-Control üretir) ya da güvenlik başlıklarını orada da tekrarlayın.
Değişikliklerden sonra her zaman aynı sıra: nginx -t, sonra systemctl reload nginx, sonra curl -I ile yanıt başlıklarına bakmak. Sayfa hızını ölçmenin ve yorumlamanın ayrıntıları Core Web Vitals yazımızda.
8. İkinci bir site eklemek
Aynı sunucuda yeni bir alan adı yayımlamak, 3. adımı yeni adla tekrarlamaktan ibarettir: ayrı bir kök dizin, ayrı bir server dosyası, ayrı günlük dosyaları ve ardından o alan adı için certbot --nginx -d yeni-alan.com.tr. Nginx, isteği server_name eşleşmesine göre doğru bloğa yönlendirir. Siteleri birbirinden yalıtmak istiyorsanız her biri için ayrı bir Linux kullanıcısı ve ayrı bir PHP-FPM havuzu (/etc/php/8.3/fpm/pool.d/) açın; böylece bir sitedeki açık diğerlerinin dosyalarına ulaşamaz.
9. Günlükler ve güncellemeler
Ubuntu paketi Nginx günlüklerini kendiliğinden döndürür: /etc/logrotate.d/nginx dosyasına göre günlükler her gün döner, 14 gün saklanır ve sıkıştırılır. Siteye özel günlük dosyalarını /var/log/nginx/ altında tuttuğunuz sürece bu kurala dahil olurlar; başka bir dizine yazarsanız döndürme kuralını kendiniz eklemelisiniz, yoksa disk bir gün günlükle dolar.
Güvenlik güncellemeleri için Ubuntu 24.04'te unattended-upgrades kurulu ve açık gelir; test sunucumuzda /etc/apt/apt.conf.d/20auto-upgrades dosyası her iki ayarı da "1" olarak içeriyordu. Bu, Nginx dahil güvenlik yamalarının her gün kendiliğinden kurulması demektir. Kontrol etmek için:
$ systemctl is-enabled unattended-upgrades
enabled
$ cat /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
Otomatik güncelleme yeniden başlatma gerektiren çekirdek yamalarını kurar ama sunucuyu kendisi yeniden başlatmaz. /var/run/reboot-required dosyası varsa uygun bir saatte yeniden başlatın.
Günlük işlerde kullanacağınız komutlar
| Komut | Ne yapar | Ne zaman |
|---|---|---|
nginx -t | Yapılandırmanın sözdizimini denetler, hiçbir şeyi değiştirmez | Her düzenlemeden sonra, yeniden yüklemeden önce |
systemctl reload nginx | Yeni yapılandırmayı açık bağlantıları koparmadan yükler | Site ya da sertifika değişikliğinde |
systemctl restart nginx | Süreci durdurup başlatır; bağlantılar kopar | Yalnız modül değişikliği ya da takılma durumunda |
nginx -T | Dahil edilen bütün dosyalarla birlikte etkin yapılandırmanın tamamını basar | "Bu ayar nereden geliyor?" sorusunda |
journalctl -u nginx -n 50 | Servisin son başlatma ve hata kayıtları | Nginx açılmıyorsa |
En sık yapılan hata, nginx -t adımını atlayıp doğrudan restart kullanmaktır: yapılandırmada bir hata varsa Nginx kapanır ve açılmaz, bütün siteler aynı anda düşer. reload ise hatalı yapılandırmayı reddeder ve eski yapılandırmayla çalışmaya devam eder.
Sık yapılan hatalar
| Belirti | Muhtemel sebep | Kontrol |
|---|---|---|
| Alan adı yerine "Welcome to nginx" sayfası | server_name eşleşmiyor ya da site etkin değil | ls -l /etc/nginx/sites-enabled/, nginx -T | grep server_name |
| 502 Bad Gateway | PHP-FPM kapalı ya da soket yolu yanlış | systemctl status php8.3-fpm, ls /run/php/ |
| 403 Forbidden | Dizin izni ya da index dosyası yok | namei -l /var/www/ornek.com.tr/html/index.html |
| Certbot doğrulaması başarısız | DNS henüz yayılmadı ya da 80 kapalı | dig +short ornek.com.tr, ufw status |
| Değişiklik yansımıyor | Yeniden yükleme yapılmadı | nginx -t && systemctl reload nginx |
Hata ayıklarken ilk bakılacak yer sitenin kendi hata günlüğüdür: tail -f /var/log/nginx/ornek.com.tr.error.log. Sunucunun güvenliğini bir adım ileri taşımak için ilk gün güvenlik listesine dönün; siteniz WordPress olacaksa ardından WordPress hızlandırma rehberine geçebilirsiniz.
Sık sorulan sorular
Nginx mi Apache mi kurmalıyım?
Yeni bir kurulumda çoğu zaman Nginx: statik dosya ve çok sayıda eşzamanlı bağlantıda daha az bellek kullanır, PHP'yi PHP-FPM üzerinden çalıştırır. Uygulamanız .htaccess dosyalarına dayanıyorsa (bazı eski PHP uygulamaları) Apache daha az uğraştırır.
Certbot "Challenge failed" hatası veriyor, ne yapmalıyım?
Üç şeyi sırayla kontrol edin: alan adının A kaydı gerçekten bu sunucunun IP adresini gösteriyor mu (dig +short alanadiniz.com), 80 numaralı port güvenlik duvarında açık mı (ufw status), ve Nginx yapılandırmasındaki server_name alan adınızla birebir aynı mı. DNS değişikliği yeni yapıldıysa yayılmasını bekleyin.
Let's Encrypt sertifikası kaç gün geçerli?
Bu rehberi yazdığımız tarihte verilen sertifika 90 günlüktü. Certbot paketi bir systemd zamanlayıcısı kurar ve süresi yaklaşan sertifikayı kendiliğinden yeniler; certbot renew --dry-run ile yenilemenin çalıştığını test edebilirsiniz.
502 Bad Gateway hatası alıyorum, sebebi ne?
Nginx isteği arkasındaki servise (çoğu zaman PHP-FPM) iletemiyor demektir. systemctl status php8.3-fpm ile servisin çalıştığını, yapılandırmadaki fastcgi_pass yolunun /run/php/ altındaki gerçek soket adıyla aynı olduğunu kontrol edin. Ayrıntı /var/log/nginx/ altındaki hata günlüğündedir.
- #nginx
- #ubuntu
- #lets encrypt
- #php-fpm
- #vds kurulum
Bu rehberi uygulayacak bir sunucu mu lazım? VDS paketlerimizde Ubuntu 24.04 seçeneği var; kök erişimi tamamen sizde.
VDS paketlerine bakın