Dev-first, self-hosted remote access for your LAN.
An open-source alternative to AnyDesk and TeamViewer — no third-party cloud, no exposed RDP, no inbound ports on controlled machines.
Scope: designed for LAN / trusted networks. Not audited for direct internet exposure. For remote access over the internet, place the broker behind a VPN or tunnel.
The same command installs or updates — your .env and certificates are always preserved.
# Broker — Linux, WSL, Git Bash (auto-detects platform)
curl -fsSL https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-broker.sh | bashWindows PowerShell (no bash):
irm https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-broker.ps1 | iex
# Sender — Windows (run as Administrator)
irm https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-sender.ps1 | iex
# Viewer — Windows
irm https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-viewer.ps1 | iexYou run a small broker on any Linux box (a Raspberry Pi handles it fine — ARM64 build coming). Your Windows machines connect outbound to it — nothing listens for inbound connections, no third-party cloud, nothing phones home.
- Screen capture and remote control — mouse, keyboard, scroll wheel
- Clipboard sync — copy on one machine, paste on the other, bidirectional
- File transfer — drag files onto the video surface, progress bar included
- Wake-on-LAN — wake offline machines from the viewer sidebar
- Hardware H.264 — Quick Sync (Intel) or NVENC (NVIDIA) via FFmpeg, selectable by
.env - Multiple senders — control several machines from one viewer, switch with a click
- Automatic reconnect — exponential backoff on broker restart or network hiccup
Setup order: broker first, then sender, then viewer. The broker generates the SHARED_SECRET and ca-cert.pem that the other machines need.
Linux (recommended)
curl -fsSL https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-broker.sh | bash
cd ~/selfdesk
./scripts/bootstrap.sh brokerNote the printed SHARED_SECRET. Then open the firewall and start:
sudo ufw allow from <YOUR_SUBNET>/24 to any port <LISTEN_PORT> proto tcp
node dist/index.jsWindows
irm https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-broker.ps1 | iex
cd $env:USERPROFILE\selfdesk-broker
powershell -File scripts\bootstrap.ps1 -Role broker
node dist\index.jsAfter the broker starts, copy certs/ca-cert.pem to each Windows machine — senders and viewers need it to verify the broker's TLS certificate.
irm https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-sender.ps1 | iex
# Copy ca-cert.pem from the broker into C:\tools\selfdesk-sender\, then:
cd C:\tools\selfdesk-sender
powershell -File scripts\bootstrap.ps1 -Role sender
# → prompts for broker host, SHARED_SECRET, SENDER_ID, encoder (jpeg / qsv / nvenc)
.\SelfDesk.Sender.exeirm https://raw.githubusercontent.com/Viniciusap/selfdesk/master/scripts/install-viewer.ps1 | iex
# Copy ca-cert.pem from the broker into C:\tools\selfdesk-viewer\, then:
cd C:\tools\selfdesk-viewer
powershell -File scripts\bootstrap.ps1 -Role receiver
# → prompts for broker host and SHARED_SECRET
.\SelfDesk.Viewer.exeExpand
git clone https://github.com/Viniciusap/selfdesk.git
cd selfdeskBroker (Linux)
./scripts/install.sh broker # installs Node.js LTS if missing, compiles
./scripts/bootstrap.sh broker # generates .env, SHARED_SECRET, certs/
sudo ufw allow from <YOUR_SUBNET>/24 to any port <LISTEN_PORT> proto tcp
cd broker && npm startSender (Windows)
.\scripts\install.ps1 -Role sender # installs .NET 10 SDK if missing, compiles
.\scripts\bootstrap.ps1 -Role sender
cd sender && dotnet runViewer (Windows)
.\scripts\install.ps1 -Role receiver
.\scripts\bootstrap.ps1 -Role receiver
cd viewer && dotnet run SENDER (C#/.NET) BROKER (Node.js) VIEWER (C#/WPF)
┌─────────────────┐ ┌──────────────────────┐ ┌─────────────────┐
│ Screen capture │ │ Authenticates conns │ │ Renders stream │
│ Encode (JPEG / │──TLS──▶ │ Routes by peer_id │◀TLS─│ Captures input │
│ H264) │outbound │ Never decodes video │outbd│ Picks sender │
│ Inject input │ └──────────────────────┘ └────────┬────────┘
└────────▲────────┘ │
└──────────────── INPUT_EVENT ────────────────────────────┘
The broker is a dumb authenticated pipe: it routes bytes by peer_id and never decodes video. Adding a second sender is pure config — no code changes.
- TLS 1.3 on every connection with a LAN-local CA (no public CA dependency). Clients pin the CA via
TLS_CA_PATH. - HMAC-SHA256 challenge-response —
SHARED_SECRETnever travels over the wire. - Zero inbound ports on Windows machines — outbound connections to the broker only.
- No secrets committed —
.env, keys, and certificates are in.gitignore.
Found a vulnerability? Open an issue or email vinicius.ap48@gmail.com.
Bootstrap generates the .env files for you — you rarely need to edit them by hand. The broker bootstrap prints the SHARED_SECRET for you to paste into the sender and viewer .env files.
| Variable | broker | sender | viewer | Description |
|---|---|---|---|---|
ROLE |
✓ | ✓ | ✓ | broker | sender | receiver |
SHARED_SECRET |
✓ | ✓ | ✓ | Identical on all three; generated at the broker |
LISTEN_PORT |
✓ | TLS listen port | ||
ALLOWED_SENDERS |
✓ | Comma-separated list of permitted SENDER_IDs |
||
TLS_CERT_PATH |
✓ | Path to server-cert.pem |
||
TLS_KEY_PATH |
✓ | Path to server-key.pem |
||
LOG_LEVEL |
✓ | debug | info | warn | error |
||
SENDER_ID |
✓ | Unique identifier (must be in ALLOWED_SENDERS) |
||
BROKER_HOST |
✓ | ✓ | Broker IP or hostname | |
BROKER_PORT |
✓ | ✓ | Broker port | |
TLS_CA_PATH |
✓ | ✓ | Path to ca-cert.pem (CA pinning) |
|
ENCODER |
✓ | jpeg | qsv | nvenc |
||
TARGET_FPS |
✓ | Capture FPS (default: 30) |
||
JPEG_QUALITY |
✓ | JPEG quality 1–100 (default: 75) |
- On the new machine, run
install-sender.ps1, copyca-cert.pem, run bootstrap with a uniqueSENDER_ID(e.g.laptop-02). - On the broker, add the new ID to
ALLOWED_SENDERS(e.g.laptop-01,laptop-02) and restart.
The viewer automatically shows the new sender in the list. No code changes.
selfdesk/
├── .github/workflows/
│ ├── ci.yml # broker tests (Ubuntu) + .NET build+tests (Windows)
│ └── release.yml # builds release zips/tarballs on version tags
├── scripts/
│ ├── install-broker.sh # broker install/update — Linux/WSL/Git Bash
│ ├── install-broker.ps1 # broker install/update — Windows PowerShell
│ ├── install-sender.ps1 # sender install/update — Windows
│ ├── install-viewer.ps1 # viewer install/update — Windows
│ ├── bootstrap.sh # generates .env + TLS certs (Linux)
│ └── bootstrap.ps1 # generates .env + TLS certs (Windows)
├── broker/ # Node.js + TypeScript — authenticated relay
├── sender/ # C# / .NET 10 — capture + encode + inject input
├── viewer/ # C# / WPF / .NET 10 — render stream + capture input
├── shared/
│ ├── protocol/ # protocol.ts — authoritative message type constants
│ └── dotnet/ # MessageType.cs + WireProtocol.cs — C# mirror
└── selfdesk.slnx # .NET solution (sender + viewer + tests)
All core features are implemented. What's open:
| Area | Issues |
|---|---|
| Platform | macOS support, Linux sender, ARM64 broker build |
| Distribution | Docker image, Web viewer |
| UX | Multi-monitor switching, Remote cursor shape, Ctrl+Alt+Del |
| Protocol | Clipboard images, Mic passthrough |
| Ops | Prometheus metrics, Log rotation |
See all open issues here.
See CONTRIBUTING.md for conventions, test commands, and project structure details.
Good entry points: good first issue · help wanted
Distributed under the MIT License. See LICENSE.
SelfDesk is intended for machines you own or have explicit authorization to access.
