{"id":1582,"date":"2025-11-09T19:13:06","date_gmt":"2025-11-09T16:13:06","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/nginx-rate-limiting-ve-fail2ban-ile-wp%e2%80%91login-php-ve-xml%e2%80%91rpc-brute%e2%80%91force-saldirilarini-nasil-saksiya-alirsin\/"},"modified":"2025-11-09T19:13:06","modified_gmt":"2025-11-09T16:13:06","slug":"nginx-rate-limiting-ve-fail2ban-ile-wp%e2%80%91login-php-ve-xml%e2%80%91rpc-brute%e2%80%91force-saldirilarini-nasil-saksiya-alirsin","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/nginx-rate-limiting-ve-fail2ban-ile-wp%e2%80%91login-php-ve-xml%e2%80%91rpc-brute%e2%80%91force-saldirilarini-nasil-saksiya-alirsin\/","title":{"rendered":"Nginx Rate Limiting ve Fail2ban ile wp\u2011login.php ve XML\u2011RPC Brute\u2011Force Sald\u0131r\u0131lar\u0131n\u0131 Nas\u0131l Saks\u0131ya Al\u0131rs\u0131n?"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><h2 id='section-1'>Bir Sabah Loglar\u0131n Aras\u0131na D\u00fc\u015fmek: Neden Bu Konuyu Konu\u015fuyoruz?<\/h2>\n<p>Hi\u00e7 d\u00fcn ak\u015fam her \u015fey yolundayken sabah kahveni al\u0131p masaya oturdu\u011funda, log dosyalar\u0131n\u0131n \u00e7\u0131\u011f gibi b\u00fcy\u00fcd\u00fc\u011f\u00fcn\u00fc g\u00f6rd\u00fcn m\u00fc? Ben bir g\u00fcn tam olarak bunu ya\u015fad\u0131m. Sunucuya bakt\u0131m, CPU pek ses etmiyor ama bant geni\u015fli\u011finde ufak bir k\u0131p\u0131rdanma, Nginx loglar\u0131nda ard\u0131 ard\u0131na ayn\u0131 yollar: <strong>\/wp-login.php<\/strong> ve <strong>\/xmlrpc.php<\/strong>. Mesaj belli: Biri kap\u0131y\u0131 zorlam\u0131\u015f. D\u00fc\u015f\u00fcnd\u00fcm ki, bu sadece benim ba\u015f\u0131ma gelmiyor; WordPress kullanan pek \u00e7ok ki\u015finin \u201ctan\u0131d\u0131k\u201d sorunu. \u015eu me\u015fhur brute-force dalgalar\u0131.<\/p>\n<p>\u0130\u015fte burada iki eski dost devreye giriyor: <strong>Nginx Rate Limiting<\/strong> ve <strong>Fail2ban<\/strong>. Biri nazik\u00e7e \u201cyava\u015f karde\u015fim\u201d derken, di\u011feri sab\u0131rs\u0131z\u0131 kap\u0131dan al\u0131p kenara koyuyor. Bu yaz\u0131da ikisini birlikte nas\u0131l taktiksel ve s\u0131cak bir uyum i\u00e7inde \u00e7al\u0131\u015ft\u0131rabilece\u011fimizi konu\u015faca\u011f\u0131z. Nginx taraf\u0131nda ak\u0131\u015f\u0131 s\u0131n\u0131rlayaca\u011f\u0131z, istekleri ritme sokaca\u011f\u0131z; Fail2ban ile de \u0131srarc\u0131lar\u0131 k\u0131sa s\u00fcreli tatillere g\u00f6nderece\u011fiz. Arada Cloudflare, ger\u00e7ek IP, loglama ve ufak tefek p\u00fcr\u00fczler hakk\u0131nda da tatl\u0131 notlar var. Sonunda elinde hem anla\u015f\u0131l\u0131r hem de uygulanabilir bir re\u00e7ete olacak.<\/p>\n<h2 id='section-2'>Hedef Neden Hep wp-login.php ve XML\u2011RPC?<\/h2>\n<p>\u00d6nce hik\u00e2yenin kahramanlar\u0131n\u0131 tan\u0131yal\u0131m. <strong>wp-login.php<\/strong> WordPress\u2019in giri\u015f kap\u0131s\u0131. Tahmin edilebilir, herkes\u00e7e biliniyor. Sald\u0131rganlar, kullan\u0131c\u0131 ad\u0131 ve parola deneyerek bu kap\u0131y\u0131 zorlamay\u0131 pek seviyor. Y\u00fczlerce, bazen binlerce deneme ile k\u00fc\u00e7\u00fck bir a\u00e7\u0131k ar\u0131yorlar. Kimi zaman \u00e7\u0131ld\u0131rtacak kadar \u0131srarc\u0131 olabiliyorlar, \u00f6zellikle de bir yerlerden s\u0131zd\u0131r\u0131lm\u0131\u015f kullan\u0131c\u0131 ad\u0131 listeleri ellerindeyse.<\/p>\n<p><strong>xmlrpc.php<\/strong> ise farkl\u0131 bir d\u00fcnya. Uzaktan y\u00f6netim, mobil uygulama, Jetpack gibi ara\u00e7lar burada devreye giriyor. G\u00fczel taraf\u0131 \u015fu: Bir istekle birden fazla giri\u015f denemesini paketleyebiliyorlar. Bu da sald\u0131rgan\u0131n i\u015ftah\u0131n\u0131 kabart\u0131yor. E\u011fer sen XML\u2011RPC\u2019yi kullanm\u0131yorsan, bu kap\u0131 gereksiz a\u00e7\u0131k say\u0131l\u0131r. Kullan\u0131yorsan da \u00f6yle her iste\u011fi kabul etmek zorunda de\u011filsin; ak\u0131\u015f\u0131n\u0131 s\u0131n\u0131rlamak iyi fikir.<\/p>\n<p>G\u00fcn\u00fcn sonunda ikisi de ayn\u0131 problemi do\u011furuyor: Gere\u011finden fazla deneme, gereksiz kaynak t\u00fcketimi ve g\u00fcvenlik riski. Benim yakla\u015f\u0131m\u0131m \u015fu oldu: Nginx ile ritmi d\u00fc\u015f\u00fcr, Fail2ban ile \u0131srarc\u0131y\u0131 d\u0131\u015far\u0131 al. Bu komboyu do\u011fru kurunca hem kaynaklar\u0131n nefes al\u0131yor hem de gece daha rahat uyuyorsun.<\/p>\n<h2 id='section-3'>Nginx Rate Limiting: \u201cYava\u015f, Derin Nefes\u201d Tekni\u011fi<\/h2>\n<p>Mesela \u015f\u00f6yle d\u00fc\u015f\u00fcn: Kap\u0131nda bir s\u0131ra olu\u015fuyor, kap\u0131daki g\u00f6revli nazik ama net. \u201cHerkes s\u0131rayla.\u201d Nginx\u2019in <strong>limit_req<\/strong> mod\u00fcl\u00fc tam bunu yap\u0131yor. \u0130stek ba\u015f\u0131na bir ritim belirliyorsun, bir de ta\u015fma pay\u0131 tan\u0131ml\u0131yorsun. B\u00f6ylece ani patlamalar\u0131 yutuyor ama \u0131srarc\u0131y\u0131 tuhaf bir tempoya zorluyor. Bu bile pek \u00e7ok botun hevesini k\u0131r\u0131yor.<\/p>\n<p>Ben genelde giri\u015f kap\u0131s\u0131nda sadece <strong>POST<\/strong> isteklerini s\u0131n\u0131rl\u0131yorum. Ziyaret\u00e7i giri\u015f sayfas\u0131n\u0131 g\u00f6r\u00fcnt\u00fcleyebilir, sorun yok; ama arka arkaya parola deneyecekse, i\u015fte orada fren. XML\u2011RPC i\u00e7inse biraz daha s\u0131k\u0131 davran\u0131yorum \u00e7\u00fcnk\u00fc tek istekte birden fazla deneme yap\u0131labiliyor.<\/p>\n<p>A\u015fa\u011f\u0131daki \u00f6rnek Nginx taraf\u0131nda temel bir kurulum. De\u011ferler yol g\u00f6sterici, senin trafik profilin ve kullan\u0131c\u0131 deneyimin do\u011frultusunda yumu\u015fatabilirsin.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># \/etc\/nginx\/nginx.conf (veya http{} blo\u011fu)\n# IP ba\u015f\u0131na ritim alanlar\u0131\nlimit_req_zone $binary_remote_addr zone=wp_login:10m rate=5r\/m;       # wp-login i\u00e7in dakikada 5\nlimit_req_zone $binary_remote_addr zone=xmlrpc:10m rate=30r\/m;        # xmlrpc i\u00e7in dakikada 30\n\n# 429 kodunu net belirtelim\nlimit_req_status 429;\n\n# \u0130ste\u011fin POST olup olmad\u0131\u011f\u0131n\u0131 i\u015faretlemek i\u00e7in ufak bir i\u015faret\u00e7i\nmap $request_method $is_post {\n    default 0;\n    POST    1;\n}\n\n# \u0130ste\u011fin login\/xmlrpc olup olmad\u0131\u011f\u0131n\u0131 loglarda ay\u0131rmak daha g\u00fczel olur\nmap $uri $is_sensitive_endpoint {\n    default 0;\n    \/wp-login.php 1;\n    \/xmlrpc.php  1;\n}\n\nlog_format sensitive '$remote_addr - $remote_user [$time_local] '\n                    '&quot;$request&quot; $status $body_bytes_sent '\n                    '&quot;$http_referer&quot; &quot;$http_user_agent&quot;';\n<\/code><\/pre>\n<p>Sunucu blo\u011funda ise \u015fu \u015fekilde i\u015fleyebiliriz. Burada p\u00fcf noktas\u0131, <strong>limit_except<\/strong> ile yaln\u0131zca POST\u2019lar\u0131 s\u0131n\u0131rlamak ve 429 veren istekleri g\u00f6ze batmayan bir metinle kar\u015f\u0131lamak. Kullan\u0131c\u0131ya 429 g\u00f6stermek yerine ufak bir gecikme ve \u201csonra dene\u201d mesaj\u0131 koymak, botlar\u0131 pek ilgilendirmez ama insanlar i\u00e7in anla\u015f\u0131l\u0131r olur.<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\"># \/etc\/nginx\/sites-enabled\/senin-site.conf  (server{} i\u00e7inde)\n\n# Duyarl\u0131 yollar i\u00e7in ayr\u0131 log dosyas\u0131 a\u00e7mak istersen:\naccess_log \/var\/log\/nginx\/sensitive.log sensitive if=$is_sensitive_endpoint;\n\nlocation = \/wp-login.php {\n    # GET serbest, POST s\u0131n\u0131rl\u0131\n    limit_except GET {\n        limit_req zone=wp_login burst=10 nodelay;\n        add_header Retry-After 60 always;\n    }\n    # Burada normal PHP y\u00f6nlendirme blo\u011funu ekle\n    include fastcgi_params;\n    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n    fastcgi_pass unix:\/run\/php\/php8.2-fpm.sock;\n}\n\nlocation = \/xmlrpc.php {\n    # XML-RPC genelde sadece POST al\u0131r, o y\u00fczden direkt limit uyguluyoruz\n    limit_req zone=xmlrpc burst=20 nodelay;\n    add_header Retry-After 60 always;\n    include fastcgi_params;\n    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n    fastcgi_pass unix:\/run\/php\/php8.2-fpm.sock;\n}\n\n# \u0130ste\u011fe ba\u011fl\u0131: 429'lar i\u00e7in zarif bir yan\u0131t\nerror_page 429 = @ratelimited;\nlocation @ratelimited {\n    return 429 'Biraz yava\u015f gidelim. L\u00fctfen k\u0131sa bir s\u00fcre sonra tekrar dene.';\n    add_header Content-Type text\/plain;\n}\n<\/code><\/pre>\n<p>Burada kulland\u0131\u011f\u0131m oranlar \u00f6rnek. Giri\u015f sayfas\u0131nda dakikada be\u015f ba\u015far\u0131l\u0131 deneme, ta\u015fma pay\u0131 on; XML\u2011RPC\u2019de dakikada otuz, ta\u015fma pay\u0131 yirmi gibi. Ziyaret\u00e7i kitlene g\u00f6re y\u00fckseltip d\u00fc\u015f\u00fcrebilirsin. Ben \u00f6nce s\u0131k\u0131 ba\u015flar, sonra \u015fik\u00e2yet gelmezse biraz gev\u015fetirim. En g\u00fczeli ufak ufak ayar \u00e7ekmek.<\/p>\n<p>Teknik merakl\u0131s\u0131ysan Nginx\u2019in bu mod\u00fcl\u00fc i\u00e7in resmi dok\u00fcmana g\u00f6z atman iyi olur. Ben ilk kurcalad\u0131\u011f\u0131mda sahay\u0131 daha iyi anlamam\u0131 sa\u011flad\u0131: <a href=\"https:\/\/nginx.org\/en\/docs\/http\/ngx_http_limit_req_module.html\" rel=\"nofollow noopener\" target=\"_blank\">Nginx limit_req mod\u00fcl\u00fc dok\u00fcmantasyonu<\/a>.<\/p>\n<h2 id='section-4'>Fail2ban: Israrc\u0131y\u0131 Nezaketen D\u0131\u015far\u0131 Almak<\/h2>\n<p>Nginx ritmi d\u00fc\u015f\u00fcrd\u00fc. G\u00fczel. Ama baz\u0131 sald\u0131rganlar var ki tespih gibi \u0131srarla deniyor. Burada <strong>Fail2ban<\/strong> devreye girdi mi i\u015fler kolayla\u015f\u0131yor. Benim yakla\u015f\u0131m: Nginx\u2019in 429 verdi\u011fi <em>POST<\/em> isteklerini izlemek ve bunun belirli bir say\u0131y\u0131 ge\u00e7mesi durumunda IP\u2019yi bannlamak. B\u00f6ylece hem masum ziyaret\u00e7iyi \u00fczm\u00fcyorsun hem de sald\u0131rgana net bir s\u0131n\u0131r \u00e7iziyorsun.<\/p>\n<p>\u00d6nce basit bir filtre yazal\u0131m. Varsay\u0131lan Nginx log format\u0131n\u0131 kulland\u0131\u011f\u0131n\u0131 varsay\u0131yorum; IP, tarih, istek ve durum kodu klasik ak\u0131\u015fta.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># \/etc\/fail2ban\/filter.d\/nginx-wp-xmlrpc-rl.conf\n[Definition]\nfailregex = ^&lt;HOST&gt;s-s.*s&quot;POSTs\/wp-login.phpsHTTP\/S+&quot;s429s\n            ^&lt;HOST&gt;s-s.*s&quot;POSTs\/xmlrpc.phpsHTTP\/S+&quot;s429s\nignoreregex =\n<\/code><\/pre>\n<p>\u015eimdi bir de jail kural\u0131. Burada hangi portlar\u0131 kapataca\u011f\u0131n\u0131, ka\u00e7 denemeden sonra ban ataca\u011f\u0131n\u0131 ve ne kadar s\u00fcreyle d\u0131\u015far\u0131 alaca\u011f\u0131n\u0131 belirliyorsun. \u0130stersen \u201cnftables\u201d aksiyonunu da kullanabilirsin, sunucunda nftables \u00e7al\u0131\u015f\u0131yorsa bu daha g\u00fcncel bir yol.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># \/etc\/fail2ban\/jail.d\/nginx-wp-xmlrpc-rl.conf\n[nginx-wp-xmlrpc-rl]\nenabled  = true\nfilter   = nginx-wp-xmlrpc-rl\n# nftables kullan\u0131yorsan \u015fu aksiyonu tercih et (da\u011f\u0131t\u0131m\u0131na g\u00f6re de\u011fi\u015febilir):\n# action = nftables-multiport[name=nginx-rl, port=&quot;http,https&quot;, protocol=tcp]\n# iptables kullan\u0131yorsan:\naction   = iptables-multiport[name=nginx-rl, port=&quot;http,https&quot;, protocol=tcp]\nlogpath  = \/var\/log\/nginx\/access.log\nfindtime = 5m\nmaxretry = 5\nbantime  = 1h\n<\/code><\/pre>\n<p>Fail2ban\u2019i yeniden ba\u015flatmadan \u00f6nce kural\u0131n loglarla e\u015fle\u015fti\u011finden emin olmak g\u00fczel. Ben genelde test i\u00e7in a\u015fa\u011f\u0131dakini \u00e7al\u0131\u015ft\u0131r\u0131yorum:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">fail2ban-regex \/var\/log\/nginx\/access.log \/etc\/fail2ban\/filter.d\/nginx-wp-xmlrpc-rl.conf<\/code><\/pre>\n<p>\u00c7\u0131kan sonu\u00e7ta e\u015fle\u015fen sat\u0131rlar g\u00f6r\u00fcyorsan, do\u011fru yoldas\u0131n. Ard\u0131ndan Fail2ban\u2019i aya\u011fa kald\u0131r:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">systemctl restart fail2ban\nfail2ban-client status nginx-wp-xmlrpc-rl<\/code><\/pre>\n<p>Burada yasakl\u0131 IP say\u0131s\u0131n\u0131, ka\u00e7 kez tetiklendi\u011fini g\u00f6r\u00fcrs\u00fcn. Gerekirse <strong>findtime<\/strong>, <strong>maxretry<\/strong> ve <strong>bantime<\/strong> gibi parametreleri ufak ufak ayarlayarak kendi sitenin ritmine uydurursun. Ben ilk g\u00fcnlerde biraz s\u0131k\u0131 b\u0131rak\u0131p birka\u00e7 g\u00fcn sonra verileri okuyup daha dengeli de\u011ferlere \u00e7ekerim.<\/p>\n<p>Ek bir not: Cloudflare arkas\u0131ndaysan a\u011f katman\u0131nda IP banlamak pek i\u015fe yaramaz, \u00e7\u00fcnk\u00fc ba\u011flant\u0131 sunucuna Cloudflare IP\u2019lerinden gelir. Yine de loglarda ger\u00e7ek istemci IP\u2019sini g\u00f6rmek istiyorsan Fail2ban ile <em>Cloudflare action<\/em> kullanabilir veya Nginx i\u00e7inde yasaklanan IP\u2019leri bir harita dosyas\u0131na yazd\u0131ran aksiyonlar tercih edebilirsin. \u00c7ok derine dalmadan, pratik kalmak istersen Nginx rate limit \u00e7o\u011fu zaman tek ba\u015f\u0131na sald\u0131r\u0131y\u0131 s\u00f6nd\u00fcr\u00fcr, Fail2ban ise ar\u0131za yapanlar\u0131 daha h\u0131zl\u0131 budar. Fail2ban\u2019in dok\u00fcmantasyonuna g\u00f6z atmak istersen: <a href=\"https:\/\/fail2ban.readthedocs.io\/en\/latest\/\" rel=\"nofollow noopener\" target=\"_blank\">Fail2ban resmi dok\u00fcmantasyonu<\/a>.<\/p>\n<h2 id='section-5'>Proxy Arkas\u0131, Ger\u00e7ek IP, Loglar ve K\u00fc\u00e7\u00fck Tuzaklar<\/h2>\n<p>\u0130\u015fin en \u00e7ok atlanan k\u0131sm\u0131 buras\u0131. E\u011fer Cloudflare veya ba\u015fka bir CDN\/proxy kullan\u0131yorsan, Nginx\u2019in ger\u00e7ek istemci IP\u2019sini g\u00f6rmesi gerekir. Aksi halde loglarda hep CDN IP\u2019lerini g\u00f6r\u00fcrs\u00fcn; Fail2ban de yanl\u0131\u015f IP\u2019yi hedef al\u0131r. Bunun \u00e7\u00f6z\u00fcm\u00fc basit: Ger\u00e7ek IP ba\u015fl\u0131\u011f\u0131n\u0131 tan\u0131tmak.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># \/etc\/nginx\/nginx.conf (http{} i\u00e7inde)\n# Cloudflare \u00f6rne\u011fi:\nset_real_ip_from  173.245.48.0\/20;\nset_real_ip_from  103.21.244.0\/22;\nset_real_ip_from  103.22.200.0\/22;\nset_real_ip_from  103.31.4.0\/22;\n# ... (Cloudflare IPv4\/IPv6 bloklar\u0131n\u0131n tamam\u0131)\nreal_ip_header    CF-Connecting-IP;\n<\/code><\/pre>\n<p>Cloudflare IP bloklar\u0131 de\u011fi\u015febildi\u011fi i\u00e7in g\u00fcncel listeyi periyodik kontrol etmekte fayda var. Ayr\u0131ca HTTP\/2 ve HTTP\/3 kullan\u0131yorsan, a\u011f\u0131n u\u00e7tan uca modernle\u015fmesi hem performans hem de stabilite i\u00e7in iyi hissettiriyor. Buna dair pratik bir kurulum ak\u0131\u015f\u0131 istersen, \u015fu rehber elini s\u0131cak tutar: <a href=\"https:\/\/www.dchost.com\/blog\/nginx-ve-cloudflareda-http-2-ve-http-3-quic-nasil-etkinlestirilir-wordpress-icin-uctan-uca-kurulum-ve-test-rehberi\/\">Nginx ve Cloudflare\u2019da HTTP\/2 ve HTTP\/3\u2019\u00fc etkinle\u015ftirme rehberi<\/a>.<\/p>\n<p>G\u00fcvenlik katman\u0131n\u0131 sadece uygulama taraf\u0131nda b\u0131rakmak bazen yetmeyebilir. Basit ama etkili bir a\u011f duvar\u0131 d\u00fczeni de i\u015fleri sakinle\u015ftirir. E\u011fer sunucunda <strong>nftables<\/strong> kullan\u0131yorsan, rate limit ve k\u00fc\u00e7\u00fck ak\u0131\u015f kurallar\u0131 hayli leziz sonu\u00e7 veriyor. Bir ara \u015fu yaz\u0131da anlatt\u0131\u011f\u0131m yakla\u015f\u0131ma g\u00f6z atm\u0131\u015ft\u0131m ve h\u00e2l\u00e2 \u00e7o\u011fu <a href=\"https:\/\/www.dchost.com\/tr\/vps\">VPS<\/a>\u2019te i\u015f g\u00f6r\u00fcyor: <a href=\"https:\/\/www.dchost.com\/blog\/nftables-ile-vps-guvenlik-duvari-rehberi-rate-limit-port-knocking-ve-ipv6-kurallari-nasil-tatli-tatli-kurulur\/\">nftables ile VPS g\u00fcvenlik duvar\u0131 rehberi<\/a>.<\/p>\n<p>Log taraf\u0131nda ise bir \u00f6neri daha: Duyarl\u0131 u\u00e7 noktalar\u0131 ayr\u0131 log dosyas\u0131na almak tan\u0131 koymay\u0131 kolayla\u015ft\u0131r\u0131yor. \u00dcstteki <code>log_format sensitive<\/code> ve <code>access_log ... if=$is_sensitive_endpoint<\/code> ikilisi bunun i\u00e7in. \u0130leride merkezi loglamaya ge\u00e7ersen anomaliyi yakalamak \u00e7ok daha kolayla\u015f\u0131r.<\/p>\n<h2 id='section-6'>XML\u2011RPC\u2019yi Kapatmal\u0131 m\u0131y\u0131m, K\u0131smal\u0131 m\u0131y\u0131m?<\/h2>\n<p>G\u00fczel soru. Her zaman ayn\u0131 cevap yok. E\u011fer WordPress mobil uygulamas\u0131, baz\u0131 otomasyon ara\u00e7lar\u0131 veya Jetpack gibi \u00f6zellikler kullan\u0131yorsan <strong>xmlrpc.php<\/strong> i\u015fe yar\u0131yor. Ama hi\u00e7 kullanm\u0131yorsan, neden a\u00e7\u0131k dursun? Ben genelde \u015f\u00f6yle yap\u0131yorum: \u00d6nce kullan\u0131p kullanmad\u0131\u011f\u0131m\u0131 d\u00fcr\u00fcst\u00e7e kontrol ediyorum. Kullanm\u0131yorsam net bi\u00e7imde kapat\u0131yorum. Kullan\u0131yorsam da Nginx ile s\u0131k\u0131 bir rate limit, gerekiyorsa ufak bir <em>Basic Auth<\/em> duvar\u0131 veya IP tabanl\u0131 k\u0131s\u0131t ekliyorum.<\/p>\n<p>Kapatmak istersen Nginx taraf\u0131nda nazik\u00e7e kap\u0131 duvar\u0131 \u00f6rebilirsin:<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\">location = \/xmlrpc.php {\n    return 444;  # sessizce kapat\n}\n<\/code><\/pre>\n<p>Bu, botlar\u0131n hevesini hemen k\u0131rar. Fakat tamamen kapatmadan \u00f6nce sisteminde nelere dokundu\u011funu d\u00fc\u015f\u00fcn. E\u011fer emin de\u011filsen, \u00f6nce s\u0131k\u0131 bir rate limit ile ba\u015fla, g\u00f6zlemle. WordPress ekosistemindeki uzaktan \u00e7a\u011fr\u0131lar\u0131 anlama niyetindeysen, resmi referanslar fikir veriyor: <a href=\"https:\/\/developer.wordpress.org\/apis\/overview\/xml-rpc\/\" rel=\"nofollow noopener\" target=\"_blank\">WordPress XML\u2011RPC genel bak\u0131\u015f<\/a>.<\/p>\n<p>Ben bazen bir \u201c\u00f6n kap\u0131\u201d daha koyuyorum. \u00d6zellikle xmlrpc\u2019nin ger\u00e7ekten gerekli oldu\u011fu projelerde, k\u00fc\u00e7\u00fck bir <strong>Basic Auth<\/strong> katman\u0131 fena i\u015f g\u00f6rm\u00fcyor. Sald\u0131rganlar i\u00e7in fazladan bir kap\u0131, me\u015fru servisler i\u00e7inse kolayca ge\u00e7ilen bir e\u015fik. Dikkat edilmesi gereken nokta, uygulaman\u0131n kulland\u0131\u011f\u0131 istemcilerin bu ekstra kimli\u011fi do\u011fru verebilmesi.<\/p>\n<h2 id='section-7'>\u0130zlemek, Test Etmek, K\u00fc\u00e7\u00fck Ayarlar Yapmak<\/h2>\n<p>Bir kurulumun ger\u00e7ekten \u00e7al\u0131\u015f\u0131p \u00e7al\u0131\u015fmad\u0131\u011f\u0131n\u0131 anlaman\u0131n en h\u0131zl\u0131 yolu k\u00fc\u00e7\u00fck testler. Ben \u00f6nce bir terminale ge\u00e7ip birka\u00e7 h\u0131zl\u0131 POST iste\u011fi atar\u0131m, Nginx\u2019ten 429 d\u00fc\u015f\u00fcyor mu bakar\u0131m:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">for i in $(seq 1 20); do \n  curl -s -o \/dev\/null -w &quot;%{http_code}n&quot; -X POST https:\/\/alanad\u0131n.com\/wp-login.php; \n  sleep 0.5; \ndone\n<\/code><\/pre>\n<p>Bir noktada 429 g\u00f6r\u00fcyorsan, Nginx ritmi yakalam\u0131\u015f demektir. Ard\u0131ndan <code>fail2ban-client status nginx-wp-xmlrpc-rl<\/code> ile ban\u2019\u0131n tetiklenip tetiklenmedi\u011fine bakar\u0131m. \u0130lk saatlerde biraz s\u0131k\u0131 bir bantime koyup, birka\u00e7 g\u00fcn sonra veriyi okur ayarlar\u0131 yumu\u015fat\u0131r\u0131m.<\/p>\n<p>E\u011fer merkezi loglama kuruluysa trend g\u00f6rmek \u00e7ok daha kolay. Ben \u00e7o\u011fu VPS\u2019te <a href=\"https:\/\/www.dchost.com\/blog\/vps-log-yonetimi-nasil-rayina-oturur-grafana-loki-promtail-ile-merkezi-loglama-tutma-sureleri-ve-alarm-kurallari\/\">Grafana Loki + Promtail ile merkezi loglama<\/a> yakla\u015f\u0131m\u0131n\u0131 seviyorum. 429 art\u0131\u015f e\u011frisi, belirli saatlerde yo\u011funla\u015fan denemeler, hatta tek bir kaynaktan f\u0131\u015fk\u0131ran dalga\u2026 Hepsi g\u00f6z\u00fcn\u00fcn \u00f6n\u00fcne seriliyor. Tetikleyici alarmlar kurgulamak da cabas\u0131.<\/p>\n<p>WordPress\u2019i konteynerlarda ko\u015fturuyorsan, Nginx ve PHP-FPM kombinasyonunu container i\u00e7inde ya da host \u00fcst\u00fcnde konumland\u0131rman fark yarat\u0131r. Bu tarz canl\u0131ya alma ve kal\u0131c\u0131 depolama ak\u0131\u015flar\u0131n\u0131 derli toplu bir \u015fekilde g\u00f6rmek istersen, \u015furadaki yolculuk bence iyi bir rehber oluyor: <a href=\"https:\/\/www.dchost.com\/blog\/docker-ile-wordpressi-vpste-nasil-yasatiriz-nginx-mariadb-redis-ve-lets-encrypt-ile-kalici-depolama-macerasi\/\">Docker ile WordPress\u2019i VPS\u2019te ya\u015fatmak<\/a>.<\/p>\n<h2 id='section-8'>Ufak P\u00fcr\u00fczler, Pratik \u00c7\u00f6z\u00fcmler<\/h2>\n<p>Her kurulumda bir iki k\u00fc\u00e7\u00fck p\u00fcr\u00fcz \u00e7\u0131kar. En yayg\u0131n olanlar\u0131 \u015f\u00f6yle deneyimledim. Birincisi, <strong>log format\u0131<\/strong>. Fail2ban filtresindeki regex, log format\u0131nla birebir uyumlu olmal\u0131. \u00d6zel bir format kullan\u0131yorsan filtreyi ona g\u00f6re g\u00fcncelle. Test i\u00e7in <code>fail2ban-regex<\/code> kurtar\u0131c\u0131. \u0130kincisi, <strong>ger\u00e7ek IP<\/strong>. Proxy arkas\u0131nda ger\u00e7ek IP\u2019yi Nginx\u2019e tan\u0131tmad\u0131ysan Fail2ban yanl\u0131\u015f ki\u015fiyi cezaland\u0131rabilir. Bu da can s\u0131kar.<\/p>\n<p>\u00dc\u00e7\u00fcnc\u00fcs\u00fc, <strong>limitleri \u00e7ok s\u0131k\u0131 tutmak<\/strong>. Bazen iyi niyetli kullan\u0131c\u0131lar\u0131n, \u00f6zellikle mobil ba\u011flant\u0131larda, birka\u00e7 denemesi \u00fcst \u00fcste gelebiliyor. \u0130lk g\u00fcnlerde biraz s\u0131k\u0131 ba\u015flay\u0131p sonra veriye bakarak yumu\u015fatmak, hem g\u00fcvenli\u011fi hem kullan\u0131c\u0131 deneyimini dengeler. D\u00f6rd\u00fcnc\u00fcs\u00fc, <strong>testi ihmal etmek<\/strong>. Terminalden bir iki <code>curl<\/code> ile 429\u2019u g\u00f6rmek, Fail2ban istatistiklerini kontrol etmek al\u0131\u015fkanl\u0131k olsun. Son olarak, <strong>Cloudflare aksiyonlar\u0131<\/strong>. Ger\u00e7ekten laz\u0131m oldu\u011funda Fail2ban\u2019in Cloudflare API aksiyonlar\u0131na da bakabilirsin; do\u011frudan Cloudflare d\u00fczeyinde engellemek bazen daha pratik oluyor.<\/p>\n<p>Bu arada SSL ve modern protokoller taraf\u0131nda da ufak dokunu\u015flar yapmak sunucunun genel sa\u011fl\u0131\u011f\u0131n\u0131 etkiliyor. Sertifika, HSTS, modern \u015fifre tak\u0131mlar\u0131 ve el s\u0131k\u0131\u015fmas\u0131 ayarlar\u0131 i\u00e7in ben ge\u00e7mi\u015fte \u015fu rehberden faydalanm\u0131\u015ft\u0131m: <a href=\"https:\/\/www.dchost.com\/blog\/tls-1-3-ve-modern-sifrelerin-sicacik-mutfagi-nginx-apachede-ocsp-stapling-hsts-preload-ve-pfs-nasil-kurulur\/\">TLS 1.3 ve modern \u015fifrelerin s\u0131cac\u0131k mutfa\u011f\u0131<\/a>. G\u00fcvenlik bir b\u00fct\u00fcn.<\/p>\n<h2 id='section-9'>Kapan\u0131\u015f: Ritmi Sen Belirle<\/h2>\n<p>\u015e\u00f6yle ba\u011flayay\u0131m: Brute\u2011force asl\u0131nda \u00e7o\u011fu zaman g\u00fcr\u00fclt\u00fcden ibaret. Yeter ki ritmi sen belirle. <strong>Nginx rate limiting<\/strong> ile bir anda y\u00fckleneni yava\u015flat, <strong>Fail2ban<\/strong> ile \u0131srarc\u0131y\u0131 kibarca d\u0131\u015far\u0131 al. Gerekirse xmlrpc\u2019yi kapat, gerekirse k\u0131s. Proxy arkas\u0131ndaysan ger\u00e7ek IP\u2019yi tan\u0131t, loglar\u0131n\u0131 ayr\u0131 bir k\u00f6\u015feye not al, sonra da birka\u00e7 k\u00fc\u00e7\u00fck testle d\u00fczenini do\u011frula. Hepsi bu kadar. Karma\u015f\u0131k gibi g\u00f6r\u00fcnse de elin al\u0131\u015f\u0131nca \u00e7ok do\u011fal bir refleks haline geliyor.<\/p>\n<p>Umar\u0131m bu yaz\u0131 sana fikir vermi\u015ftir. Kendi trafi\u011fini ve kullan\u0131c\u0131lar\u0131n\u0131 tan\u0131y\u0131p de\u011ferleri ona g\u00f6re ayarlad\u0131\u011f\u0131nda, hem sunucun rahat edecek hem sen. Tak\u0131ld\u0131\u011f\u0131n bir yerde k\u00fc\u00e7\u00fck k\u00fc\u00e7\u00fck ilerle, par\u00e7a par\u00e7a test et. Bir sonraki yaz\u0131da g\u00f6r\u00fc\u015fmek \u00fczere; loglar\u0131n sakince akmas\u0131, ban listelerinin bo\u015f kalmas\u0131 dile\u011fiyle. Bu arada detayl\u0131 belge okumay\u0131 seviyorsan Nginx\u2019in limit mod\u00fcl\u00fc ve Fail2ban dok\u00fcmantasyonlar\u0131 g\u00fczel kaynaklar; k\u00fc\u00e7\u00fck molalarda g\u00f6z atmak iyi geliyor.<\/p>\n<p>\u0130lgini \u00e7ekebilecek d\u0131\u015f kaynaklar: <a href=\"https:\/\/nginx.org\/en\/docs\/http\/ngx_http_limit_req_module.html\" rel=\"nofollow noopener\" target=\"_blank\">Nginx limit_req mod\u00fcl\u00fc<\/a>, <a href=\"https:\/\/fail2ban.readthedocs.io\/en\/latest\/\" rel=\"nofollow noopener\" target=\"_blank\">Fail2ban belgeleri<\/a> ve <a href=\"https:\/\/developer.wordpress.org\/apis\/overview\/xml-rpc\/\" rel=\"nofollow noopener\" target=\"_blank\">WordPress XML\u2011RPC genel bak\u0131\u015f<\/a>. \u0130\u00e7erideki yolculuklar i\u00e7inse <a href=\"https:\/\/www.dchost.com\/blog\/nftables-ile-vps-guvenlik-duvari-rehberi-rate-limit-port-knocking-ve-ipv6-kurallari-nasil-tatli-tatli-kurulur\/\">nftables ile VPS g\u00fcvenlik duvar\u0131<\/a>, <a href=\"https:\/\/www.dchost.com\/blog\/vps-log-yonetimi-nasil-rayina-oturur-grafana-loki-promtail-ile-merkezi-loglama-tutma-sureleri-ve-alarm-kurallari\/\">Loki + Promtail ile log y\u00f6netimi<\/a>, <a href=\"https:\/\/www.dchost.com\/blog\/docker-ile-wordpressi-vpste-nasil-yasatiriz-nginx-mariadb-redis-ve-lets-encrypt-ile-kalici-depolama-macerasi\/\">WordPress\u2019i Docker\u2019da ya\u015fatmak<\/a> ve <a href=\"https:\/\/www.dchost.com\/blog\/nginx-ve-cloudflareda-http-2-ve-http-3-quic-nasil-etkinlestirilir-wordpress-icin-uctan-uca-kurulum-ve-test-rehberi\/\">Cloudflare + Nginx ile HTTP\/2\u20113<\/a> leziz e\u015flik\u00e7iler olur.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Bir Sabah Loglar\u0131n Aras\u0131na D\u00fc\u015fmek: Neden Bu Konuyu Konu\u015fuyoruz? Hi\u00e7 d\u00fcn ak\u015fam her \u015fey yolundayken sabah kahveni al\u0131p masaya oturdu\u011funda, log dosyalar\u0131n\u0131n \u00e7\u0131\u011f gibi b\u00fcy\u00fcd\u00fc\u011f\u00fcn\u00fc g\u00f6rd\u00fcn m\u00fc? Ben bir g\u00fcn tam olarak bunu ya\u015fad\u0131m. Sunucuya bakt\u0131m, CPU pek ses etmiyor ama bant geni\u015fli\u011finde ufak bir k\u0131p\u0131rdanma, Nginx loglar\u0131nda ard\u0131 ard\u0131na ayn\u0131 yollar: \/wp-login.php ve \/xmlrpc.php. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1583,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-1582","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-teknoloji"],"_links":{"self":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/posts\/1582","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/comments?post=1582"}],"version-history":[{"count":0,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/posts\/1582\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/media\/1583"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/media?parent=1582"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/categories?post=1582"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/tags?post=1582"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}