slackhq/nebula · critical

nebula certificate for this host is expired

Error message

nebula certificate for this host is expired

What it means

After successfully parsing pki.cert, loadCertificate checks c.Expired(time.Now()); if the certificate's validity window has passed, startup aborts with this error. Nebula refuses to run with an expired host certificate because peers and the CA would reject it anyway.

Source

Thrown at pki.go:526

			return nil, curve, false, fmt.Errorf("unable to read pki.key file %s: %s", privPathOrPEM, err)
		}
		rawKey, _, curve, err = cert.UnmarshalPrivateKeyFromPEM(pemPrivateKey)
		if err != nil {
			return nil, curve, false, fmt.Errorf("error while unmarshaling pki.key %s: %s", privPathOrPEM, err)
		}
	}

	return
}

func loadCertificate(b []byte) (cert.Certificate, []byte, error) {
	c, b, err := cert.UnmarshalCertificateFromPEM(b)
	if err != nil {
		return nil, b, fmt.Errorf("error while unmarshaling pki.cert: %w", err)
	}

	if c.Expired(time.Now()) {
		return nil, b, fmt.Errorf("nebula certificate for this host is expired")
	}

	if len(c.Networks()) == 0 {
		return nil, b, fmt.Errorf("no networks encoded in certificate")
	}

	if c.IsCA() {
		return nil, b, fmt.Errorf("host certificate is a CA certificate")
	}

	return c, b, nil
}

func loadCAPoolFromConfig(l *slog.Logger, c *config.C) (*cert.CAPool, error) {
	caPathOrPEM := c.GetString("pki.ca", "")
	if caPathOrPEM == "" {
		return nil, errors.New("no pki.ca path or PEM data provided")
	}

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Reissue the host certificate with 'nebula-cert sign' (longer -duration if desired) and update pki.cert
  2. Fix the host clock if it is wrong (NTP sync) and restart
  3. Verify expiry with 'nebula-cert print -path host.crt' before restarting

Example fix

// before
nebula-cert sign -ca-cpath ca.crt -ca-kpath ca.key -name host -ip 10.0.0.5  # default short duration
// after
nebula-cert sign -ca-cpath ca.crt -ca-kpath ca.key -name host -ip 10.0.0.5 -duration 8760h
Defensive patterns

Strategy: validation

Validate before calling

c, _, err := cert.UnmarshalCertificateFromPEM(certBytes)
if err == nil && c.Expired(time.Now()) {
    return fmt.Errorf("host cert expired; reissue before starting")
}

Type guard

func certValid(c cert.Certificate) bool { return !c.Expired(time.Now()) }

Try / catch

if err := runNebula(); err != nil && strings.Contains(err.Error(), "expired") {
    if rerr := reissueCert(); rerr != nil { return rerr }
    return runNebula()
}

Prevention

When it happens

Trigger: newCertStateFromConfig loads a host certificate whose NotAfter timestamp is earlier than the current wall-clock time.

Common situations: Long-lived deployments where a 1-year (or short-lived) cert aged out; machine clock jumped forward (wrong RTC, VM restore); cert issued with a short expiry for testing.

Understand the failure class

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/3b0a886e966959ec. Report an issue: GitHub.