Skip to content

Remote Access and Security

CONNECT has exactly one access rule, evaluated per request:

A caller is allowed in if it is on the local machine, if it presents a valid API key, or if it presents a valid dev key while remote development is switched on.

Everything else is answered with 401. There is one authentication instance and no per-endpoint exception list — individual endpoints add authorization checks on top (who may do what), never a different way to prove who you are.

The third case is the remote development mode: a second, separate key that is off by default and that developers of realvirtual WEB use to work on one running session from two machines. If you are not doing that, it does not exist for you — leave it empty and nothing changes.

For a gateway used only on the PC it runs on, this means: nothing to configure, and nothing reachable from outside without a key.

Set ApiKey in appsettings.json next to the executable and restart the gateway:

{ "ApiKey": "a-long-random-value" }

An empty key disables the key mechanism, which is fine as long as the gateway is only used locally.

A key can be presented in three ways:

WayUsed by
X-API-Key headerScripts, Unity, MCP clients
Authorization: Bearer <key>HTTP clients that prefer it
Session cookieBrowsers, after the one-time link below

A browser cannot attach a header to a page it is asked to load, so a remote HMI would not be able to fetch even its own model. The one-time link solves this:

http://<host>:5100/?apikey=<key>

Opening that URL once exchanges the key for a session cookie — httpOnly, SameSite=Strict, valid for one working day — and redirects to the clean address. Every later request from that browser, including every model download, carries the cookie.

The exchange happens on a page navigation only. Scripts, Unity and AI clients keep using the header and are unaffected.

Windows binds all network adapters by default, so a gateway can be reachable from other machines even though nobody set that up. Exactly that combination — reachable beyond the local machine and no API key — raises a notice in the tray menu with what to do: set ApiKey, then open the gateway once with the one-time link.

A purely local installation stays silent.

CONNECT does not terminate TLS itself. The supported remote setup is a reverse proxy that terminates TLS and speaks plain HTTP to the gateway on the local machine.

When you do that, configure TrustedProxies with the proxy’s address. Without it, the proxy is the transport peer — so every request arriving through it would look local and the key would never be demanded. That is deliberate: a request that still carries unresolved forwarding headers is never treated as local.

The gateway warns at startup when it is reachable beyond the local machine without TLS, without trusted proxies or without an API key.

Two exceptions exist, and both are intentional.

/health answers without any proof. Monitoring has to work. It carries liveness, version identity and yes/no capability flags — nothing else. The operational detail (signal and client counts, license state) lives at /health/detail, behind the normal rule.

Some development routes refuse remote callers even with a valid API key. One of them runs a test command, and the gateway API key must never become remote code execution. The only way past that ceiling is the separate dev key below — a different secret, behind a switch that ships off.

This section is for developers of realvirtual WEB. If you run CONNECT as a gateway, skip it — the feature is off and stays off unless you deliberately turn both halves on.

When CONNECT runs the realvirtual WEB development server, that server is served to the local machine only, and the normal API key does not change it: a development workspace holds sources and customer project data, and it is not a delivery. To work on one running session from a second machine — desktop and laptop, office and on the road, with live reload and the plant connection intact — two things have to be set:

HalfWhere
A dev key, Dev.ApiKeyappsettings.json next to the executable — empty by default
The switch realvirtual WEB → Allow remote access (dev)Tray menu — off by default, applies immediately

Either one missing means the remote machine is refused. The normal ApiKey never opens this.

Publish the gateway port to your tailnet — this is the tested path, and using the same port matters, because it keeps the page, the live-reload socket, the HMI bridge and the AI endpoint on one address:

Terminal window
tailscale serve --bg --https=5100 http://127.0.0.1:5100
# close it again
tailscale serve --https=5100 off

Then open this once on the other machine:

https://<magicdns-name>:5100/?devkey=<your dev key>

The key is exchanged for a session cookie and the address is cleaned up, exactly like the API-key link above. Everything afterwards — sources, live reload, the HMI — travels on that cookie. Scripts use the X-Dev-Key header instead.

  • The AI endpoint needs its own switch. MCP server → Allow remote clients is a separate setting that the dev key does not touch. Remote development without remote AI clients is a perfectly normal state.
  • Switching the toggle off applies to new requests. A live-reload connection that is already open keeps running until it goes idle. Close the browser tab to end it immediately.

On Linux the startup gate still requires the normal ApiKey whenever the gateway is reachable beyond the local machine; the dev key does not substitute for it. An unlicensed installation gets no remote development either.

Three surfaces additionally check where the browser came from, because the access rule alone cannot detect a DNS rebinding attack — the attacker’s page carries a consistent name that resolves to the local address:

SurfaceRestriction
MCP endpointTrusted origins only, and local clients only unless remote MCP clients are explicitly allowed
Bundled HMI bridgeTrusted origins or the gateway’s own origin
Update confirmationTrusted origins or the gateway’s own origin

A bare IP address is accepted as a host, which is what keeps a remote HMI on http://192.168.x.y:5100 working: rebinding needs a name whose DNS answer can be changed after the page was served.

The gateway exposes an MCP endpoint for AI tools. It is on by default, and writes are allowed by default — the access rule above is what makes that safe. Both switches are in the tray menu:

  • MCP server → Enabled — a startup switch; the tray offers the restart that applies a change.
  • MCP server → Allow write access — read live; connected clients are notified when it changes.

Remote MCP clients are refused unless explicitly allowed. Details: AI clients.