Traffic Shaping Reference
Traffic shaper rules limit upload and/or download throughput for matching requests.
In the management UI, choose Traffic Policy -> Traffic Shaper. Traffic shapers have a dedicated tab with a rule count, text and enabled-state filters, and compact columns for the rule, match and key, budget and scope, priority and state, and actions. They are not combined with cache rules; use the adjacent Cache tab for cache eligibility and storage.
Exact Fields And Defaults
| Setting | Default | Description |
|---|---|---|
| Name | traffic-shaper when empty | Operator label. |
| Priority | 100 in database defaults | Lower numbers are evaluated first. |
| Budget scope | per_key | per_key or per_request. |
| Protocol scope | all | Apply to all requests, WebSocket handshakes only, or requests excluding WebSocket handshakes. |
| Upload bytes per second | 0 | Request body throughput limit; 0 means unlimited. |
| Download bytes per second | 0 | Response body throughput limit; 0 means unlimited. |
| Burst bytes | 0 | Token bucket burst; defaults to the configured rate at runtime when unset. |
| Request exempt bytes | 0 | Initial request bytes sent without shaping. |
| Response exempt bytes | 0 | Initial response bytes sent without shaping. |
Validation Rules
Traffic shapers use request-only CEL match_rule rules. Empty match rules match every request. See CEL Policy Matching for variables, helper functions, builder behavior, limits, and examples.
Protocol scope is evaluated before CEL matching. All requests is the default and preserves the behavior of rules created by older versions. WebSockets only limits the rule to valid WebSocket handshake requests. Exclude WebSockets applies it to other HTTP requests. A WebSocket handshake must be a bodyless GET with Connection: upgrade, Upgrade: websocket, version 13, and a valid 16-byte Sec-WebSocket-Key; an isolated or malformed upgrade header is treated as ordinary HTTP traffic. If a syntactically valid handshake receives a non-101 response, p2pstream applies the first matching ordinary-HTTP shaper to that response so client-controlled headers cannot bypass shaping.
Route data, target data, target health, and load-balancer state are not available inside shaper match CEL. p2pstream may perform a route-only path security match before traffic shapers, but traffic shapers still run before route target selection.
Traffic-shaper path matching and path key parts use p2pstream's decoded request path. On routes that allow encoded separators for upstream compatibility, avoid shaping policy that relies on decoded slash boundaries as a security boundary.
Key parts still identify the per-key budget. They can use remote IP, host, method, path, protocol, header, cookie, and query parameter values.
For per_key shaping, REMOTE_IP is the only built-in client-IP identity source. HEADER key parts remain supported for application headers such as X-Plan, but forwarding or client-IP headers such as Forwarded, X-Forwarded-For, X-Real-IP, X-Forwarded-Host, X-Forwarded-Proto, and X-Forwarded-Port are rejected. per_request shaping ignores key parts.
Before upgrading from an older version that allowed arbitrary header key parts, inspect stored per-key shapers:
SELECT id, name, key_parts_json
FROM public_traffic_shaper_rules
WHERE lower(key_parts_json) LIKE '%forwarded%'
OR lower(key_parts_json) LIKE '%x-real-ip%'
OR lower(key_parts_json) LIKE '%client-ip%'
OR lower(key_parts_json) LIKE '%connecting-ip%';Byte rates and exempt bytes must be non-negative. Use realistic rates so operational debugging remains clear.


Runtime Effects
Traffic shapers run after WAF and rate-limit checks and before route/target forwarding. Shaping wraps streaming request and response bodies, so very small responses may finish before the limit is noticeable.
After a successful 101 Switching Protocols response, the same rule remains attached to the upgraded connection. Bytes read from the upstream WebSocket consume the download budget, and bytes written to it consume the upload budget. The proxy preserves the bidirectional stream while doing this; shaping does not replace the upgrade body with a read-only wrapper.
per_key shares buckets for matching requests with the same key. per_request creates fresh buckets for each request. Editing a rule resets its in-memory buckets.
Examples
One MiB/s public download limit:
Host pattern: files.example.com
Path prefix: /download
Budget scope: per_key
Protocol scope: all
Download bytes per second: 1048576
Upload bytes per second: 0
Response exempt bytes: 65536