Product Decisions This Supports
- Build vs. buy for remote server operations. This package is the "buy" option for SSH/SFTP as a commodity capability. It prices at $0 (MIT) and buys roughly 2–5 engineer-days of work you'd otherwise spend wrapping
phpseclib or shelling out to ssh/scp via Symfony Process. Frame it as buying ergonomics, not capability — the underlying protocol work is phpseclib's, and that library is the durable dependency; this is a thin Laravel-flavoured facade over it.
- Roadmap slot for internal ops tooling. Concretely unlocks: an admin-panel-driven deployment trigger, scheduled off-site backups (dump → SFTP → remote host), pulling application logs or
artisan output from staging/production into a dashboard, pushing generated reports/exports to a partner's SFTP drop, and "run this command on server X" runbooks that today live in a wiki and a senior engineer's memory.
- Feature scoping — what you're actually shipping. Because the API is
run(), put(), get(), list(), the scope conversation becomes "which remote actions do we expose, to whom, with what audit trail" rather than "can we do SSH." That's a much better roadmap conversation, and it's the main reason to prefer this over a bespoke wrapper.
- Multi-environment, multi-tenant reach as a config problem. Named remotes mean one code path serves staging, prod, and customer-dedicated servers — turning "support N deployment targets" from an engineering epic into a config file plus a permission model.
- A forcing function on the maintenance-risk decision. The package's last release is September 2020 (a Laravel 8 compatibility bump). Adopting it is a deliberate choice to take on an unmaintained-but-stable dependency. That decision belongs on the roadmap explicitly, with an owner and a review date — not buried in a
composer.json diff.
- Deployment-strategy evaluation. It sits in a crowded field (Laravel Envoy, Deployer, GitHub Actions, Forge/Ploi, cloud-native tooling). Its differentiated niche is in-application, runtime-triggered remote actions — not CI-driven deploys. Use that distinction to decide whether you're buying a deploy tool or an ops-primitive, because they answer different roadmap questions.
When to Consider This Package
Adopt when most of these are true:
- You're on Laravel 6, 7, or 8 and have no near-term plan to move past 8. This is the hard gate — the compatibility release targets Laravel 8 and there is no evidence of support for later majors.
- The work is internal, low-blast-radius tooling: admin panels, back-office automation, ops dashboards. Failure means a retried job, not a customer-facing incident.
- You have a small, stable fleet (a handful of servers you control, or a partner SFTP endpoint) with credentials you already manage.
- Your team is Laravel-fluent but not ops-specialised — the fluent API plus facade is a genuine onboarding win over raw
phpseclib.
- You need synchronous, request- or job-scoped command execution and file transfer, not interactive shells or streaming sessions.
- You're willing to wrap it behind your own narrow interface (e.g.
RemoteGateway) and pin ^6.2 so a future major can't drag you across.
Look elsewhere when any of these are true:
- Laravel 9+ or an upgrade on the roadmap. Treat the package as a dead end for framework currency. Plan the exit before you plan the migration.
- Security or compliance sensitivity. Credentials in config/env, no built-in audit log, no host-key-verification story in the marketing copy, and an unmaintained dependency are a bad combination for SOC 2 / PCI scope. Build on
phpseclib directly so you own the security posture.
- Deployment is the use case. Laravel Envoy, Deployer, or CI-native pipelines give you atomic releases, rollback, and zero-downtime — this package gives you
run(). Don't confuse the two.
- You need scale or concurrency. Sequential SSH calls in a web request will not survive contact with ten servers. You'd be building a queue + parallelism layer on top, at which point evaluate the ecosystem properly.
- Long-running or interactive sessions (tail -f, REPLs, streaming output) — outside the design envelope.
- You want a supported vendor relationship. 275 stars and a 2020 last release is a hobby-scale maintenance signal; there is no one to escalate to.
- A managed platform already solves it. If you're on Forge/Ploi/Vapor or a cloud with SSM/Systems Manager, you're paying for this capability already.
Adoption gate to insist on: a spike that proves the package installs and runs one real command against a staging host on your framework and PHP version, plus a written exit plan (how you'd swap to raw phpseclib behind the interface). If the spike is red or the exit plan is hand-wavy, don't adopt.
How to Pitch It (Stakeholders)
To executives (one paragraph): We can add remote-server automation — deployment triggers, off-site backups, pulling logs into our admin panel, pushing files to partners — in days rather than weeks, using a free, MIT-licensed Laravel package that wraps a well-established SSH library. The trade-off is that the package itself hasn't been updated since 2020, so it's a fit for internal tooling on our current framework version and not a long-term platform bet. I'd like to approve a short, time-boxed spike with an explicit exit plan, and cap the commitment at internal, non-customer-facing workflows. Estimated cost: a few engineer-days; risk: low and contained, provided we keep it behind our own interface.
To engineering (the honest version):
- What it is: a fluent, facade-backed wrapper over
phpseclib — run(), put(), get(), list(), named connections, password or key auth. You are not adopting an SSH implementation; you're adopting an API shape.
- What we're committing to: pin
^6.2, resolve through the container rather than calling the facade in controllers, hide it behind one small interface bound in AppServiceProvider, keep credentials in .env and structural config in config/, and never return its types or exceptions across a controller or job boundary. Translate at the edge.
- What we accept: unmaintained since Sept 2020, effectively no path past Laravel 8, no vendor support, and a security surface we own. Queue anything that touches it — don't hold an SSH socket inside a request, and don't try to serialise client objects into jobs; pass identifiers and re-resolve in
handle().
- What "done" looks like: one integration test against a throwaway host, tagged so it doesn't run on every commit; a fake bound in the container for everything else; and a one-page exit plan to raw
phpseclib — because that swap is cheap now and expensive later.
- What we're explicitly not doing: using this for production deployments, customer-facing transfers, or anything inside a compliance boundary. If a stakeholder asks for one of those, we re-open the build-vs-buy decision rather than stretching this package.