{"id":3610,"date":"2025-12-28T18:36:02","date_gmt":"2025-12-28T15:36:02","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/websocket-tabanli-gercek-zamanli-uygulamalar-icin-dogru-hosting-secimi\/"},"modified":"2026-11-04T20:10:42","modified_gmt":"2026-11-04T17:10:42","slug":"websocket-hosting-secimi-reverb-socketio","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/websocket-hosting-secimi-reverb-socketio\/","title":{"rendered":"WebSocket Hosting: Laravel Reverb ve Socket.IO"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><div id=\"toc_container\" role=\"navigation\" aria-label=\"Table of Contents\" data-nosnippet class=\"toc_transparent no_bullets toc_numbered toc_title_center\"><p class=\"toc_title\">\u0130\u00e7indekiler<\/p><ul class=\"toc_list\"><li><a href=\"#WebSocket_Hosting_Laravel_Reverb_ve_SocketIO\"><span class=\"toc_number toc_depth_1\">1.<\/span> WebSocket Hosting: Laravel Reverb ve Socket.IO<\/a><\/li><li><a href=\"#WebSocket_ve_Gercek_Zamanli_Iletisim_HTTPden_Farki_Ne\"><span class=\"toc_number toc_depth_1\">2.<\/span> WebSocket ve Ger\u00e7ek Zamanl\u0131 \u0130leti\u015fim: HTTP\u2019den Fark\u0131 Ne?<\/a><\/li><li><a href=\"#Paylasimli_Hosting_Uzerinde_WebSocket_Nodejs_ve_Laravel_Echo_Mumkun_mu\"><span class=\"toc_number toc_depth_1\">3.<\/span> Payla\u015f\u0131ml\u0131 Hosting \u00dczerinde WebSocket, Node.js ve Laravel Echo M\u00fcmk\u00fcn m\u00fc?<\/a><ul><li><a href=\"#Paylasimli_Hostingte_Laravel_Echo_Kullanimi\"><span class=\"toc_number toc_depth_2\">3.1.<\/span> Payla\u015f\u0131ml\u0131 Hostingte Laravel Echo Kullan\u0131m\u0131<\/a><\/li><li><a href=\"#Resource_Limit_Reached_Gercegi\"><span class=\"toc_number toc_depth_2\">3.2.<\/span> \u201cResource Limit Reached\u201d Ger\u00e7e\u011fi<\/a><\/li><\/ul><\/li><li><a href=\"#VPS_Uzerinde_WebSocket_Sunucusu_Kurmanin_Avantajlari\"><span class=\"toc_number toc_depth_1\">4.<\/span> VPS \u00dczerinde WebSocket Sunucusu Kurman\u0131n Avantajlar\u0131<\/a><ul><li><a href=\"#Kapasite_Planlama_Kac_WebSocket_Baglantisi_Tasiyabilirim\"><span class=\"toc_number toc_depth_2\">4.1.<\/span> Kapasite Planlama: Ka\u00e7 WebSocket Ba\u011flant\u0131s\u0131 Ta\u015f\u0131yabilirim?<\/a><\/li><li><a href=\"#Guvenlik_Firewall_ve_Ag_Katmani\"><span class=\"toc_number toc_depth_2\">4.2.<\/span> G\u00fcvenlik, Firewall ve A\u011f Katman\u0131<\/a><\/li><\/ul><\/li><li><a href=\"#Laravel_Reverb_ve_Echo_Calisan_Yayin_Akisi\"><span class=\"toc_number toc_depth_1\">5.<\/span> Laravel Reverb ve Echo: \u00c7al\u0131\u015fan Yay\u0131n Ak\u0131\u015f\u0131<\/a><ul><li><a href=\"#1_Kurulum_Ortam_Degiskenleri_ve_Kanal_Yetkisi\"><span class=\"toc_number toc_depth_2\">5.1.<\/span> 1) Kurulum, Ortam De\u011fi\u015fkenleri ve Kanal Yetkisi<\/a><\/li><li><a href=\"#2_Yetkili_Yayin_Rotasi_ve_Echo_Abonesi\"><span class=\"toc_number toc_depth_2\">5.2.<\/span> 2) Yetkili Yay\u0131n Rotas\u0131 ve Echo Abonesi<\/a><\/li><li><a href=\"#3_Nginx_ile_WebSocket_Reverse_Proxy\"><span class=\"toc_number toc_depth_2\">5.3.<\/span> 3) Nginx ile WebSocket Reverse Proxy<\/a><\/li><li><a href=\"#4_Reverb_Queue_Worker_ve_Nodejs_Surec_Yonetimi\"><span class=\"toc_number toc_depth_2\">5.4.<\/span> 4) Reverb, Queue Worker ve Node.js S\u00fcre\u00e7 Y\u00f6netimi<\/a><\/li><\/ul><\/li><li><a href=\"#Bagimsiz_Nodejs_ve_SocketIO_Yetkili_Oda_Ornegi\"><span class=\"toc_number toc_depth_1\">6.<\/span> Ba\u011f\u0131ms\u0131z Node.js ve Socket.IO: Yetkili Oda \u00d6rne\u011fi<\/a><\/li><li><a href=\"#Paylasimli_Hostingten_VPSe_WebSocket_Uygulamasini_Tasimak\"><span class=\"toc_number toc_depth_1\">7.<\/span> Payla\u015f\u0131ml\u0131 Hosting\u2019ten VPS\u2019e WebSocket Uygulamas\u0131n\u0131 Ta\u015f\u0131mak<\/a><ul><li><a href=\"#1_DNS_ve_Alan_Adi_Plani\"><span class=\"toc_number toc_depth_2\">7.1.<\/span> 1) DNS ve Alan Ad\u0131 Plan\u0131<\/a><\/li><li><a href=\"#2_Uygulama_ve_Konfigurasyon_Tasima\"><span class=\"toc_number toc_depth_2\">7.2.<\/span> 2) Uygulama ve Konfig\u00fcrasyon Ta\u015f\u0131ma<\/a><\/li><li><a href=\"#3_Test_Load_Test_ve_Asamali_Gecis\"><span class=\"toc_number toc_depth_2\">7.3.<\/span> 3) Test, Load Test ve A\u015famal\u0131 Ge\u00e7i\u015f<\/a><\/li><\/ul><\/li><li><a href=\"#Operasyonel_Ipuclari_Loglama_Izleme_Yedekleme\"><span class=\"toc_number toc_depth_1\">8.<\/span> Operasyonel \u0130pu\u00e7lar\u0131: Loglama, \u0130zleme, Yedekleme<\/a><ul><li><a href=\"#Loglama_ve_Gozlemlenebilirlik\"><span class=\"toc_number toc_depth_2\">8.1.<\/span> Loglama ve G\u00f6zlemlenebilirlik<\/a><\/li><li><a href=\"#Kaynak_Izleme_ve_Alarm\"><span class=\"toc_number toc_depth_2\">8.2.<\/span> Kaynak \u0130zleme ve Alarm<\/a><\/li><li><a href=\"#Yedekleme_Stratejisi\"><span class=\"toc_number toc_depth_2\">8.3.<\/span> Yedekleme Stratejisi<\/a><\/li><\/ul><\/li><li><a href=\"#DCHost_Tarafinda_Hangi_Senaryoda_Hangi_Urun_Mantikli\"><span class=\"toc_number toc_depth_1\">9.<\/span> DCHost Taraf\u0131nda Hangi Senaryoda Hangi \u00dcr\u00fcn Mant\u0131kl\u0131?<\/a><\/li><li><a href=\"#Hosting_Secimini_Protokol_ve_Olcumle_Yapin\"><span class=\"toc_number toc_depth_1\">10.<\/span> Hosting Se\u00e7imini Protokol ve \u00d6l\u00e7\u00fcmle Yap\u0131n<\/a><\/li><li><a href=\"#Birincil_Teknik_Kaynaklar\"><span class=\"toc_number toc_depth_1\">11.<\/span> Birincil Teknik Kaynaklar<\/a><\/li><\/ul><\/div>\n<h2><span id=\"WebSocket_Hosting_Laravel_Reverb_ve_SocketIO\">WebSocket Hosting: Laravel Reverb ve Socket.IO<\/span><\/h2>\n<p>Ger\u00e7ek zamanl\u0131 bildirimler, canl\u0131 destek pencereleri, anl\u0131k skor veya fiyat panelleri, \u00e7ok oyunculu oyunlar\u2026 Bunlar\u0131n ortak noktas\u0131, verilerin istemcilere d\u00fc\u015f\u00fck gecikmeyle ula\u015ft\u0131r\u0131lmas\u0131 ihtiyac\u0131d\u0131r. <strong>Kal\u0131c\u0131 ve \u00e7ift y\u00f6nl\u00fc bir ba\u011flant\u0131<\/strong> bunu sa\u011flaman\u0131n yollar\u0131ndan biridir. Bu da bizi WebSocket protokol\u00fcne, Node.js tabanl\u0131 sunuculara, Laravel Echo ve Socket.io gibi k\u00fct\u00fcphanelere g\u00f6t\u00fcr\u00fcyor.<\/p>\n<p>WebSocket, klasik PHP tabanl\u0131 request\u2013response i\u015fleyi\u015finden farkl\u0131d\u0131r: Tek bir iste\u011fi yan\u0131tlamak yerine, a\u00e7\u0131k ba\u011flant\u0131 \u00fczerinden mesaj al\u0131\u015fveri\u015fini s\u00fcrd\u00fcr\u00fcr; ba\u011flant\u0131lar dakikalarca, hatta saatlerce a\u00e7\u0131k kalabilir. Bu da hosting taraf\u0131nda <strong>farkl\u0131 kaynak planlamas\u0131, farkl\u0131 g\u00fcvenlik kurallar\u0131 ve farkl\u0131 mimari kararlar\u0131<\/strong> gerektiriyor.<\/p>\n<p>Bu yaz\u0131da, \u00f6zellikle <strong>Node.js, Laravel Echo ve Socket.io kullanan WebSocket uygulamalar\u0131n\u0131<\/strong> <a href=\"https:\/\/www.dchost.com\/tr\/web-hosting\">payla\u015f\u0131ml\u0131 hosting<\/a> ve <a href=\"https:\/\/www.dchost.com\/tr\/vps\">VPS<\/a> se\u00e7enekleri a\u00e7\u0131s\u0131ndan kar\u015f\u0131la\u015ft\u0131raca\u011f\u0131z; harici servislerin veya dedicated altyap\u0131n\u0131n hangi ihtiya\u00e7larda de\u011ferlendirilebilece\u011fini de ele alaca\u011f\u0131z.<\/p>\n<p>\u00d6rnekler Laravel 13 \/ PHP 8.3+, Reverb 1.12 ve Echo 2.6 ile ba\u011f\u0131ms\u0131z Node.js 22 \/ Socket.IO 4 ak\u0131\u015flar\u0131n\u0131 kapsar. Laravel uygulamas\u0131 i\u00e7in \u00e7al\u0131\u015fan oturum a\u00e7ma sistemi, veritaban\u0131, Composer ve Vite derleme ortam\u0131 \u00f6n ko\u015fuldur. Kurulum komutlar\u0131 uygulaman\u0131n kendi dizininde \u00e7al\u0131\u015ft\u0131r\u0131l\u0131r; mevcut projenin ba\u011f\u0131ml\u0131l\u0131klar\u0131 ve migration de\u011fi\u015fiklikleri \u00f6nce staging ortam\u0131nda incelenir.<\/p>\n<p>E\u011fer kafan\u0131zda \u015fu sorular varsa, yaz\u0131n\u0131n sonuna geldi\u011finizde \u00e7ok daha net bir yol haritan\u0131z olacak:<\/p>\n<ul>\n<li>\u201cPayla\u015f\u0131ml\u0131 hostingte WebSocket \u00e7al\u0131\u015ft\u0131rabilir miyim, yoksa do\u011frudan VPS\u2019e mi ge\u00e7meliyim?\u201d<\/li>\n<li>\u201cLaravel Echo i\u00e7in kendi WebSocket sunucumu mu kurmal\u0131y\u0131m, Pusher\/benzeri servis mi kullanmal\u0131y\u0131m?\u201d<\/li>\n<li>\u201cNode.js + Socket.io sunucusu i\u00e7in ka\u00e7 vCPU, ka\u00e7 GB RAM ay\u0131rmal\u0131y\u0131m?\u201d<\/li>\n<li>\u201cNginx reverse proxy, Cloudflare, SSL ve WebSocket bir araya geldi\u011finde mimariyi nas\u0131l kurmal\u0131y\u0131m?\u201d<\/li>\n<\/ul>\n<h2><span id=\"WebSocket_ve_Gercek_Zamanli_Iletisim_HTTPden_Farki_Ne\">WebSocket ve Ger\u00e7ek Zamanl\u0131 \u0130leti\u015fim: HTTP\u2019den Fark\u0131 Ne?<\/span><\/h2>\n<p>Klasik HTTP request\u2013response modelinde taray\u0131c\u0131 istek g\u00f6nderir, sunucu yan\u0131tlar; alttaki ba\u011flant\u0131 sonraki istekler i\u00e7in a\u00e7\u0131k tutulabilir. WebSocket\u2019te ise:<\/p>\n<ul>\n<li>\u0130stemci, HTTP\/1.1 \u00fczerinden kurulan ba\u011flant\u0131da bir <strong>upgrade<\/strong> iste\u011fi g\u00f6nderir (Handshake).<\/li>\n<li>Sunucu kabul ederse ba\u011flant\u0131 WebSocket\u2019e y\u00fckseltilir.<\/li>\n<li>Bu ba\u011flant\u0131, taraflardan biri kapatana veya a\u011f kopana kadar <strong>a\u00e7\u0131k<\/strong> kalabilir.<\/li>\n<li>Sunucu ve istemci bu tek ba\u011flant\u0131 \u00fczerinden <strong>iki y\u00f6nl\u00fc mesaj al\u0131\u015fveri\u015fi<\/strong> yapmaya devam eder.<\/li>\n<\/ul>\n<p><strong>Socket.IO, ham WebSocket de\u011fildir:<\/strong> ba\u011flant\u0131, oda ve olay mesajlar\u0131 i\u00e7in kendi protokol\u00fcn\u00fc kullan\u0131r; sunucu ile <code>socket.io-client<\/code> e\u015fle\u015fir. Laravel Echo ise taray\u0131c\u0131 istemcisidir. A\u015fa\u011f\u0131daki Laravel \u00f6rne\u011finde Echo, <strong>Reverb sunucusunun Pusher protokol\u00fcne<\/strong> <code>pusher-js<\/code> \u00fczerinden ba\u011flan\u0131r. Ayr\u0131 Socket.IO \u00f6rne\u011fi bu ak\u0131\u015fa kendili\u011finden ba\u011flanmaz; Redis adresini payla\u015fmak da bir protokol k\u00f6pr\u00fcs\u00fc olu\u015fturmaz.<\/p>\n<p>Eski <code>laravel-echo-server<\/code> deposu ar\u015fivlenmi\u015ftir ve 1.6.3 paketi Socket.IO 2.x ba\u011f\u0131ml\u0131l\u0131\u011f\u0131 ta\u015f\u0131r. BeyondCode Laravel WebSockets de art\u0131k bak\u0131m almad\u0131\u011f\u0131n\u0131 belirtip Reverb \u00f6nerir. Bu ara\u00e7lar\u0131 Laravel 13 i\u00e7in yeni kurulum yolu olarak kullanmay\u0131n; mevcut eski y\u0131\u011f\u0131n i\u00e7in s\u00fcr\u00fcm ve ge\u00e7i\u015f uyumlulu\u011funu ayr\u0131ca inceleyin.<\/p>\n<p>Ancak kal\u0131c\u0131 ba\u011flant\u0131lar\u0131n \u015fu sonu\u00e7lar\u0131 var:<\/p>\n<ul>\n<li>Her a\u00e7\u0131k ba\u011flant\u0131 uygulamada durum, bellek ve dosya tan\u0131t\u0131c\u0131s\u0131; i\u015fletim sisteminde socket buffer gibi kaynaklar tutar.<\/li>\n<li>Ba\u011flant\u0131 say\u0131s\u0131 yan\u0131nda mesaj boyutu, s\u0131kl\u0131\u011f\u0131 ve bir mesaj\u0131n ka\u00e7 aboneye g\u00f6nderildi\u011fi kaynak ihtiyac\u0131n\u0131 belirler.<\/li>\n<li>Payla\u015f\u0131ml\u0131 hostingte uzun \u00f6m\u00fcrl\u00fc s\u00fcre\u00e7, proxy ve ba\u011flant\u0131 limitleri sa\u011flay\u0131c\u0131ya ve pakete g\u00f6re do\u011frulanmal\u0131d\u0131r.<\/li>\n<\/ul>\n<p>PHP uygulamas\u0131 ile ger\u00e7ek zamanl\u0131 ba\u011flant\u0131 katman\u0131 ayn\u0131 sunucuda olmak zorunda de\u011fildir. Karar\u0131 s\u00fcre\u00e7 izni, \u00f6l\u00e7\u00fclm\u00fc\u015f kapasite, operasyon sorumlulu\u011fu ve toplam maliyet \u00fczerinden verin.<\/p>\n<h2><span id=\"Paylasimli_Hosting_Uzerinde_WebSocket_Nodejs_ve_Laravel_Echo_Mumkun_mu\">Payla\u015f\u0131ml\u0131 Hosting \u00dczerinde WebSocket, Node.js ve Laravel Echo M\u00fcmk\u00fcn m\u00fc?<\/span><\/h2>\n<p>Payla\u015f\u0131ml\u0131 hostingte sistem y\u00f6netimi sa\u011flay\u0131c\u0131dad\u0131r. PHP deste\u011finin yan\u0131nda Node.js veya ba\u015fka uzun s\u00fcreli s\u00fcre\u00e7 deste\u011fi sunulabilir; panelin ad\u0131 tek ba\u015f\u0131na yeterli bilgi de\u011fildir. \u015eu s\u0131n\u0131rlar\u0131 kontrol edin:<\/p>\n<ul>\n<li>Kaynaklar (CPU, RAM, IO), sa\u011flay\u0131c\u0131n\u0131n kulland\u0131\u011f\u0131 altyap\u0131ya g\u00f6re <strong>CloudLinux veya benzeri mekanizmalarla<\/strong> s\u0131n\u0131rland\u0131r\u0131labilir.<\/li>\n<li><strong>S\u00fcrekli \u00e7al\u0131\u015fan Node.js s\u00fcre\u00e7lerinin<\/strong> desteklenip desteklenmedi\u011fi ve hangi ko\u015fullarda sonland\u0131r\u0131ld\u0131\u011f\u0131 plana g\u00f6re do\u011frulanmal\u0131d\u0131r.<\/li>\n<li>\u00d6zel port a\u00e7ma, firewall kural\u0131 de\u011fi\u015ftirme veya kernel ayar\u0131 yapma yetkisi genellikle verilmez.<\/li>\n<\/ul>\n<p>cPanel veya ba\u015fka bir panelde Node.js uygulamas\u0131 olu\u015fturabilmek, WebSocket ba\u011flant\u0131s\u0131n\u0131n proxy \u00fczerinden kesintisiz iletilece\u011fini garanti etmez. Sa\u011flay\u0131c\u0131dan s\u00fcre\u00e7 yeniden ba\u015flatma politikas\u0131n\u0131, WebSocket upgrade deste\u011fini, timeout ve kaynak limitlerini do\u011frulay\u0131n. Uygunluk de\u011ferlendirmesinde:<\/p>\n<ul>\n<li>MVP ve i\u00e7 ara\u00e7larda dahi oturum a\u00e7ma, ba\u011flant\u0131 kopmas\u0131 ve beklenen mesaj trafi\u011fini test edin.<\/li>\n<li>\u00dcretim i\u00e7in yaln\u0131z kullan\u0131c\u0131 say\u0131s\u0131n\u0131 de\u011fil, paket ko\u015fullar\u0131n\u0131 ve temsil\u00ee y\u00fck alt\u0131nda gecikme\/hata oran\u0131n\u0131 de\u011ferlendirin.<\/li>\n<\/ul>\n<h3><span id=\"Paylasimli_Hostingte_Laravel_Echo_Kullanimi\">Payla\u015f\u0131ml\u0131 Hostingte Laravel Echo Kullan\u0131m\u0131<\/span><\/h3>\n<p>Laravel projelerinde, ger\u00e7ek zamanl\u0131 bildirim i\u00e7in iki temel model var:<\/p>\n<ol>\n<li><strong>Y\u00f6netilen yay\u0131n servisi:<\/strong> Laravel desteklenen HTTP API\u2019siyle yay\u0131nlar, taray\u0131c\u0131 servisle uyumlu istemciyi kullan\u0131r.<\/li>\n<li><strong>Kendi sunucunuz:<\/strong> Laravel Reverb ile yay\u0131n, \u00f6zel kanal yetkilendirmesi ve Echo istemcisi ayn\u0131 desteklenen protokol\u00fc kullan\u0131r. Reverb PHP s\u00fcrecidir; Node.js ba\u011flant\u0131 sunucusu gerektirmez.<\/li>\n<\/ol>\n<p>\u0130kinci se\u00e7enek i\u00e7in paketin a\u015fa\u011f\u0131daki s\u00fcre\u00e7 ve ba\u011flant\u0131 gereksinimlerini kar\u015f\u0131lamas\u0131 gerekir:<\/p>\n<ul>\n<li>Reverb gibi se\u00e7ilen WebSocket sunucusu s\u00fcrekli \u00e7al\u0131\u015fmal\u0131d\u0131r; ba\u011f\u0131ms\u0131z Socket.IO se\u00e7erseniz bu bir Node.js s\u00fcrecidir.<\/li>\n<li><code>ShouldBroadcast<\/code> olaylar\u0131 kuyrukta i\u015flendi\u011fi i\u00e7in queue worker gerekir. Harici yay\u0131n servisi se\u00e7mek bu ihtiyac\u0131 kald\u0131rmaz.<\/li>\n<li>Redis zorunlu de\u011fildir; se\u00e7ilen queue\/cache veya yatay \u00f6l\u00e7eklendirme tasar\u0131m\u0131 kullan\u0131yorsa desteklenen, eri\u015filebilir bir Redis servisi gerekir.<\/li>\n<\/ul>\n<p>O y\u00fczden, payla\u015f\u0131ml\u0131 hostingte Laravel kullan\u0131yorsan\u0131z ve k\u00fc\u00e7\u00fck bir projeyseniz, <strong>harici WebSocket\/broadcast servisi<\/strong> daha mant\u0131kl\u0131 bir ba\u015flang\u0131\u00e7 olabilir. Ancak trafik ve maliyet artt\u0131k\u00e7a <a href=\"https:\/\/www.dchost.com\/blog\/laravel-ve-diger-php-frameworkler-icin-paylasimli-hosting-mi-vps-mi\/\">Laravel ve di\u011fer PHP framework\u2019ler i\u00e7in payla\u015f\u0131ml\u0131 hosting mi VPS mi<\/a> sorusunu yeniden de\u011ferlendirmek yararl\u0131 olabilir.<\/p>\n<h3><span id=\"Resource_Limit_Reached_Gercegi\">\u201cResource Limit Reached\u201d Ger\u00e7e\u011fi<\/span><\/h3>\n<p>Payla\u015f\u0131ml\u0131 hostingte WebSocket sunucusu aya\u011fa kald\u0131rabildi\u011finizi varsayal\u0131m. E\u015fzamanl\u0131 ba\u011flant\u0131lar ve mesaj trafi\u011fi plan\u0131n kaynak s\u0131n\u0131rlar\u0131n\u0131 a\u015ft\u0131\u011f\u0131nda:<\/p>\n<ul>\n<li>Kaynak s\u0131n\u0131rlama mekanizmas\u0131na g\u00f6re <strong>CPU kullan\u0131m\u0131 k\u0131s\u0131tlanabilir; bellek s\u0131n\u0131r\u0131nda i\u015flemler ba\u015far\u0131s\u0131z olabilir veya s\u00fcre\u00e7ler sonland\u0131r\u0131labilir<\/strong>.<\/li>\n<li>Panelde \u201cResource Limit Reached\u201d tarz\u0131 uyar\u0131lar g\u00f6rebilirsiniz.<\/li>\n<li>Sunucunuzun PHP taraf\u0131 da bundan etkilenip siteniz yava\u015flayabilir.<\/li>\n<\/ul>\n<p>Kaynak s\u0131n\u0131rlar\u0131n\u0131n etkilerini ayr\u0131nt\u0131l\u0131 incelemek i\u00e7in <a href=\"https:\/\/www.dchost.com\/blog\/resource-limit-reached-cozumu\/\">\u201cResource Limit Reached\u201d hatas\u0131n\u0131 \u00f6nleme rehberini<\/a> kullanabilirsiniz.<\/p>\n<p>\u00d6zetle: Kendi WebSocket sunucunuzu \u00e7al\u0131\u015ft\u0131rmak i\u00e7in payla\u015f\u0131ml\u0131 hostingin s\u00fcre\u00e7, proxy ve kaynak s\u0131n\u0131rlar\u0131 belirleyicidir. Bu s\u0131n\u0131rlar yetersizse <strong>VPS\u2019e ge\u00e7i\u015f<\/strong> veya <strong>harici bir ger\u00e7ek zamanl\u0131 ileti\u015fim servisi<\/strong> de\u011ferlendirilebilir; uygulaman\u0131n PHP taraf\u0131 uygun bir payla\u015f\u0131ml\u0131 hosting plan\u0131nda kalabilir.<\/p>\n<h2><span id=\"VPS_Uzerinde_WebSocket_Sunucusu_Kurmanin_Avantajlari\">VPS \u00dczerinde WebSocket Sunucusu Kurman\u0131n Avantajlar\u0131<\/span><\/h2>\n<p>VPS (Sanal \u00d6zel Sunucu), kendi ger\u00e7ek zamanl\u0131 uygulama altyap\u0131s\u0131n\u0131 y\u00f6netmek isteyenler i\u00e7in esnek bir se\u00e7enektir. Root eri\u015fimi bulunan ve ilgili ayarlara izin veren bir VPS\u2019te:<\/p>\n<ul>\n<li>Kendi <strong>Node.js, PHP, Redis, Nginx<\/strong> versiyonlar\u0131n\u0131z\u0131 se\u00e7ebilirsiniz.<\/li>\n<li><strong>Arka plan servisleri<\/strong> (systemd, PM2, Supervisor) \u00f6zg\u00fcrce kullanabilirsiniz.<\/li>\n<li>Firewall, kernel ayarlar\u0131, TCP parametreleri gibi <strong>d\u00fc\u015f\u00fck seviye ayarlara<\/strong> eri\u015fiminiz olur.<\/li>\n<li>Kaynak tahsisi ve kullan\u0131m s\u0131n\u0131rlar\u0131 VPS plan\u0131na ba\u011fl\u0131d\u0131r; <strong>vCPU say\u0131s\u0131 fiziksel CPU \u00e7ekirdeklerinin yaln\u0131z size ayr\u0131ld\u0131\u011f\u0131 anlam\u0131na gelmez<\/strong>.<\/li>\n<\/ul>\n<p>Bu konuyu \u00f6zellikle Node.js bak\u0131\u015f a\u00e7\u0131s\u0131ndan ele ald\u0131\u011f\u0131m\u0131z <a href=\"https:\/\/www.dchost.com\/blog\/node-js-uygulamalarini-nerede-host-etmeli-cpanel-paylasimli-hosting\/\">Node.js uygulamalar\u0131n\u0131 nerede host etmeli?<\/a> yaz\u0131s\u0131nda detayl\u0131 inceledik. WebSocket sunucusunu kendiniz y\u00f6netecekseniz, <strong>VPS s\u00fcre\u00e7 ve a\u011f ayarlar\u0131nda daha fazla kontrol sa\u011flayabilir<\/strong>.<\/p>\n<h3><span id=\"Kapasite_Planlama_Kac_WebSocket_Baglantisi_Tasiyabilirim\">Kapasite Planlama: Ka\u00e7 WebSocket Ba\u011flant\u0131s\u0131 Ta\u015f\u0131yabilirim?<\/span><\/h3>\n<p>G\u00fcvenilir bir ba\u011flant\u0131 say\u0131s\u0131 vermek i\u00e7in uygulaman\u0131n ger\u00e7ek kaynak t\u00fcketimini \u00f6l\u00e7mek gerekir:<\/p>\n<ul>\n<li>Bir WebSocket ba\u011flant\u0131s\u0131n\u0131n <strong>RAM t\u00fcketimi uygulamaya ve tutulan ba\u011flant\u0131 durumuna ba\u011fl\u0131d\u0131r<\/strong>; kapasite hesab\u0131nda kendi uygulaman\u0131zdan \u00f6l\u00e7\u00fclen de\u011fer kullan\u0131lmal\u0131d\u0131r.<\/li>\n<li>Mesaj i\u015fleme azald\u0131\u011f\u0131nda CPU ihtiyac\u0131 d\u00fc\u015febilir; heartbeat ve ba\u011flant\u0131 a\u00e7ma y\u00fck\u00fc s\u00fcrer. <strong>Bellek ve socket say\u0131s\u0131n\u0131<\/strong> CPU ile birlikte izleyin.<\/li>\n<li>\u00c7ok konu\u015fan (chat, oyun, canl\u0131 veri ak\u0131\u015f\u0131) odalarda CPU da ciddi devreye girer.<\/li>\n<\/ul>\n<p>Yaln\u0131zca bellek hesab\u0131n\u0131 g\u00f6stermek i\u00e7in, 2 GB RAM\u2019li bir VPS \u00fczerinde \u015fu varsay\u0131mlar\u0131 kullanal\u0131m:<\/p>\n<ul>\n<li>\u00d6rnekte i\u015fletim sistemi ve uygulamalara 0,8 GB ayr\u0131ld\u0131\u011f\u0131n\u0131, ba\u011flant\u0131lar i\u00e7in 1,2 GB kald\u0131\u011f\u0131n\u0131 varsayal\u0131m.<\/li>\n<li>Ba\u011flant\u0131 ba\u015f\u0131na 30 KB yaln\u0131z hesap varsay\u0131m\u0131 olsun; bu de\u011fer bir \u00fcr\u00fcn \u00f6l\u00e7\u00fcm\u00fc veya tipik t\u00fcketim de\u011fildir.<\/li>\n<\/ul>\n<p>Ondal\u0131k birimlerle 1,2 GB \u2248 1.200.000 KB; 1.200.000 \/ 30 \u2248 <strong>40.000<\/strong> \u00e7\u0131kar. Bu yaln\u0131zca varsay\u0131msal bellek b\u00f6l\u00fcm\u00fcd\u00fcr; sunucunun ta\u015f\u0131yabilece\u011fi ba\u011flant\u0131 say\u0131s\u0131 de\u011fildir.<\/p>\n<ul>\n<li>TCP buffer\u2019lar, kernel overhead, loglar, monitoring agent\u2019lar\u0131 vs. burada yok.<\/li>\n<li>CPU y\u00fck\u00fc, GC (garbage collector), ani trafik patlamalar\u0131 hesaba kat\u0131lm\u0131yor.<\/li>\n<\/ul>\n<p>Ayn\u0131 VPS\u2019te Laravel, veritaban\u0131, Redis veya ba\u015fka hizmetler varsa paylar\u0131n\u0131 ve ani y\u00fck pay\u0131n\u0131 ayr\u0131ca \u00f6l\u00e7\u00fcn. <strong>2 GB RAM tek ba\u015f\u0131na g\u00fcvenilir bir ba\u011flant\u0131 s\u0131n\u0131r\u0131 vermez.<\/strong> <a href=\"https:\/\/www.dchost.com\/blog\/k6-jmeter-locust-load-test\/\">k6, JMeter ve Locust ile y\u00fck testi<\/a> rehberindeki \u00f6l\u00e7\u00fcm yakla\u015f\u0131m\u0131n\u0131 kullanabilirsiniz; Socket.IO testinde ger\u00e7ek Socket.IO istemcisi veya s\u00fcr\u00fcm\u00fc do\u011frulanm\u0131\u015f protokol deste\u011fi gerekir.<\/p>\n<h3><span id=\"Guvenlik_Firewall_ve_Ag_Katmani\">G\u00fcvenlik, Firewall ve A\u011f Katman\u0131<\/span><\/h3>\n<p>VPS \u00fczerinde WebSocket sunucusu kurarken \u015fu ilkeleri benimseyin:<\/p>\n<ul>\n<li>Do\u011frudan 6001, 3000 vb. portlar\u0131 d\u0131\u015f d\u00fcnyaya a\u00e7mak yerine, <strong>Nginx reverse proxy<\/strong> \u00fczerinden web trafi\u011fini 80\/443 portlar\u0131nda kar\u015f\u0131lay\u0131n. Firewall de\u011fi\u015fikliklerinde gerekli y\u00f6netim eri\u015fimini de koruyun.<\/li>\n<li>WebSocket backend\u2019inizi <strong>127.0.0.1<\/strong> \u00fczerinde dinletin; d\u0131\u015f d\u00fcnyadan do\u011frudan eri\u015filemesin.<\/li>\n<li>Firewall (ufw, iptables, nftables vb.) ile gereksiz t\u00fcm portlar\u0131 kapat\u0131n.<\/li>\n<li>SSL\/TLS sonland\u0131rmas\u0131n\u0131 Nginx\u2019te yaparak, WebSocket ba\u011flant\u0131lar\u0131n\u0131 <strong>wss:\/\/<\/strong> \u00fczerinden g\u00fcvenli hale getirin.<\/li>\n<\/ul>\n<p>Nginx reverse proxy kurulumuna yabanc\u0131ysan\u0131z, ba\u015flang\u0131\u00e7 noktas\u0131 olarak <a href=\"https:\/\/www.dchost.com\/blog\/nginx-reverse-proxy-ve-basit-load-balancer-kurulumu\/\">Nginx reverse proxy ve basit load balancer rehberi<\/a>ni incelemeniz iyi olur. WebSocket \u00f6zelinde, <strong>upgrade<\/strong> ve <strong>connection<\/strong> ba\u015fl\u0131klar\u0131n\u0131 d\u00fczg\u00fcn iletmek kritik.<\/p>\n<p>Cloudflare kullan\u0131yorsan\u0131z WebSocket deste\u011fini, TLS ayarlar\u0131n\u0131 ve origin eri\u015fim politikas\u0131n\u0131 ayr\u0131ca do\u011frulay\u0131n. Cloudflare WAF ilk HTTP el s\u0131k\u0131\u015fmas\u0131n\u0131 denetler; sonraki WebSocket mesajlar\u0131n\u0131 taramaz. Mesaj yetkisi ve h\u0131z s\u0131n\u0131rlar\u0131 uygulamada kal\u0131r. A\u011f veya edge g\u00fcncellemeleri ba\u011flant\u0131lar\u0131 kesebilir; <a href=\"https:\/\/www.dchost.com\/blog\/cloudflare-ile-websocket-ve-grpc-yayini-nasil-hep-canli-kalir-nginx\/\">Cloudflare, WebSocket ve gRPC rehberi<\/a> ba\u011flant\u0131 katman\u0131n\u0131 ayr\u0131nt\u0131land\u0131r\u0131r.<\/p>\n<h2><span id=\"Laravel_Reverb_ve_Echo_Calisan_Yayin_Akisi\">Laravel Reverb ve Echo: \u00c7al\u0131\u015fan Yay\u0131n Ak\u0131\u015f\u0131<\/span><\/h2>\n<p>Bu \u00f6rnekte Laravel, Reverb ve queue worker ayn\u0131 VPS\u2019tedir. Taray\u0131c\u0131 <code>https:\/\/app.example.com<\/code> \u00fczerinde oturum a\u00e7ar; WebSocket ba\u011flant\u0131s\u0131 <code>ws.example.com<\/code> \u00fczerinden kurulur. Yay\u0131n yolu \u015f\u00f6yledir: yetkili HTTP iste\u011fi \u2192 database queue \u2192 worker \u2192 Reverb \u2192 yetkili Echo abonesi.<\/p>\n<ul>\n<li><strong>Laravel \/ PHP-FPM:<\/strong> oturum, CSRF, veri do\u011frulama ve \u00f6zel kanal yetkisini y\u00f6netir.<\/li>\n<li><strong>Database queue ve worker:<\/strong> yay\u0131n i\u015fini s\u0131raya al\u0131r ve Reverb\u2019e g\u00f6nderir; <code>jobs<\/code> tablosu ve worker \u00e7al\u0131\u015f\u0131r durumda olmal\u0131d\u0131r.<\/li>\n<li><strong>Reverb:<\/strong> <code>127.0.0.1:8080<\/code> \u00fczerinde dinleyen PHP WebSocket sunucusudur.<\/li>\n<li><strong>Nginx:<\/strong> taray\u0131c\u0131 TLS ba\u011flant\u0131s\u0131n\u0131 sonland\u0131r\u0131p Reverb\u2019e iletir. Echo\/Pusher istemcisi Socket.IO istemcisiyle de\u011fi\u015ftirilmez.<\/li>\n<\/ul>\n<h3><span id=\"1_Kurulum_Ortam_Degiskenleri_ve_Kanal_Yetkisi\">1) Kurulum, Ortam De\u011fi\u015fkenleri ve Kanal Yetkisi<\/span><\/h3>\n<p>Laravel 13 projenizde Reverb kurulumunu \u00e7al\u0131\u015ft\u0131r\u0131n. Kurulumun olu\u015fturdu\u011fu <code>REVERB_APP_ID<\/code>, <code>REVERB_APP_KEY<\/code> ve <code>REVERB_APP_SECRET<\/code> de\u011ferlerini koruyun; secret taray\u0131c\u0131ya gitmez. \u00d6rnek Reverb 1.12.0, Echo 2.6.3 ve Pusher JS 8.6.0 s\u00fcr\u00fcm k\u00fcmesini kullan\u0131r. <code>php artisan migrate<\/code> \u00f6ncesinde mevcut migration dosyalar\u0131n\u0131 inceleyin; database queue i\u00e7in <code>jobs<\/code> tablosunun bulundu\u011funu do\u011frulay\u0131n.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">php artisan install:broadcasting --reverb\ncomposer require laravel\/reverb:1.12.0\nnpm install --save-dev laravel-echo&#64;2.6.3 pusher-js&#64;8.6.0\nphp artisan migrate\nphp artisan channel:list\n<\/code><\/pre>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">BROADCAST_CONNECTION=reverb\nQUEUE_CONNECTION=database\nDB_QUEUE_RETRY_AFTER=90\n\nREVERB_SERVER_HOST=127.0.0.1\nREVERB_SERVER_PORT=8080\nREVERB_HOST=127.0.0.1\nREVERB_PORT=8080\nREVERB_SCHEME=http\n\nVITE_REVERB_APP_KEY=&quot;${REVERB_APP_KEY}&quot;\nVITE_REVERB_HOST=ws.example.com\nVITE_REVERB_PORT=443\nVITE_REVERB_SCHEME=https\n<\/code><\/pre>\n<p><code>REVERB_SERVER_HOST\/PORT<\/code> dinleme adresidir; <code>REVERB_HOST\/PORT\/SCHEME<\/code> Laravel\u2019in yay\u0131n hedefidir. Burada ikisi de loopback\u2019tir. <code>VITE_REVERB_*<\/code> ise taray\u0131c\u0131n\u0131n herkese a\u00e7\u0131k TLS adresidir. <code>config\/reverb.php<\/code> i\u00e7indeki ilgili uygulamada <code>allowed_origins<\/code> de\u011ferini <code>['app.example.com']<\/code> olarak daralt\u0131n; bu kanal yetkilendirmesinin yerine ge\u00e7mez. Kurulumun <code>routes\/channels.php<\/code> dosyas\u0131n\u0131 ve <code>\/broadcasting\/auth<\/code> rotas\u0131n\u0131 kaydetti\u011fini do\u011frulay\u0131n; gerekirse <code>bootstrap\/app.php<\/code> i\u00e7indeki <code>withRouting<\/code> \u00e7a\u011fr\u0131s\u0131na <code>channels: __DIR__.'\/..\/routes\/channels.php'<\/code> ekleyin.<\/p>\n<p>A\u015fa\u011f\u0131daki s\u0131n\u0131f yaln\u0131z al\u0131c\u0131ya ait kanala yay\u0131n yapar ve taray\u0131c\u0131ya yaln\u0131z <code>message<\/code> alan\u0131n\u0131 g\u00f6nderir. Public \u00f6zelliklerin tamam\u0131n\u0131 istemeden yay\u0131nlamamak i\u00e7in <code>broadcastWith<\/code> a\u00e7\u0131k\u00e7a tan\u0131ml\u0131d\u0131r.<\/p>\n<pre class=\"language-php line-numbers\"><code class=\"language-php\">&lt;?php\n\/\/ app\/Events\/NoticeCreated.php\nnamespace App\\Events;\n\nuse Illuminate\\Broadcasting\\PrivateChannel;\nuse Illuminate\\Contracts\\Broadcasting\\ShouldBroadcast;\n\nclass NoticeCreated implements ShouldBroadcast\n{\n    public function __construct(\n        public string $userId,\n        public string $message,\n    ) {}\n\n    public function broadcastOn(): array\n    {\n        return [new PrivateChannel(&#039;users.&#039;.$this-&gt;userId)];\n    }\n\n    public function broadcastAs(): string\n    {\n        return &#039;notice.created&#039;;\n    }\n\n    public function broadcastWith(): array\n    {\n        return [&#039;message&#039; =&gt; $this-&gt;message];\n    }\n}\n<\/code><\/pre>\n<pre class=\"language-php line-numbers\"><code class=\"language-php\">&lt;?php\n\/\/ routes\/channels.php: retain any other application channels.\nuse App\\Models\\User;\nuse Illuminate\\Support\\Facades\\Broadcast;\n\nBroadcast::channel(&#039;users.{userId}&#039;, function (User $user, string $userId) {\n    return (string) $user-&gt;getAuthIdentifier() === $userId;\n});\n<\/code><\/pre>\n<h3><span id=\"2_Yetkili_Yayin_Rotasi_ve_Echo_Abonesi\">2) Yetkili Yay\u0131n Rotas\u0131 ve Echo Abonesi<\/span><\/h3>\n<p>\u00c7al\u0131\u015fan Laravel oturum a\u00e7ma ak\u0131\u015f\u0131n\u0131z\u0131 kullan\u0131n. A\u015fa\u011f\u0131daki rotalar\u0131 <code>routes\/web.php<\/code> dosyas\u0131na mevcut importlar\u0131 yinelemeden ekleyin. Al\u0131c\u0131 kimli\u011fi istemciden al\u0131nmaz; oturumdaki kullan\u0131c\u0131dan t\u00fcretilir. <code>web<\/code> middleware CSRF kontrol\u00fcn\u00fc, <code>auth<\/code> oturumu, throttle ise yay\u0131n iste\u011fi h\u0131z\u0131n\u0131 s\u0131n\u0131rlar.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">\/\/ Add to routes\/web.php, below its existing PHP opening tag.\nuse App\\Events\\NoticeCreated;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Route;\n\nRoute::view(&#039;\/realtime-demo&#039;, &#039;realtime-demo&#039;)-&gt;middleware(&#039;auth&#039;);\n\nRoute::post(&#039;\/realtime-demo\/notice&#039;, function (Request $request) {\n    $data = $request-&gt;validate([&#039;message&#039; =&gt; [&#039;required&#039;, &#039;string&#039;, &#039;max:200&#039;]]);\n    event(new NoticeCreated(\n        (string) $request-&gt;user()-&gt;getAuthIdentifier(),\n        $data[&#039;message&#039;],\n    ));\n    return response()-&gt;json([&#039;queued&#039; =&gt; true], 202);\n})-&gt;middleware([&#039;auth&#039;, &#039;throttle:20,1&#039;]);\n<\/code><\/pre>\n<p><code>resources\/views\/realtime-demo.blade.php<\/code> dosyas\u0131n\u0131 ve JavaScript giri\u015fini olu\u015fturun. <code>vite.config.js<\/code> i\u00e7indeki Laravel eklentisinin <code>input<\/code> listesine <code>resources\/js\/realtime-demo.js<\/code> ekleyin; mevcut giri\u015fleri koruyun. Ayr\u0131 sayfa yaln\u0131z bu Echo \u00f6rne\u011fini ba\u015flat\u0131r.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">&lt;!-- resources\/views\/realtime-demo.blade.php --&gt;\n&lt;!doctype html&gt;\n&lt;html lang=&quot;en&quot;&gt;\n&lt;head&gt;\n    &lt;meta charset=&quot;utf-8&quot;&gt;\n    &lt;meta name=&quot;csrf-token&quot; content=&quot;{{ csrf_token() }}&quot;&gt;\n    &lt;meta name=&quot;user-id&quot; content=&quot;{{ auth()-&gt;id() }}&quot;&gt;\n    &lt;title&gt;Realtime demo&lt;\/title&gt;\n    @vite(&#039;resources\/js\/realtime-demo.js&#039;)\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;form id=&quot;notice-form&quot;&gt;\n        &lt;label&gt;Message &lt;input name=&quot;message&quot; maxlength=&quot;200&quot; required&gt;&lt;\/label&gt;\n        &lt;button id=&quot;send&quot; disabled&gt;Send&lt;\/button&gt;\n    &lt;\/form&gt;\n    &lt;p id=&quot;status&quot; role=&quot;status&quot;&gt;Connecting&lt;\/p&gt;\n    &lt;p id=&quot;notice&quot;&gt;&lt;\/p&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n<pre class=\"language-python line-numbers\"><code class=\"language-python\">\/\/ resources\/js\/realtime-demo.js\nimport Echo from &#039;laravel-echo&#039;;\nimport Pusher from &#039;pusher-js&#039;;\n\nwindow.Pusher = Pusher;\nconst csrf = document.querySelector(&#039;meta[name=&quot;csrf-token&quot;]&#039;).content;\nconst userId = document.querySelector(&#039;meta[name=&quot;user-id&quot;]&#039;).content;\nconst status = document.querySelector(&#039;#status&#039;);\nconst send = document.querySelector(&#039;#send&#039;);\nlet deliverySeen = false;\nconst echo = new Echo({\n    broadcaster: &#039;reverb&#039;,\n    key: import.meta.env.VITE_REVERB_APP_KEY,\n    wsHost: import.meta.env.VITE_REVERB_HOST,\n    wsPort: Number(import.meta.env.VITE_REVERB_PORT),\n    wssPort: Number(import.meta.env.VITE_REVERB_PORT),\n    forceTLS: import.meta.env.VITE_REVERB_SCHEME === &#039;https&#039;,\n    enabledTransports: [&#039;ws&#039;, &#039;wss&#039;],\n    authEndpoint: &#039;\/broadcasting\/auth&#039;,\n    auth: { headers: { &#039;X-CSRF-TOKEN&#039;: csrf } },\n});\n\necho.private(`users.${userId}`)\n    .subscribed(() =&gt; { send.disabled = false; status.textContent = &#039;Subscribed&#039;; })\n    .error(() =&gt; { send.disabled = true; status.textContent = &#039;Subscription failed&#039;; })\n    .listen(&#039;.notice.created&#039;, event =&gt; {\n        deliverySeen = true;\n        document.querySelector(&#039;#notice&#039;).textContent = event.message;\n        status.textContent = &#039;Event received&#039;;\n    });\n\necho.connector.pusher.connection.bind(&#039;state_change&#039;, ({ current }) =&gt; {\n    if (current !== &#039;connected&#039;) send.disabled = true;\n});\n\ndocument.querySelector(&#039;#notice-form&#039;).addEventListener(&#039;submit&#039;, async event =&gt; {\n    event.preventDefault();\n    deliverySeen = false;\n    status.textContent = &#039;Submitting&#039;;\n    try {\n        const response = await fetch(&#039;\/realtime-demo\/notice&#039;, {\n            method: &#039;POST&#039;,\n            credentials: &#039;same-origin&#039;,\n            headers: {\n                &#039;Content-Type&#039;: &#039;application\/json&#039;,\n                &#039;Accept&#039;: &#039;application\/json&#039;,\n                &#039;X-CSRF-TOKEN&#039;: csrf,\n            },\n            body: JSON.stringify({ message: event.target.elements.message.value }),\n        });\n        if (!response.ok) throw new Error(&#039;Request failed&#039;);\n        if (!deliverySeen) status.textContent = &#039;Queued; waiting for delivery&#039;;\n    } catch {\n        status.textContent = &#039;Request failed; check session or validation&#039;;\n    }\n});\n<\/code><\/pre>\n<p>\u00d6zel kanal <code>users.{userId}<\/code>, yaln\u0131z oturumdaki kullan\u0131c\u0131ya a\u00e7\u0131l\u0131r. \u00d6zel yay\u0131n ad\u0131 <code>notice.created<\/code> oldu\u011fu i\u00e7in Echo dinleyicisinde ba\u015ftaki nokta gereklidir: <code>.notice.created<\/code>. Sayfadaki Send d\u00fc\u011fmesi abonelik tamamlan\u0131nca a\u00e7\u0131l\u0131r. HTTP 202 yaln\u0131z s\u0131raya alma anlam\u0131na gelir; olay\u0131 g\u00f6rmek i\u00e7in worker ve Reverb de \u00e7al\u0131\u015fmal\u0131d\u0131r. \u00d6rnek anl\u0131k bildirimdir; teslim kayd\u0131 veya \u00e7evrimd\u0131\u015f\u0131 mesaj ge\u00e7mi\u015fi sa\u011flamaz.<\/p>\n<p>Laravel kanal yetkisi abonelik an\u0131nda de\u011ferlendirilir; a\u00e7\u0131k abonelikleri s\u00fcrekli yeniden denetlemez. Oturum veya hesap iptalinde ba\u011fl\u0131 kullan\u0131c\u0131y\u0131 ay\u0131racak uygulama mekanizmas\u0131n\u0131 ayr\u0131ca kurun.<\/p>\n<h3><span id=\"3_Nginx_ile_WebSocket_Reverse_Proxy\">3) Nginx ile WebSocket Reverse Proxy<\/span><\/h3>\n<p>Ge\u00e7erli TLS sertifikas\u0131 haz\u0131rlanm\u0131\u015f <code>ws.example.com<\/code> sanal hostu i\u00e7in a\u015fa\u011f\u0131daki yap\u0131land\u0131rma kullan\u0131labilir. <code>map<\/code> HTTP ba\u011flam\u0131ndad\u0131r. Reverb <code>\/app\/<\/code> yolu ile, sonraki ba\u011f\u0131ms\u0131z Socket.IO \u00f6rne\u011fi <code>\/socket.io\/<\/code> ile \u00e7al\u0131\u015f\u0131r; yaln\u0131z kulland\u0131\u011f\u0131n\u0131z location blo\u011funu etkinle\u015ftirebilirsiniz.<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\"># map belongs in the http context, outside server blocks.\nmap $http_upgrade $connection_upgrade {\n    default upgrade;\n    &#039;&#039; close;\n}\n\nserver {\n    listen 443 ssl;\n    server_name ws.example.com;\n    ssl_certificate     \/etc\/letsencrypt\/live\/ws.example.com\/fullchain.pem;\n    ssl_certificate_key \/etc\/letsencrypt\/live\/ws.example.com\/privkey.pem;\n\n    # Reverb browser subscriptions; Laravel publishes over loopback :8080.\n    location \/app\/ {\n        proxy_pass http:\/\/127.0.0.1:8080;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection $connection_upgrade;\n        proxy_set_header Host $host;\n        proxy_read_timeout 120s;\n        proxy_send_timeout 120s;\n    }\n\n    # Separate, optional Socket.IO example.\n    location \/socket.io\/ {\n        proxy_pass http:\/\/127.0.0.1:3000;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection $connection_upgrade;\n        proxy_set_header Host $host;\n        proxy_read_timeout 120s;\n        proxy_send_timeout 120s;\n    }\n\n    location \/ { return 404; }\n}\n<\/code><\/pre>\n<p>Burada <code>proxy_pass<\/code> sonunda URI bulunmad\u0131\u011f\u0131 i\u00e7in yol korunur. <code>proxy_read_timeout<\/code> toplam ba\u011flant\u0131 \u00f6mr\u00fc de\u011fildir; upstream\u2019den iki okuma aras\u0131ndaki sessizlik s\u00fcresini s\u0131n\u0131rlar. 120 saniye bu \u00f6rnekte Socket.IO\u2019nun varsay\u0131lan 25 saniye ping aral\u0131\u011f\u0131 + 20 saniye ping timeout toplam\u0131ndan uzundur; kendi heartbeat ayarlar\u0131n\u0131zla yeniden kontrol edin. Yap\u0131land\u0131rmay\u0131 \u00f6nce <code>nginx -t<\/code> ile do\u011frulay\u0131n. Reverb\u2019\u00fcn yay\u0131n API\u2019si <code>\/apps<\/code> yolundad\u0131r; burada Laravel do\u011frudan loopback\u2019e yay\u0131nlad\u0131\u011f\u0131 i\u00e7in bu yol internete a\u00e7\u0131lmaz. Laravel ayr\u0131 hosta ta\u015f\u0131n\u0131rsa yay\u0131n i\u00e7in eri\u015filebilir HTTPS <code>\/apps<\/code> yolu veya korumal\u0131 \u00f6zel a\u011f ba\u011flant\u0131s\u0131 ayr\u0131ca kurulmal\u0131d\u0131r.<\/p>\n<h3><span id=\"4_Reverb_Queue_Worker_ve_Nodejs_Surec_Yonetimi\">4) Reverb, Queue Worker ve Node.js S\u00fcre\u00e7 Y\u00f6netimi<\/span><\/h3>\n<p>\u0130lk do\u011frulamay\u0131 ayr\u0131 terminal s\u00fcre\u00e7leriyle yapabilirsiniz. <code>config:cache<\/code> sonras\u0131nda ortam de\u011fi\u015fiklikleri i\u00e7in cache\u2019i yeniden \u00fcretin ve uzun \u00f6m\u00fcrl\u00fc s\u00fcre\u00e7leri yeniden ba\u015flat\u0131n. Vite de\u011ferleri derleme an\u0131nda al\u0131n\u0131r; taray\u0131c\u0131 ayar\u0131n\u0131 de\u011fi\u015ftirince tekrar derleyin.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">php artisan config:cache\nnpm run build\nphp artisan reverb:start\n# In a separate process:\nphp artisan queue:work database --queue=default --sleep=1 --tries=3 --timeout=60\n<\/code><\/pre>\n<p><code>--timeout=60<\/code>, <code>DB_QUEUE_RETRY_AFTER=90<\/code> de\u011ferinden k\u00fc\u00e7\u00fckt\u00fcr. Worker timeout\u2019u i\u00e7in CLI PHP\u2019de PCNTL gerekir; d\u0131\u015f I\/O s\u00fcreleri 60 saniyelik i\u015f b\u00fct\u00e7esinden k\u0131sa olmal\u0131d\u0131r. \u0130\u015f uzunsa s\u00fcreleri birlikte yeniden hesaplay\u0131n. <code>--tries=3<\/code> ilk denemeyi i\u00e7erir. \u0130\u015f ger\u00e7ekten tamamlanmadan yaln\u0131z s\u00fcrecin a\u00e7\u0131k olmas\u0131 yay\u0131n sa\u011fl\u0131\u011f\u0131 say\u0131lmaz.<\/p>\n<ul>\n<li><strong>Supervisor veya systemd:<\/strong> Reverb ve queue worker i\u00e7in ayr\u0131 s\u00fcre\u00e7 tan\u0131mlar\u0131, uygulama kullan\u0131c\u0131s\u0131, do\u011fru PHP yolu, otomatik ba\u015flang\u0131\u00e7 ve log saklama ayarlay\u0131n. 60 saniyelik worker i\u00e7in \u00f6rne\u011fin 75 saniyelik durdurma pay\u0131 tan\u0131y\u0131n; mevcut uzun i\u015fler i\u00e7in b\u00fct\u00e7eyi yeniden hesaplay\u0131n.<\/li>\n<li><strong>Node.js:<\/strong> a\u015fa\u011f\u0131daki Socket.IO s\u00fcrecini systemd veya PM2\u2019den biri y\u00f6netsin. PM2\u2019de startup kayd\u0131 ve kaydedilmi\u015f s\u00fcre\u00e7 listesi gerekir; log rotasyonu ayr\u0131ca ayarlan\u0131r.<\/li>\n<li><strong>Da\u011f\u0131t\u0131m:<\/strong> Reverb yeniden ba\u015flat\u0131l\u0131nca ba\u011flant\u0131lar kapan\u0131r. \u0130stemci yeniden ba\u011flanmal\u0131 ve yetkisini tekrar do\u011frulatmal\u0131d\u0131r; reload komutu tek ba\u015f\u0131na kesintisiz ba\u011flant\u0131 garantisi de\u011fildir.<\/li>\n<\/ul>\n<p>VPS \u00fczerinde Node.js uygulamalar\u0131n\u0131 canl\u0131ya al\u0131rken PM2\/systemd + Nginx + SSL kombinasyonunu nas\u0131l kuraca\u011f\u0131n\u0131z\u0131, ad\u0131m ad\u0131m <a href=\"https:\/\/www.dchost.com\/blog\/node-jsi-canliya-alirken-panik-yapma-pm2-systemd-nginx-ssl-ve-sifir\/\">Node.js\u2019i canl\u0131ya alma rehberi<\/a>nde detayland\u0131rd\u0131k. WebSocket sunucular\u0131 i\u00e7in de ayn\u0131 prensipler ge\u00e7erli.<\/p>\n<h2><span id=\"Bagimsiz_Nodejs_ve_SocketIO_Yetkili_Oda_Ornegi\">Ba\u011f\u0131ms\u0131z Node.js ve Socket.IO: Yetkili Oda \u00d6rne\u011fi<\/span><\/h2>\n<p>Bu ikinci \u00f6rnek <strong>Node.js 22.23.4, Socket.IO 4.8.4 ve jose 6.2.15<\/strong> kullan\u0131r. Laravel\/Reverb ile ba\u011flant\u0131 kurmaz. Ama\u00e7, tek s\u00fcre\u00e7te \u00e7al\u0131\u015fan k\u00fc\u00e7\u00fck bir test uygulamas\u0131nda JWT do\u011frulamas\u0131, sunucu taraf\u0131 oda yetkisi, olay yay\u0131n\u0131 ve token s\u00fcresini g\u00f6stermektir. Alice yaln\u0131z <code>room:red<\/code>, Bob yaln\u0131z <code>room:blue<\/code> odas\u0131na eri\u015fir.<\/p>\n<p>Yeni bir test dizininde a\u015fa\u011f\u0131daki paketleri kurun. <code>key.mjs<\/code>, <code>token.mjs<\/code> ve <code>server.mjs<\/code> dosyalar\u0131n\u0131 sonraki \u00f6rneklerden olu\u015fturduktan sonra son \u00fc\u00e7 sat\u0131r\u0131 ayn\u0131 g\u00fcvenilir terminalde \u00e7al\u0131\u015ft\u0131r\u0131n. \u00dcretilen anahtar yaln\u0131z sunucu taraf\u0131ndad\u0131r; token be\u015f dakika ge\u00e7erlidir. \u00dcretimde demo token komutunu ve sabit ACL\u2019yi ger\u00e7ek kimlik sa\u011flay\u0131c\u0131n\u0131z\u0131n do\u011frulamas\u0131 ve g\u00fcncel izin kay\u0131tlar\u0131yla de\u011fi\u015ftirin.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">npm init -y\nnpm install --save-exact socket.io&#64;4.8.4 socket.io-client&#64;4.8.4 jose&#64;6.2.15\nexport DEMO_JWT_KEY_HEX=&quot;$(openssl rand -hex 32)&quot;\nnode token.mjs alice\nnode server.mjs\n<\/code><\/pre>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">\/\/ key.mjs: server-side only.\nconst hex = process.env.DEMO_JWT_KEY_HEX ?? &#039;&#039;;\nif (!\/^[a-f0-9]{64}$\/i.test(hex)) throw new Error(&#039;Set a 32-byte demo key&#039;);\nexport const key = Buffer.from(hex, &#039;hex&#039;);\n<\/code><\/pre>\n<pre class=\"language-python line-numbers\"><code class=\"language-python\">\/\/ token.mjs: run only in the trusted demo server terminal.\nimport { SignJWT } from &#039;jose&#039;;\nimport { key } from &#039;.\/key.mjs&#039;;\nconst user = process.argv[2];\nif (![&#039;alice&#039;, &#039;bob&#039;].includes(user)) throw new Error(&#039;Use alice or bob&#039;);\nconsole.log(await new SignJWT({})\n    .setProtectedHeader({ alg: &#039;HS256&#039; })\n    .setIssuer(&#039;realtime-demo&#039;).setAudience(&#039;realtime-demo&#039;)\n    .setSubject(user).setIssuedAt().setExpirationTime(&#039;5m&#039;)\n    .sign(key));\n<\/code><\/pre>\n<p>Sunucu, token\u2019\u0131n imzas\u0131 yan\u0131nda issuer, audience, algoritma ve s\u00fcresini denetler. Odaya kat\u0131lma ve yay\u0131nlama ayr\u0131 ayr\u0131 yetkilendirilir. Origin filtresi taray\u0131c\u0131 kaynaklar\u0131n\u0131 s\u0131n\u0131rlar; JWT ve ACL\u2019nin yerine ge\u00e7mez. CORS tek ba\u015f\u0131na WebSocket eri\u015fim kontrol\u00fc de\u011fildir.<\/p>\n<pre class=\"language-python line-numbers\"><code class=\"language-python\">\/\/ server.mjs\nimport { createServer } from &#039;node:http&#039;;\nimport { Server } from &#039;socket.io&#039;;\nimport { jwtVerify } from &#039;jose&#039;;\nimport { key } from &#039;.\/key.mjs&#039;;\n\nconst origin = &#039;https:\/\/app.example.com&#039;;\nconst acl = new Map([\n    [&#039;alice&#039;, new Set([&#039;room:red&#039;])],\n    [&#039;bob&#039;, new Set([&#039;room:blue&#039;])],\n]);\nconst http = createServer((request, response) =&gt; {\n    response.writeHead(request.url === &#039;\/health&#039; ? 200 : 404);\n    response.end(request.url === &#039;\/health&#039; ? &#039;ok&#039; : &#039;not found&#039;);\n});\nconst io = new Server(http, {\n    cors: { origin, methods: [&#039;GET&#039;, &#039;POST&#039;] },\n    allowRequest: (request, done) =&gt; done(null, request.headers.origin === origin),\n    maxHttpBufferSize: 16_384,\n});\n\nio.use(async (socket, next) =&gt; {\n    try {\n        const { payload } = await jwtVerify(socket.handshake.auth.token, key, {\n            algorithms: [&#039;HS256&#039;], issuer: &#039;realtime-demo&#039;, audience: &#039;realtime-demo&#039;,\n            requiredClaims: [&#039;sub&#039;, &#039;iat&#039;, &#039;exp&#039;], maxTokenAge: &#039;5m&#039;,\n        });\n        if (!acl.has(payload.sub) || payload.exp - payload.iat &gt; 300) {\n            throw new Error(&#039;Invalid identity or lifetime&#039;);\n        }\n        socket.data.user = payload.sub;\n        socket.data.expires = payload.exp * 1000;\n        next();\n    } catch {\n        next(new Error(&#039;Unauthorized&#039;));\n    }\n});\n\nio.on(&#039;connection&#039;, socket =&gt; {\n    const timer = setTimeout(() =&gt; socket.disconnect(true),\n        Math.max(0, socket.data.expires - Date.now()));\n    socket.on(&#039;disconnect&#039;, () =&gt; clearTimeout(timer));\n    let windowStart = Date.now(), count = 0;\n    socket.use((packet, next) =&gt; {\n        if (Date.now() &gt;= socket.data.expires) return socket.disconnect(true);\n        if (Date.now() - windowStart &gt;= 10_000) { windowStart = Date.now(); count = 0; }\n        if (++count &gt; 20) return socket.disconnect(true);\n        next();\n    });\n    socket.on(&#039;join&#039;, async (room, callback) =&gt; {\n        const reply = typeof callback === &#039;function&#039; ? callback : () =&gt; {};\n        if (!acl.get(socket.data.user)?.has(room)) return reply({ ok: false });\n        await socket.join(room);\n        reply({ ok: true });\n    });\n    socket.on(&#039;publish&#039;, (data, callback) =&gt; {\n        const reply = typeof callback === &#039;function&#039; ? callback : () =&gt; {};\n        if (!data || !acl.get(socket.data.user)?.has(data.room)\n            || !socket.rooms.has(data.room) || typeof data.text !== &#039;string&#039;\n            || !data.text.trim() || data.text.length &gt; 200) return reply({ ok: false });\n        io.to(data.room).emit(&#039;notice&#039;, { text: data.text, sender: socket.data.user });\n        reply({ ok: true });\n    });\n});\n\nhttp.listen(3000, &#039;127.0.0.1&#039;);\nfor (const signal of [&#039;SIGINT&#039;, &#039;SIGTERM&#039;]) {\n    process.once(signal, () =&gt; io.close(() =&gt; process.exit(0)));\n}\n<\/code><\/pre>\n<p>\u0130stemciyi <code>https:\/\/app.example.com<\/code> sayfas\u0131ndaki JavaScript paketine ekleyin; terminalde \u00fcretilen k\u0131sa s\u00fcreli Alice token\u2019\u0131n\u0131 test penceresine yap\u0131\u015ft\u0131r\u0131n. Token sorgu URL\u2019sine konulmaz. Bu demo ba\u011flan\u0131nca odaya kat\u0131l\u0131r ve Hello mesaj\u0131 yay\u0131nlar; a\u011fdan tekrar ba\u011flan\u0131nca ayn\u0131 i\u015flemi yineleyece\u011fi i\u00e7in i\u015f sonucunu temsil eden m\u00fckerrer i\u015flemler i\u00e7in uygun de\u011fildir.<\/p>\n<pre class=\"language-python line-numbers\"><code class=\"language-python\">\/\/ Bundle into an HTTPS page at https:\/\/app.example.com.\nimport { io } from &#039;socket.io-client&#039;;\n\nconst token = window.prompt(&#039;Paste the short-lived alice demo token&#039;);\nconst socket = io(&#039;https:\/\/ws.example.com&#039;, { auth: { token }, autoConnect: false });\nsocket.on(&#039;notice&#039;, event =&gt; { console.log(&#039;Notice:&#039;, event.text); });\nsocket.on(&#039;connect_error&#039;, () =&gt; { console.log(&#039;Connection or authorization failed&#039;); });\nsocket.on(&#039;disconnect&#039;, reason =&gt; {\n    if (reason === &#039;io server disconnect&#039;) console.log(&#039;Obtain a fresh token before reconnecting&#039;);\n});\nsocket.on(&#039;connect&#039;, () =&gt; {\n    socket.timeout(5000).emit(&#039;join&#039;, &#039;room:red&#039;, (error, joined) =&gt; {\n        if (error || !joined?.ok) return console.log(&#039;Join failed&#039;);\n        socket.timeout(5000).emit(&#039;publish&#039;, { room: &#039;room:red&#039;, text: &#039;Hello&#039; },\n            (error, result) =&gt; console.log(error || !result?.ok ? &#039;Publish failed&#039; : &#039;Accepted&#039;));\n    });\n});\nsocket.connect();\n<\/code><\/pre>\n<p>20 olay \/ 10 saniye s\u0131n\u0131r\u0131 yaln\u0131z bu ba\u011flant\u0131 i\u00e7indir; yeniden ba\u011flanma bunu s\u0131f\u0131rlar. \u00dcretimde kullan\u0131c\u0131 ve IP bazl\u0131 ba\u011flant\u0131 s\u0131n\u0131rlar\u0131, ortak h\u0131z limiti, g\u00fcncel izin\/iptal denetimi ve gerekti\u011finde ba\u011fl\u0131 kullan\u0131c\u0131lar\u0131 ay\u0131rma mekanizmas\u0131 ekleyin. Token s\u00fcresi dolunca sunucu ba\u011flant\u0131y\u0131 keser; yeni token edinmeden zorla tekrar ba\u011flanmay\u0131n. ACK, uygulaman\u0131n kabul\u00fcn\u00fc bildirir; kal\u0131c\u0131 kay\u0131t veya t\u00fcm al\u0131c\u0131lar\u0131n teslim ald\u0131\u011f\u0131n\u0131 kan\u0131tlamaz.<\/p>\n<p>Tek VPS\u2019te Node.js uygulamalar\u0131n\u0131 nas\u0131l konumland\u0131rabilece\u011finizi, Nginx ile nas\u0131l \u00f6ne \u00e7\u0131karaca\u011f\u0131n\u0131z\u0131 ve SSL\u2019i nas\u0131l y\u00f6netece\u011finizi anlamak i\u00e7in, mutlaka <a href=\"https:\/\/www.dchost.com\/blog\/node-js-uygulamalarini-nerede-host-etmeli-cpanel-paylasimli-hosting\/\">Node.js hosting kar\u015f\u0131la\u015ft\u0131rmas\u0131<\/a> yaz\u0131s\u0131n\u0131 da arka planda okuman\u0131z\u0131 \u00f6neririm.<\/p>\n<p>\u00d6rne\u011fin systemd 252 i\u00e7in <code>\/etc\/systemd\/system\/realtime-demo.service<\/code> tan\u0131m\u0131:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">[Unit]\nDescription=Socket.IO demo\nAfter=network.target\nStartLimitIntervalSec=60\nStartLimitBurst=5\n\n[Service]\nType=simple\nUser=realtime\nWorkingDirectory=\/srv\/realtime\nEnvironmentFile=\/etc\/realtime-demo.env\nExecStart=\/opt\/node22\/bin\/node \/srv\/realtime\/server.mjs\nRestart=always\nRestartSec=5\nTimeoutStopSec=30\nStandardOutput=journal\nStandardError=journal\n\n[Install]\nWantedBy=multi-user.target\n<\/code><\/pre>\n<p>\u00d6nce <code>realtime<\/code> kullan\u0131c\u0131s\u0131n\u0131, <code>\/srv\/realtime<\/code> uygulama dizinini ve ger\u00e7ek Node 22 binary yolunu haz\u0131rlay\u0131n. <code>\/etc\/realtime-demo.env<\/code> dosyas\u0131 yaln\u0131z sunucu y\u00f6neticisinin okuyabildi\u011fi izinlerle <code>DEMO_JWT_KEY_HEX=&lt;64-hex-character-key&gt;<\/code> i\u00e7ermelidir; shell komutu yaz\u0131lmaz. Anahtar demo token\u2019lar\u0131n\u0131 \u00fcreten anahtarla ayn\u0131 olmal\u0131d\u0131r. Unit dosyas\u0131n\u0131 <code>systemd-analyze verify<\/code> ile kontrol edip ard\u0131ndan yetkili y\u00f6netici hesab\u0131yla daemon-reload ve enable &#8211;now uygulay\u0131n. Restart s\u0131n\u0131r\u0131 devreye girdi\u011finde alarm gereklidir; journal i\u00e7in saklama s\u0131n\u0131r\u0131 belirleyin.<\/p>\n<h2><span id=\"Paylasimli_Hostingten_VPSe_WebSocket_Uygulamasini_Tasimak\">Payla\u015f\u0131ml\u0131 Hosting\u2019ten VPS\u2019e WebSocket Uygulamas\u0131n\u0131 Ta\u015f\u0131mak<\/span><\/h2>\n<p>\u00d6rnek bir ge\u00e7i\u015f senaryosunda ilk s\u00fcr\u00fcm payla\u015f\u0131ml\u0131 hosting + harici broadcast servisiyle yay\u0131na al\u0131nabilir. Kullan\u0131m b\u00fcy\u00fcd\u00fc\u011f\u00fcnde maliyet veya performans gereksinimleri de\u011fi\u015firse ekip <strong>VPS\u2019e ge\u00e7i\u015f<\/strong> se\u00e7ene\u011fini de\u011ferlendirebilir; bu sorunlar her projede ka\u00e7\u0131n\u0131lmaz de\u011fildir.<\/p>\n<p>Bu ge\u00e7i\u015fi daha sakin yapmak i\u00e7in \u015fu ad\u0131mlar\u0131 takip edebilirsiniz:<\/p>\n<h3><span id=\"1_DNS_ve_Alan_Adi_Plani\">1) DNS ve Alan Ad\u0131 Plan\u0131<\/span><\/h3>\n<ul>\n<li>Laravel\/PHP siteniz h\u00e2l\u00e2 payla\u015f\u0131ml\u0131 hostingte kalacaksa, <strong>WebSocket subdomain\u2019i<\/strong>ni (\u00f6rn. <code>ws.example.com<\/code>) yeni VPS\u2019e y\u00f6nlendirin. DNS de\u011fi\u015fikli\u011fi tek ba\u015f\u0131na yeterli de\u011fildir: Laravel ile VPS aras\u0131ndaki olay aktar\u0131m\u0131n\u0131 ve yetkilendirme eri\u015fimini de planlay\u0131n. \u00d6nceki tek sunuculu \u00f6rne\u011fin yerel ba\u011flant\u0131 varsay\u0131mlar\u0131 bu ayr\u0131k kurulum i\u00e7in yeterli de\u011fildir.<\/li>\n<li>Tam ge\u00e7i\u015f yapacaksan\u0131z, <code>example.com<\/code>, <code>api.example.com<\/code> ve <code>ws.example.com<\/code> gibi t\u00fcm kritik kay\u0131tlar\u0131 yeni sunucuya planl\u0131 olarak ta\u015f\u0131y\u0131n.<\/li>\n<li>DNS ge\u00e7i\u015flerinde kesintiyi en aza indirmek i\u00e7in, <a href=\"https:\/\/www.dchost.com\/blog\/sunucu-tasima-dns-ttl-planlamasi\/\">TTL stratejileriyle zero-downtime ta\u015f\u0131ma<\/a> rehberindeki \u00f6nerileri uygulay\u0131n.<\/li>\n<\/ul>\n<h3><span id=\"2_Uygulama_ve_Konfigurasyon_Tasima\">2) Uygulama ve Konfig\u00fcrasyon Ta\u015f\u0131ma<\/span><\/h3>\n<ul>\n<li>Laravel ve gerekiyorsa ayr\u0131 Socket.IO uygulamas\u0131n\u0131, kilit dosyalar\u0131 ve hedef runtime s\u00fcr\u00fcmleriyle birlikte aktar\u0131n.<\/li>\n<li>Veritaban\u0131, queue, cache ve yay\u0131n ba\u011flant\u0131s\u0131n\u0131 ayr\u0131 ayr\u0131 yap\u0131land\u0131r\u0131n; Vite adreslerini yeniden derleyin.<\/li>\n<li>\u0130ki hosta ayr\u0131l\u0131yorsa loopback adresi di\u011fer makineyi g\u00f6stermez. Laravel\u2192Reverb yay\u0131n ba\u011flant\u0131s\u0131 i\u00e7in HTTPS veya korumal\u0131 \u00f6zel a\u011f; taray\u0131c\u0131\u2192Laravel yetkilendirmesi i\u00e7in do\u011fru oturum\/origin d\u00fczeni kurun.<\/li>\n<li>Reverb, queue worker ve varsa Node s\u00fcrecini ayr\u0131 y\u00f6netip Nginx\/TLS yolunu do\u011frulay\u0131n.<\/li>\n<\/ul>\n<p>Payla\u015f\u0131ml\u0131 hostingten VPS\u2019e ge\u00e7i\u015fi genel anlamda nas\u0131l planlaman\u0131z gerekti\u011fini, sadece WebSocket de\u011fil t\u00fcm bile\u015fenler i\u00e7in <a href=\"https:\/\/www.dchost.com\/blog\/paylasimli-hostingden-vpse-gecis\/\">payla\u015f\u0131ml\u0131 hosting\u2019den VPS\u2019e ge\u00e7i\u015f rehberi<\/a>nde detayl\u0131 anlatt\u0131k.<\/p>\n<h3><span id=\"3_Test_Load_Test_ve_Asamali_Gecis\">3) Test, Load Test ve A\u015famal\u0131 Ge\u00e7i\u015f<\/span><\/h3>\n<ul>\n<li>\u00d6nce staging\u2019de oturum a\u00e7ma, izinli\/izinsiz kanal, izinli\/izinsiz yay\u0131n, ge\u00e7ersiz\/s\u00fcresi dolan token ve ger\u00e7ek olay teslimini s\u0131nay\u0131n.<\/li>\n<li>Laravel i\u00e7in Echo\/Pusher protokol\u00fcyle, Socket.IO i\u00e7in <code>socket.io-client<\/code> ile ba\u011flan\u0131n. Ham WebSocket a\u00e7\u0131lmas\u0131; Engine.IO\/Socket.IO handshake, oda aboneli\u011fi veya Laravel kanal yetkisini do\u011frulamaz.<\/li>\n<li>Ard\u0131ndan temsil\u00ee mesaj boyutu, fan-out, ba\u011flant\u0131 a\u00e7ma\/kapama, yeniden ba\u011flanma dalgas\u0131 ve worker gecikmesiyle y\u00fck testi yap\u0131n. Az istemcili i\u015flev testleri kapasite \u00f6l\u00e7\u00fcm\u00fc de\u011fildir.<\/li>\n<li>DNS \u00f6ncesinde TTL\u2019yi d\u00fc\u015f\u00fcr\u00fcp eski TTL s\u00fcresini bekleyin. TTL trafik y\u00fczdesi b\u00f6l\u00fc\u015ft\u00fcrmez ve a\u00e7\u0131k ba\u011flant\u0131lar\u0131 ta\u015f\u0131maz; a\u015famal\u0131 da\u011f\u0131t\u0131m i\u00e7in y\u00fck dengeleyici veya a\u011f\u0131rl\u0131kl\u0131 DNS gerekir. DNS \u00f6nbelle\u011fi nedeniyle tam kullan\u0131c\u0131 y\u00fczdesi beklemeyin; eski u\u00e7ta kalan ba\u011flant\u0131lar ve geri d\u00f6n\u00fc\u015f plan\u0131 ayr\u0131ca y\u00f6netilir.<\/li>\n<\/ul>\n<h2><span id=\"Operasyonel_Ipuclari_Loglama_Izleme_Yedekleme\">Operasyonel \u0130pu\u00e7lar\u0131: Loglama, \u0130zleme, Yedekleme<\/span><\/h2>\n<p>Hatal\u0131 bir yay\u0131n veya yeniden ba\u011flanma dalgas\u0131 \u00e7ok say\u0131da aboneyi etkileyebilir. G\u00f6zlem ve kurtarma yollar\u0131n\u0131 ba\u011flant\u0131 katman\u0131yla birlikte tasarlay\u0131n.<\/p>\n<h3><span id=\"Loglama_ve_Gozlemlenebilirlik\">Loglama ve G\u00f6zlemlenebilirlik<\/span><\/h3>\n<ul>\n<li>Laravel, Reverb, Node.js ve Nginx loglar\u0131nda istek\/olay korelasyonu, yetki retleri ve hata t\u00fcrlerini izleyin; token, session secret veya \u00f6zel mesaj g\u00f6vdelerini loglamay\u0131n.<\/li>\n<li>Loglar\u0131 merkezi ELK veya Loki gibi bir sistemde, eri\u015fim ve saklama s\u0131n\u0131rlar\u0131yla toplayabilirsiniz.<\/li>\n<li><a href=\"https:\/\/www.dchost.com\/blog\/vps-loki-etiket-saklama-alarm\/\">VPS merkezi log y\u00f6netimi rehberi<\/a> mimari i\u00e7in yararl\u0131d\u0131r. Promtail 2 Mart 2026\u2019da destek \u00f6mr\u00fcn\u00fc tamamlad\u0131; yeni kurulumda desteklenen bir collector, \u00f6rne\u011fin Grafana Alloy kullan\u0131n.<\/li>\n<\/ul>\n<h3><span id=\"Kaynak_Izleme_ve_Alarm\">Kaynak \u0130zleme ve Alarm<\/span><\/h3>\n<p>WebSocket ba\u011flant\u0131lar\u0131 artt\u0131k\u00e7a, CPU, RAM, disk IO ve a\u011f trafi\u011fini yak\u0131ndan izlemeniz gerekir. \u00d6zellikle:<\/p>\n<ul>\n<li>Reverb\/Node bellek t\u00fcketimi, CPU ve event-loop gecikmesi; PHP-FPM ve queue worker bask\u0131s\u0131.<\/li>\n<li>A\u00e7\u0131k ba\u011flant\u0131\/dosya tan\u0131t\u0131c\u0131s\u0131, ba\u011flant\u0131 a\u00e7ma h\u0131z\u0131, TCP durumlar\u0131 ve proxy timeout\u2019lar\u0131.<\/li>\n<li>Yay\u0131n kuyru\u011fu ya\u015f\u0131, teslim gecikmesi, hata\/yeniden deneme oran\u0131 ve yeniden ba\u011flanma dalgalar\u0131.<\/li>\n<li>Bir <code>\/health<\/code> HTTP yan\u0131t\u0131na ek olarak yetkili abonelik ve olay teslimini do\u011frulayan temsil\u00ee kontrol.<\/li>\n<\/ul>\n<p>Bu metrikleri toplamak ve dashboard\u2019lar olu\u015fturmak i\u00e7in, <a href=\"https:\/\/www.dchost.com\/blog\/vps-izleme-prometheus-grafana-uptime-kuma\/\">Prometheus + Grafana ile VPS izleme<\/a> rehberindeki yap\u0131y\u0131 WebSocket sunucunuza da uygulayabilirsiniz.<\/p>\n<h3><span id=\"Yedekleme_Stratejisi\">Yedekleme Stratejisi<\/span><\/h3>\n<p>A\u00e7\u0131k ba\u011flant\u0131lar, oda \u00fcyelikleri ve bekleyen mesajlar bellekte durum tutar; sunucu yeniden ba\u015flay\u0131nca bunlar korunmu\u015f say\u0131lmaz. Kal\u0131c\u0131 i\u015f verisini ba\u011flant\u0131 s\u00fcrecinden ay\u0131r\u0131n:<\/p>\n<ul>\n<li>Uygulama kodu, kilit dosyalar\u0131 ve g\u00fcvenli bi\u00e7imde korunan yap\u0131land\u0131rma\/anahtarlar.<\/li>\n<li>Veritaban\u0131, gerekli olay ge\u00e7mi\u015fi, son i\u015flenen olay kimli\u011fi ve yeniden senkronizasyon yolu.<\/li>\n<li>Redis kullan\u0131l\u0131yorsa queue ve session verileri i\u00e7in kay\u0131p tolerans\u0131, persistence ve eviction politikas\u0131; cache ile ayn\u0131 dayan\u0131kl\u0131l\u0131k varsay\u0131m\u0131 yap\u0131lmaz.<\/li>\n<li>Socket.IO\u2019nun varsay\u0131lan teslimi en fazla bir kezdir; ba\u011flant\u0131 kopukken ka\u00e7an sunucu olaylar\u0131 kendili\u011finden tekrar oynat\u0131lmaz. Kay\u0131p kabul edilmiyorsa kal\u0131c\u0131 ge\u00e7mi\u015f, offset ve idempotency tasarlay\u0131n.<\/li>\n<\/ul>\n<p>Uygun bir 3-2-1 yedekleme modeli kurmak i\u00e7in, <a href=\"https:\/\/www.dchost.com\/blog\/3-2-1-yedekleme-cpanel-plesk-vps\/\">3-2-1 yedekleme stratejisi rehberi<\/a>ndeki prensipleri VPS\u2019iniz i\u00e7in de uygulayabilirsiniz. Yedekleri VPS\u2019in diskinde tutmak yerine, Object Storage gibi harici ortamlara periyodik olarak aktarmak daha g\u00fcvenlidir.<\/p>\n<p>Yatay \u00f6l\u00e7eklemede Reverb\u2019\u00fcn Redis scaling deste\u011fi veya Socket.IO\u2019nun uygun adapter\u2019\u0131 s\u00fcre\u00e7ler aras\u0131nda olay da\u011f\u0131t\u0131r. Bunlar birbirinin protokol k\u00f6pr\u00fcs\u00fc de\u011fildir. Socket.IO\u2019da HTTP long-polling a\u00e7\u0131ksa \u00e7oklu node i\u00e7in oturum yap\u0131\u015fkanl\u0131\u011f\u0131 da gerekir; Redis adapter bunu kald\u0131rmaz ve kal\u0131c\u0131 replay sa\u011flamaz. Redis\u2019i \u00f6zel a\u011f, kimlik do\u011frulama\/ACL ve gerekli ba\u011flant\u0131larda TLS ile koruyun; prefix veya mant\u0131ksal DB ayr\u0131 kaynak ve ar\u0131za alan\u0131 olu\u015fturmaz.<\/p>\n<h2><span id=\"DCHost_Tarafinda_Hangi_Senaryoda_Hangi_Urun_Mantikli\">DCHost Taraf\u0131nda Hangi Senaryoda Hangi \u00dcr\u00fcn Mant\u0131kl\u0131?<\/span><\/h2>\n<p>\u00dcr\u00fcn se\u00e7imini \u015fu ihtiya\u00e7larla e\u015fle\u015ftirebilirsiniz:<\/p>\n<ul>\n<li><strong>Y\u00f6netimi sa\u011flay\u0131c\u0131da kalan uygulama:<\/strong> gerekli s\u00fcre\u00e7\/proxy \u00f6zelliklerini kar\u015f\u0131layan payla\u015f\u0131ml\u0131 plan veya harici ger\u00e7ek zamanl\u0131 servis. Uzun vadeli uygunluk \u00f6l\u00e7\u00fcm ve s\u00f6zle\u015fme ko\u015fullar\u0131yla belirlenir.<\/li>\n<li><strong>S\u00fcre\u00e7 ve a\u011f kontrol\u00fc gereken uygulama:<\/strong> uygun VPS plan\u0131; Laravel\/Reverb ve ba\u011f\u0131ms\u0131z Node.js bile\u015fenleri gerekti\u011fi kadar kurulabilir. Her projeye Redis veya Node.js eklemek zorunlu de\u011fildir.<\/li>\n<li><strong>Y\u00fcksek eri\u015filebilirlik veya \u00f6zel kaynak ihtiyac\u0131:<\/strong> birden fazla VPS, dedicated sunucu veya colocation de\u011ferlendirilebilir. Tek b\u00fcy\u00fck sunucu yedeklilik sa\u011flamaz; ar\u0131za alanlar\u0131 ve bak\u0131m sorumlulu\u011fu ayr\u0131ca tasarlan\u0131r.<\/li>\n<\/ul>\n<p>Teklif de\u011ferlendirirken hedef e\u015fzamanl\u0131 ba\u011flant\u0131 say\u0131s\u0131n\u0131, mesaj boyutunu\/s\u0131kl\u0131\u011f\u0131n\u0131, fan-out\u2019u, gecikme hedefini ve ayn\u0131 makinedeki di\u011fer servisleri belirtin. B\u00f6ylece CPU\/RAM kadar trafik kotas\u0131, y\u00f6netim kapsam\u0131 ve \u00f6l\u00e7ekleme maliyeti de kar\u015f\u0131la\u015ft\u0131r\u0131labilir.<\/p>\n<h2><span id=\"Hosting_Secimini_Protokol_ve_Olcumle_Yapin\">Hosting Se\u00e7imini Protokol ve \u00d6l\u00e7\u00fcmle Yap\u0131n<\/span><\/h2>\n<p>WebSocket hosting se\u00e7imi, yaln\u0131z birka\u00e7 paket kurmaktan fazlas\u0131n\u0131 gerektirir. Laravel Reverb\/Echo ile Socket.IO\u2019nun protokollerini do\u011fru e\u015fle\u015ftirin; yay\u0131n kayna\u011f\u0131, kanal yetkisi, kuyruk ve ba\u011flant\u0131 s\u00fcre\u00e7lerinin tamam\u0131n\u0131 test edin.<\/p>\n<p>Karar\u0131 verirken \u015fu d\u00f6rt noktay\u0131 birlikte de\u011ferlendirin:<\/p>\n<ul>\n<li>Payla\u015f\u0131ml\u0131 plan\u0131n daemon, proxy ve kaynak deste\u011fini do\u011frulay\u0131n; uygun de\u011filse harici servis veya VPS se\u00e7ene\u011fini \u00f6l\u00e7\u00fcn.<\/li>\n<li>VPS\u2019te eri\u015fim kontrol\u00fc, g\u00fcncelleme, servis ba\u015flang\u0131c\u0131, log saklama ve yedek sorumlulu\u011funu a\u00e7\u0131k\u00e7a atay\u0131n.<\/li>\n<li>Nginx\/TLS ve varsa Cloudflare\u2019i uygulama yetkisinin tamamlay\u0131c\u0131s\u0131 olarak kullan\u0131n; mesaj kontrol\u00fcn\u00fc uygulamada s\u00fcrd\u00fcr\u00fcn.<\/li>\n<li>Temsil\u00ee y\u00fck, ba\u011flant\u0131 kopmas\u0131, yeniden ba\u011flanma ve kal\u0131c\u0131 durum kurtarmay\u0131 ge\u00e7i\u015f \u00f6ncesinde deneyin.<\/li>\n<\/ul>\n<p>\u00d6nce desteklenen protokolle \u00e7al\u0131\u015fan k\u00fc\u00e7\u00fck ak\u0131\u015f\u0131 kurun, sonra ger\u00e7ek trafik bi\u00e7imiyle \u00f6l\u00e7\u00fcn. Gerekli kontrol\u00fc ve i\u015fletim kapasitesini sa\u011flayan plan, yaln\u0131z k\u00e2\u011f\u0131t \u00fczerindeki ba\u011flant\u0131 say\u0131s\u0131ndan daha anlaml\u0131 bir se\u00e7im \u00f6l\u00e7\u00fct\u00fcd\u00fcr.<\/p>\n<h2><span id=\"Birincil_Teknik_Kaynaklar\">Birincil Teknik Kaynaklar<\/span><\/h2>\n<ul>\n<li><a href=\"https:\/\/laravel.com\/framework\/docs\/13.x\/broadcasting\" rel=\"nofollow noopener\" target=\"_blank\">Laravel 13 \u2014 Broadcasting<\/a><\/li>\n<li><a href=\"https:\/\/laravel.com\/framework\/docs\/13.x\/reverb\" rel=\"nofollow noopener\" target=\"_blank\">Laravel 13 \u2014 Reverb<\/a><\/li>\n<li><a href=\"https:\/\/laravel.com\/framework\/docs\/13.x\/queues\" rel=\"nofollow noopener\" target=\"_blank\">Laravel 13 \u2014 Queues<\/a><\/li>\n<li><a href=\"https:\/\/socket.io\/docs\/v4\/\" rel=\"nofollow noopener\" target=\"_blank\">Socket.IO 4 \u2014 Introduction<\/a><\/li>\n<li><a href=\"https:\/\/socket.io\/docs\/v4\/middlewares\/\" rel=\"nofollow noopener\" target=\"_blank\">Socket.IO \u2014 Middleware<\/a><\/li>\n<li><a href=\"https:\/\/socket.io\/docs\/v4\/using-multiple-nodes\/\" rel=\"nofollow noopener\" target=\"_blank\">Socket.IO \u2014 Multiple Nodes<\/a><\/li>\n<li><a href=\"https:\/\/socket.io\/docs\/v4\/delivery-guarantees\/\" rel=\"nofollow noopener\" target=\"_blank\">Socket.IO \u2014 Delivery Guarantees<\/a><\/li>\n<li><a href=\"https:\/\/nginx.org\/en\/docs\/http\/websocket.html\" rel=\"nofollow noopener\" target=\"_blank\">Nginx \u2014 WebSocket Proxying<\/a><\/li>\n<li><a href=\"https:\/\/developers.cloudflare.com\/network\/websockets\/\" rel=\"nofollow noopener\" target=\"_blank\">Cloudflare \u2014 WebSockets<\/a><\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Payla\u015f\u0131ml\u0131 hosting ve VPS se\u00e7eneklerini ger\u00e7ek zamanl\u0131 uygulaman\u0131n gereksinimleriyle kar\u015f\u0131la\u015ft\u0131r\u0131n. Laravel Reverb\/Echo ve ba\u011f\u0131ms\u0131z Socket.IO \u00f6rnekleriyle yay\u0131n, yetkilendirme, kuyruk ve ba\u011flant\u0131 ak\u0131\u015f\u0131n\u0131 kurun.<\/p>\n","protected":false},"author":1,"featured_media":12708,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-3610","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\/3610","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=3610"}],"version-history":[{"count":8,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/posts\/3610\/revisions"}],"predecessor-version":[{"id":12710,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/posts\/3610\/revisions\/12710"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/media\/12708"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/media?parent=3610"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/categories?post=3610"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/wp-json\/wp\/v2\/tags?post=3610"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}