A web-based remote desktop for Termux and PRoot X11 environments
Project description
TermuxDesk
A lightweight, web-based remote desktop for Termux and PRoot X11 environments.
TermuxDesk captures an existing X11 display with Pillow, streams JPEG frames
through an aiohttp WebSocket, and injects mouse and keyboard events with the
XTest extension through python-xlib. It does not need root or sudo.
Project status:
0.1.0is an alpha release. Test it with your desktop and window manager before relying on it.
Demo
Requirements
- Python 3.9 or newer
- A running X11 server with the XTest extension
DISPLAYset to that server, such as:0cloudflaredonly when using--tunnel
TermuxDesk provides the remote viewer; it does not start Termux:X11, Xvfb, a desktop environment, or a window manager.
Install
From PyPI:
python -m pip install termux-desk
From a checkout:
python -m pip install .
Termux one-liner:
curl -fsSL https://raw.githubusercontent.com/amirghm/termux-desk/main/install.sh | bash
The installer must run in Termux itself, not inside a Debian/Ubuntu PRoot. This
matters because PRoot's apt repositories do not provide Termux's python
package. Run Termux package installation first, then enter your PRoot if that
is where the X11 session runs.
Quick Start
Start your X11 environment, identify its display, and run:
export DISPLAY=:0
termux-desk start
Open http://127.0.0.1:8765 in a browser on the same device.
To listen on the LAN:
termux-desk start --host 0.0.0.0
To create a temporary HTTPS URL:
termux-desk start --tunnel
Security warning: TermuxDesk 0.1.0 has no built-in authentication. Anyone
who can reach the URL can view and control the X11 session. A Cloudflare Quick
Tunnel URL is public. Share it only with trusted people, stop it after use, and
prefer Cloudflare Access or another authenticated proxy for ongoing access.
Browser Controls
- Click mode sends primary clicks on tap or mouse release.
- Drag mode holds the primary button while the pointer moves.
- Mouse movement, double-click, wheel, and horizontal scroll are supported.
- Keyboard events are sent while the viewer page has focus.
- The Help button shows the controls in the viewer.
Browser and operating-system reserved shortcuts may not reach the remote desktop.
CLI Reference
termux-desk start [--host HOST] [--port PORT] [--display DISPLAY]
[--fps FPS] [--quality 1..95] [--tunnel]
| Option | Default | Description |
|---|---|---|
--host |
127.0.0.1 |
HTTP listen address |
--port |
8765 |
HTTP listen port |
--display |
$DISPLAY |
X11 display name |
--fps |
12 |
Maximum capture rate |
--quality |
70 |
JPEG quality from 1 to 95 |
--tunnel |
off | Start a Cloudflare Quick Tunnel |
Use termux-desk --version to print the installed version and Ctrl+C to stop
the server and tunnel.
Python API
The public API has no third-party import side effects. Runtime dependencies and the X11 connection are loaded when the server starts.
from termux_desk import TermuxDeskServer
server = TermuxDeskServer(
host="127.0.0.1",
port=8765,
display=":0", # defaults to the DISPLAY environment variable
fps=12,
quality=70,
)
server.run()
For an existing asyncio application:
server = TermuxDeskServer()
await server.start()
print(server.local_url)
# ... application work ...
await server.stop()
termux_desk.run_server(**options) is a blocking convenience function.
TermuxDeskError is raised for missing dependencies, an unset or unreachable
display, missing XTest support, and tunnel startup failures.
Troubleshooting
DISPLAY is not set
Set it to the display used by your X11 session:
export DISPLAY=:0
Could not connect to X11 display
Verify the server is running, the display number is correct, and the process
has permission to connect. From a PRoot environment, preserve or explicitly
set DISPLAY.
cloudflared was not found
Install it in Termux:
pkg install cloudflared
Pillow fails to install in Termux
Install its native build dependencies, then retry:
pkg install python clang make pkg-config libjpeg-turbo libpng
python -m pip install Pillow
Architecture
The root page serves a viewer embedded directly in termux_desk.server; there
is no runtime template or static-file lookup. Each WebSocket client receives
JPEG frames and sends small JSON input messages. Pointer coordinates are
normalized in the browser, validated by the server, and scaled to the current
X11 screen dimensions before XTest injection.
Contributing
- Fork and clone the repository.
- Create a virtual environment and run
python -m pip install -e '.[dev]'. - Make a focused change and add tests.
- Run
pytestandpython -m build. - Open a pull request describing behavior changes and the X11 environment used for manual testing.
Bug reports should include Python version, Termux/PRoot distribution, X server, window manager, browser, and the exact command used.
License
MIT © 2026 TermuxDesk contributors.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file termux_desk-0.1.1.tar.gz.
File metadata
- Download URL: termux_desk-0.1.1.tar.gz
- Upload date:
- Size: 17.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
214d882544f6d6209642b9e46be090f220247201e93f0cfbfe27947f3d72641f
|
|
| MD5 |
b1da530f3c961f02771050cc7bc91b1d
|
|
| BLAKE2b-256 |
1ecd707a64f32d1125f1bf06f6d9b7eff20725bfd1b63fb0aa0b0e37e87e1086
|
File details
Details for the file termux_desk-0.1.1-py3-none-any.whl.
File metadata
- Download URL: termux_desk-0.1.1-py3-none-any.whl
- Upload date:
- Size: 17.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d290eccf976f332e7ce2688cf3a6e0915eee40df658bc2dacbc97ca7682aa91f
|
|
| MD5 |
c152d97800683f75c3f4a415e435bf6e
|
|
| BLAKE2b-256 |
45dc8b9a93a166c21b923cd1bd63149b2902fb8deb008a7309749da910e29283
|