Skip to main content

SRE Toolbox

Port Forwarder

Listen on a local TCP port and forward each connection to a remote host and port. Python 3.13 or newer; no runtime dependencies beyond the standard library.

Install

pip install lupaxa-port-forwarder
port-forwarder --help

CLI

port-forwarder 8080 remote.example.com 80
port-forwarder 8080:remote.example.com:80 5432:db.internal:5432
port-forwarder 8080:[::1]:80
port-forwarder 8080 remote.example.com 80 --bind 0.0.0.0 --allow 10.0.0.0/8
port-forwarder 8080 remote.example.com 80 --max-connections 8 --idle-timeout 60
port-forwarder 8080 remote.example.com 80 --timeout 2.5 --quiet
python -m lupaxa.port_forwarder --version

Pass one LOCAL HOST REMOTE triple, or one or more LOCAL:HOST:REMOTE mappings. IPv6 remotes use brackets. Shared flags apply to every mapping. Each accepted client opens a new remote connection and relays bytes both ways until either side closes. A half-close on one side leaves the other direction open so the reply can still arrive.

By default the listener binds 127.0.0.1. Use --bind 0.0.0.0 when other hosts must connect, and --allow (repeatable IP or CIDR) to limit who may. IPv4-mapped IPv6 sources are compared as IPv4 against --allow. --timeout bounds the remote connect; it is not the idle timer. --max-connections and --idle-timeout cap concurrent sessions and quiet ones. Listen and remote ports must be 1–65535.

The process stays in the foreground. Ctrl+C or SIGTERM closes the listen sockets, waits for in-flight relays, and exits 0. A bind failure or bad arguments print to stderr and exit 1.

Flag Default Description
--bind 127.0.0.1 Local address to listen on
--timeout 10 Remote connect timeout in seconds
--max-connections unlimited Max concurrent sessions per listener
--allow off Repeatable source IP or CIDR allowlist
--idle-timeout off Close a session after this many idle seconds
--verbose off Log debug detail
--quiet off Log warnings and errors only
--version — Print the package version and exit

--verbose and --quiet cannot be combined. --timeout and --idle-timeout must be greater than 0 when set. --max-connections must be at least 1 when set.

Examples

Forward a Local HTTP Port

port-forwarder 8080 remote.example.com 80

Then open 127.0.0.1:8080 in a browser or with curl.

Reach an Internal Database from This Machine

port-forwarder 5432 db.internal 5432

Connect your local client to 127.0.0.1:5432.

Forward Two Ports in One Process

port-forwarder 8080:remote.example.com:80 5432:db.internal:5432

Forward to an IPv6 Remote

port-forwarder 8080:[::1]:80

Share the Listener on the LAN

port-forwarder 8080 remote.example.com 80 --bind 0.0.0.0 --allow 10.0.0.0/8

Other hosts in 10.0.0.0/8 can now connect to this machine's address on port 8080. Repeat --allow for more networks.

Cap Sessions and Close Idle Ones

port-forwarder 8080 remote.example.com 80 --max-connections 8 --idle-timeout 60

Bound the Remote Connect

port-forwarder 8080 remote.example.com 80 --timeout 2.5 --quiet

Run as a Module

python -m lupaxa.port_forwarder --version

Library

from lupaxa.port_forwarder import PortForwarder, PortForwarderGroup

with PortForwarder(8080, "remote.example.com", 80) as forwarder:
    forwarder.start()

start() blocks. Call stop() from another thread, or leave the with block. Several mappings can share a PortForwarderGroup:

http = PortForwarder(8080, "remote.example.com", 80, bind_host="127.0.0.1")
db = PortForwarder(5432, "db.internal", 5432, max_connections=4)
with PortForwarderGroup([http, db]) as group:
    try:
        group.start()
    except KeyboardInterrupt:
        group.stop()

local_port=0 asks the OS for an ephemeral port. Read bound_port after on_ready fires:

from threading import Event, Thread

from lupaxa.port_forwarder import PortForwarder

ready = Event()
with PortForwarder(0, "127.0.0.1", 9000, connect_timeout=2.5) as forwarder:
    thread = Thread(target=forwarder.start, kwargs={"on_ready": ready.set}, daemon=True)
    thread.start()
    ready.wait()
    print(forwarder.bound_port)

Development

make init
make python-install-dev
make python-check
The Lupaxa Project Footer

Metadata

Release files for lupaxa-port-forwarder 0.1.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lupaxa-port-forwarder 0.1.5
File Size Uploaded
lupaxa_port_forwarder-0.1.5.tar.gz 11.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lupaxa-port-forwarder 0.1.5
File Interpreter ABI Platform
lupaxa_port_forwarder-0.1.5-py3-none-any.whl Python 3 none any Details

Total release size: 24.8 kB

Release files / lupaxa_port_forwarder-0.1.5.tar.gz

Download URL lupaxa_port_forwarder-0.1.5.tar.gz
Size 11.0 kB
Tags Source
SHA-256 checksum
How to use checksums
bfe7ed9c06986e7976214383a7b0e6b5aaed111c633a37974da8354b57ba4d56
BLAKE2b-256 checksum
How to use checksums
fb3cd5ee62db289c328571a6dd33d040dc7e89402034243a9480a0641707a513
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / lupaxa_port_forwarder-0.1.5-py3-none-any.whl

Download URL lupaxa_port_forwarder-0.1.5-py3-none-any.whl
Size 13.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bd9fe74933e63444a6dbe6a41d12898f2236b4a09156aecaedd14be7e877fde5
BLAKE2b-256 checksum
How to use checksums
b088e86440e5d983cb5381e0ca9064d5650f0026b1f30ccbc930a1c917896515
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.5 This release

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page