# How to Configure Bandwidth Limits per Proxy in frp for Traffic Shaping

> Learn how to configure frp bandwidth limits per proxy for effective traffic shaping. Control client or server traffic with simple settings for optimal performance.

- Repository: [fatedier/frp](https://github.com/fatedier/frp)
- Tags: how-to-guide
- Published: 2026-02-26

---

**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`](https://github.com/fatedier/frp/blob/main/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`](https://github.com/fatedier/frp/blob/main/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`](https://github.com/fatedier/frp/blob/main/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:

```ini
[ssh]
type = tcp
local_port = 22
remote_port = 6000
bandwidth_limit = 500KB
bandwidth_limit_mode = client

```

YAML configuration:

```yaml
ssh:
  type: tcp
  localPort: 22
  remotePort: 6000
  transport:
    bandwidthLimit: 1MB
    bandwidthLimitMode: client

```

Command-line usage:

```bash
./frpc -c frpc.ini --bandwidth_limit 200KB

```

## Configuring Server-Side Bandwidth Limits

Server-side enforcement occurs in [`server/proxy/proxy.go`](https://github.com/fatedier/frp/blob/main/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:

```ini
[ssh]
type = tcp
local_port = 22
remote_port = 6000
bandwidth_limit = 2MB
bandwidth_limit_mode = server

```

Server startup with global defaults:

```bash
./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`](https://github.com/fatedier/frp/blob/main/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`](https://github.com/fatedier/frp/blob/main/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:

```go
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 `ProxyTransport` configuration struct in [`pkg/config/v1/proxy.go`](https://github.com/fatedier/frp/blob/main/pkg/config/v1/proxy.go).
- The `bandwidth_limit` parameter accepts values like `100KB` or `1MB`, while `bandwidth_limit_mode` selects enforcement side (`client` or `server`).
- Client-side enforcement occurs in [`client/proxy/proxy.go`](https://github.com/fatedier/frp/blob/main/client/proxy/proxy.go), throttling outgoing traffic when mode is `"client"`.
- Server-side enforcement occurs in [`server/proxy/proxy.go`](https://github.com/fatedier/frp/blob/main/server/proxy/proxy.go), limiting server-to-client traffic when mode is `"server"`.
- The implementation uses `golang.org/x/time/rate` to wrap connections with token bucket limiters, providing smooth traffic shaping.
- End-to-end test coverage exists in [`test/e2e/v1/features/bandwidth_limit.go`](https://github.com/fatedier/frp/blob/main/test/e2e/v1/features/bandwidth_limit.go) to 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`](https://github.com/fatedier/frp/blob/main/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`](https://github.com/fatedier/frp/blob/main/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.