Skip to content
  • MangoFly

    A self-hosted WireGuard mesh. Devices connect straight to each other; the coordination server is one binary and a SQLite file, and never sees their traffic.

    encrypted WireGuard · peer to peerLaptopbehind home NATServerin a datacentrePhoneon mobile datacoordination serverone binary · one SQLite filecontrol plane only (TLS)keys · tunnel addresses · peer lists · sealed ICE candidatesholds no private keys · carries no traffic · cannot decryptdatacontrol
  • MangoDock

    Docker management with nothing on the hosts. Reaches each daemon over an ordinary SSH session — no agent to install, no port to open.

    The MangoDock dashboard showing three host cards with container state counts, CPU and memory gauges, a usage history and recent events
  • MangoWiFi

    A Wi-Fi 6/7/8 test bench. One binary runs as Console or Agent either side of the access point under test, measuring latency under real load.

    AP under testWi-Fi 6 / 6E / 7Agentstation side · real radioLAN receiveriperf3 -sConsoleUI · orchestrates · probes
  • Blog
  • Nothing phones home

    No telemetry, no analytics, no crash reporter, no account login. Check it with a packet capture on your own network.

    Download MangoSSH
  • Project
  • Download
  • Guides · Automation

    Scripts

    Save a command or a whole shell script once, then run it on one SSH host or fifty at the same time. Each host reports its own output and exit code, so you can see at a glance which ones failed.

    • SSH hosts
    • Runs in parallel, one connection per host
    • About 10 minutes

    How a script runs

    When you click Run Now, MangoSSH opens one SSH connection per selected host, all at once, and runs the script body in a separate command channel. Nothing is typed into your terminal tabs. Output streams back live, and each host's run ends as success (exit code 0) or failed (any other code, a timeout, or a connection error).

    Connections are reused. If you already have a terminal open to a host, the script runs over that connection. Otherwise MangoSSH signs in on its own and keeps the connection for 15 minutes, so a second run straight after the first skips the handshake.

    Scripts or runbooks?

    A script is one body of commands run on N hosts, right now. If MangoSSH closes mid-run, that run is lost. When you need several steps in order, retries, an approval gate, or a run that survives the app closing, use a runbook.

    Create a script

    1. Open Scripts from the Workspace sidebar. The page has its own rail on the left: Overview, Scripts, Monitor Script Runs, Schedules, Runbooks and Activity.

    2. Click + New. Enter a Script name (names must be unique, ignoring case) and an optional Description.

    3. Type or paste the Command body. This is what runs on each host. To pull in a file you already have, use the Run Single Script button beside the label: despite its name, it only reads a local .sh, .ps1, .py or similar file into the body. It does not run anything.

    4. Pick a Shell (see the next section), and set the timeouts if the defaults do not suit.

    5. Click Save. The script now appears under Scripts in the rail and in the — Select a saved script — dropdown.

    You can also build a script from commands you already ran: open a host's History tab, select the commands, and click Save as Script. Import accepts a raw script file (it becomes one script named after the file) or a JSON bundle made by Export.

    FieldWhat it does
    Wall timeout (seconds)Hard deadline for the whole run. Default 300. The run fails with “Command timed out after 300s”.
    Idle timeout (seconds)Kills the run if it prints nothing for this long. Blank means off. Useful for long jobs that print progress: a hang shows up early instead of at the wall deadline.
    TagsComma-separated labels for your own filing. The rail search matches them.
    ParametersValues you are asked for before each run. See below.
    ShellWhich interpreter runs the body.
    HotkeyA key combination that runs the script on the host you are looking at.

    Choose a shell

    ShellBehaviour
    Auto (remote default)The body goes to the account's own shell as-is. If the script has attachments, MangoSSH first checks whether the host is Unix-like or Windows and wraps the body to match (PowerShell on Windows).
    sh / bashThe body is fed to that interpreter unchanged, so multi-line scripts, quotes and $variables behave exactly as they would in a file. Pick bash when you use bash syntax such as arrays or [[ ]].
    PowerShellAlways wraps the body for powershell -NoProfile -NonInteractive. Use it for Windows hosts running OpenSSH.
    There is no terminal on the far side

    Scripts run without a TTY, so nothing can answer a prompt. A plain sudo that asks for a password fails. Use sudo -n with a NOPASSWD rule for the specific commands, and pass -y (or the equivalent) to anything that asks for confirmation.

    Parameters

    Parameters let one script serve many cases: which service to restart, which branch to deploy. Declare them in Parameters, one per line:

    name = default | prompt

    Only the name is required. env, env = prod and env = prod | Which environment? are all valid. Lines starting with # are ignored. Then write {{name}} in the body wherever the value belongs (spaces inside the braces are fine).

    When you click Run Now, a dialog titled with the script's name asks for each value, labelled with its prompt and prefilled with the default. Enter runs, Esc or Cancel aborts the run. Every host gets the same values. Scheduled runs have nobody to ask, so they use the defaults.

    Only declared names are replaced. A body that contains other {{ … }} text, such as a Helm, Jinja or Go template, is sent untouched.

    Quote parameters in the body

    Values are pasted into the command as plain text, with no escaping. Write "{{service}}" rather than {{service}} so a value with spaces stays one argument, and remember that whoever runs the script can put any shell text in that box.

    Attach files

    Attachments are files copied to each host next to the command body: a config file, a helper script, a small binary. Use Attach Multiple Files to pick files from your computer, or Empty Attachment Placeholder to add a named entry and type its content with its Edit button.

    • They do not run on their own. Call them from the body, by bare name: ./helper.sh, python3 ./check.py, cat app.conf.
    • On each run, MangoSSH creates a temporary folder on the host, writes the files there, runs the body inside it, and deletes the folder afterwards, even if the body fails.
    • Shell and Python files default to mode 0755, everything else to 0644. The chmod button flips between the two. Windows hosts ignore the mode.
    • Names must be plain file names: no /, no \, and no leading dot.
    • Files travel inside every command, once per host. Keep them to configs and helpers, not large archives.

    Pick the hosts

    Open the 🎯 Run on hosts dropdown. It lists your saved SSH hosts grouped by host group, with All and None at the top.

    • A whole group: tick the checkbox on the group's header. It selects every runnable host in that group and shows a count such as 3/5. A partly selected group shows a dash.
    • By tag: the Tags row shows one chip per host tag, for example #prod. Click a chip to tick every runnable host with that tag, and click again to clear them.
    • One by one: tick individual rows.

    Two markers warn you before you run:

    MarkerMeaning
    ⛔ BlockedThe host signs in with keyboard-interactive (MFA) authentication and has no open session. There is nobody to answer the prompt, so All, group and tag selection skip it, and Run Now refuses to run if you tick it by hand.
    ⚠ Might failPassword authentication with no saved password, or key authentication with no key file set. MangoSSH asks you to confirm before running.

    Hover a marker to see the exact reason. Both disappear while you have a live terminal open to that host, because the script then runs over that session.

    Which sign-in methods can run unattended

    A script signs in without you, so the host needs a credential MangoSSH can use by itself:

    Auth methodWorks in a script?
    PasswordYes, if you ticked Save password to OS keychain on the host.
    Key, Key + passwordYes. Save the key's passphrase too, if it has one.
    AgentYes, while your SSH agent is running. A FIDO2 key asks for a touch once, when the connection opens.
    pass, 1Password, AWS SSM, DopplerYes. MangoSSH fetches the secret through that tool's command-line client, which must already be signed in.
    BitwardenOnly if the Bitwarden vault is already unlocked in the environment MangoSSH runs in. A script cannot ask for the master password.
    Interactive (MFA), Key + interactiveNo, unless a terminal to that host is open at the time.

    Hosts reached through a ProxyCommand or an HTTP/SOCKS proxy work. Hosts reached only through a Proxy Jump (bastion) do not: the unattended path connects directly and usually times out. Open a terminal to such a host first, and the script runs over that session.

    Run and read the results

    Click Run Now. MangoSSH saves the script first, asks for parameters if there are any, starts one run per host, and switches to Monitor Script Runs.

    • Runs are grouped by script, newest first, with a summary such as 4 runs · 3 ok · 1 failed. A group with runs still going opens by itself.
    • Each card shows the status (pending, running, success, failed, cancelled), the host as user@host:port, start time, duration and the exit code.
    • Click a card to see stdout and stderr, which update live while it runs. A connection or timeout problem appears as Error above them.
    • Cancel on a running card stops that host's run only.
    • The pop-out icon on a group opens every run of that script at full size, with buttons to expand, collapse and copy them all as text.

    Exit code 0 is success. Anything else is a failure, and so is a host that closes the connection without reporting a code. In a multi-line body, the last command's code is the one reported, so end with the check that matters, or use set -e to stop at the first error.

    The last 500 runs are kept across restarts. Clear History removes them; runs still in progress carry on. Every run is also written to the audit log as a script_run event with the host, exit code and duration.

    Worked example: restart a service everywhere

    This script restarts a service you name, checks it came back, and shows its latest log lines.

    1. Click + New and name it restart-service. Set Shell to bash.

    2. In Parameters, enter:

      service = nginx | Service to restart
      lines = 20 | Log lines to show afterwards
    3. In Command body, enter:

      sudo -n systemctl restart "{{service}}"
      if ! systemctl is-active --quiet "{{service}}"; then
        echo "{{service}} did not come back" >&2
        exit 2
      fi
      journalctl -u "{{service}}" -n {{lines}} --no-pager
    4. In 🎯 Run on hosts, tick the header of your web group (or click the #web tag chip).

    5. Click Run Now. In the dialog, change Service to restart to php8.2-fpm, leave the lines at 20, and press Enter.

    6. Watch Monitor Script Runs. Hosts where the service came back show success · exit 0 with the journal output. A host where it did not shows failed · exit 2 and the message under stderr. A host where sudo wanted a password fails with exit 1 and sudo's own message.

    Run in a terminal instead

    Run in Terminal types the body into a connected terminal tab, line by line, exactly as if you had pasted it. You watch it run in the console, which suits interactive checks. The trade-offs: it runs on one host only, records no exit code, does not appear in the Monitor, does not stage attachments, and does not fill in {{parameters}}.

    Schedule a script

    1. Tick the hosts in 🎯 Run on hosts. The hosts ticked when you save are the ones the schedule runs on.

    2. Under 🕘 Schedule (optional), pick a Mode: Every N minutes, Once at a specific time (switches itself off after it fires), or On a cron schedule. A cron expression uses the usual five fields, for example 0 3 * * * for 03:00 every day, and the form shows the next run time as you type.

    3. Click Save. A mistyped cron expression is rejected here, with the reason.

    Schedules in the rail lists every scheduled script and runbook with its next run and an Enable / Disable switch. Scheduled scripts show ⏰ in the rail.

    Schedules need MangoSSH running

    The scheduler lives inside the app and checks every 30 seconds, so a run can start up to half a minute late. While the app is closed nothing fires. A run missed that way fires once on the next launch; it does not replay every window it missed. Scheduled runs use parameter defaults, and need hosts that can sign in unattended (see above).

    • Bind a hotkey: click Click to bind… under Hotkey and press a combination with at least one modifier, such as Ctrl+Alt+R. Save the script.
    • Use it: press the combination while MangoSSH is focused. The script runs on the host whose session you are looking at, after asking for parameters if it has any. It skips the ⚠ confirmation, since a hotkey is deliberate. It does nothing while your cursor is in a text field.
    • Script and macro hotkeys share one list, so a combination can belong to only one of them. Binding a combination another script holds moves it to this one.
    • Search: the Search scripts… box in the rail filters by name, description and tags.

    Share and move scripts

    • Export saves every script as one JSON file; Import brings a bundle in as new scripts, without overwriting any you have.
    • Export as File saves just the open script's body as a standalone .sh, .ps1, .py or similar file, with the extension guessed from the body's shebang line.
    • If your team uses a shared vault with team scripts, Share to Team publishes a saved script to it. Team scripts appear in the dropdown; members without edit rights can run them or use Copy to Local.

    Troubleshooting

    SymptomLikely cause
    “No saved password for this host, and no live SSH session to piggyback on”Edit the host, enter the password, tick Save password to OS keychain and save. Or switch the host to key or agent authentication.
    “Can't run against N host(s) using interactive auth”Those hosts are marked ⛔. Untick them, change their authentication, or open a terminal to them first.
    “Command timed out after 300s”The job needs longer. Raise Wall timeout (seconds).
    “Command produced no output for Ns (idle timeout)”The job went quiet for longer than Idle timeout (seconds). Raise it, or make the job print progress.
    sudo: a password is requiredScripts cannot answer prompts. Use sudo -n with a NOPASSWD rule.
    Connection times out on one host onlyThat host is behind a Proxy Jump bastion. Open a terminal to it, then run again.
    {{name}} appears literally in the outputThe name is not declared under Parameters, or you used Run in Terminal, which does not fill parameters in.
    A schedule did not fireMangoSSH was closed, the schedule is disabled under Schedules, or no hosts were ticked when it was saved.