This commit is contained in:
oliver
2026-05-27 16:28:42 -03:00
parent eb4d83e9e9
commit ce01dd64f7
9 changed files with 609 additions and 0 deletions
+135
View File
@@ -0,0 +1,135 @@
#!/bin/sh
set -eu
# ---------------------------------------------------------------------------
# chroot-setup.sh — Runs inside the Alpine chroot to configure the system
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
# 1. APK repositories
# ---------------------------------------------------------------------------
echo "==> Configuring APK repositories"
cat > /etc/apk/repositories <<'EOF'
https://dl-cdn.alpinelinux.org/alpine/latest-stable/main
https://dl-cdn.alpinelinux.org/alpine/latest-stable/community
EOF
apk update
# ---------------------------------------------------------------------------
# 2. Install packages
# ---------------------------------------------------------------------------
echo "==> Installing packages"
apk add --no-cache \
linux-lts \
mkinitfs \
openrc \
busybox \
musl \
libc-utils \
util-linux \
e2fsprogs \
dosfstools \
btrfs-progs \
parted \
sfdisk \
openssh \
dhcpcd \
iproute2 \
iputils \
net-tools \
curl \
wget \
ca-certificates \
vim \
mc \
bind-tools \
nmap \
rsync \
alpine-conf
# ---------------------------------------------------------------------------
# 3. Generate initramfs
# ---------------------------------------------------------------------------
echo "==> Generating initramfs with mkinitfs"
mkinitfs $(ls /lib/modules/ | tail -1)
# ---------------------------------------------------------------------------
# 4. Network configuration
# ---------------------------------------------------------------------------
echo "==> Configuring network interfaces"
mkdir -p /etc/network
cat > /etc/network/interfaces <<'EOF'
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
EOF
# ---------------------------------------------------------------------------
# 5. SSH configuration
# ---------------------------------------------------------------------------
echo "==> Configuring sshd"
sed -i \
-e 's/^#*\s*PermitRootLogin.*/PermitRootLogin yes/' \
-e 's/^#*\s*PasswordAuthentication.*/PasswordAuthentication yes/' \
/etc/ssh/sshd_config
# Ensure the directives exist if sed found nothing to replace
grep -q '^PermitRootLogin' /etc/ssh/sshd_config || echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config
grep -q '^PasswordAuthentication' /etc/ssh/sshd_config || echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config
echo "==> Generating SSH host keys"
ssh-keygen -A
# ---------------------------------------------------------------------------
# 6. Root password
# ---------------------------------------------------------------------------
echo "==> Setting root password"
echo "root:alpine" | chpasswd
# ---------------------------------------------------------------------------
# 7. Nebula OpenRC service
# ---------------------------------------------------------------------------
echo "==> Creating /etc/init.d/nebula"
cat > /etc/init.d/nebula <<'EOF'
#!/sbin/openrc-run
description="Nebula overlay network"
command="/usr/local/bin/nebula"
command_args="-config /etc/nebula/config.yml"
command_background=true
pidfile="/run/nebula.pid"
depend() {
need net
after networking
}
start_pre() {
checkpath -f -m 0600 -o root:root /run/nebula.pid
}
EOF
chmod +x /etc/init.d/nebula
# ---------------------------------------------------------------------------
# 8. OpenRC service enablement
# ---------------------------------------------------------------------------
echo "==> Enabling services"
rc-update add sshd default
rc-update add networking default
rc-update add nebula default
# Also ensure basic boot services are present
rc-update add devfs sysinit || true
rc-update add dmesg sysinit || true
rc-update add mdev sysinit || true
rc-update add hwdrivers sysinit || true
# ---------------------------------------------------------------------------
# 9. Hostname
# ---------------------------------------------------------------------------
echo "==> Setting hostname to 'rescue'"
echo "rescue" > /etc/hostname
echo "==> chroot-setup.sh complete"
+211
View File
@@ -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 "================================================================"