{"record":{"id":"484df517137ef333","repo":"nats-io/nats-server","slug":"websocket-requires-tls-configuration","errorCode":null,"errorMessage":"websocket requires TLS configuration","messagePattern":"websocket requires TLS configuration","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/websocket.go","lineNumber":1134,"sourceCode":"\tif _, err := io.ReadFull(crand.Reader, p); err != nil {\n\t\treturn _EMPTY_, err\n\t}\n\treturn base64.StdEncoding.EncodeToString(p), nil\n}\n\n// Validate the websocket related options.\nfunc validateWebsocketOptions(o *Options) error {\n\two := &o.Websocket\n\t// If no port is defined, we don't care about other options\n\tif wo.Port == 0 {\n\t\treturn nil\n\t}\n\tif !wsAllowedFIPS() {\n\t\treturn fmt.Errorf(\"websocket: cannot be used in FIPS-140 mode when built with this Go version, use Go 1.26 or later\")\n\t}\n\t// Enforce TLS... unless NoTLS is set to true.\n\tif wo.TLSConfig == nil && !wo.NoTLS {\n\t\treturn errors.New(\"websocket requires TLS configuration\")\n\t}\n\t// Make sure that allowed origins, if specified, can be parsed.\n\tfor _, ao := range wo.AllowedOrigins {\n\t\tu, err := url.ParseRequestURI(ao)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to parse allowed origin: %v\", err)\n\t\t}\n\t\tif u.Scheme != \"http\" && u.Scheme != \"https\" {\n\t\t\treturn fmt.Errorf(\"unable to parse allowed origin %q: allowed origins must be absolute URLs with http or https scheme\", ao)\n\t\t}\n\t\tif u.Host == _EMPTY_ {\n\t\t\treturn fmt.Errorf(\"unable to parse allowed origin %q: host is required\", ao)\n\t\t}\n\t\tif _, _, err := wsGetHostAndPort(u.Scheme == \"https\", u.Host); err != nil {\n\t\t\treturn fmt.Errorf(\"unable to parse allowed origin: %v\", err)\n\t\t}\n\t}\n\t// If there is a NoAuthUser, we need to have Users defined and","sourceCodeStart":1116,"sourceCodeEnd":1152,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/websocket.go#L1116-L1152","documentation":"The websocket block validation (websocket.go, options validation) enforces that a TLS configuration is provided unless NoTLS is explicitly set. Because plain websocket (ws://) without explicit opt-out is considered unsafe/misconfigured, the server refuses to start. FIPS builds with an older Go are rejected beforehand with a separate message.","triggerScenarios":"Config contains a websocket {} block but no tls {} sub-block (TLSConfig is nil) and no `no_tls: true`; programmatic Options set Websocket without TLSConfig and leave NoTLS false.","commonSituations":"Dev setups intending plain ws:// but forgetting no_tls: true; TLS configured at an external proxy but not in NATS while no_tls wasn't set; copying a production config and removing the TLS block.","solutions":["Add a tls block (cert_file/key_file) under websocket {} to enable TLS","If you intentionally want plain ws://, set `no_tls: true` in the websocket block","When building Options in code, assign Websocket.TLSConfig or set Websocket.NoTLS = true","If on FIPS mode with Go < 1.26, upgrade the build toolchain per the adjacent FIPS error"],"exampleFix":"// before (server.conf)\nwebsocket {\n  port: 8080\n}\n// after\nwebsocket {\n  port: 8080\n  no_tls: true\n}","handlingStrategy":"validation","validationCode":"// before starting the server programmatically\nfunc validateWebsocketOpts(wo *server.WebsocketOpts) error {\n    if wo == nil || (wo.TLSConfig == nil && !wo.NoTLS) {\n        return errors.New(\"websocket: set TLSConfig or NoTLS=true\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair a websocket block with either tls {} or no_tls: true","Validate configs with nats-server -t in CI","Document that TLS at an external proxy still requires no_tls: true locally","Review FIPS/Go version requirements before enabling websockets in FIPS builds"],"tags":["websocket","tls","config","startup"],"backgroundTag":"missing-tls-config","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}