Apache ve .htaccess'ten Nginx'e geçiş
Apache'de site sahibi, klasöre koyduğu bir .htaccess dosyasıyla yönlendirme, parola koruması ya da önbellek ayarı yapabilir; sunucu bu dosyayı her istekte okur. Nginx'te böyle bir dosya yoktur: tüm kurallar sunucunun kendi yapılandırma dosyalarında durur ve sunucu yeniden yüklendiğinde bir kez okunur.
Bu yüzden Apache'den Nginx'e geçiş bir "dosya kopyalama" işi değil, bir çeviri işidir: .htaccess içindeki her kuralın Nginx'teki karşılığı yazılır. Bu rehber en yaygın kuralları yan yana örneklerle verir, sık düşülen tuzakları ve geçişten sonra neyin sınanacağını anlatır. Nginx'e yeniyseniz önce Nginx nedir rehberine göz atın.
Kısaca
- Nginx .htaccess dosyalarını okumaz; kurallar sunucu yapılandırmasına taşınır.
- Çoğu RewriteRule için rewrite gerekmez: try_files ve return yeterlidir.
- PHP, mod_php yerine PHP-FPM ile çalışır; php_value satırları başka yere taşınır.
- Her değişiklik nginx -t ile sınanır, sonra yeniden yüklenir.
İpucu
Geçişi canlı sitede değil, önce bir deneme ortamında ya da ayrı bir alt alan adında yapın; eski Apache yapılandırmasını ve .htaccess dosyalarını geri dönüş için saklayın.
Bu sayfada
Geçişin mantığı ve sırası
-
Temel farkı anlayın
- Kuralların yeri: Apache'de kurallar klasörlere dağılmış
.htaccessdosyalarında olabilir. Nginx'te hepsi sunucu yapılandırmasındadır: genellikle site başına bir dosya ve içinde birserver { … }bloğu. Dosyaların yeri dağıtıma göre değişir (/etc/nginx/conf.dyaygındır;/etc/nginx/sites-availableDebian/Ubuntu düzenidir). - Yürürlüğe girme:
.htaccesskaydedildiği anda geçerlidir. Nginx'te değişikliknginx -tile sınanır ve yeniden yükleme (reload) ile geçerli olur. Hatalı yapılandırma sınamada yakalanır; çalışan site etkilenmez. - Yetki: Yapılandırmayı değiştirmek sunucu yöneticisi yetkisi ister. Paylaşımlı barındırmada bu erişim çoğunlukla yoktur; orada kuralları barındırma firması ya da panel uygular.
- Yaklaşım: Apache'de her şey
RewriteRuleile çözülür. Nginx'te istek önce birlocationile eşleştirilir, sonra o konumun yönergeleri (directive) uygulanır.
: Büyüt - Kuralların yeri: Apache'de kurallar klasörlere dağılmış
-
Geçişi planlayın
- Envanter çıkarın: Sitedeki tüm
.htaccessdosyalarını bulun; alt klasörlerdekiler (yönetim paneli, yükleme klasörü) kolay unutulur. Apache sanal sunucu (VirtualHost) dosyasındaki kurallara da bakın. - Kuralları sınıflayın: yönlendirme, adres yeniden yazma, erişim kısıtı, başlıklar, PHP ayarları. Artık kullanılmayanları taşımayın.
- Nginx karşılıklarını yazın (aşağıdaki bölümler).
- Sınayın:
nginx -t, ardından deneme ortamında test listesi. - Geçin ve izleyin: hata günlüğünü ilk günlerde yakından takip edin.
Bash# Sitedeki tüm .htaccess dosyalarını listele (yolu kendi site dizininizle değiştirin) find /var/www/ornek.com -name ".htaccess" -type f # Nginx yapılandırmasını sına; sorun yoksa yeniden yükle sudo nginx -t && sudo systemctl reload nginx
: Büyüt - Envanter çıkarın: Sitedeki tüm
-
location eşleşme önceliğini öğrenin
.htaccesskuralları yukarıdan aşağıya sırayla çalışır. Nginx'te ise bir isteği tek birlocationkarşılar ve hangisinin seçileceği yazılış sırasına değil şu önceliğe bağlıdır:location = /adres: tam eşleşme varsa hemen seçilir.- Önek (prefix) konumları arasından en uzun eşleşen bulunur. Bu konum
^~ile yazılmışsa seçilir ve düzenli ifadelere bakılmaz. - Düzenli ifadeli konumlar (
~büyük/küçük harfe duyarlı,~*duyarsız) dosyadaki sırayla denenir; ilk eşleşen seçilir. - Hiçbir düzenli ifade eşleşmezse 2. adımda bulunan en uzun önek konumu kullanılır.
Sonuç:
location /yonetim/içine yazdığınız parola koruması,/yonetim/index.phpisteğine uygulanmaz; çünkü bu isteğilocation ~ \.php$karşılar. Çözüm, konumu^~ile yazıp PHP konumunu içine yerleştirmektir (erişim kısıtı bölümündeki örneğe bakın).
: Büyüt -
PHP'yi PHP-FPM'e bağlayın
Apache çoğu kurulumda PHP'yi kendi içinde çalıştırır (mod_php). Nginx'in içinde PHP yoktur;
.phpisteklerini ayrı çalışan PHP-FPM hizmetinefastcgi_passile iletir.Nginxlocation ~ \.php$ { # Dosya yoksa PHP-FPM'e gönderme try_files $uri =404; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # Soket yolu dağıtıma ve PHP sürümüne göre değişir fastcgi_pass unix:/run/php/php-fpm.sock; }try_files $uri =404;satırı, var olmayan bir.phpadresinin PHP-FPM'e gönderilmesini önler. Soket yolu ve havuz ayarları için Nginx ve PHP-FPM rehberine bakın.
: Büyüt
Karşılık tablosu
| İş | Apache / .htaccess | Nginx |
|---|---|---|
| Ön denetleyici | RewriteCond !-f, !-d + RewriteRule | try_files $uri $uri/ /index.php?$query_string; |
| HTTPS ve www | RewriteCond %{HTTPS} + RewriteRule [R=301] | ayrı server bloğu + return 301 |
| Tek adres yönlendirme | Redirect 301 | location = … { return 301 …; } |
| Temiz adres | RewriteRule … [L] | rewrite … last; ya da location |
| Parola koruması | AuthType Basic, AuthUserFile | auth_basic, auth_basic_user_file |
| IP kısıtı | Require ip | allow / deny |
| Dizin listeleme | Options -Indexes | autoindex off; (varsayılan zaten kapalı) |
| Hata sayfası | ErrorDocument | error_page |
| Önbellek başlıkları | mod_expires (ExpiresByType) | expires |
| Yanıt başlığı | Header set | add_header |
| PHP | mod_php | PHP-FPM + fastcgi_pass |
| PHP ayarı | php_value, php_flag | PHP-FPM havuz ayarı ya da .user.ini |
Ön denetleyici (front controller)
Çoğu PHP çatısı ve içerik yönetim sistemi, var olmayan her adresi index.php dosyasına yollar. Apache'de bu, "dosya değilse, klasör değilse" koşullu bir RewriteRule ile yapılır:
RewriteEngine On
# İstenen şey gerçek bir dosya ya da klasör değilse index.php'ye gönder
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]Nginx'te aynı iş tek satırdır. try_files sırayla dosyayı, klasörü dener; ikisi de yoksa isteği son değere yönlendirir:
root /var/www/ornek.com/public;
index index.php index.html;
# Biçim 1: uygulama yolu REQUEST_URI'den okuyor (çoğu çatı)
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Biçim 2: uygulama yolu bir parametreden okuyorsa (index.php?url=...)
# Yukarıdaki "location /" yerine şu ikisini kullanın:
#
# location / {
# try_files $uri $uri/ @uygulama;
# }
# location @uygulama {
# rewrite ^/(.*)$ /index.php?url=$1 last;
# }Uygulamanız yolu bir sorgu parametresinden okuyorsa (ör. index.php?url=…), örnekteki ikinci biçimi kullanın. rewrite, özgün sorgu dizgisini yeni adrese kendiliğinden ekler (Apache'deki QSA karşılığı).
HTTPS ve www yönlendirmesi
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.ornek.com%{REQUEST_URI} [L,R=301]Nginx'te bunun için koşul yazılmaz. Yönlendirilecek her ad için ayrı bir server bloğu açılır ve içine yalnızca return 301 konur; asıl site kendi bloğunda kalır:
# 1) HTTP üzerinden gelen her şey -> HTTPS + www
server {
listen 80;
server_name ornek.com www.ornek.com;
return 301 https://www.ornek.com$request_uri;
}
# 2) HTTPS ama www'siz -> www
server {
listen 443 ssl;
server_name ornek.com;
ssl_certificate /etc/letsencrypt/live/ornek.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ornek.com/privkey.pem;
return 301 https://www.ornek.com$request_uri;
}
# 3) Asıl site
server {
listen 443 ssl;
server_name www.ornek.com;
ssl_certificate /etc/letsencrypt/live/ornek.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ornek.com/privkey.pem;
root /var/www/ornek.com/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}HTTPS üzerinden gelen ornek.com isteğini yönlendirebilmek için o blokta da geçerli sertifika gerekir. Sertifika kurulumu için Nginx'te HTTPS rehberine bakın.
Tek adres yönlendirme ve temiz adresler
# Tek adres yönlendirme
Redirect 301 /eski-sayfa.html https://www.ornek.com/yeni-sayfa
# Bir bölümü topluca taşıma
RedirectMatch 301 ^/blog/(.*)$ https://www.ornek.com/yazilar/$1
# Temiz adres: /urun/42 -> urun.php?id=42
RewriteEngine On
RewriteRule ^urun/([0-9]+)/?$ urun.php?id=$1 [L,QSA]# Tek adres yönlendirme
location = /eski-sayfa.html {
return 301 https://www.ornek.com/yeni-sayfa;
}
# Bir bölümü topluca taşıma (sorgu parametreleri korunur)
location ~ ^/blog/(.*)$ {
return 301 https://www.ornek.com/yazilar/$1$is_args$args;
}
# Temiz adres: /urun/42 -> /urun.php?id=42
# Desen / ile başlar; özgün sorgu dizgisi kendiliğinden eklenir
rewrite ^/urun/([0-9]+)/?$ /urun.php?id=$1 last;.htaccessiçindeki desenlerde baştaki eğik çizgi yoktur (^urun/…); Nginx'te adres her zaman/ile başlar (^/urun/…). Çeviride en sık unutulan ayrıntı budur.- Yalnızca yönlendirme yapacaksanız
rewrite … permanentyerinereturn 301kullanın; daha yalın ve okunaklıdır. last, yeni adreslelocationaramasını yeniden başlatır; böylece/urun.phpPHP konumuna ulaşır.- Onlarca eski adres yönlendirecekseniz her biri için ayrı
locationyazmak yerinemapyönergesiyle bir eşleme tablosu kurmak daha düzenlidir.
Dizin koruma, IP kısıtı ve gizli dosyalar
# /yonetim/.htaccess : parola koruması
AuthType Basic
AuthName "Panel"
AuthUserFile /home/ornek/.htpasswd
Require valid-user
# /rapor/.htaccess : yalnız belirli IP adresleri (Apache 2.4)
Require ip 203.0.113.10
Require ip 10.0.0.0/24
# Kök .htaccess : dizin listelemeyi kapat, nokta ile başlayan adresleri engelle
Options -Indexes
RewriteEngine On
RewriteRule (^|/)\.(?!well-known) - [F]# Nokta ile başlayan dosya ve klasörler (.htaccess, .env, .git ...) kapalı;
# sertifika doğrulaması için .well-known açık kalır. Diğer düzenli ifadeli konumlardan önce yazın.
location ~ /\.(?!well-known) {
deny all;
}
# Parola koruması. ^~ : düzenli ifadeli konumlara (ör. \.php$) bakılmaz;
# bu yüzden PHP konumu içeride yeniden tanımlanır ve koruma .php dosyalarını da kapsar.
location ^~ /yonetim/ {
auth_basic "Panel";
auth_basic_user_file /etc/nginx/.htpasswd;
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
}
# Yalnız belirli IP adresleri
location ^~ /rapor/ {
allow 203.0.113.10;
allow 10.0.0.0/24;
deny all;
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
}
# Dizin listeleme: varsayılan zaten off; açıkça yazmak isteğe bağlıdır
autoindex off;- Parola dosyası:
htpasswdile üretilmiş dosya çoğu durumda Nginx'te de kullanılabilir. Parola özet türünün desteklendiğini giriş yaparak doğrulayın; dosyayı web kökünün dışında tutun. - IP kısıtı:
allowvedenyyazıldığı sırayla değerlendirilir; ilk eşleşen kural geçerlidir. Sitenin önünde CDN ya da başka bir vekil sunucu (proxy) varsa Nginx ziyaretçinin değil vekilin IP adresini görür; gerçek adres ayrıca yapılandırılmadan IP kısıtı beklediğiniz gibi çalışmaz. - Dizin listeleme: Nginx'te
autoindexvarsayılan olarak kapalıdır;Options -Indexessatırının karşılığını yazmak zorunlu değildir. - Gizli dosyalar: Apache'nin varsayılan yapılandırması
.htile başlayan dosyaları kendiliğinden gizler; Nginx'te böyle bir varsayılan yoktur. Geçişten sonra geride kalan.htaccess,.envya da.gitiçeriği düz metin olarak indirilebilir. Nokta ile başlayan adresleri kapatan konumu mutlaka ekleyin ve diğer düzenli ifadeli konumlardan önce yazın. - Alt klasörlerdeki "Deny from all": Yükleme ya da yedek klasörlerindeki
.htaccesskorumaları da artık çalışmaz; her biri için birlocationyazın. Bkz. Nginx güvenlik ayarları.
Hata sayfaları ve önbellek başlıkları
# Özel hata sayfaları
ErrorDocument 404 /404.html
ErrorDocument 500 /500.html
# Önbellek başlıkları (mod_expires)
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 30 days"
ExpiresByType application/javascript "access plus 30 days"
ExpiresByType image/webp "access plus 90 days"
ExpiresByType image/jpeg "access plus 90 days"
</IfModule># Özel hata sayfaları
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# Önbellek başlıkları
location ~* \.(?:css|js)$ {
expires 30d;
}
location ~* \.(?:webp|jpg|jpeg|png|gif|svg|ico)$ {
expires 90d;
}PHP'nin ürettiği hata yanıtlarında (ör. uygulamanın döndürdüğü 404) error_page kendiliğinden devreye girmez; bunun için ilgili konumda fastcgi_intercept_errors on; gerekir. Önbellek süreleri ve sıkıştırma için önbellek ve sıkıştırma rehberine bakın.
php_value ve php_flag satırları
.htaccess içindeki php_value ve php_flag satırları yalnızca mod_php ile çalışır. Nginx bunları okumaz; PHP-FPM de okumaz. İki karşılığı vardır:
- PHP-FPM havuz ayarı:
php_value[…]/php_flag[…]ya da uygulamanın değiştiremeyeceğiphp_admin_value[…]/php_admin_flag[…]. Değişiklikten sonra PHP-FPM yeniden yüklenir. .user.ini: Site klasörüne konur, yeniden yükleme gerektirmez; ancak yalnızca klasör düzeyinde değiştirilebilen ayarlar için geçerlidir ve PHP dosyayı belirli aralıklarla yeniden okuduğu için (varsayılan 300 saniye) değişiklik hemen görünmeyebilir.
# Yalnız mod_php ile çalışır; Nginx + PHP-FPM bu satırları okumaz
php_value upload_max_filesize 32M
php_value post_max_size 32M
php_value memory_limit 256M
php_flag display_errors off; Seçenek 1: site kök dizininde .user.ini dosyası
upload_max_filesize = 32M
post_max_size = 32M
memory_limit = 256M
display_errors = Off
; Seçenek 2: PHP-FPM havuz dosyası (ör. www.conf; yeri dağıtıma göre değişir)
; php_admin_* ile verilen değeri uygulama ini_set() ile değiştiremez
php_admin_value[upload_max_filesize] = 32M
php_admin_value[post_max_size] = 32M
php_admin_value[memory_limit] = 256M
php_admin_flag[display_errors] = offDosya yükleme sınırını taşıyorsanız Nginx tarafını da unutmayın: client_max_body_size varsayılanı 1m'dir; yükseltilmezse büyük yüklemeler PHP'ye ulaşmadan 413 hatasıyla reddedilir.
"if" yönergesi ve diğer tuzaklar
ifbir programlama dili koşulu değildir.locationiçindeifile birlikte güvenle kullanılabilecek yönergelerreturnverewrite'tır; başka yönergelerle birlikte beklenmedik sonuçlar verebilir.RewriteCondsatırlarını birebirif'e çevirmek yerine önce şunu sorun: bu iştry_files,return, ayrı birserverya dalocationbloğu veyamapile yapılabilir mi? Çoğu zaman yapılabilir.- Sıra farkı:
.htaccesskuralları sırayla işler ve birbirini etkiler; Nginx'te tek bir konum seçilir. Kuralları aynı sırayla alt alta yazmak aynı sonucu vermez. - Devralma:
add_headergibi yönergeler, alt düzeyde aynı yönerge yazıldığında üst düzeyden devralınmaz. - Hazır çeviri araçları: Çevrimiçi dönüştürücüler iyi bir başlangıç taslağı verebilir, ancak çıktıları sıklıkla gereksiz
ifiçerir. Her satırı anlayarak gözden geçirin. - Uygulamanın kendi
.htaccessdosyası: Hazır yazılımlar (içerik yönetim sistemleri, çatılar) kurulumda.htaccessüretir ve güncellemelerde değiştirebilir. Nginx'te bu kuralların karşılığını yazılımın belgesinden alın ve güncellemelerden sonra yeniden kontrol edin.
Geçişten sonra test listesi
# Yönlendirmeler: durum kodu ve Location başlığı
curl -sI http://ornek.com/ | grep -i -E "^HTTP|^location"
curl -sI https://ornek.com/ | grep -i -E "^HTTP|^location"
curl -sI https://www.ornek.com/eski-sayfa.html | grep -i -E "^HTTP|^location"
# Gizli dosyalar: 403 ya da 404 dönmeli, içerik gelmemeli
curl -s -o /dev/null -w "%{http_code}\n" https://www.ornek.com/.htaccess
curl -s -o /dev/null -w "%{http_code}\n" https://www.ornek.com/.env
curl -s -o /dev/null -w "%{http_code}\n" https://www.ornek.com/.git/config
# Parola korumalı alan: 401 dönmeli (.php dahil)
curl -s -o /dev/null -w "%{http_code}\n" https://www.ornek.com/yonetim/index.php
# Var olmayan adres: 404
curl -s -o /dev/null -w "%{http_code}\n" https://www.ornek.com/olmayan-sayfa- Ana sayfa, bir iç sayfa ve temiz adresli bir sayfa (ör. ürün, yazı) açılıyor.
http://ve www'siz adres, tek adımda doğru HTTPS adresine 301 ile gidiyor.- Eski adres yönlendirmeleri çalışıyor; sorgu parametreleri korunuyor.
- Var olmayan adres 404 ve özel hata sayfasını veriyor; var olmayan
.phpadresi de öyle. - Yönetim paneli parola soruyor;
.phpdosyaları dahil. /.htaccess,/.env,/.git/configgibi adresler erişilemez.- Yükleme klasöründe PHP çalışmıyor; dizin listesi görünmüyor.
- Form gönderimi, giriş, dosya yükleme (büyük dosya dahil) çalışıyor.
- Statik dosyalar doğru
Cache-ControlveContent-Typeile geliyor. - Güvenlik başlıkları yerinde (bkz. güvenlik başlıkları).
- Nginx ve PHP-FPM hata günlüklerinde beklenmeyen kayıt yok.
Sık sorulan sorular
.htaccess dosyamı Nginx'e olduğu gibi kopyalayabilir miyim?
Hayır. Nginx .htaccess dosyalarını okumaz ve sözdizimi farklıdır. Her kuralın karşılığı sunucu yapılandırmasına yazılır; dosyanın kendisi Nginx açısından sıradan bir metin dosyasıdır ve erişime kapatılmalıdır.
Paylaşımlı barındırmada Nginx kurallarını kendim yazabilir miyim?
Genellikle hayır; sunucu yapılandırması yönetici yetkisi ister. Bazı paneller sınırlı bir alan sunar ya da Nginx'i Apache'nin önünde çalıştırır; bu durumda .htaccess çalışmaya devam eder. Barındırma firmanıza sorun.
Nginx'i Apache'nin önünde kullanırsam .htaccess çalışır mı?
Evet. Nginx ters vekil (reverse proxy) olarak öne konup istekleri Apache'ye iletiyorsa .htaccess kurallarını yine Apache uygular. Yalnız Nginx'in doğrudan sunduğu statik dosyalar bu kurallardan geçmez.
Her RewriteCond için "if" yazmam gerekir mi?
Hayır; çoğu zaman gerekmez. Dosya var mı denetimi try_files ile, alan adı ve HTTPS koşulları ayrı server bloklarıyla, adrese göre koşullar location ile karşılanır. "if" yalnızca return ya da rewrite ile birlikte ve başka yol yoksa kullanılmalıdır.
Geçişten sonra site yavaşladı ya da 502 veriyor; nereye bakmalıyım?
Önce Nginx hata günlüğüne ve PHP-FPM günlüğüne bakın. 502 çoğunlukla PHP-FPM'in çalışmadığını ya da soket yolunun yanlış olduğunu gösterir.
BYK Yazılım Destek Ekibi
Bu rehber BYK Yazılım destek ekibi tarafından hazırlanır ve düzenli olarak gözden geçirilir. Son güncelleme: 04.10.2026.
İlgili rehberler
- Nginx ve PHP-FPM: PHP siteleri Nginx ile nasıl çalışır?fastcgi_pass, SCRIPT_FILENAME, try_files, havuz (pool) kavramı, soket izinleri ve 502 hatası.
- Nginx güvenlik ayarları: oran sınırlama, başlıklar, erişim kısıtlarıNginx'te oran sınırlama, güvenlik başlıkları, gizli dosya ve yönetim yolu kısıtları ile istek sınırları.
- Nginx'te HTTPS: SSL sertifikası kurulumuNginx'te sertifika alma, HTTPS'e yönlendirme, HSTS, SSL sonlandırma ve otomatik yenileme adımları.
- 502, 504 ve diğer Nginx hataları: nedenleri ve çözümleri502, 504, 413, 499, 403 ve 404 hatalarının anlamı, olası nedenleri, günlüklerle teşhisi ve çözümü.
Web sitenizin altyapısını birlikte konuşalım
BYK Yazılım kurumsal web siteleri geliştirir. Sitenizle ilgili sorularınız için bize yazabilirsiniz.
Bize ulaşın Kurumsal web sitesi hizmetimiz