serversinc / ssh-runner
Actions-based SSH Runner
Requires
- php: ^8.4
- illuminate/support: ^8.0
- spatie/ssh: ^1.13
Requires (Dev)
- laravel/pint: ^1.29
- orchestra/testbench: ^6.0
- phpunit/phpunit: ^9.0
- rector/rector: ^2.4
This package is auto-updated.
Last update: 2026-05-07 19:29:00 UTC
README
A pipeline-based SSH runner for Laravel that executes commands on remote servers with support for action composition, failure strategies, automatic rollback, and execution logging.
This package provides a fluent API for building SSH command pipelines using the Spatie SSH library under the hood.
Installation
You can install the package via Composer:
composer require serversinc/ssh-runner
Configuration
Publish the configuration file:
php artisan vendor:publish --provider="Serversinc\SshRunner\SshRunnerServiceProvider" --tag="ssh-runner-config"
Publish the migrations:
php artisan vendor:publish --provider="Serversinc\SshRunner\SshRunnerServiceProvider" --tag="ssh-runner-migrations"
Run the migrations to create the logging tables:
php artisan migrate
Basic Usage
1. Implement the SshServer Interface
Your server model must implement the SshServer contract:
use Serversinc\SshRunner\Contracts\SshServer; class Server extends Model implements SshServer { public function getSshHost(): string { return $this->ip_address; } public function getSshPort(): int { return $this->ssh_port ?? 22; } public function getSshUser(): string { return $this->ssh_user; } public function getSshKeyPath(): ?string { return $this->ssh_key_path; } public function getSshKeyContents(): ?string { return $this->ssh_key_contents; } }
2. Create an Action
Actions are reusable, testable units of work:
use Serversinc\SshRunner\Actions\BaseSshAction; use Serversinc\SshRunner\Contracts\SshServer; use Serversinc\SshRunner\Results\ActionResult; use Spatie\Ssh\Ssh; class InstallPackage extends BaseSshAction { public function __construct(private string $packageName) { } public function handle(SshServer $server, Ssh $ssh): ActionResult { return $this->run($ssh, ["apt-get install -y {$this->packageName}"]); } public function undo(SshServer $server, Ssh $ssh): void { // Called automatically on rollback $ssh->execute(["apt-get remove -y {$this->packageName}"]); } }
3. Execute a Pipeline
There are several ways to execute pipelines:
Using the Facade (Recommended)
use SshRunner; use Serversinc\SshRunner\Enums\FailureStrategy; $result = SshRunner::pipeline($server) ->run(new UpdatePackageList) ->run(new InstallPackage('nginx')) ->run(new InstallPackage('nginx')) ->run(new RestartService('nginx')) ->execute(); if ($result->success) { echo "Pipeline completed in {$result->duration()} seconds"; } else { foreach ($result->failedActions() as $action) { echo "Failed: {$action->action}\n"; echo "Error: {$action->errorOutput}\n"; } }
Using SshConnection
use Serversinc\SshRunner\SshConnection; $connection = SshConnection::for($server); $result = $connection->pipeline() ->run(new UpdatePackageList) ->run(new InstallPackage('nginx')) ->execute();
Using the Factory Class
use Serversinc\SshRunner\SshRunner; $result = SshRunner::pipeline($server) ->run(new UpdatePackageList) ->run(new InstallPackage('nginx')) ->execute();
Failure Strategies
Control what happens when an action fails:
use Serversinc\SshRunner\Enums\FailureStrategy; // STOP (default) - Stop execution on first failure $pipeline->onFailure(FailureStrategy::STOP); // CONTINUE - Keep executing remaining actions $pipeline->onFailure(FailureStrategy::CONTINUE); // ROLLBACK - Undo completed actions in reverse order $pipeline->onFailure(FailureStrategy::ROLLBACK) ->run(new CreateDatabase) ->run(new CreateUser) // If this fails, CreateDatabase->undo() is called ->execute();
Execution Logging
All pipeline runs are automatically logged to the database:
use Serversinc\SshRunner\Models\SshPipelineLog; // Get all runs for a server $runs = SshPipelineLog::where('server_id', $server->id)->get(); // Check if a specific run failed $run = SshPipelineLog::find(1); if ($run->failed()) { foreach ($run->actionLogs as $log) { echo "{$log->action}: {$log->exit_code}\n"; } }
Single Action Execution
Execute a single action without the pipeline:
// Using the Facade $result = SshRunner::run($server, new UpdatePackageList); // Or using SshConnection $connection = SshConnection::for($server); $result = $connection->execute(new UpdatePackageList); if ($result->success) { echo $result->output; } else { echo $result->errorOutput; }
Advanced Usage
Creating a Connection for Reuse
use Serversinc\SshRunner\SshConnection; use Serversinc\SshRunner\SshPipeline; $connection = SshConnection::for($server); // Execute multiple pipelines on the same connection $result1 = $connection->pipeline() ->run(new Action1()) ->execute(); $result2 = $connection->pipeline() ->run(new Action2()) ->execute();
Using SshRunner Factory Methods
use Serversinc\SshRunner\SshRunner; // Create a connection $connection = SshRunner::connect($server); // Create a pipeline directly $pipeline = SshRunner::pipeline($server); // Execute a single action $result = SshRunner::run($server, new SomeAction());
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security-related issues, please use the issue tracker and mark it as a security concern.
Credits
License
The MIT License (MIT). Please see License File for more information.