meshTerm 2.3.4 - Troubleshooting
By what you see: symptom, why, fix.

How to read this page

Each entry starts with the message or symptom, in the words the app uses, then says why it happens and the fix. Bold names are buttons in meshTerm. Where the app can fix something with one tap, that button is the first thing listed; the commands are for when a tap cannot work (for example the server cannot be reached, so nothing can be run on it for you). Button names and messages follow meshTerm 2.3.3. On older versions the same causes and commands apply; you just run the commands yourself.

Commands

Run commands on the server (in a meshTerm terminal, or in your provider's web console), not on the phone. They are written for a normal user with sudo:

  • Signed in as root? Leave out the leading sudo. Fresh Debian, Ubuntu and Alpine images have no sudo at all.
  • No sudo on the host? Wrap the whole command in su -c '...'. It asks for the root password. meshTerm does the same in the install commands it offers ("Needs the root password.").
  • On Debian and Ubuntu, run apt-get update before apt-get install. A fresh server's package lists are empty and the install fails with "Unable to locate package". Every Debian and Ubuntu command here already includes it.

1. Getting connected

Most connection failures show a failure page with the cause in plain words and the next step as buttons, such as Edit Host, Copy Public Key, Show Install Command, Server Setup Help and Reconnect. For the short version of the basics (hostnames that do not resolve, a connection that hangs at "Connecting...", Tailscale), see Troubleshooting in the user guide.

"HOST refused the connection on port 22. Check that SSH is running on that port."

WhyThe host answered, but nothing is listening for SSH on that port. The SSH server (sshd) is not installed, is stopped, or listens on a different port. A brand-new server often has no SSH server yet.

Fix

Tap Server Setup Help on the failure (it is also on Add Host's first step as New server? How to turn on SSH). It lists the commands for your system. You need console access to the server, for example your provider's web console, because the phone cannot reach it yet.

# Debian, Ubuntu
sudo apt-get update && sudo apt-get install -y openssh-server
sudo systemctl enable --now ssh

# Fedora
sudo dnf install -y openssh-server && sudo systemctl enable --now sshd

# Alpine (as root)
apk add openssh && rc-update add sshd && rc-service sshd start

On a Mac, turn on Remote Login in System Settings, under General, Sharing. To check which port sshd uses and whether it is listening, run sudo ss -tlnp | grep sshd, then put that port in Edit Host.

The service is named ssh on Debian and Ubuntu and sshd on Fedora. A related message, "accepted the connection but didn't start SSH", means something is listening on the port but it is not an SSH server (or it is still starting). Check that sshd is running on that port.

"Couldn't reach HOST:22. Check that the host is online and on the same network or tailnet." / "The Host Didn't Answer"

WhyNothing came back at all. Usually a firewall on the server or a cloud security group is dropping the traffic, the IP address is wrong, the server is off, or it has only a private address and you are not on that network. A refused connection (above) means the host answered; a timeout means it did not.

Fix
  • Check the address and that the server is running. In your provider's console, confirm the public IP.
  • Cloud servers: open the provider's firewall (security group, firewall rule) for TCP port 22, or your own SSH port. Allowing only your own IP is safer than allowing everyone.
  • Tailscale needs no open port. If both ends are on your tailnet, connect by the host's tailnet name or 100.x address and close port 22 to the internet. See the Tailscale Setup Guide.
  • Host on your home or office network: grant meshTerm the Local Network permission in iOS Settings, under Privacy & Security.
  • Server firewall on the host itself. Server Setup Help shows these with your port filled in; they open only the SSH port:
# Ubuntu, Debian (ufw)
sudo ufw allow 22/tcp

# Fedora (firewalld)
sudo firewall-cmd --permanent --add-service=ssh && sudo firewall-cmd --reload

If connections work and then drop when idle, a firewall or NAT in between is closing quiet connections. Set ClientAliveInterval 60 in /etc/ssh/sshd_config and reload sshd.

"HOST rejected the password for USER. Check the username and password in Edit Host."

WhyEither the username or password is wrong, or the server does not allow password sign-in for that account. Many cloud images turn password sign-in off, and many servers refuse root's password altogether (PermitRootLogin). For root, the app adds: "Many servers refuse root's password (PermitRootLogin). Sign in as a normal user, or use an SSH key."

Fix
  • Open Edit Host and re-enter the username and password. Usernames are case sensitive.
  • Sign in as a normal user instead of root. Cloud images usually create one for you, for example ubuntu on Ubuntu images or ec2-user on Amazon Linux. The username field's hint reads "ubuntu, admin, your-name...".
  • Better, use an SSH key (see server only accepts SSH keys). We recommend against turning on PermitRootLogin yes.

A saved password that is wrong can repeat on every reconnect and may trigger fail2ban. Fix the password first.

"HOST only accepts SSH keys for USER. Add a key to the server (Show Install Command), then choose it in Edit Host."

WhyThe server has PasswordAuthentication no, which is the default on most cloud images and a good security setting. Only a key will work.

Fix

On the failure page:

  • Show Install Command opens a sheet with the key's one-line authorized_keys command. For a password host it lets you pick a key or tap Generate a New Key.
  • Copy Public Key copies the key in one tap (the button flips to "Copied").
  • Install on Host appears only when another saved host reaches the same server and user with a different working sign-in (a saved password, Tailscale SSH or a different key). It installs the key through that host.

Otherwise run the command once on the server from a session that already works, your provider's web console, or cloud-init. The command the app shows appends your public key to the file:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
printf '\n%s\n' 'ssh-ed25519 AAAA...your-public-key... meshterm' >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Then choose that key in Edit Host and tap Reconnect. Run it once: running this by hand twice adds the key twice (Install on Host in the app does not).

"HOST rejected the SSH key for USER. Add its public key to ~/.ssh/authorized_keys for that user, or choose another key in Edit Host."

WhyThe server does not recognise the key. The public key is not in that user's authorized_keys, the key in Edit Host is a different one, or the file or folder has permissions sshd refuses to trust.

Fix
  • Use Copy Public Key and Show Install Command as above, and check that Edit Host uses the key you installed.
  • Check the server side. sshd silently ignores keys when the folder or file is too open:
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
chmod go-w ~          # the home folder must not be writable by others
sudo grep -i pubkeyauthentication /etc/ssh/sshd_config   # should not say "no"
  • "didn't accept key sign-in for USER on its own": either key sign-in is off for this user, or the server also wants a password after the key (AuthenticationMethods), which meshTerm does not support yet. Switch to password sign-in in Edit Host, or allow key-only sign-in on the server.
  • Alpine: an account created with adduser -D is locked, and sshd refuses even key sign-in ("account is locked"). Set a password once with passwd USER (as root); that unlocks it.
  • Check that the key type is supported: see RSA keys can't be used.

"RSA keys can't be used in this app yet. Generate an Ed25519 key instead." / "Unsupported key type"

WhymeshTerm signs in with Ed25519 and ECDSA (P-256, P-384, P-521) keys. RSA user keys are not supported, so an imported RSA private key is refused.

Fix
  1. On the import error, tap Generate an Ed25519 Key Instead. It makes the key (named after your import) and moves to Add the Key to the Server.
  2. That step shows the one-line authorized_keys command with Copy and Copy Public Key. Run it on the server. It adds the new key next to your RSA key, which keeps working for your other apps.
  3. Add Host has the same shortcut: Generate a New Key beside Import. Existing keys: SSH Keys, open a key, Add It Yourself.

From a computer that can already sign in, the classic way also works:

ssh-keygen -t ed25519
ssh-copy-id -i ~/.ssh/id_ed25519.pub USER@HOST

Then import that key into meshTerm. See SSH keys in the guide.

"Couldn't set up a secure connection with HOST: it most likely only offers an RSA host key, which meshTerm can't use yet."

WhyThe server proves who it is with a host key. meshTerm understands Ed25519 and ECDSA host keys, not RSA. A server that offers only an RSA host key (an old install, or a HostKey line that lists only the RSA file) cannot complete the handshake. The app cannot tell this apart from other handshake problems, so it names the likeliest cause.

Fix

On the server, create the missing host keys, including Ed25519, then reload sshd:

sudo ssh-keygen -A
grep -i '^HostKey' /etc/ssh/sshd_config      # if present, make sure an ed25519 line is listed

# reload sshd
sudo systemctl reload ssh      # Debian, Ubuntu
sudo systemctl reload sshd     # Fedora
sudo rc-service sshd reload    # Alpine

After this, meshTerm shows the unknown host key prompt as for any new host (see the next entry).

"Unknown Host Key" and "Host Key Changed"

WhyThe first time you connect, meshTerm shows the server's key fingerprint and asks you to trust it. If a server later presents a different key, you see Host Key Changed: "the host was reinstalled or its address changed. Trust the new key only if you expected this." It can also mean someone is intercepting the connection, which is why the prompt never trusts by default.

Fix

Compare the fingerprint on screen with the server's own, from the server's console (not over the connection you are checking):

ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
# the file follows the key type the prompt shows, for example:
ssh-keygen -lf /etc/ssh/ssh_host_ecdsa_key.pub

If the fingerprints match, tap Trust Host. For a changed key: if you rebuilt or re-imaged the server, trust the new key; if you did not, do not connect and look at the server first. You can also see and remove saved keys in Settings > Hosts & Network > Trusted servers: remove one to be asked again at the next connect. Cloud consoles often print the host key fingerprints at first boot, which is another way to check.

"Host key not trusted yet" on some screens (the Containers Fleet, the Sessions list, system usage) means you have not trusted the host yet: open the host once from the Sessions tab, review the key, then try again.

"HOST only allows keyboard-interactive sign-in for USER, which meshTerm doesn't support."

WhySome servers ask questions at sign-in instead of taking a plain password: a one-time code from an authenticator app, a hardware key prompt, or a PAM password prompt on a server with PasswordAuthentication no. That is "keyboard-interactive", and meshTerm cannot answer it. This is also what two-factor authentication on SSH usually looks like, so 2FA accounts cannot sign in this way.

Fix
  • Add an SSH key for this user (the safer fix): Show Install Command, as in server only accepts SSH keys. This works when the server accepts a key alone.
  • A server that requires a key and a code (AuthenticationMethods publickey,keyboard-interactive) cannot be used. Use Tailscale SSH for that machine, or give meshTerm its own account that allows a key alone.
  • Or turn on PasswordAuthentication yes in /etc/ssh/sshd_config and reload sshd. This lets anyone try passwords on that server, so use it only if you accept that, and ideally with fail2ban or a firewall in front.

"HOST closed the connection during sign-in, often a block after too many attempts (fail2ban)."

WhyTools such as fail2ban ban an IP address after several failed sign-ins. Your phone's address is then dropped or reset until the ban ends.

Fix

Wait a few minutes, fix the password or key that was failing, then reconnect. If you have console access you can lift the ban:

sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip YOUR.IP.ADDRESS

To stop it happening again, sign in with a key (a wrong saved password is the usual trigger) or add your tailnet or home network to fail2ban's ignoreip.

"Tailscale SSH on HOST didn't accept USER."

WhyThe host was added as a Tailscale SSH host (no password or key), but either your tailnet's SSH rule does not allow that user, or the server is not running Tailscale SSH.

Fix

Check your tailnet's SSH rule in the Tailscale admin console. On the host, turn Tailscale SSH on:

sudo tailscale up --ssh

Or switch the host to key or password sign-in in Edit Host; a Tailscale-connected host still accepts those over your tailnet. Details are in the Tailscale Setup Guide.

Pasting user@host:port, ssh://... or an IPv6 address

WhyPeople paste whatever they copied from a terminal or provider page. meshTerm sorts it out for you.

Fix

Paste it into Hostname and move on. meshTerm trims it, removes ssh:// and any path, puts the part before the last @ into an empty Username field, and puts :2222 into the Port field if it is empty or still 22. [2001:db8::1]:2222 works for IPv6; a bare IPv6 address is left alone. A password inside the URL (ssh://user:secret@host) is dropped, never saved.

"The hostname can't contain spaces or symbols. Enter just the name or IP address." means something is left over after that, such as a space or URL punctuation. If the pasted port and the Port field disagree, the form asks you to choose one.

Key installed but Windows still asks for a password

WhyThe Windows SSH server reads a different file depending on the account. A standard account uses C:\Users\<you>\.ssh\authorized_keys. An administrator uses C:\ProgramData\ssh\administrators_authorized_keys, and Windows ignores that file unless it is locked to Administrators and SYSTEM. A server can also point AuthorizedKeysFile somewhere else, such as C:\ProgramData\ssh\keys\..., where a standard account can't write. Wrong permissions on the file have the same effect.

Fix
  • Use Install Key on the host. meshTerm picks the right file for the account. If it says an administrator needs to add the key, send that person the public key and the file name it shows.
  • If meshTerm says it added the key but you should check, look at AuthorizedKeysFile in C:\ProgramData\ssh\sshd_config and make sure the key is in the file it names.
  • Administrator accounts: the file must be locked to Administrators and SYSTEM only. In an administrator PowerShell:
icacls.exe $env:ProgramData\ssh\administrators_authorized_keys /inheritance:r /grant *S-1-5-32-544:F /grant *S-1-5-18:F

Then try again. Details are in Windows hosts.

Permission denied signing in to a Windows host

WhyThe Windows SSH server decides who may sign in. Many servers allow only members of Administrators or the OpenSSH Users group (an AllowGroups line in C:\ProgramData\ssh\sshd_config). A standard account that is in neither is refused, even with the right password or key. An account that has never signed in to Windows also has no profile yet.

Fix

Ask an administrator to add the account to OpenSSH Users. In an administrator PowerShell:

net localgroup "OpenSSH Users" USER /add

If the group doesn't exist, check AllowGroups in the config for the group the server uses. Make sure the account has signed in to Windows once, then try again.

Tailscale SSH is missing for a Windows host

WhyTailscale SSH (Tailscale's own SSH server with tailnet sign-in) isn't available on Windows, so meshTerm doesn't offer it for Windows hosts. A device that Tailscale reports as Windows starts on password sign-in.

Fix

Connect to the machine's tailnet name or 100.x address with a key or a password, like any other host. The Windows OpenSSH server must be running on it. See Windows hosts.

2. Terminal and persistence

Persistence is chosen per host: tmux, mtRoam or None. See Persistent sessions and Check persistence in the guide.

"No session persistence": "tmux isn't installed on HOST, so this session won't persist."

WhyThe host is set to tmux but has no tmux, so you got a plain shell that ends with the connection. Fresh servers rarely have tmux.

Fix

Tap Install tmux on the banner. meshTerm pastes the install command for your system at the prompt; you read it and press Return, and it never runs by itself. In the Sessions list, "tmux wasn't found" offers Install tmux in Terminal, which opens a terminal that runs the command shown above it. Which command you get depends on who you are on the server:

  • root: no sudo.
  • A user with sudo: the sudo form. sudo asks for your password in the terminal.
  • A host with no sudo (fresh Debian, Ubuntu, Alpine): su -c '...', with "Needs the root password."
  • An account that cannot use sudo (not in the sudo, wheel or admin group): the sudo form still shows, with "If your account can't use sudo, ask the server's admin to run this." If it fails, sign in as root or an admin account, or ask the server's admin.
# Debian, Ubuntu
sudo apt-get update && sudo apt-get install -y tmux
# no sudo on the host
su -c 'apt-get update && apt-get install -y tmux'
# as root
apt-get update && apt-get install -y tmux

# Fedora, RHEL, Rocky, Alma         sudo dnf install -y tmux
# Amazon Linux 2, CentOS 7          sudo yum install -y tmux
# Alpine (as root)                  apk add tmux
# openSUSE                          sudo zypper install -y tmux
# Arch                              sudo pacman -S --noconfirm tmux

Prefer not to install it? Set the host's Persistence to None to stop the banner. The mtRoam alternative is in the guide.

"tmux wasn't found on HOST. ... If it's already installed, add its folder to PATH in ~/.bashrc or ~/.zshenv."

WhyA tool installed with Homebrew on a Mac lives in /opt/homebrew/bin (Apple silicon) or /usr/local/bin, and the PATH an SSH command gets on macOS is only /usr/bin:/bin:/usr/sbin:/sbin. meshTerm looks in /usr/bin, /usr/local/bin, /opt/homebrew/bin and /opt/local/bin as well, so a Homebrew tmux is normally found. If yours still is not, it is installed somewhere else or not at all.

Fix

No tmux yet? The command is brew install tmux (never with sudo). "No Homebrew on this Mac? Install it first from brew.sh, then run the command." If tmux is installed in an unusual place, add its folder to your PATH in a file that non-interactive SSH reads. ~/.profile is not read by SSH commands, so use ~/.zshenv (zsh, the Mac default) or the top of ~/.bashrc:

brew install tmux
echo 'export PATH="/opt/homebrew/bin:$PATH"' >> ~/.zshenv

"tmux 3.1 is too old (3.2 or newer needed)." / "Using classic tmux"

WhyNative panes and the tmux palette page use tmux control mode, which needs tmux 3.2. With an older tmux, meshTerm falls back to the classic tmux attach by itself, so the session still persists, just without native panes. Some long-term-support distros still ship older versions (Ubuntu 20.04 and Debian 11, for example).

Fix
tmux -V

A newer tmux usually comes from your distro's backports or EPEL, a newer distro release, or a static build. After upgrading, tap Check persistence on the host's Details so meshTerm tries control mode on the next connect. Nothing is broken if you leave it: sessions persist either way.

"Couldn't start tmux control mode on HOST." / control mode misbehaves on one host

WhyControl mode is the default way meshTerm talks to tmux 3.2 or newer. Unusual shell start-up files, wrappers around tmux, or restricted shells can interfere.

Fix

Reconnect to try again, or use classic tmux for that host: Edit Host > Session > tmux attach > Legacy. Other hosts keep control mode, and you can switch back any time. See Control mode or Legacy.

"mtRoam isn't installed on this host. Using tmux."

WhyThe host's Persistence is mtRoam, but the mtroamd daemon is not on the host. meshTerm cannot install it for you from the app, so it carries the session through tmux instead.

Fix

Tap Switch to tmux to make tmux the host's setting for good, or Install guide to install mtroamd (see Installing mtroamd). If tmux is missing too, the first banner is "No session persistence" with Install tmux; after you dismiss it, the mtRoam notice offers Install tmux as well. After installing mtroamd, tap Check persistence on the host's Details to use it straight away. For "Connection Failed" on an mtRoam host and the other mtRoam messages, see the guide's troubleshooting.

Garbled accents, boxes or odd characters in some programs (locale)

WhyAn SSH command without a login does not always get a UTF-8 locale. Measured on fresh images: Debian 12 and Ubuntu 22.04 give the plain POSIX locale, Ubuntu 24.04 and Fedora give C.UTF-8, a Mac gives C, and Alpine has no locale tool. Many servers do not accept the client's language setting either (Fedora and Alpine's sshd have no AcceptEnv), so it is dropped. UTF-8 text itself passes through fine; only programs that check the locale can misbehave.

Fix
locale                                   # what does this session have?
echo 'export LANG=C.UTF-8' >> ~/.bashrc       # Linux (use ~/.zshenv for zsh)
echo 'export LANG=en_US.UTF-8' >> ~/.zshenv   # macOS

Put it in ~/.bashrc or ~/.zshenv, not ~/.profile, so that non-interactive SSH commands see it. Inside tmux, tmux -u forces UTF-8 for a client.

3. Files (SFTP)

"The file service isn't available on HOST: its SSH server has no SFTP."

WhymeshTerm's file browser, attachments and uploads use SFTP, an SSH subsystem. The server answered "no" to it, or the Subsystem line points at a program that does not exist. On Debian and Ubuntu the SFTP package comes with openssh-server and Alpine's openssh includes it, so the realistic cause is a sshd_config that was edited. There is no Try Again button because retrying cannot help. (Older versions of the app waited forever instead of saying so.)

Fix

Add this line to /etc/ssh/sshd_config (remove any other Subsystem sftp line first), then reload sshd:

Subsystem sftp internal-sftp

sudo sshd -t                    # check the file first
sudo systemctl reload ssh       # Debian, Ubuntu
sudo systemctl reload sshd      # Fedora
sudo rc-service sshd reload     # Alpine

If you would rather keep the external program, make sure its package is there (Debian or Ubuntu):

sudo apt-get update && sudo apt-get install -y openssh-sftp-server

The same message appears for a terminal attachment on that host, with the same commands. See SFTP file browser.

"HOST's file service didn't answer in time. Try again."

WhyThe SSH connection worked, but the SFTP server did not start answering within about 15 seconds. The host may be overloaded, very low on memory, or the link is slow or lossy.

Fix

Tap Try Again. If it keeps happening, look at the server: uptime (load), free -h (memory) and df -h (a full disk slows everything). A closer or wired route, or connecting over Tailscale, helps on a poor link. If the problem is only in huge folders, work in a subfolder.

"refused the rename", "refused to create the folder", "refused to delete this item", "refused the upload"

WhyThe server's permissions say no. Your account needs write permission on the folder. Other causes: the name already exists, a folder has to be empty before deleting, the disk is full, or the file is in use. Some SFTP servers also reject renames across filesystems.

Fix
ls -ld /path/to/folder        # who owns it, and who can write
df -h /path/to/folder         # is the disk full?
sudo chown -R $USER: /path/to/folder   # only if the folder should be yours

Keep a rename target in the same folder. Avoid signing in as root just to fix permissions; change the ownership or group instead.

4. Port forwarding

"HOST doesn't allow port forwarding. Set AllowTcpForwarding yes in /etc/ssh/sshd_config, then reload sshd."

WhyThe server's sshd refused the forward ("administratively prohibited"). The same cause shows up as "This host's SSH server blocks port forwarding" on a tunnel row and "Port Forwarding Is Off" when Containers opens a web page through a forward.

Fix

The row has the line to copy. On the server:

AllowTcpForwarding yes       # in /etc/ssh/sshd_config

sudo sshd -t
sudo systemctl reload ssh    # Debian, Ubuntu (sshd on Fedora; rc-service sshd reload on Alpine)

meshTerm only needs local (-L) and dynamic (-D) forwards, so AllowTcpForwarding local is enough and is the narrower choice. Check for a Match block or a per-user PermitOpen that overrides it. See Port forwarding & Tunnels.

5. Agents

Claude, Codex and Gemini run on your host, not on the phone. The host needs each tool's CLI installed and signed in. They install into your home folder, so once the host has curl (or npm or Homebrew), no root access is needed. See Agent Mode.

"Prepare This Host" in Set Up Agents

WhyThe official installers are scripts that download the CLI, so the host needs curl and bash (Claude's and Antigravity's installers are bash scripts; Codex's is plain sh). A bare server may have neither: a fresh Debian 12 has no curl; Ubuntu has none either; Alpine has neither curl nor bash. When no curl, npm or Homebrew is found and an agent is missing, Set Up Agents shows Prepare This Host. Alpine hosts without bash say "no bash" up front.

Fix

Tap Run in Terminal on the line shown for your system (it opens a terminal on the host and types the command; sudo or su asks for its password there), then Check Again. Same commands by hand:

# Debian, Ubuntu
sudo apt-get update && sudo apt-get install -y curl ca-certificates
# Fedora
sudo dnf install -y curl ca-certificates
# Alpine (as root; also gets bash)
apk add curl bash ca-certificates
# no sudo on the host:  su -c 'apt-get update && apt-get install -y curl ca-certificates'
# root:                 leave out sudo

A Mac already has curl and bash. Gemini goes through Antigravity's agy CLI.

Sign-in fails or spins: "Codex said: ..." / "Starting sign-in..."

WhyCodex signs in with a device code. Some ChatGPT accounts need that turned on first. When the sign-in ends with an error before a link or code appears, meshTerm shows the last line Codex printed. Under "Starting sign-in..." the host's own output appears after about ten seconds if nothing else does.

Fix
  • Codex: in ChatGPT, open Settings > Security and turn on device code sign-in. Then Try Again. Open Terminal runs codex login on the host yourself; codex login status shows where you stand.
  • Claude: the failure quotes Claude's last line. claude auth status shows which account is signed in and claude auth login signs in.
  • Gemini: open Set Up Agents on that host, follow Google's link and paste the code back within about a minute. agy cannot always report whether it is signed in, so if an agent fails to start, sign in again there.
  • If the sign-in cannot find node, see the CLI isn't on the SSH PATH.

"NAME needs node on the SSH PATH." / the CLI is installed but "not found"

WhyAgents start through a non-interactive SSH command, which does not read your interactive shell set-up. A CLI installed with npm is a #!/usr/bin/env node script, and nvm only puts node on the PATH in interactive shells. Homebrew's folder (/opt/homebrew/bin on a Mac) is not on the SSH PATH either. meshTerm adds the usual places for you (~/.local/bin, ~/.npm-global/bin, /usr/local/bin, /opt/homebrew/bin, Linuxbrew, volta, mise and asdf shims, fnm's default), but nvm has no fixed folder.

Fix

Run this in a terminal on the host (where node works), then tap Check Again. The app shows the same line:

mkdir -p ~/.local/bin && ln -s "$(command -v node)" ~/.local/bin/node

For a CLI itself that cannot be found, link it the same way, for example ln -s "$(command -v codex)" ~/.local/bin/codex. Putting an export PATH=... line in ~/.profile does not help, because SSH commands do not read it; use ~/.bashrc (near the top) or ~/.zshenv.

"Folder Not Found" when starting an agent

WhyThe working folder you chose (for example ~/new-project) does not exist on the host. A ~ is expanded to the host's home folder.

Fix

Tap Create Folder (it runs mkdir -p and starts the agent there; if it fails, an alert says why), or Use Home Folder for an agent that has not run yet. Claude files its conversations per folder, so Use Home Folder is not offered for an agent that already has history.

Using an API key instead of signing in (Use an API Key Instead)

WhySign-in is the default. An API key is the alternative when browser sign-in is not possible or you pay per use.

Fix

The setup sheet explains it per agent:

# Claude: near the top of ~/.bashrc, or in ~/.zshenv (NOT ~/.profile)
export ANTHROPIC_API_KEY=your-key

# Codex: set OPENAI_API_KEY in a terminal on the host, then
printenv OPENAI_API_KEY | codex login --with-api-key

~/.profile does not work because an SSH command runs $SHELL -c and never reads it. Codex keeps the key with its own sign-in, which every SSH command sees. Keep files that hold keys readable by you only (chmod 600). With Pro, Secret Profiles can hold keys on the phone instead. Gemini has no API-key option in the app.

Agents on a Mac host

WhyA stock Mac differs from Linux: no setsid or timeout, sleep infinity is rejected, /usr/bin/python3 and /usr/bin/git are stubs that ask to install Apple's Command Line Tools, and the SSH PATH is only /usr/bin:/bin:/usr/sbin:/sbin. meshTerm works around the first ones itself (it starts agents with setsid or else nohup, and time-limits checks with timeout, gtimeout or perl).

Fix
xcode-select --install     # real python3 and git (notifications and live status need python3)
brew install coreutils     # optional: gives gtimeout

Make sure Remote Login is on, and see Homebrew on a Mac and PATH for tools that are installed but not found. "python3 needs Apple's command line tools" in herdr or notifications means the stub, not a real python3.

"This host blocks unprivileged user namespaces and has no bubblewrap, so Codex's sandbox can't start and it will ask approval for every command."

WhyCodex isolates commands with bubblewrap, which needs the package and a kernel that lets ordinary users create namespaces. Related messages: "Harden with Bubblewrap is on, but bubblewrap isn't installed", and "bubblewrap is installed but can't start a sandbox, usually because unprivileged user namespaces are turned off".

Fix

Install it (Set Up Agents shows the line for your system, with Copy):

# Debian, Ubuntu
sudo apt-get update && sudo apt-get install -y bubblewrap
# Fedora
sudo dnf install -y bubblewrap
# Alpine (as root)
apk add bubblewrap

If it is installed but cannot start, namespaces are off. Check with sysctl user.max_user_namespaces (0 means off). Ubuntu 24.04 also restricts them with AppArmor (kernel.apparmor_restrict_unprivileged_userns); loosening that setting weakens a protection for the whole machine, so decide deliberately. Or turn off Harden with Bubblewrap in the agent's settings. Without a working sandbox, Codex simply asks for approval for each command.

6. Notifications

Agent notifications use a small hook on the host and Apple's push service through the relay. See Notifications in the guide.

Notifications don't arrive

WhyThe host setup, the agent's session or the phone's notification settings may be stopping delivery.

Fix

First open Edit Host and tap Send Test Alert. Turn on Notify this iPhone or Notify this iPad and save first if needed. The test checks this host's path to this phone; a successful test does not prove a running agent has loaded its hooks. Ayuda en espaƱol.

  • Not checked yet: there is no saved result. Use Send Test Alert to check, or Install Now to set up the host. Installed on this host means setup succeeded; test delivery next.
  • Not installed, or the test finds missing notification files: tap Install Now.
  • Missing Python or curl: run the install command shown on the host, then tap Try Again. See Host tools.
  • "Couldn't install:" or a failed last check: correct the stated cause, then tap Try Again. Check SSH access; a folder that is not private to your user needs its ownership and permissions fixed, and shell startup files must not print text or read input during non-interactive SSH commands.
  • "This device's registration changed. Tap Reinstall to update this host." or "This device's registration on the host is out of date.": tap Reinstall.
  • "The relay no longer has this device's registration.": tap Register Again to register this phone again and refresh the host's details.
  • "Codex alerts start once Codex trusts the hook. Tap Try Again.": tap Try Again.
  • "The relay refused the test alert's format. Tap Reinstall.": tap Reinstall. If the host cannot reach the relay or does not confirm the test, tap Try Again; if the relay is busy, wait before retrying.
  • The relay accepted the test but it did not arrive: tap Open Settings, allow meshTerm notifications and check Focus. Also check the two switches in Settings > Agents > Notifications.

If the test arrives but agent alerts do not, exit and restart the agent after hooks are installed. Run it in a meshTerm-managed tmux or mtRoam session, a herdr pane, or a chat in the Agents tab. A plain SSH tab or your own tmux session started outside meshTerm has no session record telling the host which phone should receive the alert. On Windows use psmux for Claude, Codex or agy (Gemini). Codex in herdr panes alerts through herdr; enable Notify for herdr Agents for herdr alerts.

On Windows and Linux, when two Codex windows share a folder, meshTerm can identify only one and the other can miss alerts. codex resume <id> always identifies the session for routing. With more than one phone or tablet set up for alerts on the host, only windows launched with codex resume <id> send Codex's background alerts. Use separate folders or resume the specific session. On macOS, run terminal Codex as codex --no-daemon, including in herdr panes, or use the Agents tab.

For question alerts such as "Claude has questions.", turn on Agent needs approval in Settings > Agents > Notifications. It controls both questions and approvals. Tap a question alert to open the session, then answer in the terminal; the alert has no answer or approval action. See Notifications for supported agents.

Notifications need Python 3.5 or later and curl

WhyLinux and macOS alerts need both tools. Python 2 alone, or Python older than 3.5, is not enough: the app says "Notifications need Python 3.5 or later on HOST. Its Python is older." A Mac's /usr/bin/python3 may only be a placeholder until the Command Line Tools are installed.

Fix

Run the command the host's status row shows, then tap Try Again. The agent chat banner also offers Run in Terminal. For example:

# Debian, Ubuntu
sudo apt-get update && sudo apt-get install -y python3 curl ca-certificates
# Fedora
sudo dnf install -y python3 curl
# Alpine (as root)
apk add python3 curl ca-certificates
# Mac: install the Command Line Tools
xcode-select --install

If Python was found but did not start, set a global Python version in pyenv or asdf and tap Try Again. meshTerm also searches Homebrew, conda and ~/.local/bin; see Host requirements. If the test says hooks cannot find or start Python, tap Reinstall. If it says agents started outside a login shell cannot find curl, install the system's curl so it is available in /usr/bin or /bin.

Windows: restricted PowerShell or old curl

WhyAlerts use Windows PowerShell 5.1 and the built-in curl.exe, with no Python dependency. Constrained Language Mode blocks setup; older Windows versions may lack curl or send alerts more slowly.

Fix
  • PowerShell Is Restricted: "PowerShell is restricted on HOST, so meshTerm can't turn on notifications there." Ask the host's administrator about the policy; retrying alone will not fix it.
  • Missing curl.exe: update Windows, then tap Try Again. Windows 10 version 1803 and later include it.
  • "This host's curl.exe is older than 7.68, so alerts go to your devices one at a time.": alerts still work, one phone at a time. Updating Windows or curl can speed delivery to multiple devices.

"Notifications are turned off for meshTerm in iOS Settings."

WhyThe host side may be fine, but iOS itself is not allowed to show meshTerm's alerts.

Fix

Tap Open Settings where it is offered, or go to iOS Settings > Notifications > meshTerm and turn on Allow Notifications. Check that no Focus mode is silencing it.

"Live Activities are off for meshTerm in iOS Settings."

WhyThe lock-screen and Dynamic Island status for running agents needs the Live Activities permission for the app.

Fix

In iOS Settings, open meshTerm's settings and turn on Live Activities. Alerts still arrive without them.

7. herdr

herdr keeps Claude, Codex and Gemini running on your host, each in its own pane. See herdr in the guide.

"meshTerm alerts aren't set up" / "Open this host in meshTerm" means the meshTerm plugin was installed outside the app and no device is set up for alerts. herdr attempts this notice at most once a week; its Set up meshTerm alerts action offers setup guidance on demand (a toast on Windows, if herdr's toast settings allow it). Open the host's herdr dashboard in meshTerm and tap Turn On in Turn on herdr alerts for this iPhone (or iPad / device).

"Set Up herdr", "herdr X is too old", "herdr has no build for HOST"

Whyherdr runs on your host, so the host needs herdr 0.9.2 or later in your home folder, plus python3 for live status (without it status updates only every few seconds, shown as "No python3: updates every few seconds"). Set Up herdr checks the host and installs herdr's official build in one tap, with no admin rights. Its installer needs curl, awk and a SHA-256 tool. Windows hosts need herdr 0.9.4 or later: see herdr install stopped on Windows.

Fix
  • Missing tools: the sheet shows the install line for your system. Run it, then Check Again. For Debian and Ubuntu that is, for example, sudo apt-get update && sudo apt-get install -y curl ca-certificates python3 (drop sudo as root).
  • "herdr is installed but doesn't run on this host. Its standard build may not suit this system (Alpine, for example)": the standard build is not for every system. Use the install guide's other ways.
  • "herdr X is in ~/.local/bin, but your login shell finds an older herdr first": update or remove the older one, then Check Again. If Homebrew installed it, brew upgrade herdr updates it.
  • "The installer finished, but HOST can't find herdr on this host": wait a moment and Check Again.
  • Update herdr appears when a host's herdr is older than the app needs.

On Linux and macOS, the notification plugin needs Python 3.5 or later and curl; see Host tools. Windows alerts use PowerShell and curl.exe instead; see Windows notification requirements.

herdr install stopped on Windows

WhyOn a Windows host the herdr install runs over your connection. If the connection drops, or you leave meshTerm, the install stops part way.

Fix

Keep meshTerm open and tap Try Again. Running the install again is safe. If it keeps stopping, check that the host is reachable and that curl.exe works there (current Windows includes it). herdr 0.9.4 or later on x86_64 is needed; ARM isn't covered yet. See herdr on Windows.

herdr says this host restricts PowerShell

WhySome company policies put PowerShell in Constrained Language Mode. herdr support on Windows needs full PowerShell, so it can't run on that host.

Fix

Ask an administrator to allow it for your account, then Check Again. Or use herdr in a plain terminal on the host.

8. Containers

The Containers tab (Pro) finds Docker, Podman, nerdctl and Apple's container tool on your hosts, shows them in a Fleet, and lets you start, stop and deploy. If you are new to containers, read Docker 101 first. When something stops a host, its Fleet card shows the failure (not a spinner) with the fix. Where a command is needed, Run in Terminal opens a terminal on the host and types it for you, and Copy copies it. After you fix it, tap Check Again or Try Again. Commands that need root show "Needs an administrator", and become su -c '...' ("Needs the root password.") on hosts without sudo; as root they have no sudo. Linux hosts are covered throughout; Mac hosts (Docker Desktop, OrbStack, Colima, Podman machine and Apple's container tool) need meshTerm 2.3.

"No Container Engine Found" / "Couldn't find a container engine on HOST. Install Docker or Podman on the host, then check again."

WhyNothing on that host looks like a container engine. The Fleet lists such hosts as "N hosts have no container engine" with Show; each opens its host screen with the install lines for its system.

Fix

Install one engine, then Check Again. The full walkthrough, with the choice between Docker and Podman, is in Docker 101. The short version:

# Debian, Ubuntu: the distro package
sudo apt-get update && sudo apt-get install -y docker.io
# ...or Docker's official convenience script (any of Ubuntu, Debian, Fedora, RHEL, CentOS)
curl -fsSL https://get.docker.com | sh
# let your user talk to Docker (read the security note first), then sign in again
sudo usermod -aG docker $USER
# ...or Podman, which needs no group and can run rootless
sudo apt-get update && sudo apt-get install -y podman

# Fedora
sudo dnf install -y podman

# Alpine (as root)
apk add docker docker-cli-compose && rc-update add docker default && rc-service docker start && addgroup $USER docker

# macOS
brew install --cask docker-desktop      # or: brew install --cask orbstack

Fresh Debian, Ubuntu and Alpine images have no sudo. Either sign the host in as root (every line then has no sudo and no group step), or set sudo up once as root:

su -c 'apt-get update && apt-get install -y sudo && usermod -aG sudo USER'      # Debian, Ubuntu
su -c 'dnf install -y sudo && usermod -aG wheel USER'                         # Fedora
su -c 'apk add sudo && addgroup USER wheel && echo "%wheel ALL=(ALL:ALL) ALL" > /etc/sudoers.d/wheel'   # Alpine

Replace USER with your SSH username, and sign in again. If your account is not allowed to install software at all, the app says "Your account can't install software on this host. Sign in as root or an admin account, or ask the server's admin." and keeps the command for the admin.

"Container Engine Not Running": "The container engine on HOST isn't running. Start it on the host, then try again."

WhyThe engine is installed but its service is stopped or not enabled. Related lines: "Docker is installed, but its system service isn't running and rootless Docker isn't set up", "The system Docker service is installed but turned off", and "Needs Setup" with "The engine is installed, but nothing answered. Its service may be installed but stopped."

Fix

Use the start command for your engine and init system. Run in Terminal on the card types it; Check Again afterwards.

# systemd (most Linux): system engines
sudo systemctl enable --now docker
sudo systemctl enable --now podman.socket
sudo systemctl enable --now containerd        # nerdctl

# systemd: rootless engines (your own user's service, no sudo)
systemctl --user enable --now docker
systemctl --user enable --now podman.socket

# OpenRC (Alpine)
sudo rc-service docker start && sudo rc-update add docker default
sudo rc-service podman start && sudo rc-update add podman default
sudo rc-service containerd start && sudo rc-update add containerd default

# macOS
open -a Docker              # Docker Desktop
open -a OrbStack
colima start
podman machine start
container system start      # Apple's container tool

Debian 12 with docker.io: the dockerd program lives in /usr/sbin, which is not on the PATH an SSH command gets on Debian, so the app cannot see it and says the service "may be installed but stopped". Starting the service works: sudo systemctl enable --now docker. If a command such as dockerd or sshd is "not found" in your own terminal, add the folders: export PATH="$PATH:/usr/sbin:/sbin".

"No Permission for the Container Engine": "The SSH user on HOST can't reach the Docker socket. Add the user to the docker group ..."

WhyThe engine's socket belongs to root and the docker group, and your SSH user is in neither. Rootful Podman's and containerd's sockets are root-only too ("The SSH user on HOST can't reach rootful Podman's socket" or "containerd's socket, which nerdctl uses"). Read this first: membership of the docker group is equivalent to root on that host, and anything that can use rootful Docker can read and change the whole machine. That is how Docker works, not a flaw, and for a personal server where you are already the administrator it is a common and reasonable choice. See Docker 101: security.

Fix
sudo usermod -aG docker $USER        # then sign out of the SSH session and in again
id                                   # check that "docker" is listed

meshTerm opens a new SSH connection, so tap Try Again after you have fixed it (the group applies to new connections). Other options: set the engine up with sudo (see sudo needs a password), add the host as root, or use rootless Docker or rootless Podman, which need no group and keep containers away from the host's root. A rootless engine that cannot be reached ("can't reach their own rootless engine") has a stopped user service: start it and keep it running with lingering.

Sudo needs a password: "Not Allowed to Use Sudo", "Sudo Check Didn't Pass", "sudo on HOST couldn't run the container engine"

WhySome engines run as root, so meshTerm runs their commands with sudo -n, which cannot ask for a password. If sudo wants a password, says "sorry, try again", "a password is required", "is not in the sudoers file", or "sudo: command not found", the engine cannot be used that way. A sudo password grants nothing on the host by itself; passwordless sudo for the engine is the same as root access to the host, which the app tells you before you choose it.

Fix
  • Use a Sudo Password (or Use My SSH Password when it is the same). meshTerm tests it first, before saving anything. If the test fails you see "Sudo Check Didn't Pass" and nothing is added. The password stays on this device in the Keychain and is removed with the host.
  • Passwordless sudo, narrowly. If you want no password, allow only the engine program, never everything:
command -v docker                                    # the full path, for example /usr/bin/docker
sudo visudo -f /etc/sudoers.d/meshterm-docker        # then add one line:
USER ALL=(root) NOPASSWD: /usr/bin/docker
  • Not a sudoer, or no sudo installed: the app shows the set-up line to run as root (see No container engine found), or add the host as root in Edit Host. Making an account a sudoer is copy-only, for root or another admin: sudo usermod -aG sudo USER (Debian, Ubuntu) or sudo usermod -aG wheel USER (Fedora).
  • Use Rootless Docker/Podman Instead is offered where it can work, and avoids sudo altogether.

Hosts under "Not Checked" in the Fleet

WhyThe Fleet lists every SSH host it could not check, with the reason and one way out, instead of hiding it. Windows hosts and hidden hosts are never listed.

Fix
Reason on the rowWhat to do
Host key not trustedTrust Host. It shows the fingerprint prompt (see host keys), then the host is checked.
No password or key on this device, so it couldn't sign inEdit Host, add the password or key.
Tailscale isn't connectedOpen Tailscale Settings, bring Tailscale up.
Not reachable, refused, no answer, not checked yetCheck Again checks that host alone. For the cause, see refused and timeouts.

"Couldn't Check Your Hosts" means every host was skipped; "No Containers Found Yet" has Check Again too. Pull down on the Fleet to check everything again. If Find Container Hosts Automatically is off in Settings > Containers, a new host is checked only when you pull to refresh. Without Pro, the Containers tab shows a read-only preview of your hosts and engines, and pulling down checks names only.

"Compose Not Installed", "Compose on this host is too old: found 1.29.2, need 2.x or newer", git missing

WhyStacks and templates need Docker Compose v2 (the docker compose command). Compose v1 (docker-compose with a hyphen) is too old. Debian's own Compose package is the old v1. Deploying from a Git repository also needs git on the host. "Stacks and templates need Compose v2, so Templates shows in the + menu once it's installed."

Fix
# Ubuntu
sudo apt-get update && sudo apt-get install -y docker-compose-v2
# Debian: Docker's script installs the Compose plugin (the Debian package is v1)
curl -fsSL https://get.docker.com | sh
# Fedora
sudo dnf install -y docker-compose
# Alpine
sudo apk add docker-cli-compose
# macOS
brew install docker-compose

# Any Linux: the official Compose v2 binary, as Docker's CLI plugin
sudo mkdir -p /usr/local/lib/docker/cli-plugins && sudo curl -fsSL "https://github.com/docker/compose/releases/latest/download/docker-compose-linux-$(uname -m)" -o /usr/local/lib/docker/cli-plugins/docker-compose && sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
# Podman: it looks for a docker-compose program on the PATH
sudo curl -fsSL "https://github.com/docker/compose/releases/latest/download/docker-compose-linux-$(uname -m)" -o /usr/local/bin/docker-compose && sudo chmod +x /usr/local/bin/docker-compose

# git
sudo apt-get update && sudo apt-get install -y git        # Debian, Ubuntu
sudo dnf install -y git                                  # Fedora
sudo apk add git                                         # Alpine
xcode-select --install                                   # macOS

Then tap Check Again on New Stack or the host's Stacks section; meshTerm reconnects to the host so it notices the change. The standalone curl lines need curl (see fresh-server notes).

"Port Already in Use": "Port 8080 is already used on HOST. Choose another host port."

WhyAnother container or program on the host already listens on that port, so the new container cannot publish it.

Fix

Tap Edit to go back to the form and pick a free host port (only the left number in 8080:80 changes). To find what holds it:

sudo ss -tlnp | grep ':8080 '
docker ps --format '{{.Names}}  {{.Ports}}'

"Rootless engines can't publish port 80 or any other port below 1024."

WhyOn Linux an ordinary (non-root) user cannot listen on ports below 1024, and a rootless engine runs as an ordinary user. New Container warns about it and offers Use 8080 (8000 plus the port, or the next free one).

Fix

Use a port of 1024 or higher, such as 8080, and reach the service on that port (or through meshTerm's web forwarding). If you truly need port 80 or 443, you can lower the host's limit, but the caveat matters: it lets every user on the host bind those ports, not just this engine.

sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
echo 'net.ipv4.ip_unprivileged_port_start=80' | sudo tee /etc/sysctl.d/99-unprivileged-ports.conf

A reverse proxy that runs as root (or with a system engine) on 80 and 443, forwarding to your container on a high port, is the other common choice. A Mac's engine never gets this warning.

"Host Out of Disk Space": "HOST is out of disk space. Free some space (Disk Usage can remove unused images), then try again."

WhyImages, stopped containers, build cache and logs add up, and a pull or create needs room. Also a stack whose file could not be written ("can't write") usually means the disk is full there.

Fix

Tap Open Disk Usage and remove unused images, or on the host:

df -h                       # which filesystem is full?
docker system df            # what the engine is using
docker image prune          # dangling images only
docker image prune -a       # every image no container uses (they can be pulled again)

Be careful with docker system prune --volumes: volumes hold your data, and it deletes unused ones. Check first.

"Image Not Built for This Host": "This image has no build for this host's processor (arm64). Pick a tag that's built for several processors."

WhyImages are built for a processor type. A common case is an amd64-only image on an Arm server (arm64, such as Oracle's or AWS Graviton's Arm instances, or an Apple silicon Mac), or the reverse.

Fix
uname -m        # x86_64 means amd64; aarch64 or arm64 means arm64

Choose a tag or an image that publishes both (most official images do; look for "Architectures" on the registry page). If an image only exists for the other processor, run it somewhere that matches, or build it for your host.

"Couldn't Reach the Registry", "Registry Login Needed", "Registry Certificate Not Trusted", "Registry Is Limiting Requests"

WhyThe host (not your phone) downloads images, so the host needs internet, DNS and CA certificates, and some images need a login.

Fix
  • "can't reach the image registry. Check the host's internet connection, DNS or proxy": test from the host. A 401 answer from the first line below still means the registry is reachable.
    curl -sI https://registry-1.docker.io/v2/ | head -1
    getent hosts registry-1.docker.io
  • "This image needs a registry login." Sign in to the registry on the host, in a terminal (the app pre-fills the image's registry; use sudo where that engine runs under sudo):
    docker login                          # Docker Hub
    docker login ghcr.io                  # another registry
    podman login ghcr.io                  # or: nerdctl login, container registry login
  • "The registry has no image by that name, or it's private." Check the name and tag, or log in.
  • "Registry Is Limiting Requests" (Docker Hub's anonymous pull limit): try again in a few minutes, or log in.
  • "Registry Certificate Not Trusted" ("usually because the host's CA certificates aren't installed"): minimal Debian images do not include them. A fresh server shows x509: certificate signed by unknown authority.
    sudo apt-get update && sudo apt-get install -y ca-certificates      # Debian, Ubuntu
    sudo dnf install -y ca-certificates                                # Fedora
    sudo apk add ca-certificates                                       # Alpine
    If your network intercepts HTTPS with its own certificate, add that CA to the host's trust store and run sudo update-ca-certificates (Debian, Ubuntu).

"Image Name Needs a Registry" (Podman: "short-name ... did not resolve")

WhyDocker assumes Docker Hub for a bare name like nginx. Podman does not: on Debian 12 and Ubuntu 24.04 it fails with "short-name "nginx" did not resolve to an alias and no unqualified-search registries are defined in /etc/containers/registries.conf"; on Fedora some names work and others say "short-name resolution enforced but cannot prompt without a TTY". Fully qualified names work everywhere.

Fix

meshTerm writes a bare name as docker.io/library/NAME (or docker.io/USER/NAME) for Podman in New Container's form, preview and review, and never picks a registry by searching. When you run Podman yourself, type the full name:

podman pull docker.io/library/nginx

To make bare names work for your user, add unqualified-search-registries = ["docker.io"] to ~/.config/containers/registries.conf (or the system file /etc/containers/registries.conf). Check the registry's trust before you do; bare names can resolve to a different image than you expect.

"Rootless Docker stops when USER signs out. Keep it running with lingering."

WhyA rootless engine is a service of your user, and systemd stops a user's services when their last session ends, which includes your SSH session. The containers go with it. "Lingering" keeps the user's services running without a session. The Fleet and the host screen show this as an advisory line for a ready rootless engine.

Fix
sudo loginctl enable-linger $USER
loginctl show-user $USER -p Linger      # Linger=yes

Tap Run in Terminal on the line, then Check Again.

Portainer: "Certificate Not Trusted Yet", "Portainer Environment Gone", "HTTPS Required", token errors

WhyPortainer servers are reached over HTTPS with an access token. Portainer makes its own certificate when it is installed, so "presented a certificate this device doesn't trust yet" is expected the first time.

Fix
  • Certificate Not Trusted Yet: compare the fingerprint with the one your Portainer server shows before you trust it. Certificate Changed ("different from the one you trusted") can mean the server was reinstalled, or that someone is intercepting the connection; do not trust until you know which.
  • "Portainer must use HTTPS (usually port 9443)." Use the https:// address and Portainer's HTTPS port.
  • "Portainer didn't accept this access token." Create a new one in Portainer under My account, then Access tokens, and replace it. A user with access to only the environments you want here is safest.
  • Portainer Environment Gone / no Docker environment: the environment was removed on the server, or the token cannot use any Docker environment. Add one in Portainer under Environments, Add environment, then check again. Kubernetes environments are not supported, and neither is Portainer behind a URL path.
  • Shell and Open in Terminal need a host added over SSH; a Portainer environment alone cannot open a terminal.

"Couldn't Reach the Web Page" / "The SSH server on HOST doesn't allow port forwarding (AllowTcpForwarding), so the web page can't be opened."

WhymeshTerm opens a container's web page through an SSH port forward, so the server must allow forwarding. A container that publishes its port only on the host's own address (127.0.0.1) is reached the same way: "Reach them with port forwarding."

Fix

Allow forwarding as in Port forwarding is blocked, and reload sshd for your system (the app's fix adds the right reload line):

sudo systemctl reload ssh      # Debian, Ubuntu
sudo systemctl reload sshd     # Fedora
sudo rc-service sshd reload    # Alpine (OpenRC)

9. Fresh-server notes

These come from real tests on brand-new minimal images (Debian 11 and 12, Ubuntu 22.04 and 24.04, Fedora, Alpine 3.20, and macOS 15 and 26). Cloud provider images are usually a little fuller, but a minimal image or a new VM can look like this, and it explains many of the messages above.

  • Debian and Ubuntu package lists are empty until you run apt-get update. apt-get install alone fails with "Unable to locate package". Fedora (dnf) and Alpine (apk add) do not need a refresh first.
  • Many images have no sudo: Debian, Ubuntu and Alpine minimal images have none; Fedora has it. As root, drop sudo. Otherwise use su -c '...', or set up sudo once as root (see No container engine found).
  • Common tools are missing. After openssh-server alone: Debian 12 has no curl, python3, git or sudo; Ubuntu has python3 but no curl, git or sudo; Fedora has curl and sudo but no python3 or git; Alpine has no curl, python3, bash or sudo (busybox supplies setsid and timeout). None has tmux. This is why agents, notifications and Containers sometimes ask you to install a package first.
  • Debian's PATH lacks /usr/sbin for SSH sessions (/usr/local/bin:/usr/bin:/bin:/usr/games), so tools such as dockerd from docker.io are invisible to non-root SSH commands. Ubuntu, Fedora and macOS include the sbin folders.
  • The sshd service is ssh on Debian and Ubuntu, sshd on Fedora and, on Alpine, run with OpenRC (rc-service sshd ...).
  • Alpine's adduser -D makes a locked account that sshd refuses, even with a key. Set a password once with passwd USER.
  • Debian 11 is end of life. Its security repository can return 404, so installs may fail outright. Use a supported release.
  • The locale may not be UTF-8 for non-login SSH commands (see locale).
  • Packages differ by distro. Fedora has no uidmap package: newuidmap and newgidmap come from shadow-utils, already in the base image. passt (rootless Podman networking) exists on Ubuntu 24.04 and newer and on Fedora, not on Ubuntu 22.04 or Debian 11. See rootless in Docker 101.
  • macOS: password sign-in works on a stock Mac once Remote Login is on. python3 and git are Apple stubs until the Command Line Tools are installed; Homebrew's folder is not on the SSH PATH; there is no setsid or timeout.

Still stuck?

Ask in our GitHub Discussions, or report a bug from Settings > Feedback and Feature Requests (see Feedback and feature requests). Copy Details there copies your app version, device and feature counts, never hostnames, usernames, IP addresses, keys or logs. The repo is public, so leave those out of anything you write. For anything private, email meshterm@gmail.com.