Provision PowerDNS zones immediately on domain link and add ensure-zone command.
Deploy Ladill Hosting / deploy (push) Successful in 40s
Deploy Ladill Hosting / deploy (push) Successful in 40s
Async-only zone jobs left Ladill NS returning REFUSED for new domains, which surfaces as Let's Encrypt SERVFAIL during SSL issuance. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Jobs\ProvisionDomainSlaveZoneJob;
|
||||||
|
use App\Jobs\ProvisionDomainZoneJob;
|
||||||
|
use App\Models\Domain;
|
||||||
|
use App\Services\Dns\PowerDnsClient;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class EnsureDomainZoneCommand extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'domain:ensure-zone
|
||||||
|
{host : Apex domain host, e.g. amenscientifichospital.com}
|
||||||
|
{--sync : Run in-process instead of queueing}';
|
||||||
|
|
||||||
|
protected $description = 'Create or refresh the PowerDNS zone for a domain (fixes SERVFAIL/REFUSED on Ladill NS).';
|
||||||
|
|
||||||
|
public function handle(PowerDnsClient $pdns): int
|
||||||
|
{
|
||||||
|
$host = strtolower(trim((string) $this->argument('host'), ". \t\n\r\0\x0B"));
|
||||||
|
$domain = Domain::query()->where('host', $host)->first();
|
||||||
|
|
||||||
|
if (! $domain) {
|
||||||
|
$this->error("No Domain row found for {$host}. Link the domain in Hosting first.");
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info(sprintf(
|
||||||
|
'Ensuring zone for %s (domain_id=%d, dns_mode=%s, onboarding=%s)',
|
||||||
|
$domain->host,
|
||||||
|
$domain->id,
|
||||||
|
$domain->dns_mode ?: '(null)',
|
||||||
|
$domain->onboarding_mode ?: '(null)'
|
||||||
|
));
|
||||||
|
|
||||||
|
if (! $this->option('sync')) {
|
||||||
|
ProvisionDomainZoneJob::dispatch($domain->id);
|
||||||
|
$this->info('Queued ProvisionDomainZoneJob. Use --sync to run immediately.');
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
(new ProvisionDomainZoneJob($domain->id))->handle($pdns);
|
||||||
|
$this->info('Zone provisioned on PowerDNS master.');
|
||||||
|
ProvisionDomainSlaveZoneJob::dispatch($domain->id);
|
||||||
|
$this->info('Queued slave zone sync.');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->error('Failed: '.$e->getMessage());
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Services\Domain;
|
namespace App\Services\Domain;
|
||||||
|
|
||||||
use App\Jobs\MailProvisioningJob;
|
use App\Jobs\MailProvisioningJob;
|
||||||
|
use App\Jobs\ProvisionDomainSlaveZoneJob;
|
||||||
use App\Jobs\ProvisionDomainZoneJob;
|
use App\Jobs\ProvisionDomainZoneJob;
|
||||||
use App\Jobs\SslProvisioningJob;
|
use App\Jobs\SslProvisioningJob;
|
||||||
use App\Models\Domain;
|
use App\Models\Domain;
|
||||||
@@ -12,6 +13,7 @@ use App\Models\DomainNsCheck;
|
|||||||
use App\Notifications\DomainVerifiedNotification;
|
use App\Notifications\DomainVerifiedNotification;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class DomainVerificationService
|
class DomainVerificationService
|
||||||
@@ -265,7 +267,26 @@ class DomainVerificationService
|
|||||||
|
|
||||||
public function reprovision(Domain $domain): void
|
public function reprovision(Domain $domain): void
|
||||||
{
|
{
|
||||||
$this->dispatchProvisioningChain($domain->id);
|
$domain = $domain->fresh() ?? $domain;
|
||||||
|
$this->ensureDkimKeys($domain);
|
||||||
|
|
||||||
|
// Create the authoritative zone immediately when possible. Async-only
|
||||||
|
// provisioning left Ladill NS delegated with REFUSED answers (SERVFAIL
|
||||||
|
// for Let's Encrypt) whenever the queue lagged or failed.
|
||||||
|
try {
|
||||||
|
$this->pdns->ensureZone($domain->fresh());
|
||||||
|
ProvisionDomainSlaveZoneJob::dispatch($domain->id);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
Log::warning('Immediate PDNS ensureZone failed; queueing retry', [
|
||||||
|
'domain_id' => $domain->id,
|
||||||
|
'host' => $domain->host,
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
ProvisionDomainZoneJob::dispatch($domain->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MailProvisioningJob::dispatch($domain->id);
|
||||||
|
SslProvisioningJob::dispatch($domain->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function dispatchProvisioningChain(int $domainId): void
|
private function dispatchProvisioningChain(int $domainId): void
|
||||||
|
|||||||
Reference in New Issue
Block a user