How to Set Up frp with KCP Protocol for Better Performance on Lossy Networks

Enable KCP in frp by setting kcpBindPort on the server and transport.protocol = "kcp" on the client to replace TCP with a UDP-based transport that tolerates packet loss.

The fatedier/frp (Fast Reverse Proxy) repository supports the KCP protocol as an alternative transport layer, allowing you to tunnel traffic over UDP with forward error correction. This configuration significantly reduces latency and improves throughput on unstable networks such as mobile or satellite connections. By switching from TCP to KCP, frp maintains its full feature set—including multiplexing and authentication—while gaining resilience against packet loss.

Architecture and Implementation Details

frp implements KCP transport through a modular design that separates the underlying UDP socket handling from the high-level proxy logic.

Server-Side KCP Listener

When you configure kcpBindPort in the server configuration, frps creates a dedicated UDP listener that accepts KCP connections. In server/service.go#L84-L89, the server initializes Service.kcpListener and registers it with the generic connection handler, treating KCP sessions identically to TCP sockets once established.

Client-Side Transport Selection

The client selects KCP through the transport.protocol configuration field. As defined in pkg/config/v1/client.go#L99-L104, the ClientTransportConfig.Protocol field accepts "kcp" as a valid value, triggering the client to dial the server using UDP-based KCP instead of standard TCP.

Underlying KCP Implementation

frp leverages the third-party library github.com/xtaci/kcp-go/v5 for the low-level transport. The session configuration in pkg/util/net/kcp.go#L96-L106 applies production-ready defaults:

  • No-delay mode (SetNoDelay(1, 20, 2, 1)) for fast retransmission
  • MTU 1350 to avoid fragmentation on most internet paths
  • Window size 1024×1024 to accommodate high-bandwidth delay products

The validation logic in pkg/config/v1/validation/visitor.go#L58-L59 ensures that the KCP port is positive and the protocol name is supported before the client attempts to connect.

Why KCP Improves Performance on Lossy Networks

KCP adds several mechanisms that TCP lacks, making it ideal for high-latency or lossy environments:

  • Forward error correction recovers missing packets without waiting for a full round-trip retransmission.
  • Selective ACKs allow the protocol to acknowledge specific received segments while requesting only the missing ones.
  • Configurable congestion control via the window size parameter lets you tune the pipeline depth to match your specific network characteristics.

Configuration Examples

Server Configuration (frps.toml)

Configure the server to listen on both TCP and UDP ports. The kcpBindPort can match your standard bindPort since they use different protocols.


# frps.toml

bindPort = 7000          # TCP port for standard connections

kcpBindPort = 7000       # UDP port for KCP traffic

# Optional performance settings

transport.tcpMux = true
log.level = "info"

The kcpBindPort field maps directly to ServerConfig.KCPBindPort as defined in the configuration structs.

Client Configuration (frpc.toml)

Set transport.protocol to "kcp" and ensure serverPort matches the server's kcpBindPort.


# frpc.toml

serverAddr = "your.frps.host"
serverPort = 7000          # Must align with server's kcpBindPort

transport.protocol = "kcp"

[[proxies]]
name = "ssh"
type = "tcp"
localPort = 22
remotePort = 6000

This configuration populates ClientTransportConfig.Protocol (see [pkg/config/v1/client.go](https://github.com/fatedier/frp/blob/dev/pkg/config/v1/client.go)), causing the client to establish a KCP session during initialization.

Programmatic Configuration (Go)

For custom integrations using the frp client library:

package main

import (
    "github.com/fatedier/frp/pkg/config/v1"
    "github.com/fatedier/frp/pkg/client"
)

func main() {
    cfg := &v1.ClientCommonConfig{
        ServerAddr: "your.frps.host",
        ServerPort: 7000,
        Transport: v1.ClientTransportConfig{
            Protocol: "kcp",  // Enable KCP transport
        },
    }
    
    cfg.Complete()  // Fill default values
    c, _ := client.NewClient(cfg)
    c.Run()
}

Advanced Tuning Options

If the default settings do not match your network environment, you can modify the hardcoded parameters in [pkg/util/net/kcp.go](https://github.com/fatedier/frp/blob/dev/pkg/util/net/kcp.go):

  • No-delay tuning: Adjust SetNoDelay(1, interval, resend, nc) to control packet resend timing.
  • MTU adjustment: Call SetMtu(size) with a larger value (up to 1400) if your network supports jumbo frames.
  • Window sizing: Increase SetWindowSize(snd, rcv) beyond 1024 for high-bandwidth satellite links.

Note that these parameters require recompiling the binary; they are not exposed in the TOML configuration files in the current release.

Summary

  • Enable KCP on the server by setting kcpBindPort in frps.toml to expose a UDP listener.
  • Configure the client to use transport.protocol = "kcp" to establish UDP-based connections.
  • Benefit from loss tolerance through forward error correction and selective acknowledgment built into the KCP protocol.
  • Reference implementation files including server/service.go, pkg/util/net/kcp.go, and pkg/config/v1/client.go for the complete transport stack.
  • Tune performance by modifying window sizes and no-delay parameters in the source code if default values are insufficient for your bandwidth-delay product.

Frequently Asked Questions

Does using KCP require opening additional firewall ports?

Yes. While TCP traffic uses bindPort, KCP operates over UDP. You must allow inbound UDP traffic on the kcpBindPort (default 7000) on your server firewall. The client only needs outbound UDP access to that same port.

Can I mix TCP and KCP clients on the same frps server?

Absolutely. When you configure kcpBindPort alongside bindPort, the server accepts both TCP and KCP connections simultaneously. Individual clients choose their transport protocol via the transport.protocol setting without affecting other connected clients.

Is KCP always faster than TCP?

Not necessarily. KCP excels on lossy or high-latency networks where TCP's congestion control would throttle throughput. On stable, low-latency networks (such as a data center LAN), TCP often performs better due to lower protocol overhead and kernel-level optimizations.

How do I verify that my connection is using KCP?

Check the server logs after starting frpc. When KCP is active, the connection handshake occurs over UDP, and the logs will show the session establishing on the kcpBindPort rather than the standard TCP port. You can also monitor network traffic using tcpdump or Wireshark to confirm UDP packets on the configured port.

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 →