HAProxy, yük dengeleme işini yıllardır en az kaynakla ve en öngörülebilir biçimde yapan araçlardan biri. Tek bir yapılandırma dosyası, birkaç yüz megabaytlık bellek ve doğru ayarlanmış zaman aşımlarıyla saniyede on binlerce isteği taşıyabiliyor. Bu rehberde HAProxy kurulumunu sıfırdan yapacak, arkasına üç uygulama sunucusu koyacak, sağlık kontrollerini ayarlayacak, TLS'i dengeleyicide sonlandıracak ve sunucuları yeniden başlatmadan havuza alıp çıkarmayı öğreneceksin.
Yük dengelemenin kavramsal tarafını — L4/L7 farkı, algoritmalar, sticky session tartışması — yük dengeleyici nedir yazısında ele almıştım; burada doğrudan çalışan yapılandırmalara odaklanacağım. Örneklerde dengeleyici düğümün adresi 185.12.34.56, uygulama sunucuları özel ağda 10.0.0.11, 10.0.0.12 ve 10.0.0.13 olacak. Alan adı olarak firmaniz.com kullanacağım.
Kurulum ve Yapılandırma Dosyasının Yapısı#
Debian/Ubuntu ve RHEL türevlerinde HAProxy depolarda hazır gelir. Dağıtım deposundaki sürüm genelde birkaç sürüm geridedir ama üretim için fazlasıyla yeterlidir; en yeni özelliklere ihtiyacın varsa resmî HAProxy deposunu ekleyebilirsin.
# Debian / Ubuntu
sudo apt update && sudo apt install -y haproxy socat
# RHEL / Rocky / AlmaLinux
sudo dnf install -y haproxy socat
# Kurulu sürümü ve derleme seçeneklerini gör
haproxy -vv | head -5
sudo systemctl enable --now haproxy
socat paketini de kurdum çünkü ileride runtime API'ye onunla bağlanacağız. Yapılandırma dosyası /etc/haproxy/haproxy.cfg altındadır ve dört tür bölümden oluşur: global (süreç düzeyi ayarlar), defaults (aşağıdaki tüm bölümlere miras kalan varsayılanlar), frontend (dışarıyı dinleyen taraf) ve backend (arkadaki sunucu havuzu). listen ise frontend ile backend'i tek blokta birleştiren kısayoldur.
global
log /dev/log local0
maxconn 20000
user haproxy
group haproxy
daemon
# Runtime API için yönetim soketi
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults
log global
mode http
option httplog
option dontlognull
option forwardfor # gerçek istemci IP'sini X-Forwarded-For ile ilet
timeout connect 5s
timeout client 30s
timeout server 30s
timeout http-request 10s
timeout http-keep-alive 4s
maxconn değerini sistemin dosya tanıtıcı sınırıyla birlikte düşün: her bağlantı hem istemci hem sunucu tarafında birer soket tüketir. option forwardfor satırı ilk günden açık olmalı; sonradan eklemek, o zamana kadar toplanan bütün erişim kayıtlarının dengeleyicinin IP'siyle dolması demektir.
Temel HTTP Yük Dengeleme Yapılandırması#
Şimdi asıl işi yapan iki bloğu ekleyelim. Frontend 80 portunu dinleyecek, backend üç sunucuya round robin ile dağıtacak.
frontend web_in
bind *:80
default_backend web_pool
backend web_pool
balance roundrobin
option httpchk GET /healthz
http-check expect status 200
default-server inter 2s rise 3 fall 3 maxconn 500
server web1 10.0.0.11:80 check
server web2 10.0.0.12:80 check
server web3 10.0.0.13:80 check
Yapılandırmayı kaydettikten sonra uygulamadan önce mutlaka doğrula; hatalı bir dosyayla yeniden yükleme yapmak servisi düşürebilir.
# Söz dizimi ve mantık kontrolü - "Configuration file is valid" görmelisin
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
# Sorun yoksa kesintisiz yeniden yükle (mevcut bağlantılar korunur)
sudo systemctl reload haproxy
reload ile restart arasındaki fark burada kritik: reload yeni süreci başlatıp eski sürecin açık bağlantılarını bitirmesini bekler, restart ise bağlantıları keser. Üretimde neredeyse hiçbir zaman restart kullanmazsın.
Havuzdaki sunucular farklı güçteyse ağırlık verebilirsin. weight varsayılan olarak 1'dir; 8 vCPU'luk bir düğüme 2, 4 vCPU'luk düğüme 1 vermek dağılımı gerçek kapasiteye yaklaştırır. İstek süreleri değişkense balance roundrobin yerine balance leastconn kullan; uzun süren indirmelerin olduğu bir uygulamada aradaki fark gözle görülür.
Sağlık Kontrolleri ve Sunucu Seçenekleri#
Sağlık kontrolü, HAProxy'yi basit bir yönlendiriciden ayıran şeydir. Yukarıdaki default-server inter 2s rise 3 fall 3 satırı üç şey söylüyor: her sunucuya 2 saniyede bir kontrol isteği at, 3 ardışık başarısızlıkta havuzdan çıkar, 3 ardışık başarıda geri al.
| Parametre | Anlamı | Pratik değer |
|---|---|---|
inter | Kontrol aralığı | 2s |
fall | Kaç hatada kapatılsın | 3 |
rise | Kaç başarıda açılsın | 3 |
fastinter | Geçiş hâlindeyken aralık | 1s |
maxconn | Sunucu başına eşzamanlı bağlantı | Uygulamanın işçi sayısı |
slowstart | Yeni açılan üyeye kademeli trafik | 30s |
backup | Sadece hepsi düşerse devreye gir | Bakım sayfası için |
maxconn değerini sunucu satırında belirtmek çok işe yarar: uygulama sunucun 200 eşzamanlı isteği kaldırıyorsa ve dengeleyici 800 istek yollarsa, fazlası uygulamada kuyruğa girip zaman aşımına uğrar. Sunucu başına maxconn koyduğunda fazla istek HAProxy'de bekler ve sıra geldikçe iletilir; bu, çökmek yerine yavaşlamak demektir ve her zaman tercih edilir.
slowstart ise yeni açılan ya da bakımdan dönen sunucunun tam trafik yerine kademeli olarak yük almasını sağlar; JIT derlemesi, bağlantı havuzu ve önbellek ısınana kadar geçen sürede gelen ani yük yüzünden düğümün tekrar sağlıksız işaretlenmesini engeller. Otomatik ölçekleme kullanıyorsan bu ayar neredeyse zorunludur; nedenini otomatik ölçekleme yazısındaki ısınma süresi bölümünde ayrıntılı anlattım.
Tümüyle düşen bir havuz için bakım sayfası tutan bir yedek sunucu tanımlamak da iyi bir alışkanlıktır:
server bakim 10.0.0.30:80 check backup
TLS Sonlandırma ve HTTPS Yönlendirmesi#
HAProxy sertifikayı tek bir PEM dosyasında bekler: sertifika, ara sertifikalar ve özel anahtar art arda birleştirilmiş hâlde. Let's Encrypt kullanıyorsan fullchain.pem ile privkey.pem dosyalarını birleştirmen gerekir.
sudo mkdir -p /etc/haproxy/certs
sudo bash -c 'cat /etc/letsencrypt/live/firmaniz.com/fullchain.pem \
/etc/letsencrypt/live/firmaniz.com/privkey.pem \
> /etc/haproxy/certs/firmaniz.com.pem'
sudo chmod 600 /etc/haproxy/certs/firmaniz.com.pem
Frontend tarafını da şu şekilde güncelle:
frontend web_in
bind *:80
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
# HTTP ile gelen her isteği HTTPS'e taşı
http-request redirect scheme https unless { ssl_fc }
# Arka uca hangi şemayla gelindiğini bildir
http-request set-header X-Forwarded-Proto https if { ssl_fc }
http-response set-header Strict-Transport-Security "max-age=31536000"
default_backend web_pool
crt parametresine dosya yerine dizin verdim; HAProxy dizindeki tüm PEM dosyalarını yükler ve SNI'ye göre doğru olanı seçer. Böylece yeni alan adı eklemek, dizine dosya koyup yeniden yüklemekten ibaret olur.
X-Forwarded-Proto satırı gözden kaçarsa arka uçta sonsuz yönlendirme döngüsü oluşur: uygulama düz HTTP gördüğü için HTTPS'e yönlendirir, dengeleyici zaten HTTPS'ten geldiği için tekrar düz HTTP olarak iletir ve tarayıcı ERR_TOO_MANY_REDIRECTS verir. Arka uç yapılandırmanda yönlendirme kuralını bu başlığa bakacak biçimde yazmalısın. Sertifika yenilemesini otomatikleştirdiğinde certbot kancasına birleştirme ve systemctl reload haproxy komutlarını eklemeyi unutma; yoksa yenilenen sertifika HAProxy'ye hiç ulaşmaz. Sertifika seçenekleri konusunda kararsızsan SSL sayfamızdaki karşılaştırma yardımcı olur.
Oturum Sürekliliği ve Yola Göre Yönlendirme#
Uygulaman oturumu hâlâ sunucu belleğinde tutuyorsa geçici çözüm olarak çerez tabanlı sabitleme kullanabilirsin. HAProxy kendi çerezini ekler ve kullanıcıyı aynı sunucuya yönlendirir:
backend web_pool
balance roundrobin
cookie SRVID insert indirect nocache
server web1 10.0.0.11:80 check cookie w1
server web2 10.0.0.12:80 check cookie w2
server web3 10.0.0.13:80 check cookie w3
insert çerezi HAProxy'nin ürettiğini, indirect çerezin arka uca iletilmeyeceğini, nocache ise ara önbelleklerin bu yanıtı saklamamasını söyler. Bu yöntem işe yarar ama kalıcı çözüm değildir: sabitlendiği sunucu çöken kullanıcının oturumu gerçekten kaybolur. Doğru yol oturumu Redis gibi ortak bir depoya taşımaktır.
Yola göre yönlendirme ise L7'nin asıl gücüdür. API trafiğini ayrı bir havuza, statik dosyaları başka bir havuza gönderebilirsin:
frontend web_in
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
acl is_api path_beg /api/
acl is_stat path_beg /static/ /assets/
use_backend api_pool if is_api
use_backend static_pool if is_stat
default_backend web_pool
Bu ayrım, API'nin ağır sorgularının web sayfalarını yavaşlatmasını engeller ve iki havuzu birbirinden bağımsız ölçeklemene izin verir.
İstatistik Paneli ve Runtime API#
HAProxy'nin en sevdiğim özelliği, çalışırken yapılandırmaya dokunmadan sunucu durumu değiştirebilmendir. Önce istatistik panelini açalım — dışarıya açmamak için yalnızca yerel adrese bağlıyorum:
listen stats
bind 127.0.0.1:8404
stats enable
stats uri /haproxy?stats
stats refresh 10s
stats show-legends
Panele SSH tüneliyle erişebilirsin. Asıl güçlü taraf ise yönetim soketidir:
# Havuzdaki tüm sunucuların anlık durumu
echo "show stat" | sudo socat stdio /run/haproxy/admin.sock | cut -d, -f1,2,18,19
# Bakıma alacağın sunucuya yeni bağlantı gönderme, mevcutları bitir
echo "set server web_pool/web1 state drain" | sudo socat stdio /run/haproxy/admin.sock
# İşin bitince havuza geri al
echo "set server web_pool/web1 state ready" | sudo socat stdio /run/haproxy/admin.sock
# Ağırlığı canlı değiştir (kademeli trafik vermek için)
echo "set weight web_pool/web1 20%" | sudo socat stdio /run/haproxy/admin.sock
drain durumu, sürüm geçişlerinin kesintisiz yapılmasının anahtarıdır: sunucuyu drain'e al, açık isteklerin bitmesini bekle, güncelle, ready yap, bir sonrakine geç. Bu döngüyü bir betiğe alırsan elinde basit ama etkili bir kesintisiz dağıtım aracı olur.
Kayıtlar ve Sorun Giderme#
HAProxy varsayılan olarak syslog'a yazar; rsyslog yapılandırmasında local0 tesisini ayrı bir dosyaya yönlendirmezsen kayıtları göremezsin.
# Kayıt dosyasını canlı izle
sudo tail -f /var/log/haproxy.log
# Örnek satır (sondaki kodlar teşhisin anahtarı):
# firmaniz.com web_in~ web_pool/web2 0/0/1/48/49 200 5321 - - ---- 12/12/0/1/0 0/0
Satırın sonundaki iki karakterlik sonlandırma kodları tam olarak neyin ters gittiğini söyler:
| Kod | Anlamı | Tipik sebep |
|---|---|---|
---- | Normal tamamlandı | — |
sH-- | Sunucu yanıt zaman aşımı | timeout server düşük ya da uygulama yavaş |
cD-- | İstemci bağlantıyı kesti | Kullanıcı sayfayı kapattı |
SC-- | Sunucuya bağlanılamadı | Uygulama kapalı, güvenlik duvarı engelliyor |
sQ-- | Kuyrukta zaman aşımı | maxconn çok düşük |
PR-- | İstek reddedildi | ACL kuralı ya da hatalı istek |
sH görüyorsan timeout server değerini uygulamanın en uzun makul yanıt süresinin biraz üstüne çekmelisin; sQ görüyorsan sunucu başına maxconn değerini yükseltmen ya da düğüm eklemen gerekir. Bu kodları okuyabilmek, HAProxy sorunlarının büyük kısmını dakikalar içinde çözer.
Sık Yapılan Hatalar#
Yapılandırmayı doğrulamadan yeniden yüklemek. haproxy -c -f komutu iki saniye sürer ve servisi düşürmeni engeller. Otomasyona alıyorsan bu adımı zorunlu kıl.
Zaman aşımı uyumsuzluğu. Arka uçtaki keepalive süresi, HAProxy'nin timeout server değerinden kısaysa rastgele 502 hataları görürsün. Arka ucun keepalive süresi her zaman daha uzun olmalı.
Sağlık kontrolünü veritabanına bağlamak. /healthz uç noktası veritabanı sorgusu yapıyorsa, veritabanı bir saniyeliğine yavaşladığında tüm havuz aynı anda düşer ve kısmi bir sorun tam kesintiye dönüşür.
Tek dengeleyici düğümüyle yetinmek. HAProxy arkasındaki üç sunucuyu yedekli hâle getirir ama kendisi tek düğümse hata noktasını sadece taşımış olursun. İkinci bir düğüm ve aralarında dolaşan bir sanal IP şart.
Sertifika yenilemesinden sonra yeniden yüklemeyi unutmak. Certbot sertifikayı yeniler, HAProxy eskisini bellekte tutmaya devam eder ve 90 gün sonra site sertifika hatası verir. Yenileme kancasına reload eklemeyi ilk günden yap.
Sıkça Sorulan Sorular#
HAProxy mi Nginx mi kullanmalıyım#
İkisi de yük dengeleme yapar ama odakları farklıdır. HAProxy sadece proxy ve dengeleyici olarak tasarlandığı için sağlık kontrolü, kuyruk yönetimi, runtime API ve ayrıntılı kayıt konularında daha zengindir. Nginx ise aynı zamanda web sunucusudur; statik dosya sunmak, önbelleklemek ve PHP-FPM'i çalıştırmak istiyorsan tek araçla iş görürsün. Ayrı bir dengeleyici katmanı kuruyorsan HAProxy, mevcut Nginx'i dengeleyici olarak da kullanacaksan Nginx mantıklıdır.
HAProxy yapılandırmasını değiştirince kesinti olur mu#
systemctl reload haproxy kullandığın sürece olmaz. Reload sırasında yeni süreç yeni bağlantıları alır, eski süreç mevcut bağlantılarını tamamlayıp kapanır. Kesinti yalnızca restart kullandığında ya da yapılandırma hatalıysa yaşanır; bu yüzden her değişiklikten önce haproxy -c -f ile doğrulama yapmak alışkanlık hâline gelmeli.
Bir sunucuyu bakıma almak için HAProxy'yi yeniden başlatmam gerekir mi#
Hayır, gerekmez. Yönetim soketi üzerinden set server havuz/sunucu state drain komutuyla o sunucuya yeni istek gönderilmesini durdurursun; mevcut istekler normal biçimde tamamlanır. Bakım bittiğinde state ready ile geri alırsın. Yapılandırma dosyasına hiç dokunmadığın için yeniden yükleme de gerekmez.
HAProxy kaç eşzamanlı bağlantı kaldırır#
Bu, maxconn ayarına, sunucunun çekirdek sayısına ve TLS sonlandırma yapıp yapmadığına bağlıdır. Düz HTTP proxy'lemede orta seviye bir sunucu on binlerce eşzamanlı bağlantıyı rahat taşır; TLS sonlandırma eklendiğinde el sıkışma maliyeti yüzünden bu sayı belirgin biçimde düşer. Gerçek sınırını kendi trafiğinle yük testi yaparak ölçmen gerekir, genel bir rakam yanıltıcı olur.
HAProxy WebSocket bağlantılarını destekler mi#
Evet, ek bir modül gerekmez. WebSocket, HTTP yükseltme (upgrade) mekanizmasıyla başladığı için HAProxy bunu doğal olarak taşır. Dikkat etmen gereken tek şey zaman aşımlarıdır: uzun süre veri akmayan bir WebSocket bağlantısı timeout client ya da timeout server süresine takılıp kapanır. Bu tür trafik için ayrı bir backend tanımlayıp orada zaman aşımlarını uzatmak en temiz çözümdür.
Gerçek ziyaretçi IP'sini arka uçta nasıl görürüm#
HTTP modunda option forwardfor satırı X-Forwarded-For başlığını ekler; arka uçtaki web sunucusunda da bu başlığa yalnızca dengeleyicinin IP'sinden gelirse güvenecek şekilde ayar yapman gerekir. TCP modunda başlık ekleyemezsin; bu durumda sunucu satırına send-proxy ekleyip arka uçta PROXY protokol desteğini açarsın. İkisinden birini kurmadan erişim kayıtların tek bir IP ile dolar.
HAProxy Windows üzerinde çalışır mı#
Doğrudan çalışmaz; HAProxy Linux ve diğer Unix türevleri için geliştirilmiştir. Windows ortamında kullanmak istersen WSL2 ya da bir Linux sanal makinesi üzerinden çalıştırman gerekir, ancak üretim için bu yolu önermem. Arka uçtaki uygulama sunucularının Windows olması ise tamamen sorunsuzdur; HAProxy onlarla sıradan HTTP ya da TCP üzerinden konuşur.
Kapanış#
HAProxy ile çalışan bir yük dengeleyici kurmak yarım saatlik bir iş; üretime dayanıklı hâle getirmek ise birkaç ayrıntıya dikkat etmekten geçiyor. Aklında kalması gereken dört alışkanlık: her değişiklikten önce haproxy -c -f ile doğrula, sağlık kontrolünü sığ tut ve inter/rise/fall değerlerini bilinçli seç, sunucu başına maxconn vererek çökmek yerine yavaşlamayı seç ve bakımlarını runtime API'nin drain durumu üzerinden yap.
Bu kurulumu barındıracak altyapı için tam root erişimli VDS ya da esnek kaynaklı bulut sunucu paketlerimiz uygun bir başlangıç; dengeleyici ve arka uç düğümlerinin kurulumunu, izlenmesini ve sertifika yenilemelerini kendin üstlenmek istemiyorsan sunucu yönetimi hizmetimiz bu işi devralır. Trafik ölçeklerini kabaca planlamak için bant genişliği hesaplayıcı aracımızı kullanabilirsin.