Reverb publishing is pinned to the INTERNAL reverb service (both dev * and prod compose name it `reverb`), so realtime keeps working right after a * domain change and never depends on the new public cert. The browser endpoint is * injected by the layout from DeploymentService::reverbClient(). * - app.url -> https:// so absolute URL generation matches how the panel is * served. With no domain (bare IP / dev) the env-derived app.url is left as is. */ public function boot(DeploymentService $deployment): void { // Re-apply the onboarding gate to EVERY Livewire component update, not just the // initial page GET. Livewire only re-runs route middleware that is registered as // persistent; without this, a component mounted while onboarded could keep running // destructive actions (hardening, SSH-key provisioning, credential changes) over // /livewire/update after the account is reverted to must_change_password mid-session. Livewire::addPersistentMiddleware([ EnsureSecurityOnboarded::class, ]); config([ 'broadcasting.connections.reverb.options.host' => 'reverb', 'broadcasting.connections.reverb.options.port' => 8080, 'broadcasting.connections.reverb.options.scheme' => 'http', 'broadcasting.connections.reverb.options.useTLS' => false, ]); $domain = $deployment->domain(); if ($domain !== null) { config(['app.url' => 'https://'.$domain]); } $this->applyMailSettings(); } /** * Apply the operator's SMTP settings (Settings\Email) to runtime config so * password-reset mails and notifications actually send. boot() runs every request, * so a saved change takes effect on the next request. * * Only switches to the `smtp` mailer when host + from-address are configured; * otherwise the safe install default (`log`) is left untouched, so nothing breaks * while unconfigured. The stored SMTP password is encrypted at rest (APP_KEY) and * decrypted here. Wrapped in try/catch like DeploymentService — the settings table * may not exist yet during install/migrate, and that must never break boot. */ private function applyMailSettings(): void { try { $host = Setting::get('mail_host'); $from = Setting::get('mail_from_address'); if ($host === null || $host === '' || $from === null || $from === '') { return; // unconfigured -> keep the safe default mailer } $encryption = Setting::get('mail_encryption', 'tls'); $storedPassword = Setting::get('mail_password'); $password = null; if ($storedPassword !== null && $storedPassword !== '') { $password = Crypt::decryptString($storedPassword); } config([ 'mail.default' => 'smtp', 'mail.mailers.smtp.host' => $host, 'mail.mailers.smtp.port' => (int) (Setting::get('mail_port', '587') ?? 587), 'mail.mailers.smtp.username' => Setting::get('mail_username') ?: null, 'mail.mailers.smtp.password' => $password ?: null, 'mail.mailers.smtp.encryption' => $encryption === 'none' ? null : $encryption, 'mail.from.address' => $from, 'mail.from.name' => Setting::get('mail_from_name') ?: $from, ]); } catch (Throwable) { // Settings table not migrated yet (install/migrate) or an undecryptable value — // leave the default mailer untouched. Never break boot. } } }