Nginx ile WordPress ve WooCommerce Caching

Geçenlerde bir arkadaşım e-ticaret sitesi için reklam verdikten sonra sitesinin trafiği kaldıramayıp çöktüğünü söyledi. Arkadaşım sitesinde wordpress ve woocommerce pluginini kullanıyordu. 10 dolarlık vps üzerinde apache2+php+mariadb üçlüsü üzerinden sitesinini yayınlamıştık fakat yükün artmasıyla beraber bu stack sorunumuzu çözmez hale gelmişti. Bende yeni çözümler aramaya başladım.

İlk olarak apache yerine nginx ile değiştirmeyi düşündüm çünkü nginx yapılan testlere göre yük altında çok daha iyi bir performans gösteriyordu. Ayrıca konfigurasyonuda oldukça basitti. Nginx kurulumunu yaptım ve php olarak php’nin en güncel sürümü olan 7.3 sürümünü tercih ettim. Php-fpm’i nginx’in arkasında çalışacak şekilde konfigure ettim.

Artık caching konfigurasyonlarını yazmak için hazırdım. Nginx tarafında bütün istekleri cacheyip sunucu yükünü düşürmeyi hedefliyordum. Önceki stack’e yaklaşık 100-200 anlık ziyaretçi kaldırabilen sunucunun şuanki durumu anlık 2000-3000 kullanıcıya başarılı bir şekilde hizmet verebiliyor.

Konfigurasyondan biraz bahsetmek gerekirse;

fastcgi_cache_path /var/run/nginx-fastcgi-cache levels=1:2 keys_zone=FASTCGICACHE:512m inactive=60m;

ile /var/run/nginx-fastcgi-cache pathine isteklerin 60dk boyunca cachelenmesini bu cachelerin maksimum 512mb yer kullanabilecekleri şekilde ayarladım.

limit_req zone=zone burst=5;
limit_req_zone "$http_x_forwarded_for" zone=zone:10m rate=2r/s;

ile http flood yani layer 7 dos saldırısı durumunda uygun bir rate limiting ayarladım. Buradaki dikkat edilmesi gereken nokta site cloudflare arkasında olduğu için ziyaretçilerin gerçek ip adresini göremiyoruz eğer ziyaretçinin gerçek ip’sini öğrenmemiz gerekirse “$http_x_forwarded_for” değişkeninden yararlanabiliriz bu değişken bizim için http http_x_forwarded_for header’ından gerçek ip’yi okur (cloudflare http_x_forwarded_for headerında ziyaretçinin gerçek ip’sini iletiyor)

listen 443 ssl http2;

ile sunucumuzun http2+ssl ile çalışmasını sağladık.

set $skip_cache 0;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 0;
}
# Don't cache uris containing the following segments
if ($request_uri ~* "/xmlrpc.php|wp-.*.php|/feed/|sitemap(_index)?.xml") {
set $skip_cache 1;
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
if ($http_cookie ~* "wp_woocommerce_session.*") {
set $skip_cache 1;
}
if ($request_uri ~* "/store.*|/cart.*|/my-account.*|/checkout.*|/addons.*") {
set $skip_cache 1;
}
location / {
try_files $uri $uri/ /index.php?q=$uri&$args;
}
location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ {
access_log off;
expires max;
}
location ~ /\.ht {
deny all;
}

ile hangi durumlarda cache’in bypass edileceğinin kurallarını yazdık.

ve artık test etmeye hazırız.

Gördüğünüz gibi dönen cevabın headerlarında x-fastcgi-cache: HIT ibaresi buluyor buda demek oluyor ki response başarılı bir şekilde cache’den dönmüş.

İlgili konfigurasyonlara aşağıdaki linkten ulaşabilirsiniz.

https://github.com/ismkdc/nginx-woocommerce-caching/

Okuduğunuz için teşekkürler, bir sonraki yazımızda görüşmek üzere :)