Wildcard-Zertifikat mit Traefik und Caddy über die netcup-DNS-API
Teil 15 der Reihe netcup Spezial: Wildcard-Zertifikate von Let's Encrypt mit Traefik und Caddy über die netcup-DNS-Prüfung holen. Mit Messung der netcup-Wartezeiten und der Lösung, an der Caddy zunächst scheiterte.
Geprüft am 04.11.2026 · für Traefik 3.7.17, Caddy 2.11.7, caddy-dns/netcup xcaddy 04.11.2026, Docker 29.9.2
Mit KI erstellt – redaktionelle Prüfung ausstehend
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Ein Wildcard-Zertifikat wie *.sedv-lab.de deckt beliebig viele Unterdomains ab und lässt sich auch für Dienste ausstellen, die nur im Heimnetz oder hinter einer Firewall laufen. Let's Encrypt stellt Wildcards nur über die DNS-Prüfung aus: Ihr Reverse Proxy legt kurz einen TXT-Eintrag in der Zone an, Let's Encrypt fragt ihn ab, danach wird er wieder gelöscht. Traefik und Caddy können das mit der DNS-API von netcup selbst erledigen. Diese Anleitung zeigt beide Wege Schritt für Schritt und erklärt, warum die Prüfung bei netcup länger dauert als anderswo und woran Caddy im Test zunächst scheiterte.
Dies ist Teil 15 der Reihe „netcup Spezial“.
Testaufbau
Getestet haben wir am 04.11.2026 auf einem netcup VPS 500 G12.5 mit Ubuntu 24.04.5 und Docker 29.9.2. Die Domain sedv-lab.de ist bei netcup registriert und nutzt das klassische netcup-DNS mit den Nameservern root-dns, second-dns und third-dns.netcup.net.
| Komponente | Version | Ergebnis |
|---|---|---|
| Traefik (mit lego) | 3.7.17 | Wildcard für sedv-lab.de und *.sedv-lab.de nach 11 Minuten |
| Caddy mit caddy-dns/netcup | 2.11.7 | Wildcard für *.caddy.sedv-lab.de nach 7 Minuten, erst nach zwei Anpassungen |
Beide Proxys liefen auf eigenen Ports, weil 80 und 443 auf dem Testserver belegt waren. Für die DNS-Prüfung spielt das keine Rolle: Let's Encrypt muss Ihren Server dafür nicht erreichen.
Voraussetzungen
- Eine Domain bei netcup mit den netcup-Nameservern
- Ein Legacy-API-Key und das API-Passwort aus dem CCP, wie in Teil 14 beschrieben
- Ein Linux-Server mit Docker und Docker Compose
- Für jeden Test etwa 15 Minuten Geduld
Ein Hinweis vorab: netcup kennzeichnet die Legacy-API im CCP als auslaufend. Der netcup-Support schrieb uns am 04.11.2026 außerdem, dass Domains eines Kundenkontos nur auf das neue CloudDNS umgestellt werden können, wenn dort keine Legacy-API-Keys mehr existieren. Wer den Weg aus dieser Anleitung nutzt, bleibt also vorerst beim klassischen DNS. Die lego-Doku nennt für CloudDNS bereits einen eigenen Anbieter netcupv1.
Schritt 1: Zugangsdaten in einer Datei ablegen
Beide Proxys lesen die Zugangsdaten aus Umgebungsvariablen. Legen Sie dafür einen Ordner an und darin eine Datei, die nur root lesen darf:
mkdir -p /root/wild && cd /root/wild
(umask 077; nano netcup.env)
Inhalt der Datei, mit Ihren Werten:
NETCUP_CUSTOMER_NUMBER=12345
NETCUP_API_KEY=IHR-API-KEY
NETCUP_API_PASSWORD=IHR-API-PASSWORT
Die Namen sind fest vorgegeben: Traefik erwartet genau diese drei Variablen, und im Caddyfile verweisen wir später auf dieselben Namen.
Bedenken Sie die Reichweite: Der Legacy-API-Key gilt für alle Domains Ihres Kundenkontos und lässt sich nicht auf eine Domain beschränken. Wer Docker-Rechte auf dem Server hat, sieht die Werte außerdem mit docker inspect. Legen Sie deshalb einen eigenen Key nur für diesen Zweck an, löschen Sie ihn, wenn Sie ihn nicht mehr brauchen, und geben Sie Docker-Rechte nur wenigen Benutzern.
Verifizieren: ls -l netcup.env zeigt -rw-------, und cut -d= -f1 netcup.env zeigt die drei Namen.
Schritt 2: Verstehen, warum netcup Zeit braucht
Bevor Sie starten, lohnt ein Blick auf das Verhalten von netcup, denn daran entscheidet sich, ob die Prüfung gelingt. Wir haben auf zwei Domains gleichzeitig einen TXT-Eintrag über die API angelegt und alle zehn Sekunden an jedem der drei Nameserver nachgefragt:
| Nameserver | sichtbar nach |
|---|---|
| root-dns.netcup.net | 502 Sekunden |
| second-dns.netcup.net | 543 Sekunden |
| third-dns.netcup.net | 574 Sekunden |
Auf beiden Domains erschien der Eintrag innerhalb einer Sekunde. netcup veröffentlicht Änderungen also gebündelt. Aus rund sechs Beobachtungen an diesem Vormittag ergaben sich Abstände von etwa neun bis zehneinhalb Minuten zwischen solchen Veröffentlichungen. Ein Eintrag, der kurz nach einer Veröffentlichung angelegt wird, wartet fast zehn Minuten, einer kurz davor nur Sekunden. Danach übernimmt root-dns zuerst, second-dns und third-dns folgen rund 40 und 70 Sekunden später. Die netcup-Hilfe spricht von einer Aktualisierung „im Regelfall innerhalb von ca. 10 Minuten“.
Im CCP sehen Sie diesen Zustand im Reiter DNS Ihrer Domain. Ein frisch angelegter Eintrag stand dort bei uns in der Spalte gültig auf unknown, bis netcup ihn veröffentlicht hatte:

Für die DNS-Prüfung heißt das: Der Proxy muss warten, bis alle drei Nameserver den Eintrag liefern. Let's Encrypt fragt einen beliebigen davon, zum Teil von mehreren Standorten aus.
Verifizieren: Sie kennen die drei Nameserver Ihrer Domain. dig +short NS sedv-lab.de zeigt sie, mit Ihrer Domain statt unserer.
Schritt 3: Traefik einrichten
Traefik nutzt für Zertifikate die Bibliothek lego, die netcup als Anbieter mitbringt. Die compose.yaml im Ordner /root/wild mit einem Testdienst whoami:
services:
traefik:
image: traefik:v3.7.17
container_name: traefik-wild
restart: unless-stopped
command:
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.websecure.address=:443
- --certificatesresolvers.netcup.acme.email=admin@sedv-lab.de
- --certificatesresolvers.netcup.acme.storage=/letsencrypt/acme.json
- --certificatesresolvers.netcup.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
- --certificatesresolvers.netcup.acme.dnschallenge.provider=netcup
- --log.level=INFO
env_file: netcup.env
ports:
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
whoami:
image: traefik/whoami:v1.11
labels:
- traefik.enable=true
- traefik.http.routers.whoami.rule=Host(`app.sedv-lab.de`)
- traefik.http.routers.whoami.entrypoints=websecure
- traefik.http.routers.whoami.tls.certresolver=netcup
- traefik.http.routers.whoami.tls.domains[0].main=sedv-lab.de
- traefik.http.routers.whoami.tls.domains[0].sans=*.sedv-lab.de
Traefik bekommt über docker.sock Zugriff auf die Docker-API, um die Labels zu lesen. Das :ro schützt nur die Datei, nicht die API. Traefik hat damit praktisch Root-Rechte auf dem Host. Wer das vermeiden will, schaltet einen Socket-Proxy davor.
Die Zeile mit caserver schickt die Anfragen zuerst an das Testsystem von Let's Encrypt. Dessen Zertifikate sind nicht vertrauenswürdig, zählen aber nicht gegen die Limits. Gerade bei den langen Wartezeiten von netcup ist das sinnvoll, bis alles läuft. Die Labels unter tls.domains fordern ein Zertifikat für die Domain selbst und alle Unterdomains an, auch wenn der Router nur app.sedv-lab.de bedient.
Verifizieren: docker compose config --quiet meldet keinen Fehler.
Schritt 4: Traefik starten und das Zertifikat prüfen
docker compose up -d
docker logs -f traefik-wild
Im Log sehen Sie, wie lego den Eintrag anlegt und dann wartet. Gekürzt sah das bei uns so aus:
09:02:51Z INF Obtaining bundled SAN certificate. domains="sedv-lab.de, *.sedv-lab.de"
09:02:52Z INF dns01: waiting for record propagation domain=*.sedv-lab.de interval=30000 timeout=900000
09:13:28Z INF The server validated our request. domain=*.sedv-lab.de
09:14:02Z INF The server validated our request. domain=sedv-lab.de
09:14:05Z INF Server responded with a certificate. domains="sedv-lab.de, *.sedv-lab.de"
Die Zeiten im Log sind UTC. lego prüft alle 30 Sekunden und gibt nach 15 Minuten auf. Das reichte im Test: Gut zehneinhalb Minuten wartete lego auf den Eintrag für die Wildcard, eine halbe Minute auf den zweiten, insgesamt dauerte es gut elf Minuten. Ein erster Lauf gegen das Testsystem auf einer zweiten Domain brauchte knapp sechs Minuten. Die Dauer hängt also davon ab, wann die nächste Veröffentlichung bei netcup ansteht. Reichen die 15 Minuten einmal nicht, verlängert laut lego-Doku die Variable NETCUP_PROPAGATION_TIMEOUT in Sekunden die Wartezeit. Im Test war das nicht nötig.
Klappt das mit dem Testsystem, entfernen Sie die Zeile mit caserver, löschen die Datei letsencrypt/acme.json mit dem Testzertifikat und starten neu:
docker compose down
rm letsencrypt/acme.json
docker compose up -d
Ob das echte Zertifikat ausgeliefert wird, prüfen Sie direkt auf dem Server, ohne dass die Domain schon auf ihn zeigen muss:
echo | openssl s_client -connect 127.0.0.1:443 -servername app.sedv-lab.de 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
subject=CN = sedv-lab.de
issuer=C = US, O = Let's Encrypt, CN = YR2
notBefore=Nov 4 08:15:34 2026 GMT
notAfter=Feb 2 08:15:33 2027 GMT
X509v3 Subject Alternative Name:
DNS:*.sedv-lab.de, DNS:sedv-lab.de
Im Test lief Traefik auf Port 8443, deshalb stand dort 127.0.0.1:8443. Ein curl --resolve app.sedv-lab.de:443:127.0.0.1 https://app.sedv-lab.de/ lieferte die Antwort des Dienstes whoami ohne Zertifikatsfehler.
Damit Sie die Dienste auch im Browser erreichen, brauchen die Namen noch A- und AAAA-Einträge, etwa * und @ auf die Adresse Ihres Servers oder für reine Heimnetzdienste auf eine interne Adresse. Bei einer neuen netcup-Domain zeigen diese Einträge zunächst auf den Parkserver von netcup.
Verifizieren: issuer nennt Let's Encrypt ohne den Zusatz (STAGING), und unter Subject Alternative Name steht die Wildcard.
Schritt 5: Caddy mit dem netcup-Modul bauen
Das offizielle Caddy-Image enthält keine DNS-Anbieter. Sie bauen deshalb ein eigenes Image mit dem Modul caddy-dns/netcup. Legen Sie /root/wild/caddy an und darin dieses Dockerfile:
FROM caddy:2.11.7-builder AS builder
RUN xcaddy build --with github.com/caddy-dns/netcup
FROM caddy:2.11.7
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
Dazu die compose.yaml:
services:
caddy:
build: .
image: caddy-netcup:2.11.7
container_name: caddy-wild
restart: unless-stopped
env_file: ../netcup.env
ports:
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:
Laufen Traefik und Caddy wie in unserem Test auf demselben Server, braucht einer von beiden einen anderen Port. Wir haben Caddy mit "9443:443" auf 9443 gelegt. Bauen Sie das Image:
cd /root/wild/caddy
docker compose build
Der Bau dauerte auf dem VPS 500 rund drei Minuten, das fertige Image ist 162 MB groß.
Verifizieren: docker run --rm caddy-netcup:2.11.7 caddy list-modules | grep netcup zeigt dns.providers.netcup.
Schritt 6: Das Caddyfile mit genug Wartezeit
Das Caddyfile im selben Ordner:
{
email admin@sedv-lab.de
acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}
*.caddy.sedv-lab.de, caddy.sedv-lab.de {
tls {
dns netcup {
customer_number {env.NETCUP_CUSTOMER_NUMBER}
api_key {env.NETCUP_API_KEY}
api_password {env.NETCUP_API_PASSWORD}
}
propagation_timeout 15m
resolvers third-dns.netcup.net
}
@app host app.caddy.sedv-lab.de
handle @app {
respond "Hallo von Caddy" 200
}
handle {
respond "Wildcard aktiv" 200
}
}
Zwei Zeilen sind bei netcup entscheidend. propagation_timeout 15m verlängert die Wartezeit, denn Caddy wartet ohne diese Angabe laut Doku nur zwei Minuten. resolvers third-dns.netcup.net lässt Caddy beim Warten den Nameserver fragen, der in beiden Messungen zuletzt dran war. Diese Lösung hängt also von der Reihenfolge ab, in der netcup die Nameserver aktualisiert.
Mit root-dns und second-dns als Resolvern ging es im Test schief. Sind eigene Resolver gesetzt, fragt Caddy nur diese und gibt frei, sobald der erste den Eintrag liefert. Das war root-dns. Let's Encrypt fragte aber auch die anderen Nameserver. Beim zweiten Versuch ist das genau belegt: root-dns lieferte den neuen Eintrag ab 10:00:40 Uhr, um 10:00:41 Uhr kam die Absage:
Incorrect TXT record "…" (and 1 more) found at _acme-challenge.caddy.sedv-lab.de
Ein noch nicht aktualisierter Nameserver lieferte also die alten Einträge aus dem ersten Versuch. Der erste Versuch war schon mit No TXT record found gescheitert. Zum Vergleich haben wir Caddy auch ganz ohne propagation_timeout und resolvers laufen lassen. Nach genau zwei Minuten brach es ab:
timed out waiting for record to fully propagate; verify DNS provider configuration is correct - last error: <nil>
Die Meldung klingt nach falschen Zugangsdaten, gemeint ist aber nur die zu kurze Wartezeit. Die README des Moduls empfiehlt ebenfalls lange Zeiten und nennt in Ausnahmefällen bis zu 20 Minuten. Ihr Beispiel setzt zusätzlich propagation_delay 600s, also zehn Minuten Warten vor der ersten Prüfung.
Verifizieren: docker run --rm --env-file ../netcup.env -v $PWD/Caddyfile:/etc/caddy/Caddyfile:ro caddy-netcup:2.11.7 caddy validate --config /etc/caddy/Caddyfile meldet Valid configuration.
Schritt 7: Caddy starten und prüfen
docker compose up -d
docker logs -f caddy-wild
Caddy holt für *.caddy.sedv-lab.de und caddy.sedv-lab.de zwei getrennte Zertifikate und legt dafür zwei TXT-Einträge an. Mit der Anpassung lief es im Testsystem nach knapp elf Minuten durch, mit dem echten Let's Encrypt nach gut sieben Minuten:
10:14:26 trying to solve challenge *.caddy.sedv-lab.de
10:14:26 trying to solve challenge caddy.sedv-lab.de
10:21:34 certificate obtained successfully caddy.sedv-lab.de
10:21:35 certificate obtained successfully *.caddy.sedv-lab.de
Die Zeilen sind aus dem JSON-Log von Caddy gekürzt, die Zeiten in Ortszeit. Für das echte Zertifikat entfernen Sie die Zeile acme_ca und starten den Container neu. Die Prüfung mit openssl, im Test auf Port 9443:
echo | openssl s_client -connect 127.0.0.1:443 -servername app.caddy.sedv-lab.de 2>/dev/null | openssl x509 -noout -subject -issuer -enddate
subject=CN = *.caddy.sedv-lab.de
issuer=C = US, O = Let's Encrypt, CN = YE1
notAfter=Feb 2 08:23:01 2027 GMT
Verifizieren: curl --resolve app.caddy.sedv-lab.de:443:127.0.0.1 https://app.caddy.sedv-lab.de/ antwortet mit Hallo von Caddy.
Schritt 8: Im API-Log nachvollziehen
Jeder Anlege- und Löschvorgang der Proxys steht im CCP unter Domains, API Log:

Um 10:14:26 legte Caddy die beiden Einträge an, um 10:21:32 entfernte es sie wieder. Bleiben nach einem abgebrochenen Versuch Einträge mit _acme-challenge im Reiter DNS stehen, können Sie diese dort von Hand löschen.
Verifizieren: Nach jedem Zertifikat stehen im API Log Paare aus Anlegen und Löschen, und im Reiter DNS bleibt kein _acme-challenge-Eintrag zurück.
Typische Fehler
| Meldung | Ursache und Lösung |
|---|---|
No TXT record found at _acme-challenge.caddy.sedv-lab.de (Caddy) | Caddy hat zu früh Bescheid gegeben, ein Nameserver hatte den Eintrag noch nicht. resolvers third-dns.netcup.net setzen. |
During secondary validation: No TXT record found | Gleiche Ursache, Let's Encrypt hat von einem weiteren Standort aus geprüft. Gleiche Lösung. |
Incorrect TXT record ... found | Ein Nameserver liefert noch alte Einträge aus einem früheren Versuch. Ursache und Lösung wie bei No TXT record found. |
timed out waiting for record to fully propagate (Caddy) | Caddy wartet ohne Angabe nur zwei Minuten. propagation_timeout 15m setzen. |
context canceled (Caddy) | Ein caddy reload während einer laufenden Anfrage bricht sie ab. Zertifikatsanfragen deshalb abwarten, bevor Sie neu laden. |
| Prüfung dauert über zehn Minuten | Normal bei netcup, siehe Schritt 2. Erst nach 15 Minuten ohne Ergebnis lohnt die Fehlersuche. |
Zertifikat mit (STAGING) im Aussteller | Die Zeile caserver oder acme_ca ist noch aktiv, oder das Testzertifikat liegt noch im Speicher. Zeile entfernen, bei Traefik acme.json löschen. |
Häufige Fragen
Traefik oder Caddy?
Traefik bringt den netcup-Anbieter mit und hat im Test ohne jede Anpassung funktioniert. Caddy braucht ein eigenes Image, eine längere Wartezeit und die zusätzliche Resolver-Zeile. Damit lief es im Test zweimal ohne Fehler durch, gegen das Testsystem und für das echte Zertifikat. Nehmen Sie den Proxy, den Sie ohnehin schon nutzen.
Wie läuft die Erneuerung?
Beide Proxys erneuern ihre Zertifikate selbst, und zwar über denselben DNS-Weg. Jede Erneuerung dauert deshalb ebenfalls einige Minuten und braucht einen gültigen API-Key. Löschen Sie den Key also nicht, solange ein Proxy damit arbeitet.
Brauche ich offene Ports für die DNS-Prüfung?
Nein. Let's Encrypt fragt nur die Nameserver von netcup. Deshalb eignet sich der Weg auch für Dienste, die nur intern erreichbar sind, solange der Server die netcup-API und Let's Encrypt erreicht.
Und was ist mit acme.sh?
acme.sh nutzt dieselbe netcup-API und ist sinnvoll, wenn kein Reverse Proxy die Zertifikate holen soll. Die Anleitung dazu ist unten verlinkt.
Was passiert, wenn netcup die Legacy-API abschaltet?
Dann funktionieren die Anbieter aus dieser Anleitung nicht mehr, die Erneuerungen schlagen fehl. Für Traefik nennt die lego-Doku bereits den Anbieter netcupv1 für die CloudDNS-API. Behalten Sie die Ankündigungen von netcup im Blick und stellen Sie rechtzeitig um.
Fazit
Wildcard-Zertifikate über netcup funktionierten im Test mit Traefik und Caddy, sobald die Eigenheiten von netcup berücksichtigt waren. Änderungen werden im Test gebündelt etwa alle zehn Minuten veröffentlicht, und die drei Nameserver übernehmen sie nacheinander. Traefik wartet von sich aus lange genug. Caddy braucht eine längere Wartezeit und die Prüfung gegen third-dns.netcup.net. Testen Sie zuerst gegen das Testsystem von Let's Encrypt und planen Sie für jeden Versuch eine Viertelstunde ein.


