fatedier/frp · warning

host header rewrite failed

Error message

host header rewrite failed

What it means

In vhost Listener.Accept, after a connection is accepted the muxer optionally rewrites the HTTP Host header (feature used by frp's host-header rewriting for http proxies with rewriteHost). If that rewrite function fails to parse/wrap the connection's first request, the raw error is logged (Warnf) and this generic error is returned instead of the connection. The connection is dropped, not retried.

Source

Thrown at pkg/util/vhost/vhost.go:252

	accept          chan net.Conn
	ctx             context.Context
}

func (l *Listener) Accept() (net.Conn, error) {
	xl := xlog.FromContextSafe(l.ctx)
	conn, ok := <-l.accept
	if !ok {
		return nil, fmt.Errorf("listener closed")
	}

	// if rewriteHost func is exist
	// rewrite http requests with a modified host header
	// if l.rewriteHost is empty, nothing to do
	if l.mux.rewriteHost != nil {
		sConn, err := l.mux.rewriteHost(conn, l.rewriteHost)
		if err != nil {
			xl.Warnf("host header rewrite failed: %v", err)
			return nil, fmt.Errorf("host header rewrite failed")
		}
		xl.Debugf("rewrite host to [%s] success", l.rewriteHost)
		conn = sConn
	}
	return netpkg.NewContextConn(l.ctx, conn), nil
}

func (l *Listener) Close() error {
	l.mux.registryRouter.Del(l.name, l.location, l.routeByHTTPUser)
	close(l.accept)
	return nil
}

func (l *Listener) Name() string {
	return l.name
}

func (l *Listener) Addr() net.Addr {

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Send valid HTTP/1.x requests on the plain vhost port; use vhostHTTPSPort (type=https) for TLS traffic
  2. Check the accompanying Warnf line — it contains the underlying cause (e.g. malformed request, connection reset)
  3. If a proxy needs the original Host preserved, disable host rewriting for that proxy so this code path is skipped

Example fix

# before
curl https://frps:8080/   # TLS bytes to plain http vhost port with rewrite

# after
curl http://frps:8080/   # plain HTTP on vhostHTTPPort
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure only well-formed plain HTTP/1.x hits a rewriting vhost listener
// (send TLS only to the https vhost port)

Try / catch

conn, err := vl.Accept()
if err != nil {
    if strings.Contains(err.Error(), "host header rewrite failed") {
        xl.Warnf("dropped non-HTTP/malformed conn: %v", err)
        continue // drop just this conn; the listener stays usable
    }
    return err
}

Prevention

When it happens

Trigger: A client connects to a vhost listener configured with host rewriting and sends data that is not a parseable HTTP request (binary, TLS bytes to a plain port, truncated request); the rewrite wrapper encounters an I/O error reading the first bytes; extremely long/malformed request headers.

Common situations: HTTPS traffic sent to vhostHTTPPort (plaintext) where rewriting is enabled; health-check TCP probes that connect and send non-HTTP bytes; clients disconnecting mid-request so the header read fails.

Related errors


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