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.

Maintainers

Package info

github.com/pstoute/laravel-hosting-management

pkg:composer/pstoute/laravel-hosting-management

Statistics

Installs: 258

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.1 2026-02-04 01:17 UTC

This package is auto-updated.

Last update: 2026-03-04 01:32:03 UTC


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.

Credits