Bir sunucuda birden fazla web uygulamasını farklı alan adlarıyla güvenli (HTTPS) şekilde yayınlamak istiyorsanız, modern bir ters proxy çözümü olan Traefik v3 harika bir seçenek. Bu rehberde, Docker Compose kullanarak Traefik v3 ile otomatik Let’s Encrypt sertifika yönetimini, HTTP’den HTTPS’e yönlendirmeyi ve birden fazla alan adını tek yapılandırmada yönetmeyi adım adım göstereceğim.
Traefik v3 nedir ve neden tercih edilmeli?
Traefik v3, konteyner tabanlı mimariler için optimize edilmiş, otomatik keşif ve sade etiketleme (label) mantığıyla çalışan bir ters proxy ve yük dengeleyicidir. Docker, Kubernetes ve diğer sağlayıcılarla derin entegrasyon sunar. v3 sürümü, performans ve yapılandırma deneyiminde iyileştirmeler getirirken, Let’s Encrypt ile otomatik TLS/SSL sertifikalandırmayı pratik hale getirir.
Ön koşullar ve DNS
- Bir Linux sunucu (Ubuntu/Debian/CentOS vb.)
- Docker ve Docker Compose kurulu
- Alan adınızda, sunucunuzun IP adresine işaret eden A/AAAA kayıtları (örnek: app.example.com ve traefik.example.com)
İpucu: Cloudflare kullanıyorsanız ve HTTP-01 doğrulaması yapacaksanız, ilgili DNS kaydını “DNS only” (turuncu bulut kapalı) olarak ayarlayın; aksi halde Let’s Encrypt doğrulaması başarısız olabilir.
Adım 1: Docker ağı ve klasörler
Aşağıdaki ağ, farklı Compose dosyaları arasında servisleri paylaşmanızı sağlar. Oluşturun:
docker network create web
mkdir -p traefik/letsencrypt
touch traefik/letsencrypt/acme.json
chmod 600 traefik/letsencrypt/acme.json
Adım 2: Traefik v3 için docker-compose.yml
Aşağıdaki dosya, Traefik’i 80/443 portlarına bağlar, Let’s Encrypt’i HTTP-01 ile etkinleştirir, HTTP’yi otomatik olarak HTTPS’e yönlendirir ve güvenli bir kontrol paneli kurar. E-postayı ve alan adlarını kendinize göre düzenlemeyi unutmayın.
version: "3.8"
services:
traefik:
image: traefik:v3.0
container_name: traefik
command:
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- [email protected]
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
- --api.dashboard=true
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik/letsencrypt:/letsencrypt
networks:
- web
labels:
- "traefik.enable=true"
# Dashboard için güvenli router
- "traefik.http.routers.api.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
# Basit BasicAuth middleware (parolayı hashleyip $$ ile kaçırın)
- "traefik.http.middlewares.basicauth.basicauth.users=admin:$$2y$$12$$REPLACE_WITH_YOUR_BCRYPT_HASH"
- "traefik.http.routers.api.middlewares=basicauth@docker"
# Örnek uygulama
whoami:
image: traefik/whoami
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`app.example.com`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
networks:
- web
networks:
web:
external: true
Bu dosyada iki önemli nokta var: “exposedbydefault=false” etiketsiz konteynerların dış dünyaya açılmasını engeller; “http redirections” ise tüm HTTP trafiğini otomatik olarak HTTPS’e taşır. Dashboard’ı traefik.example.com üzerinden basit bir BasicAuth ile koruyoruz. Parola hash’ini üretmek için şu komutlardan birini kullanabilirsiniz:
# OpenSSL ile bcrypt:
htpasswd -nbB admin SIFRENIZ
# Ya da Python:
python3 -c "import bcrypt; print(b'admin:' + bcrypt.hashpw(b'SIFRENIZ', bcrypt.gensalt()))"
Elde ettiğiniz hash’i compose dosyasına yapıştırırken $ karakterlerini $$ ile kaçırın; aksi halde Compose bunu çevresel değişken sanacaktır.
Adım 3: Servis ekleme ve çoklu alan adı
Yeni bir servis eklemek için ilgili konteynere “traefik.enable=true” etiketi ve “rule=Host(`sub.example.com`)" kuralı tanımlayın. Her servis için ayrı router, entrypoint ve TLS resolver atayabilirsiniz. Örneğin bir Node.js uygulaması için:
myapp:
image: node:20-alpine
working_dir: /app
command: ["node", "server.js"]
volumes:
- ./myapp:/app
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`api.example.com`)"
- "traefik.http.routers.myapp.entrypoints=websecure"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
networks:
- web
Statik dosya sunucuları, PHP-FPM arkasındaki Nginx veya Go/Rust uygulamaları da benzer şekilde etiketlenir. Tüm servisler aynı “web” ağına bağlı oldukça Traefik onları otomatik keşfeder.
Güvenlik ve en iyi uygulamalar
- Dashboard’ı mutlaka alt alan adı ve BasicAuth (veya IP kısıtlaması) ile koruyun.
- “acme.json” dosyasını 600 izinleriyle saklayın; sertifika anahtarları bu dosyada tutulur.
- Gereksiz portları açmayın; yalnızca 80 ve 443 çoğu kurulum için yeterlidir.
- Üretimde otomatik yeniden başlatma politikası (“restart: unless-stopped”) kullanabilirsiniz.
Sık karşılaşılan hatalar ve çözümler
- Sertifika alınamadı: DNS kayıtlarınız doğru mu? Cloudflare “proxied” açık mı? HTTP-01 için kapalı olmalı. Alternatif olarak DNS-01 challenge kullanarak wildcard (*.example.com) alabilirsiniz.
- 80/443 dinlenemiyor: Sunucuda bu portları kullanan farklı bir servis (ör. Nginx) çalışıyor olabilir. Kapatın veya taşıyın.
- Rate limit: Let’s Encrypt test sırasında üretim yerine staging sunucularını deneyin. Traefik için “acme.caserver” parametresiyle staging’e geçebilirsiniz.
- “acme.json permission denied”: Dosya izinlerini 600 yapın ve doğru mount yolunu kontrol edin.
Sonuç
Traefik v3 ve Docker Compose ile çok sayıda servisi tek bir sunucu üzerinde, otomatik SSL ve modern yönlendirme yetenekleriyle dakikalar içinde yayına alabilirsiniz. Etiket tabanlı mimari, CI/CD süreçlerine rahatça entegre olurken, yeniden başlatma ihtiyacı olmadan konfigürasyon değişikliklerini devreye almanızı sağlar. Üstelik ölçeklenebilir ve gözlemlenebilir bir altyapının temelini atmış olursunuz.