Stage Recorder Deployment
Stage Recorder — Deployment: Recorder and Video Portal
Covers: Windows and Linux · recorder and portal on one machine or on two · MQTT broker · reminder mails
Components
A complete installation has up to four parts. Only the recorder is mandatory.
| Part | What it is | Runs on |
|---|---|---|
| Recorder | the application: capture, playback, scheduling, file browser, OSC/MQTT/VNC | the machine with the capture hardware and the license dongle |
| Video portal | an unmodified PeerTube instance with the Stage Recorder plugin and theme, as three Docker containers (PeerTube, PostgreSQL, Redis) | the same machine, or any Linux machine, NAS or VM that runs Docker |
| MQTT broker | optional; needed only for MQTT remote control and status publishing | anywhere on the LAN, often the portal host |
| Mail server | optional; an existing SMTP account for the reminder digest | not deployed, only configured |
The recorder does not have to be reachable from the portal. Every transfer, including the portal's Bring back to recorder button, is initiated by the recorder: it uploads, it downloads, and it polls the portal every 30 s for fetch requests. The portal may therefore sit behind a firewall or a NAT the recorder cannot be reached through, and the recorder may sit behind one as well.
Choosing a topology
| Topology | When | Trade-offs |
|---|---|---|
| A. One machine — recorder and portal on the recording PC | one venue, a few viewers on the same LAN, no spare hardware | simplest to set up; transcoding competes with real-time capture, so limit it (see below); Windows needs Docker Desktop with WSL 2 |
| B. Two machines on the LAN — recorder plus a Linux portal host (NUC, NAS, VM) | the recommended configuration for a venue | the recording machine is not affected; the portal host performs the transcoding; each side needs only a host name and a port |
| C. Portal off site — a VPS or a server in the company network, reached over the internet | several venues share one portal, or viewers watch from outside the venue | put a TLS reverse proxy in front; uploads take the venue's upstream bandwidth, so use the transfer window; the recorder still needs no inbound port |
Rules that hold for every topology:
- The portal is addressed by exactly one name —
PEERTUBE_WEBSERVER_HOSTNAMEin its.env. PeerTube answers the login endpoint only when theHostheader matches it; an IP address or a second alias getshttp 403. Pick a name that every browser and the recorder can resolve (DNS, mDNS or ahostsentry), and use that same name in the recorder's/Portal/URL. PEERTUBE_SECRETis generated once and never changed after the instance has data.- Keep the portal on plain HTTP only inside a trusted LAN. Any instance reachable from outside the LAN is placed behind a reverse proxy with TLS (topology C).
Recommendation: B for a venue, C when the portal serves more than one venue. A is adequate as a starting point and can be separated later: the recorder only knows the portal as a URL, so moving the stack means copying the docker/ directory with its volumes/ to the new host and changing /Portal/URL.
Network reference
Inbound ports the recorder opens (all configurable in the settings tree):
| Port | Protocol | Purpose | Key |
|---|---|---|---|
| 7000 | UDP | OSC commands | /System/IO/OSC/Receive Port
|
| 5900 | TCP | VNC remote UI, only with VNC on | /System/IO/VNC/Port, /System/IO/VNC/Use VNC
|
| 5800 | TCP | browser viewer and the links in the reminder mails, only with VNC on; 0 switches it off |
/System/IO/VNC/Web Port
|
Outbound connections the recorder makes:
| Target | Port | Purpose | Key |
|---|---|---|---|
| MQTT broker | 1883 TCP | commands in, status out | /System/IO/MQTT/Broker Address, /System/IO/MQTT/Use MQTT
|
| portal | 9000 TCP (443 behind a proxy) | uploads, downloads, fetch-request polling | /Portal/URL
|
| SMTP server | 587 TCP | reminder digest | /Mail/Server, /Mail/Port
|
Inbound port the portal opens: 9000 TCP (PEERTUBE_WEBSERVER_PORT), or 80/443 on the reverse proxy in topology C.
The MQTT default broker.hivemq.com is a public broker. Either switch MQTT off or point it at a broker of your own (section "MQTT broker") before the system goes live.
Part 1 — The recorder on Windows
1. Install. Run Tourette_Stage_Recorder_5.0.<build>.exe from tools/installer/. It installs the application to C:\Program Files\Tourette Stage Recorder 5.0\ with the FFmpeg libraries, ffmpeg.exe (used to render H.264 proxies for the portal), the dongle library, the files\ tree, the video portal deployment under portal\ (Part 3) and this guide as deployment.pdf, and registers the .mxr / .mxr_syncset file types. A desktop and a start-menu shortcut are created.
2. Dongle. Plug in the Rockey4ND license dongle before the first start. Without it the application starts with no channels and a warning.
3. First start. Start from the shortcut. The settings file is created at %APPDATA%\mxw_recorder\mxr_recorder.ini; recordings go to Documents\TouretteStageRecorder until /Recording/Root says otherwise. Every key mentioned in this document appears in the configuration tree of the Settings tab after the first run.
4. Recording root. Set /Recording/Root to the recording disk. If that path is a mount that may be absent, note that a missing root at record start does not prevent the recording: the default root is used instead and the main tab shows a red banner.
5. Firewall. Windows asks on the first start; allow the application on the Private profile. If the rig's network is classified Public, either reclassify it or add inbound rules by hand for UDP 7000 and, with VNC on, TCP 5900 and 5800:
netsh advfirewall firewall add rule name="MXW Recorder OSC" dir=in action=allow protocol=UDP localport=7000 netsh advfirewall firewall add rule name="MXW Recorder VNC" dir=in action=allow protocol=TCP localport=5900,5800
6. Proxies for the portal. With /Portal/Use Upload Original off (the default) every take that is not H.264 is encoded to an H.264 proxy with h264_nvenc before the upload; that needs an NVIDIA GPU. Without one the proxy step fails with T003/T004 and the original goes up instead. /System/FFmpeg Path overrides the lookup (ffmpeg.exe next to the executable is found on its own).
7. Restart policy. Settings under /System are read once at startup. After changing any of them use the red Save & Restart button.
Part 2 — The recorder on Linux
The recorder is installed from a Debian package built for Ubuntu 24.04 (amd64), tourette-stage-recorder_<version>_amd64.deb (tools/installer/linux/build_deb.py in the source tree builds it from a Linux build of the application).
1. Install.
sudo apt install ./tourette-stage-recorder_<version>_amd64.deb
apt resolves the dependencies (wxWidgets 3.2, GTK 3, ALSA, libcurl) and installs ffmpeg as a recommendation; it renders the H.264 proxies for the portal. The package places:
| Path | Content |
|---|---|
/opt/TouretteStageRecorder/ |
the application mxw_recorder, the files/ tree, the video portal deployment under portal/ (Part 3)
|
/usr/bin/tourette-stage-recorder |
the launcher; it sets the working directory and starts the application |
/usr/share/applications/tourette-stage-recorder.desktop |
the entry in the applications menu |
/usr/share/doc/tourette-stage-recorder/deployment.pdf |
this guide |
2. License. The Linux build has no dongle support; it reads the license file. Copy mxr_license.lic to /opt/TouretteStageRecorder/ before the first start:
sudo cp mxr_license.lic /opt/TouretteStageRecorder/
3. First start. Start Tourette Stage Recorder from the applications menu, or tourette-stage-recorder from a terminal. The settings file is created at ~/.mxw_recorder/mxr_recorder.ini of the user who runs it; recordings go to ~/Documents/TouretteStageRecorder until /Recording/Root says otherwise. Every key mentioned in this document appears in the configuration tree of the Settings tab after the first run.
4. Recording root. Set /Recording/Root to the recording disk, as on Windows.
5. Firewall. With ufw:
sudo ufw allow 7000/udp # OSC sudo ufw allow 5900,5800/tcp # VNC and browser viewer, only with VNC on
6. Proxies for the portal. As on Windows, a take that is not H.264 is encoded to an H.264 proxy with h264_nvenc before the upload, which requires an NVIDIA GPU with its driver; without one the original is uploaded. The recorder finds ffmpeg at /usr/bin/ffmpeg; /System/FFmpeg Path overrides this.
7. Autostart. For a kiosk, start tourette-stage-recorder from the desktop session's autostart. The application needs a display and OpenGL; a system service without a session is not sufficient.
8. Restart policy. As on Windows, settings under /System are read once at startup; use Save & Restart after changing them.
Part 3 — The video portal
The portal is the same on Windows and Linux: Docker with the Compose plugin, and the portal/ directory that both installers place next to the application (C:\Program Files\Tourette Stage Recorder 5.0\portal\ on Windows, /opt/TouretteStageRecorder/portal/ on Linux; in the source tree it is tools/installer/portal/). Node.js is not needed on the host; the plugin is packed inside the image build.
The stack writes its database and media into docker/volumes/ next to its compose file, and its secrets into docker/.env. Neither belongs under the installation directory, which is read-only for the operator. Copy portal/ to a writable location first, on the machine that will run the portal:
cp -r /opt/TouretteStageRecorder/portal ~/portal # Linux xcopy /E /I "C:\Program Files\Tourette Stage Recorder 5.0\portal" %USERPROFILE%\portal (Windows)
The paths in this part refer to that copy. For a separate portal host (topology B or C), copy the directory to that machine.
3.1 Docker
- Linux (portal host or single machine): install Docker Engine and the Compose plugin from Docker's repository (
docker-ce,docker-compose-plugin), add the operator to thedockergroup, log in again. Enable the service so the stack comes back after a reboot:sudo systemctl enable docker. - Windows (single machine): install Docker Desktop with the WSL 2 backend and enable Start Docker Desktop when you sign in. Two properties of this configuration are relevant:
- WSL's mirrored networking mode makes the Linux side own the host's LAN address. A container can reach the Windows host only through
127.0.0.1, not through the LAN address. For this reason the portal never connects to the recorder; no configuration is required for this, and no connection from the portal to the recorder should be set up. - Transcoding runs inside WSL and competes with capture. Cap it in
%USERPROFILE%\.wslconfig(for examplememory=8GB,processors=4) and keepMXR_TRANSCODE_RESOLUTIONSto a single rendition.
- WSL's mirrored networking mode makes the Linux side own the host's LAN address. A container can reach the Windows host only through
3.2 Configure and start
In the copy of the portal directory:
cd ~/portal python3 build_portal.py --env --hostname portal.local --recorder-url http://recorder-pc:5800 cd docker
--env writes docker/.env from .env.example with fresh secrets. Open it and check:
| Key | Set it to |
|---|---|
PEERTUBE_WEBSERVER_HOSTNAME |
the one name the portal is reached by (see "Choosing a topology"); on a single machine localhost works for the recorder, but other browsers then need the machine's name — prefer the name
|
PEERTUBE_WEBSERVER_PORT, PEERTUBE_WEBSERVER_HTTPS |
9000 and false on the LAN; 443 and true behind a TLS proxy
|
PEERTUBE_ADMIN_EMAIL, PT_INITIAL_ROOT_PASSWORD |
the admin account; the setup logs in with this password on every start |
MXR_RECORDER_USER, MXR_RECORDER_PASSWORD, MXR_RECORDER_CHANNEL |
the recorder's account and channel; the same values go into the recorder's /Portal/User, /Portal/Password, /Portal/Channel
|
MXR_RECORDER_URL |
informational, shown in the plugin settings; no connection is made to it |
MXR_KEEP_ORIGINAL |
true when the recorder uploads originals (/Portal/Use Upload Original) and the disk can hold them; otherwise only renditions are kept
|
MXR_TRANSCODE_RESOLUTIONS |
720p on a single machine, 720p,1080p on a dedicated host
|
MXR_INSTANCE_NAME |
the name in the browser tab and in the portal's mails |
Then:
docker compose up -d docker compose logs -f peertube # wait for "mxr setup: done"
The setup step runs on every start and is idempotent: it installs or updates the plugin and the theme, creates the recorder user and channel, closes registration, sets the default privacy to internal (logged-in users only), configures transcoding and uploads the branding. Open http://<hostname>:9000 in a browser and log in as the recorder user once to confirm.
3.3 Offline portal host
Build the image on a machine with internet access and transfer it:
python3 build_portal.py --save mxr-peertube.tar # copy mxr-peertube.tar and the docker/ directory (with .env) to the host docker load -i mxr-peertube.tar docker compose up -d
3.4 TLS and the outside world (topology C)
Put a reverse proxy with a certificate in front of port 9000 and expose only 443. With Caddy the complete configuration is one block:
portal.example.org {
reverse_proxy 127.0.0.1:9000
}
In .env set PEERTUBE_WEBSERVER_HOSTNAME=portal.example.org, PEERTUBE_WEBSERVER_PORT=443, PEERTUBE_WEBSERVER_HTTPS=true; the proxy's address must be covered by PEERTUBE_TRUST_PROXY. In the recorder /Portal/URL becomes https://portal.example.org. /Portal/Use Insecure TLS is only for a self-signed certificate on a LAN, never for a public host.
3.5 Where the data lives, backup, updates
Everything is under docker/volumes/ of the portal directory on the host:
| Directory | Holds |
|---|---|
volumes/db/ |
PostgreSQL — videos, chapters, users, the plugin's records and fetch queue |
volumes/data/streaming-playlists/hls/<uuid>/ |
the transcoded renditions (what a fetch downloads when no original is kept) |
volumes/data/original-video-files/ |
uploaded originals, only with MXR_KEEP_ORIGINAL=true
|
volumes/data/thumbnails, previews, storyboards, captions, torrents |
derived assets |
volumes/config/ |
PeerTube's production configuration |
- Backup:
docker compose stop, copyvolumes/and.envtogether,docker compose start. Database and files belong together — a video row points at its files by uuid. - Move to another host: the same copy, then
docker compose up -dthere and a new/Portal/URLin the recorder if the name changed. - Update: install the new recorder version, copy its
portal/over the working copy (keepingdocker/volumes/anddocker/.env),python3 build_portal.py,docker compose up -d. The setup updates the plugin and theme when their version changed. - Disk: originals require the full take size per upload; renditions require approximately the proxy bitrate (
/Portal/Proxy Bitrate Mbit, default 12) times the duration. The recorder's own retention (/Storage/*) never touches the portal; deleting on the portal is done in its admin, and the recorder's Re-sync with portal button then drops those takes from its index.
Part 4 — Connect the recorder to the portal
In the recorder's Settings tab (password from /System/SettingsKey, default 123456):
| Key | Value |
|---|---|
/Portal/URL |
http://<PEERTUBE_WEBSERVER_HOSTNAME>:9000 — exactly the name from .env, no IP
|
/Portal/User, /Portal/Password |
MXR_RECORDER_USER / MXR_RECORDER_PASSWORD
|
/Portal/Channel |
MXR_RECORDER_CHANNEL, or empty for the user's default channel
|
/Portal/Privacy |
internal (default): visible to logged-in users only
|
/Portal/Use Upload Original |
on only together with MXR_KEEP_ORIGINAL=true
|
/Portal/Use Transfer While Recording |
off (default) keeps the upload bandwidth and the disk away from a running take |
/Portal/Transfer From Hour, /Portal/Transfer To Hour |
a window, e.g. 1 and 7 for nights; 0 and 24 means always
|
Save & Restart. Then verify the connection:
- Record a short take, load it in the player, press Publish to portal. The file browser's flags column runs through uploading n %; the log says
portal: published <name> -> <url>. - The Files tab's Portal view lists it after Reload. Open the portal page: title, tags and the markers as chapters are there.
- Delete the local file in the browser, press Fetch to local in the Portal view (or Bring back to recorder on the portal page): the file returns to its date folder, protected, with its markers.
If the login fails with http 403, the URL is not the configured host name. If the listing fails with T008, check the account and the channel name.
Part 5 — MQTT broker
Required only when show control or monitoring uses MQTT. Any MQTT 3.1.1 broker is suitable; Mosquitto is used in the examples below.
- Linux:
sudo apt install mosquitto, then in/etc/mosquitto/conf.d/lan.conf:
listener 1883 allow_anonymous true
sudo systemctl enable --now mosquitto. Restrict anonymous access to the LAN (bind the listener to the LAN interface, or add a password file for other clients); the recorder itself does not support broker authentication.
- Windows: the Mosquitto installer from mosquitto.org, the same two lines in
mosquitto.conf, installed as a service.
In the recorder: /System/IO/MQTT/Use MQTT on, /System/IO/MQTT/Broker Address = the broker's name or IP, /System/IO/MQTT/System ID unique per recorder when several share a broker. Save & Restart. The broker's log shows mxr-client-… connecting.
Part 6 — Reminder mails
The recorder sends one digest a day listing takes that crossed the warning age and those within a week of deletion, with a keep and a publish link per take. The links point at the recorder's web port, so they work only for people who can reach the recorder on port 5800.
| Key | Value |
|---|---|
/Mail/Use Reminders |
on |
/Mail/Server, /Mail/Port, /Mail/Use TLS |
the SMTP account, default port 587 with STARTTLS |
/Mail/User, /Mail/Password, /Mail/From |
its credentials and sender address |
/Mail/Recipients |
comma-separated |
/Mail/Recorder URL |
how recipients reach the recorder, default http://<hostname>:5800; must match the VNC web port
|
/Mail/Send Hour |
default 8
|
/System/IO/VNC/Use VNC must be on with a non-zero web port, otherwise N001 is logged and the links cannot be answered.
Checklists
Single machine, Windows (topology A)
- Installer, dongle, first start,
/Recording/Root - Docker Desktop with WSL 2,
.wslconfiglimits,MXR_TRANSCODE_RESOLUTIONS=720p build_portal.py --env --hostname <pc-name>,.envchecked,docker compose up -d, "mxr setup: done"/Portal/*in the recorder, Save & Restart, verification of the connection- Firewall: UDP 7000 in; TCP 9000 in for other viewers; TCP 5900/5800 in only with VNC
- Transfer window set to the hours without shows
Two machines (topology B)
- Recorder as in Part 1 or 2
- Portal host: Docker Engine enabled at boot,
build_portal.py --env --hostname <portal-name>,docker compose up -d - Name resolution for
<portal-name>on the recorder and on the viewers' machines /Portal/URL = http://<portal-name>:9000, verification of the connection- Backup plan for
volumes/and.env
Off site (topology C)
- Everything from B on the server
- Reverse proxy with TLS,
.envon 443/https,PEERTUBE_TRUST_PROXY /Portal/URL = https://…, transfer window for the venue's uplink- Only 443 open on the server; the recorder needs no inbound port at all