fatedier/frp · error
connections to tcp vhost must be of method CONNECT
Error message
connections to tcp vhost must be of method CONNECT
What it means
Returned by frp's HTTPConnectTCPMuxer when it reads the first request from an incoming connection on a tcpmux port of type httpconnect and the HTTP method is not CONNECT. The httpconnect muxer expects the standard HTTP proxy CONNECT handshake (optionally with Proxy-Authorization basic auth) before it will route the connection to a proxy.
Source
Thrown at pkg/util/tcpmux/httpconnect.go:61
return nil, err
}
mux.SetCheckAuthFunc(ret.auth).
SetSuccessHookFunc(ret.sendConnectResponse).
SetFailHookFunc(vhostFailed)
ret.Muxer = mux
return ret, nil
}
func (muxer *HTTPConnectTCPMuxer) readHTTPConnectRequest(rd io.Reader) (host, httpUser, httpPwd string, err error) {
bufioReader := bufio.NewReader(rd)
req, err := http.ReadRequest(bufioReader)
if err != nil {
return
}
if req.Method != "CONNECT" {
err = fmt.Errorf("connections to tcp vhost must be of method CONNECT")
return
}
host, _ = httppkg.CanonicalHost(req.Host)
proxyAuth := req.Header.Get("Proxy-Authorization")
if proxyAuth != "" {
httpUser, httpPwd, _ = httppkg.ParseBasicAuth(proxyAuth)
}
return
}
func (muxer *HTTPConnectTCPMuxer) sendConnectResponse(c net.Conn, _ map[string]string) error {
if muxer.passthrough {
return nil
}
res := httppkg.OkResponse()
if res.Body != nil {
defer res.Body.Close()View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Send a real CONNECT request: `curl -x http://frps:port http://target` or configure the client as an HTTP proxy
- If you want plain HTTP virtual hosting on that port, use vhostHTTPPort / type = "http" instead of tcpmux httpconnect
- Supply Proxy-Authorization (basic auth) if the proxy configured routeByHTTPUser credentials
- Verify the tcpmux port in frps.toml matches the port the client connects to
Example fix
# before GET / HTTP/1.1 Host: internal.example.com -> error: connections to tcp vhost must be of method CONNECT # after curl -x http://frps:7400 http://internal.example.com/ # sends CONNECT internal.example.com:80
Defensive patterns
Strategy: validation
Validate before calling
// only send CONNECT to an httpconnect muxer port req, _ := http.NewRequest(http.MethodConnect, "http://target.example.com:80", nil) resp, err := http.DefaultClient.Do(req) // a proxy client will issue CONNECT
Try / catch
resp, err := client.Do(req)
if err != nil && strings.Contains(err.Error(), "must be of method CONNECT") {
// wrong client mode: switch to proxy CONNECT semantics or use vhost http port
} Prevention
- Treat tcpmux(httpconnect) ports as HTTP-proxy ports: configure clients as proxies, not browsers
- Document the mux type next to the port number in your ops runbook
- Health-check such ports with a raw CONNECT or TCP dial, never HTTP GET
When it happens
Trigger: A client opens a TCP connection to frps's tcpmuxHTTPConnectPort and sends a plain request (GET/POST) instead of `CONNECT host:port HTTP/1.1`; using an HTTP proxy client against the port with a non-tunnel request; telnet/curl (without -x / CONNECT semantics) probing the port.
Common situations: Configuring tcpmuxType = "httpconnect" on the frpc proxy but pointing a regular HTTP client or browser at that port; Squid-style proxy expectations vs plain HTTP; a health checker doing HTTP GET against the muxer port.
Related errors
- subdomain and custom domains should not be both empty
- name should not be empty
- subdomain is not supported because this feature is not enabl
- '.' and '*' are not supported in subdomain
- invalid argument: body can't be empty
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/89b5df6e824389a4.
Report an issue: GitHub.