Portunus
Features

Port-range Rules

Map a contiguous listen-port window onto a same-offset target window with a single push.

Available since v0.2.0. A single rule binds many listeners atomically.

How it works

A port-range rule maps a contiguous listen-port range onto the same offset in a contiguous target-port range on a single upstream host.

Listen 30000-30050  →  upstream.local:30000-30050
                       ^ each port forwards to its same-offset target
                         (30005 → upstream.local:30005, etc.)

Range rules collapse to one row in list-rules and one row per collector in /metrics regardless of range size. Per-port detail is opt-in via --per-port.

Push a range rule

portunus-server push-rule edge-01 30000-30050 upstream.local:30000-30050
# binds 51 ports atomically

UDP works the same way:

portunus-server push-rule edge-01 30000-30050 upstream.local:30000-30050 \
  --protocol udp

Limits

The default cap is 1024 ports per range, configurable in server.toml:

# Maximum ports a single port-range rule may span.
# Each port consumes one socket (one fd) on the client.
range_rule_max_ports = 1024

Raising this above the default also requires raising LimitNOFILE on the client's systemd unit. The cap exists so an operator typo can't burst the client's RLIMIT_NOFILE.

Per-port stats

# CLI
portunus-server rule-stats <rule_id> --per-port

# HTTP
curl -H "Authorization: Bearer $PORTUNUS_OPERATOR_TOKEN" \
     'http://127.0.0.1:7080/v1/rules/<id>/stats?per_port=true'

Per-port byte counters surface only through the API/CLI on demand; they are not exported as separate Prometheus series. The Prometheus cardinality budget stays one row per rule no matter how wide the range.

Conflict handling

Range conflicts reuse the v1 port_in_use error code with the offending port named in the message:

error: activation_failed: port_in_use (port 30005 already bound)

The whole range is atomic — if any port in the requested range is unavailable, the entire rule transitions to Failed and binds nothing.

Verified

  • 100-port range push wall-clock: ~18 ms on a Linux x86_64 host.
  • Total fresh-deploy → traffic round-trip on 3 sample ports: ~0.93 s.

On this page