For a while I'd wanted a way to control my home machines without depending on AnyDesk, which now asks for an account just to connect, or TeamViewer, which kept deciding my personal use was "commercial" and locking me out. Nothing out there quite fit what I wanted, so over the last few months I built SelfDesk.
Repo (MIT): https://github.com/Viniciusap/selfdesk
How it works
The idea is pretty simple. You run a small broker on any Linux box and your Windows machines connect outbound to it. A Raspberry Pi handles it without trouble. Nothing listens for inbound connections, there's no third-party cloud in the middle, and nothing phones home. It all stays on your own network.
SENDER (C#/.NET) BROKER (Node.js) RECEIVER (C#/WPF)
capture + encode ──TLS──▶ authenticated relay ◀──TLS── renders + input
inject input (never decodes video) picks the sender
The broker is basically a dumb authenticated pipe. It routes bytes by peer_id and never decodes the video, so adding a second machine is pure config, no code changes.
Security
This was the part I cared about most:
- TLS 1.3 everywhere, with a LAN-local CA. No public CA, no plaintext fallback.
- HMAC-SHA256 challenge-response auth, so the shared secret never actually crosses the wire.
- Zero inbound ports on the Windows machines. Outbound only.
It's built for trusted LANs, not direct internet exposure. If you need access from outside, put the broker behind a VPN or a tunnel.
What it does today
- Screen capture and full remote control (mouse, keyboard, scroll)
- Clipboard sync both ways
- Drag-and-drop file transfer with a progress bar
- Wake-on-LAN straight from the viewer
- Hardware H.264 (Quick Sync or NVENC) if you have an Intel or Nvidia GPU
- Several machines from one viewer, switch between them with a click
Setup
Setup is two steps per machine: the install one-liner pulls and unpacks the latest release, then a bootstrap generates the .env, the SHARED_SECRET and the TLS certificates. That same one-liner is also the updater — run it again any time and it grabs the newest build while preserving your existing .env and certs. On a fresh machine it doesn't start anything on its own; it prints the bootstrap step for you to run. Do the broker first, since it mints the secret and the CA the others pin to, and copy its ca-cert.pem onto the sender and viewer before bootstrapping them.
Broker — Linux, WSL or Git Bash:
curl -fsSL https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-broker.sh | bash
cd ~/selfdesk
./scripts/bootstrap.sh broker
sudo ufw allow from <YOUR_SUBNET>/24 to any port 7000 proto tcp
node dist/index.js
On a pure Windows broker (no bash), use the PowerShell installer instead:
irm https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-broker.ps1 | iex
Sender — the machine you want to control (Windows, PowerShell):
irm https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-sender.ps1 | iex
Viewer — the machine you sit at (Windows, PowerShell):
irm https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-viewer.ps1 | iex
Bootstrap walks you through each value and writes the .env files, so you don't normally edit them by hand. Here's what each one ends up holding:
# broker/.env
ROLE=broker
SHARED_SECRET=<generated here — paste into the other two>
LISTEN_PORT=7000
ALLOWED_SENDERS=laptop-01,laptop-02
TLS_CERT_PATH=certs/server-cert.pem
TLS_KEY_PATH=certs/server-key.pem
LOG_LEVEL=info
# sender/.env
ROLE=sender
SHARED_SECRET=<same as broker>
SENDER_ID=laptop-01 # must be listed in ALLOWED_SENDERS
BROKER_HOST=192.168.1.10
BROKER_PORT=7000
TLS_CA_PATH=certs/ca-cert.pem
ENCODER=jpeg # or qsv (Intel) / nvenc (Nvidia)
TARGET_FPS=30
JPEG_QUALITY=75
# viewer/.env
ROLE=receiver
SHARED_SECRET=<same as broker>
BROKER_HOST=192.168.1.10
BROKER_PORT=7000
TLS_CA_PATH=certs/ca-cert.pem
The only two rules to keep in mind: SHARED_SECRET has to be identical on all three machines, and each SENDER_ID has to match an entry in the broker's ALLOWED_SENDERS. Building from source instead of binaries is documented in the README.
I could use some help
It's only been public for about a week, so it's early. The core runs well on my own setup, but I'm sure there are rough edges I haven't hit yet, and right now it's just me working on it. There's plenty on the list: more testing across different hardware and GPUs, codec work, docs, packaging, and one of the bigger things I want to tackle next is macOS support, since today the sender and viewer are Windows-only.
If self-hosting, or lower-level .NET and networking, is your thing, I'd really appreciate contributors. The codebase, comments, tests and docs are all in English now, so it's approachable to dig into. I've opened a few issues to get started — there's a good first issue if you want something small, and the bigger pieces like a unified setup command and macOS support are tagged Enhancement. PRs and feedback on the setup experience are just as welcome.

Top comments (0)