Skip to content

Güvenlik ve Optimizasyon

Video güvenliği (Bunny CDN imzalı URL), Cloudflare Zero Trust ile admin güvenliği, route ve edge cache stratejileri, dinamik robots.txt ve sitemap üretimi.

Bu sayfa Achidemy’de video güvenliği (Bunny CDN imzalı URL), Cloudflare Zero Trust ile admin panelinin güvenliğe alınması, route/edge cache stratejileri ve SEO için dinamik robots.txt ile sitemap üretimini açıklar.

Video Güvenliği — Bunny CDN İmzalı (Signed) URL

Section titled “Video Güvenliği — Bunny CDN İmzalı (Signed) URL”

Videolar Bunny.net Stream üzerinden sunulur. Doğrudan indirmeyi ve yetkisiz erişimi engellemek için imzalı (signed) URL kullanılır.

  • Dosya: app/lib/video-security.ts
  • Fonksiyon: generateSignedVideoUrl(videoId, libraryId, securityKey, expirationSeconds?)
  • Algoritma: Bunny’nin beklediği formatta token üretilir:
    • expires = now + expirationSeconds (varsayılan 3600 saniye = 1 saat)
    • tokenData = securityKey + videoId + expires
    • SHA-256 hash alınır → hex string = token
    • URL: https://iframe.mediadelivery.net/embed/{libraryId}/{videoId}?token={token}&expires={expires}

Bunny CDN, gelen istekteki token ve expires değerini aynı mantıkla doğrular; süre dolmuş veya token yanlışsa içerik verilmez.

DeğişkenAçıklama
BUNNY_LIBRARY_IDBunny Stream Library ID
BUNNY_VIDEO_SECURITY_KEYBunny panelinden alınan Pull Zone → Remote Auth / Security Key (imza için kullanılır)
  • Öğrenme sayfası: app/routes/learn.$slug.tsx — kayıtlı derslerde sadece erişim hakkı olan kullanıcılara signedVideoUrl üretilir (preview dersler + enroll edilmiş kullanıcılar).
  • Kurs detay sayfası: app/routes/course.$id.tsx — önizleme (preview) dersler için signedPreviewUrl üretilir.

BUNNY_VIDEO_SECURITY_KEY tanımlı değilse imzalı URL üretilmez; eski embed URL’i (token olmadan) kullanılır — bu durumda videolar doğrudan paylaşılabilir ve indirilebilir, production’da güvenlik anahtarı kullanılması önerilir.


Cloudflare Zero Trust — Admin Panelinin Güvenliğe Alınması

Section titled “Cloudflare Zero Trust — Admin Panelinin Güvenliğe Alınması”

Admin paneli uygulama seviyesinde şu şekilde korunur:

  • Dosya: app/routes/admin.tsx (layout loader)
  • Kontrol: Better Auth session alınır; session?.user?.id yoksa veya veritabanındaki kullanıcı role !== "admin" ise 404’e yönlendirilir.
  • Tüm admin alt sayfaları bu layout’tan geçer; yani sadece role = admin olan kullanıcılar /admin/* sayfalarına erişebilir.

Production’da admin panelini ek bir katmanla korumak için Cloudflare Zero Trust (Access) kullanılabilir:

  1. Cloudflare Dashboard → Zero Trust → Access → Applications ile yeni bir uygulama tanımlanır.
  2. Protected hostname: admin.yourdomain.com veya yourdomain.com/admin (path bazlı kural ile).
  3. Policy: Örneğin sadece belirli e-posta alanları, GitHub/Google SSO veya One-time PIN ile giriş zorunlu tutulur.
  4. Böylece sunucuya istek ulaşmadan önce Cloudflare, kimlik doğrulamayı yapar; yetkisiz kullanıcılar login sayfasına yönlendirilir.

Dökümantasyon: Cloudflare Zero Trust — Application Access ve Protect a self-hosted application resmi dokümanlarından path/host bazlı kurulum yapılabilir.

Özet: Uygulama içi koruma (session + admin role) şu an tek katman; Cloudflare Access ile /admin (veya admin subdomain’i) ikinci katman olarak kilitlenebilir.


SEO & Sitemap — Dinamik robots.txt ve Sitemap Üretimi

Section titled “SEO & Sitemap — Dinamik robots.txt ve Sitemap Üretimi”
  • Route: GET /robots.txt (dil prefix’i yok)
  • Dosya: app/routes/robots[.]txt.ts
  • İçerik: Loader içinde request.url ile host ve protocol alınır; baseUrl dinamik oluşturulur. Aynı kod Cloudflare Workers veya farklı domain’de çalışır.

Kurallar özeti:

  • User-agent: * — Genel kurallar: public sayfalar (ana sayfa, /tr/, /en/, /de/, pricing, teaching, courses, course) Allow; admin, instructor, account, my-courses, cart, payment, login, register, onboarding, learn, verify, api, 404/500 Disallow.
  • Googlebot / Bingbot / Yandex — Aynı public sayfalar Allow; isteğe bağlı Crawl-delay (bazı botlar için).
  • Sitemap: Response’ta Sitemap: ${baseUrl}/sitemap.xml ve dil bazlı sitemap-tr.xml, sitemap-en.xml, sitemap-de.xml referansları yer alır.

Not: Dil bazlı sitemap URL’leri (sitemap-tr.xml vb.) robots.txt’te belirtilmiş olabilir; şu an routes.ts içinde yalnızca tek sitemap.xml route’u vardır. Dil bazlı ayrı sitemap’ler istenirse ek route’lar eklenebilir.

Route & Edge Cache — React Router v7 + Cloudflare CDN

Section titled “Route & Edge Cache — React Router v7 + Cloudflare CDN”

Ana sayfa ve kurs katalogu gibi yüksek trafikli, ancak verisi saniyede değişmeyen sayfalar için SSR hızında SSG benzeri bir deneyim sağlamak amacıyla HTTP cache header’ları kullanılır.

  • Dosyalar:
    • app/routes/_index.tsx (ana sayfa)
    • app/routes/courses.all.tsx (kategori bazlı kurs listesi)
  • Fonksiyon: Her iki dosyada da component dışına export function headers() tanımlıdır.
  • Header değeri:
export function headers() {
return {
"Cache-Control":
"public, max-age=60, s-maxage=3600, stale-while-revalidate=86400",
};
}

Açıklama:

  • max-age=60: Kullanıcının tarayıcısı yanıtı 1 dakika boyunca önbelleğe alır.
  • s-maxage=3600: Cloudflare Edge (CDN) yanıtı 1 saat boyunca önbellekte tutar; bu süre boyunca istekler worker’a uğramadan statik HTML’den cevaplanır.
  • stale-while-revalidate=86400: 1 saatten sonra bile yanıt “stale” olarak kullanıcıya anında gösterilir, arka planda yeni HTML işlenip Edge önbelleği sessizce güncellenir (SWR).

Bu sayede:

  • İlk istekte SSR maliyeti ödenir.
  • Sonraki binlerce istek, Cloudflare Edge’ten milisaniye içinde döner.
  • Veri güncellemeleri arka planda yenilenir; kullanıcılar neredeyse her zaman “sıcak” sayfa görür.

  • Route: GET /sitemap.xml
  • Dosya: app/routes/sitemap[.]xml.ts
  • Veri: getDb(env.DATABASE_URL) ile veritabanına bağlanılır; courses tablosundan status = 'published' olan kursların slug değerleri alınır.
  • URL’ler:
    • Statik sayfalar: baseUrl/{lang}{page} — diller: tr, en, de, es; sayfalar: "", /courses, /pricing, /teaching, /terms/privacy. Her biri için changefreq: weekly, priority: ana sayfa 1.0, diğerleri 0.8.
    • Kurs sayfaları: baseUrl/{lang}/course/{slug} — sadece yayında olan kurslar; changefreq: daily, priority: 0.9.
  • Response: Content-Type: application/xml, Cache-Control: public, max-age=3600.

Base URL: Sitemap içinde base URL sabit veya env’den okunabilir. Production’da canlı adres https://achidemy.net (BASE_URL / BETTER_AUTH) kullanılmalıdır. Bkz. Ortam Değişkenleri.

  • Route: /:lang/sitemap (ör. /tr/sitemap)
  • Dosya: app/routes/$lang.sitemap.tsx
  • İçerik: HTML sitemap sayfası — platform bölümü (ana sayfa, tüm kurslar, fiyatlandırma, eğitmen ol), popüler kurslar (ör. kategori bazlı linkler), yasal (gizlilik, kullanım şartları, çerez politikası) linkleri. Arama motorları için ek bilgi; XML sitemap’in yerine geçmez.

KonuAçıklama
Video güvenliğiapp/lib/video-security.tsgenerateSignedVideoUrl ile Bunny CDN imzalı URL (SHA-256 token + expires). learn ve course sayfalarında kullanılır. Env: BUNNY_LIBRARY_ID, BUNNY_VIDEO_SECURITY_KEY.
Admin güvenliğiUygulama: session + user.role === "admin" (admin.tsx loader). Önerilen ek katman: Cloudflare Zero Trust (Access) ile /admin veya admin hostname koruması.
Route/Edge cacheapp/routes/_index.tsx ve app/routes/courses.all.tsx içinde headers() fonksiyonu ile Cache-Control: public, max-age=60, s-maxage=3600, stale-while-revalidate=86400; ana sayfa ve kurs listeleri Cloudflare Edge üzerinde SWR stratejisiyle cache’lenir.
robots.txtDinamik, request.url ile baseUrl. Allow/Disallow + Sitemap referansları; dil bazlı sitemap URL’leri isteğe bağlı.
sitemap.xmlDinamik; DB’den yayındaki kurslar + statik sayfalar; diller (tr, en, de, es); XML; cache 1 saat.
/:lang/sitemapHTML sitemap sayfası (kullanıcı ve SEO için).

İlgili: Ortam Değişkenleri (Bunny ve diğer env), Admin Console (panel yetkilendirmesi), Eğitmen ve Kurs Yönetimi (video yükleme ve Bunny kullanımı), Hesap Güvenliği ve Oturum Yönetimi (hesap paylaşımı engelleme, review bombing koruması).

  • app/lib/video-security.tsgenerateSignedVideoUrl; Bunny CDN imzalı URL.
  • app/routes/robots[.]txt.ts — Dinamik robots.txt.
  • app/routes/sitemap[.]xml.ts — Dinamik sitemap XML.
  • app/routes/$lang.sitemap.tsx — HTML sitemap sayfası.
  • app/routes/admin.tsx — Admin layout; session ve role kontrolü.