remote-exec-server

# πŸš€ Remote Exec Server & Client ![License](https://img.shields.io/badge/License-MIT-blue.svg) ![Python](https://img.shields.io/badge/Python-3.8%2B-green.svg) ![GitHub stars](https://img.shields.io/github/stars/foxhackerzdevs/remote-exec-server?style=social) ![GitHub forks](https://img.shields.io/github/forks/foxhackerzdevs/remote-exec-server?style=social) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/foxhackerzdevs/remote-exec-server?label=release&color=orange) ![GitHub all releases](https://img.shields.io/github/downloads/foxhackerzdevs/remote-exec-server/total?label=downloads&color=blue) **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](#overview) β€’ [Installation](#installation) β€’ [Usage](#usage) β€’ [Security Considerations](#security-considerations) β€’ [License](#license)

πŸ“– Table of Contents


Overview

Remote Exec Server & Client is a minimal remote command execution framework written entirely with the Python standard library.

The project consists of:

The design is intentionally lightweight, dependency-free, and easy to deploy.


🌱 Project Inspiration

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:

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.


Features


Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Client    β”‚
β”‚  (symlink)  β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
       β”‚ HTTP POST
       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Server    β”‚
β”‚ server.py   β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
       β”‚
       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ subprocess  β”‚
β”‚ execution   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚
       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Output    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Visual Diagram

BusyBox-style Remote Exec Diagram


Requirements

No external dependencies are required.


⚑ Quick Start

Start the server:

python server.py

Create a command symlink:

ln -s client.py gp

Execute a remote command:

echo "print(nextprime(100))" | ./gp -q

Installation

Server Setup

Copy server.py to the machine that will execute commands.

Run:

python server.py

Default listening address:

0.0.0.0:8000

Client Setup

Edit the server address:

host = "SERVER_IP:8000"

Make executable:

chmod +x client.py

Place 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/node

Each symlink name becomes the command executed remotely.


Configuration

Client

Set the server host:

host = "192.168.56.1:8000"

TLS, built in as of v1.4.0. Set environment variables before running the client:

REMOTE_EXEC_TLS=1 python client.py

For self-signed certificates (typical for local/dev deployments), also skip verification:

REMOTE_EXEC_TLS=1 REMOTE_EXEC_TLS_INSECURE=1 python client.py

REMOTE_EXEC_TLS_INSECURE disables certificate verification entirely β€” never set it when connecting over an untrusted network, only for local testing with a self-signed cert you generated yourself.


Server

Bind only to localhost:

HTTPServer(("127.0.0.1", 8000), MyHandler)

Change port:

HTTPServer(("0.0.0.0", 9000), MyHandler)

TLS, built in as of v1.4.0. Set REMOTE_EXEC_TLS_CERT and REMOTE_EXEC_TLS_KEY to the paths of a PEM certificate and private key:

REMOTE_EXEC_TLS_CERT=cert.pem REMOTE_EXEC_TLS_KEY=key.pem python server.py

If either is unset, the server runs in plain HTTP (the original default behavior).

Generating a self-signed certificate for local testing:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost"

For real deployments, use a certificate from a trusted CA (e.g. Let’s Encrypt) instead of a self-signed one, and omit REMOTE_EXEC_TLS_INSECURE on the client.


Usage

Basic Execution

command_name [arguments]

With Standard Input

echo "input data" | command_name [arguments]
ln -s client.py python
ln -s client.py node
ln -s client.py gp

The invoked name determines the command sent to the server.


Protocol

The communication protocol is intentionally simple.

Request

POST /python script.py arg1 arg2 HTTP/1.1
Host: server:8000
Content-Type: text/plain

Request body:

stdin data goes here

Server Processing

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 subprocess

# stdout and stderr are read by two concurrent threads feeding a shared
# queue, so neither stream can block or lose data while waiting on the other

Output 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. stdout and stderr are captured concurrently by separate reader threads, so stderr output is never lost and can’t deadlock the subprocess by filling its pipe buffer.


Response

The response uses Transfer-Encoding: chunked. Each line 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.

stdout lines are streamed as-is. stderr lines are streamed live too, prefixed with [stderr] so they’re distinguishable from stdout in the client’s terminal:

stdout line 1
[stderr] warning: something noteworthy
stdout line 2

Both streams are forwarded regardless of the process’s exit code β€” not just on failure.


Examples

Remote PARI/GP

echo "print(nextprime(100))" | gp -q

Remote Python

echo "print('Hello World')" | python

Remote Node.js

echo "console.log('hello from node')" | node

Pass Arguments

echo "hello" | python script.py arg1 arg2

Security Considerations

This project provides remote command execution capability and should be treated accordingly.

Risks

Command Whitelisting

Built in as of v1.3.0. Set the REMOTE_EXEC_ALLOWED environment variable to a comma-separated list of allowed command names before starting the server:

REMOTE_EXEC_ALLOWED="gp,python,node" python server.py

If unset or empty, all commands are allowed (the original default behavior) β€” setting this is strongly recommended for any network-exposed deployment. Disallowed commands receive a 403 Forbidden response.

Network Restrictions

Authentication

Implement one or more of:

Isolation

Run commands:

Encryption

Built in as of v1.4.0. Set REMOTE_EXEC_TLS_CERT / REMOTE_EXEC_TLS_KEY on the server and REMOTE_EXEC_TLS=1 on the client β€” see Configuration. Use HTTPS/TLS whenever traffic crosses an untrusted network; a self-signed certificate is fine for local testing, but use a CA-issued certificate for real deployments.


Troubleshooting

Connection Refused

Verify:

python server.py

Check:


Command Not Found

Verify the executable exists:

which python
which node
which gp

Empty Output

Check:


Wrong Host

Verify:

host = "SERVER_IP:8000"

Project Structure

.
β”œβ”€β”€ client.py
β”œβ”€β”€ server.py
β”œβ”€β”€ README.md
β”œβ”€β”€ LICENSE
β”œβ”€β”€ CONTRIBUTING.md
└── docs/
    └── diagram.png

Limitations

Current implementation intentionally remains minimal.


Future Improvements


Contributing

Contributions are welcome.

Potential contribution areas:

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.


License

SPDX-License-Identifier: MIT

This project is licensed under the MIT License β€” see the repository LICENSE file for the full text:

LICENSE


πŸ”— See also