Skip to content

Automating SSH with Tasker

ZestSSH Pro includes an automation API that lets external apps trigger SSH commands on your saved connections. On Android, Tasker is the most powerful way to build automated workflows --- run deployments on a schedule, trigger backups when you leave home, or check server health every hour.

This guide walks through the setup process, then gives five real-world examples.

  • ZestSSH Pro subscription (automation is a Pro feature)
  • Tasker installed on your Android device
  • At least one saved connection in ZestSSH with a working SSH key or password identity

Open ZestSSH, go to Settings > Automation. Toggle Enable Automation on. This allows external apps to trigger commands through ZestSSH.

Still in the Automation settings, tap Manage API Keys, then Create Key.

  • Label: Give it a descriptive name like “Tasker - General” or “Tasker - Backup Tasks”
  • Expiration (optional): Set an expiry date if you want the key to auto-expire for security.

Tap Create. ZestSSH generates a 48-character cryptographically secure key. Copy it --- you will need it for Tasker. The key is stored securely on-device using the platform keychain and is never transmitted.

Security notes:

  • API keys are validated with constant-time comparison to prevent timing attacks.
  • After 5 consecutive failed validation attempts, ZestSSH locks out API key requests for 60 seconds.
  • You can create multiple keys with different labels (e.g. one per Tasker profile) and revoke them independently.

Open Tasker, go to the Tasks tab, and create a new task.

Add an action: Net > Browse URL

Set the URL to:

zestssh://execute?connection=MyServer&command=uptime&key=YOUR_API_KEY_HERE&timeout=30

Replace:

  • MyServer with your connection’s label or ID
  • uptime with the command you want to run
  • YOUR_API_KEY_HERE with your actual API key

Add an action: System > Send Intent

Configure:

  • Action: com.affluentlabs.zestssh.EXECUTE
  • Extra: connection_id:MyServer
  • Extra: command:uptime
  • Extra: key:YOUR_API_KEY_HERE
  • Extra: timeout:30
  • Target: Service

The intent method gives you access to the result via Tasker’s %stdout and %exit_code variables.

The connection parameter matches connections flexibly:

  1. Exact connection ID (UUID) --- highest priority
  2. Exact label match (case-insensitive)
  3. Partial label match (first hit)

So connection=prod will match a connection labeled “Production Server” if no exact match is found.

When using the Intent method, ZestSSH returns the result to Tasker with:

  • stdout --- the command’s standard output
  • exit_code --- 0 for success, non-zero for failure

You can use these in subsequent Tasker actions:

If %exit_code = 0
Notify: Server check passed
Else
Notify: Server check FAILED
End If

Both URL and Intent methods support output filters:

ParameterEffect
grep=patternKeep only lines matching this regex pattern
head=NTake only the first N lines
tail=NTake only the last N lines

Filters apply in order: grep, then head, then tail.

Example --- get just the load average from uptime:

zestssh://execute?connection=MyServer&command=uptime&grep=load&key=KEY

For fire-and-forget tasks where you want the result posted to an external service:

zestssh://execute?connection=MyServer&command=uptime&key=KEY&callback=https://hooks.example.com/results

ZestSSH sends a POST request (HTTPS only) with a JSON body containing connection, command, stdout, stderr, exit_code, elapsed_ms, and timestamp.

Profile trigger: Time > Every day at 2:00 AM

Task:

zestssh://execute?connection=NAS&command=sudo /opt/backup/nightly.sh&key=KEY&timeout=300

Set the timeout to 300 seconds (5 minutes) for long-running backups. Add a Tasker notification action after the Browse URL to alert you of the result.

Profile trigger: Notification from your Git hosting provider’s app (GitHub, GitLab)

Task:

zestssh://execute?connection=ProdServer&command=cd /var/www/app && git pull origin main && docker compose up -d --build&key=KEY&timeout=120

Chain commands with && so the deploy stops if git pull fails.

Profile trigger: Time > Every 1 Hour

Task:

zestssh://execute?connection=WebServer&command=echo "cpu:$(top -bn1 | grep Cpu | awk '{print $2}')% mem:$(free -m | awk '/Mem/{printf "%.0f", $3/$2*100}')% disk:$(df -h / | awk 'NR==2{print $5}')"&key=KEY&timeout=15

Follow with a Tasker IF action to send a notification only if CPU or disk exceeds thresholds.

If you have saved snippets in ZestSSH, you can trigger them by name:

zestssh://snippet?connection=ProdServer&name=restart-nginx&key=KEY

Snippets support variable substitution. Pass variables with the var_ prefix:

zestssh://snippet?connection=ProdServer&name=deploy-branch&var_branch=develop&key=KEY

If the snippet contains {{branch}}, ZestSSH replaces it with develop before execution.

Example 5: Batch Execution Across Multiple Servers

Section titled “Example 5: Batch Execution Across Multiple Servers”

Run the same command on several servers at once:

zestssh://batch?connections=Web1,Web2,Web3&command=sudo apt update -qq&key=KEY&parallel=true&timeout=60

The connections parameter is a comma-separated list of connection labels or IDs. Set parallel=true (default) to run all connections concurrently, or parallel=false for sequential execution.

The combined output includes a header for each connection:

=== Web1 (exit=0) ===
5 packages can be upgraded.
=== Web2 (exit=0) ===
All packages are up to date.
=== Web3 (exit=1) ===
STDERR: E: Could not get lock /var/lib/dpkg/lock

Workflows are multi-step sequences defined in ZestSSH’s Workflow Editor. Trigger them from Tasker:

zestssh://workflow?name=nightly-maintenance&key=KEY

Or by workflow ID:

zestssh://workflow?id=550e8400-e29b-41d4-a716-446655440000&key=KEY

Workflows execute their steps in order, with configurable failure handling (abort, continue, or jump to a specific step).

  • Create dedicated API keys for each Tasker profile. If you change a profile, revoke its specific key without breaking others.
  • Set reasonable timeouts. The default is 30 seconds. Long-running commands need longer timeouts. Set the maximum to what makes sense for the task --- not an arbitrarily large number.
  • Use snippets for complex commands. Instead of cramming a long command into a URL, save it as a snippet in ZestSSH and reference it by name.
  • Test interactively first. Before automating a command, run it manually in a ZestSSH terminal session to make sure it works as expected.
  • Secure your API keys. Do not share Tasker profiles that contain raw API keys. If you export a Tasker backup, the keys are embedded in plaintext.
  • Check the automation log. ZestSSH keeps a history of all automation runs (up to 500 entries) in Settings > Automation > Log. Use it to debug failed tasks.