pstoute / laravel-hosting-management
A unified hosting provider abstraction layer for Laravel, providing a single API to manage servers, sites, databases, SSL certificates, and deployments across multiple hosting platforms.
Package info
github.com/pstoute/laravel-hosting-management
pkg:composer/pstoute/laravel-hosting-management
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.0
- illuminate/contracts: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
README
A unified hosting provider abstraction layer for Laravel. Manage servers, sites, databases, SSL certificates, and deployments across multiple hosting platforms with a single, consistent API.
Supported Providers
| Provider | Server Management | Site Management | SSL | Deployments | Backups |
|---|---|---|---|---|---|
| Laravel Forge | Yes | Yes | Yes | Yes | Yes |
| GridPane | Yes | Yes | Yes | Yes | Yes |
| Cloudways | Yes | Yes | Yes | Yes | Yes |
| Kinsta | Yes | Yes | Yes | Yes | Yes |
| WP Engine | Limited | Yes | Yes | Yes | Yes |
| Ploi | Yes | Yes | Yes | Yes | Yes |
| RunCloud | Yes | Yes | Yes | Yes | Yes |
| SpinupWP | Yes | Yes | Yes | Yes | Yes |
| cPanel/WHM | Limited | Yes | Yes | No | Yes |
Requirements
- PHP 8.2 or higher
- Laravel 10.x, 11.x, or 12.x
- Guzzle HTTP 7.x
Installation
Install via Composer:
composer require pstoute/laravel-hosting-management
The service provider will be automatically registered via Laravel's package discovery.
Publish Configuration
php artisan vendor:publish --provider="Pstoute\LaravelHosting\HostingServiceProvider"
Configuration
Add your provider credentials to your .env file:
# Default provider HOSTING_PROVIDER=forge # Laravel Forge FORGE_API_TOKEN=your-forge-api-token # GridPane GRIDPANE_API_TOKEN=your-gridpane-api-token # Cloudways CLOUDWAYS_EMAIL=your-email@example.com CLOUDWAYS_API_KEY=your-cloudways-api-key # Kinsta KINSTA_API_KEY=your-kinsta-api-key KINSTA_COMPANY_ID=your-company-id # WP Engine WPENGINE_USERNAME=your-username WPENGINE_PASSWORD=your-password WPENGINE_ACCOUNT_ID=your-account-id # Ploi PLOI_API_TOKEN=your-ploi-api-token # RunCloud RUNCLOUD_API_KEY=your-api-key RUNCLOUD_API_SECRET=your-api-secret # SpinupWP SPINUPWP_API_TOKEN=your-spinupwp-api-token # cPanel/WHM CPANEL_API_URL=https://server.example.com:2087 CPANEL_API_TOKEN=your-cpanel-api-token CPANEL_USERNAME=root
Quick Start
Using the Facade
use Pstoute\LaravelHosting\Facades\Hosting; // Use the default provider $servers = Hosting::listServers(); // Use a specific provider $servers = Hosting::driver('forge')->listServers(); $sites = Hosting::driver('gridpane')->listSites();
Server Management
use Pstoute\LaravelHosting\Facades\Hosting; use Pstoute\LaravelHosting\Enums\ServerStatus; // List all servers $servers = Hosting::listServers(); // Filter operational servers $operational = $servers->filter(fn ($s) => $s->status === ServerStatus::Active); // Get a specific server $server = Hosting::getServer('server-id'); // Create a new server $server = Hosting::createServer([ 'name' => 'my-new-server', 'provider' => 'digitalocean', 'region' => 'nyc1', 'size' => 's-1vcpu-1gb', 'php_version' => '8.3', ]); // Reboot a server Hosting::rebootServer('server-id'); // Delete a server Hosting::deleteServer('server-id'); // Get server metrics $metrics = Hosting::getServerMetrics('server-id'); echo "CPU: {$metrics->cpuUsage}%"; echo "Memory: {$metrics->memoryUsage}%"; echo "Disk: {$metrics->diskUsage}%";
Site Management
use Pstoute\LaravelHosting\Facades\Hosting; use Pstoute\LaravelHosting\Enums\PhpVersion; // List all sites $sites = Hosting::listSites(); // List sites for a specific server $sites = Hosting::listSites('server-id'); // Get a specific site $site = Hosting::getSite('site-id'); // Create a new site $site = Hosting::createSite('server-id', [ 'domain' => 'example.com', 'php_version' => '8.3', 'wordpress' => true, ]); // Update PHP version Hosting::setPhpVersion('site-id', PhpVersion::PHP_84); // Suspend/unsuspend a site Hosting::suspendSite('site-id'); Hosting::unsuspendSite('site-id'); // Delete a site Hosting::deleteSite('site-id');
SSL Certificate Management
use Pstoute\LaravelHosting\Facades\Hosting; // Get SSL certificate status $ssl = Hosting::getSslCertificate('site-id'); if ($ssl && $ssl->expiresSoon(30)) { echo "SSL expires in less than 30 days!"; } // Install Let's Encrypt SSL $ssl = Hosting::installSslCertificate('site-id'); // Install custom SSL certificate $ssl = Hosting::installCustomSsl( 'site-id', $certificateContent, $privateKeyContent ); // Remove SSL certificate Hosting::removeSslCertificate('site-id');
Database Management
use Pstoute\LaravelHosting\Facades\Hosting; // List databases on a server $databases = Hosting::listDatabases('server-id'); // Create a database $database = Hosting::createDatabase('server-id', 'my_database'); // Create a database user $user = Hosting::createDatabaseUser('server-id', 'db_user', 'secure_password'); // Delete database Hosting::deleteDatabase('server-id', 'database-id');
Deployments
use Pstoute\LaravelHosting\Facades\Hosting; // Trigger a deployment $deployment = Hosting::deploy('site-id'); // Check deployment status $deployment = Hosting::getDeploymentStatus('site-id', $deployment->id); if ($deployment->isSuccessful()) { echo "Deployment completed in {$deployment->humanReadableDuration()}"; } // List deployment history $deployments = Hosting::listDeployments('site-id'); // Rollback to a previous deployment $rollback = Hosting::rollback('site-id', 'deployment-id');
Backups
use Pstoute\LaravelHosting\Facades\Hosting; // List backups $backups = Hosting::listBackups('site-id'); // Create a backup $backup = Hosting::createBackup('site-id', [ 'type' => 'full', // or 'database', 'files' ]); // Restore from backup Hosting::restoreBackup('site-id', 'backup-id'); // Delete a backup Hosting::deleteBackup('site-id', 'backup-id');
Connection Testing
use Pstoute\LaravelHosting\Facades\Hosting; // Test connection to the provider $result = Hosting::testConnection(); if ($result->success) { echo "Connected successfully!"; echo "Latency: {$result->latencyMs}ms"; } else { echo "Connection failed: {$result->message}"; }
Checking Provider Capabilities
use Pstoute\LaravelHosting\Facades\Hosting; use Pstoute\LaravelHosting\Enums\Capability; // Check if provider supports a capability if (Hosting::supportsCapability(Capability::GitDeployment)) { Hosting::deploy('site-id'); } // Get all capabilities $capabilities = Hosting::getCapabilities();
Data Transfer Objects (DTOs)
All data returned from provider methods uses strongly-typed DTOs:
Server
$server->id; // string $server->name; // string $server->ipAddress; // ?string $server->status; // ServerStatus enum $server->phpVersion; // ?PhpVersion enum $server->isOperational(); // bool $server->toArray(); // array
Site
$site->id; // string $site->serverId; // string $site->domain; // string $site->status; // SiteStatus enum $site->sslEnabled; // bool $site->isWordPress; // bool $site->hasValidSsl(); // bool
SslCertificate
$ssl->status; // SslStatus enum $ssl->expiresAt; // ?DateTimeImmutable $ssl->isValid(); // bool $ssl->isExpired(); // bool $ssl->expiresSoon(30); // bool (days threshold)
Deployment
$deployment->status; // DeploymentStatus enum $deployment->isSuccessful(); // bool $deployment->isComplete(); // bool $deployment->durationSeconds; // ?int $deployment->humanReadableDuration(); // string
ServerMetrics
$metrics->cpuUsage; // float $metrics->memoryUsage; // float $metrics->diskUsage; // float $metrics->isCpuCritical(90); // bool $metrics->isMemoryCritical(90); // bool $metrics->humanReadableUptime(); // string
Enums
ServerStatus
ServerStatus::Provisioning ServerStatus::Active ServerStatus::Inactive ServerStatus::Rebooting ServerStatus::Failed ServerStatus::Deleting ServerStatus::Unknown
SiteStatus
SiteStatus::Installing SiteStatus::Active SiteStatus::Suspended SiteStatus::Maintenance SiteStatus::Failed SiteStatus::Deleting SiteStatus::Unknown
PhpVersion
PhpVersion::PHP_74 PhpVersion::PHP_80 PhpVersion::PHP_81 PhpVersion::PHP_82 PhpVersion::PHP_83 PhpVersion::PHP_84 // Utilities PhpVersion::fromString('8.3'); // PhpVersion::PHP_83 PhpVersion::latest(); // PhpVersion::PHP_84 PhpVersion::recommended(); // PhpVersion::PHP_83 PhpVersion::PHP_83->isSupported(); // bool
Capability
Capability::ServerManagement
Capability::SiteManagement
Capability::DatabaseManagement
Capability::SslInstallation
Capability::GitDeployment
Capability::AutoDeployment
Capability::Backups
// ... and more
Events
The package dispatches events for key operations:
// Server events Pstoute\LaravelHosting\Events\ServerCreated Pstoute\LaravelHosting\Events\ServerProvisioned Pstoute\LaravelHosting\Events\ServerDeleted Pstoute\LaravelHosting\Events\ServerRebooted // Site events Pstoute\LaravelHosting\Events\SiteCreated Pstoute\LaravelHosting\Events\SiteDeleted Pstoute\LaravelHosting\Events\SiteSuspended Pstoute\LaravelHosting\Events\SiteUnsuspended // SSL events Pstoute\LaravelHosting\Events\SslCertificateInstalled Pstoute\LaravelHosting\Events\SslCertificateExpiring // Deployment events Pstoute\LaravelHosting\Events\DeploymentStarted Pstoute\LaravelHosting\Events\DeploymentCompleted Pstoute\LaravelHosting\Events\DeploymentFailed // Backup events Pstoute\LaravelHosting\Events\BackupCreated Pstoute\LaravelHosting\Events\BackupRestored
Listen to events in your EventServiceProvider:
protected $listen = [ \Pstoute\LaravelHosting\Events\DeploymentCompleted::class => [ \App\Listeners\NotifyDeploymentComplete::class, ], ];
Exception Handling
use Pstoute\LaravelHosting\Exceptions\HostingException; use Pstoute\LaravelHosting\Exceptions\ServerNotFoundException; use Pstoute\LaravelHosting\Exceptions\SiteNotFoundException; use Pstoute\LaravelHosting\Exceptions\AuthenticationException; use Pstoute\LaravelHosting\Exceptions\RateLimitException; use Pstoute\LaravelHosting\Exceptions\ProvisioningException; try { $server = Hosting::getServer('invalid-id'); } catch (ServerNotFoundException $e) { // Server not found } catch (AuthenticationException $e) { // Invalid API credentials } catch (RateLimitException $e) { // Too many requests, retry after: $e->retryAfter } catch (HostingException $e) { // Generic hosting error }
Testing
The package includes a FakeHostingProvider for testing your applications:
use Pstoute\LaravelHosting\Testing\FakeHostingProvider; use Pstoute\LaravelHosting\Facades\Hosting; use Pstoute\LaravelHosting\Data\Server; public function test_it_creates_a_server(): void { $fake = new FakeHostingProvider(); // Swap the provider Hosting::swap($fake); // Pre-seed data $fake->withServers([ Server::fromArray([ 'id' => '1', 'name' => 'existing-server', 'status' => 'active', ]), ]); // Your test code $servers = Hosting::listServers(); $this->assertCount(1, $servers); // Create a server $server = Hosting::createServer(['name' => 'new-server']); // Assertions $fake->assertServerCreated('new-server'); $fake->assertMethodCalled('createServer'); $fake->assertMethodNotCalled('deleteServer'); } public function test_it_handles_failures(): void { $fake = new FakeHostingProvider(); $fake->shouldFailWith('Simulated API error'); Hosting::swap($fake); $this->expectException(\Pstoute\LaravelHosting\Exceptions\HostingException::class); Hosting::listServers(); }
Available Test Assertions
$fake->assertServerCreated(?string $name = null); $fake->assertSiteCreated(?string $domain = null); $fake->assertSslInstalled(?string $siteId = null); $fake->assertDeployed(?string $siteId = null); $fake->assertBackupCreated(?string $siteId = null); $fake->assertMethodCalled(string $method, ?int $times = null); $fake->assertMethodNotCalled(string $method); $fake->getRecordedCalls(); // Get all recorded method calls $fake->getCallsTo(string $method); // Get calls to specific method
Test Setup Methods
$fake->withServers([...]); // Pre-populate servers $fake->withSites([...]); // Pre-populate sites $fake->withDatabases([...]); $fake->withCapabilities([Capability::ServerManagement]); $fake->shouldFailWith('Error message'); $fake->notConfigured(); $fake->reset(); // Reset all state
Caching
The package includes built-in caching to reduce API calls:
// config/hosting.php 'cache' => [ 'enabled' => env('HOSTING_CACHE_ENABLED', true), 'prefix' => 'hosting:', 'ttl' => [ 'servers' => 300, // 5 minutes 'sites' => 300, // 5 minutes 'ssl' => 3600, // 1 hour 'databases' => 600, // 10 minutes 'deployments' => 0, // Never cache ], ],
Rate Limiting
Built-in rate limiting protects against API limits:
// config/hosting.php 'rate_limits' => [ 'enabled' => env('HOSTING_RATE_LIMIT_ENABLED', true), 'per_minute' => env('HOSTING_RATE_LIMIT_PER_MINUTE', 60), ],
Extending with Custom Providers
Register custom providers in your service provider:
use Pstoute\LaravelHosting\Facades\Hosting; public function boot(): void { Hosting::extend('custom', function ($app, $config) { return new CustomHostingProvider($config); }); }
License
This package is open-source software licensed under the MIT license.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.