fix: auto-create default user, force reboot, i915 firmware, first boot info

Critical fixes from ISO testing on .198:
- Backend auto-creates default user (password123) on first start
  so login works immediately after onboarding
- Force reboot (reboot -f) after install to avoid SquashFS errors
  when live USB is removed
- Eject USB before prompting user, not after
- Add firmware-misc-nonfree for Intel i915 GPU (suppresses dozens
  of "Possible missing firmware" warnings during initramfs update)
- First boot screen: wait up to 10s for DHCP before showing IP
- First boot screen: compact layout fits 80-col terminals
- ISOLINUX menu resolution dropped to 640x480 for universal
  VESA compatibility (was 1024x768, caused scaling on some hardware)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian 2026-03-28 13:06:34 +00:00
parent 9db55b0b34
commit 2021de5cda
3 changed files with 58 additions and 64 deletions

View File

@ -95,6 +95,18 @@ impl AuthManager {
Self { data_dir } Self { data_dir }
} }
/// Ensure a default user exists on first boot.
/// Called once at startup — creates user with default password if none exists.
pub async fn ensure_default_user(&self) -> Result<()> {
if self.is_setup().await? {
return Ok(());
}
tracing::info!("[onboarding] no user found — creating default user (password: password123)");
self.setup_user("password123").await?;
tracing::info!("[onboarding] default user created — user should change password after login");
Ok(())
}
pub async fn is_setup(&self) -> Result<bool> { pub async fn is_setup(&self) -> Result<bool> {
let user_file = self.data_dir.join("user.json"); let user_file = self.data_dir.join("user.json");
Ok(user_file.exists()) Ok(user_file.exists())

View File

@ -112,13 +112,12 @@ async fn main() -> Result<()> {
}); });
} }
// In dev mode, ensure a default user exists so login works without manual setup // Ensure a default user exists so login works after install/onboarding.
if config.dev_mode { // In production, the default password is "password123" (shown during install).
// In dev mode, the dev default password is used.
{
let auth = AuthManager::new(config.data_dir.clone()); let auth = AuthManager::new(config.data_dir.clone());
if !auth.is_setup().await? { auth.ensure_default_user().await?;
auth.setup_user(DEV_DEFAULT_PASSWORD).await?;
info!("👤 Created default dev user (password: {})", DEV_DEFAULT_PASSWORD);
}
} }
// Create server // Create server

View File

@ -261,6 +261,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
cryptsetup \ cryptsetup \
firmware-realtek \ firmware-realtek \
firmware-iwlwifi \ firmware-iwlwifi \
firmware-misc-nonfree \
intel-microcode \ intel-microcode \
amd64-microcode \ amd64-microcode \
xorg \ xorg \
@ -1815,55 +1816,37 @@ case ":$PATH:" in
esac esac
if [ -t 0 ] && [ -z "$ARCHIPELAGO_WELCOMED" ]; then if [ -t 0 ] && [ -z "$ARCHIPELAGO_WELCOMED" ]; then
export ARCHIPELAGO_WELCOMED=1 export ARCHIPELAGO_WELCOMED=1
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
# Wait for network (DHCP may not be ready yet on first boot)
IP=""
for i in 1 2 3 4 5; do
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
[ -n "$IP" ] && break
sleep 2
done
clear
echo "" echo ""
echo " _" echo " a r c h i p e l a g o"
echo " ,--.\\\`-. __" echo " ━━━━━━━━━━━━━━━━━━━━━"
echo " _,.\\\`. \\:/,\" \\\`-._" echo " bitcoin node os"
echo " ,-*\" _,.-;-*\\\`-.+\"*._ )"
echo " ( ,.\"* ,-\" / \\\`. \\\\. \\\`."
echo " ,\" ,;\" ,\"\\../\\ \\: \\"
echo " ( ,\"/ / \\\\.,' : )) /"
echo " \\ |/ / \\\\.,' / // ,'"
echo " \\_)\\ ,' \\\\.,' ( / )/"
echo " \\\` \\._,' \\\`\""
echo " \\..\/"
echo " \\..\/"
echo " ~ ~\\..\/ ~~ ~~"
echo " ~~ ~~ \\..\/ ~~ ~ ~~"
echo " ~~ ~ ~~ __...---\\../-...__ ~~~ ~~"
echo " ~~~~ ~_,--' \\..\/ \\\`--.__ ~~ ~~"
echo " ~~~ __,--' \\\`\" \\\`--.__ ~~~"
echo "~~ ,--' \\\`--."
echo " '------......______ ______......------\\\` ~~"
echo " ~~~ ~ ~~ ~ \\\`\\\`\\\`\\\`\\\`---\"\"\"\"\" ~~ ~ ~~"
echo " ~~~~ ~~ ~~~~ ~~~~~~ ~ ~~ ~~ ~~~ ~"
echo ""
echo " █████╗ ██████╗ ██████╗██╗ ██╗██╗██████╗ ███████╗██╗ █████╗ ██████╗ ██████╗ "
echo " ██╔══██╗██╔══██╗██╔════╝██║ ██║██║██╔══██╗██╔════╝██║ ██╔══██╗██╔════╝ ██╔═══██╗"
echo " ███████║██████╔╝██║ ███████║██║██████╔╝█████╗ ██║ ███████║██║ ███╗██║ ██║"
echo " ██╔══██║██╔══██╗██║ ██╔══██║██║██╔═══╝ ██╔══╝ ██║ ██╔══██║██║ ██║██║ ██║"
echo " ██║ ██║██║ ██║╚██████╗██║ ██║██║██║ ███████╗███████╗██║ ██║╚██████╔╝╚██████╔╝"
echo " ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ "
echo ""
echo " 🏝️ BITCOIN NODE OS 🏝️"
echo "" echo ""
if [ -n "$IP" ]; then if [ -n "$IP" ]; then
echo " 🌐 Web UI: http://$IP" echo " Web UI: http://$IP"
echo " 📡 SSH: ssh archipelago@$IP" echo " SSH: ssh archipelago@$IP"
echo " 🔑 Password: archipelago (SSH) / password123 (Web UI)" echo " Password: archipelago (SSH) / password123 (Web)"
echo ""
fi
if [ -b /dev/mapper/archipelago-data ]; then
echo " 🔒 Storage: LUKS2 encrypted"
fi
echo " 📺 Display:"
if systemctl is-active archipelago-kiosk.service >/dev/null 2>&1; then
echo " Kiosk ACTIVE — Ctrl+Alt+F1 for terminal"
else else
echo " Console — Ctrl+Alt+F7 for kiosk" echo " Waiting for network..."
fi
echo ""
if [ -b /dev/mapper/archipelago-data ]; then
echo " Storage: LUKS2 encrypted"
fi
if systemctl is-active archipelago-kiosk.service >/dev/null 2>&1; then
echo " Display: Kiosk active (Ctrl+Alt+F1 for terminal)"
else
echo " Display: Console (Ctrl+Alt+F7 for kiosk)"
fi fi
echo " Commands: sudo archipelago-kiosk enable|disable|toggle"
echo "" echo ""
fi fi
PROFILE PROFILE
@ -2504,13 +2487,8 @@ cc "${YELLOW}>>> REMOVE THE USB DRIVE NOW <<<${NC}"
echo "" echo ""
# Install log already saved before unmount (above) # Install log already saved before unmount (above)
cc "${DIM}Press Enter to reboot${NC}" # Eject USB BEFORE prompting — prevents SquashFS errors when user pulls drive
read -s
# Suppress all error output during cleanup and reboot
exec 2>/dev/null exec 2>/dev/null
# Try to eject the USB boot media to prevent booting back into installer
BOOT_DEV=$(findmnt -n -o SOURCE /run/archiso 2>/dev/null || findmnt -n -o SOURCE /cdrom 2>/dev/null || findmnt -n -o SOURCE /run/live/medium 2>/dev/null || echo "") BOOT_DEV=$(findmnt -n -o SOURCE /run/archiso 2>/dev/null || findmnt -n -o SOURCE /cdrom 2>/dev/null || findmnt -n -o SOURCE /run/live/medium 2>/dev/null || echo "")
if [ -n "$BOOT_DEV" ]; then if [ -n "$BOOT_DEV" ]; then
BOOT_DISK=$(lsblk -no PKNAME "$BOOT_DEV" 2>/dev/null | head -1) BOOT_DISK=$(lsblk -no PKNAME "$BOOT_DEV" 2>/dev/null | head -1)
@ -2521,8 +2499,13 @@ if [ -n "$BOOT_DEV" ]; then
eject "/dev/$BOOT_DISK" 2>/dev/null || true eject "/dev/$BOOT_DISK" 2>/dev/null || true
fi fi
fi fi
exec 2>&1
reboot cc "${DIM}Press Enter to reboot${NC}"
read -s
# Force reboot — avoids systemd trying to cleanly stop the (now-ejected) live FS
reboot -f
INSTALLER_SCRIPT INSTALLER_SCRIPT
# For unbundled builds, patch the completion message to reflect no pre-loaded apps # For unbundled builds, patch the completion message to reflect no pre-loaded apps
@ -2624,15 +2607,15 @@ UI vesamenu.c32
PROMPT 0 PROMPT 0
TIMEOUT 0 TIMEOUT 0
MENU TITLE Bitcoin Node OS MENU TITLE bitcoin node os
MENU BACKGROUND splash.png MENU BACKGROUND splash.png
MENU RESOLUTION 1024 768 MENU RESOLUTION 640 480
MENU VSHIFT 15 MENU VSHIFT 12
MENU HSHIFT 28 MENU HSHIFT 5
MENU WIDTH 26 MENU WIDTH 30
MENU MARGIN 2 MENU MARGIN 1
MENU ROWS 5 MENU ROWS 5
MENU TABMSG Press TAB to edit | https://archipelago.sh MENU TABMSG press tab to edit | archipelago.sh
MENU COLOR screen 37;40 #00000000 #00000000 none MENU COLOR screen 37;40 #00000000 #00000000 none
MENU COLOR border 30;40 #00000000 #00000000 none MENU COLOR border 30;40 #00000000 #00000000 none
MENU COLOR title 1;37;40 #80888888 #00000000 none MENU COLOR title 1;37;40 #80888888 #00000000 none