instance($run); $host = $instance->host; $fqdn = $instance->subdomain.'.'.config('provisioning.dns.zone'); // DNS — persist the record id [E] before anything downstream. if (! $this->hasResource($run, 'dns_record_id')) { $recordId = $this->dns->upsertRecord($fqdn, 'A', $host->public_ip); $instance->dnsRecords()->create([ 'provider' => 'hetzner', 'record_id' => $recordId, 'fqdn' => $fqdn, 'type' => 'A', 'value' => $host->public_ip, ]); $this->recordResource($run, $host, 'dns_record_id', $recordId); } // Traefik file-provider route → the guest VM (fall back to the host only // if the guest address wasn't captured). if (! $instance->route_written) { $target = $instance->guest_ip ?: ($host->wg_ip ?? $host->public_ip); $this->traefik->write($instance->subdomain, $target); $instance->update(['route_written' => true]); } // TLS via HTTP-01 — poll until the certificate is served. if (! $instance->cert_ok) { if ($this->traefik->certReachable($fqdn)) { $instance->update(['cert_ok' => true]); } elseif ($run->started_at !== null && $run->started_at->copy()->addSeconds(840)->isPast()) { return StepResult::fail('cert_timeout'); } else { return StepResult::poll(20, 'waiting for certificate'); } } return StepResult::advance(); } }