Lightweight Python-based remote command execution system
One client script, multiple symlinks, BusyBox-style.
⚠️ WARNING
This software executes commands received over HTTP.
Never expose it directly to the public Internet without authentication, encryption, access controls, and proper isolation.
Overview • Installation • Usage • Security Considerations • License
- Overview
- Features
- Architecture
- Requirements
- Quick Start
- Installation
- Configuration
- Usage
- Protocol
- Examples
- Security Considerations
- Troubleshooting
- Project Structure
- Limitations
- Future Improvements
- Contributing
- License
Remote Exec Server & Client is a minimal remote command execution framework written entirely with the Python standard library.
The project consists of:
- server.py — receives HTTP requests and executes commands locally.
- client.py — forwards command invocations and standard input to the server.
- BusyBox-style symlink support — one client script can act as many commands depending on the name it is invoked under.
The design is intentionally lightweight, dependency-free, and easy to deploy.
The idea for Remote Exec Server & Client grew out of work on pari-gp-scripts, a collection of scripts for the PARI/GP number theory system.
While developing those scripts, I experimented with:
- Symlink wrappers — one script acting as multiple commands, BusyBox‑style.
- Lightweight tooling — keeping dependencies minimal and relying on the standard library.
- Command forwarding — piping input into
gpand other interpreters for quick execution.
These patterns sparked the realization that the same approach could be generalized: instead of just wrapping gp locally, why not design a framework where one client script can forward commands to a server over HTTP?
Thus, Remote Exec Server & Client was born — a minimal, dependency‑free system for remote command execution, inspired by the simplicity and flexibility of the PARI/GP scripting workflow.
- HTTP-based command forwarding
- Standard input (stdin) forwarding
- Command-line argument support
- Real-time output streaming (chunked transfer encoding) — live progress bars and interactive output display correctly
- BusyBox-style symlink invocation
- Works with any executable installed on the server
- No third-party dependencies
- Cross-platform Python implementation
- Minimal setup and deployment
┌─────────────┐
│ Client │
│ (symlink) │
└──────┬──────┘
│ HTTP POST
▼
┌─────────────┐
│ Server │
│ server.py │
└──────┬──────┘
│
▼
┌─────────────┐
│ subprocess │
│ execution │
└─────────────┘
│
▼
┌─────────────┐
│ Output │
└─────────────┘
- Python 3.8+
- Network connectivity between client and server
No external dependencies are required.
Start the server:
python server.pyCreate a command symlink:
ln -s client.py gpExecute a remote command:
echo "print(nextprime(100))" | ./gp -qCopy server.py to the machine that will execute commands.
Run:
python server.pyDefault listening address:
0.0.0.0:8000
Edit the server address:
host = "SERVER_IP:8000"Make executable:
chmod +x client.pyPlace in your PATH:
cp client.py ~/bin/Create command aliases:
ln -s ~/bin/client.py ~/bin/gp
ln -s ~/bin/client.py ~/bin/python
ln -s ~/bin/client.py ~/bin/nodeEach symlink name becomes the command executed remotely.
Set the server host:
host = "192.168.56.1:8000"To enable HTTPS:
http.client.HTTPSConnectioninstead of:
http.client.HTTPConnectionThe server must also be configured for TLS.
Bind only to localhost:
HTTPServer(("127.0.0.1", 8000), MyHandler)Change port:
HTTPServer(("0.0.0.0", 9000), MyHandler)command_name [arguments]echo "input data" | command_name [arguments]ln -s client.py python
ln -s client.py node
ln -s client.py gpThe invoked name determines the command sent to the server.
The communication protocol is intentionally simple.
POST /python script.py arg1 arg2 HTTP/1.1
Host: server:8000
Content-Type: text/plainRequest body:
stdin data goes here
cmd_parts = shlex.split(raw_path)
process = subprocess.Popen(cmd_parts, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
process.stdin.write(stdin_data)
process.stdin.close() # signal EOF to the subprocessOutput is streamed to the client line by line as the subprocess produces it, using HTTP chunked transfer encoding — rather than waiting for the process to exit and sending the full output at once.
The response uses Transfer-Encoding: chunked. Each line of stdout is sent as a separate chunk as soon as it's produced, so long-running or interactive commands (e.g. progress bars) display in real time on the client rather than appearing all at once at the end.
Success:
stdout output (streamed line by line)
Failure (appended as a final chunk if the process exits non-zero):
Error:
stderr output
echo "print(nextprime(100))" | gp -qecho "print('Hello World')" | pythonecho "console.log('hello from node')" | nodeecho "hello" | python script.py arg1 arg2This project provides remote command execution capability and should be treated accordingly.
- Arbitrary command execution
- Remote code execution (RCE)
- Unauthorized access
- Resource exhaustion
- Data exposure
ALLOWED = {"python", "gp", "node"}
if cmd_parts[0] not in ALLOWED:
output = f"Command not allowed: {cmd_parts[0]}"
return- VPN access only
- SSH tunnels
- Firewall allowlists
- Private networks
Implement one or more of:
- API keys
- Bearer tokens
- Mutual TLS
- Basic authentication
Run commands:
- Inside Docker containers
- Inside restricted user accounts
- Inside sandboxes
Use HTTPS/TLS whenever traffic crosses untrusted networks.
Verify:
python server.pyCheck:
- Server is running
- Correct IP address
- Correct port
- Firewall configuration
Verify the executable exists:
which python
which node
which gpCheck:
- Server logs
- Command stdout/stderr behavior
- Input handling
Verify:
host = "SERVER_IP:8000".
├── client.py
├── server.py
├── README.md
├── LICENSE
├── CONTRIBUTING.md
└── docs/
└── diagram.png
Current implementation intentionally remains minimal.
- No authentication
- No TLS support by default
- No concurrency (single request handled at a time)
- No request validation
- No rate limiting
- No audit logging
- No file transfer support
- HTTPS/TLS support
- API-key authentication
- Mutual TLS
- Built-in command whitelists
- Async request handling
- Docker deployment
- Audit logging
- Request signing
- Rate limiting
- File upload/download support
Contributions are welcome.
Potential contribution areas:
- Security enhancements
- Protocol improvements
- Testing
- Documentation
- Containerization
- Performance optimization
Feel free to open issues, submit pull requests, or fork the project.
See CONTRIBUTING.md for guidelines on documentation, security, development, and the contribution flow.
SPDX-License-Identifier: MIT
This project is licensed under the MIT License — see the repository LICENSE file for the full text:
- PARI/GP Scripts —
A collection of Bash wrappers for PARI/GP number theory experiments that inspired the design of this project.
