2026-04-05 09:04:45 +00:00
|
|
|
#!/bin/sh
|
|
|
|
|
# build-vps.sh — Build mfsBSD ISO with Clawdie-AI payload for VPS providers
|
|
|
|
|
#
|
|
|
|
|
# Usage:
|
|
|
|
|
# ./build-vps.sh # full build
|
|
|
|
|
# ./build-vps.sh --skip-fetch # use cached files
|
|
|
|
|
# ./build-vps.sh --clawdie-version 0.9.0
|
|
|
|
|
#
|
2026-04-05 14:19:32 +00:00
|
|
|
# Output: tmp/output/clawdie-vps-DD.mmm.YYYY.iso
|
2026-04-05 09:04:45 +00:00
|
|
|
#
|
|
|
|
|
# This ISO can be uploaded to:
|
|
|
|
|
# - Vultr (Custom ISO)
|
|
|
|
|
# - Any provider with ISO mount support
|
|
|
|
|
#
|
|
|
|
|
# After boot:
|
|
|
|
|
# ssh -p 1022 mfsbsd@your-ip
|
|
|
|
|
# Password: clawdie2026
|
|
|
|
|
# /usr/local/share/clawdie-iso/firstboot.sh
|
|
|
|
|
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
|
|
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
2026-04-05 14:19:32 +00:00
|
|
|
TMP_DIR="${SCRIPT_DIR}/tmp"
|
|
|
|
|
CACHE_DIR="${TMP_DIR}/cache"
|
|
|
|
|
PKG_REPO_DIR="${TMP_DIR}/packages"
|
|
|
|
|
OUTPUT_DIR="${TMP_DIR}/output"
|
|
|
|
|
ISO_WORK="${TMP_DIR}/iso-work"
|
2026-04-05 09:04:45 +00:00
|
|
|
|
|
|
|
|
. "${SCRIPT_DIR}/build.cfg"
|
2026-04-05 14:19:32 +00:00
|
|
|
mkdir -p "$TMP_DIR"
|
2026-04-05 09:04:45 +00:00
|
|
|
|
|
|
|
|
# --- VPS-specific config ---
|
|
|
|
|
MFSBSD_ISO_URL="https://depenguin.me/files/mfsbsd-15.0-RELEASE-amd64.iso"
|
|
|
|
|
MFSBSD_PASSWORD="clawdie2026"
|
|
|
|
|
SSH_PORT="1022"
|
|
|
|
|
|
|
|
|
|
# --- argument parsing ---
|
|
|
|
|
SKIP_FETCH=0
|
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
|
|
|
case "$1" in
|
|
|
|
|
--clawdie-version) CLAWDIE_VERSION="$2"; shift 2 ;;
|
|
|
|
|
--skip-fetch) SKIP_FETCH=1; shift ;;
|
|
|
|
|
*) echo "Unknown arg: $1"; exit 1 ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
echo "==> Clawdie-VPS ISO Build"
|
|
|
|
|
echo " FreeBSD : mfsBSD 15.0-RELEASE"
|
|
|
|
|
echo " Clawdie : v${CLAWDIE_VERSION}"
|
|
|
|
|
echo " Password: ${MFSBSD_PASSWORD}"
|
|
|
|
|
echo " SSH Port: ${SSH_PORT}"
|
|
|
|
|
echo ""
|
|
|
|
|
|
|
|
|
|
# --- step 1: fetch mfsBSD ISO ---
|
|
|
|
|
MFSBSD_ISO="${CACHE_DIR}/mfsbsd-15.0-RELEASE-amd64.iso"
|
|
|
|
|
if [ "$SKIP_FETCH" -eq 0 ] || [ ! -f "$MFSBSD_ISO" ]; then
|
|
|
|
|
echo "==> [1/6] Downloading mfsBSD ISO..."
|
|
|
|
|
mkdir -p "$CACHE_DIR"
|
|
|
|
|
curl -L --progress-bar -o "$MFSBSD_ISO" "$MFSBSD_ISO_URL"
|
|
|
|
|
echo " Done: $(du -sh "$MFSBSD_ISO" | cut -f1)"
|
|
|
|
|
else
|
|
|
|
|
echo "==> [1/6] mfsBSD ISO cached."
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# --- step 2: fetch Clawdie-AI tarball ---
|
|
|
|
|
if [ "$CLAWDIE_VERSION" = "latest" ] || [ -z "$CLAWDIE_VERSION" ]; then
|
|
|
|
|
echo "==> [2/6] Resolving latest Clawdie-AI version..."
|
2026-06-02 09:00:33 +02:00
|
|
|
CLAWDIE_VERSION=$(
|
|
|
|
|
curl -fsS "https://code.smilepowered.org/api/v1/repos/clawdie/clawdie-ai/releases?limit=20" 2>/dev/null \
|
|
|
|
|
| grep -o '"tag_name":"[^"]*"' \
|
|
|
|
|
| head -1 \
|
|
|
|
|
| cut -d'"' -f4 \
|
|
|
|
|
| sed 's/^v//'
|
|
|
|
|
)
|
|
|
|
|
if [ -z "$CLAWDIE_VERSION" ]; then
|
|
|
|
|
CLAWDIE_VERSION=$(
|
|
|
|
|
git ls-remote --tags "https://code.smilepowered.org/clawdie/clawdie-ai.git" 2>/dev/null \
|
|
|
|
|
| awk -F/ '$2 == "tags" && $3 ~ /^v[0-9]+\.[0-9]+\.[0-9]+$/ { print $3 }' \
|
|
|
|
|
| sed 's/^v//' \
|
|
|
|
|
| sort -t. -k1,1n -k2,2n -k3,3n \
|
|
|
|
|
| tail -n 1 \
|
|
|
|
|
| sed 's/^v//'
|
|
|
|
|
)
|
|
|
|
|
fi
|
|
|
|
|
if [ -z "$CLAWDIE_VERSION" ]; then
|
|
|
|
|
echo "ERROR: could not resolve latest Clawdie-AI release/tag from Forgejo."
|
|
|
|
|
echo " Pin --clawdie-version X.Y.Z explicitly."
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
2026-04-05 09:04:45 +00:00
|
|
|
echo " Resolved: v${CLAWDIE_VERSION}"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
CLAWDIE_TARBALL="${CACHE_DIR}/clawdie-ai-v${CLAWDIE_VERSION}.tar.gz"
|
|
|
|
|
if [ "$SKIP_FETCH" -eq 0 ] || [ ! -f "$CLAWDIE_TARBALL" ]; then
|
|
|
|
|
echo "==> [2/6] Downloading Clawdie-AI v${CLAWDIE_VERSION}..."
|
|
|
|
|
curl -L --progress-bar -o "$CLAWDIE_TARBALL" \
|
2026-06-02 09:00:33 +02:00
|
|
|
"https://code.smilepowered.org/clawdie/clawdie-ai/archive/v${CLAWDIE_VERSION}.tar.gz"
|
2026-04-05 09:04:45 +00:00
|
|
|
else
|
|
|
|
|
echo "==> [2/6] Clawdie-AI cached."
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# --- step 3: fetch packages (if not already done) ---
|
2026-04-05 14:19:32 +00:00
|
|
|
if [ "$SKIP_FETCH" -eq 0 ] && [ ! -d "$PKG_REPO_DIR/All" ]; then
|
2026-04-05 09:04:45 +00:00
|
|
|
echo "==> [3/6] Packages not fetched. Run ./build.sh --fetch-only first."
|
|
|
|
|
echo " Skipping package bundle (ISO will require internet for pkg install)."
|
|
|
|
|
PKG_BUNDLE=0
|
|
|
|
|
else
|
|
|
|
|
echo "==> [3/6] Package bundle ready."
|
|
|
|
|
PKG_BUNDLE=1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# --- step 4: extract and modify mfsBSD ---
|
|
|
|
|
echo "==> [4/6] Extracting mfsBSD..."
|
|
|
|
|
rm -rf "$ISO_WORK"
|
|
|
|
|
mkdir -p "$ISO_WORK"
|
|
|
|
|
|
|
|
|
|
# mfsBSD ISO is a standard ISO9660 - extract with bsdtar or mount
|
|
|
|
|
# On FreeBSD: mdconfig + mount -t cd9660
|
|
|
|
|
# On Linux: mount -o loop
|
|
|
|
|
|
|
|
|
|
if [ "$(uname)" = "FreeBSD" ]; then
|
|
|
|
|
MD=$(mdconfig -f "$MFSBSD_ISO")
|
|
|
|
|
mount -t cd9660 "/dev/${MD}" "${ISO_WORK}/mnt"
|
|
|
|
|
cp -a "${ISO_WORK}/mnt/"* "${ISO_WORK}/"
|
|
|
|
|
umount "${ISO_WORK}/mnt"
|
|
|
|
|
mdconfig -d -u "$MD"
|
|
|
|
|
else
|
|
|
|
|
# Linux: use bsdtar to extract ISO
|
|
|
|
|
tar -xf "$MFSBSD_ISO" -C "${ISO_WORK}"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo " Extracted to ${ISO_WORK}"
|
|
|
|
|
|
|
|
|
|
# --- step 5: inject Clawdie payload ---
|
|
|
|
|
echo "==> [5/6] Injecting Clawdie payload..."
|
|
|
|
|
|
|
|
|
|
# Create clawdie-iso directory structure
|
|
|
|
|
CLAWDIE_SHARE="${ISO_WORK}/usr/local/share/clawdie-iso"
|
|
|
|
|
mkdir -p "$CLAWDIE_SHARE"
|
|
|
|
|
|
|
|
|
|
# Copy firstboot scripts (both USB and VPS versions)
|
|
|
|
|
cp -r "${SCRIPT_DIR}/firstboot" "${CLAWDIE_SHARE}/"
|
|
|
|
|
cp "${SCRIPT_DIR}/build.cfg" "${CLAWDIE_SHARE}/"
|
|
|
|
|
|
|
|
|
|
# Copy VPS-specific files
|
|
|
|
|
if [ -d "${SCRIPT_DIR}/vps" ]; then
|
|
|
|
|
cp "${SCRIPT_DIR}/vps/firstboot-vps.sh" "${CLAWDIE_SHARE}/firstboot-vps.sh"
|
|
|
|
|
chmod +x "${CLAWDIE_SHARE}/firstboot-vps.sh"
|
2026-04-27 11:56:49 +02:00
|
|
|
[ -f "${SCRIPT_DIR}/vps/setup.txt.tpl" ] && \
|
|
|
|
|
cp "${SCRIPT_DIR}/vps/setup.txt.tpl" "${CLAWDIE_SHARE}/setup.txt.tpl"
|
Align VPS firstboot with modular pipeline (Sam & Claude)
Rewrite vps/firstboot-vps.sh as phase-1 only: partition disk,
create ZFS pool "clawdie", install FreeBSD base, inject firstboot
payload, install bootloader, reboot. On first HDD boot the standard
firstboot.sh modular pipeline runs (zfs detect, wizard, gpu, pkg,
ssh, env, system, tailscale, deploy).
Pre-baked clawdie.conf values get written to build.cfg with
TARGET=cloud so the wizard is skipped. Pool named "clawdie"
(not zroot) for pool detection compatibility.
Remove duplicate clawdie-vps-setup.sh.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 11:31:59 +00:00
|
|
|
[ -f "${SCRIPT_DIR}/vps/clawdie.conf.tpl" ] && \
|
|
|
|
|
cp "${SCRIPT_DIR}/vps/clawdie.conf.tpl" "${CLAWDIE_SHARE}/clawdie.conf.tpl"
|
2026-04-05 09:04:45 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Copy Clawdie-AI tarball
|
|
|
|
|
cp "$CLAWDIE_TARBALL" "${CLAWDIE_SHARE}/clawdie-ai.tar.gz"
|
|
|
|
|
|
|
|
|
|
# Copy packages if available
|
2026-04-05 14:19:32 +00:00
|
|
|
if [ "$PKG_BUNDLE" -eq 1 ] && [ -d "$PKG_REPO_DIR/All" ]; then
|
|
|
|
|
cp -r "$PKG_REPO_DIR" "${CLAWDIE_SHARE}/"
|
2026-04-05 09:04:45 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Create rc.local to auto-start SSH and show instructions
|
|
|
|
|
cat > "${ISO_WORK}/etc/rc.local" <<'EOF'
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
# Clawdie-VPS rc.local - runs on mfsBSD boot
|
|
|
|
|
|
|
|
|
|
# Ensure SSH is running
|
|
|
|
|
service sshd onestart 2>/dev/null || /etc/rc.d/sshd onestart 2>/dev/null || true
|
|
|
|
|
|
|
|
|
|
# Show welcome message on console
|
|
|
|
|
cat > /etc/motd <<'MOTD'
|
|
|
|
|
|
|
|
|
|
╔═══════════════════════════════════════════════════════════════╗
|
|
|
|
|
║ Clawdie-VPS (mfsBSD) ║
|
|
|
|
|
╠═══════════════════════════════════════════════════════════════╣
|
|
|
|
|
║ ║
|
|
|
|
|
║ SSH: ssh -p 1022 mfsbsd@<this-ip> ║
|
|
|
|
|
║ Pass: clawdie2026 ║
|
|
|
|
|
║ ║
|
|
|
|
|
║ Then run the installer: ║
|
|
|
|
|
║ /usr/local/share/clawdie-iso/firstboot-vps.sh ║
|
|
|
|
|
║ ║
|
2026-04-27 11:56:49 +02:00
|
|
|
║ For headless install, copy setup.txt.tpl to setup.txt ║
|
2026-04-05 09:04:45 +00:00
|
|
|
║ and edit before running firstboot-vps.sh ║
|
|
|
|
|
║ ║
|
|
|
|
|
║ This will install FreeBSD + Clawdie-AI to disk. ║
|
|
|
|
|
║ ALL DATA ON DISK WILL BE ERASED. ║
|
|
|
|
|
║ ║
|
|
|
|
|
╚═══════════════════════════════════════════════════════════════╝
|
|
|
|
|
|
|
|
|
|
MOTD
|
|
|
|
|
|
|
|
|
|
# Also log to console
|
|
|
|
|
echo ""
|
|
|
|
|
echo "Clawdie-VPS ready. SSH to port 1022, password: clawdie2026"
|
|
|
|
|
echo "Run: /usr/local/share/clawdie-iso/firstboot-vps.sh"
|
|
|
|
|
echo ""
|
|
|
|
|
EOF
|
|
|
|
|
chmod +x "${ISO_WORK}/etc/rc.local"
|
|
|
|
|
|
|
|
|
|
# Set root password in mfsBSD
|
|
|
|
|
# mfsBSD uses /etc/master.passwd - we need to hash the password
|
|
|
|
|
if [ "$(uname)" = "FreeBSD" ]; then
|
|
|
|
|
HASH=$(encrypt -p "$MFSBSD_PASSWORD" | tail -1)
|
|
|
|
|
else
|
|
|
|
|
# Linux: use openssl
|
|
|
|
|
HASH=$(openssl passwd -6 "$MFSBSD_PASSWORD")
|
|
|
|
|
fi
|
|
|
|
|
|
2026-04-05 14:46:54 +00:00
|
|
|
# Portable sed -i: FreeBSD requires '' as separate arg, GNU does not
|
|
|
|
|
if [ "$(uname)" = "FreeBSD" ]; then
|
|
|
|
|
_sed_i() { sed -i '' "$@"; }
|
|
|
|
|
else
|
|
|
|
|
_sed_i() { sed -i "$@"; }
|
|
|
|
|
fi
|
|
|
|
|
|
2026-04-05 09:04:45 +00:00
|
|
|
# Update password in mfsBSD's password file
|
|
|
|
|
if [ -f "${ISO_WORK}/etc/master.passwd" ]; then
|
2026-04-05 14:46:54 +00:00
|
|
|
_sed_i "s|^root:[^:]*:|root:${HASH}:|" "${ISO_WORK}/etc/master.passwd"
|
2026-04-05 09:04:45 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Configure SSH to listen on port 1022
|
|
|
|
|
if [ -f "${ISO_WORK}/etc/ssh/sshd_config" ]; then
|
2026-04-05 14:46:54 +00:00
|
|
|
_sed_i 's/^#*Port .*/Port 1022/' "${ISO_WORK}/etc/ssh/sshd_config"
|
2026-04-05 09:04:45 +00:00
|
|
|
grep -q "^Port " "${ISO_WORK}/etc/ssh/sshd_config" || echo "Port 1022" >> "${ISO_WORK}/etc/ssh/sshd_config"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Enable SSH in rc.conf
|
|
|
|
|
echo 'sshd_enable="YES"' >> "${ISO_WORK}/etc/rc.conf"
|
|
|
|
|
|
|
|
|
|
echo " Payload injected."
|
|
|
|
|
|
|
|
|
|
# --- step 6: repack ISO ---
|
|
|
|
|
echo "==> [6/6] Repacking ISO..."
|
|
|
|
|
|
|
|
|
|
mkdir -p "$OUTPUT_DIR"
|
2026-04-05 14:19:32 +00:00
|
|
|
DATE_STAMP="$(LC_TIME=C date +%d.%b.%Y | tr 'A-Z' 'a-z')"
|
|
|
|
|
OUTPUT_ISO="${OUTPUT_DIR}/clawdie-vps-${DATE_STAMP}.iso"
|
2026-04-05 09:04:45 +00:00
|
|
|
|
|
|
|
|
# Use genisoimage (Linux) or mkisofs (FreeBSD)
|
|
|
|
|
if command -v genisoimage >/dev/null 2>&1; then
|
|
|
|
|
genisoimage -o "$OUTPUT_ISO" -b boot/cdboot -no-emul-boot \
|
|
|
|
|
-J -R -V "CLAWDIE_VPS" "$ISO_WORK"
|
|
|
|
|
elif command -v mkisofs >/dev/null 2>&1; then
|
|
|
|
|
mkisofs -o "$OUTPUT_ISO" -b boot/cdboot -no-emul-boot \
|
|
|
|
|
-J -R -V "CLAWDIE_VPS" "$ISO_WORK"
|
|
|
|
|
else
|
|
|
|
|
echo "ERROR: Neither genisoimage nor mkisofs found."
|
|
|
|
|
echo "Install: apt install genisoimage OR pkg install cdrtools"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Cleanup
|
|
|
|
|
rm -rf "$ISO_WORK"
|
|
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
echo "============================================"
|
|
|
|
|
echo " Build complete!"
|
|
|
|
|
echo ""
|
|
|
|
|
echo " Output: ${OUTPUT_ISO}"
|
|
|
|
|
echo " Size: $(du -sh "$OUTPUT_ISO" | cut -f1)"
|
|
|
|
|
echo ""
|
|
|
|
|
echo " Upload to Vultr:"
|
|
|
|
|
echo " 1. Go to Server → Settings → Custom ISO"
|
|
|
|
|
echo " 2. Upload ${OUTPUT_ISO}"
|
|
|
|
|
echo " 3. Reboot server"
|
|
|
|
|
echo ""
|
|
|
|
|
echo " After boot:"
|
|
|
|
|
echo " ssh -p 1022 mfsbsd@<your-vps-ip>"
|
|
|
|
|
echo " Password: ${MFSBSD_PASSWORD}"
|
|
|
|
|
echo ""
|
|
|
|
|
echo " Then run:"
|
|
|
|
|
echo " /usr/local/share/clawdie-iso/firstboot-vps.sh"
|
|
|
|
|
echo ""
|
|
|
|
|
echo " For headless install:"
|
2026-04-27 11:56:49 +02:00
|
|
|
echo " cp /usr/local/share/clawdie-iso/setup.txt.tpl \\"
|
|
|
|
|
echo " /usr/local/share/clawdie-iso/setup.txt"
|
|
|
|
|
echo " # Edit setup.txt, then:"
|
2026-04-05 09:04:45 +00:00
|
|
|
echo " /usr/local/share/clawdie-iso/firstboot-vps.sh"
|
|
|
|
|
echo "============================================"
|