Skip to main content

Web-based terminal accessible from phone via Cloudflare Tunnel

Project description

Porterminal - Vibe Code From Anywhere

PyPI Python Downloads License CI

1. uvx ptn
2. Scan the QR
3. Access your terminal from your phone

Porterminal demo

Why

I wanted to vibe code from bed.

ngrok requires registration and the free tier sucks. Cloudflare Quick Tunnel works great but is hard to use directly on the phone. Termius requires complicated setup: port forwarding, firewall rules, key management... Tried Claude Code web, but it can't access my local hardware and environment. Also tried Happy, but it's too bulky and updates lag behind.

So I built something simpler: run a command, scan a QR, start typing.

Features

  • One command, instant access - No SSH, no port forwarding, no config files. Cloudflare tunnel + QR code.
  • Actually usable on mobile - Touch-optimized with momentum scrolling, pinch-to-zoom, swipe gestures, and modifier keys (Ctrl, Alt).
  • Full terminal apps - vim, htop, less, tmux all work correctly with proper alt-screen buffer handling.
  • Persistent multi-tab sessions - Sessions survive disconnects. Close the browser, switch networks, reconnect from another device—your shell and running processes are still there. Multiple devices can view the same session simultaneously.
  • Cross-platform - Windows (PowerShell, CMD, WSL), Linux/macOS (Bash, Zsh, Fish, Nushell, and any shell via $SHELL). Auto-detects your shells.

Install

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

One-line install (uv + ptn):

OS Command
Windows powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/lyehe/porterminal/master/install.ps1 | iex"
macOS/Linux curl -LsSf https://raw.githubusercontent.com/lyehe/porterminal/master/install.sh | sh

Requires Python 3.12+ and cloudflared (auto-installed if missing).

Usage

ptn                    # Start in current directory
ptn ~/projects/myapp   # Start in specific folder
Flag Description
-n, --no-tunnel Local network only (no Cloudflare tunnel)
-b, --background Run in background and return immediately
-p, --password Prompt for password to protect this session
-sp, --save-password Save or clear password in config
-tp, --toggle-password Set password requirement (on/off/toggle)
-v, --verbose Show detailed startup logs
-i, --init Create .ptn/ptn.yaml config (-i "" for auto-discovery, or -i URL/PATH)
-c, --compose Enable compose mode by default
-u, --check-update Check if a newer version is available
-V, --version Show version

Mobile Gestures

Gesture Action
Tap Focus terminal, clear selection
Long-press Start text selection
Double-tap Select word
Swipe left/right Arrow keys (← →)
Scroll Momentum scrolling with physics
Pinch Zoom text (10-24px)

Modifier keys (Ctrl, Alt, Shift): Tap once for sticky (one keystroke), double-tap for lock.

Compose mode (▤ button): Toggle a text input field where you can type or dictate, edit your text with full mobile editing features (autocorrect, suggestions, cursor positioning), then send to terminal. Useful for longer commands or voice input.

Configuration

Run ptn --init to create a starter config. It auto-discovers project scripts from package.json, pyproject.toml, or Makefile and adds them as buttons:

ptn -i ""
# Created: .ptn/ptn.yaml
# Discovered 3 project script(s): build, dev, test

Or create ptn.yaml manually:

# Terminal settings
terminal:
  default_shell: nu              # Default shell ID
  shells:                        # Custom shell definitions
    - id: nu
      name: Nushell
      command: nu
      args: []

# Custom buttons (appear in toolbar)
# row: 1 = default row, 2+ = additional rows
buttons:
  - label: "claude"
    send:
      - "claude"
      - 100        # delay in ms
      - "\r"
  - label: "build"
    send: "npm run build\r"
    row: 2         # second button row

# Update checker settings
update:
  notify_on_startup: true   # Show update notification
  check_interval: 86400     # Seconds between checks (default: 24h)

# Security settings
security:
  require_password: true    # Always require password at startup
  password_hash: ""         # Saved password hash (use ptn -sp to set)
  max_auth_attempts: 5      # Max failed attempts before disconnect

Config is searched in order: $PORTERMINAL_CONFIG_PATH, ./ptn.yaml, ./.ptn/ptn.yaml, ~/.ptn/ptn.yaml.

Security

Protect your terminal with a password:

From the UI: Open Settings (gear icon) and use the Security section to set/change password and toggle password requirement. Changes require server restart.

From CLI:

# One-time password (prompt each session)
ptn -p

# Save password to config (no prompt needed)
ptn -sp
# Password: ****
# Confirm password: ****

# Clear saved password (enter empty password)
ptn -sp
# Password: [press Enter]

# Set or toggle password requirement
ptn -tp on       # Enable
ptn -tp off      # Disable
ptn -tp toggle   # Toggle current state

See docs/security.md for details.

Troubleshooting

Connection fails? Cloudflare tunnel sometimes blocks connections. Restart the server (Ctrl+C, then ptn) to get a fresh tunnel URL.

Shell not detected? Set your $SHELL environment variable or configure shells in ptn.yaml.

Contributing

Issues and PRs welcome.

git clone https://github.com/lyehe/porterminal
cd porterminal
uv sync
uv run ptn

License

AGPL-3.0

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

ptn-0.6.1.tar.gz (218.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ptn-0.6.1-py3-none-any.whl (246.6 kB view details)

Uploaded Python 3

File details

Details for the file ptn-0.6.1.tar.gz.

File metadata

  • Download URL: ptn-0.6.1.tar.gz
  • Upload date:
  • Size: 218.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ptn-0.6.1.tar.gz
Algorithm Hash digest
SHA256 c042b49f8f119c97e3873b472f3aeb53c963346d94749806c89f9ef3ca1d58dd
MD5 09243ad19194428d3948049acf175d40
BLAKE2b-256 a02dc8bc4e0b896c907c98bf3057f2906562d486bc442eec06e2a24581c09b4e

See more details on using hashes here.

Provenance

The following attestation bundles were made for ptn-0.6.1.tar.gz:

Publisher: publish.yml on lyehe/porterminal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ptn-0.6.1-py3-none-any.whl.

File metadata

  • Download URL: ptn-0.6.1-py3-none-any.whl
  • Upload date:
  • Size: 246.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ptn-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bdb15dfff2df3c2191d72283ae7d48c0f35ba09105aa3bd494dabb91b98d5251
MD5 0d2199f227c3fdad492f61e59ace33c8
BLAKE2b-256 48bc7a6f4a21ad5d1cdf0d48bc1877d7f6e1a5dc991d0df72c7c023289496993

See more details on using hashes here.

Provenance

The following attestation bundles were made for ptn-0.6.1-py3-none-any.whl:

Publisher: publish.yml on lyehe/porterminal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page