Picking a deployment shape

Starting everything up

What actually runs

A streamed kiosk runs three processes. Knowing their names helps, because when something fails, it is almost always obvious which one is responsible:

  • Unreal — your packaged application. It renders the avatar and sends video out.

  • The signalling server — a small Node application. It introduces the browser and Unreal. Once introduced, video flows directly between them instead of going through the server. This same server also serves the page the big screen displays.

  • A tunnel, only if the kiosk has no public address of its own: ngrok, or the cloud setup at the end of this page.

The operator tablet is not in this list. Unreal serves the tablet page itself, on its own port, so nothing extra runs for it.

On-site deployments run none of this. If Unreal is on the machine driving the screen, it renders straight to the display and there is no server, no tunnel and no relay. This page is for streamed layouts.

Where the servers are

The signalling server is not part of the plugin — Epic’s PixelStreaming2 ships no servers at all. A known-good copy is included with this plugin at PromethistLinkPixelStreaming/Samples/WebServers, and it runs from wherever you put it.

There are two steps the first time:

  1. Run SignallingWebServer\platform_scripts\cmd\setup.bat. It downloads a private copy of Node and coturn. They are deliberately omitted from the repository, so nothing starts until you do this.

  2. Start the server with SignallingWebServer\platform_scripts\cmd\start_with_stun.bat.

This provides a running server with Epic’s defaults. It is enough to prove the pieces can talk to each other, but it is not what you want on a real kiosk.

The flags that matter

Everything a kiosk needs is a command-line flag on that same script. Rather than describe them twice, we ship the launcher we use ourselves: PromethistLinkPixelStreaming/Samples/Examples/signalling_server.bat.

It consists almost entirely of comments, which explain why each flag is there:

  • --peer_options_file turn.json — points both the browser and Unreal at your TURN relay. See Do you need a TURN relay? before assuming you need one.

  • --turn_secret_file — mints fresh TURN credentials per connection instead of a shared password.

  • --player_token_file — refuses viewers who do not present a token. See Locking the control channel.

  • --max_players 1 — a kiosk has one screen.

  • --media_proxy — serves the agent’s images through the server, resized and paced. Without it, the first seconds of a session can arrive with the video lagging the audio.

  • --homepage — which page the server serves.

Start from that file rather than Epic’s defaults, and delete what you do not need.

What order, and how to tell it worked

Start the signalling server first, then Unreal. Unreal retries, so the reverse order also works, but this way the logs read in the order things happened.

The server prints its listening ports as soon as it starts — one for the Unreal streamer, one for viewers. When Unreal connects, the server logs the streamer arriving. If you never see that line, the fault lies between Unreal and the server, and no amount of browser reloading will fix it.

If a browser connects and gets audio but no picture, or a picture that never arrives, the introduction worked but the media path failed. That is the TURN relay question, not a signalling problem.

Two files you create yourself, and never commit

The launcher looks for both files beside itself, quietly skipping the feature if either is missing. This silence is deliberate, but it means a missing file looks like a fault:

  • turn_secret.txt — the shared secret, matching static-auth-secret on your TURN server. Without it, the relay refuses every allocation, and behind symmetric NAT you get signalling that connects and video that never arrives.

  • player_token.txt — who may open the stream at all. Leave it out for a public demo.

Keep both files out of source control. Create them per machine.

Or: the signalling server in the cloud

Everything above runs on the kiosk. The alternative moves the signalling server onto a small Linux server you rent, ideally the one already running your TURN relay. The kiosk keeps one outgoing, encrypted SSH connection open to it, and Unreal reaches the server through that. Viewers only ever talk to the cloud server.

What you gain:

  • The kiosk accepts no incoming connection and viewers never learn its address, so nothing has to be opened on the network it sits on.

  • No ngrok. The page has your own name and certificate, on port 443 only.

  • It heals itself: the kiosk redials within seconds, Unreal reconnects on its own, and the server forgets a dead kiosk within a minute.

What it costs:

  • A server to run and keep updated, and a DNS name pointing at it.

  • All video passes through your relay, so you pay for its traffic: about 3.6 GB per hour at 8 Mbit/s.

  • One streaming PC per server. With two connected, the page cannot tell which one to show.

Choose it when the kiosk sits on a network you do not control or cannot open — a customer’s site, an office behind a strict firewall, a home connection — or when its address must stay private. If the kiosk has a public address behind a firewall you manage, the setup above is simpler.

The scripts are in PromethistLinkPixelStreaming/Samples/Examples: streamer_tunnel.bat for the kiosk, and the Cloud_Signalling folder for the server, whose README.md walks through the first deployment.