SSD Nodes Learn Hosting plans →
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-08-27

Tek Docker Compose Dosyasında Traefik ile 5 Uygulama

Traefik v3 kullanarak tek IP adresi üzerinden beş farklı uygulamayı yönetin. Host kuralları, otomatik TLS ve acme.json dosyasındaki izin hatası gibi kritik sorunları çözün.

Tek IP, beş uygulama, tek 443 portu

VPS sunucunuzun tek bir genel IPv4 adresi ve tek bir TCP 443 portu vardır. Bu sunucuda Gitea, uygulamanızın bir staging kopyası, dahili bir panel, bir durum sayfası ve bir webhook alıcısı olmak üzere beş farklı alan adı barındırmak istiyorsunuz. Reverse proxy, :80 ve :443 portlarını yöneten, her istekteki Host başlığını okuyan ve isteği doğru container'a ileten süreçtir. Traefik bu işlemi gerçekleştirir; ayrıca siz manuel olarak certbot çalıştırmanıza gerek kalmadan her alan adı için sertifika alır ve yeniler. Nginx ve Caddy de aynı beş alan adını sorunsuz bir şekilde sonlandırabilir; bu nedenle seçim henüz yapılmadıysa, her birini birine bağlamadan önce üç proxy'nin sertifika yönetimi ve uygulama başına yapılandırma maliyeti açısından değerlendirilmesi faydalı olacaktır.

Traefik'i bir nginx server {} bloğundan ayıran şey, yapılandırmasının kaynağıdır. Nginx'te bir dosyayı düzenleyip yeniden yüklersiniz; sertifika yaşam döngüsü ise ayrı bir iş olarak kalır. Bu, nginx üzerinde certbot ile Let's Encrypt sertifikası oluşturma sürecinde izlediğiniz, yenileme zamanlayıcısının web sunucusundan tamamen bağımsız olduğu iş akışıdır. Traefik'in Docker sağlayıcısı, Docker olay akışını izler ve container'larınızdaki etiketleri (labels) okur: Host() kural etiketi taşıyan bir container başlattığınızda bir saniye içinde yönlendirilebilir hale gelir; durdurduğunuzda ise rota kaybolur. Tuzak da buradadır. Etiketlerde yaşayan yapılandırma aynı anda beş farklı yerdedir; hatalı bir etiket sessizce başarısız olur, container basitçe yönlendirilmez ve Traefik hiçbir uyarı vermez.

Dört temel kavram

  • Entrypoints (Giriş noktaları), dinleme soketleridir. İki adet tanımlayacaksınız: web, :80 üzerinde ve websecure, :443 üzerinde.
  • Routers (Yönlendiriciler), bir isteği (Host(...)) eşleştirir ve bir servise bağlar. Sertifikalar, tls.certresolver aracılığıyla yönlendirici bazında talep edilir.
  • Services (Servisler), arka uçtur; bir container ve onun Docker ağı içinde dinlediği porttur.
  • Middlewares (Ara katmanlar), yönlendirici ile servis arasında yer alır: temel kimlik doğrulama, IP izin listeleri, başlık yeniden yazma ve yönlendirmeler.

Bu dört kavram, aksi takdirde elle yazmanız gereken işlerin Traefik'teki karşılıklarıdır: yönlendirici bir server_name, servis bir proxy_pass hedefi ve ara katmanlar ise nginx reverse proxy sunucu bloğunu satır satır oluştururken kendi başınıza ayarladığınız başlık ve kimlik doğrulama yönergeleridir.

Statik yapılandırma (giriş noktaları, sağlayıcılar, ACME) Traefik komut satırından veya traefik.yml üzerinden aktarılır ve bu ayarları değiştirmek Traefik'in yeniden başlatılmasını gerektirir. Dinamik yapılandırma (yönlendiriciler, servisler, ara katmanlar) ise container etiketlerinden gelir ve anlık olarak yeniden yüklenir. Bu ikisini birbirine karıştırmak, "bayrağım hiçbir işe yaramıyor" sorununun yaygın kaynağıdır.

Compose dosyası

proxy adındaki paylaşımlı bir Docker ağı, yapının temelini oluşturur. Traefik, bir container'a yalnızca her ikisi de aynı ağ üzerindeyse erişebilir.

name: edge

networks:
  proxy:
    name: proxy

services:
  traefik:
    image: traefik:v3.5
    restart: unless-stopped
    command:
      - --providers.docker=true
      - --providers.docker.exposedByDefault=false
      - --providers.docker.network=proxy
      - --entryPoints.web.address=:80
      - --entryPoints.websecure.address=:443
      - --entryPoints.web.http.redirections.entryPoint.to=websecure
      - --entryPoints.web.http.redirections.entryPoint.scheme=https
      - --certificatesresolvers.le.acme.email=you@example.com
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.le.acme.tlschallenge=true
      # while you iterate, point at staging so a mistake costs nothing:
      # - --certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
      - --api.dashboard=true
      - --log.level=INFO
      - --accesslog=true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)
      - traefik.http.routers.dashboard.entrypoints=websecure
      - traefik.http.routers.dashboard.tls.certresolver=le
      - traefik.http.routers.dashboard.service=api@internal
      - traefik.http.routers.dashboard.middlewares=dashboard-auth
      - traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$REPLACE$$THIS

  gitea:
    image: gitea/gitea:1  # major-only pin keeps this demo copy-pasteable; pin an exact release in production
    restart: unless-stopped
    volumes:
      - ./gitea:/data
    networks:
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.gitea.rule=Host(`git.example.com`)
      - traefik.http.routers.gitea.entrypoints=websecure
      - traefik.http.routers.gitea.tls.certresolver=le
      - traefik.http.services.gitea.loadbalancer.server.port=3000

Önce docker compose up -d, ardından docker compose logs -f traefik yapılandırılır. Her yeni uygulama, kendi yönlendirici adına, kendi Host() değerine ve kendi dahili portuna sahip bir gitea bloğunun kopyasıdır. TLS ve yedeklemelerle Docker üzerinde Nextcloud kurulumu da aynı şekilde sisteme dahil edilebilir; yayınlanan portları kaldırın, container'ı proxy ağına bağlayın ve yönlendirici etiketlerinin ana bilgisayar adını ve sertifikayı yönetmesine izin verin.

Buradaki beş ayrıntı kritik öneme sahiptir.

exposedByDefault=false, traefik.enable=true etiketi eklenene kadar bir container'ı Traefik için görünmez kılar. Bu ayarı atlarsanız, başlattığınız her container (bir şeyi kontrol etmek için çalıştırdığınız geçici postgres dahil) için otomatik olarak bir rota oluşturulur.

providers.docker.network=proxy, bir container birden fazla ağa bağlı olduğunda Traefik'in hangisini kullanacağını belirtir. Bu ayar belirtilmezse Traefik yanlış container IP'sini seçebilir; bu durum uygulama hatası gibi görünen 502 hatalarına yol açar.

loadbalancer.server.port=3000, container içerisindeki portu ifade eder; örneğin Gitea içeride 3000 numaralı portu dinler. Hiçbir uygulama container'ının dışarıya port açmadığına, yalnızca Traefik'in port açtığına dikkat edin.

web giriş noktasındaki yönlendirme, düz metin isteklerini HTTPS'e 308 koduyla yönlendirir. 80 numaralı port yine de açık kalır: ACME HTTP sınaması ve doğrudan ana bilgisayar adını yazan kullanıcılar için bu gereklidir.

Temel kimlik doğrulama (basic-auth) hash değerindeki çift $$, bir yazım hatası değil, Compose'un kaçış karakteri (escaping) kullanımıdır. Hash değerini htpasswd -nbB admin 'your-password' (apache2-utils paketi) ile oluşturun ve ardından her $ karakterini ikiye katlayın.

Sertifika ve acme.json tuzağı

tlschallenge=true, TLS-ALPN-01 yöntemini seçer: Let's Encrypt, sunucunuza 443 numaralı port üzerinden bağlanır ve Traefik, TLS el sıkışması sırasında sınamayı yanıtlar. Alternatif yöntem, 80 numaralı portu kullanan HTTP-01 yöntemidir; Traefik'in command: listesindeki tlschallenge satırını şu iki satırla değiştirin:

      - --certificatesresolvers.le.acme.httpchallenge=true
      - --certificatesresolvers.le.acme.httpchallenge.entrypoint=web

Her iki yöntem de çalışır. Her ikisi de, ana makine adınız için genel DNS kayıtlarının halihazırda VPS'nizi işaret etmesini gerektirir; sertifika yetkilisi alan adını çözümler ve dışarıdan bağlantı kurar. Öncelikle A (ve AAAA) kaydını oluşturun, dig +short git.example.com ile doğrulayın ve ardından Traefik'i başlatın.

Şimdi ise birçok kişinin bir akşamını harcamasına neden olan tuzağa gelelim. Traefik, ACME hesap anahtarını ve verilen tüm sertifikaları tek bir acme.json dosyasında tutar. Eğer bu dosya grup veya herkes tarafından okunabilir durumdaysa, Traefik buna çok yakın bir satır yazdırır ve durur:

error: unable to get ACME account: permissions 644 for /letsencrypt/acme.json are too open, please use 600

Temiz çözüm yukarıda belirtilendir: dizini bind-mount edin ve Traefik'in dosyayı doğru izinlerle kendisinin oluşturmasına izin verin. Eğer acme.json dosyasını touch ile oluşturduysanız, umask değeriniz dosya izinlerini 644 yapmıştır. Bunu ana makine üzerinde şu şekilde düzeltin:

chmod 600 ./letsencrypt/acme.json
docker compose restart traefik

Bu dizini uygulama birimlerinizle birlikte yedekleyin. Bu dizini kaybetmek telafi edilebilir bir durumdur, sertifikalar yeniden oluşturulur; ancak beş ana makine adını aynı anda yeniden oluşturmak, hız sınırlarına (rate limits) takılmanıza neden olur.

Denemeler yaparken staging CA kullanın. caserver satırının yorumunu kaldırın, tüm rotaların çalıştığından emin olun, ardından satırı tekrar yorum haline getirin ve üretim sertifikalarının sıfırdan talep edilmesi için acme.json dosyasını silin. Let's Encrypt üretim ortamı, aynı ana makine adı kümesi için haftada beş kopya sertifikaya izin verir ve aynı isim için tekrarlanan başarısız doğrulamaları kısıtlar. Staging ortamı güvenilmeyen sertifikalar verir, tarayıcınız uyarı verir ve bu uyarı, işlemin çok daha esnek sınırlar dahilinde çalıştığının işaretidir.

Dashboard bir kontrol yüzeyidir, demo değil

Çoğu hızlı başlangıç kılavuzu, dashboard'u herhangi bir kimlik doğrulama olmaksızın 8080 numaralı port üzerinden sunan --api.insecure=true ayarını kullanır. Genel IP adresine sahip bir sunucuda bu durum; yönlendirme topolojinizi, ana makine adlarınızı, ara katman (middleware) isimlerinizi ve arka uç portlarınızı, tarama yapan herkese açık eder.

Yukarıdaki traefik servisinde yer alan etiketler bunun alternatifidir: Dashboard, diğer tüm uygulamalar gibi gerçek bir ana makine adı üzerinden, TLS ile ve basicauth arkasında yönlendirilir. service=api@internal, yönlendiriciyi Traefik'in yerleşik API'sine bağlayan kısımdır. Soldan sağa doğru uygulanan bir IP izin listesi zinciri ekleyerek güvenliği daha da sıkılaştırın. Ofis adresiniz dinamikse, aralığı aynı VPS üzerinde kendi barındırdığınız bir WireGuard VPN tarafından atanan alt ağa göre ayarlayın ve dashboard'a yalnızca tünel üzerinden erişin:

- traefik.http.middlewares.office.ipallowlist.sourcerange=10.0.0.7/32
- traefik.http.routers.dashboard.middlewares=office,dashboard-auth

Beş uygulama kendi hesaplarına ihtiyaç duymaya başladığında, paylaşımlı bir basicauth parolası artık savunulabilir olmaktan çıkar. Aynı ara katman yuvası, kararı kendi barındırdığınız bir tek oturum açma (SSO) sunucusu olan Authentik'e devreden bir forwardauth kullanabilir. Böylece dashboard ve yanındaki her rota, tek bir yerden iptal edebileceğiniz tek bir oturum açma ekranının arkasında yer alır.

Docker soketi root yetkisine sahiptir

/var/run/docker.sock, ana makineden / dizinini bağlayan bir container oluşturabilen bir API'dir. Bu API'ye erişim, makine üzerinde root yetkisine sahip olmakla eşdeğerdir ve Traefik'in etiketleri okuyabilmesi için bu erişime ihtiyacı vardır.

Bağlama noktasında :ro bayrağını koruyun, ancak bunun ne sağladığı konusunda net olun: bu işlem yalnızca soket dosyasını salt okunur yapar. Docker API'sine giden POST isteklerini engellemez. Asıl çözüm, Traefik'e doğrudan soketi vermemek ve araya bir filtreleme proxy'si koymaktır:

  dockerproxy:
    image: tecnativa/docker-socket-proxy   # pin the current tag
    restart: unless-stopped
    environment:
      CONTAINERS: 1
      NETWORKS: 1
      POST: 0
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - proxy

Soket birimini (volume) Traefik yapılandırmasından kaldırın ve sağlayıcıyı proxy'ye yönlendirin:

--providers.docker.endpoint=tcp://dockerproxy:2375

Traefik, container'lar ve ağlar üzerindeki okuma erişimini korur ancak yeni bir şey oluşturma yetkisini kaybeder.

Güvenlik duvarı, portlar ve herkesin yanlış yaptığı kural

İki açık port ve ek olarak SSH:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Docker tarafından yayınlanan portlar ufw kurallarını atlar. Docker, kendi iptables kurallarını ufw zincirlerinden önce değerlendirilecek şekilde ekler; bu nedenle ports: ["3000:3000"] ile başlatılan bir container, ufw üzerinde bir "deny" kuralı olsa dahi internetten erişilebilir durumdadır. Buradaki savunma yöntemi güvenlik duvarı yapılandırması değil, mimari bir tercihtir: portları yalnızca Traefik üzerinden yayınlayın ve diğer tüm container yapılarına networks: [proxy] dışında hiçbir port atamayın. Eğer bir servisin ana makineye (host) erişmesi kesinlikle gerekiyorsa, servisi loopback arayüzüne bağlayın, yani "127.0.0.1:3000:3000" kullanın.

Sorun Giderme: karşılaşacağınız hatalar

404 page not found, Traefik tarafından sunulur. Hiçbir yönlendirici (router) eşleşmedi. Olasılık sırasına göre: container traefik.enable=true etiketinden yoksundur (exposedByDefault=false ayarlanmış olmalıdır); Host() kuralı yazdığınız isimle eşleşmiyordur; bir etiketteki yönlendirici ismi diğerinden farklıdır (routers.gitea.rule ve routers.gitea.entrypoints aynı kelime olmalıdır); veya ana makine adını (hostname) backtick yerine tırnak içine almışsınızdır. Traefik v3, eşleştiriciler içinde backtick kullanılmasını zorunlu kılar.

502 Bad Gateway. Bir yönlendirici eşleşti ancak arka uç (backend) erişilemez durumda. Neredeyse her zaman container proxy ağında değildir, docker inspect -f '{{json .NetworkSettings.Networks}}' gitea ayarını kontrol edin. Diğer bir olasılık ise yanlış loadbalancer.server.port değeridir: yayınlanmış bir port verdiniz veya uygulama başka bir portta dinleme yapıyor olabilir. Günlük kayıtları denemeyi belirtir: dial tcp 172.18.0.5:8080: connect: connection refused.

Tarayıcı uyarı veriyor ve sertifika TRAEFIK DEFAULT CERT adına düzenlenmiş. O ana makine adı için bir sertifika mevcut değil ve Traefik kendi imzalı yer tutucu sertifikasını sunuyor. ACME satırlarını okuyun:

unable to obtain ACME certificate for domains "git.example.com" ...
acme: error: 400 ... DNS problem: NXDOMAIN looking up A for git.example.com

DNS henüz sunucuya yönlendirilmemiş. Kaydı düzeltin, TTL süresinin dolmasını bekleyin ve Traefik'i yeniden başlatın.

Invalid response from http://git.example.com/.well-known/acme-challenge/... HTTP sınaması (challenge) sırasında: 80 numaralı port dışarıdan Traefik'e ulaşmıyor; bu genellikle ufw değil, VPS önündeki sağlayıcı seviyesindeki bir güvenlik duvarından kaynaklanır.

Sertifikalar düzenlenmiyor ve DNS'iniz Cloudflare üzerinde, turuncu bulut aktif. Cloudflare, TLS sonlandırmasını kendi uç noktasında yapar ve TLS-ALPN-01 bu süreçte tamamlanamaz. Sertifika düzenlenirken kaydı "DNS-only" moduna getirin veya bir API anahtarı ile DNS-01 sınamasına geçin. DNS-01, wildcard sertifikaları düzenleyebilen tek sınama yöntemidir.

Yönlendirme döngüsü (Redirect loop). Traefik'in önündeki bir katman zaten TLS'i sonlandırıyor ve düz metin trafiğini :80 portuna iletiyor; giriş noktası (entrypoint) yönlendirmesi ise trafiği tekrar HTTPS'e gönderiyor. İki yönlendirmeden birini kaldırın.

Sürekliliği sağlama

Docker birimi önyükleme sırasında etkinleştirilmeli (systemctl is-enabled docker) ve restart: unless-stopped, yeniden başlatma sonrasında yığının tekrar ayağa kalkmasını sağlar. Belirgin bir kontrol için, docker compose -f /srv/edge/compose.yml up -d komutunu RemainAfterExit=yes ile çalıştıran küçük bir systemd birimi, size systemctl status edge ve sıralama denetimi imkanı sunar.

Traefik etiketini sabitleyin (traefik:v3.5, asla latest kullanmayın). v2'den v3'e yükseltme işlemi kural sözdizimini ve sağlayıcı isimlerini değiştirdi; bu nedenle denetimsiz bir latest, artık anlamadığı bir yapılandırmayı sorunsuzca yeniden yükleyecektir. Yükseltmeyi bilinçli yapın: geçiş notlarını okuyun, etiketi güncelleyin, docker compose up -d traefik komutunu çalıştırın ve günlük kayıtlarını izleyin. Eğer hala v2 etiketindeyseniz, Traefik v2'den v3'e geçiş kılavuzu, tüm yeniden adlandırmaları, uyumluluk modunu ve sertifikalarınızı koruyan bir geri dönüş sürecini adım adım açıklar.

./letsencrypt dosyasını ve her uygulamanın veri birimini yedekleyin. Traefik, compose dosyasından yeniden oluşturamayacağınız başka hiçbir durum bilgisi tutmaz.

Ölçeklendirme sırasında karşılaşılan sorunlar

İlk sınır verimlilik değil, tek bir sunucudur: tek bir VPS üzerinde çalışan tek bir Traefik, beş uygulama için tek hata noktasıdır ve acme.json düz dosya depolama kullandığından, iki Traefik örneğinin aynı anda yazma yapması veriyi bozar. Ölçeklendirme, sertifika depolama alanını dosyadan başka bir yere taşımayı veya TLS termination işlemini başka bir noktada yapmayı gerektirir.

İkinci sorun uzun ömürlü bağlantılardır. Server-sent events, büyük boyutlu yüklemeler ve yavaş istemciler, giriş noktasının yanıt zaman aşımlarına takılır; --entryPoints.websecure.transport.respondingTimeouts.readTimeout ve onun writeTimeout ile idleTimeout kardeşleri bu noktada ayarlanması gereken parametrelerdir. WebSockets herhangi bir ek yapılandırma gerektirmeden doğrudan iletilir.

Üçüncü sorun disktir. --accesslog=true çıktıları stdout'a yazar ve Docker'ın json-file sürücüsü, bir sınır belirlenmediği sürece bunları sonsuza kadar tutar. Traefik servisi üzerinde logging.options.max-size ayarını yapılandırın veya erişim günlüklerini bir dosyaya yazdırıp log rotasyonu uygulayın.

Bunların hiçbiri bir orkestrasyon aracı gerektirmez. Yalnızca kontrolünüz altında olan, gerçek bir IP adresine sahip ve 80 ile 443 numaralı portları dış dünyaya açık olan bir sunucuya ihtiyaç vardır; tek bir küçük VPS tüm bağımlılık listesini karşılar.

FAQ

Traefik çalıştırıyorsam yine de certbot kullanmam gerekir mi?

Hayır. Traefik'in ACME çözümleyicisi, yönlendirdiği her ana bilgisayar adı için sertifika talep eder ve yeniler; bunların tamamını acme.json içinde saklar. Certbot, nginx veya başka bir sunucu TLS sonlandırmasını kendisi yaptığında doğru araç olmaya devam eder; aynı ana bilgisayar adları için her ikisini de çalıştırmak yalnızca Let's Encrypt hız sınırlarını tüketir.

Konteynerim Traefik üzerinden neden 404 hatası döndürüyor?

Traefik tarafından sunulan bir 404, istekle eşleşen hiçbir yönlendiricinin bulunmadığı anlamına gelir. Konteynerin traefik.enable=true etiketini taşıdığından (exposedByDefault=false ayarlandığında zorunludur), Host() değerinin yazdığınız isimle eşleştiğinden ve yönlendirici isminin o uygulama için tüm etiketlerde aynı olduğundan emin olun. Traefik v3, eşleştirici içinde tırnak işareti yerine ters tırnak (backtick) kullanılmasını gerektirir.

Burada 404 ile 502 arasındaki fark nedir?

404, yönlendirmenin hiç gerçekleşmediği anlamına gelir; 502 ise bir yönlendiricinin eşleştiği ancak arka uç servisin bağlantıyı reddettiği anlamına gelir. 502 hatasının yaygın nedenleri, konteynerin proxy ağına bağlı olmaması ve loadbalancer.server.port etiketinin konteyner içindeki dinleme portu yerine dışa açılmış bir porta işaret etmesidir. Erişim günlüğü, Traefik'in bağlantı kurmaya çalıştığı tam adresi gösterir.

Docker soketini salt okunur olarak bağlamak yeterli midir?

:ro bayrağı soket dosyasını salt okunur yapar, ancak arkasındaki API'yi değil; POST istekleri bu soket üzerinden iletilmeye devam eder ve Docker API erişimi, ana makinede root yetkisine eşdeğerdir. Daha güvenli yapılandırma, yukarıda gösterilen docker-socket-proxy konteyneridir; bu yapı Traefik'e yalnızca konteyner ve ağ okuma yetkisi verir ve yazma işlemlerini tamamen engeller.

Traefik joker (wildcard) sertifika düzenleyebilir mi?

Yalnızca DNS sağlayıcınız için bir API anahtarı ile DNS-01 doğrulaması üzerinden düzenleyebilir. TLS-ALPN-01 ve HTTP-01 yöntemlerinin her biri tek bir ana bilgisayar adını doğrular ve joker sertifika üretemez. Cloudflare gibi bir CDN, VPS'inizin önünde TLS sonlandırması yapıyorsa ve diğer iki doğrulama yöntemi tamamlanamıyorsa, çözüm yine DNS-01 yöntemidir.