Files
ladill-hosting/app/Services/Domain/DomainDnsBlueprintService.php
T
isaaccladandCursor e251a4cf60
Deploy Ladill Hosting / deploy (push) Failing after 17s
Initial Ladill Hosting app with Gitea deploy pipeline.
Shared web hosting extracted from the platform monolith, with CI deploy
to /var/www/ladill-hosting matching Bird/Domains/Email.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 16:24:20 +00:00

177 lines
5.8 KiB
PHP

<?php
namespace App\Services\Domain;
use App\Models\Domain;
class DomainDnsBlueprintService
{
public function expectedNameservers(): array
{
$nameservers = (array) config('mailinfra.nameservers', ['ns1.ladill.com', 'ns2.ladill.com']);
return collect($nameservers)
->map(fn ($value) => strtolower(trim((string) $value, ". \t\n\r\0\x0B")))
->filter()
->unique()
->values()
->all();
}
public function mailSetupInstructions(): array
{
return [
'imap' => [
'server' => (string) config('mailinfra.mail_host', 'mail.ladill.com'),
'port' => (int) config('mailinfra.imap_port', 993),
'security' => 'SSL/TLS',
'username' => 'full_email',
],
'smtp' => [
'server' => (string) config('mailinfra.mail_host', 'mail.ladill.com'),
'port' => (int) config('mailinfra.smtp_port', 587),
'security' => 'STARTTLS',
'authentication' => true,
'username' => 'full_email',
],
'smtp_ssl' => [
'server' => (string) config('mailinfra.mail_host', 'mail.ladill.com'),
'port' => (int) config('mailinfra.smtp_ssl_port', 465),
'security' => 'SSL/TLS',
],
];
}
public function managedRecords(Domain $domain, string $selector, string $publicKey): array
{
$mailHost = strtolower(trim((string) config('mailinfra.mail_host', 'mail.ladill.com')));
$autodiscoverHost = strtolower(trim((string) config('mailinfra.autodiscover_host', 'autodiscover.ladill.com')));
$autoconfigHost = strtolower(trim((string) config('mailinfra.autoconfig_host', 'autoconfig.ladill.com')));
$ttl = (int) config('mailinfra.default_ttl', 3600);
$websiteIp = trim((string) config('mailinfra.website_a_record', ''));
$wwwTarget = trim((string) config('mailinfra.website_www_cname', '@'));
$rua = trim((string) config('mailinfra.dmarc_rua', 'mailto:dmarc@ladill.com'));
$records = [];
// Always include A record for apex domain (use configured IP or placeholder)
$records[] = [
'name' => '@',
'type' => 'A',
'value' => $websiteIp !== '' ? $websiteIp : '161.97.138.149',
'ttl' => $ttl,
'priority' => null,
'source' => 'managed',
'status' => 'active',
'notes' => 'Website apex record',
];
// Always include www record (CNAME to @ or A record to same IP)
if ($wwwTarget !== '' && $wwwTarget !== '@') {
$records[] = [
'name' => 'www',
'type' => 'CNAME',
'value' => $wwwTarget,
'ttl' => $ttl,
'priority' => null,
'source' => 'managed',
'status' => 'active',
'notes' => 'Website www record',
];
} else {
// Default: www points to same IP as apex
$records[] = [
'name' => 'www',
'type' => 'A',
'value' => $websiteIp !== '' ? $websiteIp : '161.97.138.149',
'ttl' => $ttl,
'priority' => null,
'source' => 'managed',
'status' => 'active',
'notes' => 'Website www record',
];
}
$records[] = [
'name' => '@',
'type' => 'MX',
'value' => $mailHost.'.',
'ttl' => $ttl,
'priority' => 10,
'source' => 'managed',
'status' => 'active',
'notes' => 'Primary mail exchanger',
];
$records[] = [
'name' => '@',
'type' => 'TXT',
'value' => (string) config('mailinfra.spf_customer_txt'),
'ttl' => $ttl,
'priority' => null,
'source' => 'managed',
'status' => 'active',
'notes' => 'SPF policy',
];
$records[] = [
'name' => $selector.'._domainkey',
'type' => 'TXT',
'value' => sprintf('v=DKIM1; k=rsa; p=%s', $publicKey),
'ttl' => $ttl,
'priority' => null,
'source' => 'managed',
'status' => 'active',
'notes' => 'DKIM public key',
];
$records[] = [
'name' => '_dmarc',
'type' => 'TXT',
'value' => sprintf('v=DMARC1; p=none; rua=%s; adkim=s; aspf=s', $rua),
'ttl' => $ttl,
'priority' => null,
'source' => 'managed',
'status' => 'active',
'notes' => 'DMARC policy',
];
$records[] = [
'name' => 'autodiscover',
'type' => 'CNAME',
'value' => $autodiscoverHost.'.',
'ttl' => $ttl,
'priority' => null,
'source' => 'managed',
'status' => 'active',
'notes' => 'Autodiscover helper',
];
$records[] = [
'name' => 'autoconfig',
'type' => 'CNAME',
'value' => $autoconfigHost.'.',
'ttl' => $ttl,
'priority' => null,
'source' => 'managed',
'status' => 'active',
'notes' => 'Autoconfig helper',
];
return $records;
}
public function manualDnsPack(Domain $domain, string $selector, string $publicKey): array
{
return collect($this->managedRecords($domain, $selector, $publicKey))
->map(function (array $record) {
$record['source'] = 'required_manual';
$record['status'] = 'pending';
return $record;
})
->values()
->all();
}
}