Kendi sunucunuzda font, gizlilik mevzuatı ve bir eksik istek
Dışarıdan gelen font stili, sayfanız çizilmeden önce her ziyaretçinin IP adresini başka bir şirkete verir. Kendi sunucunuza almak bunu ve bir turu siler.
Sayfanın head kısmına konan iki satır, bir font ailesini dışarıdaki bir servisten getirir. Bir dakika sürer, tipografi yerine oturur ve kimse bir daha dönüp bakmaz. Aynı iki satır, sayfayı açan herkesin IP adresini ve açtığı sayfanın adresini, sizin içeriğinizden tek bir karakter çizilmeden önce başka bir şirkete bildirir. Avrupa'da da Türkiye'de de bu bir kişisel veri işleme faaliyetidir ve hesabını veren taraf site sahibidir.
Gerçekte ne oluyor
Başka bir origin'e giden stil bağlantısı, tarayıcının ziyaretçi adına yaptığı bir istektir ve her HTTP isteği dosya adından fazlasını taşır. Karşıdaki sunucuya IP adresi, user agent metni, kabul edilen diller ve stil dosyası söz konusu olduğunda onu isteyen belgenin adresi gider. Bu, hangi cihazın hangi sayfaya ne zaman baktığını bilmek için fazlasıyla yeterlidir.
Avrupa mevzuatı, bir kişiyle ilişkilendirilebildiği ölçüde IP adresini kişisel veri sayar. Avrupa Birliği Adalet Divanı 2016'da, site işletmecisinin elindeki dinamik adresler için bunu açıkça karara bağladı. Türk hukuku da aynı okumayı izler: IP adresi kişisel veridir ve yurt dışındaki bir sunucuya gönderilmesi kendi koşulları olan bir aktarımdır. Bu rejim 2024'te yeniden düzenlendi ve standart sözleşme metinleri de aktarım yollarından biri haline geldi.
İşi asıl zorlaştıran, bunun sayfanın neresinde olduğudur. Font stili head içindedir, yani istek HTML daha ayrıştırılırken gider. Sayfanın aşağısındaki bir rıza kutusu burada hiçbir işe yaramaz, çünkü aktarım kutu ortaya çıkmadan önce tamamlanmıştır. İstekten sonra alınan rıza süstür.
Bir Alman eyalet mahkemesi Ocak 2022'de konuyu somutlaştırdı. Dışarıdan font yükleyen bir sitenin, ziyaretçinin IP adresini hukuka aykırı biçimde üçüncü bir ülkeye aktardığına hükmetti, bunun durdurulmasına karar verdi ve davacıya yüz euro tazminat bağladı. Rakam hiçbir şey. Yayılan şey gerekçeydi: aynı fontlar sitenin kendi sunucusundan verilebileceği için aktarım zorunlu değildi. Ardından bir ihtarname dalgası geldi, bir kısmı fırsatçıydı, ama epey ekip fontlarını aceleyle taşıdı.
Hukuki tarafın yanında düpedüz bir performans sorunu da var. Dışarıdaki font size ikinci bir origin'e DNS sorgusu, TCP bağlantısı ve TLS el sıkışması getirir. Üstüne çoğu zaman üçüncü bir origin daha gelir, çünkü stil dosyası ile font dosyaları farklı sunucularda durur. Stil dosyası boyamayı bloklar, yani o gelene kadar hiçbir şey çizilmez, font dosyaları ise ancak o dosya ayrıştırıldıktan sonra keşfedilir. preconnect ipucu bağlantıyı önden ısıtır ama CSS için gereken fazladan turu ortadan kaldırmaz.
Eski karşı argüman ortak cache'ti: ziyaretçi aynı aileyi kullanan başka sitelere girmiştir, font zaten diskindedir. Tarayıcılar bir takip kanalını kapatmak için HTTP cache'ini üst seviye siteye göre böldüğünde bu doğru olmaktan çıktı. Chrome bölmeyi 2020'de, Firefox 2021 başında yayınladı, Safari ise yıllar önce yapmıştı. Bugün fontunuz, başka kaç site onu kullanırsa kullansın, sizin siteniz için yeniden indirilir. Ortak cache argümanı artık yalnızca kod incelemelerinde yaşıyor.
Nasıl görülür
İşe üretilmiş çıktıdan başlayın, çünkü font referansı HTML yerine bir stil dosyasının içinde saklanmış olabilir:
grep -rEoh 'https?://[a-zA-Z0-9.-]+' dist/*.html dist/*.css dist/**/*.css | sort -u
# https://ornek.comBu listede kendi origin'inizden başka ne varsa, ziyaretçilerinizin konuştuğu bir şirkettir. Sonra sayfanın kendisinden doğrulayın, böylece çalışma anında eklenen istekleri de yakalarsınız:
performance.getEntriesByType('resource')
.filter((r) => new URL(r.name).origin !== location.origin)
.map((r) => [new URL(r.name).host, r.initiatorType, Math.round(r.duration)]);Çözüm
Kendi sunucunuza almak dört adım ve bir saat sürer, üstelik bu sürenin çoğu lisans okumaya gider.
- Kullandığınız dosyaları woff2 olarak indirin ve lisans metnini yanlarına koyun. Açık font lisansları barındırmaya ve dağıtmaya izin verirken, bildirimin ve lisansın dosyalarla birlikte gitmesini şart koşar. Bazıları aile adını saklı tutar, yani değiştirilmiş veya alt kümelenmiş kopyanın adı farklı olmak zorunda kalabilir.
- Sitenin gerçekten çizebileceği karakterlere alt kümeleyin. Türkçe ve İngilizce bir site için bu, Latin harflerine ek olarak noktalı ve noktasız i ile diğer Türkçe harfler, noktalama ve rakamlar demektir.
- Face tanımlarını kendiniz yazın, gösterim stratejisini belirtin ve yedek font metriklerini eşleyin.
- Yalnızca ilk ekranın ihtiyacı olanı preload edin, dosyaları da hash'li adla sonsuza kadar cache'leyin.
import subsetFont from 'subset-font';
const kullanilan = new Set([...sayfaMetinleri, 'çğıİöşüÇĞÖŞÜ', '0123456789', '.,:;!?()[]{}'].join(''));
const woff2 = await subsetFont(await readFile(kaynak), [...kullanilan].join(''), {
targetFormat: 'woff2',
});@font-face {
font-family: "Site Sans";
src: url("/f/site-sans.b91c4e.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
unicode-range: U+0000-00FF, U+0100-017F, U+2000-206F;
size-adjust: 104%;
ascent-override: 92%;
}<link rel="preload" href="/f/site-sans.b91c4e.woff2" as="font" type="font/woff2" crossorigin>Preload satırındaki crossorigin isteğe bağlı değildir. Fontlar kendi origin'inizden bile CORS modunda çekilir, bu nitelik olmadan yapılan preload farklı bir istek sayılır, dosya iki kez iner ve preload sayfayı hızlandırmak yerine yavaşlatır.
Sunucu tarafında hash'li dosya adı, sert cache'leyip bir daha hiç düşünmemenizi sağlar:
location /f/ {
add_header Cache-Control "public, max-age=31536000, immutable";
add_header X-Content-Type-Options "nosniff";
types { font/woff2 woff2; }
}Katı bir içerik güvenlik politikası kullanıyorsanız, font-src 'self' satırı tam da bu noktada temenni olmaktan çıkıp gerçek olur. Sayfanın geri kalanında satır içi blokları hash'lerken tartışacağınız bir direktif azalır.
Çalıştığını nasıl doğrularsınız
Hukuken önemli olan ilk kontrol: listede başka hiçbir origin görünmemeli.
grep -rEoh 'https?://[a-zA-Z0-9.-]+' dist/*.html dist/*.css | sort -u | grep -v ornek.com
# (çıktı yok)
curl -sI https://ornek.com/f/site-sans.b91c4e.woff2 | grep -i 'cache-control\|content-type'
# cache-control: public, max-age=31536000, immutable
# content-type: font/woff2Sonra sayfayı boş cache ile açın ve ağ panelindeki bağlantı sayısına bakın. Eskiden üç origin varken tek origin kalır, font isteği de ilk birkaç milisaniyede başlar, çünkü önce gelmesi gereken bir stil dosyasının içinde keşfedilmek yerine preload edilmiştir. Yedek font metrikleriniz eşlenmişse geçiş satır sonlarını oynatmadan olur; bu ölçümün ayrıntısı alt kümeleme ve kayma yazısında duruyor.
Nelere dikkat etmeli
- Lisansı indirmeden sonra değil önce okuyun. Açık ailelerin çoğu sorunsuzdur, birkaç ticari aile yalnızca barındıran servis üzerinden lisanslıdır ve cevap bir blog yazısında değil lisans dosyasındadır.
- Alt kümelemeyi dikkatli yapın. Kullanıcı adları, alıntılanan metinler, para birimi işaretleri ve başka dildeki tek bir kelime alt kümenin dışına düşüp sessizce yedek fontla çizilebilir. O aralıklar için daha geniş bir face bırakın ya da yedeğe düşmeyi bilerek kabul edin.
- Variable font otomatik olarak küçük değildir. Tek bir variable dosya dört statik ağırlığı yenebilir, iki alt kümelenmiş statik dosyaya kaybedebilir de. İkisini de üretip byte'ları karşılaştırın.
- Her şeyi preload etmek, hiçbir şeyi preload etmemekle aynı hatadır. İlk ekran için iki dosya genelde doğru sayıdır, fazladan her preload HTML ve kritik CSS ile yarışır.
- Rıza kutusu head'deki isteği düzeltmez. İstek rızadan önce gidiyorsa kutu yalnızca kayıt tutmuş olur. Üçüncü taraf bir çağrıyı gerçekten rızaya bağlayacaksanız, o çağrı rıza gelene kadar hiç kurulmamalıdır. Fontta bunun en kolay yolu çağrıyı tümden ortadan kaldırmaktır.
- Cache başlıklarının sunucu yapılandırmasından sağ çıkması gerekir. Tek bir location bloğunun içine eklenen başlık, üstten miras alınanları sessizce düşürebilir; bu kendi başına bir tuzaktır.
Fontları kendi sunucunuza taşımak, hukuki gerekçenin, gizlilik gerekçesinin ve performans gerekçesinin aynı yöne baktığı ender değişikliklerden biri. Üstelik bir öğleden sonra sürer ve bir daha tekrarlanması gerekmez. Aynı zamanda iyi bir alışkanlık testi: sayfalarınızın head kısmındaki her üçüncü taraf referansı için birinin çıkıp neyin, kime gittiğini ve o satır olmasa neyin bozulacağını söyleyebilmesi gerekir. Dürüst cevap çoğu zaman, kimsenin niyet ettiğinden fazlasını gönderdiği ve kendi sunucunuzdaki bir kopyanın aynı işi göreceğidir.
Sorular ve cevaplar
- Üçüncü taraf font servisi kullanmak mevzuata aykırı mı?
- Otomatik bir ihlal değil, dayanak gerektiren bir kişisel veri aktarımı. Ziyaretçinin IP adresi, işin içinde olması gerekmeyen bir şirkete, genelde başka bir ülkeye, sayfa çizilmeden ve rıza alınma ihtimali doğmadan gider. Aynı fontun kendi sunucunuzdan servis edilebildiği ve bunun neredeyse hiçbir maliyeti olmadığı düşünülürse, aktarımın zorunlu olduğunu savunmak zor.
- Fontu kendi sunucuma almak sayfayı gerçekten hızlandırır mı?
- Genelde evet ve öngörülebilir biçimde. Başka bir origin'e yapılan DNS sorgusunu, TCP bağlantısını ve TLS el sıkışmasını ortadan kaldırırsınız. Üstüne, font dosyaları keşfedilmeden önce gelmesi gereken ve boyamayı bloklayan bir stil dosyası da kalkar. Yavaş mobil bağlantıda bu, ilk harfin çizilmesinden önceki birkaç yüz milisaniye demektir.
- Ortak cache savunması hâlâ geçerli mi?
- Değil. Tarayıcılar HTTP cache'ini artık üst seviye siteye göre anahtarlıyor, yani bir sitede indirilen font başka bir sitede yeniden kullanılmıyor. Chrome bu değişikliği 2020'de, Firefox 2021 başında yayınladı, Safari ise cache'ini yıllar önce bölmüştü. Fontu kaç sitenin kullandığı fark etmeksizin her ziyaretçi onu yeniden indirir.
- Açık lisanslı bir fontu kendi sunucuma alırken neyi saklamalıyım?
- Dosyaları kopyalamadan önce lisansı okuyun. Açık font lisansları genelde kendi sunucunuzda barındırmaya ve yeniden dağıtmaya izin verir, karşılığında lisans metninin ve telif bildiriminin dosyalarla birlikte gitmesini ister. Bazıları aile adını da saklı tutar, yani değiştirilmiş veya alt kümelenmiş dosyanın adını değiştirmeniz gerekebilir. Lisans dosyasını hem depoda hem servis ettiğiniz klasörde tutun.