{"record":{"id":"7682120beece34fc","repo":"fatedier/frp","slug":"tls-certfile-must-be-specified-when-tls-is-enabled","errorCode":null,"errorMessage":"tls.certFile must be specified when tls is enabled","messagePattern":"tls\\.certFile must be specified when tls is enabled","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/v1/validation/common.go","lineNumber":27,"sourceCode":"// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage validation\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\tv1 \"github.com/fatedier/frp/pkg/config/v1\"\n)\n\nfunc validateWebServerConfig(c *v1.WebServerConfig) error {\n\tif c.TLS != nil {\n\t\tif c.TLS.CertFile == \"\" {\n\t\t\treturn fmt.Errorf(\"tls.certFile must be specified when tls is enabled\")\n\t\t}\n\t\tif c.TLS.KeyFile == \"\" {\n\t\t\treturn fmt.Errorf(\"tls.keyFile must be specified when tls is enabled\")\n\t\t}\n\t}\n\n\treturn ValidatePort(c.Port, \"webServer.port\")\n}\n\n// ValidatePort checks that the network port is in range\nfunc ValidatePort(port int, fieldPath string) error {\n\tif 0 <= port && port <= 65535 {\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"%s: port number %d must be in the range 0..65535\", fieldPath, port)\n}\n\nfunc validateLogConfig(c *v1.LogConfig) error {","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/v1/validation/common.go#L9-L45","documentation":"For the admin webServer, enabling TLS (webServer.tls present/non-nil) requires a server certificate. validateWebServerConfig returns immediately if tls.certFile is empty, so the dashboards' HTTPS listener cannot start half-configured.","triggerScenarios":"Client or server config with [webServer.tls] section (or tls: {} in YAML) but no certFile key — e.g. only keyFile provided, or the tls block added as a placeholder.","commonSituations":"Copying a webServer block and forgetting the cert path; intending plain HTTP but accidentally leaving an empty tls map which YAML parses as non-nil; cert path variable left blank in a template.","solutions":["Set webServer.tls.certFile to a valid PEM certificate path (alongside keyFile)","Or remove the webServer.tls section entirely if HTTPS on the admin endpoint is not wanted (empty tls:{} still counts as enabled)","Verify file permissions so frp can read the cert at startup"],"exampleFix":"# before\n[webServer]\nport = 7400\n[webServer.tls]\nkeyFile = \"admin.key\"\n\n# after\n[webServer]\nport = 7400\n[webServer.tls]\ncertFile = \"admin.crt\"\nkeyFile = \"admin.key\"","handlingStrategy":"validation","validationCode":"func webServerTLSComplete(c *v1.WebServerConfig) bool {\n    return c.TLS == nil || c.TLS.CertFile != \"\"\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid empty tls:{} maps in YAML — they enable the TLS requirement","Pair cert and key paths in one template variable set"],"tags":["frp","config","webserver","tls","dashboard","go"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}