tourze/cloudflare-dns-bundle
A Symfony bundle that integrates Cloudflare DNS management into your application, letting you configure credentials and zones through bundle configuration and manage DNS records programmatically via the Cloudflare API with minimal setup.
This package wraps Cloudflare's DNS API, so the first thing to internalize is that it is a Symfony-style bundle, not a Laravel package with a service provider out of the box. Treat it as a library you wire up yourself.
Minimal steps:
composer require tourze/cloudflare-dns-bundle and pin to ^0.2 (the 0.2.0 changelog is only a compare link, so read the 0.1.3...0.2.0 diff before trusting the upgrade).Zone:DNS:Edit plus Zone:Zone:Read is enough for most work. Do not use the global API key.CLOUDFLARE_API_TOKEN and your zone ID(s) to config/services.php / .env rather than hardcoding.src/ for the DNS client/manager class and its constructor — that tells you what to bind into Laravel's container.First use case: a small artisan command that lists zones and upserts an A record for a subdomain. That exercises auth, zone lookup, and write path in one go.
// config/services.php
'cloudflare' => [
'token' => env('CLOUDFLARE_API_TOKEN'),
'zone' => env('CLOUDFLARE_ZONE_ID'),
],
Container binding. Register the underlying client/manager as a singleton in a small CloudflareServiceProvider you own. The bundle's Symfony DI wiring won't auto-run, so this is the bridge:
$this->app->singleton(DnsManager::class, fn ($app) => new DnsManager(
$app['config']->get('services.cloudflare.token')
));
Zone-per-environment mapping. Keep a config map of logical names (app, staging, cdn) to zone IDs, then resolve by name in code. Avoid scattering raw zone IDs through jobs and commands.
Reconciliation command. The highest-leverage pattern is an artisan dns:sync command that reads a declarative array of desired records (name, type, content, proxied, ttl) and diffs it against listRecords. Run it on deploy. This turns DNS into code and sidesteps the "who changed the record in the dashboard" problem.
Queued writes. Wrap create/update/delete in a job with retries and backoff. Cloudflare occasionally returns transient 5xx; a naive synchronous call in a request cycle will surface those to users.
Test seam. Bind a fake or point the HTTP client at Laravel's Http::fake() if the package uses an injectable client. If it doesn't, isolate it behind your own DnsProvider interface so feature tests never touch the network.
php artisan vendor:publish works, you'll waste an hour. Check for a DependencyInjection/ folder and wire manually.0.1.3...0.2.0 yourself; pre-1.0 semver means minor bumps can break constructor signatures. Pin exact versions in composer.json until you've reviewed.ttl on an orange-clouded record is silently meaningless — Cloudflare forces auto. Don't write assertions on TTL for proxied entries.(type, name), not content. Updating content in place requires the record ID from a list call first; blind create calls produce duplicate A records and unpredictable resolution.Given the lack of any substantive 0.2.0 notes, verify behavior against the actual diff before adopting; the patterns above hold regardless of what changed in the minor.
How can I help you explore Laravel packages today?