How frp TCP Stream Multiplexing Improves Performance and Reduces Latency

frp uses the Yamux library to multiplex multiple logical proxy streams over a single TCP connection, eliminating per-request handshake overhead and reducing latency by reusing an established congestion-controlled socket.

frp (Fast Reverse Proxy) is an open-source reverse proxy application that enables exposing local servers behind NATs to the internet. One of its key performance optimizations is frp TCP stream multiplexing, which allows multiple proxy connections to share a single underlying TCP socket between the client (frpc) and server (frps).

What Is frp TCP Stream Multiplexing?

TCP stream multiplexing in frp is implemented via the TCPMux feature, which leverages the Yamux library to create many logical streams over one physical TCP connection. Instead of opening a new TCP socket for every proxy request, frp maintains a persistent session and opens lightweight streams within it.

This approach eliminates the TCP three-way handshake and TLS negotiation for every new proxy connection, significantly reducing connection establishment time and CPU overhead.

Performance Benefits of TCP Stream Multiplexing in frp

The following table summarizes how TCPMux improves performance and reduces latency:

TCPMux Capability Performance Impact
Reuses one TCP socket for all proxy connections Eliminates TCP handshake and TLS setup per request, saving round-trip time and CPU cycles
Maintains persistent connections with configurable TCPMuxKeepaliveInterval Prevents idle timeouts, allowing subsequent streams to start instantly without connection setup
Shares congestion-control state (window size, RTT, loss recovery) across streams Improves throughput for many small streams by leveraging an already-trained congestion window
Aggregates traffic on a single port via TCPMuxHTTPConnectPort Reduces kernel socket overhead and simplifies NAT/firewall configuration
Enables per-proxy routing via the TCPMux group controller Allows multiple domains or users to share one multiplexed connection while remaining logically isolated

How frp Implements TCP Stream Multiplexing

frp's multiplexing architecture involves coordinated configuration on both client and server sides, utilizing the Yamux library for session management.

Server-Side Configuration

In pkg/config/v1/server.go, TCPMux is enabled by default with TCPMux set to true:

// Server transport defaults to TCPMux enabled
// src: pkg/config/v1/server.go#L58-L64
c.TCPMux = util.EmptyOr(c.TCPMux, lo.ToPtr(true))

When TCPMuxHTTPConnectPort is configured, the server creates an HTTP CONNECT multiplexer listener in server/service.go:

// Create the http-connect multiplexer if needed
// src: server/service.go#L185-L199
if cfg.TCPMuxHTTPConnectPort > 0 {
    address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.TCPMuxHTTPConnectPort))
    l, err = net.Listen("tcp", address)
    svr.rc.TCPMuxHTTPConnectMuxer, err = tcpmux.NewHTTPConnectTCPMuxer(l, cfg.TCPMuxPassthrough, vhostReadWriteTimeout)
}

Client-Side Connection Handling

On the client side, client/connector.go establishes a single TCP connection and wraps it in a Yamux session when tcpMux is enabled:

// Open the underlying connection and start a Yamux session
// src: client/connector.go#L15-L25
if !lo.FromPtr(c.cfg.Transport.TCPMux) { return nil }
conn, err := c.realConnect()
fmuxCfg := fmux.DefaultConfig()
fmuxCfg.KeepAliveInterval = time.Duration(c.cfg.Transport.TCPMuxKeepaliveInterval) * time.Second
session, err := fmux.Client(conn, fmuxCfg)   // one Yamux session
c.muxSession = session

Each proxy connection request then opens a new logical stream within this session:

// Retrieve a stream from the Yamux session
// src: client/connector.go#L36-L42
stream, err := c.muxSession.OpenStream()

Stream Routing and HTTP CONNECT

The server routes multiplexed streams using server/group/tcpmux.go and server/proxy/tcpmux.go. For HTTP CONNECT proxying, pkg/util/tcpmux/httpconnect.go parses the CONNECT request and routes accordingly:

// Parse CONNECT request and produce a host-specific stream
// src: pkg/util/tcpmux/httpconnect.go#L49-L70
host, httpUser, httpPwd, err := muxer.readHTTPConnectRequest(rd)

Configuring TCPMux in frp

Server Configuration (frps)

Enable multiplexing and configure keep-alive intervals in frps.toml:


# frps.toml

[common]

# Enable multiplexing (default = true)

tcp_mux = true
tcp_mux_keepalive_interval = 30   # seconds

tcp_mux_http_connect_port = 7001  # port for HTTP CONNECT multiplexing

tcp_mux_passthrough = false       # let frps handle CONNECT response

Client Configuration (frpc)

Configure the client to use the multiplexed connection:


# frpc.toml

[common]
server_addr = "your.frps.host"
server_port = 7000
tcp_mux = true                     # use one underlying connection

tcp_mux_keepalive_interval = 30   # keep-alive for the Yamux session

HTTP CONNECT Multiplexing

For HTTP CONNECT proxying, specify the multiplexer type in your proxy configuration:

[ssh]
type = "tcp"
local_port = 2222
remote_port = 22
multiplexer = "httpconnect"   # tells frpc to use the HTTP CONNECT port

Key Source Files for frp TCP Stream Multiplexing

Path Role
pkg/config/v1/server.go Transport configuration with default TCPMux = true
client/connector.go Opens Yamux session and manages stream creation
server/service.go Creates HTTP CONNECT multiplexer listener
server/group/tcpmux.go Routes multiplexed streams to correct proxy listeners
server/proxy/tcpmux.go Proxy factory for TCPMux type
pkg/util/tcpmux/httpconnect.go Implements HTTP CONNECT multiplexing logic

Summary

  • frp TCP stream multiplexing collapses multiple logical proxy connections into a single physical TCP socket using the Yamux library.
  • Eliminates per-connection overhead by removing TCP handshakes and TLS negotiations for each new proxy request.
  • Reduces latency through persistent connections with configurable keep-alive intervals and shared congestion-control state.
  • Simplifies infrastructure by aggregating traffic onto single ports and reducing kernel socket allocation.
  • Maintains isolation between different proxies through logical stream routing while sharing the underlying transport.

Frequently Asked Questions

What is the difference between TCPMux and regular TCP proxying in frp?

Regular TCP proxying creates a new TCP connection for every proxy request, requiring a full TCP handshake and TLS negotiation each time. TCPMux maintains a single persistent TCP connection between frpc and frps, opening lightweight logical streams within that session for each new proxy request, which eliminates connection setup latency.

How does TCPMux affect latency compared to creating new connections?

TCPMux significantly reduces latency by removing the TCP three-way handshake and TLS handshake from the critical path of new proxy requests. Once the initial Yamux session is established, new streams start instantly without waiting for network round-trips, and shared congestion-control state ensures optimal throughput immediately rather than requiring slow-start ramp-up.

Can I use TCPMux with HTTP CONNECT proxying?

Yes, frp supports HTTP CONNECT multiplexing through the tcp_mux_http_connect_port configuration on the server and the multiplexer = "httpconnect" setting on the client. This allows the HTTP CONNECT protocol to benefit from the same connection reuse and reduced overhead as standard TCP multiplexing, with the server handling CONNECT request parsing in pkg/util/tcpmux/httpconnect.go.

What happens if the multiplexed connection drops?

If the underlying TCP connection carrying the Yamux session is interrupted, all logical streams within that session are terminated simultaneously. The frp client will automatically attempt to reconnect and establish a new Yamux session based on the configured keep-alive intervals and retry logic, but any in-flight requests on the dropped connection will need to be reestablished on the new session.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →