A small local terminal server that lets the browser act as a terminal window manager.
The Rust backend serves a single HTML page and forwards WebSocket traffic to an
independent PTY session. The frontend uses Xterm.js, reads a channel query
parameter, and asks the backend to open each new browser window as a separate
terminal session.
Files under static/ are embedded into the Rust binary at build time.
The frontend entrypoint is static/app.js, split into ES modules under
static/js/, with Alpine.js stores and components handling the browser UI
bindings.
- Browser terminal UI powered by Xterm.js
- Rust WebSocket backend using Axum
- Static assets embedded into the Rust binary
- Alpine.js UI bindings with frontend scripts split into ES modules
- One PTY session per WebSocket connection
?channel=<id>URL-based session identity- New-window button for opening a fresh terminal session in the current session's working directory
- Settings dialog for terminal font and font size
- Nerd Font loading via
@xterm/addon-web-fonts - Settings persisted in
localStorage - Live settings sync across open tabs via the browser
storageevent - Window title sync from Xterm title updates
- Dynamic document icon for Claude, Codex, OpenCode, Qoder, Amp, Cline, Copilot, Cursor, Kilo Code, and Kimi terminal titles
- Tailwind CDN for compact page styling
cargo runThe server opens the browser automatically. You can also open it manually:
http://127.0.0.1:3000/?channel=main
When the server listens on a loopback address such as 127.0.0.1 or
localhost and only allows loopback origins, Basic Auth is disabled by default.
When it listens on a non-loopback address or allows a non-loopback CORS origin,
the server prints Basic Auth credentials when it starts. The default username is
admin; if no fixed password is configured, a random password is generated for
that run.
Use a different port with:
cargo run -- --port 3100Bind to a different host, or allow a separate frontend origin:
cargo run -- --host 0.0.0.0 --port 3100 --cors-origin http://localhost:5173HOST, PORT, CORS_ORIGIN, and DANGEROUS_ALLOW_ALL_HOST environment
variables are also supported.
When --cors-origin is omitted, only loopback hosts and loopback origins on the
server port are allowed, such as http://127.0.0.1:3000 or
http://localhost:3000. The same origin policy is also applied to WebSocket
handshakes.
To allow arbitrary Host and Origin headers, pass the explicit dangerous
flag:
cargo run -- --dangerous-allow-all-hostBasic Auth remains enabled in this mode.
Use ~/.browser-terminalrc to pin a fixed Basic Auth password. A configured
password also enables Basic Auth when listening on a loopback address:
username = admin
password = change-this-password
user is accepted as an alias for username, and basic_auth_password is
accepted as an alias for password.
The server binds to 127.0.0.1 by default and is intended for local use. It
does not include TLS, so do not expose it directly to the public internet.
Shells start in the user's home directory. The PTY implementation uses
portable-pty, and the home directory is resolved with the cross-platform
dirs crate.
- Rust
- Axum
- Tokio
- portable-pty
- include_dir
- Alpine.js
- Xterm.js
- Xterm.js Web Fonts addon
- Tailwind CSS CDN
- LobeHub Icons static SVG CDN
- Nerd Fonts via jsDelivr