# WebSocket browser terminal · MAX25-Stack Remote operator terminal over WebSocket — same M25/1 session model as `max25-terminal`, via loopback proxy. ## Architecture ``` Browser (PHP + JS) → httpd reverse-proxy WS /max25-websocket/ws (TLS/wss at edge) → max25-ws-proxy 127.0.0.1:7326/max25 → max25d M25/1 TCP 127.0.0.1:7325 ``` WebSocket is **not** inside max25d (unlike hyBBX in-process WebSocket). The proxy forwards bytes without protocol translation. | Component | Path | |-----------|------| | Browser UI | `stacks/web/share/reverse-proxy/docroot/max25-websocket/` | | Session defaults | `/etc/max25/web-terminal.ini` (see `web-terminal.ini.example`) | | WebSocket proxy | `max25-ws-proxy` — config `web-proxy.ini` | | Primary CLI client | `max25-terminal` (unchanged) | ## Ports | Port | Service | |------|---------| | **7325** | max25d M25/1 TCP | | **7326** | WebSocket proxy (loopback; expose via httpd only) | ## Session defaults (`web-terminal.ini`) Copy `share/web-terminal.ini.example` to `/etc/max25/web-terminal.ini` or set `MAX25_WEB_TERMINAL_INI`. Values mirror max25d `[modem]` and `[devices] default`. Applied **per WebSocket session** on connect: | Key | Source | Meaning | |-----|--------|---------| | `device` | `[session]` or max25d `[devices] default` | One device per session (`SET DEVICE`) | | `callerid` | `[session]` or max25d `[modem]` | `SET CALLERID` if different from daemon | | `callid` | `[session]` or max25d `[modem]` | `SET CALLID` if different | | `ax25_ui` | `[session]` or max25d `[modem]` | `SET AX25_UI on\|off` | | `connect_on_start` | `[session]` | `CONNECT` after setup (default yes) | Optional `max25d_ini` under `[max25-web-terminal]` merges missing keys from live max25d config. ## Browser UI ### Header Live fields: **DEVICE**, **CALLERID**, **CALLID**, **ax25-ui**, **connected**. **Device dropdown** lists only ids returned by `GET DEVICES` from max25d. Unknown ids are rejected. ### Menu (F10 equivalent) Non-intrusive **Menu ▾** dropdown plus slash commands: | Command | Action | |---------|--------| | `/callerid [id]` | `SET CALLERID` | | `/callid [id]` | `SET CALLID` | | `/status` | `GET STATUS` | | `/send ` | `SEND` | | `/monitor [on\|off\|toggle]` | `MONITOR` | | `/connect` / `/disconnect` | `CONNECT` / `DISCONNECT` | | `/devices` | `GET DEVICES` (device overview) | | `/device ` | `SET DEVICE` (max25d id only) | | `/ax25_ui on\|off` | `SET AX25_UI` | | `/help` | Command list | Plain text (no `/`) is sent as **`SEND`** — same as `max25-terminal` Enter. ### Multiple sessions Each browser tab / WebSocket connection is an independent M25/1 client. Same `web-terminal.ini` defaults apply; per-session changes via `/` commands or dropdown. ## Deploy ```bash cmake --install $BUILD --prefix $PREFIX ``` Installs: - `$PREFIX/bin/max25-ws-proxy` - `$PREFIX/share/max25/web-proxy.ini.example` - `$PREFIX/share/max25/web-terminal.ini.example` - `$PREFIX/share/max25/reverse-proxy/` (httpd snippets + `docroot/`) ### systemd (proxy) Example: `share/max25/max25-ws-proxy.service.example` — run proxy on loopback; point httpd `WS` to `127.0.0.1:7326/max25`. ### httpd See `share/max25/reverse-proxy/{nginx,apache2,lighttpd}.conf.example` — proxy `WS /max25-websocket/ws` to the loopback WebSocket service. ## Local dev ```bash ./stacks/web/scripts/dev-server.sh ``` Open `http://127.0.0.1:8080/` — requires max25d on TCP 7325 and proxy on 7326. ## max25-terminal device overview CLI client F10 menu: | # | Action | |---|--------| | 8 | List DEVICES (`GET DEVICES` → RX pane) | | 7 | Change DEVICE (lists devices first, then prompt) | Device list at session start after `CONNECT`. ## Security - Proxy binds **loopback** by default — expose only through httpd + TLS. - Optional `tcp_password` in `web-proxy.ini` `[upstream]` when max25d `[network] tcp_password` is set. - No browser-side auth beyond site/httpd policy. ## Related | Doc | Topic | |-----|-------| | [MAX25-TERMINAL.md](MAX25-TERMINAL.md) | CLI operator client | | [MAX25-CLIENT.md](MAX25-CLIENT.md) | M25/1 protocol | | [stacks/web/README.md](../stacks/web/README.md) | Stack build / smoke |