{"id":51181155,"url":"https://github.com/blhsing/tunneldesktop","last_synced_at":"2026-06-27T07:01:29.309Z","repository":{"id":367458635,"uuid":"1280904849","full_name":"blhsing/TunnelDesktop","owner":"blhsing","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-26T04:09:08.000Z","size":49,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-26T05:23:34.137Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blhsing.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-26T03:41:21.000Z","updated_at":"2026-06-26T04:09:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/blhsing/TunnelDesktop","commit_stats":null,"previous_names":["blhsing/tunneldesktop"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/blhsing/TunnelDesktop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blhsing%2FTunnelDesktop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blhsing%2FTunnelDesktop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blhsing%2FTunnelDesktop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blhsing%2FTunnelDesktop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blhsing","download_url":"https://codeload.github.com/blhsing/TunnelDesktop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blhsing%2FTunnelDesktop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34844346,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-27T07:01:28.620Z","updated_at":"2026-06-27T07:01:29.294Z","avatar_url":"https://github.com/blhsing.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TunnelDesktop\n\nTunnelDesktop is an outbound-only RDP rendezvous tunnel for a work PC that cannot accept inbound connections. The current architecture uses an Azure App Service relay at `https://test-officialwebsite.azurewebsites.net/relay/`. The primary relay implementation is .NET, and a protocol-compatible Python/FastAPI relay is also available under `python-relay/`. The work-side Windows service and home-side apps connect out to the relay over WebSockets.\n\nConfiguration is a single shared relay room URL. For example:\n\n```text\nhttps://test-officialwebsite.azurewebsites.net/relay/workdesk\n```\n\nThe room name is the path segment after `/relay/`. The first endpoint to use a room creates it in memory, and later endpoints join the same room by using the same URL.\n\n## Table Of Contents\n\n- [How It Works](#how-it-works)\n- [Installation](#installation)\n  - [1. Deploy Azure Relay](#1-deploy-azure-relay)\n  - [2. Deploy Python Relay On OCI](#2-deploy-python-relay-on-oci)\n  - [3. Choose A Room URL](#3-choose-a-room-url)\n  - [4. Install Work Agent](#4-install-work-agent)\n  - [5. Run Home App](#5-run-home-app)\n  - [6. Run Android Home App](#6-run-android-home-app)\n- [Deliverables](#deliverables)\n  - [Azure Relay Web Service](#azure-relay-web-service)\n  - [Python Relay Web Service](#python-relay-web-service)\n  - [Work Agent](#work-agent)\n  - [Agent Configurator](#agent-configurator)\n  - [Home App](#home-app)\n  - [Android Home App](#android-home-app)\n- [Security Model](#security-model)\n- [Build Prerequisites](#build-prerequisites)\n- [Build Commands](#build-commands)\n- [URL Configuration](#url-configuration)\n- [Troubleshooting](#troubleshooting)\n  - [Agent Self-Test Fails Through Proxy](#agent-self-test-fails-through-proxy)\n  - [Home App Connects But RDP Fails](#home-app-connects-but-rdp-fails)\n  - [Azure Relay Status](#azure-relay-status)\n- [Development](#development)\n- [Repository Layout](#repository-layout)\n- [Status](#status)\n- [Current Limitations](#current-limitations)\n\n## How It Works\n\n```text\nHome PC\n  mstsc -\u003e 127.0.0.1:\u003chome app port\u003e\n        |\n        v\nclient.exe\n  friendly Windows control panel + tray icon\n  outbound WebSocket over HTTPS\n        |\n        v\nAzure App Service relay\n  dashboard: https://test-officialwebsite.azurewebsites.net/relay/workdesk\n  data:      wss://test-officialwebsite.azurewebsites.net/relay/workdesk/ws\n        |\n        v\nagent.exe Windows service\n  outbound WebSocket over HTTPS, optionally through HTTP proxy\n  per paired socket -\u003e 127.0.0.1:3389\n```\n\nThe relay groups sockets by room name. A waiting work-agent socket is paired with one home-client socket from the same room, then the relay copies binary WebSocket frames in both directions. The relay does not store credentials or generated client files.\n\nThe home app also keeps a lightweight `home-agent` presence WebSocket open while it is running. That presence socket lets the Azure dashboard and the home control panel show whether the home side is online; RDP data still flows only when the home app starts a local listener and Remote Desktop connects to it.\n\nThe Android home app follows the same model. It runs a foreground service, listens on Android loopback, and lets a separate Android RDP client connect to `127.0.0.1:\u003cport\u003e` on the phone. The phone is not a relay and does not need inbound access from the internet.\n\n## Installation\n\n### 1. Deploy Azure Relay\n\nBuild the deployable zip:\n\n```powershell\n.\\build\\build-azure-relay.ps1\n```\n\nDeploy `dist\\azure-relay\\tunneldesktop-azure-relay.zip` to the Azure App Service. Confirm WebSockets are enabled in App Service configuration.\n\nDashboard and health endpoints:\n\n```text\nhttps://test-officialwebsite.azurewebsites.net/relay/\nhttps://test-officialwebsite.azurewebsites.net/relay/\u003croom\u003e\nhttps://test-officialwebsite.azurewebsites.net/relay/health\nhttps://test-officialwebsite.azurewebsites.net/relay/status\n```\n\n### 2. Deploy Python Relay On OCI\n\nThe Python relay can also run on a small Linux VM. The current OCI deployment is:\n\n```text\nhttp://217.142.228.117/relay/b\n```\n\nIt runs as the systemd service `tunneldesktop-relay.service` under `/opt/tunneldesktop/python-relay` and listens on public HTTP port `80`. The OCI security rules must allow inbound TCP `80`, and the VM firewall must allow the `http` service.\n\nBuild the normal Python source zip and a Linux/Python 3.9 vendored zip:\n\n```powershell\npython -m pip install -r python-relay\\requirements-dev.txt\n.\\build\\build-python-relay.ps1\n```\n\nArtifacts:\n\n```text\ndist\\python-relay\\tunneldesktop-python-relay.zip\ndist\\python-relay\\tunneldesktop-python-relay-linux-cp39-vendored.zip\n```\n\nThe vendored zip is for Oracle Linux 9's system Python 3.9 and avoids running `pip` on a low-memory Always Free VM. Deploy by extracting the vendored zip to `/opt/tunneldesktop/python-relay`, setting `PYTHONPATH=/opt/tunneldesktop/python-relay/vendor`, and running:\n\n```text\n/usr/bin/python3 -m uvicorn app:app --host 0.0.0.0 --port 80 --proxy-headers\n```\n\n### 3. Choose A Room URL\n\nPick a room name that is easy for you to remember but not obvious to outsiders:\n\n```text\nhttps://test-officialwebsite.azurewebsites.net/relay/workdesk\n```\n\nFor the OCI relay, the equivalent room URL is:\n\n```text\nhttp://217.142.228.117/relay/workdesk\n```\n\nUse exactly the same URL on the work agent and the home app.\n\n### 4. Install Work Agent\n\nRun the configurator:\n\n```text\nagent-configurator-windows-amd64.exe\n```\n\nIt defaults to `D:\\TunnelDesktop\\Agent` when `D:` exists. Select `agent-windows-amd64.exe`, enter the relay room URL, then click `Install / Update`. The configurator copies the work agent as `agent.exe`, installs or updates the automatic `TunnelDesktopAgent` Windows service, configures SCM restart recovery, and starts the service.\n\nCommand-line install is also supported:\n\n```powershell\n.\\agent-windows-amd64.exe -install -relay-url https://test-officialwebsite.azurewebsites.net/relay/workdesk\n```\n\nUseful checks:\n\n```powershell\n.\\agent-windows-amd64.exe -status\n.\\agent-windows-amd64.exe -self-test -relay-url https://test-officialwebsite.azurewebsites.net/relay/workdesk\n```\n\nWebSocket mode uses standard proxy environment variables by default, such as `HTTP_PROXY` and `HTTPS_PROXY`. Use `-proxy http://proxy.example:8080` to force a proxy, or `-proxy direct` to bypass proxy discovery.\n\n### 5. Run Home App\n\nStart the Windows home app with the same room URL:\n\n```powershell\n.\\client-windows-amd64.exe -relay-url https://test-officialwebsite.azurewebsites.net/relay/workdesk\n```\n\nThe app opens a friendly control panel and a notification-area icon. Click `Connect` to start the local RDP listener and open Remote Desktop. The default local listener is `127.0.0.1:3390`, avoiding Windows' normal local RDP port `3389`, and the app opens one outbound WebSocket to Azure for each local RDP session.\n\nThe home app stores its room URL, local RDP address, and proxy mode in `%APPDATA%\\TunnelDesktop\\home-client.json`. Console debug mode is still available:\n\n```powershell\n.\\client-windows-amd64.exe -console -relay-url https://test-officialwebsite.azurewebsites.net/relay/workdesk\n```\n\n### 6. Run Android Home App\n\nInstall the debug-signed APK:\n\n```text\ndist\\android\\tunneldesktop-home-android-debug.apk\n```\n\nOpen TunnelDesktop Home, enter the same relay room URL as the work agent, keep the local RDP port at `3390`, and start the tunnel. In an Android RDP client, connect to:\n\n```text\n127.0.0.1:3390\n```\n\nThe Android app keeps the tunnel alive through a foreground service while you switch to the RDP client. It also maintains the same `home-agent` presence socket used by the relay dashboard.\n\n## Deliverables\n\n### Azure Relay Web Service\n\n`azure-relay/` is a .NET 8 minimal ASP.NET Core service. It exposes:\n\n- `GET /relay/` for the live overview dashboard.\n- `GET /relay/{room}` for a room-scoped live dashboard.\n- `GET /relay/health` for machine-readable health.\n- `GET /relay/status` for JSON status.\n- `GET /relay/ws` and `GET /relay/{room}/ws` as WebSocket endpoints.\n\nWebSocket clients identify their role with:\n\n```text\nX-TunnelDesktop-Role: agent | client | home-agent | probe | dashboard\n```\n\nRoles:\n\n- `agent`: work-side idle socket waiting to be paired.\n- `client`: home-side data socket for one RDP connection.\n- `home-agent`: Windows home app status presence.\n- `probe`: self-test connection.\n- `dashboard`: browser status stream.\n\nThe dashboard shows work-agent presence, home-app presence, active stream counts, total stream count, and recent remote addresses.\n\n### Python Relay Web Service\n\n`python-relay/` is a FastAPI/ASGI implementation of the same relay contract. It is useful for hosting on Python-capable App Service plans, on a Linux VM such as OCI Always Free, or for local relay testing without the .NET runtime.\n\nIt exposes the same user-facing paths:\n\n- `GET /relay/` and `GET /relay/\u003croom\u003e` for the live dashboard.\n- `GET /relay/health` for health JSON.\n- `GET /relay/status` for JSON status.\n- `GET /relay/ws` and `GET /relay/\u003croom\u003e/ws` as WebSocket endpoints.\n\nRun it locally:\n\n```powershell\npython -m pip install -r python-relay\\requirements.txt\npython -m uvicorn app:app --app-dir python-relay --host 127.0.0.1 --port 8000\n```\n\nBuild the deployable Python zip:\n\n```powershell\npython -m pip install -r python-relay\\requirements-dev.txt\n.\\build\\build-python-relay.ps1\n```\n\nThe build emits both the source-style zip and an Oracle Linux 9 / Python 3.9 vendored zip for minimal VM deployments.\n\n### Work Agent\n\n`agent.exe` is the work-side Windows component. It is Windows-service-first because RDP must work while the user is logged out.\n\nDefault behavior:\n\n- `agent.exe` with no args uses the default relay room URL.\n- `-relay-url \u003curl\u003e` selects a named room.\n- The service keeps a small pool of idle outbound WebSockets to Azure.\n- When Azure pairs a socket, the agent dials `127.0.0.1:3389` and pipes bytes.\n\nDebug and operations:\n\n```powershell\n.\\agent.exe -console -relay-url https://test-officialwebsite.azurewebsites.net/relay/workdesk\n.\\agent.exe -self-test -relay-url https://test-officialwebsite.azurewebsites.net/relay/workdesk\n.\\agent.exe -status\n.\\agent.exe -uninstall\n```\n\n### Agent Configurator\n\n`agent-configurator-windows-amd64.exe` is the native Windows setup and service management GUI.\n\nIt:\n\n- Prefers `D:\\TunnelDesktop\\Agent` as the install directory when `D:` exists.\n- Copies the selected agent binary to `agent.exe`.\n- Installs or updates the automatic `TunnelDesktopAgent` Windows service with the configured relay URL.\n- Configures SCM restart recovery.\n- Starts, stops, restarts, uninstalls, refreshes status, opens the install folder, and runs `agent.exe -self-test`.\n\n### Home App\n\n`client.exe` is the secure home-side Windows path. It provides:\n\n- A polished control panel with relay room URL, local RDP address, proxy mode, status tiles, room details, and activity log.\n- A notification-area icon with open, connect, stop, Remote Desktop, and quit actions.\n- Persistent home-app presence on the relay dashboard.\n- A loopback RDP listener, normally `127.0.0.1:3390`.\n- Automatic Remote Desktop launch when the user clicks `Connect`.\n\n### Android Home App\n\n`android-home/` is the Android home endpoint. It is not an RDP client by itself; it provides the loopback tunnel that an Android RDP client uses.\n\nIt provides:\n\n- A native Android control panel with relay room URL, local RDP port, status tiles, activity log, copy, dashboard, and RDP launch actions.\n- A foreground service so the tunnel can keep running while another app is active.\n- A loopback RDP listener, normally `127.0.0.1:3390`.\n- One outbound `client` WebSocket per local RDP connection.\n- A persistent `home-agent` presence WebSocket while the service is running.\n\nGood free Android RDP client options include Microsoft's Remote Desktop/Windows App client and the open-source FreeRDP-based aFreeRDP client. Configure the RDP client to connect to the TunnelDesktop local target shown in the Android app.\n\n## Security Model\n\n- Work and home endpoints make outbound HTTPS WebSocket connections only.\n- The room name in the URL is the pairing key.\n- The relay never dials the work PC or home PC.\n- The work agent only dials `127.0.0.1:3389` after Azure has paired a same-room home connection.\n- The home app listens on loopback by default, so other LAN devices cannot connect to the local RDP listener unless the user intentionally changes the listen address.\n\nChoose room names that are not obvious. Anyone who knows the room URL can attempt to join that room.\n\nThis software can route around corporate egress controls to expose an internal RDP session. Confirm that use is permitted by workplace policy. This project intentionally does not add anti-monitoring, stealth, or obfuscation behavior.\n\n## Build Prerequisites\n\nRequired:\n\n- Go 1.25+.\n- .NET SDK 8+ for the Azure relay.\n- Python 3.11+ for the Python relay.\n- JDK 17+ plus Android SDK platform 35 and build-tools 35.0.0 for the Android home app.\n- Gradle 9.x, or a compatible Gradle installation on `PATH`, for the Android home app.\n- `rsrc` for Windows GUI manifest resources; `build\\build-go.ps1` installs it under `D:\\Go\\bin` when missing.\n\nThis repo has been built with Go installed under `D:\\Scoop` and .NET SDK 9.x publishing the relay as `net8.0`.\n\n## Build Commands\n\nBuild Azure relay zip:\n\n```powershell\n.\\build\\build-azure-relay.ps1\n```\n\nBuild Python relay zip:\n\n```powershell\n.\\build\\build-python-relay.ps1\n```\n\nBuild Go binaries:\n\n```powershell\n.\\build\\build-go.ps1\n```\n\nBuild Android home APK:\n\n```powershell\n.\\build\\build-android-home.ps1\n```\n\nArtifacts:\n\n```text\ndist\\azure-relay\\tunneldesktop-azure-relay.zip\ndist\\python-relay\\tunneldesktop-python-relay.zip\ndist\\python-relay\\tunneldesktop-python-relay-linux-cp39-vendored.zip\ndist\\bin\\agent-windows-amd64.exe\ndist\\bin\\agent-configurator-windows-amd64.exe\ndist\\bin\\client-windows-amd64.exe\ndist\\android\\tunneldesktop-home-android-debug.apk\n```\n\n## URL Configuration\n\nUse one shared URL:\n\n```text\nhttps://test-officialwebsite.azurewebsites.net/relay/\u003croom\u003e\n```\n\nOCI Python relay example:\n\n```text\nhttp://217.142.228.117/relay/\u003croom\u003e\n```\n\nRules:\n\n- `\u003croom\u003e` is created automatically on first use.\n- Reusing the same URL joins the same room.\n- The WebSocket endpoint is derived automatically as `/relay/\u003croom\u003e/ws`.\n- The base `/relay/` path is an overview dashboard.\n- No generated pairing files are required for the normal Azure WebSocket path.\n\n## Troubleshooting\n\n### Agent Self-Test Fails Through Proxy\n\nRun:\n\n```powershell\n.\\agent.exe -self-test -relay-url https://test-officialwebsite.azurewebsites.net/relay/workdesk\n```\n\nFor Azure mode, self-test checks local RDP and then opens a `probe` WebSocket.\n\nCommon causes:\n\n- Corporate proxy blocks `CONNECT test-officialwebsite.azurewebsites.net:443`.\n- Proxy requires authentication not supported by the service account.\n- Azure App Service WebSockets are disabled.\n- The Azure relay has not been deployed or is not running.\n- Local RDP is disabled or not listening on `127.0.0.1:3389`.\n\n### Home App Connects But RDP Fails\n\nCheck:\n\n- The home app status tiles show the same room URL as the work agent.\n- The room dashboard shows waiting work-agent sockets.\n- The agent service is running.\n- Work PC allows RDP.\n- The configured Windows account is allowed to log in remotely.\n- The home app local listen port is not already in use. If `127.0.0.1:3389` fails on the home PC, use `127.0.0.1:3390`.\n\n### Azure Relay Status\n\nOpen:\n\n```text\nhttps://test-officialwebsite.azurewebsites.net/relay/workdesk\n```\n\nThe dashboard receives live status over WebSocket. Useful fields:\n\n- waiting work-agent sockets\n- home-app presence\n- active RDP stream pairs\n- total stream pairs\n- last home-client source address\n\n## Development\n\nRun all Go tests:\n\n```powershell\ngo test ./...\n```\n\nBuild and test the Azure relay:\n\n```powershell\n.\\build\\build-azure-relay.ps1\n```\n\nRebuild after Windows agent/client changes:\n\n```powershell\n.\\build\\build-go.ps1\n```\n\n## Repository Layout\n\n```text\nazure-relay/      .NET Azure App Service WebSocket relay\npython-relay/     Python/FastAPI WebSocket relay\ncmd/agent         Windows service work-side agent\ncmd/agent-configurator Windows service setup/configurator GUI\ncmd/client        Windows control-panel/tray home app\nandroid-home/     Android foreground-service home app\ninternal/tunnel   TLS, auth, CONNECT, WebSocket, yamux, pipe, allowlist\nbuild/            build scripts\n```\n\n## Status\n\nThis repo currently contains:\n\n- Azure App Service WebSocket relay source and publish script.\n- Protocol-compatible Python WebSocket relay source and publish script.\n- Live dashboard with WebSocket status updates.\n- Named-room URL joining under `/relay/\u003croom\u003e`.\n- Windows work agent implemented as a Windows service deliverable.\n- Windows configurator GUI for installing and managing the work agent service.\n- Windows home app implemented as a friendly control-panel and tray deliverable.\n- Android home app implemented as a foreground-service loopback tunnel endpoint.\n- Build scripts for Go binaries, relay packages, and the Android APK.\n\n## Current Limitations\n\n- The Azure relay is a simple in-memory broker. Restarting the App Service disconnects active sessions and clears room status.\n- Multiple App Service instances are not supported unless sticky routing or shared broker state is added.\n- The Go work agent supports direct, environment, and basic HTTP proxy URLs. NTLM proxy authentication is not implemented in the service.\n- The home app is a Windows RDP launcher and tunnel endpoint, not a full RDP client.\n- The Android home app is also a tunnel endpoint, not a full RDP client; use a separate Android RDP client against `127.0.0.1:3390`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblhsing%2Ftunneldesktop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblhsing%2Ftunneldesktop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblhsing%2Ftunneldesktop/lists"}