Skip to main content

py-frp

A small Python TCP reverse tunnel inspired by the public-server/private-client model used by frp and rathole. The current scope is TCP port forwarding with a server, a client, a practical subset of frp TOML/INI configs, and a practical subset of rathole TOML configs.

Installation

Install from PyPI:

pip install py-simple-nat-tunnel

Install from source:

pip install .

Install in editable development mode:

pip install -e .

Installed commands:

py-frp --version
py-frp server -c examples/frps.toml
py-frp client -c examples/frpc.toml
py-frps -c examples/frps.toml
py-frpc -c examples/frpc.toml

On Windows, if the scripts directory is not on PATH, use the module entry point directly:

python -m py_frp server -c examples/frps.toml
python -m py_frp client -c examples/frpc.toml

Quick Start

On the public server:

py-frp server -c examples/frps.toml

On the private client:

py-frp client -c examples/frpc.toml

The default examples/frpc.toml exposes the client's 127.0.0.1:22 on the server's 0.0.0.0:6000. Connect from outside with:

ssh -p 6000 user@your-server

Configless Port Pool Mode

The server can run without a config file by specifying a control port and a public port pool:

py-frp server --bind-port 7000 --port-pool 6000-6009

--port-pool can be repeated. The server merges all ranges and single ports; a-b means the inclusive range from a through b, and a by itself adds one port:

py-frp server --bind-port 7000 --port-pool 6000-6009 --port-pool 7000 --port-pool 7100-7102

At startup, the server prints one shared random token to stdout. Tokens use only unambiguous letters and digits, excluding I, O, 0, 1, and l. Give that one token to all clients that are allowed to use the pool.

Clients only need the server address and the shared token. The local target defaults to 127.0.0.1:22:

py-frp client --server your-server:7000 --token TOKEN_FROM_SERVER

After registration, the client prints the assigned remote port to stdout:

6003

If the local target is not SSH, set it explicitly:

py-frp client --server your-server:7000 --token TOKEN_FROM_SERVER --local 127.0.0.1:8080

The target does not have to run on the client itself. Any TCP address reachable from the client can be forwarded, including another device on the client's LAN. For example, this exposes 192.168.1.50:8080 through the assigned public port:

py-frp client --server your-server:7000 --token TOKEN_FROM_SERVER --local 192.168.1.50:8080

The same applies to config files. Set localIP (frp), local_ip (legacy frp INI), or the host part of local_addr (rathole) to the LAN device address. The client machine must be able to connect to that address, and the target device's firewall must allow the connection from the client machine.

Multiple clients can use the same shared token at the same time. Each client is assigned one currently unused port from the pool, using the lowest available port first. If the pool is exhausted, the server rejects the new client and the client logs a single insufficient-resource error instead of disconnecting an existing client.

frp Config Subset

Server frps.toml:

bindPort = 7000

[auth]
token = "change-me"

Client frpc.toml:

serverAddr = "your-server"
serverPort = 7000

[auth]
token = "change-me"

[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000

To forward a service on another LAN device, use (for example) localIP = "192.168.1.50" with that device's service port.

Legacy frp INI [common] and TCP proxy sections are also supported:

[common]
server_addr = your-server
server_port = 7000
token = change-me

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000

rathole Config Subset

Server:

[server]
bind_addr = "0.0.0.0:2333"
default_token = "change-me"

[server.services.ssh]
bind_addr = "0.0.0.0:6000"

Client:

[client]
remote_addr = "your-server:2333"
default_token = "change-me"

[client.services.ssh]
local_addr = "127.0.0.1:22"

Privilege Elevation

When the server needs to bind a privileged listen port below 1024, it tries to relaunch once through py-admin-launch by default. You can also control this explicitly:

py-frp server -c frps.toml --elevate
py-frp server -c frps.toml --no-auto-elevate

The relaunched command receives an internal marker so elevation is attempted at most once.

Current Scope

Supported:

  • TCP reverse port forwarding
  • Multiple services/proxies
  • Token authentication
  • Configless shared-token port pool mode
  • Common frp TOML and legacy INI TCP configs
  • Common rathole TOML TCP configs
  • One-command installation through pip install
  • Console scripts

Not currently supported:

  • UDP
  • HTTP/HTTPS virtual hosts
  • frp plugins, load balancing, STCP, or XTCP
  • rathole Noise/TLS encrypted transport
  • Multiplexing; each public connection opens one independent tunnel TCP

Tests

python -m unittest discover -s tests -v

Metadata

Release files for py-simple-nat-tunnel 0.1.6

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

Source distribution (sdist)

Source distribution for py-simple-nat-tunnel 0.1.6
File Size Uploaded
py_simple_nat_tunnel-0.1.6.tar.gz 26.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for py-simple-nat-tunnel 0.1.6
File Interpreter ABI Platform
py_simple_nat_tunnel-0.1.6-py3-none-any.whl Python 3 none any Details

Total release size: 49.1 kB

Release files / py_simple_nat_tunnel-0.1.6.tar.gz

Download URL py_simple_nat_tunnel-0.1.6.tar.gz
Size 26.8 kB
Tags Source
SHA-256 checksum
How to use checksums
2e1914ed449c453aebc62b56967a7f60e7bf4c739296f998250844d3cc1bc202
BLAKE2b-256 checksum
How to use checksums
d9824e6ec3abd99911cc78eef9961440473fe6f066f52dc4b5cce5b2d83cf1cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.2.1 CPython/3.13.5 Windows/11

Release files / py_simple_nat_tunnel-0.1.6-py3-none-any.whl

Download URL py_simple_nat_tunnel-0.1.6-py3-none-any.whl
Size 22.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
df92cbd9be8a4724df77c294a82e652f9290912bd0ded7a401494bebb4510368
BLAKE2b-256 checksum
How to use checksums
981fd78bb5e7997857fbc992ea354b202fa407092e0c2d0f06557f1b94080437
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.2.1 CPython/3.13.5 Windows/11

Release history Release notifications | RSS feed

0.7.0

2 release files

0.6.0

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.6 This release

2 release files

0.1.5

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