An open API service indexing awesome lists of open source software.

https://github.com/cs01/termpair

View and control terminals from your browser with end-to-end encryption πŸ”’
https://github.com/cs01/termpair

e2ee end-to-end-encryption fastapi pty rust terminal websocket xtermjs

Last synced: 14 days ago
JSON representation

View and control terminals from your browser with end-to-end encryption πŸ”’

Awesome Lists containing this project

README

          


TermPair



View and control remote terminals from your browser with end-to-end encryption




termpair share command



termpair browser view

## Why TermPair?

* **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-only` to 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.

## Installation

### Quick Install

```
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
```

### GitHub Releases

Download a prebuilt binary from the [releases page](https://github.com/cs01/termpair/releases). Available for Linux (x86_64, aarch64), macOS (x86_64, Apple Silicon), and Windows (x86_64).

### Build from Source

```
git clone https://github.com/cs01/termpair.git
cd termpair/termpair-rs
cargo build --release
cp target/release/termpair ~/.local/bin/
```

## Usage

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.

## How it Works

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ 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](https://xtermjs.org/) + [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API).

### Encryption

Three AES-128-GCM keys are created per session:

1. **Output key** -- encrypts terminal output before sending to the server
2. **Input key** -- encrypts browser input before sending to the server
3. **Bootstrap key** -- delivered via the [URL hash fragment](https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/hash) (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://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts) (HTTPS or localhost).

## Deployment

### NGINX

```nginx
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";
}
}
```

### systemd

```ini
# /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.target
```

```
sudo systemctl daemon-reload
sudo systemctl enable termpair.service
sudo systemctl restart termpair
```

### TLS

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
```

## CLI Reference

```
$ termpair serve [OPTIONS]
-p, --port port to listen on [default: 8000]
--host host to bind to [default: localhost]
-c, --certfile path to SSL certificate for HTTPS
-k, --keyfile path to SSL private key for HTTPS

$ termpair share [OPTIONS]
--cmd command to run [default: $SHELL]
-p, --port server port [default: 443]
--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)
```

## See Also

**[sharemyclaude](https://github.com/cs01/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.