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 <- errView on GitHub (pinned to 909b515798)
Solutions
- Set api.server.tls.key_file_path in the config to the path of the private key file.
- Verify YAML indentation: key_file_path must be nested under the same tls: section as cert_file_path.
- 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
- Always configure cert_file_path and key_file_path as a pair (use config templates/anchors).
- Validate the full config with `cscli config show` / `crowdsec -c ... -t` before restart.
- Keep both files in the same provisioning playbook step.
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.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- missing TLS cert file
- missing lapi client credentials
- missing TLS key file
- missing TLS cert file
- plugins are enabled, but the plugin_config section is missin
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/f19bb9c0b8033fe3.
Report an issue: GitHub.