Self-hosted remote access and fleet management for Windows devices, built on .NET 10.
RemoteAppClient is a self-hosted remote support system. A Windows agent runs as a SYSTEM service on managed devices, keeps an outbound control channel to the server, reports telemetry, provisions TightVNC, and opens SSH tunnels on demand. The Linux server owns enrollment, command signing, authentication, audit logging, release channels, update packages, and MSI generation. The Windows console client is the operator/admin UI.
The desktop capture and encoding layer is intentionally not implemented here. TightVNC does that work as a separate process. RemoteAppClient provides the control plane, enrollment, tunnel orchestration, security model, fleet UI, and update workflow around it.
Use this only on systems you own or are explicitly authorized to administer.
Website and screenshots | Deployment guide
- What's New in 3.0.0
- Changelog
- What It Does
- Architecture
- Projects
- Security Model
- Configuration
- Linux Operator Console
- Deployment Flow
- Build
- Runtime Commands
- Release Packages
- Repository Layout
- Support
- TightVNC And Licensing
Every key a device holds moves into its TPM, and certificates look after themselves. Every component is
3.0.0.0; one schema change (upgrade-3.0.0.sql, idempotent).
- The device key is a non-exportable TPM key (Microsoft Platform Crypto Provider; software key storage where
the TPM is missing, not ready or flagged for vulnerable firmware). The certificate sits in
LocalMachine\Mybound to it; nothing private is written to a file any more, so neither an administrator nor a lifted disk yields a usable device identity. The DPAPI-sealed PFX remains only where CNG key storage is unavailable. - Devices enrolled earlier re-key by themselves, 5–30 minutes after the new agent starts: new key, new certificate, proof with the new one, only then the switch. A failure anywhere leaves the old identity in place.
- Certificates renew the same way within 180 days of their end, so the 825-day certificates from 2026 renew in 2028 instead of expiring.
- A lost TPM key is recovered with one click. After a BIOS update that cleared the TPM, the agent sends a lost-key request without a certificate; the device turns yellow in the console (KULCSKÉRÉS) and Approve issues the certificate for the same device id, with its group and notes intact. Nothing is issued by itself.
- The console shows where the key is (kulcs: TPM / szoftver / fájl) and when the certificate ends; Commands → Új eszközkulcs (TPM) re-keys a device on demand.
- The tunnel's SSH key is a TPM key as well, served to
ssh.exeby an ssh-agent built into the agent service; no private key file exists any longer. Its certificate lives three days and is fetched over mTLS, so only the device with the TPM-bound identity gets one. Devices enrolled earlier move over by a proven rotation: the new key opens a real connection to the bastion before the server revokes the old one. - Also in this release: verbose logging on demand (24-hour device log level, TightVNC detail, a daily file log), the server mails when its own checks fail, audit rows live a year, sleeping and roaming devices reconnect at once, deployment hardening, and the first automated tests (201 by now, run by CI on every push).
Earlier releases: CHANGELOG.md.
Remote access:
- Lists enrolled devices with online state, user, local/public IP, component versions, boot time, VPN/Wi-Fi state, local lock state, and recent incidents.
- Opens a reverse SSH tunnel from the target agent to the bastion and launches TightVNC through that bastion port.
- Supports consent prompts, unattended access policy, and a local "disable remote access" lock on the endpoint.
- Sends availability questions and operator messages to the signed-in device user.
- Supports power actions such as restart, forced restart, cancel shutdown, and sign out.
Fleet management:
- Device groups with inherited access policy.
- Admin/operator roles with device and group grants.
- User management, password reset, password recovery tokens, TOTP, and optional Windows Hello sign-in.
- Audit log for access, enrollment, package, user, settings, and security events.
- Server branding: owner name, support phone, and support email.
Operations:
- Release channels:
rtmandbeta. - Components:
agent,updater,client, andvnc. - Upload packages, roll out by channel, promote beta packages to RTM, and update devices.
- Build per-group MSI installers on the server with agent, updater, optional console client, optional Start menu shortcut, bundled TightVNC MSI, and an embedded bootstrap blob.
- Localized UI/log strings with English and Hungarian dictionaries.
- Shared runtime language setting for all local executables on a device.
Linux server
+------------------------+
| RemoteServer |
| |
Windows agent --->| /agent WSS + mTLS | signed commands
SYSTEM | /api/* mTLS | telemetry, VNC secret, update packages
| /enroll token based |
| /auth/* login/TOTP |
| /admin/* localhost |
+-----------+------------+
|
| MariaDB
|
v
audit, users,
devices, packages
Windows agent -- ssh -R --> bastion localhost port --> console client --> TightVNC viewer
Console client -- named pipe --> local agent broker -- ssh -L --> bastion/admin API
Important routing rules:
- Agents initiate outbound connections. Managed Windows devices do not need inbound ports.
/agentis a WebSocket command channel and requires a client certificate./api/*is for telemetry, VNC secret reporting, and update package downloads. It is protected by mTLS in the nginx deployment./admin/*is localhost-only on the server. The console reaches it through a local agent broker, which opensssh -Lusing the enrolled device identity.- The operator console does not own an SSH key for the bastion. The local agent opens the forward through a named pipe broker, and server-side auth/grants still decide what the signed-in user may do.
- The target VNC service remains on the endpoint loopback. It is exposed only through an agent-created reverse tunnel.
| Project | Purpose | Runs on |
|---|---|---|
RemoteAgent |
Windows service: enrollment bootstrap, command channel, command verification, telemetry, VNC provisioning, local broker, reverse tunnel, updates | Managed Windows devices as SYSTEM |
RemoteAgent.Updater |
Helper service: watchdog, heartbeat monitoring, and executable replacement for agent updates | Managed Windows devices as SYSTEM |
RemoteClient |
WinForms/MaterialSkin console for operators and administrators | Windows admin/operator devices |
RemoteClient.Lite |
Viewer-only Windows console: signs in with an ephemeral SSH certificate, no local agent needed | Windows operator devices |
RemoteClient.Linux |
Viewer-only Avalonia console for Linux operators | Linux operator devices |
RemoteClient.Cli |
racctl: command-line access to the log, the health snapshot, the fleet listings and the server self-update with an access token |
Enrolled Windows devices |
RemoteClient.Core |
Shared console logic: admin API client, tunnel transports, localization | Referenced by the consoles and racctl |
RemoteServer |
ASP.NET Core server: enrollment, auth, admin API, command signing, telemetry ingest, package storage, MSI generation, audit, diagnostics | Linux |
RemoteAgent.Contracts |
Shared DTOs and canonical command signature logic | Referenced by client, agent, and server |
RemoteAgent.Resources |
Shared resources | Referenced by application projects |
RemoteAppClient treats command authenticity as mandatory:
- Agent identity is based on per-device client certificates issued during enrollment.
- The agent pins the server TLS certificate fingerprint.
- Server commands are signed with ECDSA P-256.
- The agent verifies every command against the enrolled server command-signing public key.
- Command replay is limited with nonce tracking plus a timestamp window.
- The server can choose only the remote bastion port for a tunnel. Bastion host, user, SSH key, SSH certificate, host key, and local target port come from device config.
- The bastion host key is pinned through a private known_hosts file created per SSH session.
/admin/*is not exposed externally by the nginx deployment.- Console sessions still require username/password plus TOTP unless Windows Hello is used.
- Operators see only granted devices/groups and can open tunnels only for those devices.
- Passwords are hashed with Argon2id.
- Database secrets such as VNC passwords, SMTP password, and Graph client secret are encrypted at rest with AES-256-GCM using a server-side key file.
- Enrollment tokens are stored as hashes. The raw token is visible only when generated.
- Bootstrap/MSI enrollment tokens create Pending devices by default; an administrator must approve them.
- The local VNC lock can disable remote access on a device and cannot be undone remotely.
Deployment assumption: Kestrel listens on localhost behind nginx. Do not expose the RemoteServer Kestrel port directly to the internet.
RemoteAppClient has four configuration surfaces:
- Server appsettings and environment variables.
- Agent appsettings plus enrollment-generated files.
- Console client local settings.
- Shared per-machine language settings.
Server settings are read from src/RemoteServer/appsettings.json and environment variables.
The deployment scripts write sensitive values into /etc/remoteserver/*.env, consumed by
the systemd service through EnvironmentFile.
Environment variables use ASP.NET Core double-underscore syntax:
Server__PublicUrl=https://remote.example.com
Server__Bastion__Host=remote.example.com
ConnectionStrings__MariaDb="Server=localhost;Port=3306;Database=remoteserver;User Id=remoteserver;Password=..."| Setting | Default | Required | Description |
|---|---|---|---|
ConnectionStrings:MariaDb |
CHANGEME sample |
Yes | MariaDB connection string. deploy/setup.sh (step 02) writes this to /etc/remoteserver/db.env. |
Server:CommandSigningKeyPath |
/etc/remoteserver/cmd_signing.key sample |
Yes | ECDSA P-256 private key used to sign agent commands. The public key is returned to agents during enrollment. |
Server:CaCertPath |
/etc/remoteserver/ca.crt |
Yes | Client-certificate CA public certificate. nginx also uses this for mTLS validation. |
Server:CaKeyPath |
/etc/remoteserver/ca.key |
Yes | Client-certificate CA private key. Keep readable only by the service user. |
Server:ClientCertValidityDays |
825 |
No | Validity period for issued agent client certificates. |
Server:SecretKeyPath |
/etc/remoteserver/secret.key |
Yes | 32-byte AES-GCM key for database secret encryption. |
Server:PackagesDir |
/var/lib/remoteserver/packages |
Yes | Persistent package store for uploaded EXE/MSI files and generated MSI installers. |
Server:PublicUrl |
empty | Yes for bootstrap/MSI | Public base URL embedded into bootstrap blobs, for example https://remote.example.com. |
Server:MinClientVersion |
1.5.0.0 |
No | Oldest console client allowed to sign in. Older clients receive a mandatory update response. Empty disables the gate. |
Server:MsiSigning:CertPath |
empty | No | Optional Authenticode signing certificate path for generated MSI files. Empty means unsigned MSI. |
Server:MsiSigning:Password |
empty | If signing | Password for the MSI signing PFX. Prefer environment/secret storage. |
Server:MsiSigning:TimestampUrl |
http://timestamp.digicert.com |
No | Timestamp server used by osslsigncode. |
Server:Bastion:Host |
empty | Yes | Public SSH bastion host returned to agents during enrollment. |
Server:Bastion:Port |
22 |
No | SSH bastion port. |
Server:Bastion:User |
agent |
No | Restricted SSH user used by enrolled agents. |
Server:Bastion:HostKey |
empty | Yes | Bastion host key in known_hosts format without the trailing comment, for example ssh-ed25519 AAAA.... |
Server:Bastion:SshCaKeyPath |
/etc/remoteserver/agent_ca |
Yes | SSH CA private key used to sign agent SSH keys. |
Server:Bastion:SshCertValidityDays |
825 |
No | Validity period for agent SSH certificates. |
Server:Bastion:TunnelPortMin |
50000 |
No | First bastion port used for stable per-device reverse tunnels. |
Server:Bastion:TunnelPortMax |
60000 |
No | Exclusive upper bound of the per-device tunnel port range. |
Server-side values stored in the database:
- Owner name, support phone, support email.
- Email provider: none, SMTP, or Microsoft Graph.
- SMTP password and Graph client secret, encrypted with
SecretProtector. - Graph secret expiry date and notification state.
- Users, roles, grants, devices, groups, packages, tokens, audit logs, and sessions.
The agent reads Agent options from appsettings, environment variables, and then
overrides most runtime values from C:\ProgramData\RemoteAgent\enrollment.json after
enrollment. In normal MSI/bootstrap installs, you should not hand-edit most of these.
Local agent data directory by default:
C:\ProgramData\RemoteAgent
Important generated files:
| File | Purpose |
|---|---|
enrollment.json |
Device ID, server URL, command-signing public key, bastion host/user/host key. |
agent.pfx.dat |
DPAPI-protected client certificate PFX for mTLS. |
ca.crt |
Server/client CA certificate returned during enrollment. |
id_ed25519 |
Agent SSH private key for bastion tunnels. ACL is restricted to SYSTEM and Administrators. |
id_ed25519-cert.pub |
SSH certificate signed by the server-side SSH CA. |
bootstrap.dat |
Optional one-time bootstrap blob consumed on first start. |
vnc.secret |
Local VNC password cache used for reporting to the server. |
| Setting | Default | Usually set by | Description |
|---|---|---|---|
Agent:AgentId |
empty | enrollment | Stable device identifier. Empty means derived locally until enrollment supplies the server device ID. |
Agent:EnrollmentDir |
C:\ProgramData\RemoteAgent |
appsettings/MSI | Directory for enrollment output and runtime state. |
Agent:ClientCertPfxPath |
empty | enrollment | DPAPI-protected PFX path used for mTLS. |
Agent:CommandChannel:Url |
sample URL | enrollment | WSS endpoint, for example wss://remote.example.com/agent. |
Agent:CommandChannel:ClientCertThumbprint |
empty | legacy/manual config | Store thumbprint fallback when no PFX path is configured. |
Agent:CommandChannel:ServerCertPinSha256 |
empty | enrollment/manual | SHA-256 pin of the server TLS certificate. |
Agent:CommandChannel:CommandSigningPublicKey |
empty | enrollment | Base64 SPKI public key used to verify signed commands. |
Agent:CommandChannel:MaxCommandAgeSeconds |
60 |
appsettings | Replay window for signed commands. |
Agent:CommandChannel:ReconnectBaseDelaySeconds |
2 |
appsettings | Initial reconnect delay after command channel failure. |
Agent:CommandChannel:ReconnectMaxDelaySeconds |
120 |
appsettings | Maximum reconnect delay. |
Agent:CommandChannel:KeepAliveIntervalSeconds |
15 |
appsettings | WebSocket keepalive interval. |
Agent:CommandChannel:KeepAliveTimeoutSeconds |
10 |
appsettings | Pong timeout before reconnecting stale connections. |
Agent:Tunnel:BastionHost |
sample host | enrollment | SSH bastion hostname. |
Agent:Tunnel:BastionPort |
22 |
enrollment | SSH bastion port. |
Agent:Tunnel:BastionUser |
agent |
enrollment | Restricted SSH user. |
Agent:Tunnel:PrivateKeyPath |
C:\ProgramData\RemoteAgent\id_ed25519 |
enrollment/appsettings | Agent SSH private key. |
Agent:Tunnel:CertificatePath |
empty | enrollment | Agent SSH certificate path. |
Agent:Tunnel:BastionHostKey |
empty | enrollment | Pinned bastion host key. |
Agent:Tunnel:LocalForwardPort |
5900 |
appsettings | Local target port exposed through reverse tunnel, normally TightVNC. |
Agent:Tunnel:IdleTimeoutSeconds |
1800 |
appsettings | Auto-close idle remote access tunnel. |
Agent:Tunnel:SshExecutablePath |
C:\Windows\System32\OpenSSH\ssh.exe |
appsettings | ssh.exe path. Empty means resolve from PATH. |
Agent:Telemetry:IngestUrl |
sample URL | enrollment | Telemetry endpoint, for example https://remote.example.com/api/telemetry. |
Agent:Telemetry:ClientCertThumbprint |
empty | legacy/manual config | Store thumbprint fallback for telemetry mTLS. |
Agent:Telemetry:ServerCertPinSha256 |
empty | enrollment/manual | TLS pin for telemetry HTTP calls. |
Agent:Telemetry:IntervalSeconds |
300 |
appsettings | Telemetry interval. |
The console client stores local user settings here:
%APPDATA%\RemoteClient\config.json
Current client flow:
- It first connects to the local agent broker named pipe:
RemoteAgent.broker. - The agent broker opens
ssh -Lforwards to the bastion. - The client talks HTTP to the forwarded localhost port.
- The client launches TightVNC viewer for remote desktop sessions.
| Setting | Default | Description |
|---|---|---|
AdminApiPort |
5000 |
Bastion loopback port for the server admin API. The local agent broker forwards this. |
ViewerExe |
C:\Program Files\TightVNC\tvnviewer.exe |
TightVNC viewer path used by the console. |
ThemeMode |
dark |
light, dark, or auto. |
Channel |
rtm |
Console self-update channel, rtm or beta. |
HelloCredentialId |
null | Windows Hello credential registered for this local client/user. |
HelloUsername |
null | Username associated with the local Windows Hello credential. |
SshHost, SshUser, SshPort, SshKeyPath, SshExe |
legacy/manual fields | Present in the config model, but the current console path uses the local agent broker instead of a client-owned SSH key. |
All local executables read the shared language preference from:
%ProgramData%\RemoteAppClient\settings.json
Supported values:
| Value | Meaning |
|---|---|
auto |
Use the system UI culture. |
en |
English. |
hu |
Hungarian. |
The console Settings page writes this file. Running services and already-open windows may need a restart to fully pick up the new language.
deploy/setup.sh runs as ordered steps under deploy/steps/. The values they generate
should not be committed:
| Step | Output |
|---|---|
02-mariadb |
MariaDB database/user (or your external DB) and /etc/remoteserver/db.env. |
03-schema |
Baseline schema loaded into the database. |
04-server |
/opt/remoteserver, command-signing key, client CA, secret.key, bastion.env (+ PublicUrl), systemd unit, package directory. |
05-bastion |
Restricted agent SSH user, SSH CA key, sshd Match block. |
06-tls |
Let's Encrypt certificate via Cloudflare DNS-01. |
07-nginx |
443 multiplexer (SSH + HTTPS/WSS on one port), mTLS for /agent /ssh /api/*, localhost-only /admin/*. |
08-harden |
UFW, fail2ban, and sshd hardening. |
09-blob |
First bootstrap blob + admin login. |
10-selfupdate |
Console-driven server self-update helper (systemd path-units + root helper scripts). |
deploy/fetch-tightvnc.sh (run separately) downloads the pinned TightVNC MSI and the
matching GPL source ZIP under third_party/tightvnc.
Multiserver Linux RemoteAppClient Lite is a viewer-only operator console for Linux (Debian/Ubuntu). It connects to the same server as the Windows console and opens VNC sessions to enrolled devices, but it runs no agent and can do nothing on the remote side beyond what an operator already can.
How it differs from the Windows console:
- No local SYSTEM agent / broker. On sign-in the server mints a short-lived (12 h)
operator SSH certificate for an ephemeral key, and the console opens its own
ssh -Lforwards to the bastion with that cert — there is no client-owned long-lived SSH key. - Per-account gate. The account must have the keyless-operator flag, set in the Windows console (Users → pick the user → Keyless operator (Linux console)). Without it the server mints no certificate and sign-in is refused.
- Viewer only. Device list, telemetry, VNC connect, and password recovery — no device management, MSI, channels, or server administration.
| Need | Package |
|---|---|
| SSH client (tunnels) | openssh-client |
| VNC viewer | ssvnc (preferred — adds fit-to-window scaling + 256-color) or tigervnc-viewer |
Both are declared as dependencies of the .deb.
sudo apt install ./remoteclient_<version>_amd64.deb # or run the AppImage directlyThe .deb and AppImage are built from a self-contained linux-x64 publish:
dotnet publish src/RemoteClient.Linux/RemoteClient.Linux.csproj -c Release -r linux-x64 --self-contained -o publish/client-linux
src/RemoteClient.Linux/packaging/build-deb.sh publish/client-linux <version> icon/RemoteAccessBlue_256x256.png .
src/RemoteClient.Linux/packaging/build-appimage.sh publish/client-linux <version> icon/RemoteAccessBlue_256x256.png .CI builds the .deb on every push (the client-linux job) and attaches it to tagged releases.
Launch Multiserver Linux RemoteAppClient Lite, sign in (server URL, username, password, and TOTP when required), pick a device, and Connect (VNC). The device table (hostname, group, note, online, last-seen) is sortable and searchable. Settings adjusts the VNC scaling and 256-color mode plus the UI language (Auto / English / Magyar; the language applies after a restart). Forgot password? runs the same code-based recovery as the Windows console.
deploy/setup.sh takes a fresh server from zero to a running RemoteServer — database, server,
bastion, TLS, the 443 multiplexer, hardening, the self-update helper, and the first
bootstrap blob — then verifies it. Run it on the server, as a user with passwordless sudo:
git clone https://github.com/v1k70rk4/RemoteAppClient.git
cd RemoteAppClient
./deploy/setup.shIt asks a few things up front — public DNS name, ACME email, and whether you have your own
MariaDB (otherwise it installs one) — then runs to the end. It is idempotent, and each step
under deploy/steps/ can run on its own, e.g. ./deploy/setup.sh 06-tls 07-nginx. For an
unattended run, copy deploy/config.env.example to deploy/config.env and fill it in. Details:
deploy/README.md. The keys and certificates involved, their lifetimes and what can be
rotated: deploy/KEYS.md.
TLS uses Let's Encrypt with Cloudflare DNS-01 — the script prompts for a Cloudflare API token
(Zone → DNS → Edit), or place it at /etc/letsencrypt/cloudflare.ini first. No Cloudflare? Issue
the certificate yourself and skip 06-tls. At the end, 09-blob prints the bootstrap blob and
the first admin login (admin + a temporary password to change on first sign-in; it is kept in
/var/lib/remoteserver/first-admin-password.txt, readable by the service user only, and the file is
removed once the password has been changed).
For the first machine, manual enrollment is simplest; later, build group MSIs from the console. In an elevated PowerShell, put the release artifacts in one folder and run:
.\RemoteAgent.exe bootstrap "<blob>"
.\RemoteAgent.exe install-service --owner "Company Name" --group "First devices"To provision TightVNC on first start, place the pinned MSI at .\vnc\tightvnc.msi first (see
TightVNC And Licensing). The agent enrolls on first start, opens its
tunnel, and reports telemetry. Because the bootstrap token is not auto-approved, the device stays
Pending until approved.
Start RemoteClient.exe, sign in as admin with the temporary password, complete the forced
password change and TOTP setup, then approve the Pending device in the Devices view. From there
you can upload packages, build group MSI installers, and use the normal remote workflow.
sudo systemctl status remoteserver
sudo journalctl -u remoteserver -f
sudo nginx -t && sudo tail -f /var/log/nginx/error.log| Symptom | Check |
|---|---|
09-blob reports missing PublicUrl |
Set Server__PublicUrl in /etc/remoteserver/bastion.env, restart remoteserver. |
09-blob reports missing schema |
Re-run ./deploy/setup.sh 03-schema (RAC_SCHEMA_FORCE=1 to reload). |
| Agent enrolls but console cannot connect | RemoteAgent service running? Bastion host key present in bastion.env? |
/agent or /api/* returns 403 |
Check nginx mTLS and the client CA. |
/admin/* unreachable from the internet |
Expected — localhost-only, reached through an enrolled device tunnel. |
| TightVNC not installed | Ensure vnc\tightvnc.msi sits next to the agent before service start, or run RemoteAgent.exe provision-vnc --msi <path> elevated. |
Requirements:
- .NET 10 SDK.
- Windows for the Windows-targeted projects (
RemoteAgent,RemoteAgent.Updater,RemoteClient). - Linux or Windows for the server project.
wixlon Linux when building MSI packages server-side.osslsigncodeonly if MSI Authenticode signing is configured.
Build with build.ps1 (run it without parameters to see the options). The Windows components come out as
single-file, self-contained EXEs:
.\build.ps1 -Unsigned # agent, updater, console - development build
.\build.ps1 -Fleet -Deploy # signed with the fleet certificate, then replace this machine's installation
.\build.ps1 -Tag # release build (adds RemoteClient.Lite), signed with the release certificate
.\build.ps1 -Msi # sign the MSI(s) generated by the server
.\build.ps1 -ServerOnly # the server package, RemoteServer-linux-x64.tar.gzSigning scripts and output folders are machine-specific and belong in build.local.psd1 next to build.ps1
(ignored by git); Get-Help .\build.ps1 -Detailed shows its format. A signing script is invoked as
& <script> -Path <file>. Default output: C:\RAC\build, and C:\RAC\release for -Tag.
racctl is not part of the release assets; build it where you use it and store a token minted in the console:
dotnet publish src/RemoteClient.Cli/RemoteClient.Cli.csproj -c Release -o C:\tools\racctl
C:\tools\racctl\racctl.exe token # paste the token when asked (never on the command line); DPAPI-protected, current user
C:\tools\racctl\racctl.exe logs --level warn --since 2hBuild the server on Linux:
dotnet publish src/RemoteServer/RemoteServer.csproj \
-c Release \
-r linux-x64 \
--self-contained \
-o publish/server
tar -C publish/server -czf RemoteServer-linux-x64.tar.gz .Run a development build:
dotnet build RemoteAppClient.slnxAgent commands:
RemoteAgent.exe enroll --token <token> --server https://remote.example.com [--hostname NAME] [--out C:\ProgramData\RemoteAgent]
RemoteAgent.exe bootstrap "<blob>"
RemoteAgent.exe install-service [--owner "Company"] [--group "Group"]
RemoteAgent.exe uninstall-service
RemoteAgent.exe provision-vnc [--msi path\to\tightvnc.msi] [--password <password>]
RemoteAgent.exe remove-vnc
RemoteAgent.exe vnc-lock
RemoteAgent.exe vnc-unlockServer first-run helper:
/opt/remoteserver/RemoteServer mint-blobmint-blob checks database/schema, first admin, command-signing key, CA, PublicUrl,
and bastion configuration before printing the first bootstrap blob.
.github/workflows/build.yml publishes artifacts on v* tags:
| File | Use |
|---|---|
RemoteAgent.exe |
Upload as the agent package. |
RemoteAgent.Updater.exe |
Upload as the updater package. |
RemoteClient.exe |
Upload as the client package. |
RemoteServer-linux-x64.tar.gz |
Deploy to the Linux server with deploy/setup.sh (step 04-server). |
Typical release:
git tag v1.7.0
git push origin v1.7.0The server stores uploaded packages in Server:PackagesDir, computes SHA-256, and uses
the hash in signed update commands. Agents verify package hashes before staging or
installing updates.
src/
RemoteAgent/ Windows agent service
RemoteAgent.Updater/ helper/watchdog/update service
RemoteClient/ WinForms operator/admin console
RemoteServer/ ASP.NET Core server
RemoteAgent.Contracts/ shared DTOs and command signatures
RemoteAgent.Resources/ shared resources
deploy/ from-scratch server installer
setup.sh orchestrator that runs the steps below
lib.sh
config.env.example
steps/ 01-prereqs … 11-verify
fetch-tightvnc.sh pinned TightVNC MSI + GPL source
README.md
icon/
third_party/
.github/workflows/build.yml
build.ps1
RemoteAppClient.slnx
RemoteAppClient is free and MIT-licensed. If it saves you time, you can support its development on Ko-fi.
RemoteAppClient is released under the MIT License.
RemoteAppClient uses TightVNC as a separate process for screen capture and remote desktop.
The repository does not commit the TightVNC binary. deploy/fetch-tightvnc.sh downloads a
pinned version, verifies SHA-256, and also downloads the corresponding source ZIP for GPL
compliance.
TightVNC remains under its own GPLv2 license. RemoteAppClient interacts with it as an installed external program and MSI package.