GitLab Pages ile Statik Site Yayınlama Rehberi
Statik site barındırmak için bir VPS kiralamak, Nginx kurmak, SSL sertifikası ayarlamak… Bunların hepsini daha önce yaşadıysanız ne kadar vakit aldığını biliyorsunuzdur. GitLab Pages tam bu noktada devreye giriyor ve tüm bu süreci birkaç satır YAML ile hallediyor. CI/CD pipeline’ınız zaten varsa, statik sitenizi yayına almak için ekstra bir şey yapmanıza gerek kalmıyor.
Bu yazıda GitLab Pages’i sıfırdan kuracağız, özel domain bağlayacağız, farklı static site generator’larla nasıl çalıştığını göreceğiz ve production ortamında karşılaşabileceğiniz tipik sorunları ele alacağız.
GitLab Pages Nedir, Ne Değildir
GitLab Pages, GitLab üzerindeki bir repository’den statik içerik sunmanızı sağlayan bir servistir. GitLab.com üzerinde ücretsiz kullanabilirsiniz, self-hosted GitLab kurulumlarınıza da entegre edebilirsiniz.
Önemli bir nokta: GitLab Pages sadece statik içerik sunar. PHP çalıştıramazsınız, veritabanına bağlanamazsınız, sunucu taraflı herhangi bir kod koşamazsınız. Ama Hugo, Jekyll, Gatsby, MkDocs, VuePress gibi static site generator’larla ürettiğiniz çıktıları, ya da direkt HTML/CSS/JS dosyalarını sonuna kadar güzel yayımlayabilirsiniz.
Servisin temel mantığı şu:
- CI/CD pipeline çalışır
- Build işlemi sonucunda
public/adında bir dizin oluşturulur - Bu dizin
pagesjob’ı tarafından artifact olarak işaretlenir - GitLab bu dizini statik web sunucusunda yayımlar
Temel Gereksinimler
Başlamadan önce nelere ihtiyacınız var:
- GitLab hesabı: GitLab.com veya kendi sunucunuzda GitLab CE/EE kurulu olmalı
- Repository: Public veya private, fark etmez
.gitlab-ci.ymldosyası: Pipeline tanımınız- Build çıktısı
public/dizinine gitmeli: Bu zorunlu, değiştirilemez
Self-hosted GitLab kullanıyorsanız, sistem yöneticisinin GitLab Pages özelliğini etkinleştirmiş olması gerekiyor. /etc/gitlab/gitlab.rb dosyasında pages_external_url tanımlanmış olmalı.
En Basit Örnek: Düz HTML Sitesi
Önce işin özünü görmek için en minimal örneği yapalım. Elimizde sadece statik HTML dosyaları var diyelim.
my-site/
├── .gitlab-ci.yml
├── index.html
├── about.html
└── assets/
├── style.css
└── app.js
Bu yapı için .gitlab-ci.yml dosyası şöyle olur:
pages:
stage: deploy
script:
- mkdir -p public
- cp -r index.html about.html assets/ public/
artifacts:
paths:
- public
only:
- main
Bu kadar. Gerçekten bu kadar. pages job adı özel ve zorunludur, değiştirirseniz GitLab Pages devreye girmez. artifacts.paths altında public tanımlanması da zorunludur.
Commit’i atıp push’ladıktan sonra GitLab’ın sol menüsünden Deploy > Pages kısmına gidip sitenizin URL’ini görebilirsiniz. GitLab.com kullanıyorsanız adres şu formatta olur: https://kullaniciadiniz.gitlab.io/proje-adi/
Hugo ile GitLab Pages
Hugo, Go ile yazılmış ve inanılmaz hızlı bir static site generator. Blog, dokümantasyon sitesi, şirket web sitesi için sıklıkla tercih edilen araçlardan biri. GitLab Pages ile birlikte kullanımı oldukça yaygın.
Önce local’de Hugo projesini oluşturun:
hugo new site myblog
cd myblog
git init
git remote add origin [email protected]:kullaniciadiniz/myblog.git
Bir tema ekleyin, sonra .gitlab-ci.yml dosyasını oluşturun:
image: registry.gitlab.com/pages/hugo:latest
variables:
GIT_SUBMODULE_STRATEGY: recursive
pages:
stage: deploy
script:
- hugo --minify
artifacts:
paths:
- public
rules:
- if: $CI_COMMIT_BRANCH == "main"
pages-test:
stage: deploy
script:
- hugo --minify --baseURL "/"
artifacts:
paths:
- public
expire_in: 1 week
rules:
- if: $CI_COMMIT_BRANCH != "main"
Burada GIT_SUBMODULE_STRATEGY: recursive ayarı önemli. Hugo temaları genellikle git submodule olarak ekleniyor, bu ayar olmadan tema dosyaları pipeline içinde boş gelecektir.
pages-test job’ı ise main dışındaki branch’lerde çalışıyor ve preview build üretiyor. Production’a almadan önce görsel kontrol yapabilmek için kullanışlı.
Hugo Sürüm Yönetimi
Zaman içinde farklı projeleriniz farklı Hugo sürümleri gerektirebilir. Bunu .gitlab-ci.yml içinde sabit bir imajla çözmek yerine, extend edilebilir bir yaklaşım kullanabilirsiniz:
variables:
HUGO_VERSION: "0.120.4"
pages:
stage: deploy
image: hugomods/hugo:${HUGO_VERSION}
script:
- hugo --minify --gc
artifacts:
paths:
- public
rules:
- if: $CI_COMMIT_BRANCH == "main"
Jekyll ile GitLab Pages
Jekyll, GitHub Pages’in de kullandığı Ruby tabanlı static site generator. GitLab’ın kendi dökümantasyon sitesi bile yıllarca Jekyll ile çalıştı.
image: ruby:3.2
cache:
paths:
- vendor/
before_script:
- gem install bundler
- bundle install --path vendor
pages:
stage: deploy
script:
- bundle exec jekyll build -d public
artifacts:
paths:
- public
rules:
- if: $CI_COMMIT_BRANCH == "main"
test:
stage: test
script:
- bundle exec jekyll build -d test
- bundle exec htmlproofer test --disable-external
artifacts:
paths:
- test
expire_in: 1 week
rules:
- if: $CI_COMMIT_BRANCH != "main"
Bu örnekte htmlproofer tool’unu da ekliyoruz. Broken link’leri, eksik alt etiketlerini, geçersiz iç linkleri otomatik olarak kontrol ediyor. Production’a gitmeden önce bu kontrollerin geçmesi gerekiyor.
cache kısmı da önemli. Ruby gem’lerini her pipeline’da sıfırdan indirmek yerine cache’leyerek pipeline süresini ciddi ölçüde kısaltıyoruz.
MkDocs ile Teknik Dokümantasyon Sitesi
Proje dokümantasyonu, iç wiki, API dökümantasyonu için MkDocs mükemmel bir araç. Material teması ile de profesyonel bir görünüm elde edebiliyorsunuz.
image: python:3.11-slim
cache:
paths:
- .cache/pip
before_script:
- pip install mkdocs mkdocs-material mkdocs-minify-plugin
pages:
stage: deploy
script:
- mkdocs build --strict --verbose
- mv site public
artifacts:
paths:
- public
rules:
- if: $CI_COMMIT_BRANCH == "main"
lint-docs:
stage: test
script:
- pip install mkdocs mkdocs-material
- mkdocs build --strict
rules:
- if: $CI_COMMIT_BRANCH != "main"
--strict flag’i burada kritik. Uyarıları hata olarak işliyor, yani broken link veya eksik referans varsa pipeline fail ediyor. Dökümantasyon kalitesini otomatik olarak zorlamış oluyorsunuz.
Özel Domain Bağlamak
GitLab’ın verdiği *.gitlab.io URL’i çoğu kişisel proje için yeterli, ama kurumsal kullanımda kendi domain’inizi bağlamak isteyeceksiniz.
GitLab.com üzerinde özel domain eklemek için:
1. GitLab’da domain ekleyin
Repository sayfasından Deploy > Pages kısmına gidin, New Domain butonuna tıklayın ve domain’inizi girin. GitLab size bir verification TXT kaydı gösterecek.
2. DNS kayıtlarını ayarlayın
Domain sağlayıcınızın panelinde şu kayıtları ekleyin:
# Apex domain için (ornegin example.com)
CNAME @ kullaniciadiniz.gitlab.io
# Alt domain için (ornegin blog.example.com)
CNAME blog kullaniciadiniz.gitlab.io
# Verification icin
TXT _gitlab-pages-verification-code.example.com gitlab-pages-verification-code=xxxxxxxx
3. SSL sertifikasını aktifleştirin
GitLab, Let’s Encrypt entegrasyonu ile otomatik SSL sertifikası alabiliyor. Domain doğrulandıktan sonra Force HTTPS seçeneğini de aktif edin.
DNS propagation’ı bekleyip doğruladıktan sonra siteniz https://example.com adresinden yayımlanmaya başlayacak.
Erişim Kontrolü ve Private Pages
Bazı durumlarda sitenin herkese açık olmasını istemezsiniz. Staging ortamı, iç dökümantasyon, müşteriye özel preview sayfaları… GitLab Pages için erişim kontrolü tanımlayabilirsiniz.
Repository sayfasından Settings > General > Visibility, project features, permissions kısmına gidip Pages bölümünde şu seçenekler var:
- Everyone: Herkes erişebilir
- Everyone with access: Proje member’ları
- Only project members: Sadece proje üyeleri
Private pages aktif olduğunda ziyaretçilerden GitLab hesabıyla giriş yapmaları isteniyor. CI/CD job’larından erişmek için ise CI_JOB_TOKEN kullanabilirsiniz.
Gerçek Dünya Senaryosu: Çoklu Ortam Yayımı
Bir şirkette çalıştığınızı ve hem staging hem production ortamı için GitLab Pages kullanmak istediğinizi düşünelim. Develop branch’i staging’e, main branch’i production’a yayımlamalı.
stages:
- build
- test
- deploy
variables:
NODE_VERSION: "20"
.build-template: &build-template
image: node:${NODE_VERSION}-alpine
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
before_script:
- npm ci
build-staging:
<<: *build-template
stage: build
script:
- npm run build:staging
artifacts:
paths:
- dist/
expire_in: 1 day
rules:
- if: $CI_COMMIT_BRANCH == "develop"
build-production:
<<: *build-template
stage: build
script:
- npm run build:production
artifacts:
paths:
- dist/
expire_in: 1 week
rules:
- if: $CI_COMMIT_BRANCH == "main"
lighthouse-test:
stage: test
image: cypress/browsers:node20-chrome108
script:
- npm install -g @lhci/cli
- lhci autorun
rules:
- if: $CI_COMMIT_BRANCH == "main"
allow_failure: true
pages:
stage: deploy
script:
- mv dist public
artifacts:
paths:
- public
rules:
- if: $CI_COMMIT_BRANCH == "main"
environment:
name: production
url: https://example.com
pages-staging:
stage: deploy
script:
- mv dist public
artifacts:
paths:
- public
expire_in: 2 weeks
rules:
- if: $CI_COMMIT_BRANCH == "develop"
environment:
name: staging
url: https://staging.example.com
Bu yapıda environment tanımı önemli. GitLab’ın Operate > Environments sayfasında her iki ortamın durumunu, son deploy’u ve URL’ini görebiliyorsunuz.
Pipeline Optimizasyonu
Pages pipeline’ınız zamanla yavaşlayabilir. Birkaç pratik optimizasyon:
Cache Stratejisi
cache:
key:
files:
- package-lock.json
prefix: ${CI_JOB_NAME}
paths:
- node_modules/
policy: pull-push
key.files ile package-lock.json değiştiğinde cache invalidate oluyor, değişmediğinde eski cache kullanılıyor. prefix ile her job’ın kendi cache’i oluyor, çakışma olmuyor.
Parallel Build
Büyük sitelerde build işlemi uzun sürebilir. Mümkünse build’i parçalara bölebilirsiniz:
build-en:
stage: build
script:
- hugo --contentDir content/en --destination public/en
artifacts:
paths:
- public/en/
build-tr:
stage: build
script:
- hugo --contentDir content/tr --destination public/tr
artifacts:
paths:
- public/tr/
pages:
stage: deploy
script:
- mkdir -p public
- cp -r public/en/* public/
- cp -r public/tr/* public/
artifacts:
paths:
- public
Sadece Değişen Dosyalarda Build Tetikleme
Her commit’te tam build yapmak istemeyebilirsiniz. Özellikle büyük bir dokümantasyon sitesinde sadece content değiştiğinde build tetiklensin isteyebilirsiniz:
pages:
stage: deploy
script:
- mkdocs build
- mv site public
artifacts:
paths:
- public
rules:
- if: $CI_COMMIT_BRANCH == "main"
changes:
- docs/**/*
- mkdocs.yml
changes direktifi ile sadece belirtilen dosyalar değiştiğinde job tetikleniyor.
Sık Karşılaşılan Sorunlar
Public Dizini Oluşturulmuyor
En yaygın hata budur. Job başarılı görünür ama Pages güncellenmez. Sebebi genellikle build aracının çıktıyı farklı bir dizine yazmasıdır.
# Yanlis: Build ciktisi dist/ dizinine gidiyor
npm run build
# public/ dizini yok, Pages guncellenmez
# Dogru: dist/ icerigi public/ altina aliniyor
npm run build
mv dist public
Base URL Problemi
Statik siteniz https://kullanici.gitlab.io/proje-adi/ altında yayımlanıyor ama site kök dizinde (/) olduğunu varsayarak asset yüklüyor. Bu durumda CSS ve JS dosyaları yüklenemiyor.
Hugo için:
script:
- hugo --baseURL "https://kullanici.gitlab.io/proje-adi/"
Ya da config.yaml içinde:
baseURL: "https://kullanici.gitlab.io/proje-adi/"
404 Sayfaları Single Page Application’larda
React, Vue gibi SPA’lar client-side routing kullanıyor. GitLab Pages doğrudan dosya sunduğu için /about adresine gidildiğinde about.html arar, bulamazsa 404 döner.
Çözüm: 404.html dosyasını index.html ile aynı yapın. GitLab Pages 404 durumunda 404.html dosyasını sunar, SPA kendi routing’ini halleder.
pages:
script:
- npm run build
- cp public/index.html public/404.html
artifacts:
paths:
- public
Self-Hosted GitLab’da Pages Etkin Değil
Kendi GitLab kurulumunuzda Pages çalışmıyorsa önce /etc/gitlab/gitlab.rb dosyasını kontrol edin:
sudo grep -i pages /etc/gitlab/gitlab.rb | grep -v "^#"
Gerekli minimum konfigürasyon:
pages_external_url 'http://pages.example.com'
gitlab_pages['enable'] = true
Değişiklik yaptıktan sonra:
sudo gitlab-ctl reconfigure
sudo gitlab-ctl restart gitlab-pages
Deployment Koruması
Production ortamı için deployment’ları koruma altına almak iyi bir pratik. Settings > CI/CD > Protected Environments kısmından production environment’ı koruma altına alabilir, sadece belirli role’lerin deployment yapabilmesini sağlayabilirsiniz.
Aynı şekilde Settings > Repository > Protected Branches kısmından main branch’ini koruma altına alın. Direkt push’u kapat, sadece merge request ile değişiklik yapılabilsin.
Bu sayede sitenize giden her değişiklik code review sürecinden geçmek zorunda kalır. Hem güvenlik hem de kalite açısından kritik.
Monitoring ve Analitik
GitLab Pages kendi access log’unu kullanıcıya açmıyor. Sitenize gelen trafiği takip etmek için client-side analitik araçları kullanmanız gerekiyor.
Privacy-friendly seçenekler:
- Plausible.io: GDPR uyumlu, cookie’siz
- Fathom Analytics: Basit ve hızlı
- Umami: Self-hosted, tamamen ücretsiz
Google Analytics kullanmak istiyorsanız çoğu static site generator bunu doğrudan destekliyor. Hugo için config.yaml içine Google Analytics ID’nizi eklemek yeterli.
Sonuç
GitLab Pages, birkaç satır YAML ile production-ready statik site yayımlamanızı sağlayan güçlü bir araç. Öğrenme eğrisi neredeyse yok, bakım maliyeti çok düşük, ücretsiz SSL sertifikası ile birlikte geliyor.
Pratik öneri: Eğer hala bir VPS üzerinde manuel olarak statik site yayımlıyorsanız, en kısa sürede GitLab Pages’e geçin. Tek bir .gitlab-ci.yml dosyası, sunucu bakımı, SSL yenileme, Nginx konfigürasyonu gibi onlarca saatlik işin önüne geçiyor.
Büyük ekipler için de ölçeklenebilir: protected environment’lar, deployment approval’ları ve environment-specific build konfigürasyonları ile tam anlamıyla bir CI/CD sürecine entegre edebiliyorsunuz.
Bir sonraki adım olarak GitLab’ın Review Apps özelliğine bakmanızı öneririm. Her merge request için otomatik preview ortamı oluşturuyor ve Pages ile birlikte kullanıldığında kod review sürecini görsel olarak çok daha verimli hale getiriyor.
