thumbmux 提供受密碼保護的手機網頁介面,管理 tmux 工作階段與 AI Agent
thumbmux: a mobile web UI for tmux and AI agents that is password-protected from the first second
作者 Mike Meshok 開發 thumbmux,讓用戶以手機網頁介面操作 tmux 工作階段及 Claude Code、Codex 等 AI 工具。伺服器預設只監聽 127.0.0.1,要求設定密碼,並將終端置於私有 Unix socket,只有通過登入與來源檢查後才可連接。
Claude Code, Codex, OpenCode and similar tools run in a terminal for minutes or hours. Checking on such a session from a phone through an ordinary web terminal is miserable: the keyboard fights the TUI, autocorrect mangles prompts, there is no scrolling, and all sessions look the same. I built thumbmux, a mobile web interface for your own tmux: a tab per session, a normal text field, swipe scrolling, photo and file upload. What I think matters most isn't the interface but that the terminal is behind a password and listens on no open port.
A caveat up front: the interface was designed for iOS Safari. It works in desktop browsers, but I haven't poked at it there. The Docker image and the VPN compose file were not tested on the build machine, because it has no Docker. The server side is covered by tests; the screenshots below come from a test instance opened in Chrome at iPhone size.
Screenshots from a test instance with demo sessions, opened in Chrome at iPhone size.
Start with what can go wrong
A web terminal is a shell on your machine reachable over HTTP. If it's open without a password, that isn't an inconvenience, it's a hole: anyone who can reach it runs commands as you. Every decision in the project was made with that one thought in mind, so I'll start with them rather than with pretty screens.
-
Loopback only by default. Without explicit configuration the server listens only on
127.0.0.1. Docker also publishes the port on the host's loopback only. -
A password is mandatory. There is no default password. If you don't set one, the server generates a random one, saves it to
~/.thumbmux/password(mode 600) and prints it once in the log. A weak or placeholder password (shorter than 8 characters or from a list of obvious ones) is simply refused, and the server doesn't start. -
The terminal doesn't listen on the network at all. The live terminal comes from ttyd, which has no proper access control of its own. So thumbmux starts ttyd itself on a unix socket inside a private temporary directory with mode 0700. There is no TCP port to find or connect to. The terminal reaches the outside only through the main server, at
/m/term/, and only after the login and origin checks. -
Everything is behind the login except
/loginand/healthz. Session cookies are signed (HMAC-SHA256), expiring,HttpOnly,SameSite=Strict, andSecureover HTTPS. Failed logins are throttled per address: five tries, then a one-minute lock. -
CSRF and WebSocket hijacking. Every POST and every WebSocket upgrade must carry a same-origin
OriginorRefererand a non-cross-siteSec-Fetch-Site, or it gets a 403. This closes the attack where another site, open in your browser, tries to connect to your logged-in terminal. -
Cookies don't reach the terminal. The proxy strips
cookieandauthorizationfrom requests to ttyd, and the login password is not exported into the terminal's environment.
From this follows an operating rule: put thumbmux behind TLS. The repository has Caddy and nginx examples in deploy/. Use a separate (sub)domain rather than a path prefix, forward the Host header and set THUMBMUX_TRUST_PROXY=1. Or keep it on loopback and reach it through an SSH tunnel or an overlay network such as Tailscale. Don't publish the plain-HTTP port to the internet. And to be honest about it: one shared password protects a whole shell, so choose a long, unique one.
For stronger insurance there is docker-compose.vpn.yml: the container goes through a VPN with a kill-switch, so if the tunnel drops it has no network at all. This variant is on my "not tested" list.
What the interface does
thumbmux doesn't replace tmux, it sits in front of it. The sessions are ordinary ones, so you can SSH in at the same time and run tmux attach -t phone to see the same windows. Sessions keep running whether or not the phone is connected.
-
Tabs and a session list. A new tab with a shell or an agent (
claude,codex,opencode,gemini,aider, or any command from yourTHUMBMUX_AGENTSlist). The list looks like Telegram: the last lines of each session and a working / waiting / done indicator. - An input box that behaves. You type into a normal text field and the text is pasted into the pane. Swipe typing and autocorrect work as in any app. Esc, Tab, arrows, Ctrl-C and your own quick commands are buttons.
-
Swipe scrolling. A finger movement scrolls the tmux history. The page forwards touches as wheel events, and in the recommended
deploy/tmux.confone wheel tick moves exactly one line instead of five, because a swipe produces many ticks in a row. - Uploads. JPEG or PNG photos up to 15 MB (with a thumbnail) and any file up to 100 MB go to the pane's working directory; the path is typed into the agent's prompt.
- A file manager. Browse, download, make folders, rename, move, delete to trash, and undo the last 50 operations.
-
A folder as a tab with favourites, split panes, reopening past Claude Code chats through
claude --resume, and a deep link/m/?go=claude&cwd=/pathfor a keyboard shortcut. -
Optional voice input: recording in the browser, transcribed by any OpenAI-compatible service, local or cloud. While
THUMBMUX_STT_URLis empty the feature is off and no audio goes anywhere.
The server is a single file of plain Python, standard library only, plus ttyd and tmux. Installing without Docker:
sudo apt install tmux ttyd # or: brew install tmux ttyd
git clone https://github.com/meshoklv/thumbmux && cd thumbmux
cp .env.example .env # optionally set THUMBMUX_PASSWORD
./run.sh
With Docker it's simpler: docker compose up --build, a random password is printed once in the logs, and you open http://127.0.0.1:7682. If you set THUMBMUX_TMUX_SOCKET, every tmux call goes to that explicit socket instead of your normal server, which is handy for keeping it away from your main sessions.
The Telegram bot: convenient and dangerous
New in Unreleased: an optional built-in bot. It messages you when a tab finishes or asks a question, with "Reply" and "Open" buttons. Answer with text or a voice message and it is typed into the right tab. There are /sessions, /new and /help. It runs inside the server using long-polling, so only outbound HTTPS, no webhook and no open ports.
And here is the main warning. The bot is remote input into your shell: whoever can message it runs commands as you. So the integration is off by default and refuses to start if a token is set while THUMBMUX_TG_ALLOWED_CHAT_IDS is empty or malformed. Both the chat and the sender are checked; everyone else gets silence (the log keeps a line without their text). The token is read only from the environment and never logged, input is limited to 20 messages per minute per chat, and the long-poll offset is stored in a file with mode 600 so old messages aren't replayed after a restart.
A second caveat: notifications contain terminal output, so it goes to Telegram. Don't enable the integration where sessions print secrets. And so far I have tested it only against a fake Bot API in the tests, not against the real Telegram server.
Tests
tests/ has security tests (login, session cookies, CSRF and origin checks, the WebSocket tunnel) and tests for the Telegram part against a fake Bot API: notification, reply routing, a foreign chat ignored, no allowlist means no start, voice, rate limit, offset after restart. Run them with python3 -m unittest discover -s tests -v; you need tmux and ttyd. Tested on Ubuntu 24.04, Python 3.12, tmux 3.4 and ttyd 1.7.4.
The changelog also has an honest line about a fixed bug: starting the server on an already existing tmux session crashed it because of an undefined variable. Fixed.
About the AI assistant
Part of the code was written together with an AI assistant (Claude); the commit history shows this through a Co-Authored-By line.
Links
Repository: github.com/meshoklv/thumbmux, MIT license. Issues and PRs are open; please report vulnerabilities privately through GitHub Security Advisories. I post notes and new versions on Telegram at t.me/meshoklv.
Mike Meshok - github.com/meshoklv
來源:DEV Community · dev.to

