Camiler.org’u Açık Kaynak Araçlarla ve Cloudflare Gücüyle Nasıl Kurdum?

Camiler.org’u geliştirirken yalnızca içerik değil, altyapı tarafında da sağlam, ölçeklenebilir ama ilk etapta küçük bir sunucuda bile sorunsuz çalışacak bir sistem kurmak istedim. Hedefim; hızlı, esnek ve tamamen kontrolümde olan bir yapı oluşturmaktı. Ne karmaşık çözümler ne de dışa bağımlı servisler—sadece ne yaptığını bilen basit parçalar ve sürdürülebilir bir mimari.

Bu yazıda, küçük bir VPS üzerinde çalışan bu altyapının mimarisini anlatacağım. Tamamen açık kaynak araçlarla kurduğum bu yapı hem maliyetsiz hem de performanslı.

SEO tarafındaki yaklaşımı daha önce şu yazımda paylaşmıştım:
👉 Düşük Rekabetli SERP’te Google Maps ve OpenAI ile Bir SEO Deneyi

Buradaysa odak noktası tamamen altyapı: Docker’dan Redis’e, Nuxt’tan Fastify’a, imgproxy’den Cloudflare R2’ya kadar tüm parçaları nasıl birleştirdiğimi anlatacağım.

Genel Mimari: Her Şeyin Yerli Yerinde Olduğu Küçük Bir Sistem

Camiler.org’u geliştirirken kafamda net bir çerçeve vardı:
Sunucuya yük bindirmeyen, anlaşılır, sade ve gerektiğinde kolayca parçalanıp yeniden inşa edilebilecek bir yapı kurmak.

Ne abartılı servisler ne de her işi yapan şişkin çözümler…
Her parçanın tek bir işi olmalıydı — onu da iyi yapmalıydı.

Sistemin tamamı Docker konteynerleri içinde çalışıyor. Her şey tek bir VPS üzerinde, ama her bileşen olabildiğince izole. Ne çalışıyor, neden orada, nerede neye dokunuluyor… hepsi açık.

Kabaca mimari şöyle:

  • Traefik gelen trafiği yönlendiriyor, SSL yönetiyor, IP bazlı erişim kısıtlarını uyguluyor.
  • Nuxt 3, SSR modda çalışan arayüz katmanını oluşturuyor. Benim yazdığım özel bir middleware, sayfa çıktısını Redis’e kaydedip oradan servis ediyor.
  • Fastify, backend API’yi oluşturuyor. Veri tabanı bağlantısı ise Prisma üzerinden MariaDB’ye gidiyor.
  • Redis, hem frontend hem backend’in ortak hafızası gibi çalışıyor. Önbellekleme, oran sınırlama, etiket bazlı temizleme gibi pek çok iş burada dönüyor.
  • imgproxy, görselleri anlık olarak boyutlandırıyor ve optimize ediyor.
  • Cloudflare, CDN katmanını yönetiyor ve aynı zamanda R2 ile dosya saklama işini üstleniyor.
  • GitHub Actions, deploy sürecini otomatikleştiriyor.
  • Son olarak, işler ters giderse diye elimde iki küçük yardımcı var: Portainer ve phpMyAdmin.

Her şey olabildiğince sade ve ne yaptığını bilen parçalardan oluşuyor.

Traefik: Basit, Akıllı ve Docker’a Dost

Traefik, dış dünyadan gelen her isteğin ilk uğradığı yer. Reverse proxy rolünde, hangi istek hangi servise gidecek, hangi kurallar çalışacak, hangi rotada ne aktif olacak… tüm trafiği o yönetiyor.

Traefik’i tercih etmemin sebebi şu: Docker ile neredeyse kendiliğinden çalışıyor. Herhangi bir servise sadece birkaç etiket ekliyorsunuz ve Traefik onu otomatik olarak tanıyıp yönlendirmeye başlıyor. Ekstra yapılandırma dosyaları, yeniden başlatmalar yok. Bu sadelik benim gibi tek başına çalışan biri için ciddi avantaj.

Benim kullanım senaryolarım:

  • Let’s Encrypt ile otomatik SSL sertifika yönetimi
  • Etiketlere göre konteyner yönlendirme
  • IP tabanlı erişim kısıtlamaları
  • Gzip sıkıştırma ve temel güvenlik başlıkları

Yapabileceği daha karmaşık işler de var elbette, ama benim amacım basitti: Konteyner tabanlı bir sistemde, müdahale etmeden çalışan bir trafik yöneticisi. Bunu da fazlasıyla sağlıyor.

Frontend: Nuxt 3 + Özel Cache Katmanı

Arayüz katmanında Nuxt 3 kullanıyorum. SSR (server-side rendering) modda çalışıyor. Geliştirici deneyimi oldukça temiz ve esnek. Ama Nuxt’un kendi cache yetenekleri, benim ihtiyacımı karşılamadı.

Bu yüzden kendim bir cache middleware yazdım. Temel amaç, sayfa oluşturulduktan sonra bunu Redis’e kaydedip oradan servis etmek. Her istek için sunucunun yeniden render yapmasına gerek kalmıyor.

Bazı detaylar şöyle:

  • HTML çıktıları Redis’e sıkıştırılmış olarak yazılıyor. Küçük bir CPU yükü karşılığında, özellikle düşük bellekli VPS üzerinde ciddi bir memory kazancı sağlıyor.
  • ETag desteği var. Böylece tarayıcı tarafında içerik tazelik kontrolü daha verimli yapılabiliyor.
  • Etiket bazlı silme sistemi mevcut. Örneğin bir cami güncellendiğinde, onunla ilişkili “yakındaki camiler” sayfası da otomatik olarak cache’ten düşüyor.

Bu yapı sadece son kullanıcıya hızlı sayfa sunmak için değil — sunucu kaynaklarını daha verimli kullanmak, yanıt sürelerini düşürmek ve sistemin nefes almasını sağlamak için var.

Ayrıca frontend tarafında tamamen client üzerinde çalışan, Local Storage + LRU bellek temelli başka bir cache sistemimiz daha var. O sistem API çağrılarını azaltmak için etkili ama doğrudan altyapı katmanına dâhil değil, o yüzden burada detaya girmiyorum.

Backend: Fastify + Prisma + Özel Rate Limiter

Backend tarafında Fastify kullanıyorum. Hafif, modüler ve oldukça hızlı. Ekstra bir şeye ihtiyaç duymadıkça önünüze çıkmıyor.

Veri tabanı katmanında Prisma üzerinden MariaDB kullanıyorum. Prisma’nın tip güvenliği, query optimizasyonları ve genel geliştirici deneyimi gerçekten başarılı.

Rate limiting için ise hazır çözümler yetersiz kaldı. Hem rota bazlı, hem grup bazlı hem de global limitleri birlikte kontrol edebileceğim bir sistem bulamayınca, kendi rate limiter middleware’imi yazdım.

  • Redis tabanlı çalışıyor
  • Her kullanıcı veya IP için ayrı sayaçlar tutuyor
  • Otomatik zaman aşımı ile sıfırlanıyor

Kısacası: Hafif, esnek ve bana özel.

Redis: Sistemi Tutan Gizli Yapıştırıcı

Redis başlangıçta sadece cache için vardı ama zamanla projenin birçok kritik parçasını taşıyan bir katmana dönüştü.

Şu an Redis’i şu amaçlarla kullanıyorum:

  • Sayfa HTML’lerini cache’lemek
  • Backend tarafında sorgu cache’leri
  • Etiket bazlı temizleme sistemini yönetmek
  • ETag/SWR gibi kontrol başlıklarını desteklemek
  • Rate limiter sayaçlarını saklamak
  • Küçük çaplı state verilerini geçici olarak tutmak

Redis’e yazdığım tüm veriler sıkıştırılmış şekilde kaydediliyor. Küçük bir CPU yükü karşılığında, VPS’te önemli miktarda bellek tasarrufu sağlıyorum.

Ayrıca Redis tamamen opsiyonel çalışıyor. Yani bir sorun çıkarsa, sistem çökmüyor. Sadece daha az verimli çalışıyor.

imgproxy: Görselleri Anlık ve Akıllıca Sunmak

Ham görselleri doğrudan sunmak istemedim. Aynı görselin farklı boyutları, formatları, cihazlara göre optimizasyon derken iş hızla karmaşıklaşıyor.

Bunun yerine imgproxy kullanıyorum. Kaynak görseli alıp, ihtiyaç duyulan boyut ve formatta anlık olarak optimize ediyor. Böylece sadece orijinal görseli saklıyorum, ihtiyaç duyulana göre anında dönüştürüp gösteriyorum.

Görsellerin orijinalleri Cloudflare R2 üzerinde saklanıyor. imgproxy de buradan çekip işliyor.

Cloudflare: CDN + Edge Cache + Dosya Depolama

Hem görsellerin hem de statik içeriklerin hızlı ve düşük maliyetle sunulabilmesi için Cloudflare kritik rol oynuyor.

  • Görseller R2 üzerinde saklanıyor
  • imgproxy ile optimize edilen sürümler, Cloudflare CDN üzerinden dünya genelindeki edge node’lara dağıtılıyor
  • Kullanıcılar görsellere neredeyse anında erişiyor
  • Tüm bu yapı, sunucuya ekstra yük bindirmeden çalışıyor

En güzel yanı şu: Cloudflare R2’nin oldukça cömert bir ücretsiz kullanım kotası var ve bu proje için fazlasıyla yeterli geliyor. Aynı şekilde CDN katmanı da ücretsiz, hızlı ve güvenilir.

Evet, R2 teknik olarak bir vendor bağımlılığı yaratıyor gibi görünebilir. Ama aslında S3 uyumlu olduğu için dilediğim zaman başka bir servis sağlayıcıya (ya da MinIO gibi kendi barındırdığım bir çözüme) geçiş yapabilirim.

Yani hem performans hem maliyet açısından oldukça dengeli bir çözüm ve ileride büyümeye açık.

CI/CD: GitHub Actions ile Otomasyon

Deploy sürecinde karmaşık araçlara ya da dış hizmetlere ihtiyaç duymadım. GitHub Actions, bu iş için fazlasıyla yeterli ve oldukça stabil çalışıyor.

Sistem çok basit:

  • Ana branch’e bir push yaptığımda GitHub Actions devreye giriyor
  • İlgili servisin Docker imajını build ediyor
  • İmajı private registry’e gönderiyor
  • Ardından sunucudaki küçük bir webhook endpoint’ine istek atarak ilgili konteynerin yeniden başlatılmasını sağlıyor

Ne ekstra arayüzler, ne manuel komutlar, ne de fazladan bir sistem…
Küçük projelerde bu sadelik büyük konfor.

Yani tamamen otomatik ama şeffaf bir yapı var. Ne zaman ne çalıştı, ne zaman ne bozuldu—anlamak çok kolay. Özellikle tek başına çalışan biri için bu sistem hem güvenli hem de sürdürülebilir.

Portainer ve phpMyAdmin: Görsel Yardımcılar

Her şey terminalden yönetiliyor olsa da bazen hızlıca bir şeyleri görsel olarak kontrol etmek büyük kolaylık sağlayabiliyor. Bu yüzden sisteme iki küçük ama işe yarar araç dahil ettim: Portainer ve phpMyAdmin.

Portainer, Docker konteynerlerini görsel olarak izleyebileceğim, log’lara bakabileceğim, gerekirse bir servisi hızlıca yeniden başlatabileceğim hafif bir arayüz sunuyor. Sürekli açık değil ama ihtiyaç duyduğumda oldukça işimi görüyor.

phpMyAdmin ise sadece IP kısıtlamasıyla erişilebilen bir arayüz. Bazen hızlıca veri tabanında tablo yapısını kontrol etmek ya da bir iki query denemek için terminal açmak yerine doğrudan burayı kullanmak daha pratik oluyor.

Bu araçlar benim için “core infrastructure” değil—daha çok zor zamanlarda devreye giren sessiz yardımcılar gibi. Olmasa da olur ama olduklarında ciddi zaman kazandırıyorlar.

Kapanış: Genel Değerlendirme

Amacım karmaşık bir altyapı kurmak değildi. İstediğim şey; gerçek bir problemi çözen, hızlı çalışan ve sürdürülebilir bir sistem ortaya koymaktı.

Bu bakış açısı tüm mimariyi şekillendirdi. Her bileşeni bilinçli seçtim:
Açık kaynak araçlara yaslandım, Docker ile sistemi modüler tuttum, Cloudflare’i ise yalnızca gerçekten katkı sağladığı yerlerde kullandım. Gereksiz hiçbir şey yok, her parça işini yapıyor ve gerektiğinde değiştirilebilir.

Eğer siz de benzer bir projeyi sıfırdan kurmak ya da mevcut bir yapıyı sadeleştirmek istiyorsanız, burada anlattıklarımın faydalı olacağını düşünüyorum.

Okuduğunuz için teşekkür ederim.