laravel-directadmin maintained by beziworld
Description
Laravel client for the DirectAdmin API: users, domains, e-mail, databases, DNS, SSL, cron and backups.
Author
Last update
2026/11/04 13:41
(dev-master)
License
Downloads
1
Tags
Laravel DirectAdmin
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.
Features
- Multiple named connections (like database connections) plus runtime connections for servers stored in your DB
- Impersonation (
admin|user) per connection or per call withloginAs() - 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; rawcommand(),action()andapi()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:checkto 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', ...]
$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')createsjohn_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.
- E-mail: biuro@beziworld.eu
- Issues and feature requests: GitHub issues
- Security vulnerabilities: see SECURITY.md
Building a hosting panel, automated provisioning or a custom Laravel project? Get in touch through beziworld.eu.
Other packages by the author
- beziworld/laravel-przelewy24: Przelewy24 payments
- beziworld/laravel-tpay: Tpay payments and BLIK
- beziworld/laravel-smsapi: SMSAPI messages and notifications
License
MIT. See LICENSE.md. This package is not affiliated with JBMC Software (DirectAdmin).