crowdsecurity/crowdsec · critical

missing TLS key file

Error message

missing TLS key file

What it means

The LAPI server enables TLS when a cert or key file path is configured, but ServeTLS requires both. If only cert_file_path is set and key_file_path is empty, the server reports 'missing TLS key file' on the serverError channel and refuses to start with TLS.

Source

Thrown at pkg/apiserver/apiserver.go:377

	}

	return nil
}

// listenAndServeLAPI starts the http server and blocks until it's closed
// it also updates the URL field with the actual address the server is listening on
// it's meant to be run in a separate goroutine
func (s *APIServer) listenAndServeLAPI(ctx context.Context, apiReady chan bool) error {
	serverError := make(chan error, 2)

	listenConfig := &net.ListenConfig{}

	startServer := func(listener net.Listener, canTLS bool) {
		var err error

		if canTLS && s.cfg.TLS != nil && (s.cfg.TLS.CertFilePath != "" || s.cfg.TLS.KeyFilePath != "") {
			if s.cfg.TLS.KeyFilePath == "" {
				serverError <- errors.New("missing TLS key file")
				return
			}

			if s.cfg.TLS.CertFilePath == "" {
				serverError <- errors.New("missing TLS cert file")
				return
			}

			err = s.httpServer.ServeTLS(listener, s.cfg.TLS.CertFilePath, s.cfg.TLS.KeyFilePath)
		} else {
			err = s.httpServer.Serve(listener)
		}

		switch {
		case errors.Is(err, http.ErrServerClosed):
			break
		case err != nil:
			serverError <- err

View on GitHub (pinned to 909b515798)

Solutions

  1. Set api.server.tls.key_file_path in the config to the path of the private key file.
  2. Verify YAML indentation: key_file_path must be nested under the same tls: section as cert_file_path.
  3. If TLS is not wanted, remove both cert and key paths so the server falls back to plain HTTP.

Example fix

# before
api:
  server:
    tls:
      cert_file_path: /etc/ssl/certs/lapi.crt
# after
api:
  server:
    tls:
      cert_file_path: /etc/ssl/certs/lapi.crt
      key_file_path: /etc/ssl/private/lapi.key
Defensive patterns

Strategy: validation

Validate before calling

tls := cfg.API.Server.TLS
if tls != nil && (tls.CertFilePath != "" || tls.KeyFilePath != "") {
    if tls.CertFilePath == "" || tls.KeyFilePath == "" {
        return fmt.Errorf("both cert_file_path and key_file_path are required")
    }
    if _, err := os.Stat(tls.CertFilePath); err != nil { return err }
    if _, err := os.Stat(tls.KeyFilePath); err != nil { return err }
}

Try / catch

if err := server.StartApiserver(ctx); err != nil {
    log.Fatalf("LAPI startup failed: %v", err) // inspect serverError channel output
}

Prevention

When it happens

Trigger: api.server.tls configured in crowdsec config with cert_file_path set but key_file_path empty or omitted.

Common situations: Copy-pasted TLS config where the key line was deleted or mis-indented (wrong YAML nesting so the key lands outside the tls block), provisioning tools that templated only the cert path.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/f19bb9c0b8033fe3. Report an issue: GitHub.