Web-based terminal accessible from phone via Cloudflare Tunnel
Project description
Access your terminal from your phone. No setup. Just scan.
uvx ptn
Scan the QR code. Start typing. That's it.
Why I Built This
I wanted to continue vibe coding after bed. I tried ngrok, but it requires registration. I tried Cloudflare Tunnel, but it doesn't provide a usable terminal UI. I tried Termius, but it comes with apps, accounts, and too much setup. I just wanted something simpler: open a browser, get a terminal, start typing.
So I built Porterminal. A mobile-first web terminal with secure tunneling, no registration, no installation on your phone, and a touch-friendly UI optimized for vibe coding with whatever AI app you want.
Features
- One command, instant access - No SSH, no port forwarding, no config files. Cloudflare tunnel + QR code.
- Actually usable on mobile - Virtual modifier keys (Ctrl, Alt, Tab, arrows), swipe gestures, copy/paste that works.
- Multi-tab sessions - Run builds in one tab, tail logs in another. Sessions persist across reconnects.
- Cross-platform - Windows (PowerShell, CMD, WSL), Linux/macOS (Bash, Zsh, Fish). Auto-detects your shells.
Installation
| Method | Install | Update |
|---|---|---|
| uvx (no install) | uvx ptn |
uvx --refresh ptn |
| uv tool | uv tool install ptn |
uv tool upgrade ptn |
| pipx | pipx install ptn |
pipx upgrade ptn |
| pip | pip install ptn |
pip install -U ptn |
Don't have uv? Install it
Linux/macOS:
wget -qO- https://astral.sh/uv/install.sh | sh
Windows:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Requires Python 3.12+ and cloudflared (auto-installed if missing).
Usage
ptn # Start in current directory
ptn ~/projects/myapp # Start in specific folder
ptn --no-tunnel # Local network only (no Cloudflare)
ptn -b # Run in background
All options
| Option | Description |
|---|---|
path |
Starting directory (default: current) |
--no-tunnel |
Local network only |
-b, --background |
Run in background |
-v, --verbose |
Detailed logs |
-U, --update |
Update to latest |
--check-update |
Check for updates |
-V, --version |
Show version |
Configuration
Create config.yaml in your working directory (optional):
terminal:
default_shell: bash
cols: 120
rows: 30
buttons:
- label: "git"
send: "git status\r"
- label: "build"
send: "npm run build\r"
Full config options
server:
host: "127.0.0.1"
port: 8000
terminal:
cols: 120
rows: 30
default_shell: powershell
# Custom shells (auto-detected if not specified)
shells:
- id: powershell
name: PowerShell
command: powershell.exe
args: ["-NoLogo"]
- id: wsl
name: WSL
command: wsl.exe
buttons:
- label: "git"
send: "git status\r"
- label: "ls"
send: "ls -la\r"
Security
Warning: The URL is the only authentication. Anyone with the link has full terminal access.
Best practices:
- Don't share the URL
- Stop the server when not in use (
Ctrl+C) - Use
--no-tunnelfor local network only
Built-in protections:
- Environment variables sanitized (API keys, tokens stripped)
- Rate limiting on input
- Cloudflare Access integration for teams
Contributing
Issues and PRs welcome. This project uses uv for development:
git clone https://github.com/lyehe/porterminal
cd porterminal
uv sync
uv run ptn
License
Project details
Release history Release notifications | RSS feed
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 ptn-0.1.8.tar.gz.
File metadata
- Download URL: ptn-0.1.8.tar.gz
- Upload date:
- Size: 285.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff108bc377a5c13bf4155537ea3ddd150242eb742bcccbb4b108cf87731f1cc7
|
|
| MD5 |
9082c6d0188946bd56e9468ce92d2d4c
|
|
| BLAKE2b-256 |
4b3eefe141d299fa21522757bbce0f271f48767290f1de54df6efa365335ca3b
|
Provenance
The following attestation bundles were made for ptn-0.1.8.tar.gz:
Publisher:
publish.yml on lyehe/porterminal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ptn-0.1.8.tar.gz -
Subject digest:
ff108bc377a5c13bf4155537ea3ddd150242eb742bcccbb4b108cf87731f1cc7 - Sigstore transparency entry: 787758187
- Sigstore integration time:
-
Permalink:
lyehe/porterminal@fea016b4778b6d55faad804de443d936114a1325 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/lyehe
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fea016b4778b6d55faad804de443d936114a1325 -
Trigger Event:
release
-
Statement type:
File details
Details for the file ptn-0.1.8-py3-none-any.whl.
File metadata
- Download URL: ptn-0.1.8-py3-none-any.whl
- Upload date:
- Size: 313.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c49c12c88ef442354ac880d9836f71f38fd35eab736db4d2bbd1bc72bd40bf7
|
|
| MD5 |
4ab99a4e884e5bec942c702ca70cbbfd
|
|
| BLAKE2b-256 |
83fd6ac559f3821276bc6b48ab95111518df2686b69e99c4ebfc0f6168b10555
|
Provenance
The following attestation bundles were made for ptn-0.1.8-py3-none-any.whl:
Publisher:
publish.yml on lyehe/porterminal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ptn-0.1.8-py3-none-any.whl -
Subject digest:
4c49c12c88ef442354ac880d9836f71f38fd35eab736db4d2bbd1bc72bd40bf7 - Sigstore transparency entry: 787758193
- Sigstore integration time:
-
Permalink:
lyehe/porterminal@fea016b4778b6d55faad804de443d936114a1325 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/lyehe
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fea016b4778b6d55faad804de443d936114a1325 -
Trigger Event:
release
-
Statement type: