View and control remote terminals from your browser with end-to-end encryption
- Zero-knowledge sharing -- your terminal is end-to-end encrypted (AES-128-GCM). The server is a blind relay that never sees your data.
- One command to share -- run
termpair share, send the link. Anyone with the link watches your terminal live in their browser. - Let others type -- viewers can type in your terminal from the browser, or set
--read-onlyto keep them watching. - Public or private -- private sessions are encrypted and link-only. Public sessions (
--public) are listed on the landing page for anyone to discover and watch. - Survive server restarts -- if the server goes down, both sides automatically reconnect and resume where they left off.
- Single binary, no deps -- one static binary bundles the server, client, and web frontend. No Node, no Python, no Docker required.
- Works anywhere -- Linux, macOS, Windows. Share any terminal app: your shell, vim, htop, Claude Code, anything with a TTY.
curl -fsSL https://raw.githubusercontent.com/cs01/termpair/main/install.sh | sh
Installs to ~/.local/bin. Customize with environment variables:
INSTALL_DIR=/usr/local/bin sh # custom install directory
VERSION=v1.2.0 sh # specific version
Download a prebuilt binary from the releases page. Available for Linux (x86_64, aarch64), macOS (x86_64, Apple Silicon), and Windows (x86_64).
git clone https://github.com/cs01/termpair.git
cd termpair/termpair-rs
cargo build --release
cp target/release/termpair ~/.local/bin/
Start the server:
termpair serve
Share your terminal:
termpair share
This prints a URL containing a unique terminal ID and encryption key. Share it with whoever you want to give access. Anyone with the link can access your terminal while the session is running.
By default, termpair share runs your $SHELL. The server multicasts terminal output to all connected browsers.
┌─────────────────┐ ┌─────────────────┐
│ │ encrypted terminal output │ │
│ Terminal │───────────────────────────────────▶│ Browser(s) │
│ (termpair │ ┌───────────────┐ │ (xterm.js + │
│ share) │◀────────│ Server │─────────▶│ Web Crypto) │
│ │ │ (blind relay) │ │ │
│ - forks pty │ encrypted browser input │ - decrypts │
│ - encrypts I/O │ │ never sees │ │ output │
│ - manages keys │ │ plaintext │ │ - encrypts │
│ │ └───────────────┘ │ input │
└─────────────────┘ └─────────────────┘
The server is a blind relay -- it routes encrypted WebSocket messages without access to keys or plaintext. The terminal client forks a pty, encrypts all output with AES-128-GCM, and decrypts browser input. Browsers decrypt and render with xterm.js + Web Crypto API.
Three AES-128-GCM keys are created per session:
- Output key -- encrypts terminal output before sending to the server
- Input key -- encrypts browser input before sending to the server
- Bootstrap key -- delivered via the URL hash fragment (never sent to the server), used to securely exchange keys #1 and #2
Keys are rotated after 2^20 messages. IVs are monotonic counters to prevent reuse.
The browser must be in a secure context (HTTPS or localhost).
upstream termpair_app {
server 127.0.0.1:8000;
}
server {
server_name myserver.com;
listen 443 ssl;
ssl_certificate fullchain.pem;
ssl_certificate_key privkey.pem;
location /termpair/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://termpair_app/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}# /etc/systemd/system/termpair.service
[Unit]
Description=TermPair terminal sharing server
After=network.target
[Service]
ExecStart=/usr/local/bin/termpair serve --port 8000
Restart=on-failure
RestartSec=1s
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable termpair.service
sudo systemctl restart termpair
Generate a self-signed certificate:
openssl req -newkey rsa:2048 -nodes -keyout host.key -x509 -days 365 -out host.crt -batch
Then pass it to the server:
termpair serve --certfile host.crt --keyfile host.key
$ termpair serve [OPTIONS]
-p, --port <PORT> port to listen on [default: 8000]
--host <HOST> host to bind to [default: localhost]
-c, --certfile <CERTFILE> path to SSL certificate for HTTPS
-k, --keyfile <KEYFILE> path to SSL private key for HTTPS
$ termpair share [OPTIONS]
--cmd <CMD> command to run [default: $SHELL]
-p, --port <PORT> server port [default: 443]
--host <HOST> server URL [default: https://chadsmith.dev/termpair]
-r, --read-only prevent browsers from typing
-b, --open-browser open the share link in a browser
--public public session (no encryption, read-only)
sharemyclaude -- share your Claude Code session with a browser. Built on termpair, with a public relay server so you can share instantly without self-hosting.