# TCP Forwarding (https://portunus.bybee.dev/en/docs/overview/concepts/tcp-forwarding)



> **How to set it up:** [Standalone (TOML)](/en/docs/standalone/forwarding-rules#tcp-forwarding) · [Server + Client (operator)](/en/docs/server-client/forwarding-rules#tcp-forwarding)

TCP forwarding is the simplest rule type: accept a connection, open one
to the target, and copy bytes both ways until either side closes. SNI
routing and PROXY protocol build on this same TCP path; UDP forwarding
is the datagram equivalent.

## How it works [#how-it-works]

Each TCP rule runs a single `accept` loop on the client. For every
accepted connection the client opens one upstream `TcpStream::connect`
to the configured target and runs a bidirectional byte copy until either
side closes.

There is **no userspace buffering** beyond the kernel's send/recv
windows. The forwarder is a pure L4 byte passthrough — TLS sessions,
HTTP requests, and arbitrary protocols pass through unmodified.

On Linux, connections without a bandwidth cap take the `splice(2)`
fast path (zero-copy through the kernel). Rate-limited connections fall
back to a userspace copy loop. The listener binds with `SO_REUSEADDR`,
so a fast process restart (e.g. `docker restart`) rebinds immediately
instead of failing with `port_in_use` while a prior socket sits in
`TIME_WAIT`.
