Initial Ladill Hosting app with Gitea deploy pipeline.
Deploy Ladill Hosting / deploy (push) Failing after 17s
Deploy Ladill Hosting / deploy (push) Failing after 17s
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>
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user