feat: switch from ttyd to real kitty via Xpra HTML5

Replaced the tmux+ttyd web terminal with actual kitty running through
Xpra's HTML5 streaming. Full GPU rendering, native kitty tabs/splits,
persistent sessions, and multi-client support.
This commit is contained in:
Mortdecai
2026-03-26 18:32:12 -04:00
parent 94eb19aa76
commit 8f3f2cae4c
5 changed files with 170 additions and 206 deletions
+88 -96
View File
@@ -1,137 +1,129 @@
# kitty-web
Mobile-first web terminal powered by [ttyd](https://github.com/tsl0922/ttyd) + [tmux](https://github.com/tmux/tmux). One persistent tmux session, multiple tabs, accessible from any browser. Designed for phones and tablets.
Run the real [kitty terminal](https://sw.kovidgoyal.net/kitty/) in your browser. Mobile-friendly, GPU-accelerated, with full tab and split support.
Powered by [Xpra](https://xpra.org/) — serves kitty as an HTML5 application via its built-in web client. This is not a terminal emulator in JavaScript; it's the actual kitty running on your server, streamed to your browser.
## Features
- **Single persistent session** — one tmux session shared across all connected clients
- **Mobile touch toolbar** — on-screen buttons for common shortcuts (new tab, ^C, ^D, Esc, arrows, split panes, etc.)
- **Text selection mode** — tap `Sel` to enter selection mode, long-press to select and copy text, tap `Done` to resume typing
- **Push notifications** — send browser notifications from any terminal command
- **PWA installable** — add to home screen for an app-like experience
- **Dark theme** — styled for dark-mode terminals with orange accents
- **Real kitty** — GPU rendering, ligatures, image protocol, all of it
- **Kitty tabs and splits** — native `ctrl+shift+t`, splits, layouts
- **Persistent session** — close the browser, reconnect later, everything is still there
- **Multi-client** — multiple browsers can view/interact with the same session
- **Mobile-friendly** — Xpra's HTML5 client handles touch input, keyboard, and scaling
- **Push notifications** — optional notification API for long-running commands
## Architecture
```
Browser -> Caddy (HTTPS + Auth) -> ttyd (port 7681) -> tmux session
-> notify-server (port 7682) -> /api/notifications
Browser -> Caddy (HTTPS + Auth) -> Xpra HTML5 (port 7681) -> kitty
```
- **ttyd** serves the terminal UI with a custom index page that loads `toolbar.js`
- **toolbar.js** injects the mobile toolbar (shortcut buttons, selection mode) into the page at runtime
- **notify-server.py** provides a simple HTTP endpoint for push notifications
- **kitty-notify** is a CLI command to trigger notifications from scripts
Xpra runs kitty inside a virtual X display (Xvfb) and streams the rendered output to browsers via WebSocket. The HTML5 client handles input, clipboard, and display scaling.
## Quick Start
### Prerequisites
- Debian/Ubuntu (tested on Debian 13 Trixie)
- kitty (`apt install kitty`)
- Xpra (`https://xpra.org/` — add their repo for latest version)
### Install
```bash
sudo ./install.sh
# Add Xpra repo (Debian example)
curl -sL https://xpra.org/xpra.asc | sudo tee /usr/share/keyrings/xpra.asc
echo "deb [signed-by=/usr/share/keyrings/xpra.asc] https://xpra.org/ $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/xpra.list
sudo apt update && sudo apt install -y xpra kitty
# Create a service user (optional)
sudo useradd -m -s /bin/bash rdp
# Install systemd service
sudo cp systemd/kitty-web.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now kitty-web
```
This installs ttyd, tmux, systemd services, and the notification system. The terminal will be available at `http://YOUR_IP:7681`.
### Manual Start
```bash
xpra start --bind-ws=0.0.0.0:7681 \
--start="kitty" \
--html=on \
--sharing=yes \
--no-daemon
```
Then open `http://YOUR_IP:7681` in a browser.
### Configuration
Set environment variables before running the installer:
Edit `systemd/kitty-web.service` to customize:
| Variable | Default | Description |
|----------|---------|-------------|
| `KITTY_USER` | `rdp` | System user that owns the tmux session |
| `TTYD_PORT` | `7681` | Port for ttyd web terminal |
| `NOTIFY_PORT` | `7682` | Port for notification API |
| `FONT_SIZE` | `18` | Terminal font size (optimized for mobile) |
| Option | Description |
|--------|-------------|
| `--bind-ws=HOST:PORT` | WebSocket listen address |
| `--start="CMD"` | Application to launch (default: `kitty`) |
| `--sharing=yes` | Allow multiple clients to connect |
| `--readonly=no` | Allow keyboard/mouse input |
### Reverse Proxy
### Reverse Proxy (Caddy)
See `caddy-example.conf` for a complete Caddy v2 configuration with authentication. The setup supports OAuth2 Proxy, Authentik, or Authelia for access control.
Key requirements for the reverse proxy:
- WebSocket support (ttyd uses WebSockets for terminal I/O)
- Serve `/toolbar.js`, `/manifest.json`, `/icon-*.png` as static files
- Proxy `/api/*` to the notification server (port 7682)
- Proxy everything else to ttyd (port 7681)
## Mobile Toolbar
The toolbar appears automatically on screens narrower than 900px. Buttons:
| Button | Action | tmux Key |
|--------|--------|----------|
| **+Tab** | New tab | `Ctrl-A c` |
| **Next** | Next tab | `Ctrl-A n` |
| **Prev** | Previous tab | `Ctrl-A p` |
| **^C** | Interrupt | `Ctrl-C` |
| **^D** | EOF / logout | `Ctrl-D` |
| **Clr** | Clear screen | `Ctrl-L` |
| **Esc** | Escape key | `Escape` |
| **Tab** | Tab completion | `Tab` |
| **Up/Down** | History navigation | Arrow keys |
| **Sel** | Toggle text selection mode | — |
| **Spl** | Split pane vertically | `Ctrl-A %` |
| **Pane** | Cycle between panes | `Ctrl-A o` |
| **Kill** | Kill current pane/tab | `Ctrl-A x` |
## Push Notifications
Send notifications from any terminal session:
```bash
# Direct message
kitty-notify "Build complete!"
# Pipe output
echo "Deploy finished" | kitty-notify
# Use in scripts
make build && kitty-notify "Build succeeded" || kitty-notify "Build FAILED"
```
terminal.example.com {
# Add your auth here (OAuth2 Proxy, Authentik, etc.)
reverse_proxy YOUR_SERVER:7681
}
```
Notifications appear as browser push notifications on mobile. Tap the bell icon in the terminal UI to enable them. Notifications expire after 30 seconds.
WebSocket support is required. Caddy handles this automatically. See `caddy-example.conf` for a full example with authentication options.
## tmux Keybindings
### Kitty Config
The included tmux config uses `Ctrl-A` as the prefix (easier on mobile than the default `Ctrl-B`):
Place your kitty config at `~/.config/kitty/kitty.conf` for the service user. See `config/kitty.conf` for a dark-themed example.
| Key | Action |
|-----|--------|
| `Ctrl-A c` | New window/tab |
| `Ctrl-A n` / `Ctrl-A p` | Next / previous window |
| `Ctrl-A %` / `Ctrl-A "` | Split vertical / horizontal |
| `Ctrl-A o` | Cycle panes |
| `Ctrl-A x` | Kill pane |
| `Alt-1` through `Alt-5` | Jump to window 1-5 |
| `Alt-Left` / `Alt-Right` | Previous / next window |
| `Alt-t` | New window |
| Mouse scroll | Scroll through history |
## Optional: Push Notifications
The `notify-server.py` and `kitty-notify` command provide a simple browser notification system:
```bash
# Install
sudo cp notify-server.py /opt/kitty-web/
sudo cp kitty-notify /usr/local/bin/
sudo cp systemd/kitty-notify.service /etc/systemd/system/
sudo systemctl enable --now kitty-notify
# Usage
kitty-notify "Build complete!"
echo "done" | kitty-notify
```
Requires proxying `/api/*` to port 7682 — see `caddy-example.conf`.
## Files
```
kitty-web/
toolbar.js # Mobile toolbar (injected into ttyd page)
notify-server.py # Push notification HTTP API
kitty-notify # CLI notification command
manifest.json # PWA manifest
icon-192.png # PWA icon (192x192)
icon-512.png # PWA icon (512x512)
install.sh # Installer script
caddy-example.conf # Reverse proxy configuration example
README.md
LICENSE
install.sh # Automated installer
caddy-example.conf # Reverse proxy config template
notify-server.py # Push notification HTTP API (optional)
kitty-notify # CLI notification command (optional)
manifest.json # PWA manifest
icon-192.png # PWA icon
icon-512.png # PWA icon
config/
tmux.conf # tmux configuration (dark theme, mobile-friendly)
tmux.conf # tmux config (for optional tmux-inside-kitty usage)
kitty.conf # Kitty terminal config (dark theme)
systemd/
ttyd-kitty.service # ttyd systemd unit
kitty-web.service # Xpra + kitty systemd unit
kitty-notify.service # Notification API systemd unit
```
## Requirements
- Linux (Debian/Ubuntu tested)
- tmux
- Python 3 (for notification server)
- [ttyd](https://github.com/tsl0922/ttyd) (installed automatically)
- Caddy, nginx, or another reverse proxy (for HTTPS and auth)
## License
MIT