From 178ba85c5c67a69d6457592834c19fb6113c131e Mon Sep 17 00:00:00 2001 From: archipelago Date: Wed, 15 Jul 2026 05:17:02 -0400 Subject: [PATCH] fix(system): hostname rename updates /etc/hosts and re-announces mDNS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit server.set-name ran hostnamectl but left Debian's 127.0.1.1 line on the old name (breaking sudo's 'unable to resolve host' and hostname -f) and waited on avahi to notice the change by itself. Sync /etc/hosts and avahi-set-host-name (fallback: try-restart avahi-daemon) right after a successful rename, so http(s)://.local works immediately — best-effort, never blocks the rename. Co-Authored-By: Claude Fable 5 --- .../src/api/rpc/system/handlers.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/core/archipelago/src/api/rpc/system/handlers.rs b/core/archipelago/src/api/rpc/system/handlers.rs index cb2969d1..7c4e3a4d 100644 --- a/core/archipelago/src/api/rpc/system/handlers.rs +++ b/core/archipelago/src/api/rpc/system/handlers.rs @@ -53,6 +53,7 @@ impl RpcHandler { // hit a hostname-mismatch warning on top of the usual self-signed one // the moment a node is renamed. if hostname_updated { + sync_hostname_side_effects(&hostname).await; if let Err(e) = regenerate_tls_cert(&hostname).await { warn!(hostname = %hostname, "TLS cert regen after rename failed: {}", e); } @@ -375,6 +376,46 @@ pub(super) fn hostname_from_server_name(name: &str) -> String { } } +/// Post-rename side effects that keep the OS consistent with the new +/// hostname — all best-effort, the rename itself has already succeeded. +/// Debian resolves the local hostname via the 127.0.1.1 line in /etc/hosts; +/// leaving the old name there breaks `sudo` ("unable to resolve host") and +/// `hostname -f`. And while avahi eventually follows the kernel hostname, +/// re-announcing immediately makes http(s)://.local links work +/// right after the rename instead of minutes later. +async fn sync_hostname_side_effects(hostname: &str) { + // hostname_from_server_name guarantees [a-z0-9-], safe to interpolate. + let script = format!( + "if grep -q '^127\\.0\\.1\\.1' /etc/hosts; then sed -i 's/^127\\.0\\.1\\.1.*/127.0.1.1\\t{h}/' /etc/hosts; else printf '127.0.1.1\\t{h}\\n' >> /etc/hosts; fi", + h = hostname + ); + match tokio::process::Command::new("/usr/bin/sudo") + .args(["-n", "/bin/sh", "-c", &script]) + .output() + .await + { + Ok(o) if o.status.success() => {} + Ok(o) => warn!( + "/etc/hosts hostname sync failed: {}", + String::from_utf8_lossy(&o.stderr).trim() + ), + Err(e) => warn!("/etc/hosts hostname sync failed: {}", e), + } + + let republished = tokio::process::Command::new("/usr/bin/sudo") + .args(["-n", "/usr/bin/avahi-set-host-name", hostname]) + .output() + .await + .map(|o| o.status.success()) + .unwrap_or(false); + if !republished { + let _ = tokio::process::Command::new("/usr/bin/sudo") + .args(["-n", "/usr/bin/systemctl", "try-restart", "avahi-daemon"]) + .output() + .await; + } +} + async fn set_system_hostname(hostname: &str) -> Result<()> { let output = tokio::process::Command::new("/usr/bin/sudo") .args(["-n", "/usr/bin/hostnamectl", "set-hostname", hostname])