Blog

Htaccess SSL Yönlendirme: HTTP'den HTTPS'e 301 Kuralları

Htaccess SSL Yönlendirme: HTTP'den HTTPS'e 301 Kuralları

.htaccess ile SSL yönlendirme, sitenize http:// ile gelen her isteği aynı sayfanın https:// adresine kalıcı (301) olarak gönderen birkaç satırlık bir mod_rewrite kuralıdır. Apache ya da LiteSpeed kullanan bir hostingdeyseniz kuralı sitenin kök klasöründeki .htaccess dosyasının en üstüne eklemeniz yeterli; nginx .htaccess dosyasını okumadığı için aynı işi sunucu yapılandırmasında yaparsınız. Aşağıdaki örneklerde ornek.com yazan yerlere kendi alan adınızı yazın.

WordPress kullanıyorsanız bu iş için eklenti kurmanıza gerek yok. Birkaç satırla sunucu seviyesinde çözülebilecek bir yönlendirmeyi eklentiye bırakmak, her istekte gereksiz PHP çalıştırmak ve güncel tutulacak bir eklenti daha eklemek demek. Benim tercihim her zaman .htaccess ya da sunucu yapılandırması oldu.

Kodu eklemeden önce kontrol edilecek üç şey

  1. Sertifika kurulu mu? Tarayıcıya https://ornek.com yazıp sitenin uyarısız açıldığını görün. Sertifika yokken yönlendirme yaparsanız ziyaretçileri güvenlik uyarısı veren bir sayfaya göndermiş olursunuz.
  2. Sunucu hangisi? cPanel, DirectAdmin ve Plesk gibi panellerin çoğunda Apache ya da LiteSpeed çalışır ve .htaccess okunur. Sunucu yalnızca nginx ise .htaccess'e yazdığınız hiçbir kural çalışmaz.
  3. Yedeğiniz var mı? .htaccess dosyasındaki tek bir yazım hatası bütün sitede 500 hatasına yol açar. Değişiklikten önce dosyanın bir kopyasını alın.

HTTP isteklerini HTTPS'e çeviren temel kural

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Satırların yaptığı iş:

  • RewriteEngine On yeniden yazma motorunu açar. Dosyada zaten varsa (WordPress kendi bloğunda ekler) ikinci kez yazmanız sorun çıkarmaz.
  • RewriteCond %{HTTPS} off kuralın yalnızca şifresiz bağlantılarda çalışmasını sağlar. Bu satır olmazsa kural HTTPS isteklerini de yönlendirir ve döngü oluşur.
  • RewriteRule satırı isteği aynı alan adı ve aynı yolla https:// adresine gönderir. R=301 yönlendirmenin kalıcı olduğunu, L bu kuraldan sonra başka kural işlenmemesini söyler.

Sorgu dizesi, yani adresteki soru işaretinden sonraki kısım da korunur: hedef adreste soru işareti olmadığı için Apache orijinal sorgu dizesini kendiliğinden ekler. Böylece http://ornek.com/urun?renk=mavi isteği https://ornek.com/urun?renk=mavi adresine gider. Bayrakların ayrıntılı açıklaması Apache mod_rewrite belgelerinde var.

HTTPS ile birlikte www tercihini tek adımda uygulamak

Sitenin hem www'li hem www'siz, hem http hem https sürümü açılıyorsa Google'ın gözünde aynı sayfanın dört ayrı adresi var demektir. Bunları tek bir adreste toplamak, bunu da tek bir yönlendirmeyle yapmak gerekir. Önce https'e, sonra www'siz adrese giden iki aşamalı bir zincir yerine ziyaretçiyi doğrudan son adrese göndermek daha temizdir.

www'siz adrese toplamak

RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://ornek.com%{REQUEST_URI} [L,R=301]

İlk koşuldaki [OR], iki koşuldan biri doğruysa kuralın çalışmasını sağlar: bağlantı şifresizse ya da adres www ile başlıyorsa ziyaretçi https://ornek.com adresine gider. NC büyük-küçük harf farkını yok sayar.

Alan adını koda yazmak istemiyorsanız, örneğin aynı dosyayı birden çok sitede kullanıyorsanız, şu sürüm alan adını istekten alır:

RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,R=301]

Buradaki %1, son koşulda parantez içinde yakalanan ve başındaki www'den arındırılmış alan adıdır.

www'li adrese toplamak

RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.ornek.com%{REQUEST_URI} [L,R=301]

Hangi sürümü seçtiğinizin bir önemi yok; önemli olan birini seçip her yerde aynısını kullanmak: site haritasında, canonical etiketlerinde, iç bağlantılarda ve WordPress'in site adresi ayarında.

WordPress sitelerinde bu bloğu dosyadaki # BEGIN WordPress satırının üstüne yazın. Altına yazılırsa WordPress'in kuralları isteği önce işler ve yönlendirme beklediğiniz gibi çalışmayabilir. # BEGIN WordPress ile # END WordPress arasına da yazmayın; WordPress kalıcı bağlantı ayarları her kaydedildiğinde o aralığı yeniden yazar.

Aynı yönlendirmenin nginx karşılığı

nginx'te yönlendirme ayrı sunucu blokları ve return 301 ile yapılır; bu yol, rewrite ya da if kullanmaktan hem daha hızlı hem daha okunaklıdır. www'siz bir site için yapı şöyle:

server {
    listen 80;
    listen [::]:80;
    server_name ornek.com www.ornek.com;
    return 301 https://ornek.com$request_uri;
}

server {
    listen 443 ssl;
    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;
    return 301 https://ornek.com$request_uri;
}

server {
    listen 443 ssl;
    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;
    root /var/www/ornek.com;
    # sitenin geri kalan ayarları
}

$request_uri yolu ve sorgu dizesini birlikte taşır. Sertifika yolları Let's Encrypt'in varsayılan konumudur, sizin sunucunuzda farklı olabilir. Sertifikanın www.ornek.com adını da kapsaması gerekir; aksi halde https://www.ornek.com adresine gelen ziyaretçi yönlendirmeden önce sertifika uyarısı görür. Değişiklikten sonra yapılandırmayı test edip yeniden yükleyin:

sudo nginx -t && sudo systemctl reload nginx

Cloudflare arkasında sonsuz yönlendirme döngüsü

Site Cloudflare gibi bir CDN ya da ters vekil sunucunun arkasındaysa, yukarıdaki kurallar tarayıcıda "çok fazla yönlendirme" (ERR_TOO_MANY_REDIRECTS) hatasına yol açabilir. Sebebi şu: Cloudflare'in SSL/TLS ayarı "Flexible" ise ziyaretçi Cloudflare'e HTTPS ile bağlanır, ama Cloudflare sizin sunucunuza düz HTTP ile gider. Sunucu her isteği HTTP olarak gördüğü için tekrar https'e yönlendirir, Cloudflare yine HTTP ile gelir ve döngü hiç bitmez.

Kalıcı çözüm: Full (strict) mod

En doğru yol, sunucunuza geçerli bir sertifika kurup Cloudflare'de SSL/TLS modunu "Full (strict)" yapmaktır. Bu durumda Cloudflare sunucunuza da HTTPS ile bağlanır, %{HTTPS} doğru değeri verir ve yukarıdaki kurallar olduğu gibi çalışır. Sertifika olarak Let's Encrypt ya da Cloudflare'in yalnızca kendi sunucularıyla sizin sunucunuz arasındaki bağlantı için verdiği Origin CA sertifikası kullanılabilir.

Geçici çözüm: X-Forwarded-Proto başlığına bakmak

Flexible moddan hemen çıkamıyorsanız, Cloudflare'in isteğe eklediği X-Forwarded-Proto başlığına bakarak ziyaretçinin asıl bağlantı türünü öğrenebilirsiniz. Apache için:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://ornek.com%{REQUEST_URI} [L,R=301]

RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://ornek.com%{REQUEST_URI} [L,R=301]

İlk kural yalnızca hem sunucuya gelen bağlantı hem de ziyaretçinin bağlantısı şifresizse çalışır. İkinci kural, HTTPS ile gelen www isteklerini www'siz adrese alır. nginx'te aynı mantık map ile kurulur; map bloğu http bölümüne, geri kalanı 80 numaralı portu dinleyen sunucu bloğuna yazılır:

map $http_x_forwarded_proto $https_yonlendir {
    default 1;
    https   0;
}

server {
    listen 80;
    server_name ornek.com www.ornek.com;

    if ($https_yonlendir) {
        return 301 https://ornek.com$request_uri;
    }
    if ($host = www.ornek.com) {
        return 301 https://ornek.com$request_uri;
    }

    root /var/www/ornek.com;
    # sitenin geri kalan ayarları
}

Bu başlığı herhangi bir istemci de kendi isteğine ekleyebildiği için yöntemi kalıcı değil, geçici bir çözüm olarak görün.

WordPress, Flexible modda yönetim panelinde de döngüye girebilir, çünkü bağlantıyı HTTP sanar. wp-config.php dosyasında require_once ABSPATH . 'wp-settings.php'; satırından önce şu satırları eklemek bu sorunu giderir:

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

Cloudflare'in "Always Use HTTPS" ayarı da HTTP isteklerini daha sunucuya ulaşmadan https'e çevirir. Bu ayar açıksa sunucudaki HTTP kuralı yalnızca Cloudflare'i atlayıp doğrudan sunucuya gelen istekler için kalır.

Yönlendirmeyi curl ve tarayıcıyla test etmek

Tarayıcılar 301 yönlendirmelerini önbelleğe aldığı için, kuralı değiştirdikten sonra normal pencerede eski davranışı görmeye devam edebilirsiniz. Test için gizli pencere ya da daha iyisi komut satırı kullanın. curl, Windows 10 ve sonrasında, macOS ve Linux'ta hazır gelir:

curl -I "http://ornek.com/hakkimizda?kaynak=test"

Doğru kurulmuş bir kuralda cevabın ilk satırında 301 kodu (HTTP/1.1 301 Moved Permanently gibi) görünür ve yanıtta Location: https://ornek.com/hakkimizda?kaynak=test satırı bulunur. Zincirin tamamını görmek için Linux ya da macOS'ta:

curl -sIL "http://www.ornek.com/" | grep -iE "^(HTTP|location)"

Dört sürümü sırayla deneyin; her biri en fazla bir yönlendirmeyle son adrese ulaşmalı:

İstekBeklenen sonuç (www'siz site)
http://ornek.com/301 ile https://ornek.com/
http://www.ornek.com/301 ile https://ornek.com/
https://www.ornek.com/301 ile https://ornek.com/
https://ornek.com/200, yönlendirme yok

Yönlendirme çalıştıktan sonra iş bitmiş sayılmaz. Sayfa içinde http:// ile çağrılan görseller, betikler ya da stil dosyaları "karışık içerik" uyarısına yol açar; veritabanındaki eski adresleri güncellemek gerekir. Site haritasındaki ve canonical etiketlerindeki adreslerin https olduğundan emin olun ve Search Console'da birkaç sayfayı URL denetimi aracıyla kontrol edin. Bu aracın eski "Google gibi getir" özelliğinden farkını Google gibi getir yazısında anlattım; WordPress tarafındaki diğer ayarlar için WordPress SEO kontrol listesi işinize yarar.

HSTS başlığı: tarayıcıya yalnızca HTTPS kullanmasını söylemek

301 yönlendirme, ziyaretçinin ilk isteğinin yine HTTP ile gitmesini engellemez. Strict-Transport-Security (HSTS) başlığı ise tarayıcıya bu siteye belirtilen süre boyunca yalnızca HTTPS ile bağlanmasını söyler; tarayıcı http:// adresini istek göndermeden kendisi https'e çevirir. Apache ya da LiteSpeed'de .htaccess dosyasına:

<IfModule mod_headers.c>
    Header always set Strict-Transport-Security "max-age=300"
</IfModule>

nginx'te 443 portunu dinleyen sunucu bloğuna:

add_header Strict-Transport-Security "max-age=300" always;

nginx'te bir location bloğu kendi add_header satırlarını içeriyorsa, sunucu bloğundaki başlıklar o bloğa geçmez; HSTS satırını oraya da eklemeniz gerekir.

Örneklerdeki max-age=300 beş dakikadır ve bilerek kısa tutuldu. HSTS tarayıcıya bir kez ulaştıktan sonra süre dolana kadar geri alınamaz; sertifikanız bir gün sorun çıkarırsa ziyaretçiler siteye hiç giremez. Birkaç gün sorunsuz çalıştığını gördükten sonra süreyi bir haftaya, ardından bir yıla (max-age=31536000) çıkarın. includeSubDomains eklemeden önce bütün alt alan adlarınızın HTTPS ile çalıştığından emin olun. Tarayıcıların ön yükleme (preload) listesine girmek ise en az bir yıllık süre ile includeSubDomains ve preload ifadelerini birlikte ister ve listeden çıkmak uzun sürer.

Yönlendirme kuralları için hızlı teşhis

Kuralı ekledikten sonra 500 hatası alıyorum, neden?

Genelde ya bir yazım hatası vardır ya da sunucuda ilgili modül kapalıdır. mod_rewrite kapalıysa RewriteEngine satırı, mod_headers kapalıysa Header satırı hataya yol açar; Header satırını yukarıdaki gibi IfModule içine almak bu riski ortadan kaldırır. Hosting panelindeki hata günlüğü (error log) hangi satırın sorun çıkardığını gösterir.

301 yerine 302 kullansam ne olur?

302 geçici yönlendirmedir. Google uzun süre değişmeyen 302'leri zamanla kalıcı gibi değerlendirebilir, ama niyetiniz kalıcı bir taşıma olduğu için 301 hem arama motorlarına hem tarayıcılara doğru sinyali verir. Kuralı denerken 302 ile başlayıp her şey doğru çalışınca 301'e geçmek, tarayıcı önbelleğinde hatalı bir kalıcı yönlendirme kalmasını önler.

HTTPS'e geçmek sıralamamı etkiler mi?

Google, HTTPS'i hafif bir sıralama sinyali olarak kullandığını açıklamıştır; tek başına büyük bir sıçrama beklemeyin. Geçişten hemen sonra birkaç hafta dalgalanma görülebilir. Her eski adres tek bir 301 ile doğru karşılığına gidiyorsa sinyaller yeni adreslere aktarılır.

Yönlendirme eklentisi ile .htaccess kuralı bir arada kalırsa sorun olur mu?

İkisi aynı işi farklı katmanlarda yaptığı için çoğu zaman hemen bir sorun görünmez, ama zincirleme yönlendirme ve döngü riskini artırır. Birini seçin. Sunucu kuralı kullanıyorsanız eklentiyi kapatın ve WordPress'in Ayarlar > Genel sayfasındaki iki adresin de https ile başladığını kontrol edin.

HTTPS'e geçerken adres yapısını da değiştirdiyseniz, karşılığı olmayan eski adreslerin hata sayfasına düşmemesi gerekir; bunun sıralamaya etkisini 404 hatası ve SEO yazısında anlattım. Geçişten haftalar sonra sayfalarınız hâlâ aramada görünmüyorsa sitem Google'da çıkmıyor yazısındaki kontrollerle devam edin.

HY
Hüseyin Yılmaz

SEO Uzmanı & Dijital Pazarlama Danışmanı — SEO, web tasarım ve dijital pazarlama alanında uzman Hüseyin Yılmaz. Arama motorlarında görünürlüğünüzü artıran, dönüşüm odaklı stratejiler ve uygulanabilir rehberler.

Bu konuda desteğe mi ihtiyacınız var?

Sitenizi büyütmek için ücretsiz bir ön görüşme planlayalım.

İletişime Geç
WhatsApp