Azure Storage ile Statik Web Sitesi Barındırma

Sunucu kurmadan, SSL sertifikası uğraşmadan, nginx konfigürasyonu yazmadan bir web sitesi yayınlamak istiyorsanız Azure Storage’ın statik web sitesi barındırma özelliği tam size göre. Özellikle React, Vue, Angular gibi framework’lerle geliştirdiğiniz SPA’ları veya düz HTML/CSS/JS sitelerini dakikalar içinde internete açabilirsiniz. Bu yazıda sıfırdan başlayıp production-ready bir yapıya kadar gideceğiz.

Azure Storage Statik Web Sitesi Nedir?

Azure Blob Storage, normalde dosya depolamak için kullandığımız bir servis. Ama Microsoft bu servise özel bir özellik eklemiş: Static Website Hosting. Bu özelliği aktif ettiğinizde, storage account’unuzun içinde $web adında özel bir container oluşturuluyor ve bu container’a koyduğunuz dosyalar doğrudan HTTP/HTTPS üzerinden erişilebilir hale geliyor.

Neden tercih edilir diye soracak olursanız:

  • Maliyet: Sunucu tutmuyorsunuz, sadece depolama ve bant genişliği ödersiniz
  • Ölçeklenebilirlik: Azure’un global altyapısı üzerinde çalışıyor
  • Yönetim yükü: Patch, güncelleme, restart derdi yok
  • SSL: Azure CDN ile birlikte kullandığınızda ücretsiz SSL sertifikası alıyorsunuz
  • Uptime: SLA garantili bir altyapı

Tabii dezavantajları da var. Server-side kod çalıştıramazsınız, PHP veya Node.js backend buraya konamazlar. Sadece statik dosyalar: HTML, CSS, JavaScript, resimler, fontlar.

Ön Gereksinimler

Başlamadan önce şunlara ihtiyacınız var:

  • Azure hesabı (ücretsiz hesapla da bu özelliği kullanabilirsiniz)
  • Azure CLI kurulu bir makine
  • Az biraz terminal sevgisi

Azure CLI kurulu değilse:

# Ubuntu/Debian
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

# macOS
brew install azure-cli

# Windows (PowerShell)
winget install Microsoft.AzureCLI

Kurulumdan sonra login olalım:

az login

Bu komut tarayıcı açar ve Azure hesabınızla giriş yapmanızı ister. Terminal üzerinden çalışıyorsanız --use-device-code parametresini ekleyebilirsiniz.

Storage Account Oluşturma

Önce bir resource group oluşturalım, bu iyi bir pratiktir, kaynakları gruplamak hem yönetimi kolaylaştırır hem de proje bittiğinde toplu silme yapabilirsiniz:

# Resource group oluştur
az group create 
  --name rg-staticweb-prod 
  --location westeurope

# Storage account oluştur
az storage account create 
  --name mystatiwebsite2024 
  --resource-group rg-staticweb-prod 
  --location westeurope 
  --sku Standard_LRS 
  --kind StorageV2 
  --allow-blob-public-access true

Buradaki parametrelere dikkat edelim:

  • –name: Storage account adı küresel olarak benzersiz olmalı, harf ve rakamdan oluşmalı, 3-24 karakter
  • –sku Standard_LRS: Locally Redundant Storage, veriler aynı datacenter içinde 3 kez kopyalanıyor
  • –kind StorageV2: Static website özelliği için General Purpose v2 şart
  • –allow-blob-public-access true: Websitesi dosyalarına anonim erişim için gerekli

Statik Web Sitesi Özelliğini Aktif Etme

Şimdi asıl kısma geliyoruz. Bu tek komutla static website özelliğini açıyoruz:

az storage blob service-properties update 
  --account-name mystatiwebsite2024 
  --static-website 
  --index-document index.html 
  --404-document 404.html

Bu komutu çalıştırdıktan sonra Azure otomatik olarak $web container’ını oluşturur. Artık bu container’a koyduğunuz dosyalar web üzerinden erişilebilir.

Websitesi URL’ini öğrenmek için:

az storage account show 
  --name mystatiwebsite2024 
  --resource-group rg-staticweb-prod 
  --query "primaryEndpoints.web" 
  --output tsv

Çıktı şuna benzer bir şey olacak: https://mystatiwebsite2024.z6.web.core.windows.net/

İlk Dosyaları Yükleyelim

Basit bir test sitesi oluşturalım ve yükleyelim:

# Test dosyaları oluştur
mkdir -p mysite
cat > mysite/index.html << 'EOF'
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Azure Static Website</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
        h1 { color: #0078d4; }
    </style>
</head>
<body>
    <h1>Merhaba Azure!</h1>
    <p>Bu site Azure Blob Storage üzerinden sunuluyor.</p>
</body>
</html>
EOF

cat > mysite/404.html << 'EOF'
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <title>Sayfa Bulunamadı</title>
</head>
<body>
    <h1>404 - Sayfa Bulunamadı</h1>
    <a href="/">Ana Sayfaya Dön</a>
</body>
</html>
EOF

# Dosyaları yükle
az storage blob upload-batch 
  --account-name mystatiwebsite2024 
  --destination '$web' 
  --source mysite/ 
  --overwrite true

Dosyaları yükledikten sonra az önce aldığınız URL’ye gidin ve sitenizi görün.

Gerçek Dünya Senaryosu: React Uygulaması Deploy Etme

Şimdi biraz daha gerçekçi bir senaryo yapalım. Diyelim ki bir React uygulamanız var ve bunu Azure’a deploy edeceksiniz.

# React uygulamanızı build edin
cd my-react-app
npm run build

# Build çıktısını Azure'a yükle
az storage blob upload-batch 
  --account-name mystatiwebsite2024 
  --destination '$web' 
  --source build/ 
  --overwrite true 
  --content-cache-control "max-age=31536000" 
  --pattern "static/*"

# HTML dosyaları için farklı cache stratejisi
az storage blob upload-batch 
  --account-name mystatiwebsite2024 
  --destination '$web' 
  --source build/ 
  --overwrite true 
  --content-cache-control "no-cache, no-store, must-revalidate" 
  --pattern "*.html"

Neden iki ayrı upload komutu? Çünkü React build çıktısında static/ klasöründeki dosyalar (JS, CSS, resimler) dosya adlarında hash bulunuyor, main.a3b4c5d6.js gibi. Bu dosyalar değiştiğinde adları değişiyor, dolayısıyla uzun süre cache’lenebilirler. Ama index.html değiştiğinde tarayıcının hemen yeni versiyonu alması lazım.

SPA Routing Sorunu ve Çözümü

React, Vue gibi SPA’larda bir sorunla karşılaşırsınız. Kullanıcı https://siteniz.com/hakkimizda adresine direkt girerse Azure Storage 404 döner, çünkü sunucuda /hakkimizda/index.html diye bir dosya yok.

Bu sorunun çözümü basit ama akıllıca: 404 document olarak index.html‘i ayarlayın.

az storage blob service-properties update 
  --account-name mystatiwebsite2024 
  --static-website 
  --index-document index.html 
  --404-document index.html

Bu sayede her 404’te React uygulamanız devreye girer ve kendi routing’ini yapar. Tek dezavantajı HTTP 404 yerine HTTP 200 döndürülmesi ama SPA’lar için bu kabul edilebilir bir trade-off.

Özel Domain ve SSL Kurulumu

Azure Storage’ın varsayılan URL’si *.web.core.windows.net formatında, production’da bunu kullanmak istemezsiniz. Kendi domain’inizi bağlamak için Azure CDN kullanmanız gerekiyor.

Önce CDN profile ve endpoint oluşturalım:

# CDN Profile oluştur
az cdn profile create 
  --name cdn-staticweb-prod 
  --resource-group rg-staticweb-prod 
  --sku Standard_Microsoft

# CDN Endpoint oluştur
az cdn endpoint create 
  --name mywebsite-endpoint 
  --profile-name cdn-staticweb-prod 
  --resource-group rg-staticweb-prod 
  --origin mystatiwebsite2024.z6.web.core.windows.net 
  --origin-host-header mystatiwebsite2024.z6.web.core.windows.net 
  --enable-compression true 
  --query-string-caching-behavior IgnoreQueryString

CDN endpoint oluştuktan sonra custom domain ekleyebilirsiniz. Bunun için önce DNS kaydı eklemeniz gerekiyor. Domain’iniz için CNAME kaydı ekleyin:

www.sirketiniz.com -> mywebsite-endpoint.azureedge.net

DNS yayılımı tamamlandıktan sonra:

# Custom domain ekle
az cdn custom-domain create 
  --endpoint-name mywebsite-endpoint 
  --profile-name cdn-staticweb-prod 
  --resource-group rg-staticweb-prod 
  --name www-sirketiniz-com 
  --hostname www.sirketiniz.com

# HTTPS aktif et (ücretsiz SSL sertifikası)
az cdn custom-domain enable-https 
  --endpoint-name mywebsite-endpoint 
  --profile-name cdn-staticweb-prod 
  --resource-group rg-staticweb-prod 
  --name www-sirketiniz-com 
  --min-tls-version 1.2

SSL sertifikası otomatik olarak oluşturulur ve yenilenir, sizin müdahalenize gerek yok.

CI/CD Pipeline ile Otomatik Deploy

Manuel deployment iyi bir başlangıç ama production’da her commit’te otomatik deploy istiyorsunuz. GitHub Actions ile nasıl yapıldığını görelim:

# Deployment için gerekli credentials'ı al
az ad sp create-for-rbac 
  --name "sp-staticweb-deploy" 
  --role "Storage Blob Data Contributor" 
  --scopes "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/rg-staticweb-prod/providers/Microsoft.Storage/storageAccounts/mystatiwebsite2024" 
  --sdk-auth

Bu komutun çıktısını GitHub repository’nizde AZURE_CREDENTIALS adıyla secret olarak kaydedin. Sonra .github/workflows/deploy.yml dosyası oluşturun:

name: Deploy to Azure Storage

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Login to Azure
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      - name: Deploy static files
        uses: azure/CLI@v1
        with:
          inlineScript: |
            az storage blob upload-batch 
              --account-name mystatiwebsite2024 
              --destination '$web' 
              --source build/ 
              --overwrite true

      - name: Purge CDN cache
        uses: azure/CLI@v1
        with:
          inlineScript: |
            az cdn endpoint purge 
              --endpoint-name mywebsite-endpoint 
              --profile-name cdn-staticweb-prod 
              --resource-group rg-staticweb-prod 
              --content-paths '/*'

CDN cache purge adımı kritik, aksi halde kullanıcılar eski versiyonu görmeye devam edebilir.

Maliyet Optimizasyonu

Azure Storage statik web sitesi barındırma gerçekten ucuz, ama birkaç noktaya dikkat etmek gerekiyor.

Storage maliyeti için lifecycle policy ekleyin, eski versiyonları otomatik silin:

# Lifecycle policy JSON dosyası oluştur
cat > lifecycle-policy.json << 'EOF'
{
  "rules": [
    {
      "name": "deleteOldVersions",
      "enabled": true,
      "type": "Lifecycle",
      "definition": {
        "filters": {
          "blobTypes": ["blockBlob"],
          "prefixMatch": ["$web/"]
        },
        "actions": {
          "version": {
            "delete": {
              "daysAfterCreationGreaterThan": 30
            }
          }
        }
      }
    }
  ]
}
EOF

# Policy'yi uygula
az storage account management-policy create 
  --account-name mystatiwebsite2024 
  --resource-group rg-staticweb-prod 
  --policy @lifecycle-policy.json

Bant genişliği maliyetini düşürmek için dosyaları doğru sıkıştırma ile sunun. Azure CDN bunu otomatik yapabiliyor ama storage tarafında da compression ayarlayabilirsiniz:

# Gzip sıkıştırılmış CSS yükle
gzip -k build/static/css/main.css
az storage blob upload 
  --account-name mystatiwebsite2024 
  --container-name '$web' 
  --name static/css/main.css 
  --file build/static/css/main.css.gz 
  --content-encoding gzip 
  --content-type text/css 
  --overwrite true

Monitoring ve Alerting

Sitenizin durumunu izlemek için birkaç temel alert kuralı oluşturalım:

# Storage account için diagnostic settings aktif et
az monitor diagnostic-settings create 
  --name diag-staticweb 
  --resource "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/rg-staticweb-prod/providers/Microsoft.Storage/storageAccounts/mystatiwebsite2024/blobServices/default" 
  --logs '[{"category": "StorageRead", "enabled": true}, {"category": "StorageWrite", "enabled": true}]' 
  --metrics '[{"category": "Transaction", "enabled": true}]' 
  --workspace "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/rg-staticweb-prod/providers/Microsoft.OperationalInsights/workspaces/log-staticweb"

Storage availability düştüğünde alert almak için:

az monitor metrics alert create 
  --name alert-storage-availability 
  --resource-group rg-staticweb-prod 
  --scopes "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/rg-staticweb-prod/providers/Microsoft.Storage/storageAccounts/mystatiwebsite2024" 
  --condition "avg Availability < 99" 
  --window-size 5m 
  --evaluation-frequency 1m 
  --action-group "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/rg-staticweb-prod/providers/Microsoft.Insights/actionGroups/ag-ops-team" 
  --description "Storage availability dropped below 99%"

Güvenlik Ayarları

Statik site olmasına rağmen güvenlik ayarlarını ihmal etmeyin.

CORS ayarları, eğer sitenizdeki JavaScript başka API’lara istek yapıyorsa:

az storage cors add 
  --account-name mystatiwebsite2024 
  --services b 
  --methods GET HEAD OPTIONS 
  --origins "https://www.sirketiniz.com" 
  --allowed-headers "*" 
  --exposed-headers "*" 
  --max-age 3600

Storage account’a minimum TLS versiyonu zorunlu kılın:

az storage account update 
  --name mystatiwebsite2024 
  --resource-group rg-staticweb-prod 
  --min-tls-version TLS1_2 
  --https-only true

Public access’i sadece $web container ile sınırlı tutun, diğer container’lar özel kalsın. Bu varsayılan davranış zaten ama her ihtimale karşı kontrol edin:

# Diğer container'ların public access durumunu kontrol et
az storage container list 
  --account-name mystatiwebsite2024 
  --query "[].{name:name, publicAccess:properties.publicAccess}" 
  --output table

Yaygın Sorunlar ve Çözümleri

MIME type sorunları: Bazı dosyalar yanlış content-type ile sunulabilir. Örneğin .json dosyaları application/octet-stream olarak sunulursa tarayıcı onları download eder. Yükleme sırasında content-type belirtin:

az storage blob upload 
  --account-name mystatiwebsite2024 
  --container-name '$web' 
  --name manifest.json 
  --file build/manifest.json 
  --content-type application/json 
  --overwrite true

CDN cache sorunu: Deploy ettiniz ama eski site görünüyor. CDN cache’ini temizleyin:

az cdn endpoint purge 
  --endpoint-name mywebsite-endpoint 
  --profile-name cdn-staticweb-prod 
  --resource-group rg-staticweb-prod 
  --content-paths '/' '/index.html' '/static/*'

404 hataları: SPA kullanıyorsanız ve 404 document’ı index.html olarak ayarladıysanız, HTTP durum kodu 404 döner, bu bazı SEO araçlarını yanıltabilir. Azure Front Door veya CDN kuralları ile bu sorunu daha zarif bir şekilde çözebilirsiniz.

Büyük dosya yükleme hataları: Çok sayıda küçük dosya yüklerken zaman aşımı olabilir. --max-connections parametresi ile paralel upload’ları artırın:

az storage blob upload-batch 
  --account-name mystatiwebsite2024 
  --destination '$web' 
  --source build/ 
  --overwrite true 
  --max-connections 10

Alternatif: Azure Static Web Apps

Bu noktada şunu sormak gerekiyor: Neden Azure Storage kullanalım, Azure Static Web Apps değil mi? İkisi de statik site barındırıyor ama farklı kullanım senaryoları var.

Azure Static Web Apps:

  • GitHub/GitLab ile native entegrasyon
  • Serverless API desteği (Azure Functions)
  • Otomatik preview environments (PR başına ayrı URL)
  • Ücretsiz SSL ve custom domain
  • Ama daha az granular kontrol

Azure Storage Static Website:

  • Tam kontrol sizde
  • Herhangi bir CI/CD pipeline ile çalışır
  • CDN yapılandırmasını kendiniz yaparsınız
  • Daha ucuz (çok yoğun trafik senaryolarında)
  • Legacy veya özel iş gereksinimleri için daha esnek

Basit bir landing page veya blog için Static Web Apps daha pratik. Kurumsal altyapı, özel CDN kuralları veya mevcut DevOps pipeline’larına entegrasyon için Storage daha iyi bir tercih.

Sonuç

Azure Storage ile statik web sitesi barındırma, doğru kullanıldığında hem ekonomik hem de güvenilir bir çözüm. Temel kurulum birkaç komut mesafesinde, ama production’a alacaksanız CDN, SSL, monitoring ve CI/CD pipeline’ı eksiksiz kurmanız gerekiyor.

En sık düşülen hata, storage hesabını olduğu gibi bırakıp CDN eklemeden yayına çıkmak. Azure Storage’ın varsayılan URL’i hem SEO açısından hem de performans açısından yetersiz, CDN eklemek bir seçenek değil zorunluluk.

SPA’lar için 404 document trick’i hayat kurtarır, bunu uygulamayı unutmayın. Cache stratejisi de kritik, HTML dosyaları ile static asset’leri farklı cache ayarlarıyla yönetin.

Maliyetler konusunda endişeleriniz varsa şunu söyleyeyim: Orta ölçekli bir site için ayda 5-10 dolar bandında bir maliyet bekliyorsunuz, traffic artışında storage değil CDN bant genişliği faturanıza yansıyor. Lifecycle policy ile eski dosyaları temizleyin, CDN compression’ı aktif edin ve gereksiz API call’larından kaçının.

Infrastructure as Code yaklaşımını benimseyip tüm bu komutları Terraform veya Bicep ile yönetirseniz, hem tekrar kullanılabilir bir yapı kurmuş olursunuz hem de ekip arkadaşlarınız ne yaptığınızı anlayabilir. Bu konuyu ayrı bir yazıda ele alalım.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir