Search by

hostfog / hostfog-php

param3511

Official PHP client for the HostFog Panel REST API: manage sites, databases, SSL, DNS, backups and server stats.

v0.1.0 2026-10-16 09:18 UTC

This package is auto-updated.

Last update: 2026-10-16 09:39:53 UTC


README

HostFog

HostFog API client for PHP

The official PHP SDK for the HostFog Panel REST API.
Manage sites, databases, SSL certificates, DNS, backups and server stats from your own code. No dependencies.

Packagist version CI MIT licence Downloads

Install

composer require hostfog/hostfog-php

Quick start

<?php

require 'vendor/autoload.php';

use HostFog\Client;

$client = new Client(token: getenv('HOSTFOG_TOKEN'), host: 'panel.example.com');

$site = $client->sites->create(['domain' => 'example.com', 'phpVersion' => '8.3', 'ssl' => true]);
$client->ssl->issue('example.com');

foreach ($client->sites->list() as $site) {
    echo "{$site['domain']} is {$site['status']}\n";
}

Contents

Connecting

use HostFog\Client;

// Builds https://panel.example.com:2087/api/v1
$client = new Client(token: 'hf_...', host: 'panel.example.com');

// Or give the full base URL (takes precedence over host)
$client = new Client(token: 'hf_...', baseUrl: 'https://panel.example.com/api/v1');

// All options
$client = new Client(
    token: 'hf_...',
    host: '203.0.113.10',
    timeout: 60.0,      // seconds, default 30
    verifySsl: false,   // default true
    transport: null,    // custom transport, see "Testing your code"
);

Every request sends Authorization: Bearer {token}, Accept: application/json and User-Agent: hostfog-php/0.1.0, plus Content-Type: application/json when there's a body.

A freshly installed panel uses a self-signed certificate until you attach a hostname. Set verifySsl: false for that first connection only, then switch it back on.

Successful calls return the data from the response as a PHP array. Calls that get 204 No Content return null. Path segments such as domains and IDs are URL-encoded for you.

Sites

Site: {domain, status: "active"|"suspended", php_version, ssl, created_at}

// GET /sites
$sites = $client->sites->list();

// GET /sites/{domain}
$site = $client->sites->get('example.com');
// ['domain' => 'example.com', 'status' => 'active', 'php_version' => '8.3', 'ssl' => true, 'created_at' => '2026-10-16T09:00:00Z']

// POST /sites  (sent as {"domain", "php_version", "ssl"}; unset keys are left out)
$site = $client->sites->create([
    'domain' => 'example.com',
    'phpVersion' => '8.3',  // optional, 'php_version' also works
    'ssl' => true,          // optional
]);

// DELETE /sites/{domain}  (returns null)
$client->sites->delete('example.com');

// POST /sites/{domain}/suspend
$client->sites->suspend('example.com');

// POST /sites/{domain}/unsuspend
$client->sites->unsuspend('example.com');

Databases

Database: {name, user, size_bytes}

// GET /databases
$databases = $client->databases->list();

// POST /databases  (the panel generates a password if you leave it out)
$db = $client->databases->create([
    'name' => 'shop',
    'user' => 'shop_user',
    'password' => 'a-strong-password', // optional
]);

// DELETE /databases/{name}
$client->databases->delete('shop');

SSL

SslStatus: {domain, issued, issuer, valid_to, auto_renew}

// POST /ssl/{domain}  (issue or reissue a Let's Encrypt certificate)
$status = $client->ssl->issue('example.com');

// GET /ssl/{domain}
$status = $client->ssl->status('example.com');
// ['domain' => 'example.com', 'issued' => true, 'issuer' => "Let's Encrypt", 'valid_to' => '2027-01-14T00:00:00Z', 'auto_renew' => true]

DNS

DnsRecord: {id, type, name, value, ttl, priority}

// GET /dns/{domain}/records
$records = $client->dns->records('example.com');

// POST /dns/{domain}/records  (ttl and priority are optional)
$record = $client->dns->addRecord('example.com', [
    'type' => 'MX',
    'name' => '@',
    'value' => 'mail.example.com',
    'ttl' => 3600,
    'priority' => 10,
]);

$client->dns->addRecord('example.com', ['type' => 'A', 'name' => 'www', 'value' => '203.0.113.10']);

// DELETE /dns/{domain}/records/{id}
$client->dns->deleteRecord('example.com', $record['id']);

Backups

Backup: {id, domain|null, size_bytes, created_at, status}

// GET /backups
$backups = $client->backups->list();

// POST /backups  (whole server)
$backup = $client->backups->create();

// POST /backups  (one site)
$backup = $client->backups->create(['domain' => 'example.com']);

// POST /backups/{id}/restore
$client->backups->restore($backup['id']);

Server

// GET /server/info
$info = $client->server->info();
// ['hostname' => 'srv1', 'os' => 'Ubuntu 24.04', 'panel_version' => '1.0.0', 'ip' => '203.0.113.10']

// GET /server/stats
$stats = $client->server->stats();
// ['cpu_percent' => 12.5, 'memory_used' => ..., 'memory_total' => ..., 'disk_used' => ..., 'disk_total' => ..., 'load' => [0.1, 0.2, 0.3]]

Error handling

Exception When
HostFog\Exception\HostFogException Base class of everything below. Also thrown for a missing token or host.
HostFog\Exception\ApiException The panel answered with a non-2xx status.
HostFog\Exception\ConnectionException The panel couldn't be reached: DNS, refused connection, timeout or TLS failure.

ApiException exposes getStatus() (HTTP status), getErrorCode() (for example site_exists) and getMessage(). If the error body isn't valid JSON, the code is http_{status}, for example http_502.

use HostFog\Exception\ApiException;
use HostFog\Exception\ConnectionException;
use HostFog\Exception\HostFogException;

try {
    $client->sites->create(['domain' => 'example.com']);
} catch (ApiException $e) {
    if ($e->getErrorCode() === 'site_exists') {
        // already there, carry on
    } else {
        echo "API error {$e->getStatus()}: {$e->getMessage()}\n";
    }
} catch (ConnectionException $e) {
    echo "Panel unreachable: {$e->getMessage()}\n";
} catch (HostFogException $e) {
    // anything else from the SDK
}

Testing your code

Pass a transport callable to run without a network. It receives (string $method, string $url, array $headers, ?string $body) and returns ['status' => int, 'body' => string]. Throw any exception to simulate a network failure; it's rethrown as ConnectionException.

$client = new Client(
    token: 'test',
    host: 'panel.test',
    transport: function (string $method, string $url, array $headers, ?string $body): array {
        return ['status' => 200, 'body' => '{"data":[{"domain":"example.com","status":"active"}]}'];
    },
);

$client->sites->list(); // [['domain' => 'example.com', 'status' => 'active']]

API specification

openapi.yaml is the OpenAPI 3.1 contract for the HostFog Panel API v1. It's shared by the PHP, JavaScript and Python SDKs.

Requirements

  • PHP 8.1 or newer
  • ext-curl and ext-json

There are no Composer runtime dependencies.

Development

composer install
composer test        # or: vendor/bin/phpunit

The tests run fully offline. Every endpoint is checked through a recording fake transport, and the default cURL transport is tested against local HTTP and HTTPS servers on 127.0.0.1.

Publishing

This package has no publish workflow. Publishing to Packagist is a one-time step: submit https://github.com/hostfog/hostfog-php at packagist.org/packages/submit. After that, the Packagist GitHub hook picks up every new tag automatically, so releasing is just:

git tag v0.1.0 && git push origin v0.1.0

Other languages

Language API client Toolkit
PHP hostfog/hostfog-php (you are here) hostfog/toolkit-php
JavaScript hostfog/hostfog-js hostfog/toolkit-js
Python hostfog/hostfog-python hostfog/toolkit-python

Licence

MIT. Copyright (c) 2026 HostFog. See LICENSE.