mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Adding WROLPi Portable build — bootable amd64 Live USB.
New debian-live-usb/ directory produces a live ISO that boots into a full WROLPi desktop on any x86 PC without installing to the host disk. Distinct from debian-live-config/ (installer ISO). Phase 1: live boot only; Phase 2 will add persistence partition for the Postgres DB and media directory. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2806673e25
commit
ed30ed832c
5 changed files with 366 additions and 0 deletions
127
debian-live-usb/build.sh
Executable file
127
debian-live-usb/build.sh
Executable file
|
|
@ -0,0 +1,127 @@
|
|||
#!/bin/bash
|
||||
# Build WROLPi Portable — a bootable amd64 Live USB image.
|
||||
#
|
||||
# Output: an iso-hybrid image written to this directory. Users flash it to a
|
||||
# USB drive (Etcher / Rufus / dd / Raspberry Pi Imager) and boot it on any
|
||||
# x86 PC. Unlike ../debian-live-config/, this build is NOT an installer — it
|
||||
# runs the full WROLPi stack live from the USB. Phase 2 will add a persistence
|
||||
# partition so the Postgres DB and media directory survive reboots.
|
||||
#
|
||||
# https://live-team.pages.debian.net/live-manual/html/live-manual/index.en.html
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
BUILD_DIR=/var/tmp/wrolpi-build-portable
|
||||
|
||||
Help() {
|
||||
echo "Build WROLPi Portable Live USB image."
|
||||
echo
|
||||
echo "Syntax: build.sh [-h] [-b BRANCH]"
|
||||
echo "options:"
|
||||
echo "h Print this help."
|
||||
echo "b Build from this git BRANCH (default: 'release')."
|
||||
echo
|
||||
}
|
||||
|
||||
BRANCH="release"
|
||||
while getopts ":hb:" option; do
|
||||
case $option in
|
||||
h) Help; exit ;;
|
||||
b) BRANCH="${OPTARG}" ;;
|
||||
*) echo "Error: Invalid option"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Get version from the target git branch (not local checkout) so output filename matches actual content.
|
||||
VERSION=$(curl -sL "https://raw.githubusercontent.com/lrnselfreliance/wrolpi/${BRANCH}/wrolpi/version.txt")
|
||||
if [ -z "${VERSION}" ]; then
|
||||
echo "ERROR: Could not fetch version from branch '${BRANCH}'"
|
||||
exit 1
|
||||
fi
|
||||
echo "Building WROLPi Portable version: ${VERSION} from branch: ${BRANCH}"
|
||||
|
||||
# Re-execute this script if it wasn't called with sudo.
|
||||
if [ $EUID != 0 ]; then
|
||||
sudo "$0" "$@"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# Clear out old builds.
|
||||
[ -d "${BUILD_DIR}" ] && rm -rf "${BUILD_DIR}"
|
||||
mkdir "${BUILD_DIR}"
|
||||
cd "${BUILD_DIR}" || (echo "Work directory must exist" && exit 1)
|
||||
set -e
|
||||
|
||||
# Pure live config — no --debian-installer flags. The resulting image boots
|
||||
# directly into a running WROLPi system, never offering to install to disk.
|
||||
# noswap prevents the live system from activating swap partitions found on
|
||||
# the host machine's internal disks (ethereal hygiene).
|
||||
lb config \
|
||||
--binary-images iso-hybrid \
|
||||
--mode debian \
|
||||
--architectures amd64 \
|
||||
--linux-flavours amd64 \
|
||||
--distribution bookworm \
|
||||
--archive-areas "main contrib non-free non-free-firmware" \
|
||||
--updates true \
|
||||
--security true \
|
||||
--apt-recommends false \
|
||||
--firmware-binary true \
|
||||
--firmware-chroot true \
|
||||
--win32-loader false \
|
||||
--checksums sha512 \
|
||||
--clean \
|
||||
--color \
|
||||
--linux-packages "linux-image linux-headers" \
|
||||
--bootappend-live "boot=live components quiet splash noswap" \
|
||||
--iso-volume "WROLPi Portable v${VERSION}" \
|
||||
--iso-application "WROLPi Portable v${VERSION}" \
|
||||
--iso-preparer WROLPi \
|
||||
--iso-publisher https://wrolpi.org
|
||||
|
||||
rsync -a "${SCRIPT_DIR}/config" "${BUILD_DIR}/"
|
||||
|
||||
# Write branch config for hook script.
|
||||
mkdir -p "${BUILD_DIR}/config/includes.chroot/opt/wrolpi-blobs"
|
||||
echo "${BRANCH}" > "${BUILD_DIR}/config/includes.chroot/opt/wrolpi-branch"
|
||||
|
||||
# Cache directory for downloaded blobs (persists across builds).
|
||||
BLOB_CACHE="${SCRIPT_DIR}/files"
|
||||
mkdir -p "${BLOB_CACHE}"
|
||||
|
||||
# Download map fonts (skip if cached).
|
||||
if [ ! -f "${BLOB_CACHE}/map-fonts.tar.gz" ]; then
|
||||
echo "Downloading map fonts..."
|
||||
mkdir -p /tmp/map-fonts-dl
|
||||
curl -fsSL https://github.com/protomaps/basemaps-assets/archive/refs/heads/main.tar.gz \
|
||||
| tar -xz --strip-components=1 -C /tmp/map-fonts-dl basemaps-assets-main/fonts
|
||||
tar -czf "${BLOB_CACHE}/map-fonts.tar.gz" -C /tmp/map-fonts-dl fonts
|
||||
rm -rf /tmp/map-fonts-dl
|
||||
fi
|
||||
[[ -f "${BLOB_CACHE}/map-fonts.tar.gz" && -s "${BLOB_CACHE}/map-fonts.tar.gz" ]] || \
|
||||
(echo "ERROR: Failed to download map fonts!" && exit 1)
|
||||
|
||||
# Download map overview (skip if cached).
|
||||
if [ ! -f "${BLOB_CACHE}/map-overview.pmtiles" ]; then
|
||||
echo "Downloading map overview..."
|
||||
curl -fsSL https://wrolpi.nyc3.cdn.digitaloceanspaces.com/maps/map-overview.pmtiles \
|
||||
-o "${BLOB_CACHE}/map-overview.pmtiles"
|
||||
fi
|
||||
[[ -f "${BLOB_CACHE}/map-overview.pmtiles" && -s "${BLOB_CACHE}/map-overview.pmtiles" ]] || \
|
||||
(echo "ERROR: Failed to download map overview!" && exit 1)
|
||||
|
||||
# Copy cached blobs into the live image.
|
||||
cp "${BLOB_CACHE}/map-fonts.tar.gz" "${BUILD_DIR}/config/includes.chroot/opt/wrolpi-blobs/"
|
||||
cp "${BLOB_CACHE}/map-overview.pmtiles" "${BUILD_DIR}/config/includes.chroot/opt/wrolpi-blobs/"
|
||||
|
||||
time nice -n 18 lb build 2>&1 | tee "${SCRIPT_DIR}/build.log"
|
||||
|
||||
grep "9999-wrolpi.hook.chroot completed" "${SCRIPT_DIR}/build.log" >/dev/null 2>&1 || (echo "build hook failed!" && exit 1)
|
||||
|
||||
cp "${BUILD_DIR}"/*iso "${SCRIPT_DIR}/" || (echo "Build failed. No ISOs were found!" && exit 1)
|
||||
chmod 644 "${SCRIPT_DIR}"/*iso
|
||||
chown 1000:1000 "${SCRIPT_DIR}"/*iso
|
||||
DEST="${SCRIPT_DIR}/WROLPi-Portable-v${VERSION}-amd64.iso"
|
||||
[ -f "${DEST}" ] && (echo "Removing conflicting ISO" && rm "${DEST}")
|
||||
mv "${SCRIPT_DIR}"/*.iso "${DEST}"
|
||||
|
||||
echo "Build has completed. ISO output ${DEST}"
|
||||
153
debian-live-usb/config/hooks/normal/9999-wrolpi.hook.chroot
Executable file
153
debian-live-usb/config/hooks/normal/9999-wrolpi.hook.chroot
Executable file
|
|
@ -0,0 +1,153 @@
|
|||
#!/usr/bin/bash
|
||||
# Chroot hook for WROLPi Portable — composes the full WROLPi stack into the
|
||||
# live system during live-build's chroot phase. Closely mirrors the installer
|
||||
# ISO hook in ../../../debian-live-config/config/hooks/normal/, with two
|
||||
# Portable-specific additions: bake in pmtiles/tippecanoe (offline-first
|
||||
# first-boot) and drop the default Postgres cluster (Phase 2 firstboot will
|
||||
# recreate it on the persistence partition).
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
# Generate and set default locale to avoid perl warnings.
|
||||
# Users can change this later via: sudo dpkg-reconfigure locales
|
||||
sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen
|
||||
locale-gen
|
||||
echo 'LANG=en_US.UTF-8' > /etc/default/locale
|
||||
export LANG=en_US.UTF-8
|
||||
|
||||
cat >>/etc/profile <<'EOF'
|
||||
alias ll='ls -lh'
|
||||
alias la='ll -a'
|
||||
EOF
|
||||
|
||||
git --version
|
||||
|
||||
WROLPI_BRANCH="release"
|
||||
[ -f /opt/wrolpi-branch ] && WROLPI_BRANCH=$(cat /opt/wrolpi-branch)
|
||||
git clone -b "${WROLPI_BRANCH}" https://github.com/lrnselfreliance/wrolpi.git /opt/wrolpi
|
||||
rm -f /opt/wrolpi-branch
|
||||
|
||||
# Install webapp.
|
||||
cd /opt/wrolpi/app
|
||||
npm --version
|
||||
node --version
|
||||
npm install
|
||||
|
||||
# Install Node console commands.
|
||||
npm i -g serve@12.0.1 single-file-cli@2.0.73 readability-extractor@0.0.6
|
||||
|
||||
# Install Deno runtime.
|
||||
DENO_VERSION="v2.2.4"
|
||||
curl -fsSL "https://github.com/denoland/deno/releases/download/${DENO_VERSION}/deno-x86_64-unknown-linux-gnu.zip" -o /tmp/deno.zip
|
||||
unzip /tmp/deno.zip -d /usr/local/bin/
|
||||
chmod +x /usr/local/bin/deno
|
||||
rm /tmp/deno.zip
|
||||
deno --version
|
||||
|
||||
# Install Python requirements. Try multiple times because pypi may stop responding.
|
||||
python3 --version
|
||||
python3 -m venv /opt/wrolpi/venv
|
||||
/opt/wrolpi/venv/bin/pip3 install -r /opt/wrolpi/requirements.txt ||
|
||||
/opt/wrolpi/venv/bin/pip3 install -r /opt/wrolpi/requirements.txt ||
|
||||
/opt/wrolpi/venv/bin/pip3 install -r /opt/wrolpi/requirements.txt
|
||||
|
||||
# Install Controller with separate venv.
|
||||
echo "Pre-installing WROLPi Controller..."
|
||||
python3 -m venv /opt/wrolpi/controller/venv
|
||||
/opt/wrolpi/controller/venv/bin/pip install --upgrade pip
|
||||
/opt/wrolpi/controller/venv/bin/pip install -r /opt/wrolpi/controller/requirements.txt ||
|
||||
/opt/wrolpi/controller/venv/bin/pip install -r /opt/wrolpi/controller/requirements.txt ||
|
||||
/opt/wrolpi/controller/venv/bin/pip install -r /opt/wrolpi/controller/requirements.txt
|
||||
echo "Controller pre-installed"
|
||||
|
||||
# Install Caddy from official apt repo.
|
||||
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
|
||||
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
|
||||
apt-get update
|
||||
apt-get install -y caddy
|
||||
|
||||
# Configure Caddy.
|
||||
mkdir -p /etc/caddy
|
||||
cp /opt/wrolpi/etc/raspberrypios/Caddyfile /etc/caddy/Caddyfile
|
||||
mkdir -p /var/www
|
||||
cp /opt/wrolpi/etc/raspberrypios/50x.html /var/www/50x.html
|
||||
|
||||
# WROLPi needs a few privileged commands.
|
||||
cp /opt/wrolpi/etc/raspberrypios/90-wrolpi /etc/sudoers.d/90-wrolpi
|
||||
chmod 0440 /etc/sudoers.d/90-wrolpi
|
||||
# Verify this new file is valid.
|
||||
visudo -c -f /etc/sudoers.d/90-wrolpi
|
||||
|
||||
mkdir /media/wrolpi
|
||||
|
||||
# Verify blob files were copied in by includes.chroot (downloaded by build.sh).
|
||||
[[ -f /opt/wrolpi-blobs/map-fonts.tar.gz && -s /opt/wrolpi-blobs/map-fonts.tar.gz ]] || \
|
||||
(echo "ERROR: map-fonts.tar.gz missing from /opt/wrolpi-blobs!" && exit 1)
|
||||
[[ -f /opt/wrolpi-blobs/map-overview.pmtiles && -s /opt/wrolpi-blobs/map-overview.pmtiles ]] || \
|
||||
(echo "ERROR: map-overview.pmtiles missing from /opt/wrolpi-blobs!" && exit 1)
|
||||
|
||||
# Bake in pmtiles CLI so first boot does not need internet.
|
||||
# Mirrors scripts/install_protomaps.sh; duplicated here because that script's
|
||||
# migration logic relies on a running systemd, which is not present in chroot.
|
||||
PMTILES_VERSION="v1.30.1"
|
||||
curl -fsSL "https://github.com/protomaps/go-pmtiles/releases/download/${PMTILES_VERSION}/go-pmtiles_${PMTILES_VERSION#v}_Linux_amd64.tar.gz" \
|
||||
| tar -xz -C /usr/local/bin/ pmtiles
|
||||
chmod +x /usr/local/bin/pmtiles
|
||||
pmtiles version
|
||||
|
||||
# Build and bake in tippecanoe (used to build map search indexes).
|
||||
TIPPECANOE_VERSION="2.79.0"
|
||||
TIPPECANOE_BUILD_DIR=$(mktemp -d)
|
||||
curl -fsSL "https://github.com/felt/tippecanoe/archive/refs/tags/${TIPPECANOE_VERSION}.tar.gz" \
|
||||
| tar -xz -C "${TIPPECANOE_BUILD_DIR}" --strip-components=1
|
||||
(cd "${TIPPECANOE_BUILD_DIR}" && make -j"$(nproc)" && make install)
|
||||
rm -rf "${TIPPECANOE_BUILD_DIR}"
|
||||
tippecanoe --version
|
||||
|
||||
# Install WROLPi Help.
|
||||
/opt/wrolpi/scripts/install_help_service.sh
|
||||
|
||||
cp /opt/wrolpi/etc/raspberrypios/wrolpi-*.service /etc/systemd/system/
|
||||
cp /opt/wrolpi/etc/raspberrypios/wrolpi-*.timer /etc/systemd/system/
|
||||
cp /opt/wrolpi/etc/raspberrypios/wrolpi.target /etc/systemd/system/
|
||||
# Copy MOTD scripts, delete original.
|
||||
cp /opt/wrolpi/etc/raspberrypios/motd/20-wrolpi.motd /etc/update-motd.d/20-wrolpi
|
||||
cp /opt/wrolpi/etc/raspberrypios/motd/30-wrolpi-first.motd /etc/update-motd.d/30-wrolpi
|
||||
chmod +x /etc/update-motd.d/*
|
||||
truncate -s 0 /etc/motd
|
||||
|
||||
# NetworkManager for the hotspot.
|
||||
systemctl enable NetworkManager
|
||||
|
||||
# Enable iperf3 for speed testing.
|
||||
systemctl enable iperf3
|
||||
# Enable first startup script to generate certificates and start Caddy.
|
||||
systemctl enable wrolpi-first-startup.service
|
||||
# Enable Controller service to start on boot.
|
||||
systemctl enable wrolpi-controller.service
|
||||
# Enable weekly certificate renewal check.
|
||||
systemctl enable wrolpi-cert-renew.timer
|
||||
|
||||
# Drop the default Postgres cluster created by the postgresql-15 package.
|
||||
# On first boot, the persistence partition will be bind-mounted over
|
||||
# /var/lib/postgresql; with the default cluster baked into the squashfs, the
|
||||
# mount would mask it and Postgres would fail to start against an empty data
|
||||
# dir. Phase 2's firstboot service creates a fresh cluster directly on the
|
||||
# persistence partition.
|
||||
pg_dropcluster --stop 15 main
|
||||
|
||||
# Protect blob files from accidental modification or deletion.
|
||||
if [ -d /opt/wrolpi-blobs ] && ls /opt/wrolpi-blobs/* >/dev/null 2>&1; then
|
||||
chown -R root:root /opt/wrolpi-blobs
|
||||
chmod 444 /opt/wrolpi-blobs/*
|
||||
chattr +i /opt/wrolpi-blobs/*
|
||||
fi
|
||||
|
||||
set +x
|
||||
|
||||
echo
|
||||
echo "======================================================================"
|
||||
echo "9999-wrolpi.hook.chroot completed"
|
||||
echo "======================================================================"
|
||||
echo
|
||||
2
debian-live-usb/config/package-lists/desktop.list.chroot
Normal file
2
debian-live-usb/config/package-lists/desktop.list.chroot
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
task-xfce-desktop
|
||||
task-ssh-server
|
||||
82
debian-live-usb/config/package-lists/wrolpi.list.chroot
Normal file
82
debian-live-usb/config/package-lists/wrolpi.list.chroot
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
apt-transport-https
|
||||
aria2
|
||||
autoconf
|
||||
bind9-dnsutils
|
||||
build-essential
|
||||
bzip2
|
||||
ca-certificates
|
||||
calibre
|
||||
cargo
|
||||
catdoc
|
||||
chromium
|
||||
cpufrequtils
|
||||
curl
|
||||
ethtool
|
||||
exfat-fuse
|
||||
fdupes
|
||||
ffmpeg
|
||||
firefox-esr
|
||||
fonts-noto-cjk
|
||||
fonts-noto-hinted
|
||||
fonts-noto-unhinted
|
||||
gcc
|
||||
gcc-doc
|
||||
git
|
||||
git-doc
|
||||
gnupg-agent
|
||||
gpsd
|
||||
hostapd
|
||||
htop
|
||||
iotop
|
||||
iperf3
|
||||
kiwix
|
||||
kiwix-tools
|
||||
libboost-all-dev
|
||||
libbz2-dev
|
||||
libcairo2-dev
|
||||
libcurl4-gnutls-dev
|
||||
libffi-dev
|
||||
libfreetype6-dev
|
||||
libgeos++-dev
|
||||
libgeos-dev
|
||||
libicu-dev
|
||||
libpq-dev
|
||||
libproj-dev
|
||||
libreoffice
|
||||
libsqlite3-dev
|
||||
libssl-dev
|
||||
libtiff5-dev
|
||||
libtool
|
||||
libxml2-dev
|
||||
netcat-openbsd
|
||||
network-manager
|
||||
nicstat
|
||||
nodejs
|
||||
npm
|
||||
ntfs-3g
|
||||
pkg-config
|
||||
postgresql-15
|
||||
postgresql-doc
|
||||
pv
|
||||
python3-dev
|
||||
python3-doc
|
||||
python3-full
|
||||
python3-pip
|
||||
python3-venv
|
||||
rsync
|
||||
samba
|
||||
smartmontools
|
||||
software-properties-common
|
||||
sudo
|
||||
sysstat
|
||||
tar
|
||||
tcpdump
|
||||
tmux
|
||||
unrar-free
|
||||
unzip
|
||||
vim
|
||||
vlc
|
||||
wget
|
||||
wpasupplicant
|
||||
zim-tools
|
||||
zlib1g-dev
|
||||
2
debian-live-usb/files/.gitignore
vendored
Normal file
2
debian-live-usb/files/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*.pmtiles
|
||||
*.tar.gz
|
||||
Loading…
Add table
Add a link
Reference in a new issue