DEV Community

Cover image for I Replaced Termius with a Browser Tab (And It Has ESC, Ctrl, and F-keys)
Shifu
Shifu

Posted on

I Replaced Termius with a Browser Tab (And It Has ESC, Ctrl, and F-keys)

Every time I needed to check on a server from my phone, I went through the same ritual.

Open Termius. Find the saved connection. Enter credentials. Get into the shell. Then the fun begins: I need to cancel a running command — where's Ctrl+C? I need to exit vim — where's ESC? I need to tab-complete a long path — where's TAB?

Termius handles all of this, but I was paying $14/month for what amounts to a keyboard with special keys. And it only works over SSH — if my server doesn't expose an SSH daemon to the internet, I'm stuck.

So I built NomadTTY — a self-hosted web terminal that runs in any browser, with a touch-native keyboard toolbar baked in. No app. No subscription. No SSH daemon on the public internet.

What It Is

Three components, nothing extra:

  1. ttyd — exposes a bash/tmux session over WebSocket
  2. nginx — proxies ttyd and injects a keyboard toolbar before the page loads
  3. tmux — keeps your session alive when you close the browser tab

The toolbar lives at the top of the browser and gives you the keys your phone keyboard is missing:

ESC · TAB · CTRL · SHFT · ALT · ↑↓←→ · HOME · END · PGUP/PGDN · F1–F12

Modifiers are sticky: tap CTRL, then type a letter on your phone keyboard, and it sends Ctrl+C (or whatever letter). No holding. No gymnastics. This is how Termius does it — I just wanted the same thing in a browser tab.

Try It in 30 Seconds

docker run -d -p 80:80 --name nomadtty ghcr.io/shifulegend/nomadtty:latest
Enter fullscreen mode Exit fullscreen mode

Open http://localhost in your mobile browser. The toolbar appears at the top. The terminal fills the rest of the screen.

How the Toolbar Gets Injected (The Neat Part)

nginx has a sub_filter directive that can replace strings in proxied HTTP responses. NomadTTY uses this to inject three things into ttyd's HTML before the page reaches the browser:

  1. A mobile viewport meta tag
  2. A 270-byte inline script that hooks window.WebSocket to capture the /ws connection as window._S
  3. <script src="/kb.js" defer></script> — the 9 KB keyboard toolbar

The toolbar sends keystrokes by calling window._S.send('0' + bytes) — the same protocol ttyd's own frontend uses. No fork. No modification to ttyd's source. No rebuild.

Phone browser → nginx :80
  ├── GET /kb.js  →  keyboard toolbar (9 KB, zero deps)
  ├── GET /ws     →  ttyd WebSocket passthrough
  └── GET /       →  ttyd HTML + injected toolbar + viewport meta
                              ↓
                        tmux new-session -A -s main
                              ↓
                        persistent bash (survives browser close)
Enter fullscreen mode Exit fullscreen mode

Installing on a Real Server

# One-command install (Debian/Ubuntu)
curl -fsSL https://raw.githubusercontent.com/shifulegend/nomadtty/main/install.sh | sudo bash

# With a custom domain
NOMADTTY_HOST=terminal.example.com sudo -E bash -c \
  'curl -fsSL https://raw.githubusercontent.com/shifulegend/nomadtty/main/install.sh | bash'
Enter fullscreen mode Exit fullscreen mode

Works great over Tailscale — expose NomadTTY only on your private network and reach it from anywhere your phone can hit Tailscale. No public SSH port required.

Keyboard at a Glance

Key Sends
CTRL Sticky — tap, then type a letter (e.g. Ctrl+C)
SHFT Sticky shift modifier
ALT Sticky — ESC prefix for readline shortcuts (Alt+B, Alt+F)
ESC \x1b
TAB / ⇑TAB \t / Shift+Tab
↑↓←→ Arrow keys (modifier combos supported)
HOME / END \x1b[H / \x1b[F
PGUP / PGDN \x1b[5~ / \x1b[6~
Fn Toggle F1–F12 row
A− / A+ Zoom terminal font in/out

What It Won't Do

Being honest about the trade-offs:

  • Not an SSH client — NomadTTY is a web terminal, not a tunnel or port-forward tool
  • One server at a time — no multi-host UI; one NomadTTY instance per server
  • No key vault — auth is on you (Tailscale, nginx basic auth, or VPN)
  • Browser-only — needs a network connection; no offline mode

If you need Termius-style multi-server management or SSH tunneling: keep Termius. If you have one server you care about and want to reach it cleanly from your phone or tablet without installing anything — this does it.

The Stack

  • ttyd — terminal-over-WebSocket, unmodified
  • nginx — toolbar injection via sub_filter; static serving of kb.js
  • tmux — session persistence
  • src/kb.js — 9 KB IIFE, zero dependencies, no build step

No Node.js. No npm. No bundler. Docker images for linux/amd64 and linux/arm64. MIT licensed.

Get It

github.com/shifulegend/nomadtty


What do you currently use for terminal access from your phone? Termius? Blink Shell? Raw SSH apps? Something else entirely? I'm curious what the community's solutions look like — and what pain points I may have missed. Drop it in the comments.

Top comments (1)

Collapse
 
frank_signorini profile image
Frank

The sticky Ctrl and F-key emulation in a