A web-based terminal interface for interacting with tmux sessions. Features a retro CRT/Matrix aesthetic and tmux-style keyboard shortcuts.
- Web interface to send commands to tmux panes
- Live capture of pane output (polling every second)
- Window management (list, switch, create new)
- Multiple hosts through SSH, with host/session/window selection and uploads to the selected host
- Tmux-style keyboard shortcuts with
Ctrl+Bprefix - Retro CRT scanline visual effects
- Runs as a systemd user service
- Rust (for building)
- tmux (must be running with an active session)
- Linux with systemd (for service installation)
# Build and run directly
./run.sh
# Or build manually
cargo build --release
./target/release/tmux-terminalAccess the interface at http://localhost:5533
Install as a systemd user service:
make installThis will:
- Build the release binary
- Install to
~/bin/tmux-terminal/ - Enable and start the systemd user service
make build # Build release binary
make uninstall # Remove service and files
make update # Pull latest changes and restart
make start # Start service
make stop # Stop service
make restart # Restart service
make status # Check service status- Hosts: Defaults to local
not-invented-hereand SSH aliasvade. SetTMUX_HOSTSto customize. See multiple hosts. - Port: Set via
PORTenvironment variable (default:5533) - Large mode: Automatically enabled when the server's hostname ends in
.roam.internal(Cloudflare WARP private DNS). Editsrc/main.rsto match your own hostname if desired.
tmux-terminal runs on localhost and is not exposed to the public internet. To access it securely from anywhere — including the mobile app — use a Cloudflare Tunnel combined with Cloudflare WARP for private DNS resolution.
Your device (WARP client)
│
│ resolves myhost.roam.internal → Cloudflare network
▼
Cloudflare Edge
│
│ routes via named tunnel
▼
cloudflared (running on the server)
│
│ proxies to localhost:5533
▼
tmux-terminal
# Debian / Ubuntu
curl -L https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared jammy main" \
| sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt update && sudo apt install cloudflared
# macOS
brew install cloudflare/cloudflare/cloudflared
# Verify
cloudflared --versioncloudflared tunnel loginThis opens a browser window. Select the Cloudflare zone (domain) you want to use. A certificate is saved to ~/.cloudflared/cert.pem.
cloudflared tunnel create tmux-terminalExample output:
Created tunnel tmux-terminal with id a1b2c3d4-e5f6-7890-abcd-ef1234567890
Tunnel credentials written to /home/user/.cloudflared/a1b2c3d4-...json
Note the tunnel UUID — you'll need it in the next step.
Create ~/.cloudflared/config.yml:
tunnel: a1b2c3d4-e5f6-7890-abcd-ef1234567890 # your tunnel UUID
credentials-file: /home/user/.cloudflared/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json
ingress:
- hostname: myhost.roam.internal
service: http://localhost:5533
- service: http_status:404Replace myhost.roam.internal with whatever private hostname you want. The .roam.internal suffix is resolved only by WARP clients (see Step 6); you can use any suffix your Zero Trust org is configured for.
In the Cloudflare Zero Trust dashboard:
- Go to Networks → Tunnels and confirm your tunnel appears.
- Go to Networks → Private Networks → Add a private network and add your tunnel's virtual network.
- Go to Settings → WARP Client → Device settings and ensure "Include all private networks" is enabled for your device profile.
- Go to Networks → Routes and add a route:
- CIDR: the private IP range your tunnel uses (or leave broad for split-tunnel)
- Tunnel: select
tmux-terminal
For hostname-based access (e.g. myhost.roam.internal), add a Split Tunnel DNS entry:
- Go to Settings → WARP Client → Device settings → <your profile> → Split Tunnels
- Add
roam.internal(or your chosen suffix) so WARP resolves it internally
# Install and start as a system service
sudo cloudflared service install
# Or as a systemd user service (no sudo needed)
cloudflared service install --user
systemctl --user enable cloudflared
systemctl --user start cloudflared
# Check status
systemctl --user status cloudflaredOn each device that needs access:
- Install the Cloudflare WARP app (iOS, Android, macOS, Windows, Linux).
- Log in to your Zero Trust organization:
- Open WARP → Preferences / Settings → Account → Login with Cloudflare Zero Trust
- Enter your organization name (the slug from
<org>.cloudflareaccess.com)
- Enable WARP (the toggle should turn blue/on).
- Verify DNS resolution:
# macOS / Linux dig myhost.roam.internal # Should return a Cloudflare-assigned private IP curl http://myhost.roam.internal:5533/health # Should return {"status":"ok"}
tmux-terminal auto-enables "large mode" when it detects its own hostname ends in .roam.internal. To change the hostname or condition, edit src/main.rs:
// Before
let large_mode = hostname == "myhost.roam.internal";
// After — match any .roam.internal host
let large_mode = hostname.ends_with(".roam.internal");Then rebuild and restart:
make updatePress Ctrl+B to enter prefix mode, then:
| Key | Action |
|---|---|
c |
Create new window |
w |
Open window list |
n |
Next window |
p |
Previous window |
? |
Show help |
In window list modal:
j/kor arrows to navigateEnterto selectEscorqto cancel
| Endpoint | Method | Description |
|---|---|---|
/api/windows |
GET | List all tmux windows |
/api/capture |
POST | Capture pane content |
/api/send |
POST | Send command to tmux |
/api/new-window |
POST | Create new window |
/api/config |
GET | Get server configuration |
/health |
GET | Health check |
MIT