Remote control CLI tools (Claude Code, GitHub Copilot, any terminal) from mobile/desktop via PWA.
Termote = Terminal + Remote
🇻🇳 Tiếng Việt | 🇨🇳 简体中文 | 🇯🇵 日本語 | 🇰🇷 한국어 | 🇪🇸 Español | 🇧🇷 Português (BR) | 🇫🇷 Français | 🇩🇪 Deutsch | 🇷🇺 Русский | 🇮🇩 Bahasa Indonesia
- Session switching: Multiple tmux sessions with create/edit/delete
- Session tabs: Horizontal tab bar for quick window switching
- Mobile-friendly: Virtual keyboard toolbar (Tab/Ctrl/Shift/arrows, expandable)
- Gesture support: Swipe for Ctrl+C, Tab, history navigation
- Command history: Recall previously sent commands with search
- Quick actions: Floating menu for common operations (clear, cancel, exit)
- Connection indicator: Real-time server status with auto-detect disconnect
- Update checker: Automatic new version notification from GitHub releases
- PWA: Installable to homescreen, offline-capable
- Persistent sessions: tmux keeps sessions alive
- Collapsible sidebar: Desktop UI with toggleable session sidebar
- Fullscreen mode: Immersive terminal experience
- Config persistence: Auto-save installation settings with AES-256 encrypted password
flowchart TB
subgraph Client["Client (Mobile/Desktop)"]
PWA["PWA - React + TypeScript"]
Gestures["Gesture Controls"]
Keyboard["Virtual Keyboard"]
end
subgraph Server["tmux-api Server :7680"]
Static["Static Files"]
Proxy["WebSocket Proxy"]
API["REST API /api/tmux/*"]
Auth["Basic Auth"]
end
subgraph Backend["Backend Services"]
ttyd["ttyd :7681"]
tmux["tmux"]
Shell["Shell"]
Tools["CLI Tools"]
end
Gestures --> PWA
Keyboard --> PWA
PWA --> Static
PWA <--> Proxy
PWA --> API
Auth -.-> Static & Proxy & API
Proxy <--> ttyd
API --> tmux
ttyd --> tmux --> Shell --> Tools
📖 New to Termote? Check out the Getting Started Guide for a complete walkthrough with examples.
./scripts/termote.sh # Interactive menu
./scripts/termote.sh install container # Container mode (docker/podman)
./scripts/termote.sh install native # Native mode (host tools)
./scripts/termote.sh link # Create 'termote' global command
make test # Run testsAfter
link, usetermotefrom anywhere:termote health,termote install native --lan
Tip: Install gum for enhanced interactive menus (optional, bash fallback available)
macOS/Linux:
# Download and prompt before install (defaults to native mode)
curl -fsSL https://raw.githubusercontent.com/lamngockhuong/termote/main/scripts/get.sh | bash
# Auto-install without prompt
curl -fsSL .../get.sh | bash -s -- --yes
# Download only (no install)
curl -fsSL .../get.sh | bash -s -- --download-only
# Auto-update with saved config
curl -fsSL .../get.sh | bash -s -- --update
# Install specific version
curl -fsSL .../get.sh | bash -s -- --version 0.0.4
# With explicit mode and options
curl -fsSL .../get.sh | bash -s -- --yes --container --lan
curl -fsSL .../get.sh | bash -s -- --yes --native --tailscale myhost
# Force new password (ignore saved config)
curl -fsSL .../get.sh | bash -s -- --yes --container --freshWindows (PowerShell):
Note: If script execution is disabled on your system, run this first:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
# Download and prompt before install (defaults to native mode)
irm https://raw.githubusercontent.com/lamngockhuong/termote/main/scripts/get.ps1 | iex
# Auto-install without prompt
$env:TERMOTE_AUTO_YES = "true"; irm .../get.ps1 | iex
# With explicit mode
$env:TERMOTE_MODE = "container"; irm .../get.ps1 | iex
# Auto-update with saved config
$env:TERMOTE_UPDATE = "true"; irm .../get.ps1 | iex# All-in-one (auto-generates credentials, check logs: docker logs termote)
docker run -d --name termote -p 7680:7680 ghcr.io/lamngockhuong/termote:latest
# With custom credentials
docker run -d --name termote -p 7680:7680 \
-e TERMOTE_USER=admin -e TERMOTE_PASS=secret \
ghcr.io/lamngockhuong/termote:latest
# Without auth (local dev only)
docker run -d --name termote -p 7680:7680 \
-e NO_AUTH=true \
ghcr.io/lamngockhuong/termote:latest
# With volume for persistence
docker run -d --name termote -p 7680:7680 \
-v termote-data:/home/termote \
ghcr.io/lamngockhuong/termote:latest
# Mount custom workspace directory
docker run -d --name termote -p 7680:7680 \
-v ~/projects:/workspace \
ghcr.io/lamngockhuong/termote:latest
# With Tailscale HTTPS (requires Tailscale on host)
docker run -d --name termote -p 7680:7680 \
-e TERMOTE_USER=admin -e TERMOTE_PASS=secret \
ghcr.io/lamngockhuong/termote:latest
sudo tailscale serve --bg --https=443 http://127.0.0.1:7680
# Access at: https://your-hostname.tailnet-name.ts.net# Download latest release
VERSION=$(curl -s https://api.github.com/repos/lamngockhuong/termote/releases/latest | grep tag_name | cut -d '"' -f4)
wget https://github.com/lamngockhuong/termote/releases/download/${VERSION}/termote-${VERSION}.tar.gz
tar xzf termote-${VERSION}.tar.gz
cd termote-${VERSION#v}
# Install (interactive menu or with mode)
./scripts/termote.sh install
./scripts/termote.sh install containergit clone https://github.com/lamngockhuong/termote.git
cd termote
./scripts/termote.sh install containerNote:
termote.shis the unified CLI supportinginstall(builds from source, uses pre-built artifacts when available),uninstall, andhealthcommands.
flowchart LR
subgraph Container["Container Mode"]
direction TB
C1["Docker/Podman"] --> C2["tmux-api :7680"] --> C3["ttyd :7681"] --> C4["tmux"]
end
subgraph Native["Native Mode"]
direction TB
N1["Host System"] --> N2["tmux-api :7680"] --> N3["ttyd :7681"] --> N4["tmux + Host Tools"]
end
User["User"] --> Container & Native
| Mode | Description | Use Case | Platform |
|---|---|---|---|
--container |
Container mode | Simple deployment, isolated env | macOS, Linux |
--native |
All native | Host tool access (claude, gh) | macOS, Linux |
| Flag | Description |
|---|---|
--lan |
Expose to LAN (default: localhost only) |
--tailscale <host[:port]> |
Enable Tailscale HTTPS |
--no-auth |
Disable basic authentication |
--port <port> |
Host port (default: 7680, Windows: 7690) |
--fresh |
Force new password prompt (ignore saved config) |
--update |
Auto-update with saved config |
--version <ver> |
Install specific version (with or without v) |
| Environment Variable | Description |
|---|---|
WORKSPACE |
Host directory to mount (default: ./workspace) |
TERMOTE_USER |
Basic auth username (default: auto-generated) |
TERMOTE_PASS |
Basic auth password (default: auto-generated) |
NO_AUTH |
Set to true to disable authentication |
Scripts auto-detect podman or docker — both work identically.
./scripts/termote.sh install container # localhost with basic auth
./scripts/termote.sh install container --no-auth # localhost without auth
./scripts/termote.sh install container --lan # LAN accessible
# Access: http://localhost:7680
# Custom workspace directory (mounted to /workspace in container)
WORKSPACE=~/projects ./scripts/termote.sh install container
WORKSPACE=/path/to/code make install-containerSecurity note: Avoid mounting
$HOMEdirectly — sensitive directories like.ssh,.gnupgwill be accessible in container. Mount specific project directories instead.
Use when you need access to host binaries (claude, git, etc):
# Linux
sudo apt install ttyd tmux
# Or: sudo snap install ttyd
./scripts/termote.sh install native
# macOS
brew install ttyd tmux go
./scripts/termote.sh install native
# Access: http://localhost:7680Uses tailscale serve for automatic HTTPS (no manual cert management):
# Tailscale only (default port 443)
./scripts/termote.sh install container --tailscale myhost.ts.net
# Custom port
./scripts/termote.sh install native --tailscale myhost.ts.net:8765
# Tailscale + LAN accessible
./scripts/termote.sh install container --tailscale myhost.ts.net --lan
# Access: https://myhost.ts.net (or :8765 for custom port)./scripts/termote.sh uninstall container # Container mode
./scripts/termote.sh uninstall native # Native mode
./scripts/termote.sh uninstall all # Everything# Option 1: Auto-update with saved config
curl -fsSL .../get.sh | bash -s -- --update
# Option 2: Re-run one-liner (compares versions, prompts before install)
curl -fsSL .../get.sh | bash
# Option 3: Manual update
./scripts/termote.sh uninstall [container|native]
git pull origin main # If installed from source
./scripts/termote.sh install [container|native] [--lan] [--tailscale ...]| Platform | Container | Native | CLI Script |
|---|---|---|---|
| Linux | ✓ | ✓ | termote.sh |
| macOS | ✓ | ✓ | termote.sh |
| Windows | termote.ps1 |
⚠️ Windows Support (Experimental): Windows support is currently in early stages and needs more testing. Container mode requires Docker Desktop, native mode requires psmux. Please report issues on GitHub.
Windows native mode uses psmux (tmux-compatible terminal multiplexer for Windows):
# Install psmux
winget install psmux
# Run Termote
.\scripts\termote.ps1 install native
.\scripts\termote.ps1 install container # Or container mode with Docker Desktop| Action | Gesture |
|---|---|
| Cancel/interrupt | Swipe left (Ctrl+C) |
| Tab completion | Swipe right |
| History up | Swipe up |
| History down | Swipe down |
| Paste | Long press |
| Font size | Pinch in/out |
Virtual toolbar provides: Tab, Esc, Ctrl, Shift, Arrow keys, and common key combos. Supports Ctrl+Shift combinations (paste, copy). Toggle between minimal and expanded mode for additional keys (Home, End, Delete, etc.).
termote/
├── Makefile # Build/test/deploy commands
├── Dockerfile # Docker mode (tmux-api + ttyd)
├── docker-compose.yml
├── entrypoint.sh # Docker entrypoint
├── docs/ # Documentation
│ └── images/screenshots/ # App screenshots
├── pwa/ # React PWA
│ └── src/
│ ├── components/
│ ├── contexts/
│ ├── hooks/
│ ├── types/
│ └── utils/
├── tmux-api/ # Go server
│ ├── main.go # Entry point
│ ├── serve.go # Server (PWA, proxy, auth)
│ └── tmux.go # tmux API handlers
├── scripts/
│ ├── termote.sh # Unix CLI (install/uninstall/health)
│ ├── termote.ps1 # Windows PowerShell CLI
│ ├── get.sh # Unix online installer (curl | bash)
│ └── get.ps1 # Windows online installer (irm | iex)
├── tests/ # Test suite
│ ├── test-termote.sh
│ ├── test-termote.ps1 # Windows tests
│ ├── test-get.sh
│ └── test-entrypoints.sh
└── website/ # Astro Starlight docs site
└── src/content/docs/ # MDX documentation
make build # Build PWA and tmux-api
make test # Run all tests
make health # Check service health
make clean # Stop containers
# E2E tests (requires running server)
./scripts/termote.sh install container # Start server first
cd pwa && pnpm test:e2e # Run Playwright tests
cd pwa && pnpm test:e2e:ui # Run with UI debuggerManual Testing: See Self-Test Checklist
- Check tmux:
tmux ls - Verify ttyd uses
-Aflag (attach-or-create)
- Check tmux-api logs:
docker logs termote - Verify ttyd is running on port 7681
- Ensure viewport meta tag is present
- Test on real device, not emulator
ps aux | grep ttyd # Check if ttyd is running
ps aux | grep tmux-api # Check if tmux-api is running
lsof -i :7680 # Verify port is in use- Default: localhost only - not exposed to LAN unless
--lanflag used - Basic auth enabled by default - use
--no-authto disable for local dev - Built-in brute-force protection - rate limiting (5 attempts/min per IP)
- Use HTTPS (Tailscale) for production
- Restrict to trusted networks/VPN
| Project | Description |
|---|---|
| GitHub Flex | A cross-browser extension (Chrome & Firefox) that enhances GitHub's interface with productivity features |
| TabRest | Chrome extension that automatically unloads inactive tabs to free memory |
MIT

