README
¶
b3tty
A better, browser-based terminal emulator.
Description
b3tty is a terminal emulator accessible entirely from your web browser. It is built using xterm.js which provides the terminal look and feel using Javascript and CSS. A small web server acts as a proxy between a psuedo terminal and the browser, which communicates over web sockets.
The terminal appearance and server can be configured with a configuration yaml file or command-line flags. Use the following command to display available server and terminal configuration options:
b3tty start --help
Features
- Customizable themes
- User defined profiles
- In-browser menu bar for switching themes and profiles at runtime
- Mouse support
- Auto-fit and resizing
- Background image support
- Inline image rendering
- URL links
- TLS support
Installation
NOTE: b3tty is not compatible with Windows.
Requirements
- A machine running Linux or MacOS.
- Your favorite web browser.
- git and familiarity with using git.
- Go version 1.25 or higher.
- bun — used to bundle the frontend TypeScript (
src/client/terminal.ts→src/assets/terminal.min.js)
Steps
- Open a new terminal window.
- b3tty does not ship as a binary. To install b3tty, clone the repo at https://github.com/cmmorrow/b3tty.git.
- In the root b3tty directory, run
make setupto install the bun dependencies. - After installing the bun dependencies, run
make buildto build b3tty for your system. This will first bundle the frontend JavaScript with bun, then compile the Go binary.- To format frontend source files before building, run
make format. To check formatting without modifying files (e.g. in CI), runmake format-check.
- To format frontend source files before building, run
- Make the b3tty binary executable with
chmod u+x b3tty. - Either copy the b3tty binary to a directory in your
$PATHsuch as /usr/local/bin, or create a symlink to the betty executable that is in your$PATH.
Usage
To start using b3tty, first make sure the executable works by running b3tty --version. To start the server with default options, run b3tty start. To see the available command-line options when starting the server, run b3tty start --help.
When the b3tty server is started, the output should look something like the output below:
> b3tty start
2024/10/14 00:49:12 [INFO ] http server started on http://localhost:8080/?token=2uzc8uFR7o5yUDy9
Log output uses level prefixes to make it easier to identify the nature of each message:
| Level | Color | Meaning |
|---|---|---|
[INFO ] |
Cyan | Normal operational messages |
[WARN ] |
Yellow | Rejected requests, recoverable conditions |
[ERROR] |
Red | Handler errors that did not stop the server |
[FATAL] |
Bold red | Unrecoverable errors — server exits immediately |
[DEBUG] |
Magenta | Verbose diagnostics, only shown with --debug |
Colors are shown when output is an interactive terminal and suppressed when piped or redirected.
First-run setup
When b3tty starts and no config file is found, it opens a theme selector in the browser instead of the terminal. The selector presents two built-in themes — Dark and Light — as visual previews, along with a No theme option to skip and configure one manually later.
Selecting a theme and clicking OK writes a conf.yaml file to ~/.config/b3tty/ with the chosen theme and immediately reloads the page to start the terminal. Choosing No theme skips config file creation and starts the terminal with the default xterm.js colors.
Once a config file exists, the setup page is never shown again. To return to the theme selector, delete or move the config file before restarting b3tty.
Configuration
b3tty can be configured via a yaml file specified on startup with the command b3tty start --config <file path>. Themes, profiles, font, font size, cursor blink, and terminal dimensions can only be specified in the config file. The config file is a yaml file and b3tty isn't picky about the file name or path, however, it's recommended to name the file b3tty.yaml and place it in ~/.config/b3tty.
When a config file is provided, b3tty validates it on startup before the server starts. Any unknown keys or fields with the wrong data type are reported with the line number where the problem occurs, and the server will not start until the config file is corrected. An example config yaml file can be seen below:
server:
tls: true
cert-file: "/path/to/cert/file"
key-file: "/path/to/key/file"
no-auth: false
no-browser: false
terminal:
font-family: "MesloLGS Nerd Font Mono"
font-size: 16
cursor-blink: false
rows: 30
profiles:
projects:
working-directory: "~/projects"
title: "Project Development"
shell: "/bin/fish"
theme: "my-theme"
themes:
my-theme:
black: "#14181d"
bright-black: "#404040"
red: "#eb5a4b"
bright-red: "#ee837b"
green: "#c6d173"
bright-green: "#dff06c"
yellow: "#e6ce6c"
bright-yellow: "#fdf699"
blue: "#5998db"
bright-blue: "#8ccdfa"
magenta: "#e68c8c"
bright-magenta: "#f3b7b9"
cyan: "#b2e7d4"
bright-cyan: "#b2e7d4"
white: "#fefefe"
bright-white: "#feffff"
foreground: "#dbdbdb"
background: "#15191e"
cursor: "#dbdbdb"
cursor-accent: "#15191e"
selection-foreground: "#000000"
selection-background: "#bad5fb"
Config file schema
The config file is a YAML document with five top-level keys. All keys are optional; omitting a section leaves those settings at their defaults.
server
Controls how the HTTP/WebSocket server is started.
| Key | Type | Default | Description |
|---|---|---|---|
tls |
bool | false |
Enable HTTPS/WSS. Requires cert-file and key-file. Changes the default port from 8080 to 8443 when true. |
cert-file |
string | "" |
Path to the TLS certificate file. Required when tls: true. |
key-file |
string | "" |
Path to the TLS private key file. Required when tls: true. |
no-auth |
bool | false |
Disable the access-token requirement. Reduces security posture — use only in trusted environments. |
no-browser |
bool | false |
Suppress automatically opening b3tty in the default browser on startup. |
port |
int | 8080 (8443 with TLS) |
The TCP port the server listens on. |
terminal
Controls the appearance and dimensions of the terminal.
| Key | Type | Default | Description |
|---|---|---|---|
font-family |
string | "monospace" |
The font used in the terminal. Multi-word names (e.g. "Fira Code") are supported. Note: the font must be available in the browser. |
font-size |
int | 14 |
Terminal font size in pixels. |
cursor-blink |
bool | true |
Whether the terminal cursor blinks. May not work in all browsers. |
rows |
int | 24 |
Number of terminal rows. |
columns |
int | 0 |
Number of terminal columns. 0 means auto-fit to the browser window width. |
theme
A string naming which entry under themes to activate, e.g. theme: "my-theme". Omit this key (or leave it empty) to use the default xterm.js colors.
themes
A map of named theme objects. Each key is an arbitrary theme name; the value is an object whose fields set terminal colors. All fields are optional strings; omitting a field keeps the xterm.js default for that color.
Color values must be a 3- or 6-digit CSS hex color (e.g. #fff or #14181d) or a letters-only CSS named color (e.g. red or cornflowerblue). Invalid values are rejected at startup.
| Key | Description |
|---|---|
foreground |
Default text color |
background |
Terminal background color |
cursor |
Cursor color |
cursor-accent |
Color of the character beneath the cursor |
selection-foreground |
Text color inside a selection |
selection-background |
Background color of a selection |
black |
ANSI color 0 |
bright-black |
ANSI color 8 (bright black / dark grey) |
red |
ANSI color 1 |
bright-red |
ANSI color 9 |
green |
ANSI color 2 |
bright-green |
ANSI color 10 |
yellow |
ANSI color 3 |
bright-yellow |
ANSI color 11 |
blue |
ANSI color 4 |
bright-blue |
ANSI color 12 |
magenta |
ANSI color 5 |
bright-magenta |
ANSI color 13 |
cyan |
ANSI color 6 |
bright-cyan |
ANSI color 14 |
white |
ANSI color 7 |
bright-white |
ANSI color 15 |
background-image |
Absolute path to a background image file on the server. When set, the container, terminal, and profile label backgrounds become 50% transparent so the image is visible behind the terminal text. |
profiles
A map of named profile objects. Each key is an arbitrary profile name used in the ?profile= query parameter. All fields are optional strings unless noted.
| Key | Type | Default | Description |
|---|---|---|---|
shell |
string | $SHELL |
Path to the shell binary to launch (e.g. /bin/fish). Must not contain spaces. |
working-directory |
string | $HOME |
The working directory for the shell. Supports ~ and ~/… expansion. |
title |
string | "b3tty" |
Browser tab title shown when this profile is active. |
commands |
list of strings | [] |
Commands to run in the pseudo terminal immediately after it opens. Each entry is a shell command string. |
root |
string | "/" |
The HTTP root path the server is mounted under. |
Themes
b3tty allows the look and feel of the browser-based terminal to be customized in the b3tty config file. Themes set the colors used by the terminal representation in the browser. Multiple themes can be defined in the config file. One theme is active at startup (set by the theme key), and additional themes can be switched to at runtime using the Themes menu in the menu bar without reloading the page. Selecting the already-active theme from the menu is a no-op and does not make a network request.
Each color value in a theme must be either a 3- or 6-digit CSS hex color (e.g. #fff or #14181d) or a letters-only CSS named color (e.g. red or cornflowerblue). Invalid color values are reported at startup and the server will not start until they are corrected.
In addition to the standard terminal palette colors, themes support two cursor-specific keys:
| Key | Description |
|---|---|
cursor |
Color of the terminal cursor |
cursor-accent |
Color of the character beneath the cursor |
Profiles
Profiles are used to set the default terminal behavior when navigating to the b3tty url. Profiles allow the working directory and shell to be used to be set when the pseudo terminal is started by the server. The title of the browser tab can also be set to make different profiles easier to distinguish from one another.
Unlike server, terminal, and theme settings, different profiles can be used by different browser tabs (or browser windows) when connecting to the b3tty server. To use a profile defined in the b3tty config file, add the profile= query parameter to the end of the b3tty url where the value is the name of the profile to use. When more than one profile is configured, a Profiles menu also appears in the menu bar; selecting a profile from it opens that profile in a new browser tab.
When a non-default profile is active, the profile's name (its key in the config file) is displayed in a small label below the terminal in the browser. The label uses the configured font family, font size, and theme foreground and background colors. The label is hidden when using the default profile.
When more than one profile is configured, the server lists them on startup with their URL, shell, and working directory:
2024/10/14 00:49:12 [INFO ] Configured profiles:
2024/10/14 00:49:12 [INFO ] projects http://localhost:8080/?token=2uzc8uFR7o5yUDy9&profile=projects (shell: /bin/fish | dir: ~/projects)
2024/10/14 00:49:12 [INFO ] work http://localhost:8080/?token=2uzc8uFR7o5yUDy9&profile=work (shell: /bin/zsh | dir: ~/work)
Profile names are sorted alphabetically and aligned for readability.
Menu bar
The menu bar is a browser-side control strip that appears at the top of the terminal page when at least one theme or one non-default profile is configured. It is always present in the DOM but completely hidden when there is nothing to show.
Appearance and interaction:
- When collapsed, only a thin trigger strip is visible at the top of the viewport.
- Hovering over the trigger slides the full menu bar into view.
- The menu bar automatically hides after 5 seconds of inactivity, or immediately when you click outside it.
- When the menu bar opens or closes, the terminal resizes to fill the available space.
Themes menu — The first item is always Select Theme…, which opens the Theme Selector overlay (see below). When themes are defined in the config file, a separator is shown followed by one item per theme; selecting a theme applies it immediately without reloading the page.
Profiles menu — visible when more than one profile is configured. Selecting a profile opens that profile in a new browser tab.
Colors — the menu bar uses the terminal's foreground color as its background and the terminal's background color as its text color, so it contrasts naturally with the active theme. When the theme is changed via the Themes menu, the menu bar colors update automatically to match.
Theme Selector
The Theme Selector is a full-page overlay that lets you browse and apply any built-in or user-defined theme from directly inside the terminal page, without editing the config file.
Opening the Theme Selector
Click Select Theme… at the top of the Themes menu in the menu bar. The overlay opens in front of the terminal — the PTY session continues running in the background and is never interrupted.
Browsing themes
The overlay displays a card for each available theme. Each card shows the theme name and a row of color swatches drawn from the theme's palette, so you can preview the color scheme before applying it.
Click a card to select it. The OK button becomes active once a card is selected.
Applying a theme
Click OK to apply the selected theme. The following happens immediately, without a page reload:
- The theme colors are applied to the terminal and the page background.
- If the selected theme is a built-in theme that was not previously in your config file, it is added to the
themessection of your config file and thethemekey is updated — so the selection persists across restarts.
Click Cancel at any time to close the overlay without making any changes.
Built-in themes
b3tty ships with the following built-in themes, all available in the Theme Selector without any config file changes:
| Theme | Style |
|---|---|
| b3tty-dark | Dark (default dark theme) |
| b3tty-light | Light (default light theme) |
| Catppuccin Mocha | Dark |
| Catppuccin Latte | Light |
| Dracula | Dark |
| Tokyo Night | Dark |
| Solarized Dark | Dark |
| Solarized Light | Light |
| One Light | Light |
| Gruvbox Light | Light |
User-defined themes from the themes section of the config file also appear in the Theme Selector alongside the built-in ones.
Debug mode
Passing --debug to b3tty start enables verbose diagnostic output:
b3tty start --debug
On the server side, additional [DEBUG] log lines are printed covering startup configuration, incoming request metadata, PTY dimensions, resize events, and WebSocket lifecycle events.
On the browser side, debug mode activates keypress round-trip timing. After each keypress, the time from when the input is sent to the server until xterm.js has finished rendering the PTY response is printed to the browser console:
[b3tty] keypress round-trip: 4.23ms
Debug mode has no effect on normal terminal operation and is intended for development and performance investigation only.
Architecture
b3tty uses a client/server model to enable the connection from a web browser to a pseudo terminal. When the server is started, a url where b3tty can be accessed from a web browser is displayed. When the url is visited through a web browser, the server renders an HTML page containing a JSON configuration object (window.B3TTY) with the terminal settings, then loads the frontend JavaScript bundle. The frontend determines the width of the browser window to know how many columns to use, then sends that size to the server and waits for confirmation before opening a WebSocket connection. The server then forks a new pseudo terminal process sized to those dimensions. All keyboard input is forwarded over the WebSocket to the pseudo terminal, and any output from the pseudo terminal is sent back and displayed on the page.
When the WebSocket connection closes unexpectedly (e.g. a network drop), a modal dialog is displayed in the browser informing the user that the connection has been closed. The terminal cursor is also hidden at this point. Dismissing the modal by clicking OK restores the page to its normal state. Clean closes — such as the shell process exiting normally — write [exited] to the terminal but suppress the dialog.
A word on security
Because b3tty is opening a connection from a web browser to a new psuedo terminal proccess as the user of b3tty's parent process, it's important to ensure the connection and access to the server are secure. For this reason, b3tty features several security features.
Origin check
The server will only allow connections from localhost or 127.0.0.1 as part of an origin check. This is to prevent opening a remote connection to a b3tty server. If access to remote machine is needed, run betty locally then SSH into the remove machine from b3tty.
Access token
By default, when the server starts, the url with a token of 24 randomly generated characters is provided and must be provided to access the b3tty client in the browser. This is to prevent a user without access to the terminal session where b3tty was started from guessing the url. This behavior can be disabled by passing the --no-auth flag at start up or setting the server.no-auth: true property in the b3tty config.
Each failed token validation incurs an exponential backoff delay before the 403 response is sent: 1s after the first failure, doubling on each subsequent attempt up to a maximum of 30s. The counter resets when a valid token is presented. Backoff is skipped entirely when --no-auth is set.
Content Security Policy
The server sets a Content-Security-Policy header on every page response. Scripts are restricted to same-origin files and a single per-request nonce used for the inline configuration block. 'wasm-unsafe-eval' is also permitted to support xterm.js's internal use of WebAssembly. Framing by other pages is blocked via frame-ancestors 'none'.
CSRF protection
The POST /size endpoint (used by the frontend to communicate terminal dimensions before opening the WebSocket) is protected against cross-site request forgery. Requests that carry a Sec-Fetch-Site header with a value other than same-origin are rejected. This header is set automatically by browsers and cannot be overridden by page scripts.
TLS
The connection between the client and server can be secured over TLS. Using TLS will change the protocol from http and ws to https and wss as well as change the default port from 8080 to 8443. TLS can be enabled by passing the --tls, --cert-file, and --key-file flags on start up or by setting the server.tls: true, server.cert-file: <file path>, and server.key-file: <file path> properties in the b3tty config.
Contributing
Pull requests are welcome. The following checks run automatically on every PR and must pass before merging:
- Test —
make testruns the full Go and bun test suites. - Format —
make format-checkverifies that all frontend TypeScript source files are formatted with prettier. Runmake formatlocally to fix any formatting issues before pushing.
When a PR that updates the VERSION file is merged into main, a git tag matching the new version number is created automatically.
Documentation
¶
There is no documentation for this package.