Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Browser Terminal

A fully interactive shell in the browser. Keystrokes travel over a WebSocket to a real PTY on the host, and output streams back into an xterm.js terminal. Drop it into a dev environment when you need an embedded terminal without shelling out of the browser.

It is safe to clone and run: the backend binds to loopback by default, so a fresh checkout is never exposed to your network.

Features

  • Real shell sessions (PowerShell on Windows, bash elsewhere) backed by a PTY
  • Full terminal emulation — colors, cursor, resizing — via xterm.js
  • Bidirectional streaming over a single WebSocket
  • Terminal size synced to the PTY so clears and line wraps render correctly
  • Loopback-only by default, with an optional shared-token gate for exposed setups
  • Zero configuration for local use

Tech stack

Layer Technology
Frontend Next.js, React, xterm.js
Backend Node.js, Express, ws, node-pty
Tooling Turborepo, TypeScript, ESLint, Prettier, Jest
Package manager pnpm

Quick start

Prerequisites:

  • Node.js >= 18 and pnpm
  • Native build tools for node-pty, which compiles on install:
    • Windows — the "Desktop development with C++" workload (Visual Studio Build Tools)
    • macOS — Xcode Command Line Tools (xcode-select --install)
    • Linuxmake, a C/C++ compiler (build-essential), and Python 3
git clone <your-repo-url>
cd recreated-browser-terminal
pnpm install
pnpm dev

Open the storefront at http://localhost:3002. The API runs on port 5001.

No environment setup is required for local use — every setting falls back to a safe default. See Configuration to expose the server or point the frontend at a different backend.

Architecture

Browser (xterm.js)  <──WebSocket──>  API (ws)  <──PTY──>  Shell
   apps/storefront                  apps/api           powershell / bash

The frontend renders xterm.js and forwards keystrokes as JSON frames. The API validates the WebSocket upgrade, spawns a PTY on connect, pipes shell output back to the client, and kills the shell when the socket closes.

Repository structure

apps/
  api/         Express + ws server that spawns the shell (node-pty)
  storefront/  Next.js app rendering the xterm.js terminal
packages/
  logger/      Shared isomorphic logger
  ui/          Shared React components
  eslint-config, typescript-config, jest-presets

Configuration

Local use needs no configuration. To customize, copy the example files:

cp apps/api/.env.example apps/api/.env
cp apps/storefront/.env.example apps/storefront/.env.local

API (apps/api/.env)

Variable Default Description
PORT 5001 Port the server listens on.
HOST 127.0.0.1 Bind address. Loopback keeps it off the network.
TERMINAL_TOKEN (unset) Shared secret required per connection. See Security.
ALLOWED_ORIGINS localhost:3002 origins Origins permitted to open a WebSocket.

Storefront (apps/storefront/.env.local)

Variable Default Description
NEXT_PUBLIC_TERMINAL_WS_URL ws://localhost:5001 WebSocket URL of the API server.
NEXT_PUBLIC_TERMINAL_TOKEN (unset) Must match TERMINAL_TOKEN when set.

Security

This server grants whoever connects a real shell running as the OS user that started it. Treat it as remote code execution and read this before exposing it.

  • Loopback by default. Out of the box the server is reachable only from the same machine. Keep it that way unless you have a specific reason not to.
  • Origin allowlist. WebSockets aren't bound by the browser's same-origin policy, so a malicious page could otherwise open a socket to your loopback server (cross-site WebSocket hijacking). The server rejects handshakes whose Origin isn't in ALLOWED_ORIGINS. Add your frontend's origin there when you change ports or hosts.
  • Exposing beyond localhost (HOST=0.0.0.0) requires setting TERMINAL_TOKEN to a strong secret. Every client must then present that token or the connection is rejected during the WebSocket handshake, before any shell is spawned. Generate one with openssl rand -hex 32.
  • The storefront token ships to the browser (NEXT_PUBLIC_), which is fine for local or trusted use but is not a substitute for per-user authentication in a multi-user deployment. Add real auth before deploying for a team.
  • .env and .env.local are gitignored — never commit real tokens.

Testing

pnpm test          # run all tests
pnpm lint          # lint every workspace
pnpm check-types   # type-check every workspace

License

Released under the MIT License.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages