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.
All other requests receive 401. A single authentication instance handles requests, except that /health requires no authentication. Individual endpoints add authorization checks to control who may do what; they do not use separate authentication methods.
The third case is remote development mode, which uses a second, separate key and is off by default. Developers of realvirtual use it to work on one running session from two machines. If you do not need this mode, leave the key 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.
Setting an API key
Section titled “Setting an API 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:
| Way | Used by |
|---|---|
X-API-Key header | Scripts, Unity, MCP clients |
Authorization: Bearer <key> | HTTP clients that prefer it |
| Session cookie | Browsers, after the one-time link below |
Opening the HMI from another machine
Section titled “Opening the HMI from another machine”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 and redirects to the address without the key. The cookie is httpOnly, SameSite=Strict and valid for one working day. 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.
Reachable without anybody choosing it
Section titled “Reachable without anybody choosing it”Windows binds all network adapters by default, so other machines can reach a gateway without explicit setup. If the gateway is reachable beyond the local machine and has no API key, the tray menu shows a notice. It tells you to set ApiKey, then open the gateway once with the one-time link.
A purely local installation shows no notice.
TLS and reverse proxies
Section titled “TLS and reverse proxies”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 so CONNECT can read the real client address from the forwarding headers. Without it, the original address is unknown, so requests arriving through the proxy need the API key, even when they start on the same machine. /health remains the exception.
The gateway warns at startup when it is reachable beyond the local machine without TLS, without trusted proxies or without an API key.
What is deliberately different
Section titled “What is deliberately different”There are two exceptions:
/health answers without any proof. This allows monitoring without authentication. It returns only liveness, version identity and yes/no capability flags. Operational details (signal and client counts, license state) are available at /health/detail, which follows the normal access rule.
Some development routes refuse remote callers even with a valid API key. One runs a test command, so access with the gateway API key would allow remote code execution. Remote access to these routes requires the separate dev key below and a switch that is off by default.
Remote development from another machine
Section titled “Remote development from another machine”This section is for developers of realvirtual. 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 development server, only the local machine can access it. The normal API key does not grant remote access. A development workspace contains source files and customer project data; it is not a delivery. You can work on one running session from a second machine while preserving live reload and the plant connection. This supports desktop and laptop access, in the office or on the road. Configure both settings below:
| Half | Where |
|---|---|
A dev key, Dev.ApiKey | appsettings.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.
Setting it up
Section titled “Setting it up”Publish the gateway port to your tailnet using the tested setup below. Use the same port to keep the page, live-reload socket, HMI bridge and AI endpoint on one address:
tailscale serve --bg --https=5100 http://127.0.0.1:5100# close it againtailscale serve --https=5100 offThen open this once on the other machine:
https://<magicdns-name>:5100/?devkey=<your dev key>The key is exchanged for a session cookie and removed from the address, as with the API-key link above. Subsequent requests, including sources, live reload and the HMI, use that cookie. Scripts use the X-Dev-Key header instead.
Two things that catch people out
Section titled “Two things that catch people out”- The AI endpoint needs its own switch. MCP server → Allow remote clients is a separate setting that the dev key does not change. You can use remote development without allowing remote AI clients.
- 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.
Browser-origin checks
Section titled “Browser-origin checks”The access rule alone cannot detect a DNS rebinding attack. The attacker’s page keeps the same name while that name resolves to the local address. Three surfaces therefore also check the browser’s origin:
| Surface | Restriction |
|---|---|
| MCP endpoint | Trusted origins only, and local clients only unless remote MCP clients are explicitly allowed |
| Bundled HMI bridge | Trusted origins or the gateway’s own origin |
| Update confirmation | Trusted 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.
Trusted origins are the named entries of AllowedOrigins in appsettings.json and the ones added in the tray (Details ▸ Allowed origins); a * in that list counts for nothing. realvirtual’s own origins (https://web.realvirtual.io, https://realvirtual.io, https://www.realvirtual.io) are always allowed, without an entry: the hosted viewer and the public demo can read and control a gateway on the same PC with no configuration. Their AI Bridge asks for a one-time pairing in the tray — see AI clients. A viewer served from your own domain needs its origin added to AllowedOrigins.
AI clients
Section titled “AI clients”The gateway exposes an MCP endpoint for AI tools. It is on by default, and writes are allowed by default, subject to the access rule above. Both switches are in the tray menu:
- MCP server → Enabled: a startup switch. The tray offers a restart to apply 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.
See also
Section titled “See also”- Installation — where
appsettings.jsonlives - Updates — how the update confirmation is protected
- REST and WebSocket API — using the key from a script