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)
| File | Size | Uploaded | |
|---|---|---|---|
| py_simple_nat_tunnel-0.1.6.tar.gz | 26.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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
|