Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

brunofernandes's avatar

Laravel SSH

Does anyone know what happened to Laravel SSH? It used to be available in Laravel 4.2: https://laravel.com/docs/4.2/ssh#sftp-uploads

I have been using LaravelCollective for a while but it is no longer maintained and not compatible with Laravel 9. https://github.com/LaravelCollective/remote Are there any alternative to LaravelCollective/remote that are compatible with Laravel 9 & 10.

0 likes
4 replies
LaryAI's avatar
Level 58

In Laravel 4.2, the SSH component was available as part of the framework. However, it was removed in later versions of Laravel.

To achieve SSH functionality in Laravel 9, you can use the phpseclib/phpseclib package. This package provides an easy-to-use interface for SSH, SFTP, and other secure protocols.

To get started, you'll need to install the package via Composer. Open your terminal and run the following command:

composer require phpseclib/phpseclib

Once the package is installed, you can use it in your Laravel application. Here's an example of how you can use the phpseclib/phpseclib package to execute an SSH command:

use phpseclib\Net\SSH2;

$ssh = new SSH2('example.com');
if ($ssh->login('username', 'password')) {
    $output = $ssh->exec('ls -la');
    echo $output;
} else {
    echo 'SSH login failed.';
}

In this example, we create a new SSH2 instance and pass the hostname as the constructor argument. We then use the login method to authenticate with the SSH server using a username and password. If the login is successful, we can execute commands using the exec method.

Remember to replace 'example.com', 'username', and 'password' with the actual SSH server details.

You can find more information and examples in the phpseclib/phpseclib documentation: https://phpseclib.com/

Note: Make sure to handle sensitive information like passwords securely, such as using environment variables or configuration files.

simonecosci's avatar

I did this small replacement using a Service ... if you need the basic features using the same interfaces

composer remove laravelcollective/remote
composer require phpseclib/phpseclib

You can use this

<?php

namespace App\Services;

use Closure;
use Exception;
use phpseclib3\Net\SSH2;
use phpseclib3\Net\SFTP;
use phpseclib3\Crypt\PublicKeyLoader;

class SshService {

    /**
     * @var array $config
     */
    private array $config;

    /**
     * @var SSH2|null $ssh2
     */
    private null|SSH2 $ssh2;

    /**
     * @var SFTP|null $sftp
     */
    private null|SFTP $sftp;

    /**
     * @var SSH2|SFTP|null $connection
     */
    private null|SSH2|SFTP $connection;

    /**
     * @param array $config
     * @return void
     * @throws Exception
     */
    public function __construct(array $config) {
        $this->ssh2 = null;
        $this->sftp = null;
        $this->connection = null;
        $host = explode(':', $config['host'])[0];
        $port = explode(':', $config['host'])[1] ?? 22;
        $this->config = $config;
        $this->config['host'] = $host;
        $this->config['port'] = $port;
    }

    /**
     * @param string $id
     * @throws Exception
     */
    public static function into(string $id): SshService {
        $config = config('remote.connections.' . $id);
        if (empty($config)) {
            throw new Exception('Host not found');
        }
        return new self($config);
    }

    /**
     * @param string $file
     * @param string $content
     * @return SshService
     * @throws Exception
     */
    public function putString(string $file, string $content): SshService {
        $this->connection('sftp')
            ->put($file, $content);
        return $this;
    }


    /**
     * @param string $file
     * @return SshService
     * @throws Exception
     */
    public function putFile(string $file): SshService {
        $fp = fopen($file, 'r');
        $this->connection('sftp')
            ->put($file, $fp, SFTP::SOURCE_LOCAL_FILE);
        fclose($fp);
        return $this;
    }

    /**
     * @param array|string $commands
     * @param Closure|null $callback
     * @return array
     * @throws Exception
     */
    public function run(array|string $commands, Closure $callback = null): array {
        if (!is_array($commands)) {
            $commands = [$commands];
        }
        $ssh = $this->connection();
        $output = [];
        foreach ($commands as $command) {
            if (is_null($callback)) {
                $output[] = $ssh->exec($command);
            } else {
                $ssh->exec($command, function ($line) use ($callback, &$output) {
                    $output[] = $callback($line);
                });
            }
        }
        return $output;
    }

    /**
     * @param string $type
     * @return SSH2|SFTP
     * @throws Exception
     */
    public function connection(string $type = 'ssh'): SSH2|SFTP {
        if ($type === 'ssh') {
            if (!empty($this->ssh2)) {
                return $this->ssh2;
            }
            $this->ssh2 = $this->sshConnection();
            $conn = $this->ssh2;
        } elseif ($type === 'sftp') {
            if (!empty($this->sftp)) {
                return $this->sftp;
            }
            $this->sftp = $this->sftpConnection();
            $conn = $this->sftp;
        } else {
            throw new Exception('Invalid connection type');
        }
        if (!empty($this->config['keytext'])) {
            if (!empty($this->config['keyphrase'])) {
                $key = PublicKeyLoader::load($this->config['keytext'], $this->config['keyphrase']);
            } else {
                $key = PublicKeyLoader::load($this->config['keytext']);
            }
            if (!$conn->login($this->config['username'], $key)) {
                throw new Exception($type . ' Login failed');
            }
        } else {
            if (!$conn->login($this->config['username'], $this->config['password'])) {
                throw new Exception($type . ' Login failed');
            }
        }
        $conn->setTimeout($this->config['timeout']);
        return $this->connection = $conn;
    }

    /**
     * @return SSH2
     */
    private function sshConnection(): SSH2 {
        return new SSH2($this->config['host'], $this->config['port']);
    }

    /**
     * @return SFTP
     */
    private function sftpConnection(): SFTP {
        return new SFTP($this->config['host'], $this->config['port']);
    }

    /**
     * @return false|int
     * @throws Exception
     */
    public function getExitCode(): false|int {
        return $this->connection->getExitStatus();
    }

    /**
     * @return void
     */
    public function __destruct() {
        if (!empty($this->ssh2)) {
            $this->ssh2->disconnect();
        }
        if (!empty($this->sftp)) {
            $this->sftp->disconnect();
        }
    }
}

Usage

use App\Services\SshService as SSH;

$username = 'root';
$password = 'password';
$id = 'my-host';
config(['remote.connections.' . $id => [
    'host' => '127.0.0.1:22',
    'username' => $username,
    'password' => $password,
    'key' => '',
    'keytext' => '',
    'keyphrase' => '',
    'agent' => '',
    'timeout' => 0,
]]);

$connection = SSH::into($id);

// run a command
$output = $connection->run('ls -la');

// run multiple commands
$output = $connection->run(['ls -la', 'pwd']);

// upload a file
$connection->putFile('test.txt');

// create a file remotely
$connection->putString('test.txt', 'content of the file');

Please or to participate in this conversation.