24 Eylül 2025 Çarşamba

Docker Buildx ile Çok Mimarili (amd64/arm64) Container İmajı Oluşturma Rehberi

Giriş

Apple Silicon (ARM64), Raspberry Pi ve buluttaki x86 sunucular gibi farklı mimarileri hedeflemek artık modern uygulamalar için kaçınılmaz. Tek bir imajın hem amd64 hem de arm64 için çalışması, dağıtım ve bakım yükünü azaltır. Bu rehberde, Docker Buildx kullanarak çok mimarili (multi-arch) container imajı oluşturmayı, kayıt depolarına (registry) göndermeyi ve doğrulamayı adım adım anlatıyorum. Ayrıca pratik ipuçları ve sık karşılaşılan sorunlara da değineceğim.

Önkoşullar

- Docker Desktop 4.x (macOS/Windows) veya Docker Engine 24+ (Linux). Çoğu sistemde Buildx ve QEMU desteği dahili gelir.
- Registry hesabı (Docker Hub veya GitHub Container Registry: ghcr.io).
- Terminal erişimi ve temel Docker komutlarına aşinalık.

Adım 1: Buildx builder oluşturun

Linux sunucularda QEMU emülasyonu gerekebilir. Gerekirse şu komutla kurun:
docker run --privileged --rm tonistiigi/binfmt --install all

Buildx builder oluşturun ve varsayılan olarak atayın:
docker buildx create --name multi --driver docker-container --use
Kurulumun aktif olduğunu doğrulayın:
docker buildx ls

Adım 2: Örnek Dockerfile (Node.js)

Aşağıdaki Dockerfile, hem amd64 hem de arm64 için derlenebilen basit bir Node.js uygulamasını paketler. Dikkat edilmesi gereken nokta, derleme aşamasında --platform=$BUILDPLATFORM kullanımıdır; bu, builder konteynerinin mimarisine uygun taban imajı çekerek tutarlı derleme sağlar.

# syntax=docker/dockerfile:1.6
ARG NODE_VERSION=20-alpine
FROM --platform=$BUILDPLATFORM node:${NODE_VERSION} AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN npm run build || echo "derlenecek bir şey yok"

FROM node:${NODE_VERSION}
WORKDIR /app
COPY --from=builder /app ./
EXPOSE 3000
CMD ["node", "server.js"]

Not: Base imaj olarak node:20-alpine çok mimarili manifest içerir. Uygulamanız Go, Rust veya Python ise benzer yaklaşımla çok mimari derleme yapabilirsiniz. Go için CGO_ENABLED=0 gibi bayraklarla statik build tercih edilebilir.

Adım 3: Çok mimarili build ve push

Önce kayıt deposuna giriş yapın:
docker login ghcr.io

Tek komutla her iki mimari için imaj üretip manifest list olarak push edin:
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t ghcr.io/kullanici/uygulama:1.0 \
-t ghcr.io/kullanici/uygulama:latest \
--push .

Build süresini kısaltmak için --provenance=false veya uzak cache kullanabilirsiniz:
--cache-to type=registry,ref=ghcr.io/kullanici/uygulama:cache,mode=max
--cache-from type=registry,ref=ghcr.io/kullanici/uygulama:cache

Doğrulama

Manifest’ı inceleyin ve mimarileri kontrol edin:
docker buildx imagetools inspect ghcr.io/kullanici/uygulama:latest

Çıktıda Platforms: linux/amd64, linux/arm64 görmelisiniz. Farklı cihazlarda docker run çalıştırdığınızda, Docker otomatik olarak uygun mimariye karşılık gelen imajı çekecektir.

Çalıştırma

Yerelde test etmek için:
docker run -p 3000:3000 ghcr.io/kullanici/uygulama:latest
Sunucu başlatıldıktan sonra http://localhost:3000 üzerinden uygulamayı doğrulayın.

Sık karşılaşılan sorunlar ve ipuçları

Manifest bulunamadı: “no matching manifest” hatası alıyorsanız, seçtiğiniz base imajın çok mimarili desteği olmayabilir. Debian/Alpine gibi resmi imajların çoğu multi-arch’tır; özel imajlar için alternatife geçin.

Illegal instruction: Özellikle kriptografik kütüphaneler kullanan Node/Go projelerinde CPU özelliği uyumsuzluğu görülebilir. Derleme sırasında hedef mimarinin özellikleriyle uyumlu bayraklar kullanın veya musl/glibc farklarını göz önünde bulundurun.

Performans yavaşlığı: QEMU emülasyonu altında yerel olmayan mimariyi derlemek yavaş olabilir. Mümkünse arm64 runner (ör. Graviton) veya amd64 runner kullanarak native build tercih edin.

Deterministik build: npm ci, package-lock.json ve versiyon sabitleme kullanın. Go için mod dosyalarını kilitleyin, Python için requirements.txt sabitleyin.

--platform ve --build-arg: Dockerfile içinde FROM --platform=$BUILDPLATFORM kullanın, ancak çalışma katmanını mimari bağımsız tutmaya özen gösterin. Yer yer TARGETPLATFORM ile koşullu bağımlılık kurabilirsiniz.

GitHub Actions ile otomasyon (kısa örnek)

name: Build and Push Multi-Arch
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ghcr.io/kullanici/uygulama:latest

Sonuç

Docker Buildx ile çok mimarili imaj üretmek, farklı cihaz ve bulut altyapılarında aynı etiketle sorunsuz dağıtım yapmanızı sağlar. Doğru base imaj seçimi, QEMU/runner stratejisi ve cache kullanımıyla süreç hem hızlı hem de tekrarlanabilir hale gelir. Bu rehberdeki adımları CI/CD hattınıza taşıyarak, amd64 ve arm64 dünyalarını tek bir manifest altında birleştirebilirsiniz.

23 Eylül 2025 Salı

Next.js 14’te Server Actions ile Güvenli Form ve Dosya Yükleme: Adım Adım Rehber

Giriş

Next.js 14 ile birlikte hayatımıza giren Server Actions, form işlemleri ve veri mutasyonlarını API katmanı yazmadan, doğrudan sunucuda çalıştırılabilir fonksiyonlarla yönetmemizi sağlıyor. Bu yaklaşım hem güvenliği artırıyor hem de geliştirici deneyimini iyileştiriyor. Bu yazıda, App Router mimarisi altında Server Actions kullanarak güvenli form işleme ve dosya yükleme senaryosunu adım adım ele alacağız. Ayrıca performans, SEO ve güvenlik tarafındaki püf noktalarına da değineceğiz.

Önkoşullar ve Kurulum

Başlamadan önce Node.js 18+ ve Next.js 14 ortamınız hazır olmalı. Projeyi TypeScript ile başlatmanızı öneririm; tip güvenliği hem sunucu eylemlerinde hem de form verisi doğrulamada büyük kolaylık sağlar. App Router (app/ dizini) kullanıyorsanız, sayfalarınız React Server Components olarak varsayılan şekilde sunulur; bu sayede istemciye daha az JavaScript gönderilir ve SEO performansınız artar.

Server Actions Mantığı

Server Actions, bir fonksiyonun başına "use server" yönergesi eklenerek sunucuda çalıştırılmasını sağlar. Bu fonksiyonları doğrudan formun action props’una bağlayabilir ve formData alabilirsiniz. Ek bir API route yazmanız gerekmez. İş mantığı sunucuda kaldığı için token, bağlantı string’i ve gizli anahtarlar istemciye sızmaz. İşlem sonrası önbelleği tazelemek için revalidatePath() veya revalidateTag() çağırabilirsiniz.

Form Doğrulama Stratejisi

Doğrulama iki katmanda yapılmalı: istemci tarafında kullanıcı deneyimini iyileştiren anlık kontroller (örneğin e-posta formatı), sunucu tarafında ise kaynak güvenliği sağlayan kesin doğrulamalar. Server Actions içinde zod gibi bir şema doğrulama kütüphanesi kullanarak tip güvenli ve anlaşılır hata mesajları üretin. Hataları action’dan geriye döndürüp formda kullanıcıya göstermek, klasik API isteklerine göre daha yalın bir akış sağlar.

Dosya Yükleme: Route Handler mı, Server Action mı?

Basit senaryolarda formunuzdaki dosya alanını Server Action içinde formData.get("file") ile alabilirsiniz. Ancak büyük dosyalar, virüs taraması veya üçüncü taraf depolama (S3, R2 vb.) gerekiyorsa Route Handlers (app/route.ts) tercih edin. Bu sayede streaming ile bellek kullanımını kontrol edebilir, sınırları (limits) ve doğrulamayı daha esnek yönetebilirsiniz. Platformunuza göre runtime seçimi önemlidir: Node özelliklerine ihtiyaç varsa export const runtime = "nodejs" kullanın; global edge ağı üzerinde düşük gecikme istiyorsanız "edge" seçeneğini değerlendirin.

Adım Adım Senaryo: Profil Formu + Avatar Yükleme

1) Formu Tasarlayın: İsim, e-posta, kısa bio ve avatar dosya alanı ekleyin. Geriye dönüt için alan bazlı hata mesajları ve formun gönderim durumunu göstermek üzere bir yükleniyor göstergesi ekleyin.

2) Server Action Yazın: "use server" ile başlayan saveProfile fonksiyonu, formData içinden girişleri okur. zod ile isim ve e-posta zorunlu, bio uzunluğu sınırlı olacak şekilde doğrulayın. Doğrulama hatalarını sade bir nesne olarak geri döndürün.

3) Avatar İçin Doğrulama: MIME türü (image/jpeg, image/png), dosya boyutu (ör. 2 MB sınır), ve görüntü boyutları (ör. 1024x1024 üstü reddedilsin) kontrol edin. Şüpheli içerik için içerik taraması gerekiyorsa, asenkron bir kuyruk (örn. SQS, Pub/Sub) veya webhook tabanlı işleme düşünebilirsiniz.

4) Depolama Stratejisi: Büyük dosyaları doğrudan Server Action üzerinden aktarmak yerine, istemcide önceden imzalı URL (pre-signed URL) alıp doğrudan depolamaya yüklemek daha verimlidir. Bu yaklaşım, sunucu trafiğini azaltır ve edge bölgelerinde daha hızlıdır. Ardından Server Action sadece meta veriyi (dosya URL’si) veritabanına kaydeder.

5) Önbellek ve Yeniden Doğrulama: Profil sayfanız statikse bile güncelleme sonrası revalidatePath("/profil") ile görünümü anında tazeleyin. Eğer profil verilerini cache tag ile etiketlediyseniz, revalidateTag("profil") çağrısı da etkili olacaktır.

6) UX İyileştirmeleri: Progressive enhancement mantığıyla, JavaScript kapalıyken dahi form çalışmalı; JS açıkken ise iyileştirmeler devreye girmeli. useFormStatus ile buton durumunu yönetin, belirli alanlar için optimistic UI uygulayın.

Güvenlik İpuçları

CSRF: Server Actions form gönderiminde varsayılan olarak korumalı bir yol sağlar; yine de hassas işlemlerde ek kontrol (ör. origin doğrulama) uygulayın. Rate Limiting: Brute-force girişimleri için IP veya token bazlı sınırlama ekleyin. Dosya Güvenliği: İçerik türü ve boyut kontrolü zorunlu; antivirüs taraması ve izole geçici depolama ile zinciri güçlendirin. Gizli Anahtarlar: Tüm sırları process.env üzerinden sunucuda okuyun; istemciye sızdırmayın.

Performans ve SEO

App Router ile sayfalarınız server-rendered çalıştığı için ilk yükleme süresi ve SEO performansı güçlüdür. Server Actions, veri mutasyonunu aynı kökten ele aldığından fazladan JSON döndürme ve istemci durum yönetimi yükünü azaltır. Yalnızca değişmesi gereken segmentleri yeniden doğrulamak, gereksiz yeniden oluşturma maliyetini düşürür. Görsel ve statik varlıklar için HTTP cache başlıklarını doğru ayarlayın, kritik CSS’i minimal tutun.

Hata Ayıklama ve Test

Geliştirme sırasında action’larınızın giriş ve çıkışlarını ayrıntılı loglayın; hassas verileri loglardan uzak tutun. Birim testlerde, doğrulama şemalarını ve yan etkisiz iş mantığını izole ederek test edin. Uçtan uca testlerde (Playwright) gerçekçi form doldurma ve dosya yükleme akışlarını, hata durumlarını ve erişilebilirlik kontrollerini (klavye navigasyonu, ARIA etiketleri) kapsayın.

Sonuç

Next.js 14’te Server Actions, form ve dosya yükleme gibi günlük iş akışlarını basitleştirirken güvenlik ve performans avantajı da sağlar. Doğrulama, depolama ve önbellek stratejilerini doğru kurguladığınızda daha az kodla daha ölçeklenebilir bir çözüm elde edersiniz. Küçük bir profil formundan kurumsal bir içerik yönetim sistemine kadar aynı ilkelere dayanarak karmaşık senaryoları dahi güvenle kurgulayabilirsiniz.

22 Eylül 2025 Pazartesi

Passkey (WebAuthn) ile Şifresiz Giriş: Modern Web Uygulamalarına Adım Adım Entegrasyon

Passkey nedir ve neden şimdi?

Son yıllarda şifre sızıntıları, kimlik avı saldırıları ve kullanıcı deneyimi sorunları; geliştiricileri “şifresiz giriş” modellerine yöneltti. Passkey, FIDO2 ve WebAuthn standartlarını temel alarak kullanıcıların cihazlarında biyometrik (Face ID, Touch ID, Windows Hello) veya donanımsal güvenlik anahtarıyla güvenli, hızlı ve kimlik avına dayanıklı oturum açmalarını sağlar. Chrome, Safari, Edge ve Firefox’un güncel sürümleri ile iOS, Android ve Windows ekosistemleri passkey’i yerel olarak destekliyor.

Mimariye hızlı bakış

Passkey, sunucu (Relying Party) ve tarayıcı/cihaz (Authenticator) arasında challenge temelli bir akış kullanır. Sunucu, kayıt veya giriş için benzersiz bir challenge üretir; istemci tarafında navigator.credentials.create() (kayıt) veya navigator.credentials.get() (giriş) çağrısı yapılır ve oluşan kriptografik yanıt sunucuya geri gönderilir. Sunucu, bu yanıtı doğrular ve oturum açılır.

Önkoşullar ve en iyi uygulamalar

- Üretimde HTTPS zorunludur (localhost geliştirmede istisna).
- RP ID alan adınız olmalı (örn. example.com). Alt alan adılarında doğrulama için RP ID’yi üst alan adına ayarlayın.
- Kullanıcı kimlikleri ve cihazdan dönen credential ID’leri veritabanında güvenle saklanmalı.
- Kimlik avına dayanıklılık için cross-origin isteklerden kaçının; Origin ve Relying Party ID tutarlı olmalı.

Adım adım: Basit bir Node.js/Express ve WebAuthn entegrasyonu

Örnek, sunucuda @simplewebauthn/server kütüphanesini kullanır. İstemci tarafında ise tarayıcı API’lerini çağırıyoruz. Bu iskelet, tek başına üretime hazır değildir; amaç kavramı göstermektir.

1) Sunucuyu hazırlayın

// server.js
import express from 'express';
import cors from 'cors';
import session from 'express-session';
import {
  generateRegistrationOptions,
  verifyRegistrationResponse,
  generateAuthenticationOptions,
  verifyAuthenticationResponse,
} from '@simplewebauthn/server';

const app = express();
app.use(cors({ origin: 'https://app.example.com', credentials: true }));
app.use(express.json());
app.use(session({ secret: 'change-me', resave: false, saveUninitialized: true }));

// Demo bellek içi depolar
const users = new Map(); // userId -> { id, username, credentials: [] }

const rpID = 'example.com';
const rpName = 'Örnek Uygulama';

// Kayıt: seçenek üret
app.post('/webauthn/register/options', (req, res) => {
  const { username, userId } = req.body;
  let user = users.get(userId);
  if (!user) {
    user = { id: userId, username, credentials: [] };
    users.set(userId, user);
  }
  const options = generateRegistrationOptions({
    rpName,
    rpID,
    userID: user.id,
    userName: user.username,
    attestationType: 'none',
    excludeCredentials: user.credentials.map(c => ({ id: c.id, type: 'public-key' })),
    authenticatorSelection: { residentKey: 'preferred', userVerification: 'preferred' },
  });
  req.session.currentChallenge = options.challenge;
  res.json(options);
});

// Kayıt: doğrula
app.post('/webauthn/register/verify', async (req, res) => {
  const { userId, attResp } = req.body;
  const user = users.get(userId);
  const verification = await verifyRegistrationResponse({
    response: attResp,
    expectedChallenge: req.session.currentChallenge,
    expectedOrigin: 'https://app.example.com',
    expectedRPID: rpID,
  });
  if (verification.verified) {
    const { credentialPublicKey, credentialID, counter } = verification.registrationInfo;
    user.credentials.push({ id: credentialID, publicKey: credentialPublicKey, counter });
  }
  res.json({ ok: verification.verified });
});

// Giriş: seçenek üret
app.post('/webauthn/login/options', (req, res) => {
  const { userId } = req.body;
  const user = users.get(userId);
  const options = generateAuthenticationOptions({
    rpID,
    userVerification: 'preferred',
    allowCredentials: user ? user.credentials.map(c => ({ id: c.id, type: 'public-key' })) : [],
  });
  req.session.currentChallenge = options.challenge;
  res.json(options);
});

// Giriş: doğrula
app.post('/webauthn/login/verify', async (req, res) => {
  const { userId, authResp } = req.body;
  const user = users.get(userId);
  const dbCred = user.credentials.find(c => Buffer.compare(c.id, Buffer.from(authResp.rawId, 'base64url')) === 0);
  const verification = await verifyAuthenticationResponse({
    response: authResp,
    expectedChallenge: req.session.currentChallenge,
    expectedOrigin: 'https://app.example.com',
    expectedRPID: rpID,
    authenticator: dbCred,
  });
  if (verification.verified) {
    dbCred.counter = verification.authenticationInfo.newCounter;
    // Burada oturumu işaretleyin (req.session.userId = userId gibi)
  }
  res.json({ ok: verification.verified });
});

app.listen(3000, () => console.log('Server listening on http://localhost:3000'));

2) İstemci tarafı: Kayıt ve giriş akışı

// register.js (tarayıcı)
async function startRegistration(username, userId) {
  const opts = await fetch('/webauthn/register/options', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({ username, userId })
  }).then(r => r.json());

  // ArrayBuffer alanlarını dönüştürün
  opts.challenge = base64urlToBuffer(opts.challenge);
  opts.user.id = new TextEncoder().encode(opts.user.id);

  const cred = await navigator.credentials.create({ publicKey: opts });
  const attResp = credentialToJSON(cred);
  const res = await fetch('/webauthn/register/verify', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({ userId, attResp })
  }).then(r => r.json());
  return res.ok;
}

async function startLogin(userId) {
  const opts = await fetch('/webauthn/login/options', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({ userId })
  }).then(r => r.json());

  opts.challenge = base64urlToBuffer(opts.challenge);
  opts.allowCredentials = (opts.allowCredentials || []).map(a => ({ ...a, id: base64urlToBuffer(a.id) }));

  const assertion = await navigator.credentials.get({ publicKey: opts });
  const authResp = credentialToJSON(assertion);
  const res = await fetch('/webauthn/login/verify', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({ userId, authResp })
  }).then(r => r.json());
  return res.ok;
}

// Yardımcılar
function base64urlToBuffer(b64url) {
  const pad = '='.repeat((4 - (b64url.length % 4)) % 4);
  const b64 = (b64url + pad).replace(/-/g, '+').replace(/_/g, '/');
  const raw = atob(b64);
  const buf = new ArrayBuffer(raw.length);
  const view = new Uint8Array(buf);
  for (let i = 0; i < raw.length; ++i) view[i] = raw.charCodeAt(i);
  return buf;
}

function credentialToJSON(cred) {
  return JSON.parse(JSON.stringify(cred, (k, v) => v instanceof ArrayBuffer
    ? bufferToBase64url(v)
    : v));
}

function bufferToBase64url(buf) {
  const bytes = new Uint8Array(buf);
  let binary = '';
  for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
  return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/,'');
}

Güvenlik, UX ve üretim tavsiyeleri

- Kullanıcı adısız (usernameless) giriş için “resident key” tercih edin ve uygun akışı tasarlayın.
- Birden fazla passkey kaydına izin vererek cihaz kaybına karşı dayanıklılık sağlayın.
- Platform passkey (cihazda) ile çapraz platform passkey (iCloud Keychain, Google Password Manager) farklarını kullanıcılara açıklayın.
- Hata yönetimini özenle yapın: tarayıcıda NotAllowedError vb. hataları kullanıcı dostu mesajlara çevirin.
- Oturum yönetiminde kısa ömürlü JWT veya güvenli, HttpOnly, SameSite=strict cookie tercih edin.

Sorun giderme

- Origin ve RP ID uyuşmazlığı en sık hatadır: “https://app.example.com” ile rpID “example.com” olmalı.
- Sunucunuz ve istemci cihazınızın saat farkları challenge doğrulamasını bozabilir; NTP senkronizasyonunu sağlayın.
- Geliştirme aşamasında sadece localhost özel izni vardır; kendi alan adınızda test ederken mutlaka HTTPS kullanın.
- Kurumsal ortamlarda WebAuthn politikaları kısıtlanmış olabilir; tarayıcı ve OS politikalarını kontrol edin.

Sonuç

Passkey/WebAuthn, hem güvenlik hem de kullanıcı deneyimi tarafında anlamlı bir sıçrama sunuyor. Doğru RP ID, sağlam challenge yönetimi ve tutarlı origin politikasıyla kurulum basit hale geliyor. Üretime geçişte çoklu cihaz desteği, kullanıcı eğitimleri ve geri dönüş (fallback) stratejileri planlandığında, şifresiz geleceğe hazır bir kimlik doğrulama katmanı elde edebilirsiniz.

21 Eylül 2025 Pazar

HTTP/3 (QUIC) Nedir? Nginx ve Cloudflare Üzerinde Etkinleştirme Rehberi

HTTP/3 ve QUIC neden önemli?

Web sitelerinin hızlı yüklenmesi, hem kullanıcı deneyimi hem de SEO açısından belirleyicidir. HTTP/3, Google’ın QUIC taşıma protokolü üzerine inşa edilen en yeni HTTP sürümüdür ve UDP üzerinden çalışır. Bağlantı kurulumu için gereksiz el sıkışmaları ortadan kalkar, paket kaybı durumunda satır sonu tıkanması azalır ve özellikle mobil ile yüksek gecikmeli ağlarda belirgin hız kazanımı sağlar. Bu sayede TTFB düşer, etkileşim metrikleri iyileşir ve Core Web Vitals performansınız olumlu etkilenir.

HTTP/3 vs. HTTP/2: Öne çıkan farklar

HTTP/2 TCP üzerinde çalışırken, HTTP/3 QUIC sayesinde UDP kullanır. Bu mimari fark, bağlantı geçişlerinde (ör. Wi‑Fi’den 4G’ye) ve paket kaybı yaşanan ortamlarda akışların birbirini beklememesini sağlar. Üstelik 0‑RTT oturum yenileme sayesinde tekrar bağlanan kullanıcılar daha az gecikme yaşar. Sonuç olarak, aynı içerik daha akıcı ve daha hızlı sunulur.

Ön gereksinimler ve uyumluluk

HTTP/3 bugün Chrome, Edge, Firefox ve Safari’nin güncel sürümlerinde desteklenir. Sunucu tarafında ise iki kritik gereksinim ortaya çıkar: UDP/443 trafiğinin güvenlik duvarında açık olması ve TLS 1.3 desteği. Ayrıca Nginx gibi web sunucularında HTTP/3 desteği için doğru sürüm ve uygun TLS kitaplığı (OpenSSL’in QUIC destekli bir sürümü, BoringSSL veya quictls) gerekir.

Cloudflare üzerinde HTTP/3’ü etkinleştirme

Cloudflare kullanıyorsanız, HTTP/3 etkinleştirmek birkaç tıklama kadar kolaydır. Cloudflare panelinde alan adınızı seçin, Network sekmesine girin ve HTTP/3 (with QUIC) seçeneğini On konumuna getirin. Cloudflare, ziyaretçilere Alt-Svc başlığı ile HTTP/3’ü ilan eder ve QUIC üzerinden içerik sunmaya başlar. Bu aşamada ek bir sunucu yapılandırması gerekmeyebilir; ancak kaynak sunucunuzun HTTP/2 veya HTTP/1.1 için sağlıklı cevap verdiğinden emin olun.

Nginx’te HTTP/3 (QUIC) kurulum adımları

HTTP/3’ü doğrudan Nginx’te sunmak istiyorsanız, önce HTTP/3 modülü destekli bir Nginx derlemesine ihtiyaç vardır. En güncel mainline Nginx sürümünü kullanın ve derleme sırasında HTTP/3 modülünü etkinleştirin. Ayrıca QUIC destekli bir TLS kütüphanesi (örneğin OpenSSL’in QUIC desteği olan bir sürümü veya BoringSSL/quictls) ile derleme yapmanız gerekir.

Yapılandırma tarafında, site (server) bloğunuzda hem klasik TLS hem de QUIC için dinleme direktifleri ekleyin. Tipik olarak 443 portu için iki dinleme satırı kullanılır: biri listen 443 ssl; diğeri listen 443 quic reuseport;. TLS 1.3’ü açın ve geçerli bir sertifika/anahtar atayın. İstemcilerin HTTP/3’ü kolay keşfetmesi için Alt-Svc başlığı tavsiye edilir; örneğin Alt-Svc: h3=":443"; ma=86400 gibi. Böylece tarayıcılar sonraki isteklerde HTTP/3 yolunu tercih eder.

Konfigürasyon güncellemesinden sonra Nginx’i hatasız yeniden başlatın. Güvenlik duvarında UDP 443’ün gerçekten açık olduğundan emin olun; aksi halde tarayıcılar HTTP/3’e geçemeyip HTTP/2’ye geri döner.

Doğrulama ve test

Hızlı bir kontrol için tarayıcınızın geliştirici araçlarındaki Network panelinde ilgili isteğin Protocol sütununa bakın; h3 görüyorsanız HTTP/3 aktif demektir. Alternatif olarak HTTP/3 destekli bir curl sürümüyle başlıkları sorgulayabilirsiniz: curl --http3 -I https://alanadiniz.com. Dönen yanıtta alt-svc başlığı ve protokolün h3 olduğuna dair işaretler görmelisiniz. Dış doğrulama için çevrimiçi HTTP/3 test araçlarını da kullanabilirsiniz.

Performans ipuçları ve en iyi uygulamalar

HTTP/3 tek başına bir sihirli değnek değildir; ancak iyi bir önbellekleme stratejisi, doğru cache-control başlıkları, Early Hints (103) ve kaynak önceliklendirmesiyle birleştiğinde etkisi katlanır. Resimleri modern formatlara (AVIF/WebP) taşıyın, kritik CSS’i optimize edin ve CDN’inizi edge’de önbelleklemek üzere yapılandırın. Mobil ağlarda daha da iyi sonuç için DNS çözümleme sürelerini kısaltın ve gereksiz üçüncü taraf istekleri budayın.

Sorun giderme: En sık görülen engeller

- UDP kapalı: Birçok güvenlik duvarı varsayılan olarak UDP 443’ü engeller. Kuralı açın ve sağlayıcınızın UDP’yi desteklediğinden emin olun.
- Ortak barındırma kısıtları: Bazı paylaşımlı hosting ortamlarında HTTP/3 henüz sunulmaz. Bu durumda bir CDN üzerinde HTTP/3’ü etkinleştirmek pratik bir ara çözümdür.
- Yanlış TLS kitaplığı: Nginx derlemenizde QUIC destekli bir TLS kitaplığı kullanmadıysanız HTTP/3 aktif olmayacaktır. Sürüm ve yapı bayraklarını gözden geçirin.
- Orta katman proxy’ler: WAF, DDoS koruması veya ek proxy katmanları UDP’yi bozabilir. Trafik zincirindeki her bileşenin HTTP/3 uyumluluğunu doğrulayın.

SEO ve iş etkisi

Daha hızlı bağlantı kurulumu ve paket kaybına dayanıklı aktarım, özellikle mobil kullanıcıların ilk etkileşim süresini düşürür. Bu, LCP ve FID/INP gibi metriklere olumlu yansır, hemen çıkma oranlarını azaltır ve dönüşüm oranlarını artırabilir. Arama motorları doğrudan “HTTP/3 kullanıyor musunuz?” diye puan vermez; fakat hız ve kullanıcı deneyimi sinyalleri arka planda sıralamayı etkiler. Kısacası HTTP/3, teknik borcunuzu azaltan ve yatırımı hızlı geri ödeyen bir yükseltmedir.

Sonuç

HTTP/3 (QUIC), günümüzün değişken ve gürültülü ağ koşullarında web’i daha hızlı ve dayanıklı kılan önemli bir adımdır. Cloudflare gibi CDN’lerle dakikalar içinde aktif edebilir, Nginx üzerinde ise doğru sürüm ve TLS kitaplığıyla uçtan uca kontrol sağlayabilirsiniz. UDP 443’ü açmayı, TLS 1.3’ü etkinleştirmeyi ve Alt-Svc ilanını eklemeyi unutmayın. Doğrulama testlerinden sonra performans metriklerinizi izleyin; çoğu sitede ölçülebilir iyileşme göreceksiniz.

20 Eylül 2025 Cumartesi

Parolasız Gelecek: WebAuthn Passkey Entegrasyonu ile Güvenli Giriş (Next.js Örneği)

Parolasız Gelecek: WebAuthn Passkey Entegrasyonu ile Güvenli Giriş (Next.js Örneği)

Parolalar, yıllardır sızıntıların ve kimlik avı saldırılarının baş aktörü oldu. Passkey (WebAuthn + FIDO2) yaklaşımı, biyometrik doğrulama (Touch ID, Windows Hello, Android Biometrics) veya donanım anahtarı ile tek dokunuşla güvenli oturum açmayı mümkün kılar. Bu yazıda, güncel tarayıcılar ve işletim sistemleriyle uyumlu passkey altyapısını nasıl kuracağınızı, geliştirici bakışıyla adım adım anlatıyorum. Örnek teknoloji olarak Next.js kullanacağız ancak anlatım, API uç noktaları olan her yığını kapsar.

Passkey Nedir? Passkey, kullanıcının cihazında güvenli bir şekilde saklanan asimetrik anahtar çifti ile çalışır. Sunucu yalnızca genel anahtarı tutar, gizli anahtar cihazdan çıkmaz. Oturum açma akışı; origin, RP ID (Relying Party ID) ve kullanıcı doğrulaması gibi bağlamlarla sınırlandırıldığı için kimlik avı ve kimlik bilgisi doldurma saldırılarına karşı son derece dirençlidir.

Neden Passkey?

- Kimlik avına dayanıklı: İmzalama süreci etki alanına (origin) bağlıdır, sahte sitelerde işe yaramaz.
- Kullanıcı deneyimi: Tek dokunuş, yüz tanıma ya da PIN ile saniyeler içinde giriş.
- Çoklu cihaz desteği: iCloud Keychain, Google Password Manager gibi kasalarla cihazlar arası senkronizasyon.

Mimari Özet ve Gereksinimler

Sunucu tarafında challenge üretir, saklar ve istemciye gönderirsiniz. İstemci bu challenge ile cihazdaki authenticator üzerinden kayıt (registration) veya giriş (assertion) akışını tamamlar; dönen yanıtı sunucuya iletir ve sunucu WebAuthn kurallarına göre doğrular. Sunucunuzda TLS zorunlu olmalı (localhost geliştirmenin istisnasıdır). RP ID genellikle alan adınızın köküdür (ör. example.com). Veritabanında kullanıcı, keyId, publicKey, alg, signCount gibi alanlar saklanır.

Kayıt (Registration) Akışı Adımları

1) Kullanıcı e-postasını veya benzersiz kimliğini alıp sunucunuza gönderin. Sunucu, PublicKeyCredentialCreationOptions üretir: challenge (base64url), rp.id, rp.name, user.id, user.name, pubKeyAlgo listesi (örn. -7 ES256, -257 RS256), authenticatorSelection (residentKey, userVerification) ve timeout gibi alanları içerir.

2) İstemci tarafında navigator.credentials.create() ile native WebAuthn API’sini çağırın. Dönen yanıt, attestationObject ve clientDataJSON içerir.

3) Bu verileri base64url ile sunucuya POST edin. Sunucu, attestation’ı doğrular; origin, challenge eşleşmesi, RP ID hash kontrolü ve sertifika zinciri doğrulaması yapar. Başarılıysa kullanıcıya ait publicKey, keyId ve signCount’ı veritabanına kaydeder.

Giriş (Authentication) Akışı Adımları

1) Sunucu, PublicKeyCredentialRequestOptions üretir: challenge, rpId, allowCredentials (kayıtlı anahtarlar) ve userVerification.

2) İstemci, navigator.credentials.get() çağırır ve authenticator’dan imzalı assertion alır: authenticatorData, clientDataJSON ve signature.

3) Sunucu; challenge, origin, rpIdHash doğrular; publicKey ile imzayı denetler ve signCount güncellenir. Ardından oturum açma token’ı veya session başlatılır.

Next.js ile Minimal Örnek Mantığı

- /api/webauthn/register/options: Kullanıcı kimliği ile çağrılır, creationOptions döner ve server-side Session’a challenge yazılır.
- /api/webauthn/register/verify: İstemciden gelen attestation yanıtını doğrular ve anahtarı kaydeder.
- /api/webauthn/login/options: Kullanıcının kayıtlı keyId’lerine göre requestOptions üretir, challenge’ı saklar.
- /api/webauthn/login/verify: Assertion’ı doğrular, session veya JWT üretir.

Doğrulama adımları için community tarafından desteklenen simplewebauthn gibi kütüphaneler süreci kolaylaştırır. İstemci tarafında base64url dönüştürmeleri (ArrayBuffer ⇄ base64url) dikkat ister; hataların çoğu burada çıkar.

En İyi Uygulamalar ve Güvenlik İpuçları

- Origin ve RP ID tutarlılığı: www ile çıplak alan adı karışıklığı yaşamamak için tek tercih belirleyin.
- User Verification: “required” seçeneği güvenliği yükseltir (biyometrik/PIN zorunlu).
- Resident Key (Discoverable Credentials): Kullanıcı adı sormadan doğrudan passkey ile giriş akışı sağlar; UX’i iyileştirir.
- Attestation politikası: Genellikle “none” yeterlidir; donanım güveni gerekiyorsa “indirect” veya belirli CA’lar ile doğrulayın.
- signCount ve Clone Detection: signCount düşerse potansiyel klon tespitine karşı hesabı işaretleyin.
- Yedekleme: Kullanıcıya birden fazla passkey ekletin ve acil kurtarma için e-posta linki veya destek kanalı sunun (parolaya geri dönüş önermeyin).

Sık Karşılaşılan Hatalar

- TypeError: create() ya da get() için beklenen ArrayBuffer yerine base64 string gönderildi. Çözüm: Base64url’ü Uint8Array’e çevirin.
- DOMException NotAllowedError: Kullanıcı iptal etti veya sayfa güvenli değil. HTTPS kullanın ve UI’de açık bilgi verin.
- InvalidStateError: Aynı kullanıcı için aynı authenticator’da ikinci kez kayıt deneniyor. allowCredentials stratejisini gözden geçirin.

SEO ve Üretim Notları

Passkey, WebAuthn ve FIDO2 anahtar kelimelerini sayfadaki başlık ve açıklamalara ekleyin. Schema.org Person ve WebSite şemaları ile login sayfasını işaretlemek, arama motorlarına daha net sinyaller verir. Üretimde HSTS etkinleştirin, doğru CORS politikası tanımlayın ve CSRF koruması kullanın. Reverse proxy arkasında çalışıyorsanız X-Forwarded-Proto başlığının doğruluğunu garanti edin; aksi halde origin eşleşmeleri başarısız olur.

Sonuç

Passkey entegrasyonu, modern web uygulamalarında güvenliği yükseltirken kullanıcı deneyimini ciddi ölçüde iyileştirir. Next.js veya benzeri bir yığınla, birkaç API uç noktası ve iyi kurgulanmış bir doğrulama katmanı ile parolasız girişe geçebilirsiniz. Küçük bir POC ile başlayın, kayıt ve giriş akışlarını uçtan uca test edin, ardından çoklu cihaz ve kurtarma senaryolarını ekleyerek üretime taşıyın. Parolasız gelecek, bugün erişilebilir durumda.

19 Eylül 2025 Cuma

Web Uygulamana Passkey (WebAuthn) Ekleme: Node.js ile Şifresiz Giriş Rehberi 2025

Giriş

Şifresiz kimlik doğrulama, son yılların en önemli güvenlik dönüşümlerinden biri. Passkey (FIDO2/WebAuthn) sayesinde kullanıcılar, karmaşık şifrelerle uğraşmadan biyometri, güvenli donanım anahtarları veya cihaz kilidi ile giriş yapabiliyor. Bu rehberde, modern bir web uygulamasına Node.js ve tarayıcı WebAuthn API kullanarak passkey ekleme sürecini adım adım anlatıyorum. Odak noktamız: kolay kurulum, sağlam güvenlik ve güncel tarayıcı desteği.

Ön Koşullar

- Alan adınız ve HTTPS etkin (localhost için https://localhost da çalışır, ancak gerçek kullanıcılar için zorunlu HTTPS gereklidir).
- Node.js 18+ (WebCrypto ve fetch desteği için önerilir).
- Basit bir kullanıcı veritabanı (PostgreSQL, MongoDB ya da SQLite).
- Sunucu tarafında WebAuthn doğrulaması için bir kütüphane (örneğin simplewebauthn).
- RP ID (Relying Party ID) olarak genellikle kök alan adınız: example.com. Origin ise https://app.example.com gibi tam kaynak adresidir.

Mimari ve Akış

WebAuthn iki ana akıştan oluşur: Kayıt (Registration) ve Giriş (Authentication). Her ikisi de sunucunun ürettiği rastgele bir challenge değeriyle başlar.

1) Kayıt: Sunucu kullanıcıyı tanımlar, PublicKeyCredentialCreationOptions oluşturur ve challenge döner. Tarayıcı navigator.credentials.create() ile kullanıcıdan attestation üretir. Sunucu attestation’ı doğrular, credentialId ve publicKey gibi özet bilgileri veritabanına kaydeder.

2) Giriş: Sunucu PublicKeyCredentialRequestOptions döner. Tarayıcı navigator.credentials.get() ile assertion (imzalı kanıt) üretir. Sunucu imzayı ve sayaç değerini doğrular, oturumu açar.

Frontend: Kayıt Akışı

Kullanıcı giriş yaptıktan (veya e-posta doğruladıktan) sonra passkey kaydı başlatın. İstemci tarafında tipik istek:

const regOpts = await fetch('/webauthn/register/options').then(r => r.json());
const credential = await navigator.credentials.create({ publicKey: regOpts });
await fetch('/webauthn/register/verify', { method: 'POST', body: JSON.stringify(credential) });

SEO açısından önemli noktalar: “passkey kaydı”, “WebAuthn tarayıcı API”, “şifresiz kimlik doğrulama” gibi anahtar kelimeleri akışa doğal yerleştirin.

Backend: Kayıt Doğrulama

Sunucuda challenge değerini kullanıcıya özel ve tek kullanımlık olarak üretin. @simplewebauthn/server kullanıyorsanız generateRegistrationOptions ile seçenekleri üretir, verifyRegistrationResponse ile attestation doğrularsınız. Doğrulama sonrası şu alanları saklayın:

- credentialId: Kimlik.
- publicKey: İmza doğrulaması için gereken anahtar.
- signCount: Yeniden oynatma saldırılarına karşı sayaç.
- transports ve aaguid gibi meta bilgiler.

Frontend: Giriş (Authentication) Akışı

Kullanıcı giriş sayfasına geldiğinde, eğer passkey kayıtlıysa “Tek tıkla şifresiz giriş” sunabilirsiniz:

const authOpts = await fetch('/webauthn/auth/options?username=ali').then(r => r.json());
const assertion = await navigator.credentials.get({ publicKey: authOpts });
await fetch('/webauthn/auth/verify', { method: 'POST', body: JSON.stringify(assertion) });

Chrome’un Conditional UI özelliğiyle, kullanıcı adı alanına odaklanıldığında passkey önerisi otomatik çıkar. Bunun için mediation: 'conditional' kullanın ve sayfada autocomplete="username" bulunan bir alan bulundurun.

Güvenlik ve En İyi Uygulamalar

- Origin ve rpId kesin eşleşmeli. Ters proxy (Cloudflare, Nginx) arkası dağıtıma dikkat edin.
- Challenge benzersiz ve kısa ömürlü olsun; kullanıldıktan sonra silin.
- userVerification değerini tehdit modelinize göre belirleyin: required (yüksek güvenlik) veya preferred (daha iyi uyumluluk).
- residentKey (discoverable credentials) ile kullanıcı adı girmeden giriş deneyimi sağlayabilirsiniz. Bunun için residentKey: 'required' ve authenticatorSelection.requireResidentKey = true.
- Çoklu cihaz senkronizasyonu (iCloud Keychain, Google Password Manager) sayesinde passkey’ler cihazlar arasında taşınabilir; ancak kurumsal ortamda donanım güvenlik anahtarlarını (YubiKey vb.) zorunlu kılmak isteyebilirsiniz.

Test ve Hata Ayıklama

Chrome DevTools > More Tools > Virtual Authenticator ile fiziksel cihaz olmadan test yapabilirsiniz. Buradan platform/harici anahtar seçebilir, kullanıcı doğrulamasını simüle edebilirsiniz. Sık görülen hatalar: “Invalid RP ID” (alan adınız uyuşmuyor), “DOMException: The operation is insecure” (HTTPS yok), “Challenge mismatch” (eski veya farklı kullanıcıya ait challenge).

Veri Modeli ve Uyum

Bir kullanıcı birden fazla passkey’e sahip olabilir. Veritabanında users, credentials şeklinde ayrıştırın. Girişte birden çok allowCredentials döndürebilir veya discoverable credential ile boş gönderip tarayıcının seçmesini izleyebilirsiniz. KV veya bellek içi önbellek ile challenge yönetimini hızlandırın. KV kullansanız bile kalıcılık için veritabanına yedekleyin.

Dağıtım İpuçları

Sunucunuz HTTP/2 veya HTTP/3 arkasındaysa, Origin başlığının ve CF-Connecting-IP / X-Forwarded-Proto gibi başlıkların framework’ünüz tarafından doğru işlendiğinden emin olun. Serverless (Vercel, Cloudflare Workers) üzerinde de WebAuthn rahatlıkla çalışır; sadece rpId ve origin sabit ve tutarlı olmalı.

Sonuç

Passkey (WebAuthn) ile şifresiz kimlik doğrulama, hem güvenliği hem kullanıcı deneyimini ciddi biçimde iyileştiriyor. Node.js ve WebAuthn API sayesinde birkaç uç noktayı doğru kurgulayarak dakikalar içinde prototip çıkabilir, Conditional UI ile tek dokunuşla giriş deneyimi sunabilirsiniz. Doğru RP ID, benzersiz challenge yönetimi ve kapsamlı doğrulama kontrolleriyle, 2025’in güvenlik standartlarına uygun modern bir “şifresiz giriş” altyapısını bugün projelerinize ekleyin.

18 Eylül 2025 Perşembe

Tarayıcıda Yüksek Performanslı Görüntü İşleme: WebGPU ve WGSL ile Adım Adım Başlangıç Rehberi

WebGPU Nedir ve Neden Önemli?

WebGPU, tarayıcıda düşük seviyeli GPU erişimi sağlayan modern bir web standardıdır. WebGL’in yerini hedefleyen bu API, yalnızca çizim için değil, genel amaçlı hesaplama (compute) iş yükleri için de GPU gücünü kullanmanızı mümkün kılar. Bu sayede yüksek çözünürlüklü görüntü filtreleri, gerçek zamanlı video işleme veya makine öğrenmesi çıkarımı gibi ağır işleri tarayıcıda akıcı biçimde gerçekleştirebilirsiniz. Bu rehberde, WebGPU ve WGSL (WebGPU Shading Language) kullanarak basit bir görüntü filtresini nasıl kurgulayacağınızı, performans ve uyumluluk detaylarıyla anlatıyorum.

Önkoşullar ve Uyumluluk

WebGPU, Chrome 113+ ve Edge’de varsayılan olarak etkin, Safari’de 17+ sürümlerde geniş ölçüde destekleniyor. Firefox tarafında Nightly sürümünde bayrakla test edilebiliyor. Geliştirme sırasında sayfanızın HTTPS üzerinden servis edilmesi önerilir; yerelde localhost istisna kabul edilir. Uygulama başlangıcında if ('gpu' in navigator) ile özellik tespiti yaparak destek yoksa zarif bir geri dönüş (örneğin Canvas 2D veya WebGL) uygulayın.

Temel Akış: Adaptör, Cihaz ve Bağlam

İlk adımda navigator.gpu.requestAdapter() ile bir adaptör talep edilir; ardından adapter.requestDevice() ile GPU cihazı oluşturulur. Görüntü çıktınız bir <canvas> üzerindeyse, canvas.getContext('webgpu') çağrısı ile bir bağlam alınır ve uygun formatla (genellikle navigator.gpu.getPreferredCanvasFormat()) yapılandırılır. En iyi verim için cihaz ve bağlamı tek sefer oluşturup tüm etkileşimlerde yeniden kullanın.

Veri Temsili: Buffer ve Texture Seçimleri

Görüntü işleme söz konusu olduğunda veriyi çoğunlukla GPUTexture olarak tutmak gerekir. Statik resimleri ImageBitmap üzerinden yükleyip copyExternalImageToTexture ile GPU tarafına taşıyabilirsiniz. Filtre uygulanacak hedef için storage izinli bir kaplama (örneğin rgba8unorm formatında) tanımlayın. Parametreler (örneğin kernel boyutu, yoğunluk) için küçük bir GPUBuffer yeterli olacaktır. Farklı geçişlerde (compute vs render) aynı texture’ı hem storage hem texture-binding haklarıyla oluşturmayı planlayın.

WGSL ile Basit Bir Filtre Tasarlama

WGSL, WebGPU’nun yerel gölgelendirici dilidir. Örnek olarak gri tonlama filtresi düşünelim: Her piksel için RGB bileşenlerinin ağırlıklı ortalamasını alıp aynı değeri tüm kanallara yazarsınız. Compute yaklaşımında, bir @compute shader ile iş parçacıklarını 2B çalışma gruplarına böler, giriş kaplamasından örnek alır ve çıktıyı storage kaplamaya yazarsınız. Performans için @workgroup_size(8, 8) veya ekran kartınıza uygun başka bir boyut seçip test edin; farklı boyutlar, cihaz ve çözünürlüğe bağlı olarak ciddi fark yaratabilir.

Render Pass mı, Compute Pass mı?

Basit bir tonlama veya tek dokunuşlu efektlerde fragment shader’lı bir render pass yeterli olabilir; bir ekran dolgu üçgeni veya dörtgen ile giriş dokuyu örnekleyip sonuç doğrudan ekrana çıkarılır. Çok adımlı bulanıklaştırma (örneğin Gaussian blur), kenar algılama veya konvolüsyon temelli filtrelerde compute pass genellikle daha esnek ve performanslıdır. İki yaklaşımı da prototiplemek ve profil ile kıyaslamak iyi bir pratiktir.

Komut Akışı ve Kaynak Yönetimi

Her karede yeni bir komut kodlayıcı (commandEncoder) oluşturur, gerekli geçişleri kaydedip device.queue.submit() ile çalıştırırsınız. Maliyetli işlemler: tekrar tekrar buffer/texture oluşturmak, çok sayıda küçük submit yapmak ve gereksiz mapAsync çağrılarıdır. Bunları en aza indirin. Bind group’ları ve pipeline’ları mümkün olduğunca önceden oluşturup yeniden kullanın, yalnızca parametre değiştiğinde güncelleyin.

Performans İpuçları

- Yüksek çözünürlükte çalışmak yerine, görüntüyü ölçekli (örneğin 0.75x) işlemeyi deneyin ve sonuçta tekrar ölçekleyin; çoğu filtrede görsel kalite farkı az, hız kazancı yüksektir.

- Uygunsa rgba8unorm gibi 8 bit formatları tercih edin. Yarı hassas (16 bit float) gereksinimi yoksa daha hafif formatlar bellek bant genişliğini azaltır.

- Zaman ölçümü için CPU tarafında performance.now() kullanmak başlangıç için yeterli; daha ileri düzeyde cihazınız destekliyorsa timestamp-query özelliğiyle GPU süresi ölçebilirsiniz.

- Dizüstü bilgisayarlarda entegre ve ayrık GPU arasında fark büyük olabilir. requestAdapter sırasında powerPreference: 'high-performance' ipucunu verip sahada A/B testleri yapın.

Hata Ayıklama ve Geliştirici Deneyimi

WGSL hata mesajları başta göz korkutabilir. Shader’ları küçük, tek amaçlı fonksiyonlara bölmek ve her adımı ayrı çalıştırıp görselleştirmek (örneğin ara sonuçları ekrana basmak) sorun tespitini kolaylaştırır. Chrome’da chrome://gpu sayfası ve konsol uyarıları donanım/driver durumunu anlamaya yardımcı olur. Ayrıca pipeline oluştururken cihaz özelliklerini ve format desteklerini sorgulayıp koşullu yollar izlemek (örn. device.features) saha stabilitesini artırır.

Güvenlik ve Üretim Hazırlığı

WebGPU, tasarımı gereği güvenli; ancak yüksek frekansta veri aktarımı ve CORS kısıtları gibi web’in temel dinamikleri hala geçerli. Harici görsel yüklerken CORS başlıklarını doğru ayarlayın, kullanıcı verilerini işliyorsanız istemci tarafı GPU hesaplamalarının gizlilik etkilerini göz önünde bulundurun. Üretimde, hatalı cihazları belirlemek için basit bir “öz tanılama” ekranı (desteklenen formatlar, maksimum texture boyutu, başarısız pipeline sayısı) değerli geri bildirim sağlar.

Adım Adım Özet

1) Özellik tespiti yapın ve zarif bir geri dönüş belirleyin. 2) Adaptör ve cihazı oluşturun, canvas bağlamını yapılandırın. 3) Giriş görüntüsünü texture’a kopyalayın, çıktı için storage texture hazırlayın. 4) WGSL ile filtre shader’ını yazın (compute veya fragment). 5) Bind group/pipeline oluşturun, komut akışını kodlayın. 6) Performans ölçüp darboğazları azaltın. 7) Uyumluluk, hata ayıklama ve güvenlik kontrollerini ekleyin.

Sonuç

WebGPU, tarayıcıda görüntü işleme projelerini profesyonel sınıfa taşıyor. Doğru veri temsilini seçip WGSL ile minimal, okunabilir shader’lar yazdığınızda 4K çözünürlükte bile akıcı sonuçlar elde edebilirsiniz. İlk uygulamada basit bir gri tonlama veya kutu bulanıklaştırma ile başlayın; ardından çok geçişli Gaussian, kenar algılama ve renk uzayı dönüştürme gibi filtrelere genişletin. Elde edeceğiniz hız kazanımı ve taşınabilirlik, modern web uygulamalarınız için oyunu değiştirecek.