Search by

lionix / digitalocean

karakhanyansarayiksmbatyan

DigitalOcean API client for the Laravel framework

Package info

github.com/lionix-team/digitalocean-api

pkg:composer/lionix/digitalocean

Statistics

Installs: 868

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2022-12-16 13:24 UTC

This package is auto-updated.

Last update: 2026-09-26 16:13:32 UTC


README

laravel-digitalocean

tests Latest Version License

A lightweight DigitalOcean API v2 client for Laravel, created by Arayik Smbatyan (@arayiksmbatyan) at Lionix.

It talks to the REST API directly through Laravel's HTTP client — no external SDK — so it is easy to extend and fully testable with Http::fake().

Requirements

Package PHP Laravel
2.x 8.2 – 8.5 12, 13
1.x 8.0+ 8 – 10

Laravel 13 itself requires PHP 8.3+.

Installation

composer require lionix/digitalocean

The service provider and facades are registered automatically via package discovery.

Publish the config file (optional):

php artisan vendor:publish --tag=digital-ocean-config

Configuration

Generate a Personal Access Token with write scope and add it to your .env file:

DO_APP_TOKEN=your-token

# Optional
DO_DROPLET_ID=123456789   # default droplet for the do:snapshot command
DO_CDN_ENDPOINT_ID=...    # default endpoint for the do:cdn-purge command
DO_TIMEOUT=30             # request timeout in seconds
DO_RETRY_TIMES=0          # retries on connection errors, 429 and 5xx responses
DO_RETRY_SLEEP=100        # milliseconds between retries

Available services

Facade Global accessor API
Droplets Digitalocean::droplets() Droplets
DropletActions Digitalocean::dropletActions() Droplet actions (power, resize, …)
Snapshots Digitalocean::snapshots() Snapshots
Domains Digitalocean::domains() Domains
DomainRecords Digitalocean::domainRecords() DNS records
SshKeys Digitalocean::sshKeys() SSH keys
Firewalls Digitalocean::firewalls() Cloud firewalls
ReservedIps Digitalocean::reservedIps() Reserved (floating) IPs
Cdn Digitalocean::cdn() CDN endpoints and cache purge
Actions Digitalocean::actions() Action status and waiting
Regions Digitalocean::regions() Regions
Sizes Digitalocean::sizes() Droplet sizes
Images Digitalocean::images() Images
— Digitalocean::account() Account info and balance

The service classes live in Digitalocean\Services and the facades in Digitalocean\Facades.

Usage

Every service can be used in three ways:

use Digitalocean\Services\DropletsService;

// 1. Dependency injection
public function index(DropletsService $droplets)
{
    return $droplets->list();
}

// 2. Service facade
Droplets::list();

// 3. Global facade
Digitalocean::droplets()->list();

Responses

Every method returns the decoded JSON response as an array with the HTTP status code added under status_code. API errors are returned the same way, so you can check them without catching exceptions:

$response = Droplets::show(123);

if ($response['status_code'] !== 200) {
    // e.g. ['id' => 'not_found', 'message' => 'The resource you requested could not be found.', 'status_code' => 404]
    logger()->error($response['message']);
}

store() methods validate their input first and throw Illuminate\Validation\ValidationException on invalid data. Network failures throw Illuminate\Http\Client\ConnectionException.

Droplets

Droplets::list(perPage: 20, page: 1, tagName: 'web');

Droplets::store([
    'name'   => 'web-1',          // or 'names' => ['web-1', 'web-2']
    'region' => 'nyc3',
    'size'   => 's-1vcpu-1gb',
    'image'  => 'ubuntu-24-04-x64',
    'ssh_keys' => [12345],
    'tags'   => ['web'],
]);

Droplets::show(123);
Droplets::destroy(123);

Droplet Actions

use Digitalocean\Enums\DropletActionType;

DropletActions::powerOn(123);
DropletActions::powerOff(123);
DropletActions::powerCycle(123);
DropletActions::shutdown(123);
DropletActions::reboot(123);
DropletActions::rename(123, 'new-name');
DropletActions::resize(123, 's-2vcpu-4gb', disk: true);
DropletActions::snapshot(123, 'before-upgrade');

// Any other action type
DropletActions::initiate(123, DropletActionType::EnableBackups);
DropletActions::initiate(123, 'rebuild', ['image' => 'ubuntu-24-04-x64']);

DropletActions::list(123);
DropletActions::show(123, $actionId);

Domains

Domains::list();
Domains::store(['name' => 'example.com', 'ip_address' => '1.2.3.4']);
Domains::show('example.com');
Domains::destroy('example.com');

Snapshots

Snapshots::list(123);               // snapshots of a droplet
Snapshots::all('droplet');          // all account snapshots, optionally 'droplet' or 'volume'
Snapshots::make(123, 'nightly');    // named "nightly-2026-01-01 00:00:00"
Snapshots::show($snapshotId);
Snapshots::destroy($snapshotId);

DNS Records

DomainRecords::list('example.com', type: 'A', name: 'www.example.com');

DomainRecords::store('example.com', [
    'type' => 'A',        // A, AAAA, CAA, CNAME, MX, NS, SOA, SRV, TXT
    'name' => 'tenant1',
    'data' => '203.0.113.10',
    'ttl'  => 3600,
]);

DomainRecords::show('example.com', $recordId);
DomainRecords::update('example.com', $recordId, ['data' => '203.0.113.20']);
DomainRecords::destroy('example.com', $recordId);

SSH Keys

SshKeys::list();
SshKeys::store('deploy-key', 'ssh-ed25519 AAAAC3Nza... deploy@example.com');
SshKeys::show($idOrFingerprint);
SshKeys::update($idOrFingerprint, 'new-name');
SshKeys::destroy($idOrFingerprint);

Regions, Sizes and Images

Reference data for building a "create droplet" form:

Regions::list();
Sizes::list();
Images::list(type: 'distribution');   // or 'application'
Images::list(private: true);          // your snapshots, backups and custom images
Images::show('ubuntu-24-04-x64');
Images::destroy($imageId);

Firewalls

Firewalls::list();

Firewalls::store([
    'name' => 'web',
    'inbound_rules' => [
        ['protocol' => 'tcp', 'ports' => '80',  'sources' => ['addresses' => ['0.0.0.0/0', '::/0']]],
        ['protocol' => 'tcp', 'ports' => '443', 'sources' => ['addresses' => ['0.0.0.0/0', '::/0']]],
    ],
    'outbound_rules' => [
        ['protocol' => 'tcp', 'ports' => 'all', 'destinations' => ['addresses' => ['0.0.0.0/0', '::/0']]],
    ],
    'tags' => ['web'],
]);

// Temporarily allow SSH from a CI runner, then revoke it
Firewalls::allowAddress($firewallId, '203.0.113.7', ports: '22');
Firewalls::revokeAddress($firewallId, '203.0.113.7', ports: '22');

Firewalls::addRules($firewallId, inbound: [...], outbound: [...]);
Firewalls::removeRules($firewallId, inbound: [...]);
Firewalls::addDroplets($firewallId, [123, 456]);
Firewalls::removeDroplets($firewallId, [456]);
Firewalls::addTags($firewallId, ['api']);
Firewalls::removeTags($firewallId, ['api']);
Firewalls::update($firewallId, $fullDefinition);   // replaces the whole firewall
Firewalls::destroy($firewallId);

Reserved IPs

ReservedIps::list();
ReservedIps::store(['droplet_id' => 123]);     // or ['region' => 'nyc3']
ReservedIps::assign('203.0.113.50', 456);      // move the IP to another droplet (failover)
ReservedIps::unassign('203.0.113.50');
ReservedIps::show('203.0.113.50');
ReservedIps::destroy('203.0.113.50');

CDN

Cdn::list();
Cdn::show($endpointId);
Cdn::purge($endpointId);                          // everything
Cdn::purge($endpointId, ['assets/*', 'index.html']);

Actions

Most write operations (snapshots, power actions, IP assignment…) return an action. You can check it or wait for it:

use Digitalocean\Services\ActionsService;

$response = DropletActions::reboot(123);

$result = Actions::waitFor($response['action']['id'], timeout: 300, interval: 5);

if (ActionsService::completed($result)) {
    // done
}

Actions::list();
Actions::show($actionId);

Account

Digitalocean::account()->show();
Digitalocean::account()->balance();

Any other endpoint

The global service can call any endpoint that does not have a dedicated wrapper yet:

Digitalocean::send('GET', 'volumes');
Digitalocean::send('POST', 'tags', ['name' => 'production']);

For full control you can grab a pre-configured PendingRequest (base URL, token, timeout and retries already set):

app(\Digitalocean\Services\DigitaloceanApi::class)->request()->get('sizes')->json();

Artisan commands

Snapshot

php artisan do:snapshot --dropletId=123 --name=nightly --dropOldSnapshots
Option Description
--dropletId Droplet ID. Falls back to DO_DROPLET_ID, then asks interactively.
--name Snapshot name prefix (defaults to the droplet ID). The current date-time is appended.
--dropOldSnapshots Delete the droplet's existing snapshots once the new snapshot is requested.
--wait Wait until the snapshot has finished.
--timeout Maximum seconds to wait with --wait (default 3600).

Old snapshots are only removed if the new snapshot request succeeds, and with --wait only once the snapshot has actually completed. The command exits with a non-zero code on failure, so it is safe to schedule:

// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('do:snapshot --dropOldSnapshots --wait')->dailyAt('03:00');

CDN purge

php artisan do:cdn-purge                                   # everything on DO_CDN_ENDPOINT_ID
php artisan do:cdn-purge <endpoint-id> --file="css/*" --file="js/*"

Handy as the last step of a deploy script.

Testing

Because the package uses Laravel's HTTP client, you can fake DigitalOcean in your own tests:

Http::fake([
    'api.digitalocean.com/v2/droplets*' => Http::response(['droplets' => []]),
]);

Run the package test suite:

composer test

Upgrading from 1.x

See CHANGELOG.md.

License

The MIT License (MIT).