π° Hop into your terminal from anywhere. Secure remote shell access with 2FA via Cloudflare Tunnel.
npm install hop-shellHop 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_(")(")
- π 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
`bash`
npm install -g hop-shell
Then just run:
`bash`
hop
`bash`
git clone https://github.com/jzthree/hop.git ~/.hop && \
cd ~/.hop && npm install && \
sudo ln -sf ~/.hop/hop /usr/local/bin/hop
`bashClone the repo
git clone https://github.com/jzthree/hop.git ~/.hop
π° Usage
`bash
Start hopping!
hopUse iTerm control mode for local session
hop --iterm
`First time:
1. (Optional) Set a password:
hop password set
2. Scan the QR code with your authenticator app (Google Authenticator, Authy, 1Password, etc.)
3. Note the URL displayed
4. Press Enter to start your local sessionFrom your phone:
1. Open the URL in your browser
2. Enter your password (if enabled) and 6βdigit code
3. Pick or create a session
4. π° 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:
`bash
hop session add myapp --port 3000
`π Custom Domains & MultiβUser
$3
1. Set a password (required for custom domains):
`bash
hop password set
`
2. Configure your domain:
`bash
hop domain hop.yourdomain.com
`
3. Add a user + export credentials:
`bash
hop user add alice
hop user export alice
`
4. Send the exported folder to the user.$3
`bash
npm install -g hop-shell
hop client ./credentials.json
`
First 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:
-
Esc Tab Ctrl Alt β Essential terminal keys
- β β β β β Arrow keys for navigation
- π΅ Blue keyboard button β Opens native iOS keyboard for dictation, spellcheck & autocompleteFloating 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
`bash
hop --iterm
`Uses 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:
`bash
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 | 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 | Add user + subdomain |
| hop user remove | Remove user |
| hop user export | Export user credentials |
| hop session list | List sessions |
| hop session add | Create a terminal session |
| hop session add | Create a port session (proxy) |
| hop session remove | Remove a session |
| hop client | 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 multiplexer
- ttyd β Web terminal
- cloudflared β Cloudflare tunnelNode.js packages:
-
http-proxy β Request proxying
- otplib β TOTP authentication
- qrcode-terminal β QR code display
- cookie β 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 encryptionPasswords: 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/ and run hop client again.Tunnel not starting?
Make sure
cloudflared is installed: brew install cloudflaredStuck processes?
`bash
pkill ttyd; pkill cloudflared; tmux kill-server
`π License
MIT
---
Made with π° for hopping around
`
____
/ \
| ^ ^ | hop hop hop
| .. |
\ -- /
||||
``