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

  1. Send a real CONNECT request: `curl -x http://frps:port http://target` or configure the client as an HTTP proxy
  2. If you want plain HTTP virtual hosting on that port, use vhostHTTPPort / type = "http" instead of tcpmux httpconnect
  3. Supply Proxy-Authorization (basic auth) if the proxy configured routeByHTTPUser credentials
  4. 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

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


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/89b5df6e824389a4. Report an issue: GitHub.