Cloudflare ile Bookstore'u Yayına Almak: Proxy, SSL/TLS Modları, Cache Rules ve Gerçek Client IP
Cloudflare'e geçerken nameserver'ı taşır, web kayıtlarını proxied, mail kayıtlarını DNS-only bırakır, SSL/TLS modu olarak Full (strict) seçer, Page Rules yerine Cache ve Redirect Rules yazar ve origin'de CF-Connecting-IP'ye yalnızca Cloudflare'in IP aralıklarından gelen bağlantılarda güvenirsin. Laboratuvarda Flexible modun ürettiği redirect döngüsünü, ASP.NET Core'da KnownIPNetworks ile sahte header'ları reddeden testleri ve Azure Front Door karşılıklarını görüyoruz.
Sürüm notu: Bu yazıdaki örnekler .NET 10, xUnit 2.9 ve Microsoft.AspNetCore.Mvc.Testing 10.0.15, Nginx 1.30.6 ve curl 8.17 ile Docker 29 üzerinde denenmiştir; Cloudflare ve Azure Front Door adımları 14 Kasım 2026 tarihli resmi dokümanlardan aktarılmıştır, bir Cloudflare veya Azure hesabında çalıştırılmamıştır.
Önce Tahmin Et
Sitedeki serilerin ortak örnek uygulaması Bookstore (bir online kitapçı) Cloudflare'e taşındı. Origin sunucusunda henüz certificate yok, Emre de kurulum sihirbazında SSL (şifreli bağlantı protokolünün eski adı) modu olarak "Flexible"ı seçiyor: ziyaretçi Cloudflare'e HTTPS ile gelsin, Cloudflare origin'e HTTP ile gitsin. Bookstore.Api'de ise template'ten gelen app.UseHttpsRedirection() satırı duruyor.
Tahmin et: Ziyaretçi https://bookstore.example/api/books'u açtığında ne olur? Bir de şu: kayıtlar artık Cloudflare'in IP'lerini gösteriyor, origin'in IP'si "gizli". Gerçekten gizli mi? Bu yazıda Cloudflare'e geçişi adım adım kuruyor, ilk soruyu laboratuvarda tekrarlıyor, ikincisini de origin'in log'larına bakarak cevaplıyoruz.
Onboarding: Nameserver'ı Taşımak ve Kayıtları Almak
Cloudflare'in standart kurulumunda ("full setup") DNS'in kendisi Cloudflare'e geçer; birinci yazıda gördüğümüz delegasyon şimdi Cloudflare'e yapılır. Cloudflare'in dokümanına göre akış şöyle: domain'i hesaba eklersin, Cloudflare mevcut kayıtları tarayıp içe aktarır, sen listeyi gözden geçirirsin, Cloudflare sana iki nameserver adı verir, sen de bunları registrar'a yazarsın. Dördüncü yazıdaki kurallar burada aynen geçerli. Otomatik tarama her kaydı bulamaz: zone transferi kapalı olduğu için Cloudflare yaygın isimleri tahmin ederek arar; asuid.api veya s1._domainkey.mail gibi kayıtlar listeye girmeyebilir. Bu yüzden eski sağlayıcıdan zone'u dışa aktarıp içe aktarmak, sonra compare-resolvers.sh ile iki tarafı karşılaştırmak tahmine güvenmekten daha sağlam. DNSSEC (DNS cevaplarını imzalayan uzantı) açıksa NS (nameserver) değişikliğinden önce DS (TLD'deki anahtar özeti) kaydını ne yapacağına karar ver; dördüncü yazıdaki SERVFAIL senaryosu Cloudflare'e geçişte de aynen yaşanır.
Bookstore'un zone'u DNSControl ile repo'da duruyorsa geçiş daha kolay: aynı dnsconfig.js'i Cloudflare provider'ıyla uygularsın ve iki sağlayıcıdaki kayıtların aynı olduğunu araç kendisi gösterir.
Proxied ve DNS-only: Turuncu Bulut Ne Yapar?
Cloudflare'deki her A, AAAA (IPv6 adresi) ve CNAME (takma ad) kaydının bir "proxy status"u var. Proxied (turuncu bulut) bir kayıt, sorulduğunda origin'in IP'sini değil Cloudflare'in anycast IP'lerini döner; trafik Cloudflare'in edge'inden geçer, cache, WAF (web uygulaması güvenlik duvarı) ve diğer özellikler devreye girer. DNS-only (gri bulut) kayıt ise sıradan bir DNS kaydıdır, gerçek IP'yi döner. Proxied bir isme sorunca ne geldiğini görmek için Cloudflare'in yayımladığı IP aralıklarına bakabiliriz:
$ curl -s https://api.cloudflare.com/client/v4/ips | jq '{etag: .result.etag, ipv4: (.result.ipv4_cidrs | length), ipv6: (.result.ipv6_cidrs | length), first_v4: .result.ipv4_cidrs[0:3], first_v6: .result.ipv6_cidrs[0:2]}'
{
"etag": "38f79d050aa027e3be3865e495dcc9bc",
"ipv4": 15,
"ipv6": 7,
"first_v4": [
"173.245.48.0/20",
"103.21.244.0/22",
"103.22.200.0/22"
],
"first_v6": [
"2400:cb00::/32",
"2606:4700::/32"
]
}
$ dig @1.1.1.1 example.com A +short
104.20.23.154
172.66.147.243
$ python3 -c "
import ipaddress
nets = [ipaddress.ip_network(l.strip()) for l in open('cloudflare-ips.txt') if l.strip()]
for ip in ['104.20.23.154', '172.66.147.243', '173.245.48.10']:
a = ipaddress.ip_address(ip); print(ip, [str(n) for n in nets if a in n])"
104.20.23.154 ['104.16.0.0/13']
172.66.147.243 ['172.64.0.0/13']
173.245.48.10 ['173.245.48.0/20']
$ curl -sI https://example.com | grep -iE "^(HTTP|server|cf-cache-status|age)"
HTTP/2 200
server: cloudflare
age: 3029
cf-cache-status: HIT
example.com'un adresleri Cloudflare'in aralıklarında ve cevap Cloudflare'in cache'inden geliyor (cf-cache-status: HIT). Origin'in nerede olduğu DNS'ten görünmüyor.
Proxy yalnızca HTTP ve HTTPS taşır. Cloudflare'in dokümanına göre varsayılan olarak proxy'lenen portlar HTTP için 80, 8080, 8880, 2052, 2082, 2086 ve 2095; HTTPS için 443, 2053, 2083, 2087, 2096 ve 8443. Bunların bir kısmında cache kapalı. SSH (uzak terminal bağlantısı), SMTP (mail gönderim protokolü) veya bir veritabanı portu proxy'den geçmez. Bu yüzden Bookstore'da şunlar DNS-only kalmalı: MX (mail sunucusu kaydı) kaydının gösterdiği mail sunucuları, SFTP (SSH üzerinden dosya aktarımı) veya SSH için kullanılan isimler. TXT (serbest metin), MX ve CAA (certificate verebilecek kuruluşları sınırlayan kayıt) zaten proxy'lenemez; turuncu bulut yalnızca A, AAAA ve CNAME'de var. Bookstore için karar: apex, www, api ve staging isimleri proxied; mail ile ilgili her şey DNS-only.
SSL/TLS Modları ve Flexible'ın Tuzağı
Proxy'li bir sitede iki ayrı TLS (şifreli bağlantı) bağlantısı var: ziyaretçi ile Cloudflare arası (edge certificate'ı Cloudflare yönetir) ve Cloudflare ile origin arası. Mod, ikinci bağlantının nasıl kurulacağını belirler. Tablodaki CA (certificate veren kuruluş) sütunu, Cloudflare'in origin'in certificate'ını kimin imzalamış olmasını beklediğini gösteriyor. Cloudflare'in dokümanına göre:
| Mod | Cloudflare'den origin'e | Origin certificate'ı doğrulanır mı? |
|---|---|---|
| Off | HTTP (ziyaretçi tarafı da HTTP) | Hayır |
| Flexible | Her zaman HTTP | Hayır |
| Full | Ziyaretçinin protokolüyle aynı | Hayır (self-signed kabul edilir) |
| Full (strict) | Ziyaretçinin protokolüyle aynı | Evet (public CA veya Cloudflare Origin CA) |
| Strict (SSL-Only Origin Pull) | Her zaman HTTPS | Evet |
Yeni zone'larda varsayılan Automatic SSL/TLS: Cloudflare origin'i tarar ve çalışan en güvenli modu kendisi seçer, modu hiçbir zaman otomatik olarak düşürmez.
Flexible'ın ilk tehlikesi açık: ziyaretçi adres çubuğunda kilidi görüyor, ama verisi Cloudflare'den origin'e şifresiz gidiyor. İkincisi Önce Tahmin Et'teki durum. Laboratuvarda aynı kurulumu yaptım: Nginx edge ziyaretçiye HTTPS ile cevap veriyor, origin'e HTTP ile gidiyor. Origin'e de Cloudflare gibi CF-Connecting-IP ve X-Forwarded-Proto header'larını gönderiyor:
# laboratuvarda Cloudflare "Flexible": ziyaretçiye HTTPS, origin'e düz HTTP
server {
listen 8443 ssl;
server_name bookstore.example;
ssl_certificate /etc/nginx/certs/edge.crt;
ssl_certificate_key /etc/nginx/certs/edge.key;
location / {
proxy_pass http://origin;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header CF-Connecting-IP $remote_addr;
}
}
$ docker run --rm curlimages/curl:8.17.0 -sk --connect-to bookstore.example:443:host.docker.internal:8443 \
-L --max-redirs 5 -o /dev/null -w "final: %{http_code} after %{num_redirects} redirects\n" https://bookstore.example/api/books
final: 307 after 5 redirects
$ echo $?
47
$ docker run --rm curlimages/curl:8.17.0 -sk --connect-to bookstore.example:443:host.docker.internal:8443 \
-D - -o /dev/null https://bookstore.example/api/books | grep -iE "^(HTTP|location)"
HTTP/1.1 307 Temporary Redirect
Location: https://bookstore.example/api/books
Origin isteği HTTP olarak görüyor ve UseHttpsRedirection ziyaretçiyi aynı HTTPS adresine gönderiyor. Ziyaretçi tekrar Cloudflare'e geliyor, Cloudflare tekrar HTTP ile origin'e gidiyor; tarayıcıda bu "too many redirects" (ERR_TOO_MANY_REDIRECTS) hatası. curl beş yönlendirmeden sonra 47 koduyla bıraktı. Döngüyü origin'in X-Forwarded-Proto'ya güvenmesiyle kırmak mümkün, ama bu yalnızca belirtiyi giderir; origin bacağı yine şifresiz kalır.
Doğru çözüm origin'e bir certificate koyup Full (strict) kullanmak. İki seçenek var. Let's Encrypt: origin'de normal bir public certificate; SSL/TLS Certificate'ları ve HTTPS serisinin Let's Encrypt yazısındaki gibi, proxy arkasında HTTP-01'in sorun çıkarabileceğini hatırla ve DNS-01 kullan. Cloudflare Origin CA: Cloudflare panelinden 15 yıla kadar geçerli bir certificate üretilir. Yenilemesi kolay, ama yalnızca Cloudflare ona güvenir. Bir gün kaydı gri buluta alırsan veya Cloudflare'den ayrılırsan tarayıcılar bu certificate'ı reddeder. Taşınabilirlik isteyen Let's Encrypt'i, sadelik isteyen Origin CA'yı seçer. Bookstore Let's Encrypt kullanıyor, çünkü ikinci yazıdaki CAA kaydında letsencrypt.org zaten var. Cloudflare'in edge certificate'ları için de CAA izni gerekir; Cloudflare'in dokümanına göre Universal SSL açıkken zone'da CAA varsa Cloudflare kendi CA'ları için gereken CAA kayıtlarını otomatik ekliyor ve bunlar panelde görünmüyor, yalnızca dig ile görülüyor. Certificate ayrıntıları için SSL/TLS Certificate'ları ve HTTPS serisinin "Yönetilen Platformlarda Certificate" yazısına bak.
Page Rules'tan Cache Rules, Configuration Rules ve Redirect Rules'a
Eski rehberlerin çoğu Page Rules anlatır. Cloudflare, Page Rules'u legacy saydığını ve mevcut kuralları yeni ürünlere otomatik taşıyacağını duyurdu; yeni bir kurulumda Page Rules kullanmak için sebep yok. Karşılıklar: önbellek ayarları için Cache Rules, SSL modu gibi zone ayarlarını path bazında değiştirmek için Configuration Rules, yönlendirmeler için Redirect Rules'taki Single Redirects, origin'e giden host header'ı gibi ayarlar için Origin Rules. Yeni kurallar aynı path için Page Rules'tan önceliklidir. Kurallarda geçen TTL (cache süresi), cevabın edge'de ne kadar tutulacağını belirler. Bookstore'un ihtiyaçları ve karşılıkları:
| İhtiyaç | Kural | Eşleşme ifadesi | Aksiyon |
|---|---|---|---|
www'dan apex'e | Single Redirect | http.host eq "www.bookstore.example" | Dinamik hedef concat("https://bookstore.example", http.request.uri.path), 301, query string korunur |
| HTTP'den HTTPS'e | Always Use HTTPS veya Single Redirect | Bütün istekler | 301 |
| Kişiye özel API cevapları asla cache'lenmesin | Cache Rule | starts_with(http.request.uri.path, "/api/") and not starts_with(http.request.uri.path, "/api/books") | Bypass cache |
| Katalog cache'lensin | Cache Rule | starts_with(http.request.uri.path, "/api/books") | Eligible for cache; Edge TTL: "Use cache-control header if present, bypass cache if not" |
Dördüncü kural önemli. Cloudflare varsayılan olarak dosya uzantısına göre cache'ler; JS, CSS ve görseller cache'lenir, HTML ve JSON cache'lenmez. /api/books'un uzantısı yok, yani kural olmadan Cloudflare bu cevabı hiç saklamaz ve beşinci yazıda yazdığımız CDN-Cache-Control boşa gider. "Eligible for cache" ile origin'in header'larına uyulmasını söylüyoruz; header yoksa bypass. Böylece cache kararı yine origin'in kodunda kalıyor. Hash'li Angular dosyaları uzantıları sayesinde varsayılan olarak cache'leniyor ve immutable header'ını koruyor. Bu ifadeleri bir Cloudflare hesabında çalıştırmadım; Cloudflare'in Rules dili dokümanındaki alan ve fonksiyonlarla yazıldı. Kuralı canlıya almadan önce panelin "expression preview" ekranında ve bir staging host'unda dene.
Origin'de Gerçek Client IP
Proxy arkasında origin'in gördüğü bağlantı Cloudflare'in edge'inden geliyor. Rate limiting, audit log ve fraud kontrolleri için gerçek ziyaretçinin IP'si gerekir. Cloudflare bunu iki header'da gönderir: CF-Connecting-IP (tek değer, ziyaretçinin IP'si) ve X-Forwarded-For (zincirin sonuna ziyaretçinin IP'sini ekler). Forwarded Headers middleware'inin mekaniğini, middleware sırasını ve .NET 10'daki KnownIPNetworks'ü Web Server'lar ve Hosting serisinin "Reverse Proxy Arkasında ASP.NET Core" yazısında anlattık. Cloudflare'e özgü olan kısım, güvenilecek proxy listesinin Cloudflare'in yayımladığı aralıklar olması. Bu aralıkları bir dosyaya yazan script:
#!/usr/bin/env bash
# Cloudflare'in yayımladığı edge aralıklarını src/Bookstore.Api/cloudflare-ips.txt'ye yazar.
# CI'da günde bir ve deploy'da çalıştır; boş liste yazmak yerine hata ver.
set -euo pipefail
out=src/Bookstore.Api/cloudflare-ips.txt
json=$(curl -sf https://api.cloudflare.com/client/v4/ips)
jq -e '.success' <<<"$json" >/dev/null
jq -r '.result.ipv4_cidrs[], .result.ipv6_cidrs[]' <<<"$json" > "$out.new"
[[ $(wc -l < "$out.new") -gt 10 ]] || { echo "suspiciously short list" >&2; exit 1; }
mv "$out.new" "$out"
echo "etag $(jq -r '.result.etag' <<<"$json"), $(wc -l < "$out" | tr -d ' ') ranges"
$ ./scripts/update-cloudflare-ips.sh
etag 38f79d050aa027e3be3865e495dcc9bc, 22 ranges
Bookstore.Api tarafında bu dosyayı okuyan bir extension method:
using Microsoft.AspNetCore.HttpOverrides;
namespace Bookstore.Api;
public static class CloudflareForwarding
{
// CF-Connecting-IP ve X-Forwarded-Proto'ya yalnızca bağlantının kendisi Cloudflare'den geliyorsa güven.
public static IServiceCollection AddCloudflareForwarding(this IServiceCollection services, string rangesFile)
{
var ranges = File.ReadAllLines(rangesFile)
.Where(line => line.Length > 0)
.Select(System.Net.IPNetwork.Parse)
.ToList();
return services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.ForwardedForHeaderName = "CF-Connecting-IP";
options.ForwardLimit = 1;
options.KnownProxies.Clear();
options.KnownIPNetworks.Clear();
ranges.ForEach(options.KnownIPNetworks.Add);
});
}
}
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCloudflareForwarding(Path.Combine(builder.Environment.ContentRootPath, "cloudflare-ips.txt"));
builder.Services.AddHttpsRedirection(options => options.HttpsPort = 443);
var app = builder.Build();
app.UseForwardedHeaders();
app.UseHttpsRedirection();
// ...
api.MapGet("/whoami", (HttpContext http) =>
new { ClientIp = http.Connection.RemoteIpAddress?.ToString(), http.Request.Scheme });
ForwardedForHeaderName'i CF-Connecting-IP yapmak, X-Forwarded-For zincirini ayrıştırmaktan daha basit: tek bir değer, onu da Cloudflare yazıyor. KnownProxies ve KnownIPNetworks'ü temizlemek önemli; varsayılan listede loopback var. Davranışı gerçek bir Cloudflare bağlantısı olmadan test etmek için TestServer'da bağlantının kaynak IP'sini elle verdim. Biri Cloudflare'in aralığından (173.245.48.10), diğeri dışarıdan; ikisi de aynı sahte header'ları gönderiyor:
using System.Net;
using System.Text.Json;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
namespace Bookstore.Api.Tests;
public class ForwardedHeadersTests(WebApplicationFactory<Program> factory) : IClassFixture<WebApplicationFactory<Program>>
{
private record WhoAmI(string ClientIp, string Scheme);
private Task<HttpContext> SendFrom(string peer) =>
factory.Server.SendAsync(c =>
{
c.Request.Method = "GET";
c.Request.Scheme = "http";
c.Request.Host = new HostString("bookstore.example");
c.Request.Path = "/api/whoami";
c.Connection.RemoteIpAddress = IPAddress.Parse(peer);
c.Request.Headers["CF-Connecting-IP"] = "198.51.100.7";
c.Request.Headers["X-Forwarded-Proto"] = "https";
});
[Fact]
public async Task A_Cloudflare_edge_is_trusted()
{
var context = await SendFrom("173.245.48.10");
var who = await JsonSerializer.DeserializeAsync<WhoAmI>(context.Response.Body, JsonSerializerOptions.Web);
Assert.Equal("198.51.100.7", who!.ClientIp);
Assert.Equal("https", who.Scheme);
}
[Fact]
public async Task Anyone_else_is_not_trusted()
{
var context = await SendFrom("203.0.113.50");
// sahte header'lar yok sayılır: istek hâlâ düz HTTP, origin onu yönlendirir
Assert.Equal(StatusCodes.Status307TemporaryRedirect, context.Response.StatusCode);
Assert.Equal("https://bookstore.example/api/whoami", context.Response.Headers.Location.ToString());
}
}
$ dotnet test --logger "console;verbosity=normal"
Passed Bookstore.Api.Tests.ForwardedHeadersTests.A_Cloudflare_edge_is_trusted [168 ms]
Passed Bookstore.Api.Tests.ForwardedHeadersTests.Anyone_else_is_not_trusted [2 ms]
Total tests: 2
Passed: 2
Total time: 0.4751 Seconds
/api/whoami, Connection.RemoteIpAddress ve Request.Scheme'i döndüren küçük bir endpoint. Cloudflare'den gelen istekte ikisi de doğru düzeldi ve UseHttpsRedirection devreye girmedi. Dışarıdan gelen ve header'ları taklit eden istekte ise ikisi de yok sayıldı. Bu test, Önce Tahmin Et'teki döngünün neden Cloudflare arkasında olmayacağını da gösteriyor: Full (strict) ile istek origin'e zaten HTTPS ile gelir, Flexible'da bile güvenilen bir X-Forwarded-Proto yönlendirmeyi engeller. Aralıkları güncel tutmayı unutma: Cloudflare listeye yeni bir blok eklediğinde, eski listeyle çalışan origin o bloktan gelen kullanıcıların hepsini Cloudflare'in IP'si olarak görür. Script'i CI'da günde bir çalıştırmak ve değişince bir pull request açmak yeterli.
Alternatif: Azure Front Door Standard/Premium
Azure'da aynı kurulumun karşılığı Azure Front Door Standard veya Premium. Eşleşmeler şöyle: Cloudflare'deki nameserver taşıması yerine Front Door bir endpoint adı (*.azurefd.net) verir ve sen domain'ini ona CNAME ile bağlarsın; apex için ikinci yazıdaki Azure DNS alias record'u gerekir. Domain doğrulaması _dnsauth TXT'siyle yapılır. Cache, yönlendirme ve header işlemleri Front Door'un rules engine'iyle tanımlanır; route'larda query string davranışı (yok say, kullan, belirli parametreler) ayrıca seçilir. Origin'e giden istekte ziyaretçinin IP'si X-Forwarded-For ve X-Azure-ClientIP header'larında gelir. Güvenilecek kaynak aralıkları da Azure'un AzureFrontDoor.Backend service tag'inde yayımlanıyor.
Eski Azure ürünlerinden birini kullanıyorsan takvime dikkat et. Microsoft Learn'e göre Azure Front Door (classic) 31 Mart 2027'de, Azure CDN (içerik dağıtım ağı) Standard from Microsoft (classic) 30 Eylül 2027'de emekli oluyor. Classic Front Door'da 1 Nisan 2025'ten, classic CDN'de 15 Ağustos 2025'ten beri yeni kaynak oluşturulamıyor ve managed certificate desteği yok. İkisi için de önerilen hedef Front Door Standard/Premium ve Microsoft kesintisiz bir taşıma aracı sunuyor. Azure tarafındaki kurulumun ayrıntısı Cloud Temelleri serisinde.
Üretimde Dikkat
Origin'in IP'sini sır gibi koru. Proxy'nin koruması, saldırganın origin'e doğrudan gidemediği varsayımına dayanır. Origin IP'si çoğu zaman şu yollardan sızar: geçmiş DNS kayıtlarını saklayan veritabanları (Cloudflare'e geçmeden önceki A kaydı orada hâlâ duruyor), aynı sunucuyu gösteren ve DNS-only bırakılan bir isim (mail, ftp, direct), SPF (mail gönderebilecek IP'lerin listesi) kaydındaki ip4:'ler, origin'in kendi adına aldığı certificate'ların Certificate Transparency log'ları ve uygulamanın gönderdiği mail'lerin header'ları. Cloudflare'e geçtikten sonra origin'in IP'sini değiştirmek, eski IP'nin geçmişte kalmasını sağlar. Bir sonraki yazıda origin'i yalnızca Cloudflare'den gelen trafiğe açarak bu sorunu tamamen kapatacağız.
Header'ı yalnızca güvenilir kaynaktan oku. CF-Connecting-IP'yi KnownIPNetworks kontrolü olmadan okuyan bir origin'de, origin'e doğrudan ulaşabilen herkes bu header'ı yazarak istediği IP'yi taklit edebilir. Rate limiter'ın partition key'i bu IP'yse, saldırgan her istekte farklı bir IP yazıp limiti aşar.
Kuralları staging'de dene. Cache Rules ve Redirect Rules zone genelinde, birkaç saniyede bütün dünyaya yayılır. Cloudflare'de staging için ayrı bir zone ya da en azından ayrı bir hostname üzerinde test etmek, bir redirect döngüsünü production'da bulmaktan iyidir.
Cache ve SSL ayarlarını kod olarak yönet. Cloudflare'in kuralları da DNS kayıtları gibi Terraform veya DNSControl ile repo'da tutulabilir; panelden yapılan bir değişikliğin geçmişi yoktur.
Sık Düşülen Tuzaklar
Flexible'ı "geçici olarak" açmak: Origin'e certificate koymak bir saatlik iş; Flexible ise aylarca kalan bir güvenlik açığına ve Önce Tahmin Et'teki redirect döngüsüne dönüşür. Baştan Full (strict) ile başla.
Mail kayıtlarını proxy'lemek: Bir MX'in gösterdiği A kaydını turuncu buluta almak mail'i keser; proxy SMTP taşımaz. Mail ile ilgili isimler DNS-only kalmalı ve mümkünse origin'den farklı bir sunucuyu göstermeli.
Cloudflare IP listesini kopyalayıp unutmak: Origin'e sabit yazılmış eski bir liste, yeni bloklardan gelen ziyaretçileri yanlış tanımlar. Listeyi API'den otomatik güncelle.
JSON endpoint'lerin kendiliğinden cache'leneceğini sanmak: Cloudflare uzantısız path'leri varsayılan olarak cache'lemez. Header'lar doğru olsa bile katalog için bir Cache Rule gerekir.
Origin CA certificate'ı ile gri buluta geçmek: Cloudflare'i devre dışı bırakmak istediğin bir kesinti anında, Origin CA certificate'ı olan origin tarayıcılara güvenilmeyen bir certificate gösterir. Acil durum planında bu senaryoyu düşün.
Küçük Bir Deneme
★☆☆ İyi bildiğin üç sitenin apex adresini sorgula ve IP'lerin Cloudflare'in aralıklarında olup olmadığını bu yazıdaki Python satırıyla kontrol et. Hangisi proxied? curl -sI ile server ve cf-cache-status header'larına bak.
★★☆ Laboratuvardaki Flexible edge'ini Full'e çevir: origin'i Kestrel'de self-signed bir certificate'la HTTPS dinleyecek şekilde başlat, edge'in proxy_pass'ini https://'e çevir. Döngü kalkıyor mu? proxy_ssl_verify on eklediğinde ne oluyor ve bu Cloudflare'deki hangi moda karşılık geliyor?
★★★ update-cloudflare-ips.sh'ı bir CI/CD job'ına çevir: günde bir çalışsın, liste değiştiyse cloudflare-ips.txt'yi güncelleyen bir pull request açsın ve testleri çalıştırsın. Listenin boş veya çok kısa geldiği durumda job'ın kırıldığını doğrula.
Bookstore artık Cloudflare'in arkasında ve origin gerçek client IP'yi doğru okuyor. Ama origin hâlâ internete açık; IP'sini bilen herkes Cloudflare'i atlayabilir. Bir sonraki ve serinin son yazısında edge'de güvenliği ele alıyoruz: WAF, DDoS koruması, login ve sipariş endpoint'leri için rate limiting, bot yönetimi ve origin'i yalnızca CDN'e açmak.