DEV Community

Cover image for I got tired of AnyDesk and TeamViewer so I built my own remote desktop
Vinicius Apolinário
Vinicius Apolinário

Posted on

I got tired of AnyDesk and TeamViewer so I built my own remote desktop

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

SelfDesk demo

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Sender — the machine you want to control (Windows, PowerShell):

irm https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-sender.ps1 | iex
Enter fullscreen mode Exit fullscreen mode

Viewer — the machine you sit at (Windows, PowerShell):

irm https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-viewer.ps1 | iex
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
# 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
Enter fullscreen mode Exit fullscreen mode
# 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
Enter fullscreen mode Exit fullscreen mode

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.

GitHub: https://github.com/Viniciusap/selfdesk

Top comments (0)