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.
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
Open Scripts from the Workspace sidebar. The page has its own rail on the left: Overview, Scripts, Monitor Script Runs, Schedules, Runbooks and Activity.
Click + New. Enter a Script name (names must be unique, ignoring case) and an optional Description.
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,.pyor similar file into the body. It does not run anything.Pick a Shell (see the next section), and set the timeouts if the defaults do not suit.
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.
| Field | What 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. |
| Tags | Comma-separated labels for your own filing. The rail search matches them. |
| Parameters | Values you are asked for before each run. See below. |
| Shell | Which interpreter runs the body. |
| Hotkey | A key combination that runs the script on the host you are looking at. |
Choose a shell
| Shell | Behaviour |
|---|---|
| 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 / bash | The 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 [[ ]]. |
| PowerShell | Always wraps the body for powershell -NoProfile -NonInteractive. Use it for Windows hosts running OpenSSH. |
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.
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 to0644. 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:
| Marker | Meaning |
|---|---|
| ⛔ Blocked | The 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 fail | Password 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 method | Works in a script? |
|---|---|
| Password | Yes, if you ticked Save password to OS keychain on the host. |
| Key, Key + password | Yes. Save the key's passphrase too, if it has one. |
| Agent | Yes, while your SSH agent is running. A FIDO2 key asks for a touch once, when the connection opens. |
| pass, 1Password, AWS SSM, Doppler | Yes. MangoSSH fetches the secret through that tool's command-line client, which must already be signed in. |
| Bitwarden | Only if the Bitwarden vault is already unlocked in the environment MangoSSH runs in. A script cannot ask for the master password. |
| Interactive (MFA), Key + interactive | No, 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.
Click + New and name it
restart-service. Set Shell to bash.In Parameters, enter:
service = nginx | Service to restart lines = 20 | Log lines to show afterwardsIn 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-pagerIn 🎯 Run on hosts, tick the header of your
webgroup (or click the#webtag chip).Click Run Now. In the dialog, change Service to restart to
php8.2-fpm, leave the lines at 20, and press Enter.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
sudowanted 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
Tick the hosts in 🎯 Run on hosts. The hosts ticked when you save are the ones the schedule runs on.
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.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.
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).
Hotkeys and search
- 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,.pyor 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
| Symptom | Likely 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 required | Scripts cannot answer prompts. Use sudo -n with a NOPASSWD rule. |
| Connection times out on one host only | That host is behind a Proxy Jump bastion. Open a terminal to it, then run again. |
{{name}} appears literally in the output | The name is not declared under Parameters, or you used Run in Terminal, which does not fill parameters in. |
| A schedule did not fire | MangoSSH was closed, the schedule is disabled under Schedules, or no hosts were ticked when it was saved. |