#!/bin/sh # firstboot-vps.sh — Phase 1: Install FreeBSD to disk from mfsBSD # # Runs on mfsBSD (FreeBSD in RAM) after SSH login. # Partitions disk, installs base FreeBSD, injects the clawdie-iso # firstboot payload, and reboots. On first HDD boot, the standard # firstboot.sh pipeline handles everything else (wizard, packages, # GPU, .env, deploy). # # Usage: # Interactive: /usr/local/share/clawdie-iso/firstboot-vps.sh # Headless: copy setup.txt.tpl → setup.txt, edit, then run # # Flow: # 1. Detect target disk # 2. Optionally read setup.txt for pre-baked values # 3. Partition disk (GPT: EFI + swap + ZFS) # 4. Create ZFS pool "clawdie" with standard datasets # 5. Install FreeBSD base + kernel # 6. Inject firstboot payload (same as installerconfig on USB) # 7. Install bootloader + reboot # # After reboot, firstboot.sh runs the modular shell-*.sh pipeline: # zfs detect → wizard → gpu → pkg → ssh → env → system → tailscale → deploy set -e SHARE="${SHARE:-/usr/local/share/clawdie-iso}" LOG="/var/log/clawdie-vps-install.log" . "${SHARE}/build.cfg" SETUP_IMPORT_TEST=1 . "${SHARE}/firstboot/setup-import.sh" # ── Helpers ��────────────────────────────────────────────────────────────── die() { echo "ERROR: $1" >&2; exit 1; } log_vps() { echo "$(date '+%H:%M:%S') $1" | tee -a "$LOG"; } gen_password() { openssl rand -base64 32 | tr -d '\n/+=' | head -c 24; } detect_disk() { for d in /dev/nda0 /dev/nvd0 /dev/da0 /dev/vtbd0 /dev/ada0; do if [ -e "$d" ]; then echo "$d" return 0 fi done die "Cannot detect target disk" } # ── Pre-baked config (headless) ─────────────────────────────────────────── if [ -f "${SHARE}/setup.txt" ]; then clawdie_setup_import_parse_file "${SHARE}/setup.txt" setup [ -f "${SHARE}/system.env" ] && clawdie_setup_import_parse_file "${SHARE}/system.env" system clawdie_setup_import_apply_defaults log_vps "[vps] Loaded setup.txt" elif [ -f "${SHARE}/clawdie.conf" ]; then . "${SHARE}/clawdie.conf" log_vps "[vps] Loaded legacy clawdie.conf" fi # ── Detect disk ─────────────────────────────────────────────────────────── DISK=$(detect_disk) log_vps "[vps] Target disk: ${DISK}" # ── Interactive confirmation (if TTY available) ────────────────────────── if [ -t 0 ] && command -v bsddialog >/dev/null 2>&1; then _dialog() { bsddialog --backtitle "Clawdie-VPS Setup" "$@" 2>&1; } _dialog --msgbox "\ Clawdie-VPS Installer Target disk: ${DISK} ALL DATA ON THIS DISK WILL BE ERASED. After installation, the system will reboot and run the standard Clawdie firstboot wizard." 12 60 if ! _dialog --yesno "\ Confirm: ERASE ALL DATA on ${DISK} and install FreeBSD?" 8 60; then die "Cancelled." fi # Optional: pre-set TARGET for vps (skip wizard on reboot) if [ -n "${ASSISTANT_NAME:-}" ] && [ -n "${AGENT_DOMAIN:-}" ] && [ -n "${TZ:-}" ]; then _vps_target="vps" _dialog --msgbox "\ Pre-baked config detected: Agent: ${ASSISTANT_NAME} Domain: ${AGENT_DOMAIN} TZ: ${TZ} Wizard will be skipped on first boot." 12 60 else _vps_target="baremetal" fi elif [ -t 0 ]; then echo "============================================" echo " Clawdie-VPS Installer" echo " Target disk: ${DISK}" echo " ALL DATA WILL BE ERASED." echo "============================================" printf "Continue? (yes/no): " read _confirm [ "$_confirm" = "yes" ] || die "Cancelled." _vps_target="baremetal" else # No TTY — require setup.txt (legacy clawdie.conf still accepted temporarily) [ -n "${ASSISTANT_NAME:-}" ] || die "No TTY and no ASSISTANT_NAME in setup.txt" _vps_target="vps" fi # ── Step 1: Partition disk ──────────────────────────────────────────────── log_vps "[vps] [1/5] Partitioning ${DISK}..." gpart destroy -F "${DISK}" 2>/dev/null || true gpart create -s gpt "${DISK}" gpart add -t efi -s 260M -l boot "${DISK}" gpart add -t freebsd-swap -s 2G -l swap "${DISK}" gpart add -t freebsd-zfs -l zroot "${DISK}" newfs_msdos /dev/gpt/boot # ── Step 2: Create ZFS pool ────────────────────────────────────────────── log_vps "[vps] [2/5] Creating ZFS pool 'clawdie'..." ZFS_PART="${DISK}p3" [ -e "/dev/gpt/zroot" ] && ZFS_PART="/dev/gpt/zroot" zpool create -f -m none -R /mnt clawdie "$ZFS_PART" zfs create -o mountpoint=none clawdie/ROOT zfs create -o mountpoint=/ clawdie/ROOT/default zfs create -o mountpoint=/tmp -o setuid=off clawdie/tmp zfs create -o mountpoint=/usr -o canmount=off clawdie/usr zfs create -o mountpoint=/home clawdie/home zfs create -o mountpoint=/var -o canmount=off clawdie/var zfs create -o mountpoint=/var/cache -o setuid=off clawdie/var/cache zfs create -o mountpoint=/var/log -o setuid=off clawdie/var/log zfs create -o mountpoint=/var/tmp -o setuid=off clawdie/var/tmp zfs create -o mountpoint=/var/db clawdie/var/db zfs set compression=lz4 clawdie zfs set atime=off clawdie # ── Step 3: Install FreeBSD base ───────────────────────────────────────── log_vps "[vps] [3/5] Installing FreeBSD ${FREEBSD_VERSION} base..." BASE_URL="https://download.freebsd.org/releases/${FREEBSD_ARCH}/${FREEBSD_VERSION}" cd /tmp fetch "${BASE_URL}/base.txz" || die "Failed to fetch base.txz" fetch "${BASE_URL}/kernel.txz" || die "Failed to fetch kernel.txz" tar -xpf base.txz -C /mnt tar -xpf kernel.txz -C /mnt # fstab cat > /mnt/etc/fstab < /mnt/boot/loader.conf < /mnt/etc/sysctl.conf < /mnt/etc/rc.conf < /mnt/usr/local/etc/sudoers.d/wheel </dev/null || true chmod +x "${HDD_SHARE}/firstboot/zfs-pool-migrate.sh" 2>/dev/null || true chmod +x "${HDD_SHARE}/firstboot/maintenance-mode.sh" 2>/dev/null || true # Install rc.d service mkdir -p "$HDD_RCD" cp "${SHARE}/firstboot/rc.d/clawdie-firstboot" "${HDD_RCD}/clawdie-firstboot" chmod +x "${HDD_RCD}/clawdie-firstboot" # ── Step 5: Install bootloader + reboot ────────────────────────────────── log_vps "[vps] [5/5] Installing EFI bootloader..." [ -f /mnt/boot/loader.efi ] || die "loader.efi not found after base extraction" mkdir -p /mnt/boot/efi mount -t msdosfs /dev/gpt/boot /mnt/boot/efi mkdir -p /mnt/boot/efi/EFI/BOOT cp /mnt/boot/loader.efi /mnt/boot/efi/EFI/BOOT/BOOTX64.EFI umount /mnt/boot/efi zpool set bootfs=clawdie/ROOT/default clawdie log_vps "[vps] Installation complete." echo "" echo "============================================" echo " FreeBSD installed to ${DISK}" echo " Pool: clawdie" echo "" echo " On first HDD boot, the Clawdie firstboot" echo " wizard will run automatically." echo "" echo " Root password: ${_root_pw}" echo " User password: ${_user_pw}" echo "" echo " SAVE THESE PASSWORDS NOW — they are not logged." echo "============================================" echo "" # Export and reboot log_vps "[vps] Exporting pool and rebooting in 10 seconds..." sleep 10 umount /mnt/boot/efi 2>/dev/null || true zpool export clawdie reboot