A client hits your site and gets a certificate warning. The certificate presented is a self-signed cert with CN “TRAEFIK DEFAULT CERT” instead of the certificate you configured. Everything else looks fine: Traefik is up, /ping returns 200, backends are healthy, routes work. The proxy is completely healthy and the only broken thing is which certificate it picked during the TLS handshake.

This failure is invisible to most Traefik monitoring. There is no error counter, no 5xx, no failed health check. The TLS handshake succeeds; it just succeeds with the wrong certificate. Unless you probe TLS externally, you find out from a user’s screenshot.

This article covers how Traefik selects which certificate to present, why it falls back to the default, and how to find the specific mismatch in your configuration.

What this means

Traefik terminates TLS at the entrypoint and chooses which certificate to present during the TLS handshake, before any HTTP routing happens. The selection input is the Server Name Indication (SNI) extension the client sends in the TLS ClientHello. Router rules like Host() are evaluated after the handshake completes, so they play no role in certificate selection. This is the most common misconception behind this incident.

The selection logic, in order:

  1. If the client sends an SNI server name and Traefik has a certificate whose CN or SANs match it, Traefik presents that certificate.
  2. If there is no SNI, or no configured certificate matches the SNI, Traefik falls back to the default certificate from the TLS store, if you configured one (via defaultCertificate or defaultGeneratedCert).
  3. If no default certificate is configured either, Traefik generates a self-signed certificate on the fly, with CN “TRAEFIK DEFAULT CERT”, and serves that.

So “serving the default certificate” is not an error state inside Traefik. It is the defined fallback for “I could not match this handshake to any certificate you gave me.”

flowchart TD
    A[Client TLS ClientHello with SNI] --> B{SNI matches a configured cert CN or SAN?}
    B -- yes --> C[Serve matched certificate]
    B -- no --> D{Default certificate configured in TLS store?}
    D -- yes --> E[Serve configured default certificate]
    D -- no --> F[Serve generated self-signed cert - TRAEFIK DEFAULT CERT]
    C --> G[Handshake completes - routing happens after]
    E --> G
    F --> G

One important consequence: the cert presented and the router that eventually handles the request are chosen independently. A request can get the correct certificate and still 404, or get the default certificate and then route perfectly once the client accepts it. Diagnose the certificate layer separately from the routing layer. See Traefik 404 not found for the routing side.

There is also one benign case: during first-boot ACME acquisition, Traefik serves the self-signed default certificate until issuance completes. If you see the default cert for the first minutes after a fresh deploy and then the real cert appears, that is expected behavior, not a fault.

Common causes

CauseWhat it looks likeFirst thing to check
No certificate matches the SNIClients for one specific hostname get the default cert; other hostnames on the same Traefik are fineopenssl s_client -servername for the failing hostname, then compare against certs Traefik has loaded
No default certificate configuredEvery unmatched or SNI-less connection gets the self-signed “TRAEFIK DEFAULT CERT”TLS store configuration: is defaultCertificate or defaultGeneratedCert set?
First-boot ACME acquisition in progressDefault cert served briefly after a fresh deploy, then replaced by the real certTraefik logs for ACME issuance; check again after a few minutes
Router without TLS enabled, or cert not associated with the routeHTTP works, HTTPS serves default cert for that route’s hostnameRouter’s TLS configuration and which certificate resolver or store it references
TLS store misconfigurationA configured defaultCertificate is silently ignored; generated cert still servedWhether the store definition is in the dynamic configuration and named default
Certificate loaded but for a different nameCert exists in Traefik but its CN/SANs do not cover the requested hostnameInspect the certificate’s SAN list against the failing hostname

Quick checks

All of these are safe and read-only.

# See which certificate Traefik presents for a specific hostname.
# This is the single most diagnostic command for this issue.
echo | openssl s_client -servername app.example.com -connect traefik-host:443 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

If the subject shows CN = TRAEFIK DEFAULT CERT, Traefik had no matching certificate for app.example.com and no configured default. If the subject is a real cert but for a different domain than you expected, your default certificate is configured and the SNI matched nothing specific.

# Check what an SNI-less client gets (approximates scanners and very old clients).
echo | openssl s_client -connect traefik-host:443 2>/dev/null \
  | openssl x509 -noout -subject -issuer
# List certificates Traefik has loaded, with expiry.
# Labels include cn and sans, so you can check coverage for the failing hostname.
curl -s http://localhost:8080/metrics | grep traefik_tls_certs_not_after
# Inspect loaded routers and confirm TLS is enabled on the route you expect.
curl -s http://localhost:8080/api/http/routers | jq '.[] | {name, rule, tls}'
# Check TLS versions and ciphers actually being negotiated, per entrypoint.
curl -s http://localhost:8080/metrics | grep traefik_entrypoint_requests_tls_total
# Search logs for ACME issuance activity if this is a fresh deployment.
# Exact wording varies by version.
grep -iE "acme|certificate" /var/log/traefik/traefik.log | tail -50

How to diagnose it

Work from the client inward. Each step narrows which layer dropped the match.

  1. Reproduce from a controlled client. Run the openssl s_client check above against the failing hostname, both through your normal path and directly against Traefik. If the direct connection gets the right cert but the load balancer path gets the default, something in front (another TLS terminator, a CDN) is intercepting, and Traefik is not your problem.

  2. Record exactly what was served. Subject, issuer, SAN list, expiry. Three outcomes: (a) self-signed “TRAEFIK DEFAULT CERT”, meaning no configured default and no SNI match; (b) a real certificate for a different domain, meaning a configured default is being served because the SNI matched nothing specific; (c) the correct certificate, meaning the problem is client-side (trust store, old CA bundle) rather than selection.

  3. Check what certificates Traefik actually has. Use traefik_tls_certs_not_after and compare the cn/sans labels against the failing hostname. If no loaded certificate covers it, the selection behavior is correct and the problem is upstream: the certificate was never obtained or never loaded. If ACME manages that cert, this becomes a renewal or issuance failure. See Traefik certificate expired and Traefik ACME rate limit.

  4. Confirm the route references TLS correctly. Via /api/http/routers, check that the router for the hostname has TLS enabled and references the resolver or store you expect. A route without TLS configuration will still terminate TLS at the entrypoint if the entrypoint itself does TLS, but with no per-route certificate association, selection falls to SNI matching against the store.

  5. Check the TLS store default. If you intended a specific certificate as the default (for SNI-less clients and unmatched names), verify defaultCertificate or defaultGeneratedCert is defined in the dynamic configuration and that the store is the one Traefik actually uses. If both are defined, defaultCertificate wins. If the store is defined in the wrong place (for example, in static config or a file the provider is not watching), it is silently absent.

  6. Rule out the benign case. If the affected hostname was deployed minutes ago and ACME is still acquiring the certificate, wait for issuance and re-run step 1. Check logs for challenge errors if it does not resolve. See Traefik ACME rate limit if issuance keeps failing.

  7. Check for version-specific selection bugs. Traefik v3.7 changed Gateway API behavior: if the Gateway API CRDs are not updated to the expected version, the provider’s informer never syncs, no listener is programmed, and every HTTPS connection falls back to the default self-signed cert while health checks stay green. If the symptom appeared immediately after a v3.7 upgrade on Kubernetes Gateway API, check logs for Failed to watch errors on TLSRoute or BackendTLSPolicy and verify CRD versions. There were also fixes for nondeterministic certificate selection when multiple loaded certificates share SANs (overlapping wildcard and specific certs). If you have overlapping certificates, upgrading may be the fix.

Metrics and signals to monitor

SignalWhy it mattersWarning sign
traefik_tls_certs_not_after (labels: cn, sans, serial)Inventory of loaded certificates and their expiry; confirms whether the cert for the failing hostname exists at allHostname absent from the label set, or a cert covering it approaching expiry
traefik_entrypoint_requests_tls_total (labels: tls_version, tls_cipher)Confirms TLS handshakes are completing, and on which entrypoint; a mismatch between handshake success and client-reported errors points at selection, not transportHandshakes succeeding while clients report cert warnings
traefik_entrypoint_requests_total{code="404"}Rising entrypoint 404s alongside default-cert reports suggest routes are missing too, which points at provider desync rather than a cert problem404 rate rising on hostnames that previously worked
traefik_config_last_reload_successA frozen timestamp means stale configuration; a newly deployed cert or TLS store change may simply not be loadedTimestamp not advancing while config changes are being made
External synthetic TLS probes per production hostnameThe only signal that actually detects “wrong cert served”. Traefik has no metric for certificate selection outcomeProbe sees unexpected subject/issuer or a self-signed cert

Nothing in Traefik’s Prometheus metrics tells you which certificate was presented for a handshake. The selection failure is only observable from the client side. Without external TLS probes, you are blind to this entire failure class.

Fixes

Add the missing certificate for the hostname

If the SNI simply has no matching cert, obtain or load one that covers the hostname. For ACME-managed domains, fix whatever is blocking issuance (challenge reachability, rate limits, corrupted acme.json). For manually managed certs, make sure the certificate and key are defined where your provider can load them, and that the SAN list covers every hostname you serve, including bare-domain and www variants.

Tradeoff: none. This is the correct fix when the inventory check showed the cert missing.

Configure a deliberate default certificate

If you serve many hostnames and want unmatched or SNI-less connections to get a real, valid certificate instead of the self-signed fallback, set defaultCertificate (or defaultGeneratedCert for a generated cert with controlled parameters) in the TLS store. The default certificate is what non-SNI clients and scanners will see.

Tradeoff: whatever you choose as the default is publicly visible for any unmatched name, so pick something you do not mind being associated with arbitrary traffic. It also masks misconfigurations: a hostname with a missing cert now serves the default instead of failing loudly, which delays detection of the missing cert.

Enable strict SNI if you want mismatches to fail closed

If your policy is “no valid cert, no handshake”, strict SNI checking makes Traefik refuse the handshake when no certificate matches, instead of serving the default. This converts silent wrong-cert serving into an immediate, loud connection failure, which is easier to alert on and does not leak a certificate for the wrong name.

Tradeoff: clients without SNI (rare, but they exist) and any hostname with a missing cert get a hard failure instead of a working-but-wrong-cert connection. During a cert outage, the blast radius is total for the affected name rather than degraded.

Fix the TLS store or route association

If a configured default is being ignored, verify the store definition lives in the dynamic configuration (file provider, or the appropriate CRD on Kubernetes), that it is the store Traefik actually consults, and that the route in question has TLS enabled with the expected reference. Remember the selection order: per-SNI match first, store default second, generated cert last.

Wait out first-boot ACME, then investigate if it persists

For the benign first-boot case, no action is needed if the real cert appears within a few minutes. If the default cert persists, treat it as an ACME issuance failure and debug the challenge path.

Prevention

  • Probe TLS externally, per production hostname. This is the only reliable detector for wrong-cert serving. Check subject, issuer, expiry, and SAN coverage, not just “handshake succeeded”. A probe that only checks TCP 443 open will never catch this.
  • Alert on traefik_tls_certs_not_after well before expiry. A missing or expiring cert today is a default-cert incident next week. Traefik starts renewal attempts 30 days out for Let’s Encrypt, so treat renewal as broken long before expiry; ticket at under 7 days remaining.
  • Decide your default-cert policy explicitly. Either configure a deliberate default certificate, or enable strict SNI so mismatches fail closed. The worst option is the implicit one: the self-signed fallback served to real users while nobody watches.
  • Baseline which hostnames should serve which certificates and alert when the served subject changes. Cert changes outside a deployment window are a signal worth paging on.
  • After Traefik upgrades, verify certificate serving before declaring success. Version-specific selection bugs and provider sync failures (the v3.7 Gateway API case above) present as default-cert serving with green health checks. A one-line openssl s_client check per hostname in your post-upgrade checklist catches this class entirely.

How Netdata helps

Netdata surfaces the signals that bracket this failure, even though the selection decision itself is only client-observable:

  • Certificate inventory and expiry via traefik_tls_certs_not_after, with per-certificate CN and SAN labels, so you can confirm whether a cert for the failing hostname is loaded and how long it has left.
  • TLS negotiation breakdown via traefik_entrypoint_requests_tls_total, showing handshake volume by TLS version and cipher per entrypoint, which confirms handshakes are completing while clients complain.
  • Config freshness via traefik_config_last_reload_success, so you can tell immediately whether a newly added certificate or TLS store change was ever loaded, or whether Traefik is running stale config.
  • Entrypoint 404 rate to distinguish a pure certificate problem from a wider routing or provider desync problem, since the two often travel together after a bad deploy or provider outage.
  • Correlation across these signals in one view: default-cert reports plus a frozen config timestamp plus missing cert inventory points at provider desync; default-cert reports plus a present-but-expiring cert points at ACME renewal failure. Seeing them together is what turns a user screenshot into a root cause in minutes.