hop-shell
v0.6.0
Published
π° Hop into your terminal from anywhere. Secure remote shell access with 2FA via Cloudflare Tunnel.
Maintainers
Readme
π° hop
Hop into your terminal from anywhere in the world.
Access your Mac's terminal from your phone, tablet, or any browser β secured with password + 2FA, tunneled through Cloudflare.
π macOS only β Requires Homebrew for dependencies (ttyd, tmux, cloudflared)
(\(\
( -.-) "hop into your shell"
o_(")(")β¨ Features
- π Password + 2FA β Optional password plus TOTP (required for custom domains)
- π Access Anywhere β Cloudflare tunnel, no port forwarding
- π Custom Domains + MultiβUser β Share subdomains with perβuser credentials
- π± Mobile Virtual Keyboard β Custom keyboard with Esc, Ctrl, Alt, arrows, and more
- β¨οΈ Native Keyboard Support β Tap the blue button for dictation, spellcheck & autocomplete
- πͺ Multi-Session β Create and switch between named sessions
- π Port Sessions β Proxy a local HTTP/WS service via hop
- π Quick Session Switching β Floating menu to switch sessions without leaving the terminal
- π¨ Modern UI β Clean, minimal iOS-style design
- β‘ Auto-Attach β Multiple terminals share the same tunnel
π Quick Install
From npm (easiest)
npm install -g hop-shellThen just run:
hopOne-liner from source
git clone https://github.com/jzthree/hop.git ~/.hop && \
cd ~/.hop && npm install && \
sudo ln -sf ~/.hop/hop /usr/local/bin/hopManual Install from source
# Clone the repo
git clone https://github.com/jzthree/hop.git ~/.hop
# Install dependencies
cd ~/.hop && npm install
# Add to PATH (pick one)
# Option A: Symlink (requires sudo)
sudo ln -sf ~/.hop/hop /usr/local/bin/hop
# Option B: Add to PATH
echo 'export PATH="$HOME/.hop:$PATH"' >> ~/.zshrc
source ~/.zshrcπ° Usage
# Start hopping!
hop
# Use iTerm control mode for local session
hop --itermFirst time:
- (Optional) Set a password:
hop password set - Scan the QR code with your authenticator app (Google Authenticator, Authy, 1Password, etc.)
- Note the URL displayed
- Press Enter to start your local session
From your phone:
- Open the URL in your browser
- Enter your password (if enabled) and 6βdigit code
- Pick or create a session
- π° You're in! Use the virtual keyboard for terminal keys, or tap the blue button for native input
πͺ Sessions
Create multiple independent terminal sessions from the Session Picker (/sessions):
- Create: Type a name and click Create
- Join: Click Join on any existing session
- Sessions are shared: Multiple devices can view the same session
You can also create Port Sessions that proxy to a local HTTP/WS service on your machine. Use the Session Picker or:
hop session add myapp --port 3000π Custom Domains & MultiβUser
Admin (your machine)
- Set a password (required for custom domains):
hop password set - Configure your domain:
hop domain hop.yourdomain.com - Add a user + export credentials:
hop user add alice hop user export alice - Send the exported folder to the user.
User (their machine)
npm install -g hop-shell
hop client ./credentials.jsonFirst run prompts them to set a password + scan a TOTP QR code.
They then log in at their URL, e.g. https://alice.hop.yourdomain.com.
π± Mobile Keyboard
On mobile devices, Hop provides a custom virtual keyboard designed for terminal use:
Accessory Row:
EscTabCtrlAltβ Essential terminal keysβ β β ββ Arrow keys for navigation- π΅ Blue keyboard button β Opens native iOS keyboard for dictation, spellcheck & autocomplete
Floating Menu (top-right button):
- Toggle Keyboard β Show/hide the virtual keyboard
- Session List β Quick-switch between sessions
- All Sessions β Return to session picker
Tips:
- The floating button is draggable β move it anywhere
- First-time users will see a tooltip pointing to the native keyboard button
- Use the native keyboard for longer text input with autocomplete
π₯οΈ iTerm Integration
hop --itermUses tmux control mode (-CC) for native scrolling, copy/paste, splits, and search. Session remains accessible via web.
π Port Sessions
Expose local HTTP/WebSocket services through your tunnel:
hop session add myapp --port 3000
# Access at: https://your-tunnel-url/s/myapp/Works with dev servers, Jupyter, APIs β anything on localhost. Supports WebSocket.
π§ Commands
| Command | Description |
|---------|-------------|
| hop | Start hop (or attach to existing tunnel) |
| hop --iterm | Use iTerm tmux control mode for local session |
| hop url | Print current tunnel URL |
| hop qr | Show QR code for current URL |
| hop domain <hostname> | Set custom domain (named tunnel) |
| hop domain-clear | Remove custom domain, use random URLs |
| hop password set | Set/change password |
| hop password clear | Remove password protection |
| hop user list | List users |
| hop user add <name> | Add user + subdomain |
| hop user remove <name> | Remove user |
| hop user export <name> | Export user credentials |
| hop session list | List sessions |
| hop session add <name> | Create a terminal session |
| hop session add <name> --port N | Create a port session (proxy) |
| hop session remove <name> | Remove a session |
| hop client <credentials> | Run hop with exported credentials |
| hop wipe | Kill all hop tmux sessions |
| quit | Type at exit prompt to shutdown tunnel |
π¦ Dependencies
Installed automatically via Homebrew:
tmuxβ Terminal multiplexerttydβ Web terminalcloudflaredβ Cloudflare tunnel
Node.js packages:
http-proxyβ Request proxyingotplibβ TOTP authenticationqrcode-terminalβ QR code displaycookieβ Session cookies
π‘οΈ Security
- Password + TOTP β Password optional, but required for custom domains
- Rate Limiting β Exponential backoff on failed attempts
- Secure Cookies β
httpOnly,secure,sameSite=lax - Random URL β Unguessable tunnel URL for quick tunnels
- Fixed URL β Custom domains keep a stable URL
- Local Binding β ttyd only listens on 127.0.0.1
- End-to-End TLS β Cloudflare Tunnel encryption
Passwords: Recommended for any public URL; required for custom domains.
Secrets: Stored in ~/.hop-shell/ (treat like ~/.ssh/)
π Troubleshooting
QR code not working?
Delete .auth_secret and restart hop to generate a new code.
Client reset (user mode)?
Delete ~/.hop-shell/clients/<tunnel-id>/ and run hop client again.
Tunnel not starting?
Make sure cloudflared is installed: brew install cloudflared
Stuck processes?
pkill ttyd; pkill cloudflared; tmux kill-serverπ License
MIT
Made with π° for hopping around
____
/ \
| ^ ^ | hop hop hop
| .. |
\ -- /
||||