Operations
Run WebTTY servers as services and keep production behavior predictable.
WebTTY servers are remote access processes. Treat production servers like other privileged service processes by choosing the operating-system account deliberately, keeping configuration reviewable, locking down private key files, and making startup and shutdown observable.
Service ownership
For lightweight WebTTY, starting the server from a user session is often enough. The server inherits that user's environment and permissions, and the default spawn execution mode runs commands as children of that process. When a lightweight server becomes a persistent operating-system service, select login mode, the login user, the rstream context, and retry behavior explicitly instead of relying on foreground defaults.
For registered servers, prefer a service account and a runtime config file. The service manager command stays stable while the config file carries WebTTY runtime settings:
rstream webtty server -v --webtty-config /etc/rstream/webtty/prod-shell.yamlThat separation keeps the service definition boring. The service manager starts one stable command, the runtime config describes WebTTY behavior, and private material stays in dedicated enrollment and identity files.
service manager
ExecStart=rstream webtty server -v --webtty-config /etc/rstream/webtty/prod-shell.yaml
|
v
WebTTY runtime config
registered server reference, transport, execution mode, labels
|
v
local enrollment and identity files
private material, strict local permissionsOn Linux, run the process under systemd. On macOS, use a LaunchAgent when the server belongs to a user session, or a LaunchDaemon when the machine-level service model is intentional. On Windows, use a service wrapper or scheduled task under the account that owns the rstream configuration and local WebTTY files.
Configuration surfaces
WebTTY has three local configuration surfaces. Keep them separate.
| Surface | Example | Purpose |
|---|---|---|
| rstream CLI config | ~/.rstream/config.yaml or --config <file> | Account, contexts, and project selection. |
| WebTTY runtime config | /etc/rstream/webtty/prod-shell.yaml | How this server process runs. |
| WebTTY enrollment and identity files | /etc/rstream/webtty/prod-shell.enrollment.yaml, /var/lib/rstream/webtty/identities/prod-shell.identity.json | Registered-server association and private key material. |
The runtime config may reference server.serverId when the default rstream home is correct, or server.serverEnrollment when a service account uses explicit file locations. Avoid copying private keys into general-purpose YAML files. Use host permissions or the host secret manager for identity material.
Choose the account used by sessions
The execution mode controls which local operating-system account runs commands. It is independent from the rstream account that authenticates the connection.
| Mode | Account used for commands | Typical use |
|---|---|---|
spawn | The account that runs the rstream webtty server process. | A foreground or lightweight server. |
login --login-user <local-username> | One fixed account that already exists on the server machine. | A persistent remote-administration service. |
login --allow-client-user | An existing account requested by each client. | A deliberately configured multi-user host. |
For example, if WebTTY runs on server-01 with --login-user webtty, every session runs as the local operating-system account webtty on server-01. The remote operator's name and rstream login do not change that account. Its identity, home directory, shell, groups, and permissions apply to the session.
Choose the account that should own remote commands, then pass its local username explicitly:
rstream webtty server -v --server-id <server-id> \
--execution-mode login --login-user webttyTo display the current local account on the machine that will run the server, use id -un on Linux or macOS, or $env:USERNAME in Windows PowerShell. Use that result only if the current account is the one that should own WebTTY sessions. rstream does not create operating-system accounts.
Registered servers default to login mode, but the default does not guess an account. They must set --login-user, set server.loginUser in the runtime config, or deliberately enable --allow-client-user. A fixed account that is missing or unusable makes the server fail before it starts listening.
Allow client-selected accounts only when the host is intentionally configured for them:
rstream webtty server -v --server-id <server-id> \
--execution-mode login --allow-client-userThe service manager should invoke the rstream binary directly. Avoid a chain of login shells whose only purpose is to locate the executable; set the executable path, PATH, context, and process logs in the service definition instead.
On Unix-like systems, choosing a different account applies its uid, primary gid, and supplementary groups and requires the server process to have the corresponding privileges. On Windows, login mode supports the same account that runs the WebTTY service; it does not switch to another Windows account.
Login sessions receive a deliberately limited administrative environment: PATH, locale and timezone values, and the selected user's identity, home, and shell. Linux adds the selected user's validated runtime directory and D-Bus socket when available; macOS preserves the current user's temporary directory and Core Foundation encoding; Windows includes the standard profile, system, temporary-directory, and PowerShell module variables. WebTTY does not silently forward SSH agent sockets, cloud credentials, or rstream tokens.
Preserve or remove host administration deliberately
Execution mode and service hardening solve different problems. login --login-user <local-username> selects the account and builds its login environment. It does not grant new host privileges, and it does not require the service to give up privileges that the selected account already has.
For an administrative WebTTY service, run the user service without NoNewPrivileges=true or PrivateTmp=true. The session then follows the account's existing sudoers policy exactly: an account without sudo remains unprivileged, while an authorized administrator can elevate according to the host configuration. Protect the rstream and WebTTY access path accordingly, because a WebTTY session for a sudo-capable account is an administrative entrypoint.
For a terminal that must never administer the host, use a dedicated non-sudo account and optionally add both directives to the user unit:
[Service]
NoNewPrivileges=true
PrivateTmp=trueNoNewPrivileges=true prevents the service and all descendant commands from gaining privileges through sudo, setuid, or setgid programs. In a user service, PrivateTmp=true can additionally create namespace ownership mappings that make privilege-changing tools reject root-owned configuration or executables. This is expected for the non-administrative profile; do not add these directives to a WebTTY service that is intended to manage the machine.
Neither profile allows a user service to switch sessions to arbitrary operating-system accounts. That design requires a deliberately privileged machine-level service, a review of --allow-client-user, and host authentication policy appropriate to the deployment.
File permissions
Identity files contain private keys. Enrollment files contain server enrollment material. Keep both readable only by the account that runs WebTTY.
A production layout can separate runtime config from key material:
/etc/rstream/webtty/prod-shell.yaml
/etc/rstream/webtty/prod-shell.enrollment.yaml
/var/lib/rstream/webtty/identities/prod-shell.identity.jsonWhen the organization already uses a host secret manager, store or mount private material through that system instead of making it part of a general-purpose config file.
macOS privacy permissions
macOS Transparency, Consent, and Control protects Desktop, Documents, Downloads, and other privacy-sensitive data independently of Unix file permissions. A LaunchAgent cannot silently accept those prompts, and tccutil can reset permissions but cannot grant them.
For a Mac intended for unattended remote administration, an operator can open Full Disk Access and reveal the running binary as follows. Resolve package-manager symlinks so the selected item is the executable macOS actually evaluates:
open 'x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles' && \
open -R "$(realpath "$(command -v rstream)")"The operator must add and enable rstream locally, then restart the WebTTY service. Full Disk Access is broader than Files & Folders and should only be used when the remote administration scope requires it. Fleet-wide pre-approval requires a supervised Mac and a Privacy Preferences Policy Control payload installed through device management. Camera, Microphone, Screen Recording, Automation, and Accessibility remain separate permission classes.
Homebrew uses a versioned Cellar path. TCC can therefore require the current
binary to be approved again after an upgrade even though /opt/homebrew/bin/rstream
still exists as a symlink. Reveal the new realpath, replace the obsolete Full
Disk Access entry, restart the LaunchAgent, and validate the protected folders
through WebTTY. Do not modify the TCC database directly; use a managed PPPC
profile when an administered fleet needs upgrade-stable pre-approval.
Process logs
Process logs make operational behavior observable without leaking terminal data. At startup, log the selected transport, execution mode, encryption state, filesystem-sidecar state, registered-server resolution, labels, and retry behavior. At shutdown, log whether the process stopped cleanly or because of an error.
Process logs must not include terminal payloads, private keys, local enrollment files, wrapped payload keys, or decrypt material. Managed session recordings are separate from process logs and are controlled by the registered server recording policy.
Online state
Registered server online state is derived from the associated live runtime tunnel and engine state. There is no separate WebTTY liveness object to configure or troubleshoot.
If a registered server is offline, it remains visible as a registered object. Operators can still see the server record, inspect policy, and access past recordings according to retention and permissions.
Protocol parsing
Managed WebTTY features require the engine to parse the WebTTY protocol. That parsing is what enables managed sessions, recordings, live attach, control transfer, and E2E routing where protocol metadata is visible but terminal payloads can remain encrypted.
Lightweight WebTTY over HTTP and labels remains useful for simple tunnel use. It is the right choice for temporary servers and demos that do not need persistent inventory, managed session logs, or live collaboration.
Filesystem sidecar
The filesystem sidecar adds file access next to command execution. It can list, read, upload, download, and write files under one configured root. Production deployments enable it only for the narrowest useful directory:
rstream webtty server -v --rstream --name shell --fs-root /srv/app --fs-read-onlyThe sidecar resolves paths under the configured root, but it is not a sandbox. Run WebTTY as a dedicated user and expose only the directory tree the workflow needs.
The sidecar is refused when WebTTY E2E is active. If terminal payloads require end-to-end encryption, do not expose a separate file surface that is not protected by the same model.
Failure behavior
Production WebTTY fails visibly when trust cannot be established. If --e2e is set and the resolved server is not E2E, the client fails. If a workspace-managed server key is not trusted, clients fail before sending terminal content. If a trusted workspace device is required and missing, clients fail during resolution. Unsupported crypto suites fail closed.
These failures are intentional. Remote shell tooling must not silently downgrade security because a local key file is missing, a server key changed, or a workspace device was not enrolled.