> ## Documentation Index
> Fetch the complete documentation index at: https://docs.varios-ai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Eigene Zertifikate in Traefik

> TLS-Zertifikate einer eigenen CA in Traefik bereitstellen statt Let's Encrypt zu verwenden

VARIOS AI wird bei On-Premise-Installationen über **Traefik** ausgeliefert. Standardmäßig fordert Traefik das TLS-Zertifikat für Ihre Domain automatisch über **Let's Encrypt** an (Certificate Resolver `le`). Das setzt voraus, dass Ihre Instanz aus dem Internet über Port 80/443 erreichbar ist.

In vielen Unternehmensumgebungen ist das nicht gewünscht oder nicht möglich. Statt Let's Encrypt können Sie Traefik ein **eigenes Zertifikat** bereitstellen – etwa ein Wildcard-Zertifikat, ein Zertifikat Ihrer internen CA oder ein kommerziell erworbenes Zertifikat.

<Note>
  Diese Seite beschreibt das Zertifikat, mit dem Traefik **eingehende** HTTPS-Verbindungen der Nutzer absichert. Wenn VARIOS AI **ausgehend** Dienste mit selbstsignierten Zertifikaten erreichen soll, benötigen Sie stattdessen ein CA-Bundle im Container – siehe [Eigene TLS-Zertifikate](/de/extended-support/sicherheit/eigene-tls-zertifikate).
</Note>

***

## Voraussetzungen

<Steps>
  <Step title="Zertifikat und privater Schlüssel im PEM-Format">
    Traefik benötigt zwei Dateien: die Zertifikatskette (`.crt`/`.pem`) und den privaten Schlüssel (`.key`). Beide müssen im **PEM-Format** vorliegen (Textdatei, beginnend mit `-----BEGIN CERTIFICATE-----` bzw. `-----BEGIN PRIVATE KEY-----`).
  </Step>

  <Step title="Vollständige Zertifikatskette">
    Die Zertifikatsdatei muss das Serverzertifikat **und alle Zwischenzertifikate** enthalten – zuerst das Serverzertifikat, danach die Intermediates. Ohne die Kette melden Browser und API-Clients einen Zertifikatsfehler.
  </Step>

  <Step title="Unverschlüsselter privater Schlüssel">
    Traefik kann keine passphrasegeschützten Schlüssel entsperren. Der Schlüssel muss ohne Passphrase vorliegen.
  </Step>

  <Step title="Passender Common Name bzw. SAN">
    Das Zertifikat muss auf die Domain aus `PROJECT_DOMAIN` in Ihrer `.env` ausgestellt sein (bzw. diese als *Subject Alternative Name* enthalten).
  </Step>
</Steps>

<Tip>
  Format und Gültigkeit prüfen Sie vorab mit:

  ```bash theme={null}
  openssl x509 -in varios.crt -noout -subject -issuer -dates -ext subjectAltName
  openssl pkey -in varios.key -check -noout
  ```

  Zertifikat und Schlüssel gehören nur dann zusammen, wenn beide Prüfsummen identisch sind:

  ```bash theme={null}
  openssl x509 -in varios.crt -noout -modulus | openssl md5
  openssl pkey -in varios.key -noout -modulus | openssl md5
  ```
</Tip>

***

## Wie Traefik an Zertifikate kommt

Traefik kennt zwei Wege, ein Zertifikat für einen Router zu erhalten:

| Weg                      | Konfiguration                                                        | Einsatz                                              |
| ------------------------ | -------------------------------------------------------------------- | ---------------------------------------------------- |
| **ACME / Let's Encrypt** | Label `traefik.http.routers.<name>.tls.certresolver=le` am Container | Standard bei aus dem Internet erreichbaren Instanzen |
| **File Provider**        | YAML-Datei im Verzeichnis `./traefik/dynamic`                        | Eigene Zertifikate, interne CA, Wildcard-Zertifikate |

Die mitgelieferte `docker-compose.yml` für On-Premise-Installationen ist bereits für beide Wege vorbereitet. Der Traefik-Service startet mit aktiviertem File Provider und bindet die benötigten Verzeichnisse ein:

```yaml docker-compose.yml theme={null}
traefik:
  image: traefik:v3.6
  command:
    [...]
    - "--providers.file.directory=/etc/traefik/dynamic"
    - "--providers.file.watch=true"
    [...]
  volumes:
    - "/var/run/docker.sock:/var/run/docker.sock:ro"
    - "./traefik/acme:/etc/traefik/acme"
    - "./traefik/dynamic:/etc/traefik/dynamic"
    - "./traefik/certs:/etc/traefik/certs"
```

Sie müssen den Traefik-Service also **nicht anpassen**. Es genügt, die Zertifikatsdateien abzulegen, eine dynamische Konfiguration zu hinterlegen und den ACME-Resolver am Router abzuschalten.

***

## Einrichtung

<Steps>
  <Step title="Zertifikatsdateien ablegen">
    Legen Sie Zertifikat und Schlüssel im Verzeichnis `traefik/certs` **neben Ihrer `docker-compose.yml`** ab:

    ```bash theme={null}
    mkdir -p traefik/certs traefik/dynamic
    cp /pfad/zu/fullchain.pem traefik/certs/varios.crt
    cp /pfad/zu/privkey.pem   traefik/certs/varios.key
    ```

    Schützen Sie den privaten Schlüssel vor unbefugtem Zugriff:

    ```bash theme={null}
    chmod 644 traefik/certs/varios.crt
    chmod 600 traefik/certs/varios.key
    ```

    <Warning>
      Legen Sie private Schlüssel niemals in einem Verzeichnis ab, das von einem Webserver ausgeliefert wird, und nehmen Sie sie nicht in eine Versionsverwaltung auf.
    </Warning>
  </Step>

  <Step title="Dynamische Konfiguration anlegen">
    Erstellen Sie die Datei `traefik/dynamic/certificates.yml`. Traefik liest sie über den File Provider automatisch ein – die Pfade beziehen sich auf die Pfade **im Container** (`/etc/traefik/certs`), nicht auf die Pfade des Hosts.

    ```yaml traefik/dynamic/certificates.yml theme={null}
    tls:
      certificates:
        - certFile: /etc/traefik/certs/varios.crt
          keyFile: /etc/traefik/certs/varios.key

      stores:
        default:
          defaultCertificate:
            certFile: /etc/traefik/certs/varios.crt
            keyFile: /etc/traefik/certs/varios.key
    ```

    <Note>
      Der Abschnitt `certificates` stellt das Zertifikat für passende Hostnamen bereit. `stores.default.defaultCertificate` legt es zusätzlich als Standardzertifikat fest – damit antwortet Traefik auch bei Anfragen ohne passenden Hostnamen mit Ihrem Zertifikat statt mit dem generierten Platzhalter `TRAEFIK DEFAULT CERT`.
    </Note>
  </Step>

  <Step title="Let's Encrypt am Router abschalten">
    Entfernen Sie in der `docker-compose.yml` am `php`-Service das Label mit dem Certificate Resolver. Das Label `tls=true` bleibt erhalten – nur die automatische Beschaffung entfällt:

    ```yaml docker-compose.yml theme={null}
    php:
      [...]
      labels:
        - "traefik.enable=true"
        # entfernt: traefik.http.routers.${STACKNAME}.tls.certresolver=le
        - "traefik.http.routers.${STACKNAME}.tls=true"
        - "traefik.http.routers.${STACKNAME}.rule=Host(`${PROJECT_DOMAIN}`)"
        - "traefik.http.routers.${STACKNAME}.entrypoints=websecure"
        - "traefik.http.services.${STACKNAME}.loadbalancer.server.port=80"
        - "traefik.http.routers.http-${STACKNAME}.middlewares=redirect-https"
        - "traefik.http.routers.http-${STACKNAME}.rule=Host(`${PROJECT_DOMAIN}`)"
        - "traefik.http.routers.http-${STACKNAME}.entrypoints=web"
        - "traefik.http.middlewares.redirect-https.redirectscheme.scheme=https"
        - "traefik.http.middlewares.redirect-https.redirectscheme.permanent=true"
    ```

    <Warning>
      Bleibt `certresolver=le` gesetzt, versucht Traefik weiterhin, ein Let's-Encrypt-Zertifikat auszustellen. In abgeschotteten Netzen scheitert das dauerhaft und füllt das Log mit ACME-Fehlern.
    </Warning>

    Optional können Sie zusätzlich die ACME-Optionen aus dem `command`-Block des Traefik-Service entfernen (`--certificatesresolvers.le.*`), wenn Let's Encrypt gar nicht mehr genutzt wird.
  </Step>

  <Step title="Änderungen anwenden">
    ```bash theme={null}
    docker compose up -d
    ```

    Die Label-Änderung wird erst mit einem neu erstellten Container wirksam; `docker compose up -d` erledigt das automatisch. Reine Änderungen an den Dateien unterhalb von `traefik/dynamic` und `traefik/certs` übernimmt Traefik durch `--providers.file.watch=true` dagegen **ohne Neustart**.
  </Step>
</Steps>

***

## Prüfen

Prüfen Sie nach dem Start, welches Zertifikat Traefik ausliefert:

```bash theme={null}
openssl s_client -connect chat.example.com:443 -servername chat.example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates
```

<Check>
  Ausgegeben werden müssen der Aussteller und die Gültigkeit **Ihres** Zertifikats. Erscheint stattdessen `TRAEFIK DEFAULT CERT`, wurde die dynamische Konfiguration nicht geladen.
</Check>

Die Zertifikatskette prüfen Sie mit:

```bash theme={null}
curl -vI https://chat.example.com 2>&1 | grep -E "issuer|subject|SSL certificate"
```

Traefik protokolliert Fehler beim Laden der dynamischen Konfiguration im Container-Log:

```bash theme={null}
docker compose logs traefik | tail -50
```

***

## Zertifikat erneuern

Zum Austausch eines auslaufenden Zertifikats ersetzen Sie lediglich die beiden Dateien:

```bash theme={null}
cp /pfad/zu/neuer-fullchain.pem traefik/certs/varios.crt
cp /pfad/zu/neuer-privkey.pem   traefik/certs/varios.key
chmod 600 traefik/certs/varios.key
```

Dank `--providers.file.watch=true` erkennt Traefik die Änderung in der Regel automatisch. Wird das alte Zertifikat weiterhin ausgeliefert, erzwingen Sie das Neuladen:

```bash theme={null}
docker compose restart traefik
```

<Tip>
  Hinterlegen Sie eine Erinnerung vor dem Ablaufdatum. Anders als bei Let's Encrypt erneuert sich ein manuell hinterlegtes Zertifikat **nicht** von selbst.
</Tip>

***

## Mehrere Domains

Soll VARIOS AI unter mehreren Hostnamen erreichbar sein, ergänzen Sie weitere Einträge unter `certificates`. Traefik wählt anhand des per SNI übermittelten Hostnamens das passende Zertifikat aus:

```yaml traefik/dynamic/certificates.yml theme={null}
tls:
  certificates:
    - certFile: /etc/traefik/certs/chat.crt
      keyFile: /etc/traefik/certs/chat.key
    - certFile: /etc/traefik/certs/ki.crt
      keyFile: /etc/traefik/certs/ki.key

  stores:
    default:
      defaultCertificate:
        certFile: /etc/traefik/certs/chat.crt
        keyFile: /etc/traefik/certs/chat.key
```

Die zusätzlichen Hostnamen müssen außerdem in der Router-Regel stehen:

```yaml docker-compose.yml theme={null}
- "traefik.http.routers.${STACKNAME}.rule=Host(`chat.example.com`) || Host(`ki.example.com`)"
```

Ein **Wildcard-Zertifikat** (`*.example.com`) benötigt keine Sonderbehandlung – es wird wie jedes andere Zertifikat eingebunden und gilt für alle passenden Hostnamen.

***

## TLS-Optionen härten

Über den File Provider lassen sich auch die zulässigen TLS-Versionen und Cipher Suites festlegen. Legen Sie dazu eine weitere Datei im selben Verzeichnis an:

```yaml traefik/dynamic/options.yml theme={null}
tls:
  options:
    default:
      minVersion: VersionTLS12
      sniStrict: true
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
        - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
```

<Note>
  Die Option `default` gilt automatisch für alle Router, die keine eigene TLS-Option gesetzt haben. `sniStrict: true` weist Verbindungen ohne passenden Hostnamen ab – prüfen Sie vorher, dass alle Clients und Monitoring-Systeme SNI verwenden. Die Cipher-Suite-Liste wirkt nur auf TLS 1.2; die Suites von TLS 1.3 sind fest vorgegeben.
</Note>

***

## Fehlerbehebung

| Symptom                                       | Ursache                                         | Lösung                                                                                                           |
| --------------------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Browser zeigt `TRAEFIK DEFAULT CERT`          | Dynamische Konfiguration nicht geladen          | Dateiname auf `.yml` und Ablageort `traefik/dynamic` prüfen, Traefik-Log auswerten                               |
| `unable to generate TLS certificate` im Log   | ACME-Resolver noch aktiv                        | Label `tls.certresolver=le` am `php`-Service entfernen                                                           |
| `tls: private key does not match public key`  | Zertifikat und Schlüssel gehören nicht zusammen | Modulus-Prüfsummen beider Dateien vergleichen (siehe [Voraussetzungen](#voraussetzungen))                        |
| Zertifikatswarnung trotz gültigem Zertifikat  | Zwischenzertifikate fehlen                      | Serverzertifikat und Intermediates zu einer Datei zusammenführen: `cat server.crt intermediate.crt > varios.crt` |
| `permission denied` beim Lesen des Schlüssels | Dateirechte zu restriktiv für den Container     | Eigentümer der Datei prüfen; Traefik läuft im Container als Root, der Schlüssel muss dort lesbar sein            |
| Änderung wird nicht übernommen                | Label-Änderung ohne neuen Container             | `docker compose up -d` ausführen (nicht nur `restart`)                                                           |
