How to Configure Bandwidth Limits per Proxy in frp for Traffic Shaping
frp supports per-proxy bandwidth limits that can be enforced on either the client or server side using the bandwidth_limit and bandwidth_limit_mode settings.
frp (Fast Reverse Proxy) is a widely-used open-source tunneling solution written in Go that enables exposing local services behind NATs and firewalls to the internet. When managing network resources across multiple tunnels, traffic shaping becomes essential to prevent any single proxy from saturating available bandwidth. Configuring bandwidth limits per proxy in frp allows administrators to enforce QoS policies directly within the tunnel configuration.
Understanding frp's Bandwidth Limit Architecture
The bandwidth limiting system in frp is built around the ProxyTransport configuration structure defined in pkg/config/v1/proxy.go. According to the source code, each proxy can define transport settings that include a BandwidthLimit value and a BandwidthLimitMode.
The BandwidthLimit field accepts a types.BandwidthQuantity (e.g., 100KB, 1MB), while BandwidthLimitMode determines which side of the connection enforces the restriction—either "client" (default) or "server".
Configuration Flags and CLI Integration
Both settings are exposed through the command-line interface in pkg/config/flags.go. The flags --bandwidth_limit and --bandwidth_limit_mode allow runtime specification of these values when starting either frpc or frps.
Configuring Client-Side Bandwidth Limits
When BandwidthLimitMode is set to "client" (or left unspecified), the frp client (frpc) constructs a rate limiter that throttles outgoing traffic toward the server. This enforcement happens in client/proxy/proxy.go, where the code checks if the mode matches types.BandwidthLimitModeClient before wrapping the connection with a rate.Limiter.
INI configuration example:
[ssh]
type = tcp
local_port = 22
remote_port = 6000
bandwidth_limit = 500KB
bandwidth_limit_mode = client
YAML configuration:
ssh:
type: tcp
localPort: 22
remotePort: 6000
transport:
bandwidthLimit: 1MB
bandwidthLimitMode: client
Command-line usage:
./frpc -c frpc.ini --bandwidth_limit 200KB
Configuring Server-Side Bandwidth Limits
Server-side enforcement occurs in server/proxy/proxy.go. When NewProxy creates a proxy instance and detects that BandwidthLimitMode equals types.BandwidthLimitModeServer with a positive limit, it instantiates a rate.Limiter that caps total bytes sent from the server to the client.
This approach is useful when the server operator needs to control egress traffic without relying on client configuration integrity.
INI example:
[ssh]
type = tcp
local_port = 22
remote_port = 6000
bandwidth_limit = 2MB
bandwidth_limit_mode = server
Server startup with global defaults:
./frps -c frps.ini --bandwidth_limit 2MB --bandwidth_limit_mode server
How Bandwidth Limiting Works Under the Hood
The actual traffic shaping leverages the golang.org/x/time/rate package. Both client and server implementations wrap the raw work connection with rate-limited I/O wrappers created by limit.NewReader and limit.NewWriter as shown in client/proxy/proxy.go (lines 46-52).
When the configured byte rate is reached, these wrappers block further reads or writes until the rate limiter provides additional tokens. This mechanism ensures smooth, burstable traffic shaping rather than hard packet drops.
Control Channel Propagation
Bandwidth settings propagate through frp's control channel via the msg.NewProxy message structure. The ProxyBaseConfig.MarshalToMsg method in pkg/config/v1/proxy.go serializes the BandwidthLimit and BandwidthLimitMode fields, while UnmarshalFromMsg reconstructs them on the receiving side. This ensures consistent enforcement regardless of which side initiates the configuration.
Programmatic Configuration in Go
For applications embedding frp directly, you can configure bandwidth limits programmatically using the pkg/config/v1 package:
import (
"github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/types"
)
// Create a proxy with 300KB/s server-side limit
proxyCfg := &v1.ProxyBaseConfig{
Name: "my_tcp",
Type: "tcp",
Transport: v1.ProxyTransport{
BandwidthLimit: types.BandwidthQuantity(300 * 1024),
BandwidthLimitMode: types.BandwidthLimitModeServer,
},
// Additional fields: LocalPort, RemotePort, etc.
}
Summary
- frp implements per-proxy bandwidth limits through the
ProxyTransportconfiguration struct inpkg/config/v1/proxy.go. - The
bandwidth_limitparameter accepts values like100KBor1MB, whilebandwidth_limit_modeselects enforcement side (clientorserver). - Client-side enforcement occurs in
client/proxy/proxy.go, throttling outgoing traffic when mode is"client". - Server-side enforcement occurs in
server/proxy/proxy.go, limiting server-to-client traffic when mode is"server". - The implementation uses
golang.org/x/time/rateto wrap connections with token bucket limiters, providing smooth traffic shaping. - End-to-end test coverage exists in
test/e2e/v1/features/bandwidth_limit.goto verify functionality.
Frequently Asked Questions
Can I set different bandwidth limits for different proxies?
Yes. Since bandwidth limits are defined per proxy in the ProxyTransport configuration, you can assign distinct bandwidth_limit values to each proxy section in your INI or YAML configuration file. Each proxy operates with its own independent rate limiter instantiated during NewProxy.
What happens if I don't specify the bandwidth_limit_mode?
If omitted, frp defaults to "client" mode. As implemented in the configuration parsing logic in pkg/config/v1/proxy.go, an unspecified mode results in client-side enforcement, meaning the frp client application will throttle its own outgoing traffic to meet the specified limit.
Does server-side limiting affect all clients or just one proxy?
Server-side bandwidth limiting configured via bandwidth_limit_mode = server applies only to the specific proxy where it is defined. The rate limiter is instantiated per proxy in server/proxy/proxy.go, ensuring that traffic shaping policies isolate individual tunnels rather than applying globally to all connections.
What units does frp support for bandwidth limits?
frp accepts standard byte units through the types.BandwidthQuantity type. Valid suffixes include KB (kilobytes), MB (megabytes), and GB (gigabytes) per second. For example, bandwidth_limit = 500KB restricts the proxy to 500 kilobytes per second.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →