Overview
meshTerm is an SSH terminal client for iPhone and iPad. It lets you connect to remote servers using password or SSH key authentication, and integrates with Tailscale to browse and connect to your Tailnet devices directly from the app.
Beyond the terminal, meshTerm includes multi-session tabs with keyboard shortcuts, an SFTP file browser that integrates with the iOS Files app, a terminal macro bar for one-tap commands, and automatic tmux attachment so sessions survive dropped connections.
Prerequisites
For all connections
- A server with SSH enabled and accessible from your device
- Your server's hostname or IP address, port, and a valid username
For password authentication
- The password for your server account
For SSH key authentication Pro
- An Ed25519 SSH key pair. You can generate one inside meshTerm, or bring your own unencrypted OpenSSH key.
- The corresponding public key added to
~/.ssh/authorized_keyson the server
For Tailscale SSH Pro
- Tailscale app installed on your iPhone/iPad — meshTerm routes connections through the Tailscale VPN tunnel, which requires the Tailscale app to be running and connected
- Both your iPhone and the target server must be on the same Tailnet
- The server must have Tailscale SSH enabled in your Tailnet ACLs
For Tailscale device browsing Pro
- A Tailscale API token (read-only) — see Getting a Tailscale API Token
- The Tailscale app installed and connected to your Tailnet
Getting Started
Adding your first host
- Open meshTerm. You will see the host list (empty on first launch).
- Tap + in the top-right corner.
- Fill in the connection details:
- Label — a friendly name for this connection (e.g. "My Server")
- Hostname or IP — the address of your server
- Port — defaults to 22
- Username — your account name on the server
- Under Authentication, choose a method and enter your credentials.
- Tap Add to save.
Connecting
Tap any host in the list to open a terminal session. meshTerm connects immediately — you will see a "Connecting…" indicator while the session is being established.
Managing SSH Hosts
Editing a host
Swipe right on a host and tap Edit, or long-press the row to reveal options.
Deleting a host
Swipe left on a host and tap Delete.
Host limit
Free accounts can save 1 host. meshTerm Pro removes this limit.
Connecting to a Host
When you tap a host, meshTerm:
- Resolves the hostname and opens a TCP connection to the server.
- Verifies the server's host key against your saved known hosts (see Known Hosts).
- Authenticates using the method configured for that host.
- Requests a PTY and launches a shell session.
- Attempts to attach to a
tmuxsession on the server (see tmux attach).
The terminal becomes interactive as soon as the shell is ready.
tmux attach
New hosts attach to tmux by default. When you reconnect, meshTerm re-attaches to the same session so your work survives dropped connections, backgrounded apps, and closed tabs.
- If
tmuxis not installed on the server, meshTerm falls back gracefully to a standard shell — no configuration required. - You can disable automatic
tmuxattach per host from the edit screen if you prefer a plain shell.
Automatic reconnection
meshTerm watches the network path and your app's foreground state. If the connection drops — Wi-Fi in a lift, cellular-to-Wi-Fi handoff, backgrounding the app — the session reconnects automatically when the network returns or you bring the app back to the foreground.
A dim -- reconnected -- marker is drawn into the terminal so you can see exactly when the reattach happened. With tmux attach, you pick up where you left off.
Environment variables
You can attach custom environment variables to any host. These are sent to the shell session on connect. To add them, edit the host and use the Environment Variables section.
Disconnecting
Close the terminal view or terminate the shell session from the server side (e.g. exit, logout, or Ctrl+D).
Multi-Session Tabs
meshTerm supports multiple concurrent SSH sessions. A session bar sits above the terminal showing each open connection; tap a tab to switch, or swipe to dismiss it. Each session runs independently — run a build on one host while you tail logs on another, and switch between them in a single tap.
Opening and closing sessions
- Tap a host in the host list to open it in a new tab.
- Tap another host to add a second tab — the existing session stays alive in the background.
- Swipe a tab down in the session bar, or close the terminal view, to end that session.
Keyboard shortcuts
With a hardware keyboard (Magic Keyboard, Smart Folio, or any Bluetooth keyboard) attached:
| Shortcut | Action |
|---|---|
| ⌘ T | Open a new session (returns to host list to pick a host) |
| ⌘ K | Close the current session |
| ⌘ 1 – ⌘ 9 | Jump directly to the tab at that position |
| ⌘ [ | Switch to the previous tab |
| ⌘ ] | Switch to the next tab |
Session persistence
Each tab is a live SSH connection. When paired with tmux attach and automatic reconnection, tabs survive the app going to the background or losing the network — they reconnect silently when you return.
Authentication Methods
Password
Enter your password when adding or editing the host. Passwords are stored securely in the iOS Keychain and never written to disk in plain text.
SSH Key Pro
Select one of your saved SSH keys when adding or editing the host. The private key never leaves your device — meshTerm signs the authentication challenge locally and sends only the public key to the server.
To use SSH key authentication:
- Generate or import a key in Settings → SSH Keys (see SSH Key Management).
- Copy the public key and add it to
~/.ssh/authorized_keyson your server. - When adding or editing a host, set the auth method to SSH Key and select the key.
Tailscale SSH Pro
For servers on your Tailnet with Tailscale SSH enabled, no password or key is required. Tailscale authenticates the connection at the network layer using your device's Tailscale identity.
Requirements:
- Tailscale app installed and connected on your iPhone/iPad
- Server enrolled in the same Tailnet with Tailscale SSH enabled in ACLs
- On the remote host:
sudo tailscale up --ssh
Tailscale SSH authentication is handled entirely by the Tailscale app — meshTerm does not send any credentials for these connections.
SSH Key Management
Access SSH keys via Settings → SSH Keys.
Generating a new key
Generating a key is a two-step process. First, the key is created and saved; then you have the option to install it on a host without leaving the sheet.
- Tap Add Key.
- Enter a label (e.g. "Work iPhone").
- Tap Generate. meshTerm creates a new Ed25519 key pair, saves it securely in the iOS Keychain, and keeps the sheet open.
The public key is shown in the key list in OpenSSH format:
ssh-ed25519 AAAA... Work iPhone
The comment at the end reflects the label you gave the key. Tap Done to close the sheet at any time.
Installing a key on a host
If you have any saved hosts, an Install on a Host section appears on the sheet immediately after the key is generated. This lets you push the public key to a host in one step — no manual copy-and-paste into authorized_keys required.
- In the Install on a Host section, select a host from the picker.
- Tap Install Key.
meshTerm opens a non-interactive exec channel to the selected host (no PTY or shell session is started) and appends the public key to ~/.ssh/authorized_keys on the server. The connection uses the credentials already stored for that host.
Known host required. Installation uses strict host key verification — TOFU prompting is not shown during this flow. If the host's key is not yet trusted, a message in the footer will tell you to connect to that host via the terminal first, then return to install the key.
Once the key is installed successfully, the status updates in the sheet. Tap Done to dismiss.
Importing an existing key
- Tap Add Key → Import.
- Paste your unencrypted OpenSSH private key (the full contents of the file, including the
-----BEGIN OPENSSH PRIVATE KEY-----and-----END OPENSSH PRIVATE KEY-----lines). - Tap Import.
Requirements for import:
- Ed25519 keys only
- Unencrypted (no passphrase). To strip a passphrase:
ssh-keygen -p -N "" -f ~/.ssh/id_ed25519
Copying a public key
Tap the copy icon next to a key to copy the full OpenSSH public key to your clipboard. Paste this into ~/.ssh/authorized_keys on your server.
Deleting a key
Swipe left on a key and tap Delete. The private key is permanently removed from the Keychain.
If you delete a key that is assigned to a host, that host will fail to connect until you edit it and assign a different key.
Key storage
- Private keys are stored as 32-byte Ed25519 seeds in the iOS Keychain, protected at rest by the device's secure enclave.
- Private keys are marked
WhenUnlockedThisDeviceOnly— they cannot be backed up to iCloud or moved to another device. - Public keys are stored in UserDefaults for display purposes only.
Tailscale Integration
meshTerm integrates with the Tailscale VPN to let you browse your Tailnet and add devices directly as SSH hosts.
Prerequisites
- meshTerm Pro
- Tailscale app installed and connected to your Tailnet
- A read-only Tailscale API token (see below)
Getting a Tailscale API Token
In meshTerm, tap Settings → Tailscale → How to get an API token for in-app instructions. The steps are:
- Go to tailscale.com and sign in.
- Navigate to Settings → Personal Settings → Keys.
- Under API Access Tokens, click Generate token.
- Give the token a label (e.g. "meshTerm").
- Set an expiry — 90 days is recommended.
- Leave permissions as read-only (meshTerm does not need write access).
- Copy the token.
- In meshTerm, go to Settings → Tailscale → API Token and paste it in.
Your API token is stored securely in the iOS Keychain. meshTerm uses it only to fetch your device list and never modifies your Tailnet configuration.
Browsing your Tailnet
- Tap the globe icon in the host list toolbar.
- Your Tailnet devices are listed with their hostname, IP address, and operating system.
- Enter a username (applied to all devices added in this session).
- Tap + next to a device to add it as an SSH host.
Devices added from the Tailnet browser are automatically configured to use Tailscale SSH auth (if you are on Pro).
API token expiry
Tailscale API tokens expire. When your token expires, the Tailnet browser will show an error. Return to Settings → Tailscale and generate a new token using the steps above.
Snippet Vault
The Snippet Vault (Pro) is a searchable library of terminal commands you can send to the active session with a single tap.
Access it from the snippets button in the terminal toolbar.
Default snippets
meshTerm ships with two folders of pre-loaded snippets:
Linux — common admin commands including ls -lah, df -h, ps aux, ss -tuln, tail -f /var/log/syslog, systemctl status, and more.
OpenClaw — commands for OpenClaw including openclaw update, openclaw doctor, openclaw models list, openclaw gateway status, and openclaw memory index --force.
Using a snippet
Tap any snippet to send the command text directly to the terminal. The Vault closes automatically and the command is typed into your active session.
Adding snippets
- Tap + in the Snippet Vault toolbar.
- Enter a title and the command text.
- Optionally assign it to a folder and add tags.
- Tap Save.
Searching
Use the search bar at the top of the Vault. meshTerm searches across snippet titles, command text, and tags.
Folders
Tap New Folder to organise snippets. Tap a folder to view only its snippets. Deleting a folder does not delete its snippets — they move to the root level.
Terminal Macro Bar Pro
The Terminal Macro Bar is a scrollable row of one-tap commands that sits directly above the keyboard accessory, ready in every session. Put your most-used commands — git status, docker ps, tail a log, restart a service — on standby and fire them with a single tap.
Using macros
Scroll the macro row horizontally above the keyboard and tap a macro to send its command to the active terminal. Each tap sends the text followed by Return, so the command runs immediately.
The Macro Editor
Open Settings → Keyboard → Macros to manage your macro list. From the editor you can:
- Add a macro — give it a short label (what appears on the bar) and the command text.
- Edit an existing macro — tap a row to change its label or command.
- Reorder macros by dragging rows. The order in the editor matches the order on the bar.
- Delete a macro by swiping its row.
- Restore defaults to bring back meshTerm's built-in macro set.
Default macros
meshTerm ships with a small starter set you can keep, edit, or replace entirely — use Restore defaults at any time to bring them back.
SFTP File Browser Pro
The SFTP browser lets you move files on and off your servers without leaving meshTerm. It runs over the same SSH transport as your terminal sessions — no additional credentials, no extra apps, no third-party cloud in the middle.
Opening the browser
- From the host list, tap the folder icon next to a host, or open the host's detail screen and tap Browse files.
- meshTerm opens an SFTP channel over the existing SSH connection and shows the contents of the home directory.
SFTP requires the server to support the SFTP subsystem (enabled by default in OpenSSH). Tailscale SSH nodes are supported the same way as any other host.
Navigating
- Tap a folder to enter it. Tap Back in the navigation bar to go up a level.
- Pull down to refresh the current directory listing.
- The current path is shown in the title bar.
Downloading files
- Tap a file to start a download. A progress indicator shows bytes transferred.
- When the download completes, meshTerm offers to save the file via the iOS Files sheet — pick iCloud Drive, On My iPhone, or any Files-compatible location.
- A Saved to Files confirmation appears once the file is written.
Uploading files
- Tap Upload in the browser toolbar.
- Pick one or more files from the iOS Files sheet — iCloud Drive, Dropbox, On My iPhone, or any provider.
- meshTerm uploads the files to the current remote directory and shows progress per file.
File operations
Long-press a file or folder for options:
- Rename — enter a new name; the server-side rename is atomic where supported.
- Delete — confirm and meshTerm removes the file or folder. Non-empty folders are not deleted in one pass — empty them first.
- New Folder (toolbar) — create a new directory in the current path.
All SFTP operations run over the active SSH session's encrypted channel. Credentials never leave your device, and nothing is routed through a third-party server.
Terminal Controls
Modifier keys
| Key | Description |
|---|---|
| Ctrl | One-shot Ctrl modifier. Tap once, then press a key (e.g. C, D, Z, L). Releases automatically after one keystroke. |
| Esc | Sends the Escape character. Use to exit insert mode in vim or cancel prompts. |
| Alt | One-shot Alt/Meta modifier. Use for word navigation: Alt+F (forward word), Alt+B (back word). |
| Tab | Sends Tab for shell autocompletion. |
Common Ctrl sequences
| Sequence | Action |
|---|---|
| Ctrl + C | Interrupt — stop the running command |
| Ctrl + D | End of input — log out or close session |
| Ctrl + Z | Suspend — background the current process |
| Ctrl + L | Clear — redraw the screen |
| Ctrl + A | Move cursor to beginning of line |
| Ctrl + E | Move cursor to end of line |
| Ctrl + R | Reverse history search |
| Ctrl + W | Delete the word before the cursor |
Arrow keys
- ↑ / ↓ — Navigate command history; move cursor in full-screen apps (vim, htop)
- ← / → — Move cursor; scroll through menus in full-screen apps
Extended keys
Tap the keyboard dismiss button to reveal the full extended key row:
- F1–F12 — Function keys
- Home / End — Jump to start/end of line
- Page Up / Page Down — Scroll one screen at a time
Symbol strip
The symbol strip provides quick access to commonly used characters:
| ` ~ $ / \ { } [ ]
Hide Keyboard button
Tap the keyboard-dismiss button in the terminal toolbar to drop the on-screen keyboard entirely. Useful for reading long output (logs, man pages, build output) without an accessory row eating half the screen. Tap the terminal to bring the keyboard back.
Hardware keyboard auto-hide
Connect a Magic Keyboard, Smart Folio, or any Bluetooth keyboard and meshTerm's on-screen accessory bar disappears automatically, giving you a full-screen terminal. Disconnect and it reappears. There is no setting to toggle — meshTerm observes the connected keyboard and hides the accessory for you.
While a hardware keyboard is attached, the multi-session keyboard shortcuts (⌘T, ⌘K, ⌘1–9, ⌘[, ⌘]) are also available.
Security
Known Hosts (TOFU)
meshTerm uses Trust On First Use (TOFU) to verify server identity. The first time you connect to a host, meshTerm presents the server's host key fingerprint and asks you to confirm before proceeding.
- Tap Trust & Connect to accept the fingerprint and save it.
- Tap Cancel to abort the connection.
On subsequent connections, meshTerm checks the fingerprint automatically. If it has changed, the connection is blocked with a security warning (see Host key mismatch).
Viewing and managing known hosts
Go to Settings → Known Hosts to see all trusted hosts. Swipe left on an entry to delete it.
If a server's host key legitimately changes (e.g. after a rebuild), delete the old entry from Known Hosts and reconnect to accept the new fingerprint.
Credential storage
All sensitive data is stored in the iOS Keychain:
- SSH private keys
- SSH passwords
- Tailscale API tokens
Nothing sensitive is written to iCloud backup, UserDefaults, or the filesystem.
App Lock
meshTerm can be locked with Face ID, Touch ID, or your device passcode. When enabled, the app locks automatically when it moves to the background and requires biometric or passcode authentication to reopen.
Enable app lock in Settings → App Lock.
App Lock requires a device passcode to be set. If no passcode is configured, you will be prompted to set one in iOS Settings → Face ID & Passcode.
Settings
SSH Keys
Manage your SSH key pairs. See SSH Key Management.
Keyboard → Macros
Add, edit, reorder, or delete the macros shown on the Terminal Macro Bar. Use Restore defaults to bring back the built-in starter set.
App Lock
Require Face ID, Touch ID, or the device passcode to open meshTerm. See App Lock. Requires an iOS passcode to be set on the device.
Security → Known Hosts
View and delete trusted host fingerprints. See Known Hosts.
Tailscale → API Token
Enter your read-only Tailscale API token to enable Tailnet device browsing. See Tailscale Integration.
About
Shows the current app version and links to the Privacy Policy and Terms of Use.
meshTerm Pro
meshTerm Pro unlocks the following features:
| Feature | Free | Pro |
|---|---|---|
| Saved hosts | 1 | Unlimited |
| Password authentication | Yes | Yes |
| SSH key authentication | — | Yes |
| Generate / import SSH keys | — | Yes |
| Install key on a host | — | Yes |
| Tailscale SSH | — | Yes |
| Tailscale device browsing | — | Yes |
| Snippet Vault | — | Yes |
| Terminal Macro Bar | — | Yes |
| SFTP file browser | — | Yes |
| Multi-session tabs | Yes | Yes |
| Automatic tmux attach & reconnect | Yes | Yes |
| Known hosts management | Yes | Yes |
| Terminal emulation | Yes | Yes |
| App Lock | Yes | Yes |
Subscribing
Tap Upgrade in Settings or the paywall prompt. Pro is available as a monthly or annual subscription — the annual plan is the best value.
Restoring purchases
Tap Restore Purchases in Settings if you reinstall the app or switch devices.
Troubleshooting
Connection issues
"Could not resolve '[hostname]'"
The device cannot look up the hostname via DNS.
- Check the hostname is spelled correctly.
- Check your device has a working internet connection.
- If using a local hostname (e.g.
myserver.local), ensure you are on the same local network.
"Could not connect to [host]:[port]"
The TCP connection was refused or timed out.
- Verify the server is online and accessible.
- Check the port number is correct (default SSH is 22).
- Confirm SSH is running on the server:
sudo systemctl status ssh. - If connecting to a local network address, ensure meshTerm has Local Network permission: go to iOS Settings → Privacy & Security → Local Network and enable meshTerm.
"The connection was closed"
The server terminated the session.
- The server may have timed out an idle connection. Reconnect and consider setting
ClientAliveIntervalon the server. - The shell may have exited normally (e.g. you typed
exit).
Connection hangs at "Connecting…"
- Check your network connection.
- If connecting via Tailscale, ensure the Tailscale app is open and connected to your Tailnet.
- Try toggling Tailscale off and on.
Authentication issues
"No SSH key selected. Edit the host and choose a key."
The host is set to SSH key authentication but no key has been assigned.
- Go to the host list, swipe left on the host, and tap Edit.
- Under Authentication, select a key from the Key picker.
- If no keys are listed, go to Settings → SSH Keys and generate or import one first.
SSH key auth fails silently or server rejects key
- Confirm the public key is in
~/.ssh/authorized_keyson the server. - Ensure the
~/.sshdirectory has permissions700and~/.ssh/authorized_keyshas permissions600on the server. - Check
sshd_configon the server hasPubkeyAuthentication yes.
Password auth fails
- Double-check the username and password.
- The server may require key-based auth only. Check
/etc/ssh/sshd_configforPasswordAuthentication no.
Tailscale issues
"Enter your Tailscale API token in Settings first."
You opened the Tailnet browser without an API token configured.
- Go to Settings → Tailscale → API Token and paste in a valid token.
- See Getting a Tailscale API Token for how to generate one.
"Invalid or expired token."
Your API token has expired or is invalid.
- Go to tailscale.com → Settings → Personal Settings → Keys and generate a new token.
- Paste the new token into Settings → Tailscale → API Token.
Tailnet devices are missing from the browser
- Only authorised devices appear in the browser. Check your Tailnet's device authorisation settings.
- Confirm the API token was generated for the correct Tailnet account.
- Try pulling to refresh the device list.
Tailscale SSH connection fails
- Confirm the Tailscale app is installed, open, and connected to your Tailnet.
- Confirm the target device is online in your Tailnet (visible in the Tailscale admin console).
- Confirm Tailscale SSH is enabled in your Tailnet ACLs for the target device. See Tailscale SSH docs.
- Both your iPhone and the server must be on the same Tailnet.
Security warnings
Host key mismatch
⚠ Host key mismatch for [hostname]!
Stored: [expected fingerprint]
Received: [actual fingerprint]
The server's host key has changed since you last connected. This can indicate:
- Legitimate change: the server was rebuilt or its SSH keys were regenerated.
- Security issue: a man-in-the-middle attack.
If you are confident the key change is legitimate:
- Go to Settings → Known Hosts.
- Find the entry for the affected host and swipe left to delete it.
- Reconnect — you will be prompted to trust the new fingerprint.
If you are not sure, do not connect and investigate the server directly.
Key installation issues
"Connect via the terminal first to trust this host."
The host's key is not yet in your known hosts store. The Install on a Host flow uses strict verification and will not prompt you to trust an unknown host.
- Tap the host in the main host list to open a normal terminal session.
- Accept the host key fingerprint when prompted.
- Return to Settings → SSH Keys, tap the key, and use Install on a Host again.
Installation fails with an authentication error
- The credentials stored for the selected host may be incorrect or the account may not have permission to write to
~/.ssh/authorized_keys. - Try connecting to the host via the terminal to confirm the credentials work, then retry the installation.
Key appears to install but authentication still fails
- Confirm the
~/.sshdirectory has permissions700and~/.ssh/authorized_keyshas permissions600on the server. - Check that
PubkeyAuthentication yesis set in/etc/ssh/sshd_configon the server. - If the file had incorrect permissions before installation, correct them and reconnect.
SSH key import errors
"The key format is not recognised."
- Ensure you are pasting the entire private key file, including the
-----BEGIN OPENSSH PRIVATE KEY-----and-----END OPENSSH PRIVATE KEY-----header and footer lines. - The key must be in OpenSSH format, not PEM/PKCS8. To convert:
ssh-keygen -t ed25519 -m OpenSSH.
"Encrypted (passphrase-protected) keys are not supported."
meshTerm does not support passphrase-protected keys. To remove the passphrase from an existing key:
ssh-keygen -p -N "" -f ~/.ssh/id_ed25519
"Unsupported key type. Only Ed25519 keys are supported."
meshTerm supports Ed25519 keys only. To generate a compatible key:
ssh-keygen -t ed25519 -C "your label"
App Lock issues
"meshTerm requires a device passcode to protect your SSH credentials."
App Lock requires a device passcode to be set before it can be enabled.
- Go to iOS Settings → Face ID & Passcode and set up a passcode.
- Return to meshTerm and enable App Lock in Settings.
Snippet Vault
Snippets are not sent to the terminal
- Ensure you have an active terminal session open before opening the Snippet Vault.
- If the session was disconnected, reconnect and try again.
SFTP File Browser
"SFTP subsystem not available" or the browser fails to open
- The server does not have the SFTP subsystem enabled. In OpenSSH, ensure
/etc/ssh/sshd_configcontainsSubsystem sftp /usr/lib/openssh/sftp-server(the exact path varies by distro) and restartsshd. - The user's login shell may be restricted (e.g.
/usr/sbin/nologin, rbash). SFTP needs a shell the SSH server can invoke.
Permission denied when renaming, deleting, or creating folders
- Your account needs write permission on the target directory. Check with
ls -laon the server. - Some SFTP servers deny
renameacross filesystems — keep the rename target in the same directory.
Uploads or downloads stall mid-transfer
- If the SSH session itself drops, the transfer is cancelled. Check your connection and retry — automatic reconnection will restore the session and you can start the transfer again.
- Very large transfers (multi-GB) are supported but depend on the stability of both endpoints and any firewall/NAT idle timeouts in between.
Terminal Macro Bar
Tapping a macro does nothing
- You need an active terminal session — the macro bar sends text to the focused tab.
- Confirm the macro's command text is not empty in Settings → Keyboard → Macros.
Purchases
"Purchase could not be verified."
There was a problem verifying your purchase with the App Store.
- Ensure your device has a working internet connection.
- Try Restore Purchases in Settings.
- If the issue persists, contact Apple Support via the App Store.
meshTerm is developed by James Betchley. For support or feedback, please open an issue on GitHub.