Zum Inhalt springen
myvpsguide

Traefik: Reverse-Proxy, der neue Container von allein findet

Wann sich Traefik gegenüber Caddy oder nginx lohnt, wie die Labels aufgebaut sind, warum das Docker-Socket-Problem ernst ist und wie Zertifikate ohne Handarbeit entstehen.

veröffentlicht 19.08.2026
3 min lesezeit
fortgeschritten

Caddy und nginx wollen eine Konfigurationsdatei, in der jeder Dienst einmal steht. Traefik dreht das um: Es liest, welche Container laufen, und baut seine Routen daraus. Bei drei Diensten ist das egal. Bei zwanzig, die kommen und gehen, ist es der Unterschied zwischen Pflege und Selbstlauf.

Wann sich der Wechsel lohnt#

Caddy / nginxTraefik
Konfigurationeine Datei, von HandLabels am Container
Neuer DienstDatei ändern, neu ladenContainer starten, fertig
Übersichtalles an einer Stelle lesbarverteilt auf die Container
Einstiegflachsteiler, eigene Begriffe
Ohne Containerjawenig sinnvoll

Faustregel: Feste Dienste, die selten wechseln → bleib bei Caddy oder nginx. Viele Container, die häufig dazukommen → Traefik.

Der Aufbau#

# compose.yaml
services:
  traefik:
    image: traefik:v3
    restart: unless-stopped
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.websecure.address=:443
      - [email protected]
      - --certificatesresolvers.le.acme.storage=/acme/acme.json
      - --certificatesresolvers.le.acme.tlschallenge=true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - acme:/acme
    networks: [rand]

  app:
    image: meineapp
    restart: unless-stopped
    networks: [rand, intern]
    labels:
      - traefik.enable=true
      - traefik.http.routers.app.rule=Host(`app.example.com`)
      - traefik.http.routers.app.entrypoints=websecure
      - traefik.http.routers.app.tls.certresolver=le
      - traefik.http.services.app.loadbalancer.server.port=3000

  db:
    image: postgres:17
    networks: [intern]        # kein Kontakt zum Proxy-Netz

networks:
  rand:
  intern:
    internal: true

volumes:
  acme:

Drei Dinge daran sind wichtiger als der Rest:

exposedbydefault=false. Ohne das veröffentlicht Traefik jeden Container, den es sieht, auch die Datenbank. Mit dieser Zeile gilt: nur was traefik.enable=true trägt.

Zwei Netze. rand verbindet Proxy und Web-Dienste, intern (mit internal: true) trägt alles, was nie nach außen soll. Warum das der wirksame Schnitt ist, steht in Container-Netze verstehen.

Der Port im Label ist der Port im Container, nicht ein veröffentlichter. Die Anwendung braucht deshalb kein ports: mehr, und das ist der eigentliche Sicherheitsgewinn.

Das Docker-Socket ist Root-Zugriff

Wer /var/run/docker.sock in einen Container hängt, gibt diesem Container die volle Kontrolle über den Docker-Dienst und damit über den Host. :ro hilft dabei nicht, weil die Steuerung über die API läuft, nicht über Schreibrechte an der Datei. Für einen Proxy, der aus dem Internet erreichbar ist, ist das die empfindlichste Stelle des ganzen Aufbaus.

Zwei Gegenmittel, beide üblich:

  # 1. Socket-Proxy davor: gibt nur Lesezugriff auf Container-Listen frei
  dockerproxy:
    image: tecnativa/docker-socket-proxy
    environment:
      CONTAINERS: 1        # alles andere bleibt aus
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks: [intern]
# 2. Oder gleich rootless betreiben — siehe /beitraege/podman-rootless-umstieg

Danach zeigt Traefik nicht mehr auf das Socket, sondern auf den Proxy: --providers.docker.endpoint=tcp://dockerproxy:2375.

Zertifikate#

Mit tlschallenge=true holt Traefik die Zertifikate selbst, vorausgesetzt, Port 443 ist von außen erreichbar und der DNS-Eintrag zeigt hierher. Für Platzhalter-Zertifikate (*.example.com) reicht das nicht; dann braucht es die DNS-Prüfung mit den Zugangsdaten deines DNS-Anbieters.

# Läuft es? Der wichtigste Blick nach dem ersten Start:
docker compose logs traefik | grep -i "acme\|error"
docker compose exec traefik cat /acme/acme.json | head -c 200
acme.json ist eine Datei, kein Zufallsprodukt

Liegt der Speicher nicht in einem benannten Volume, holt Traefik nach jedem Neuaufbau neue Zertifikate und läuft bei mehreren Versuchen pro Woche in die Ausstellungsgrenzen der Zertifizierungsstelle. Dann steht die Seite ohne gültiges Zertifikat da, und Warten ist die einzige Abhilfe. Zum Ausprobieren gehört deshalb der Testserver (--certificatesresolvers.le.acme.caserver=…/acme-staging-v02/directory), nicht der echte.

Middleware: das, was man wirklich braucht#

    labels:
      # Basis-Authentifizierung vor eine Oberfläche ohne eigene Anmeldung
      - traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$05$$…
      - traefik.http.routers.app.middlewares=auth@docker,limit@docker
      # Drosseln, siehe /beitraege/ki-crawler-abwehren
      - traefik.http.middlewares.limit.ratelimit.average=20
      - traefik.http.middlewares.limit.ratelimit.burst=40

Das Doppel-Dollar ist kein Tippfehler: In einer Compose-Datei muss $ verdoppelt werden, sonst versucht Compose, eine Variable einzusetzen. Das ist der häufigste Grund, warum eine kopierte Basic-Auth-Zeile nicht funktioniert.

Das Dashboard#

Traefik bringt eine Übersicht mit, die zeigt, welche Route wohin führt. Sie ist beim Einrichten Gold wert und gehört nicht offen ins Internet:

      - --api.dashboard=true
    labels:
      - traefik.http.routers.dash.rule=Host(`traefik.intern.example.com`)
      - traefik.http.routers.dash.service=api@internal
      - traefik.http.routers.dash.middlewares=auth@docker

Besser noch: nur über den Tunnel erreichbar machen, dann braucht es keine Anmeldung im Internet.

Häufige Fragen#

Traefik oder Caddy?#

Caddy, wenn die Dienste feststehen und du eine lesbare Datei willst. Traefik, wenn Container kommen und gehen. Beide holen Zertifikate automatisch; das ist kein Unterscheidungsmerkmal mehr.

Warum bekomme ich 404 statt meiner Anwendung?#

Fast immer eins von dreien: traefik.enable=true fehlt, der Container hängt nicht im selben Netz wie Traefik, oder der Port im Label stimmt nicht mit dem Port im Container überein.

Kann ich Dienste außerhalb von Docker einbinden?#

Ja, über eine statische Konfigurationsdatei mit eigenen Routen. Der Reiz von Traefik liegt aber gerade im Automatischen, für rein statische Ziele ist nginx die einfachere Antwort.

Wie sehe ich, welche Routen aktiv sind?#

Im Dashboard oder über die API: curl -s http://127.0.0.1:8080/api/http/routers | jq '.[].rule'.

Was passiert bei einem Neustart des Hosts?#

Traefik liest die laufenden Container neu ein und baut seine Routen wieder auf. Wichtig ist nur, dass acme ein benanntes Volume ist, sonst siehe Kasten oben.

Kurz gesagt#

  • exposedbydefault=false ist die erste Zeile, die du setzt.
  • Zwei Netze: eins mit dem Proxy, eins internal für Datenbanken.
  • Der Port im Label ist der interne, Anwendungen brauchen kein ports: mehr.
  • Das Docker-Socket ist Root-Zugriff. Socket-Proxy davor oder rootless betreiben.
  • Zum Ausprobieren den ACME-Testserver, sonst brennst du die Ausstellungsgrenze ab.
MRMedia

Geschrieben aus dem laufenden Betrieb: MRMedia betreibt eigene Proxmox- Hosts, einen Backup-Server und Kundendienste in der EU. Fehler in einer Anleitung sind Fehler im eigenen Betrieb. Korrekturen bitte über Discord.