Cloudflare Health Checks ile Sunucu Sağlık İzleme
Sunucularınız gece yarısı çöktüğünde ilk siz mi öğreniyorsunuz, yoksa müşterileriniz mi? Bu sorunun cevabı, ne kadar iyi bir izleme altyapısı kurduğunuza bağlı. Cloudflare’in Health Checks özelliği, DNS katmanında sunucu sağlığını izleyerek hem erken uyarı hem de otomatik trafik yönlendirme imkânı sunuyor. Bu yazıda Cloudflare Health Checks’i sıfırdan nasıl kuracağınızı, API ile nasıl yöneteceğinizi ve gerçek dünya senaryolarında nasıl kullanacağınızı ele alacağız.
Cloudflare Health Checks Nedir?
Cloudflare Health Checks, belirlediğiniz sunucu veya origin’lere düzenli aralıklarla HTTP/HTTPS veya TCP istekleri göndererek sağlık durumunu izleyen bir özelliktir. Load Balancer’dan bağımsız olarak kullanılabildiği gibi, Load Balancer ile entegre çalışarak otomatik failover da sağlayabilir.
İki farklı kullanım senaryosu vardır:
- Standalone Health Checks: Sadece izleme amaçlı, trafik yönlendirme yapmadan
- Load Balancer Health Checks: Pool içindeki origin’leri izleyerek sağlıksız sunucuya trafik göndermeyi durdurur
Ücretsiz planda standalone health checks sınırlı sayıda gelir; Pro ve üzeri planlarda daha gelişmiş özellikler açılır. Load Balancer ise ayrı ücretlendirilir.
Gereksinimler ve Hazırlık
Başlamadan önce birkaç şeyi hazır etmeniz gerekiyor:
- Cloudflare hesabı ve DNS yönetimini Cloudflare’e devretmiş bir domain
- API Token veya Global API Key (API üzerinden yönetim için)
- İzlenecek sunucu IP adresleri ve port bilgileri
curlvejqyüklü bir terminal
API Token oluşturmak için Cloudflare Dashboard > My Profile > API Tokens yolunu izleyin. “Edit zone DNS” ve “Zone: Read” yetkilerini token’a ekleyin. Load Balancer yönetimi yapacaksanız “Load Balancers: Edit” yetkisini de eklemeyi unutmayın.
Ortam değişkenlerini baştan ayarlayalım:
export CF_API_TOKEN="buraya_api_tokeninizi_yazin"
export CF_ZONE_ID="zone_id_buraya"
export CF_ACCOUNT_ID="account_id_buraya"
# Token'ı test edelim
curl -s -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json" | jq '.result.status'
Çıktı "active" döndürüyorsa hazırsınız demektir.
İlk Health Check’i Oluşturmak
Dashboard Üzerinden Hızlı Kurulum
Dashboard’dan gitmek için: Cloudflare Dashboard > ilgili Zone > Traffic > Health Checks yolunu izleyin. “Create” butonuna tıklayıp aşağıdaki alanları doldurun.
- Name: Tanımlayıcı bir isim verin, örneğin “prod-web-server-01”
- URL: İzlenecek adres, örneğin
https://example.com/health - Monitoring Type: HTTP veya TCP seçin
- Check Frequency: 60 saniye önerilir
- Consecutive Fails: Kaç başarısız denemeden sonra “unhealthy” sayılacağı
- Consecutive Successes: Kaç başarılı denemeden sonra “healthy” sayılacağı
API ile Health Check Oluşturmak
Asıl gücü API’de. Şimdi bir HTTP health check oluşturalım:
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/healthchecks"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json"
--data '{
"name": "prod-web-server-01",
"description": "Production web sunucusu ana health check",
"address": "203.0.113.10",
"type": "HTTPS",
"port": 443,
"path": "/health",
"interval": 60,
"retries": 2,
"timeout": 5,
"consecutive_up": 2,
"consecutive_down": 2,
"http_config": {
"method": "GET",
"expected_codes": ["200", "204"],
"expected_body": "OK",
"follow_redirects": false,
"allow_insecure": false,
"header": {
"User-Agent": ["cloudflare-healthcheck/1.0"],
"X-Health-Check": ["true"]
}
},
"notification_suspended": false,
"suspended": false
}' | jq '.'
Bu isteği gönderdikten sonra dönen JSON’dan id alanını kaydedin, sonraki işlemlerde gerekecek.
TCP Health Check
Sadece port açıklığını kontrol etmek istiyorsanız TCP daha uygun olabilir. Özellikle database portları veya özel protokoller için kullanışlıdır:
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/healthchecks"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json"
--data '{
"name": "db-server-tcp-check",
"description": "MySQL port kontrolu",
"address": "203.0.113.20",
"type": "TCP",
"port": 3306,
"interval": 60,
"retries": 3,
"timeout": 10,
"consecutive_up": 2,
"consecutive_down": 3
}' | jq '.result | {id, name, type, address, port}'
Health Check Endpoint’i Sunucuda Hazırlamak
Cloudflare’in kontrol edeceği /health endpoint’ini sunucunuzda oluşturmanız gerekiyor. Sadece HTTP 200 döndürmek yeterli değil; gerçek bir sağlık kontrolü yapan endpoint yazmalısınız.
Nginx ile Basit Health Endpoint
# /etc/nginx/conf.d/health.conf
server {
listen 80;
listen 443 ssl;
server_name example.com;
location /health {
access_log off;
add_header Content-Type text/plain;
# Sadece Cloudflare IP'lerinden gelen isteklere izin ver
allow 103.21.244.0/22;
allow 103.22.200.0/22;
allow 103.31.4.0/22;
allow 104.16.0.0/13;
allow 104.24.0.0/14;
allow 108.162.192.0/18;
allow 131.0.72.0/22;
allow 141.101.64.0/18;
allow 162.158.0.0/15;
allow 172.64.0.0/13;
allow 173.245.48.0/20;
allow 188.114.96.0/20;
allow 190.93.240.0/20;
allow 197.234.240.0/22;
allow 198.41.128.0/17;
deny all;
return 200 "OK";
}
}
Python Flask ile Kapsamlı Health Check
Sadece “sunucu ayakta” değil, “sunucu düzgün çalışıyor” kontrolü yapmak için daha kapsamlı bir endpoint:
#!/usr/bin/env python3
# health_check.py - Flask health check endpoint'i
from flask import Flask, jsonify
import mysql.connector
import redis
import os
import time
app = Flask(__name__)
def check_database():
try:
conn = mysql.connector.connect(
host=os.getenv('DB_HOST', 'localhost'),
user=os.getenv('DB_USER', 'healthcheck'),
password=os.getenv('DB_PASS', ''),
database=os.getenv('DB_NAME', 'app'),
connect_timeout=3
)
cursor = conn.cursor()
cursor.execute("SELECT 1")
cursor.fetchone()
conn.close()
return True, "OK"
except Exception as e:
return False, str(e)
def check_redis():
try:
r = redis.Redis(
host=os.getenv('REDIS_HOST', 'localhost'),
port=6379,
socket_connect_timeout=3
)
r.ping()
return True, "OK"
except Exception as e:
return False, str(e)
def check_disk_space():
import shutil
total, used, free = shutil.disk_usage("/")
percent_used = (used / total) * 100
if percent_used > 90:
return False, f"Disk dolu: %{percent_used:.1f}"
return True, f"%{percent_used:.1f} kullaniliyor"
@app.route('/health', methods=['GET'])
def health():
checks = {}
all_healthy = True
db_ok, db_msg = check_database()
checks['database'] = {'status': 'ok' if db_ok else 'fail', 'message': db_msg}
if not db_ok:
all_healthy = False
redis_ok, redis_msg = check_redis()
checks['redis'] = {'status': 'ok' if redis_ok else 'fail', 'message': redis_msg}
if not redis_ok:
all_healthy = False
disk_ok, disk_msg = check_disk_space()
checks['disk'] = {'status': 'ok' if disk_ok else 'warn', 'message': disk_msg}
response = {
'status': 'healthy' if all_healthy else 'unhealthy',
'timestamp': int(time.time()),
'checks': checks
}
http_status = 200 if all_healthy else 503
return jsonify(response), http_status
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
Bu endpoint, Cloudflare’in expected_codes ayarında 200 ve 503’ü bekleyecek şekilde konfigüre edebilirsiniz; ama genellikle 200 döndüğünde healthy, 503 döndüğünde unhealthy olarak ayarlamak mantıklı.
Mevcut Health Check’leri Yönetmek
Tüm Health Check’leri Listeleme
# Tüm health check'leri listele ve özet göster
curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/healthchecks"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json" |
jq '.result[] | {
id: .id,
name: .name,
address: .address,
type: .type,
port: .port,
status: .status,
interval: .interval
}'
Health Check Durumunu Sorgulamak
HEALTH_CHECK_ID="buraya_health_check_id_yazin"
curl -s -X GET
"https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/healthchecks/$HEALTH_CHECK_ID"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json" |
jq '.result | {
name: .name,
status: .status,
failure_reason: .failure_reason,
checked_regions: .checked_regions
}'
Dönen status alanı healthy, unhealthy veya unknown olabilir. failure_reason alanı ise neden başarısız olduğunu açıklar.
Health Check Güncelleme
Interval’ı veya path’i değiştirmek gerektiğinde PATCH kullanın:
curl -s -X PATCH
"https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/healthchecks/$HEALTH_CHECK_ID"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json"
--data '{
"interval": 30,
"consecutive_down": 3,
"description": "Guncellendi: 30 saniye interval"
}' | jq '.result | {name, interval, consecutive_down}'
Load Balancer ile Entegrasyon
Gerçek failover senaryosu için Health Checks’i Load Balancer ile birleştirmeniz gerekiyor. Önce bir Pool oluşturalım:
# Load Balancer Pool oluştur
curl -s -X POST
"https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/load_balancers/pools"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json"
--data '{
"name": "production-web-pool",
"description": "Production web sunuculari",
"enabled": true,
"minimum_origins": 1,
"monitor": "BURAYA_MONITOR_ID",
"origins": [
{
"name": "web-01",
"address": "203.0.113.10",
"enabled": true,
"weight": 1,
"header": {
"Host": ["example.com"]
}
},
{
"name": "web-02",
"address": "203.0.113.11",
"enabled": true,
"weight": 1,
"header": {
"Host": ["example.com"]
}
}
],
"notification_email": "[email protected]"
}' | jq '.result | {id, name, healthy}'
Monitor ID’yi almak için önce bir account-level monitor oluşturmanız gerekiyor. Bu, zone-level health check’ten farklıdır:
# Account-level monitor oluştur (Load Balancer için)
curl -s -X POST
"https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/load_balancers/monitors"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json"
--data '{
"type": "https",
"description": "Production HTTPS monitor",
"method": "GET",
"path": "/health",
"port": 443,
"interval": 60,
"retries": 2,
"timeout": 5,
"consecutive_up": 2,
"consecutive_down": 2,
"expected_codes": "200",
"expected_body": "healthy",
"follow_redirects": false,
"allow_insecure": false,
"header": {
"User-Agent": ["Cloudflare-LB-Monitor"]
}
}' | jq '.result | {id, type, path, interval}'
Alerting: Bildirim Almak
Health Check değeri olmaz, bildirim yoksa. Cloudflare Notifications özelliğiyle e-posta, PagerDuty, Slack veya webhook üzerinden uyarı alabilirsiniz.
Webhook ile Slack Bildirimi
Cloudflare Dashboard’dan Notifications > Create bölümüne gidin. “Health Check status change” event’ini seçin ve webhook URL’nizi girin. Webhook payload’u şu formatta gelir:
# Webhook'u test etmek icin basit bir Python listener
# Bu script gelen Cloudflare notification'larini yakalar
python3 -c "
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers['Content-Length'])
body = self.rfile.read(length)
data = json.loads(body)
print(json.dumps(data, indent=2))
self.send_response(200)
self.end_headers()
def log_message(self, format, *args):
pass
print('Webhook dinleniyor: 0.0.0.0:9000')
HTTPServer(('0.0.0.0', 9000), Handler).serve_forever()
"
Otomatik Aksiyon Scripti
Health check durumu değiştiğinde webhook ile tetiklenecek bir script:
#!/bin/bash
# /usr/local/bin/health-check-action.sh
# Bu script webhook'tan gelen POST body'yi parse eder
# ve gerekli aksiyonları alir
LOG_FILE="/var/log/cloudflare-health-actions.log"
SLACK_WEBHOOK="https://hooks.slack.com/services/XXXXX/YYYYY/ZZZZZ"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
send_slack() {
local message="$1"
local color="$2"
curl -s -X POST "$SLACK_WEBHOOK"
-H "Content-Type: application/json"
--data "{
"attachments": [{
"color": "$color",
"text": "$message",
"footer": "Cloudflare Health Check",
"ts": $(date +%s)
}]
}" > /dev/null
}
# Stdin'den JSON oku (webhook body)
PAYLOAD=$(cat)
STATUS=$(echo "$PAYLOAD" | jq -r '.data.health_status // "unknown"')
HOSTNAME=$(echo "$PAYLOAD" | jq -r '.data.hostname // "unknown"')
ORIGIN=$(echo "$PAYLOAD" | jq -r '.data.origin // "unknown"')
log "Durum degisimi: $HOSTNAME ($ORIGIN) -> $STATUS"
case "$STATUS" in
"unhealthy")
log "KRITIK: $HOSTNAME sagliksiz! Aksiyon aliniyor..."
send_slack ":red_circle: *KRITIK*: $HOSTNAME ($ORIGIN) sagliksiz!" "danger"
# Opsiyonel: Yedek sunucuya otomatik gecis icin script cagir
# /usr/local/bin/failover.sh "$ORIGIN"
;;
"healthy")
log "IYILESME: $HOSTNAME tekrar saglikli."
send_slack ":green_circle: *IYILESME*: $HOSTNAME ($ORIGIN) tekrar saglikli!" "good"
;;
*)
log "Bilinmeyen durum: $STATUS"
;;
esac
Gerçek Dünya Senaryoları
Senaryo 1: Çoklu Veri Merkezi İzleme
İstanbul ve Almanya’da birer sunucunuz olduğunu varsayalım. Her ikisi de aktif olarak trafik alıyor. Health Check ile her ikisini izleyip, biri düştüğünde DNS kaydını otomatik olarak kaldırabilirsiniz.
Bu senaryoda Cloudflare Load Balancer’ı kullanarak aktif-aktif yapı kurulur. Her iki origin pool’da tanımlanır. Biri unhealthy olduğunda Cloudflare otomatik olarak trafiği sağlıklı origin’e yönlendirir. TTL değeri düşük tutulduğu için geçiş süresi genellikle 60 saniyenin altında kalır.
Senaryo 2: Maintenance Mode Entegrasyonu
Bakım sürecinde health check’i geçici olarak duraklatmak:
# Bakim moduna gec - health check'i askiya al
HEALTH_CHECK_ID="your_check_id"
curl -s -X PATCH
"https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/healthchecks/$HEALTH_CHECK_ID"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json"
--data '{"suspended": true}' |
jq '.result | {name, suspended}'
echo "Bakim islemi tamamlandiginda su komutu calistirin:"
echo "CF_ZONE_ID=$CF_ZONE_ID CF_API_TOKEN=$CF_API_TOKEN \"
echo " HEALTH_CHECK_ID=$HEALTH_CHECK_ID /usr/local/bin/resume-health-check.sh"
# Bakim bitti, tekrar aktif et
# curl -s -X PATCH ... --data '{"suspended": false}'
Senaryo 3: Toplu Health Check Raporu
Sabah işe geldiğinizde tüm sunucuların durumunu tek komutla görmek:
#!/bin/bash
# /usr/local/bin/morning-health-report.sh
CF_API_TOKEN="${CF_API_TOKEN}"
CF_ZONE_ID="${CF_ZONE_ID}"
echo "=== Cloudflare Health Check Raporu ==="
echo "Tarih: $(date '+%Y-%m-%d %H:%M:%S')"
echo ""
CHECKS=$(curl -s -X GET
"https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/healthchecks"
-H "Authorization: Bearer $CF_API_TOKEN"
-H "Content-Type: application/json")
TOTAL=$(echo "$CHECKS" | jq '.result | length')
HEALTHY=$(echo "$CHECKS" | jq '[.result[] | select(.status == "healthy")] | length')
UNHEALTHY=$(echo "$CHECKS" | jq '[.result[] | select(.status == "unhealthy")] | length')
echo "Toplam: $TOTAL | Saglikli: $HEALTHY | Sagliksiz: $UNHEALTHY"
echo ""
echo "--- Sagliksiz Sunucular ---"
echo "$CHECKS" | jq -r '.result[] | select(.status == "unhealthy") |
"[(.name)] (.address):(.port // 443) - (.failure_reason // "Bilinmiyor")"'
echo ""
echo "--- Saglikli Sunucular ---"
echo "$CHECKS" | jq -r '.result[] | select(.status == "healthy") |
"[(.name)] (.address):(.port // 443)"'
Bu scripti cron’a ekleyerek her sabah e-posta ile alabilirsiniz:
# Crontab'a ekle
echo "0 8 * * 1-5 /usr/local/bin/morning-health-report.sh | mail -s 'Gunluk Health Report' [email protected]" | crontab -
Sık Yapılan Hatalar ve Çözümleri
“Health check geçiyor ama sunucu yavaş” durumunda timeout değerini düşürün. Varsayılan 5 saniye timeout, yavaş yanıt veren bir sunucuyu healthy gösterebilir. Uygulamanızın normal yanıt süresi 500ms ise timeout’u 2 saniyeye çekin.
“False positive unhealthy” durumunda consecutive_down değerini 2’den 3’e çıkarın. Geçici ağ dalgalanmaları yüzünden tek başarısız kontrol alarm yaratmasın.
“Health check IP’lerim firewall’da bloklanıyor” yaygın bir sorundur. Cloudflare’in health check IP aralıklarını firewall whitelist’ine eklemeniz şart. Güncel listeyi şu komutla çekin:
# Cloudflare IP araliklerini guncelle
curl -s https://www.cloudflare.com/ips-v4 > /tmp/cf_ips_v4.txt
curl -s https://www.cloudflare.com/ips-v6 > /tmp/cf_ips_v6.txt
# UFW ile toplu izin ver
while read ip; do
ufw allow from "$ip" to any port 443 comment "Cloudflare Health Check"
done < /tmp/cf_ips_v4.txt
echo "Cloudflare IP'leri eklendi."
ufw status numbered | grep "Cloudflare"
“Expected body eşleşmiyor” hatasında büyük/küçük harf duyarlılığına dikkat edin. Cloudflare, expected_body kontrolünü case-sensitive yapar. Endpoint’inizin döndürdüğü tam metni kullanın.
İzleme Stratejisi: Ne Kadar Sık Kontrol Edilmeli?
Health check aralığı seçerken birkaç faktörü göz önünde bulundurun:
- Kritik production sistemleri: 30 saniye interval, 2 consecutive down
- Staging ortamları: 60 saniye interval, 3 consecutive down
- Düşük öncelikli servisler: 300 saniye interval, 3 consecutive down
- Database portları (TCP): 60 saniye interval yeterli, TCP check daha az kaynak tüketir
Çok agresif check (10-15 saniye) bazı sunucularda access log’larını gereksiz şişirebilir ve küçük bir yük oluşturabilir. Makul bir denge için 30-60 saniye çoğu senaryo için idealdir.
Sonuç
Cloudflare Health Checks, DNS katmanında görünürlük sağlayan ve düzgün yapılandırıldığında ekibinize ekstra nöbet tutturma ihtiyacını ortadan kaldıran güçlü bir araç. Standalone kullanımda sadece izleme ve alarm üretir; Load Balancer ile entegre kullanımda ise sağlıksız origin’e trafik göndermeyi tamamen durdurur.
Bu yazıda ele aldığımız konuları özetlemek gerekirse: API ile health check oluşturma ve yönetme, sunucu tarafında anlamlı health endpoint yazma, Load Balancer pool entegrasyonu, webhook ve Slack bildirimleri, ve gerçek hayatta karşılaşılan yaygın sorunların çözümleri.
Bir sonraki adım olarak bu altyapıyı Terraform veya Ansible ile kodunuza gömmeyi değerlendirin. Böylece “bu health check kim oluşturdu, neden var” sorularından kurtulur, tüm izleme altyapınızı versiyon kontrolünde tutarsınız. Cloudflare’in Terraform provider’ı hem zone-level health check’leri hem de account-level load balancer monitor’larını destekliyor; ilerleyen yazılarda bunu da detaylı işleyeceğiz.
