Secure LAN-based remote PC control and administration
Project description
remctl
Secure, LAN-based remote PC control and administration.
remctl lets you control machines on your local network from the command line —
lock, shutdown, execute shell commands with streaming output, transfer files,
take screenshots, and check system status. All communication is authenticated
using Ed25519 keys and encrypted with AES-256-GCM.
⚠️ Intended for your own trusted LAN devices only.
remctlis not designed for Internet-facing use. Do not expose it via port forwarding or NAT.
Installation
pip install remctl
From source
# TODO: user adds PyPI API token via env var / twine config before publishing
git clone <repo-url>
cd remctl
pip install -e ".[dev]"
Quick Start (Easy Mode)
On the target machine (the node)
# First run starts a short setup wizard (name, admin, acceptance mode),
# then runs the agent in the foreground:
remctl node start
The wizard asks three things:
- Node name — a friendly name broadcast on your LAN (e.g.
livingroom-pc). - Allow admin (exec/shell) commands? — grants the
fulltier to new controllers, otherwise they getstandard(no exec). - Acceptance mode for new controllers:
auto— trust any controller that connects (easiest, least safe)ask— ask for approval on every connectionask-new— ask only the first time a controller connects (recommended)
You can re-run the wizard any time with remctl node setup, or start without it
using the stored config via remctl node start.
On the controlling machine
# Find nodes on the LAN (lists them by name)
remctl ctl scan
# Connect to one by name — this pairs it and makes it the active node
remctl ctl connect livingroom-pc
# Now run actions on the active node
remctl ctl actions list # what can I do?
remctl ctl actions status
remctl ctl actions lock
remctl ctl actions shutdown --delay 60
remctl ctl shell "whoami" # = actions exec
If you have more than one node, target a specific one with --node:
remctl ctl actions status --node bedroom-pc
remctl ctl nodes # list paired nodes + active
remctl ctl forget livingroom-pc # remove a paired node
Advanced: Manual Two-Way Pairing
If you prefer explicit key exchange (no acceptance-mode prompts), use the original flow. Both sides must still trust each other:
# Node: show its fingerprint
remctl node pair --show
remctl node start
# Controller: pair + show its own fingerprint for the node to trust
remctl ctl pair <node-ip>
remctl ctl pair-show
# Node: trust the controller's public key file
remctl node trust-controller /path/to/controller_identity.pub
Legacy per-command form (still works, defaults to the active node):
remctl ctl <target> status
remctl ctl <target> lock
remctl ctl <target> exec "whoami"
remctl ctl <target> screenshot -o screenshot.png
remctl ctl <target> push ./file.txt /remote/path/file.txt
remctl ctl <target> pull /remote/log.log ./log.log
Command Reference
| Command | Description |
|---|---|
remctl node start |
First-run wizard (if needed) then start the node agent |
remctl node setup |
Run the setup wizard (name, admin, acceptance mode) |
remctl node install-service |
Install as OS service |
remctl ctl scan |
Discover nodes on the LAN (by name) |
remctl ctl connect <name> |
Pair with a node and make it active |
remctl ctl nodes |
List paired nodes + active |
remctl ctl forget <name> |
Remove a paired node |
remctl ctl actions list |
List available actions + tiers |
remctl ctl actions <action> [--node <name>] |
Run a named action on the active node |
remctl ctl shell "<cmd>" |
Alias for actions exec |
remctl ctl discover |
Discover nodes on LAN (legacy) |
remctl ctl pair <target> |
Pair with a node (manual flow) |
remctl ctl <target> lock |
Lock the remote workstation |
remctl ctl <target> shutdown --delay 60 |
Shutdown with optional delay |
remctl ctl <target> restart |
Restart |
remctl ctl <target> sleep |
Sleep/Suspend |
remctl ctl <target> logout |
Log out current user |
remctl ctl <target> closefocused |
Close active window |
remctl ctl <target> exec <command> |
Execute shell command (streamed) |
remctl ctl <target> status |
Show system status (CPU/mem/disk/uptime) |
remctl ctl <target> screenshot -o out.png |
Capture screenshot |
remctl ctl <target> push <local> <remote> |
Push file to node |
remctl ctl <target> pull <remote> <local> |
Pull file from node |
remctl ctl <target> cancel |
Cancel pending shutdown/restart |
Security Model (Summary)
- Identity: Ed25519 keypairs generated on first run.
- Authentication: Node accepts controllers per its acceptance mode
(
auto/ask/ask-new). Default isask-new— no auto-trust unless you opt in. The manual two-waytrust-controllerflow still works. - Encryption: X25519 ECDH key exchange → AES-256-GCM, with forward secrecy.
- Replay protection: Per-message sequence numbers + 30-second timestamp window.
- Permission tiers:
observe(status/screenshot),standard(commands + files),full(includesexec). Default for new controllers:standard. - Audit log: All commands logged unredacted at
~/.remctl/audit.log.
See docs/SECURITY.md for the full threat model.
Configuration
All config files live in ~/.remctl/:
| File | Purpose |
|---|---|
identity.key |
Private key (keep secure) |
identity.pub |
Public key |
known_nodes.json |
Paired nodes (ctl side) |
known_controllers.json |
Trusted controllers (node side) |
node_config.json |
Node settings (name, bind, port, acceptance mode, tiers) |
ctl_config.json |
Controller settings (active node) |
audit.log |
Command audit log |
Platform Support
| Platform | Status |
|---|---|
| Windows | First-class |
| Linux | Second-class (best-effort) |
| macOS | Not yet implemented |
Publishing to PyPI
python -m build
twine upload dist/*
You need a PyPI API token (not your password):
- Create a free account at https://pypi.org
- Go to https://pypi.org/manage/account/token/ and generate a token scoped to
remctl - Copy
.env.exampleto.envand fill in the token, or set these env vars:
export TWINE_USERNAME=__token__
export TWINE_PASSWORD=pypi-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
See .env.example for the full list of configurable secrets. No credentials are included in the repository.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file remctl-0.1.1.tar.gz.
File metadata
- Download URL: remctl-0.1.1.tar.gz
- Upload date:
- Size: 31.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1cefc1a1fc261475171e5dfb8d518fcea0f0f765f78579f572d9063a77cb1385
|
|
| MD5 |
c0e9ba7e65b7568b5e0ec39116923788
|
|
| BLAKE2b-256 |
6b034f23ce737ce4b13d7a21915a28e6e8917847508a4ef8ff5af7f373a6d5e1
|
File details
Details for the file remctl-0.1.1-py3-none-any.whl.
File metadata
- Download URL: remctl-0.1.1-py3-none-any.whl
- Upload date:
- Size: 32.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eba9c97e5ff6df7de0ec85398197d9c08338ef4f3635ba34f380eb4e60731579
|
|
| MD5 |
c07efb252b9846b4fdb4c2b90b14b406
|
|
| BLAKE2b-256 |
36e9f26b12e9961c643593bb8014908194e03dbdc5db4f89d311dd0f0aa5baa6
|