USB
This commit is contained in:
Executable
+211
@@ -0,0 +1,211 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# create.sh — Build a bootable Alpine Linux rescue ISO
|
||||
#
|
||||
# Run inside the Docker build container:
|
||||
# docker compose run --rm alpine bash /scripts/create.sh
|
||||
#
|
||||
# The resulting ISO is a hybrid image: it can be burned to a CD/DVD or
|
||||
# written directly to a USB stick with dd.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
ALPINE_MIRROR="https://dl-cdn.alpinelinux.org/alpine"
|
||||
ALPINE_BRANCH="latest-stable"
|
||||
ALPINE_ARCH="x86_64"
|
||||
MINIROOTFS_BASE="${ALPINE_MIRROR}/${ALPINE_BRANCH}/releases/${ALPINE_ARCH}"
|
||||
|
||||
ISO="/output/rescue-alpine.iso"
|
||||
CHROOT="/mnt/alpine-chroot"
|
||||
ISOROOT="/tmp/isoroot"
|
||||
|
||||
mkdir -p /output "$CHROOT" "$ISOROOT"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. Fetch latest Alpine minirootfs
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "==> Fetching latest Alpine minirootfs index"
|
||||
TARBALL=$(curl -fsSL "${MINIROOTFS_BASE}/" \
|
||||
| grep -oP 'alpine-minirootfs-[0-9.]+-x86_64\.tar\.gz' \
|
||||
| sort -V | tail -1)
|
||||
|
||||
[[ -z "$TARBALL" ]] && { echo "ERROR: could not determine minirootfs tarball" >&2; exit 1; }
|
||||
|
||||
TARBALL_LOCAL="/tmp/${TARBALL}"
|
||||
if [[ ! -f "$TARBALL_LOCAL" ]]; then
|
||||
echo "==> Downloading ${MINIROOTFS_BASE}/${TARBALL}"
|
||||
curl -fsSL -o "$TARBALL_LOCAL" "${MINIROOTFS_BASE}/${TARBALL}"
|
||||
else
|
||||
echo "==> Using cached ${TARBALL_LOCAL}"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Extract minirootfs into chroot
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "==> Extracting minirootfs into ${CHROOT}"
|
||||
tar -xzf "$TARBALL_LOCAL" -C "$CHROOT"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. Copy Nebula binary and config into chroot
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "==> Installing Nebula binary"
|
||||
mkdir -p "${CHROOT}/usr/local/bin"
|
||||
cp /nebula/nebula "${CHROOT}/usr/local/bin/nebula"
|
||||
chmod +x "${CHROOT}/usr/local/bin/nebula"
|
||||
|
||||
echo "==> Installing Nebula config and certificates"
|
||||
mkdir -p "${CHROOT}/etc/nebula"
|
||||
cp /nebula/config.yml "${CHROOT}/etc/nebula/config.yml"
|
||||
for f in /nebula/*.crt /nebula/*.key; do
|
||||
[[ -f "$f" ]] && cp "$f" "${CHROOT}/etc/nebula/"
|
||||
done
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4. Bind-mount virtual filesystems for chroot
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "==> Bind-mounting virtual filesystems"
|
||||
mount --bind /dev "${CHROOT}/dev"
|
||||
mount --bind /proc "${CHROOT}/proc"
|
||||
mount --bind /sys "${CHROOT}/sys"
|
||||
mkdir -p "${CHROOT}/run"
|
||||
mount --bind /run "${CHROOT}/run"
|
||||
cp /etc/resolv.conf "${CHROOT}/etc/resolv.conf"
|
||||
|
||||
# Make scripts available inside chroot
|
||||
mkdir -p "${CHROOT}/scripts"
|
||||
mount --bind /scripts "${CHROOT}/scripts"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5. Run in-chroot configuration
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "==> Running chroot-setup.sh inside chroot"
|
||||
chroot "$CHROOT" /bin/sh /scripts/chroot-setup.sh
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 6. Unmount virtual filesystems
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "==> Unmounting virtual filesystems"
|
||||
umount "${CHROOT}/scripts" || true
|
||||
umount "${CHROOT}/run" || true
|
||||
umount "${CHROOT}/sys" || true
|
||||
umount "${CHROOT}/proc" || true
|
||||
umount "${CHROOT}/dev" || true
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 7. Pack the full system as a squashfs (xz compressed)
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "==> Creating squashfs from chroot (xz — this may take a while)"
|
||||
mksquashfs "$CHROOT" "${ISOROOT}/rootfs.squashfs" \
|
||||
-comp xz -Xdict-size 100% -noappend \
|
||||
-e boot/initramfs-lts 2>/dev/null || \
|
||||
mksquashfs "$CHROOT" "${ISOROOT}/rootfs.squashfs" \
|
||||
-comp xz -noappend
|
||||
echo " squashfs size: $(du -sh "${ISOROOT}/rootfs.squashfs" | cut -f1)"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 8. Copy kernel into ISO root
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "==> Copying kernel"
|
||||
cp "${CHROOT}/boot/vmlinuz-lts" "${ISOROOT}/vmlinuz"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 9. Build tiny initramfs: busybox + init script that mounts the squashfs
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "==> Building tiny initramfs"
|
||||
INITRD="/tmp/initrd"
|
||||
rm -rf "$INITRD"
|
||||
mkdir -p "${INITRD}"/{bin,dev,proc,sys,mnt/boot,mnt/squash,mnt/upper,mnt/work,mnt/newroot}
|
||||
|
||||
# Static busybox — no external library deps
|
||||
BBOX=$(find /bin /usr/bin /usr/sbin -name 'busybox.static' -o -name 'busybox' 2>/dev/null \
|
||||
| xargs -r file 2>/dev/null | grep -i 'statically linked' | cut -d: -f1 | head -1)
|
||||
[[ -z "$BBOX" ]] && { echo "ERROR: cannot find a statically linked busybox" >&2; exit 1; }
|
||||
echo " using static busybox: $BBOX"
|
||||
cp "$BBOX" "${INITRD}/bin/busybox"
|
||||
chmod +x "${INITRD}/bin/busybox"
|
||||
for cmd in sh mount umount mkdir mknod switch_root mdev sleep; do
|
||||
ln -sf busybox "${INITRD}/bin/${cmd}"
|
||||
done
|
||||
|
||||
cat > "${INITRD}/init" <<'INIT_EOF'
|
||||
#!/bin/sh
|
||||
mount -t proc none /proc
|
||||
mount -t sysfs none /sys
|
||||
mount -t devtmpfs none /dev 2>/dev/null || mdev -s
|
||||
|
||||
# Scan block devices for the ISO containing rootfs.squashfs
|
||||
found=0
|
||||
for try in 1 2 3 4 5; do
|
||||
for dev in /dev/sr0 /dev/sda /dev/sda1 /dev/sdb /dev/sdb1 /dev/sdc /dev/sdc1; do
|
||||
[ -b "$dev" ] || continue
|
||||
mount -t iso9660 -o ro "$dev" /mnt/boot 2>/dev/null || \
|
||||
mount -o ro "$dev" /mnt/boot 2>/dev/null || continue
|
||||
if [ -f /mnt/boot/rootfs.squashfs ]; then
|
||||
found=1
|
||||
break 2
|
||||
fi
|
||||
umount /mnt/boot 2>/dev/null
|
||||
done
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if [ "$found" != "1" ]; then
|
||||
echo "ERROR: rootfs.squashfs not found — dropping to shell"
|
||||
exec sh
|
||||
fi
|
||||
|
||||
mount -t squashfs -o ro /mnt/boot/rootfs.squashfs /mnt/squash
|
||||
|
||||
mount -t tmpfs tmpfs /mnt/upper
|
||||
mkdir -p /mnt/upper/rw /mnt/upper/work
|
||||
mount -t overlay overlay \
|
||||
-o lowerdir=/mnt/squash,upperdir=/mnt/upper/rw,workdir=/mnt/upper/work \
|
||||
/mnt/newroot
|
||||
|
||||
exec switch_root /mnt/newroot /sbin/init
|
||||
INIT_EOF
|
||||
chmod +x "${INITRD}/init"
|
||||
|
||||
( cd "$INITRD" && find . | cpio --quiet -oH newc | gzip -9 ) > "${ISOROOT}/initramfs.gz"
|
||||
echo " initramfs size: $(du -sh "${ISOROOT}/initramfs.gz" | cut -f1)"
|
||||
echo " initramfs contents:"
|
||||
zcat "${ISOROOT}/initramfs.gz" | cpio -t 2>/dev/null
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 10. Build ISO with grub-mkrescue (BIOS + UEFI hybrid)
|
||||
# grub-mkrescue uses its own file loader — no BIOS INT 13h size limits.
|
||||
# ---------------------------------------------------------------------------
|
||||
echo "==> Writing GRUB config"
|
||||
mkdir -p "${ISOROOT}/boot/grub"
|
||||
cat > "${ISOROOT}/boot/grub/grub.cfg" <<'EOF'
|
||||
set timeout=5
|
||||
set default=0
|
||||
|
||||
menuentry "Alpine Linux USB Rescue" {
|
||||
linux /vmlinuz quiet init=/sbin/init
|
||||
initrd /initramfs.gz
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "==> Building hybrid ISO with grub-mkrescue: ${ISO}"
|
||||
grub-mkrescue -o "$ISO" "$ISOROOT" -- -V ALPINE_RESCUE
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Done
|
||||
# ---------------------------------------------------------------------------
|
||||
ISO_SIZE=$(du -sh "$ISO" | cut -f1)
|
||||
echo ""
|
||||
echo "================================================================"
|
||||
echo " Build complete!"
|
||||
echo " ISO : ${ISO} (${ISO_SIZE})"
|
||||
echo ""
|
||||
echo " Burn to USB:"
|
||||
echo " dd if=${ISO} of=/dev/sdX bs=4M status=progress && sync"
|
||||
echo ""
|
||||
echo " Burn to CD/DVD:"
|
||||
echo " cdrecord dev=/dev/sr0 ${ISO}"
|
||||
echo ""
|
||||
echo " Default login : root / alpine"
|
||||
echo " Nebula tunnel : auto-starts on boot (needs certs in nebula/)"
|
||||
echo "================================================================"
|
||||
Reference in New Issue
Block a user