Looking to hire Laravel developers? Try LaraJobs

laravel-directadmin maintained by beziworld

Description
Laravel client for the DirectAdmin API: users, domains, e-mail, databases, DNS, SSL, cron and backups.
Last update
2026/11/04 13:41 (dev-master)
License
Downloads
1

Comments
comments powered by Disqus

Laravel DirectAdmin

tests Latest Version License

Laravel client for the DirectAdmin hosting control panel: accounts, packages, domains, e-mail, databases, FTP, DNS, cron, SSL, backups and server information, for one or many servers.

Polska wersja dokumentacji

Features

  • Multiple named connections (like database connections) plus runtime connections for servers stored in your DB
  • Impersonation (admin|user) per connection or per call with loginAs()
  • Topic resources: users, packages, domains, email, databases, ftp, dns, cron, ssl, backups, system
  • Legacy CMD_API_* commands in JSON mode and the new /api/* JSON API; raw command(), action() and api() for anything not covered
  • Reliable error detection: DirectAdmin reports some failures with HTTP 200 and others with HTTP 500, and failed logins as 401, redirects or HTML pages; all of them become typed exceptions
  • No retries after an authentication failure, so the Brute Force Monitor does not block your server
  • php artisan directadmin:check to test a connection
  • PHP 8.3+, Laravel 12 and 13, PHPStan level 8

Installation

composer require beziworld/laravel-directadmin
php artisan vendor:publish --tag=directadmin-config   # optional
DIRECTADMIN_HOST=https://server.example.com:2222
DIRECTADMIN_USERNAME=admin
DIRECTADMIN_PASSWORD=login-key            # a login key is strongly recommended over the password
DIRECTADMIN_VERIFY_SSL=true               # false or a CA bundle path for self-signed panels
php artisan directadmin:check

Create a login key in DirectAdmin (Login Keys), restrict it to your application's IP address and to the commands you use, and deny CMD_LOGIN_KEYS on the key itself.

Usage examples

Provision a hosting account after an order is paid

use Beziworld\DirectAdmin\Data\AccountRequest;
use Beziworld\DirectAdmin\Exceptions\CommandException;
use Beziworld\DirectAdmin\Facades\DirectAdmin;

class ProvisionHosting implements ShouldQueue
{
    public function handle(): void
    {
        $password = Str::password(16);

        try {
            DirectAdmin::users()->create(new AccountRequest(
                username: $this->order->username,
                email: $this->order->email,
                password: $password,
                domain: $this->order->domain,
                package: $this->order->plan->package,      // DirectAdmin package name
                ip: config('hosting.shared_ip'),
            ));
        } catch (CommandException $e) {
            // e.g. "DirectAdmin CMD_API_ACCOUNT_USER failed: Unable to Create User (That username already exists)"
            $this->fail($e);

            return;
        }

        $client = DirectAdmin::loginAs($this->order->username);   // act as the new user
        $client->ssl()->requestLetsEncrypt($this->order->domain);
        $client->email()->createAccount($this->order->domain, 'office', Str::password(16), quota: 2048);

        Mail::to($this->order->email)->send(new HostingReady($this->order, $password));
    }
}

Suspend unpaid accounts

$overdue = Subscription::overdue()->pluck('username')->all();

if ($overdue !== []) {
    DirectAdmin::users()->suspend(...$overdue);
}

// After payment:
DirectAdmin::users()->unsuspend('john');

Upgrade a plan or change limits

DirectAdmin::users()->changePackage('john', 'business');

// Custom limits; current settings are read first, because DirectAdmin turns omitted checkboxes OFF.
DirectAdmin::users()->customize('john', ['quota' => 20480, 'bandwidth' => 'unlimited', 'ssh' => true]);

Usage dashboard for a customer

$usage = DirectAdmin::users()->usage('john');     // ['quota' => '512.3', 'bandwidth' => '1024', ...]
$config = DirectAdmin::users()->config('john');   // ['package' => 'business', 'quota' => '20480', ...]

E-mail

$email = DirectAdmin::loginAs('john')->email();

$email->createAccount('example.com', 'office', $password, quota: 1024, sendLimit: 500);
$email->updateAccount('example.com', 'office', password: $newPassword);
$email->createForwarder('example.com', 'sales', ['anna@example.com', 'piotr@example.com']);
$email->createAutoresponder('example.com', 'office', 'We will reply within 24 hours.');
$email->createVacation('example.com', 'anna', 'On holiday until 2 January.', new DateTime('2026-12-24'), new DateTime('2027-01-02'));
$email->setCatchAll('example.com', ':fail:');

Databases for a deployment

$db = DirectAdmin::loginAs('john')->databases();

$db->create('shop', 'shop', $password);           // creates john_shop and user john_shop
$db->addAccessHost('john_shop', '10.0.0.%');      // remote access from your app servers
$db->changeUserPassword('john_shop', 'john_shop', $rotated);

DNS records (e.g. domain verification)

$dns = DirectAdmin::loginAs('john')->dns();

$dns->add('example.com', 'TXT', 'example.com.', '"google-site-verification=abc123"');
$dns->add('example.com', 'MX', 'example.com.', '10 mail.example.com.');
$dns->update('example.com', 'A', 'www', oldValue: '10.0.0.1', newValue: '10.0.0.2', ttl: 300);
$dns->delete('example.com', 'TXT', 'example.com.', '"google-site-verification=abc123"');

Cron, FTP, SSL and backups

$client = DirectAdmin::loginAs('john');

$client->cron()->create('* * * * *', '/usr/local/bin/php /home/john/app/artisan schedule:run');
$client->ftp()->create('example.com', 'deploy', $password, type: 'custom', path: '/home/john/domains/example.com/app');
$client->ssl()->requestLetsEncrypt('example.com', ['example.com', 'www.example.com', 'shop.example.com']);
$client->backups()->create('example.com', ['database', 'email']);

Several servers

// config/directadmin.php
'connections' => [
    'default' => [...],
    'server2' => ['host' => env('DA2_HOST'), 'username' => env('DA2_USER'), 'password' => env('DA2_KEY')],
],

DirectAdmin::connection('server2')->users()->all();

// Servers stored in the database
DirectAdmin::build([
    'host' => $server->host,
    'username' => $server->username,
    'password' => decrypt($server->login_key),
])->system()->info();

Anything else

DirectAdmin::command('SHOW_USER_DOMAINS', ['user' => 'john']);        // any CMD_API_* (GET)
DirectAdmin::action('DOMAIN', ['action' => 'modify', 'domain' => 'x.com', 'php' => 'ON']); // any CMD_API_* (POST)
DirectAdmin::api('GET', 'db-show/databases');                          // the /api JSON API
DirectAdmin::system()->version();                                      // /api/version

Exceptions

All exceptions extend DirectAdminException:

Exception When
AuthenticationException Credentials rejected (401, redirect, HTML login page). Never retried.
CommandException DirectAdmin reported an error (command(), details(), httpStatus(), payload()) or could not be reached
InvalidConfiguration Unknown connection or missing host / credentials

Notes

  • Resource methods that create objects take names without the account prefix (create('shop') creates john_shop); methods referencing existing databases take the full name.
  • Backups and restores are queued by DirectAdmin; the call only confirms scheduling.
  • Every call is synchronous and some (account creation, SSL) take several seconds: run them in queued jobs.

Development

composer install
composer ci   # pint --test, phpstan (level 8), pest

Author

Created and maintained by Kamil Ćwiertnia, beziworld.eu.

Building a hosting panel, automated provisioning or a custom Laravel project? Get in touch through beziworld.eu.

Other packages by the author

License

MIT. See LICENSE.md. This package is not affiliated with JBMC Software (DirectAdmin).