{"record":{"id":"4df526d02fc1f300","repo":"slackhq/nebula","slug":"error-while-loading-sshd-host-key-file-s","errorCode":null,"errorMessage":"error while loading sshd.host_key file: %s","messagePattern":"error while loading sshd\\.host_key file: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ssh.go","lineNumber":106,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid sshd.listen address: %s\", err)\n\t}\n\tif port == \"22\" {\n\t\treturn nil, fmt.Errorf(\"sshd.listen can not use port 22\")\n\t}\n\n\thostKeyPathOrKey := c.GetString(\"sshd.host_key\", \"\")\n\tif hostKeyPathOrKey == \"\" {\n\t\treturn nil, fmt.Errorf(\"sshd.host_key must be provided\")\n\t}\n\n\tvar hostKeyBytes []byte\n\tif strings.Contains(hostKeyPathOrKey, \"-----BEGIN\") {\n\t\thostKeyBytes = []byte(hostKeyPathOrKey)\n\t} else {\n\t\thostKeyBytes, err = os.ReadFile(hostKeyPathOrKey)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error while loading sshd.host_key file: %s\", err)\n\t\t}\n\t}\n\n\terr = ssh.SetHostKey(hostKeyBytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error while adding sshd.host_key: %s\", err)\n\t}\n\n\t// Clear existing trusted CAs and authorized keys\n\tssh.ClearTrustedCAs()\n\tssh.ClearAuthorizedKeys()\n\n\trawCAs := c.GetStringSlice(\"sshd.trusted_cas\", []string{})\n\tfor _, caAuthorizedKey := range rawCAs {\n\t\terr := ssh.AddTrustedCA(caAuthorizedKey)\n\t\tif err != nil {\n\t\t\tl.Warn(\"SSH CA had an error, ignoring\", \"error\", err, \"sshCA\", caAuthorizedKey)\n\t\t\tcontinue","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/ssh.go#L88-L124","documentation":"When sshd.host_key is a path (not an inline PEM literal), configSSH reads it with os.ReadFile. Any read failure — missing file, permission denied, wrong path — is wrapped as \"error while loading sshd.host_key file\". The server cannot start without the host key bytes.","triggerScenarios":"sshd.host_key contains a path and os.ReadFile fails: nonexistent file, unreadable permissions, wrong working directory for a relative path, or the value is a PEM body without \"-----BEGIN\" so it is treated as a path (ssh.go:106).","commonSituations":"Container images that never copied the key file; running the binary as a non-root user lacking read permission; relative paths resolving differently under systemd's WorkingDirectory; pasting a public key or truncated key without the BEGIN header.","solutions":["Verify the path exists and is readable by the process user (ls -l / test with os.ReadFile).","Use an absolute path in sshd.host_key instead of a relative one.","If providing an inline key, ensure it includes the \"-----BEGIN ... PRIVATE KEY-----\" header so it isn't treated as a path."],"exampleFix":"// before\nhost_key = \"host_key\" // relative, wrong cwd\n// after\nhost_key = \"/etc/myapp/ssh/host_key\"","handlingStrategy":"validation","validationCode":"hk := cfg.GetString(\"sshd.host_key\", \"\")\nif !strings.Contains(hk, \"-----BEGIN\") { // treated as a path\n    if _, err := os.Stat(hk); err != nil {\n        return fmt.Errorf(\"sshd.host_key file unreadable: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"run, err := configSSH(logger, srv, c)\nif err != nil {\n    var pe *fs.PathError\n    if strings.Contains(err.Error(), \"error while loading sshd.host_key file\") {\n        logger.Error(\"cannot read sshd.host_key file; check path and permissions\")\n        os.Exit(78)\n    }\n    _ = pe\n    return err\n}","preventionTips":["Use absolute paths for sshd.host_key; never rely on the process working directory.","Ensure the key file is readable by the runtime user (check with sudo -u <user> test -r).","If embedding the key inline, it must contain a \"-----BEGIN\" PEM header."],"tags":["ssh","configuration","host-key","file-io"],"backgroundTag":"host-key-file-not-found","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}