{"record":{"id":"350319ca3799dee1","repo":"fatedier/frp","slug":"create-ssh-gateway-error-v","errorCode":null,"errorMessage":"create ssh gateway error, %v","messagePattern":"create ssh gateway error, (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"server/service.go","lineNumber":283,"sourceCode":"\tif cfg.QUICBindPort > 0 {\n\t\taddress := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.QUICBindPort))\n\t\tquicTLSCfg := tlsConfig.Clone()\n\t\tquicTLSCfg.NextProtos = []string{\"frp\"}\n\t\tsvr.quicListener, err = quic.ListenAddr(address, quicTLSCfg, &quic.Config{\n\t\t\tMaxIdleTimeout:     time.Duration(cfg.Transport.QUIC.MaxIdleTimeout) * time.Second,\n\t\t\tMaxIncomingStreams: int64(cfg.Transport.QUIC.MaxIncomingStreams),\n\t\t\tKeepAlivePeriod:    time.Duration(cfg.Transport.QUIC.KeepalivePeriod) * time.Second,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"listen on quic udp address %s error: %v\", address, err)\n\t\t}\n\t\tlog.Infof(\"frps quic listen on %s\", address)\n\t}\n\n\tif cfg.SSHTunnelGateway.BindPort > 0 {\n\t\tsshGateway, err := ssh.NewGateway(cfg.SSHTunnelGateway, cfg.BindAddr, svr.sshTunnelListener)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"create ssh gateway error: %v\", err)\n\t\t}\n\t\tsvr.sshTunnelGateway = sshGateway\n\t\tlog.Infof(\"frps sshTunnelGateway listen on port %d\", cfg.SSHTunnelGateway.BindPort)\n\t}\n\n\t// Listen for accepting connections from client using websocket protocol.\n\twebsocketPrefix := []byte(\"GET \" + netpkg.FrpWebsocketPath)\n\twebsocketLn := svr.muxer.Listen(0, uint32(len(websocketPrefix)), func(data []byte) bool {\n\t\treturn bytes.Equal(data, websocketPrefix)\n\t})\n\tsvr.websocketListener = netpkg.NewWebsocketListener(websocketLn)\n\n\t// Create http vhost muxer.\n\tif cfg.VhostHTTPPort > 0 {\n\t\trp := vhost.NewHTTPReverseProxy(vhost.HTTPReverseProxyOptions{\n\t\t\tResponseHeaderTimeoutS: cfg.VhostHTTPTimeout,\n\t\t}, svr.httpVhostRouter)\n\t\tsvr.rc.HTTPReverseProxy = rp","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/server/service.go#L265-L301","documentation":"When SSHTunnelGateway.BindPort > 0, frps builds an SSH gateway with ssh.NewGateway; failure aborts startup. The wrapped %v carries the underlying cause, typically listener or SSH key setup problems inside the gateway.","triggerScenarios":"Enabling the SSH tunnel gateway while its port or host-key resources are unavailable; a partially configured sshTunnelGateway section (missing/invalid authorized keys, key generation failure).","commonSituations":"Testing the ssh-tunnel visitor feature with incomplete gateway config; read-only filesystem preventing host-key creation; port collision for the gateway listener.","solutions":["Read the wrapped cause in the log line to see if it is a bind or key problem","Free/change the SSH gateway bind port if it is a collision","Give frps a writable directory for SSH host keys","Remove the sshTunnelGateway section if the feature is unused"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := service.New(cfg); err != nil && strings.Contains(err.Error(), \"create ssh gateway error\") {\n    // inspect wrapped cause; fix key dir/port, then restart. Do not loop-retry.","preventionTips":["Give frps a writable working directory for SSH host keys","Only enable sshTunnelGateway when the feature is actually used","Include the gateway port in the host port inventory"],"tags":["frps","startup","ssh","gateway"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}