Enhance README and RPC for package management

- Added instructions to README.md for building an ISO from source and flashing it to USB.
- Introduced a new RPC method for package installation, including security checks and container management.
- Updated Docker and Podman integration in build scripts to support both container runtimes.
- Enhanced Nginx configuration for improved timeout settings and WebSocket support.
- Added new app metadata for additional applications in the Docker package scanner.
This commit is contained in:
Dorian
2026-02-01 18:46:35 +00:00
parent 22024bde84
commit 0f40cb88b5
59 changed files with 3473 additions and 360 deletions
@@ -0,0 +1,43 @@
#!/bin/bash
# Configure Nginx to listen on Tailscale IP address
# This script should be run after Tailscale is set up and connected
set -e
echo "🔍 Detecting Tailscale IP..."
# Get Tailscale IP from tailscale0 interface
TAILSCALE_IP=$(ip -4 addr show tailscale0 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' || echo "")
if [ -z "$TAILSCALE_IP" ]; then
echo "❌ Tailscale interface not found. Is Tailscale running with host networking?"
exit 1
fi
echo "✅ Found Tailscale IP: $TAILSCALE_IP"
NGINX_CONFIG="/etc/nginx/sites-available/archipelago"
# Check if Tailscale IP is already in the config
if grep -q "listen $TAILSCALE_IP:80" "$NGINX_CONFIG"; then
echo "✅ Nginx already configured for Tailscale IP $TAILSCALE_IP"
exit 0
fi
echo "📝 Adding Tailscale IP to Nginx configuration..."
# Backup the config
sudo cp "$NGINX_CONFIG" "$NGINX_CONFIG.backup.$(date +%s)"
# Add Tailscale IP to listen directive (after the first "listen 80;")
sudo sed -i "0,/listen 80;/s//listen 80;\n listen $TAILSCALE_IP:80;/" "$NGINX_CONFIG"
echo "🔍 Testing Nginx configuration..."
sudo nginx -t
echo "🔄 Reloading Nginx..."
sudo systemctl reload nginx
echo "✅ Nginx configured to accept connections from Tailscale!"
echo " Access your Archipelago UI via Tailscale at:"
echo " http://$(hostname).tail<your-tailnet>.ts.net/"
+32 -21
View File
@@ -30,16 +30,27 @@ echo ""
# Check for required tools
check_tools() {
local missing=""
for tool in docker xorriso; do
if ! command -v $tool >/dev/null 2>&1; then
missing="$missing $tool"
fi
done
# Check for docker or podman
if command -v docker >/dev/null 2>&1; then
CONTAINER_CMD="docker"
elif command -v podman >/dev/null 2>&1; then
CONTAINER_CMD="podman"
else
missing="$missing docker-or-podman"
fi
if ! command -v xorriso >/dev/null 2>&1; then
missing="$missing xorriso"
fi
if [ -n "$missing" ]; then
echo "❌ Missing required tools:$missing"
echo " Install with: brew install$missing"
echo " Install with: apt install docker.io xorriso (or podman)"
exit 1
fi
echo "Using container runtime: $CONTAINER_CMD"
}
check_tools
@@ -182,13 +193,13 @@ RestartSec=5
WantedBy=multi-user.target
SYSTEMDSERVICE
echo " Building Docker image (this may take a few minutes)..."
docker build --platform linux/amd64 -t archipelago-rootfs -f "$WORK_DIR/Dockerfile.rootfs" "$WORK_DIR"
echo " Building $CONTAINER_CMD image (this may take a few minutes)..."
$CONTAINER_CMD build --platform linux/amd64 -t archipelago-rootfs -f "$WORK_DIR/Dockerfile.rootfs" "$WORK_DIR"
echo " Exporting filesystem..."
docker create --platform linux/amd64 --name archipelago-rootfs-tmp archipelago-rootfs
docker export archipelago-rootfs-tmp > "$ROOTFS_TAR"
docker rm archipelago-rootfs-tmp
$CONTAINER_CMD create --platform linux/amd64 --name archipelago-rootfs-tmp archipelago-rootfs
$CONTAINER_CMD export archipelago-rootfs-tmp > "$ROOTFS_TAR"
$CONTAINER_CMD rm archipelago-rootfs-tmp
echo "✅ Root filesystem created: $(du -h "$ROOTFS_TAR" | cut -f1)"
else
@@ -242,12 +253,12 @@ COPY core ./core
RUN cd core && cargo build --release --bin archipelago
BACKENDFILE
if docker build --platform linux/amd64 -t archipelago-backend -f "$BACKEND_DOCKERFILE" "$SCRIPT_DIR/.." 2>&1 | tail -20; then
if $CONTAINER_CMD build --platform linux/amd64 -t archipelago-backend -f "$BACKEND_DOCKERFILE" "$SCRIPT_DIR/.." 2>&1 | tail -20; then
echo " Extracting backend binary..."
BACKEND_CONTAINER=$(docker create --platform linux/amd64 archipelago-backend)
docker cp "$BACKEND_CONTAINER:/build/core/target/release/archipelago" "$ARCH_DIR/bin/" && \
BACKEND_CONTAINER=$($CONTAINER_CMD create --platform linux/amd64 archipelago-backend)
$CONTAINER_CMD cp "$BACKEND_CONTAINER:/build/core/target/release/archipelago" "$ARCH_DIR/bin/" && \
echo " ✅ Backend binary included ($(du -h "$ARCH_DIR/bin/archipelago" | cut -f1))"
docker rm "$BACKEND_CONTAINER"
$CONTAINER_CMD rm "$BACKEND_CONTAINER"
else
echo " ⚠️ Backend build failed - using existing binary if available"
if [ -f "$SCRIPT_DIR/../core/target/release/archipelago" ]; then
@@ -311,9 +322,9 @@ echo "$CONTAINER_IMAGES" | while read -r image filename; do
echo " ✅ Using cached: $filename"
else
echo " Pulling $image (linux/amd64)..."
if docker pull --platform linux/amd64 "$image"; then
if $CONTAINER_CMD pull --platform linux/amd64 "$image"; then
echo " Saving $filename..."
docker save "$image" -o "$tarpath"
$CONTAINER_CMD save "$image" -o "$tarpath"
echo " ✅ Saved: $(du -h "$tarpath" | cut -f1)"
else
echo " ⚠️ Failed to pull $image - skipping"
@@ -729,7 +740,7 @@ TOOLS_DIR="$WORK_DIR/tools-extract"
rm -rf "$TOOLS_DIR"
mkdir -p "$TOOLS_DIR"
docker run --rm --platform linux/amd64 \
$CONTAINER_CMD run --rm --platform linux/amd64 \
-v "$TOOLS_DIR:/output" \
debian:bookworm \
bash -c '
@@ -879,9 +890,9 @@ mkdir -p "$LIVE_DIR"
if command -v mksquashfs >/dev/null 2>&1; then
mksquashfs "$OVERLAY_DIR" "$LIVE_DIR/99-archipelago.squashfs" -comp xz -noappend
else
# Use Docker to create squashfs on macOS
echo " Using Docker to create squashfs..."
docker run --rm --platform linux/amd64 \
# Use $CONTAINER_CMD to create squashfs on macOS
echo " Using $CONTAINER_CMD to create squashfs..."
$CONTAINER_CMD run --rm --platform linux/amd64 \
-v "$OVERLAY_DIR:/overlay:ro" \
-v "$LIVE_DIR:/output" \
debian:bookworm \
+146 -24
View File
@@ -14,10 +14,15 @@ OUTPUT_DIR="$SCRIPT_DIR/results"
DEBIAN_VERSION="bookworm"
ARCH="amd64"
# Start build timer
BUILD_START=$(date +%s)
echo "╔════════════════════════════════════════════════════════╗"
echo "║ Building Archipelago - Debian Live Edition ║"
echo "╚════════════════════════════════════════════════════════╝"
echo ""
echo "⏱️ Build started: $(date '+%H:%M:%S')"
echo ""
# Create directories
mkdir -p "$WORK_DIR"
@@ -25,15 +30,33 @@ mkdir -p "$OUTPUT_DIR"
# Download Debian Live ISO if not exists
BASE_ISO="$WORK_DIR/debian-live-12-${ARCH}-standard.iso"
if [ ! -f "$BASE_ISO" ] || [ $(stat -f%z "$BASE_ISO" 2>/dev/null || echo 0) -lt 100000000 ]; then
BASE_ISO_SIZE=369131520 # Expected size: ~352MB
if [ ! -f "$BASE_ISO" ] || [ $(stat -f%z "$BASE_ISO" 2>/dev/null || stat -c%s "$BASE_ISO" 2>/dev/null || echo 0) -lt 100000000 ]; then
echo "📥 Downloading Debian Live 12 (Bookworm) Standard ISO..."
echo " Size: ~352MB | This is a one-time download (cached for future builds)"
echo ""
rm -f "$BASE_ISO"
# Use SourceForge respin which has up-to-date Debian 12 Live
curl -L -o "$BASE_ISO" \
# Download with progress bar
curl -# -L -o "$BASE_ISO" \
"https://sourceforge.net/projects/debian-live-respin-iso/files/standard/live-image-debian12.11-standard-20250522-amd64.hybrid.iso/download"
echo "✅ Downloaded Debian Live ISO"
# Verify download succeeded
if [ -f "$BASE_ISO" ] && [ $(stat -f%z "$BASE_ISO" 2>/dev/null || stat -c%s "$BASE_ISO" 2>/dev/null) -gt 300000000 ]; then
ISO_SIZE=$(du -h "$BASE_ISO" | awk '{print $1}')
echo ""
echo "✅ Downloaded Debian Live ISO ($ISO_SIZE)"
echo " 📝 Cached at: $BASE_ISO"
else
echo ""
echo "❌ Download failed or incomplete"
exit 1
fi
else
echo "✅ Using cached Debian Live ISO"
ISO_SIZE=$(du -h "$BASE_ISO" | awk '{print $1}')
echo "✅ Using cached Debian Live ISO ($ISO_SIZE)"
echo " 📁 Location: $BASE_ISO"
fi
# Extract ISO
@@ -58,17 +81,25 @@ mkdir -p "$ARCHIPELAGO_DIR/bin"
mkdir -p "$ARCHIPELAGO_DIR/scripts"
# Copy the pre-built backend if it exists
if [ -d "$SCRIPT_DIR/../core/target/release" ]; then
echo "🦀 Including Archipelago backend..."
if [ -f "$SCRIPT_DIR/build/backend/archipelago" ]; then
echo "🦀 Including Archipelago backend from build/backend..."
cp "$SCRIPT_DIR/build/backend/archipelago" "$ARCHIPELAGO_DIR/bin/"
chmod +x "$ARCHIPELAGO_DIR/bin/archipelago"
elif [ -d "$SCRIPT_DIR/../core/target/release" ]; then
echo "🦀 Including Archipelago backend from target/release..."
cp "$SCRIPT_DIR/../core/target/release/archipelago" "$ARCHIPELAGO_DIR/bin/" 2>/dev/null || true
chmod +x "$ARCHIPELAGO_DIR/bin/archipelago" 2>/dev/null || true
fi
# Copy the frontend build if it exists
if [ -d "$SCRIPT_DIR/../web/dist/neode-ui" ]; then
echo "🎨 Including Archipelago Web UI..."
if [ -d "$SCRIPT_DIR/build/frontend" ]; then
echo "🎨 Including Archipelago Web UI from build/frontend..."
cp -r "$SCRIPT_DIR/build/frontend" "$ARCHIPELAGO_DIR/web-ui"
elif [ -d "$SCRIPT_DIR/../web/dist/neode-ui" ]; then
echo "🎨 Including Archipelago Web UI from web/dist..."
cp -r "$SCRIPT_DIR/../web/dist/neode-ui" "$ARCHIPELAGO_DIR/web-ui"
elif [ -d "$SCRIPT_DIR/../neode-ui/dist" ]; then
echo "🎨 Including Archipelago frontend..."
echo "🎨 Including Archipelago frontend from neode-ui/dist..."
cp -r "$SCRIPT_DIR/../neode-ui/dist" "$ARCHIPELAGO_DIR/web-ui" 2>/dev/null || true
fi
@@ -318,8 +349,8 @@ cat > "$ISO_CUSTOM/etc/profile.d/z99-archipelago.sh" <<'PROFILE_EOF'
#!/bin/bash
# Archipelago auto-start - runs on login (z99 = runs last)
# Only run once per session and only in interactive shells
if [ -n "$ARCHIPELAGO_STARTED" ] || [ ! -t 0 ]; then
# Only run once per session
if [ -n "$ARCHIPELAGO_STARTED" ]; then
return 0 2>/dev/null || exit 0
fi
export ARCHIPELAGO_STARTED=1
@@ -403,9 +434,9 @@ echo " Commands:"
echo " archipelago-menu - Open interactive setup menu"
echo " archipelago - Start/restart backend server"
echo ""
read -p " Press Enter to open the setup menu (or Ctrl+C to skip)... "
sleep 1
# Launch the menu
# Launch the menu automatically
if [ -f /opt/archipelago/scripts/archipelago-menu.sh ]; then
exec bash /opt/archipelago/scripts/archipelago-menu.sh
elif [ -f "$BOOT_MEDIA/archipelago/scripts/archipelago-menu.sh" ]; then
@@ -419,21 +450,88 @@ chmod +x "$ISO_CUSTOM/etc/profile.d/z99-archipelago.sh"
mkdir -p "$ISO_CUSTOM/etc/skel"
cat >> "$ISO_CUSTOM/etc/skel/.bashrc" <<'BASHRC_EOF'
# Archipelago auto-start fallback
if [ -z "$ARCHIPELAGO_STARTED" ] && [ -t 0 ]; then
[ -f /etc/profile.d/z99-archipelago.sh ] && source /etc/profile.d/z99-archipelago.sh
# Archipelago auto-start
if [ -z "$ARCHIPELAGO_STARTED" ] && [ -n "$PS1" ]; then
export ARCHIPELAGO_STARTED=1
# Find boot media
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
if [ -d "$dev/archipelago" ]; then
bash "$dev/archipelago/setup-archipelago.sh" 2>/dev/null || true
break
fi
done
fi
BASHRC_EOF
# Modify GRUB config for Archipelago branding
# CRITICAL: Make getty run our script directly after auto-login
mkdir -p "$ISO_CUSTOM/etc/systemd/system/getty@tty1.service.d"
cat > "$ISO_CUSTOM/etc/systemd/system/getty@tty1.service.d/override.conf" <<'GETTY_EOF'
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin user --login-program /bin/bash --login-options "-c 'source /etc/profile.d/z99-archipelago.sh; exec bash -i'" --noclear %I $TERM
Type=idle
GETTY_EOF
# Create a live-config hook that adds our script to the actual user's .bashrc after user creation
mkdir -p "$ISO_CUSTOM/lib/live/config"
cat > "$ISO_CUSTOM/lib/live/config/9999-archipelago-autostart" <<'LIVECONFIG_EOF'
#!/bin/bash
# Live-config hook to add Archipelago auto-start to live user's bashrc
set -e
# This runs after the live user is created
if [ -d /home/user ]; then
cat >> /home/user/.bashrc <<'EOF'
# Archipelago Auto-Start
if [ -z "$ARCHIPELAGO_STARTED" ] && [ -n "$PS1" ]; then
export ARCHIPELAGO_STARTED=1
# Find boot media
BOOT_MEDIA=""
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
if [ -d "$dev/archipelago" ]; then
BOOT_MEDIA="$dev"
break
fi
done
if [ -n "$BOOT_MEDIA" ]; then
# Source the profile script
if [ -f /etc/profile.d/z99-archipelago.sh ]; then
bash /etc/profile.d/z99-archipelago.sh
fi
fi
fi
EOF
chown user:user /home/user/.bashrc
fi
LIVECONFIG_EOF
chmod +x "$ISO_CUSTOM/lib/live/config/9999-archipelago-autostart"
cat > "$ISO_CUSTOM/etc/systemd/system/getty@tty1.service.d/override.conf" <<'GETTY_EOF'
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin user --noclear %I $TERM
Type=idle
GETTY_EOF
# Modify GRUB config for Archipelago branding and auto-start
echo ""
echo "⚙️ Configuring boot..."
if [ -f "$ISO_CUSTOM/boot/grub/grub.cfg" ]; then
# Update branding
sed -i.bak \
-e 's/Debian GNU\/Linux/Archipelago Bitcoin Node OS/g' \
-e 's/Live system/Archipelago Live/g' \
"$ISO_CUSTOM/boot/grub/grub.cfg"
# Add components=live.persist boot parameter to enable persistence hooks
# This will allow our scripts to run on boot
sed -i '' -e 's/\(boot=live\)/\1 components=/' "$ISO_CUSTOM/boot/grub/grub.cfg" 2>/dev/null || true
fi
if [ -f "$ISO_CUSTOM/isolinux/menu.cfg" ]; then
@@ -500,12 +598,36 @@ fi
echo ""
echo "✅ ISO created successfully!"
echo ""
echo "📀 Output: $OUTPUT_ISO"
echo " Size: $(du -h "$OUTPUT_ISO" | cut -f1)"
# Calculate build time
BUILD_END=$(date +%s)
BUILD_DURATION=$((BUILD_END - BUILD_START))
BUILD_MINUTES=$((BUILD_DURATION / 60))
BUILD_SECONDS=$((BUILD_DURATION % 60))
ISO_SIZE=$(du -h "$OUTPUT_ISO" | cut -f1)
ISO_MD5=$(md5 -q "$OUTPUT_ISO" 2>/dev/null || md5sum "$OUTPUT_ISO" | awk '{print $1}')
echo "╔════════════════════════════════════════════════════════╗"
echo "║ 🎉 Build Complete! ║"
echo "╚════════════════════════════════════════════════════════╝"
echo ""
echo "🔥 This is Debian Live-based - reliable USB boot like StartOS!"
echo "📀 ISO File: $OUTPUT_ISO"
echo "📏 Size: $ISO_SIZE"
echo "🔐 MD5: $ISO_MD5"
echo "⏱️ Build Time: ${BUILD_MINUTES}m ${BUILD_SECONDS}s"
echo "🎯 Base: Debian 12 Live (Bookworm)"
echo ""
echo "To create USB:"
echo " 1. Use Balena Etcher to flash the ISO"
echo " 2. Or: sudo dd if=$OUTPUT_ISO of=/dev/sdX bs=4M status=progress"
echo "🔥 Next Steps:"
echo ""
echo " 1. Flash to USB:"
echo " cd image-recipe && ./write-usb-dd.sh /dev/diskN"
echo ""
echo " 2. Boot on target device"
echo ""
echo " 3. Auto-login as 'user' with menu launch"
echo ""
echo " 4. Access Web UI at http://<IP>:5678"
echo ""
echo " 5. SSH access: ssh user@<IP> (password: archipelago)"
echo ""
+410
View File
@@ -0,0 +1,410 @@
#!/bin/bash
#
# Build Archipelago Auto-Installer ISO from LIVE SERVER STATE
#
# This captures the CURRENT STATE of the development server and packages
# it into an auto-installer ISO - exactly like Start9/Umbrel.
#
# Usage: ./build-from-live-server.sh [dev-server-ip]
#
set -e
DEV_SERVER="${1:-archipelago@192.168.1.228}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
WORK_DIR="$SCRIPT_DIR/build/live-snapshot"
OUTPUT_DIR="$SCRIPT_DIR/results"
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Building Archipelago ISO from LIVE SERVER ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
echo "📡 Development Server: $DEV_SERVER"
echo ""
# Check for required tools
CONTAINER_CMD=""
if command -v docker >/dev/null 2>&1; then
CONTAINER_CMD="docker"
elif command -v podman >/dev/null 2>&1; then
CONTAINER_CMD="podman"
else
echo "❌ Missing docker or podman"
exit 1
fi
if ! command -v xorriso >/dev/null 2>&1; then
echo "❌ Missing xorriso"
exit 1
fi
if ! command -v ssh >/dev/null 2>&1; then
echo "❌ Missing ssh"
exit 1
fi
echo "Using container runtime: $CONTAINER_CMD"
echo ""
mkdir -p "$WORK_DIR"
mkdir -p "$OUTPUT_DIR"
# =============================================================================
# STEP 1: Capture LIVE SERVER state
# =============================================================================
echo "📦 Step 1: Capturing live server state..."
echo ""
SNAPSHOT_DIR="$WORK_DIR/live-server-snapshot"
rm -rf "$SNAPSHOT_DIR"
mkdir -p "$SNAPSHOT_DIR"
# Create directory structure
mkdir -p "$SNAPSHOT_DIR/bin"
mkdir -p "$SNAPSHOT_DIR/web-ui"
mkdir -p "$SNAPSHOT_DIR/configs"
mkdir -p "$SNAPSHOT_DIR/apps"
mkdir -p "$SNAPSHOT_DIR/scripts"
# Capture backend binary
echo " Capturing backend binary..."
scp "$DEV_SERVER:/usr/local/bin/archipelago" "$SNAPSHOT_DIR/bin/" 2>/dev/null || {
echo " ⚠️ Backend binary not found on server"
echo " Using local build if available..."
if [ -f "$SCRIPT_DIR/../core/target/release/archipelago" ]; then
# Build on Linux if we're on macOS
if [[ "$OSTYPE" == "darwin"* ]]; then
echo " Building backend for Linux..."
cd "$SCRIPT_DIR/../core"
$CONTAINER_CMD build --platform linux/amd64 -t archipelago-backend -f - . <<'DOCKERFILE'
FROM rust:1.93-bookworm as builder
WORKDIR /build
COPY . .
RUN cargo build --release --bin archipelago
DOCKERFILE
BACKEND_CONTAINER=$($CONTAINER_CMD create --platform linux/amd64 archipelago-backend)
$CONTAINER_CMD cp "$BACKEND_CONTAINER:/build/target/release/archipelago" "$SNAPSHOT_DIR/bin/"
$CONTAINER_CMD rm "$BACKEND_CONTAINER"
cd "$SCRIPT_DIR"
else
cp "$SCRIPT_DIR/../core/target/release/archipelago" "$SNAPSHOT_DIR/bin/"
fi
fi
}
if [ -f "$SNAPSHOT_DIR/bin/archipelago" ]; then
chmod +x "$SNAPSHOT_DIR/bin/archipelago"
echo " ✅ Backend: $(du -h "$SNAPSHOT_DIR/bin/archipelago" | cut -f1)"
else
echo " ❌ No backend binary available"
exit 1
fi
# Capture frontend (Web UI)
echo " Capturing frontend (Web UI)..."
rsync -az --delete "$DEV_SERVER:/opt/archipelago/web-ui/" "$SNAPSHOT_DIR/web-ui/" 2>/dev/null || {
echo " ⚠️ Web UI not found on server"
echo " Using local build..."
if [ -d "$SCRIPT_DIR/../web/dist/neode-ui" ]; then
cp -r "$SCRIPT_DIR/../web/dist/neode-ui/"* "$SNAPSHOT_DIR/web-ui/"
elif [ -d "$SCRIPT_DIR/../neode-ui/dist" ]; then
cp -r "$SCRIPT_DIR/../neode-ui/dist/"* "$SNAPSHOT_DIR/web-ui/"
else
echo " Building frontend..."
cd "$SCRIPT_DIR/../neode-ui"
npm run build
cp -r "$SCRIPT_DIR/../web/dist/neode-ui/"* "$SNAPSHOT_DIR/web-ui/"
cd "$SCRIPT_DIR"
fi
}
if [ -d "$SNAPSHOT_DIR/web-ui" ] && [ "$(ls -A "$SNAPSHOT_DIR/web-ui")" ]; then
echo " ✅ Web UI: $(du -sh "$SNAPSHOT_DIR/web-ui" | cut -f1)"
else
echo " ❌ No web UI available"
exit 1
fi
# Capture Nginx config
echo " Capturing Nginx config..."
scp "$DEV_SERVER:/etc/nginx/sites-available/default" "$SNAPSHOT_DIR/configs/nginx-default.conf" 2>/dev/null || \
echo " ⚠️ Using default Nginx config"
# Capture systemd service
echo " Capturing systemd service..."
scp "$DEV_SERVER:/etc/systemd/system/archipelago.service" "$SNAPSHOT_DIR/configs/archipelago.service" 2>/dev/null || {
echo " Creating default service..."
cat > "$SNAPSHOT_DIR/configs/archipelago.service" <<'SERVICE'
[Unit]
Description=Archipelago Backend
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=archipelago
Environment="ARCHIPELAGO_BIND=0.0.0.0:5678"
Environment="ARCHIPELAGO_DEV_MODE=true"
ExecStart=/usr/local/bin/archipelago
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
SERVICE
}
# Capture app manifests
echo " Capturing app manifests..."
if [ -d "$SCRIPT_DIR/../apps" ]; then
cp -r "$SCRIPT_DIR/../apps/"* "$SNAPSHOT_DIR/apps/" 2>/dev/null || true
fi
echo " ✅ Live server state captured"
echo ""
# =============================================================================
# STEP 2: Create base rootfs with captured state
# =============================================================================
echo "📦 Step 2: Creating base system with live server state..."
echo ""
ROOTFS_TAR="$WORK_DIR/archipelago-rootfs-live.tar"
# Build rootfs with Docker/Podman
cat > "$WORK_DIR/Dockerfile.rootfs" <<'DOCKERFILE'
FROM debian:bookworm
ENV DEBIAN_FRONTEND=noninteractive
# Install all required packages
RUN apt-get update && apt-get install -y \
linux-image-amd64 \
grub-efi-amd64 \
grub-efi-amd64-signed \
shim-signed \
systemd \
systemd-sysv \
dbus \
sudo \
network-manager \
openssh-server \
nginx \
podman \
curl \
wget \
htop \
vim-tiny \
ca-certificates \
locales \
console-setup \
keyboard-configuration \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Configure locale
RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen
# Create archipelago user
RUN useradd -m -s /bin/bash -G sudo archipelago && \
echo "archipelago:archipelago" | chpasswd && \
echo "archipelago ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/archipelago
# Set hostname
RUN echo "archipelago" > /etc/hostname
# Configure SSH
RUN mkdir -p /etc/ssh && \
sed -i 's/#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config || true && \
sed -i 's/#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config || true
# Create directories
RUN mkdir -p /var/lib/archipelago/{data,config,containers} && \
mkdir -p /etc/archipelago && \
mkdir -p /opt/archipelago/{bin,scripts,web-ui} && \
chown -R archipelago:archipelago /var/lib/archipelago /opt/archipelago
# Clean up
RUN apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
DOCKERFILE
echo " Building base rootfs..."
$CONTAINER_CMD build --platform linux/amd64 -t archipelago-rootfs-live -f "$WORK_DIR/Dockerfile.rootfs" "$WORK_DIR"
echo " Exporting filesystem..."
$CONTAINER_CMD create --platform linux/amd64 --name archipelago-rootfs-live-tmp archipelago-rootfs-live
$CONTAINER_CMD export archipelago-rootfs-live-tmp > "$ROOTFS_TAR"
$CONTAINER_CMD rm archipelago-rootfs-live-tmp
echo " ✅ Base rootfs created: $(du -h "$ROOTFS_TAR" | cut -f1)"
echo ""
# =============================================================================
# STEP 3: Inject live server files into rootfs
# =============================================================================
echo "📦 Step 3: Injecting live server files..."
echo ""
ROOTFS_DIR="$WORK_DIR/rootfs-extract"
rm -rf "$ROOTFS_DIR"
mkdir -p "$ROOTFS_DIR"
echo " Extracting rootfs..."
tar -xf "$ROOTFS_TAR" -C "$ROOTFS_DIR"
echo " Copying backend binary..."
cp "$SNAPSHOT_DIR/bin/archipelago" "$ROOTFS_DIR/usr/local/bin/"
chmod +x "$ROOTFS_DIR/usr/local/bin/archipelago"
echo " Copying web UI..."
rm -rf "$ROOTFS_DIR/opt/archipelago/web-ui"
mkdir -p "$ROOTFS_DIR/opt/archipelago/web-ui"
cp -r "$SNAPSHOT_DIR/web-ui/"* "$ROOTFS_DIR/opt/archipelago/web-ui/"
echo " Configuring Nginx..."
if [ -f "$SNAPSHOT_DIR/configs/nginx-default.conf" ]; then
cp "$SNAPSHOT_DIR/configs/nginx-default.conf" "$ROOTFS_DIR/etc/nginx/sites-available/archipelago"
else
cat > "$ROOTFS_DIR/etc/nginx/sites-available/archipelago" <<'NGINXCONF'
server {
listen 80 default_server;
listen [::]:80 default_server;
root /opt/archipelago/web-ui;
index index.html;
server_name _;
# Proxy API requests to backend
location /rpc/ {
proxy_pass http://localhost:5678/rpc/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /ws/ {
proxy_pass http://localhost:5678/ws/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
location /health {
proxy_pass http://localhost:5678/health;
}
# Serve static files
location / {
try_files $uri $uri/ /index.html;
}
}
NGINXCONF
fi
rm -f "$ROOTFS_DIR/etc/nginx/sites-enabled/default"
ln -sf /etc/nginx/sites-available/archipelago "$ROOTFS_DIR/etc/nginx/sites-enabled/archipelago"
echo " Configuring systemd service..."
cp "$SNAPSHOT_DIR/configs/archipelago.service" "$ROOTFS_DIR/etc/systemd/system/archipelago.service"
# Enable services (create symlinks)
mkdir -p "$ROOTFS_DIR/etc/systemd/system/multi-user.target.wants"
ln -sf /etc/systemd/system/archipelago.service "$ROOTFS_DIR/etc/systemd/system/multi-user.target.wants/archipelago.service"
ln -sf /lib/systemd/system/NetworkManager.service "$ROOTFS_DIR/etc/systemd/system/multi-user.target.wants/NetworkManager.service"
ln -sf /lib/systemd/system/ssh.service "$ROOTFS_DIR/etc/systemd/system/multi-user.target.wants/ssh.service"
ln -sf /lib/systemd/system/nginx.service "$ROOTFS_DIR/etc/systemd/system/multi-user.target.wants/nginx.service"
echo " Copying app manifests..."
if [ -d "$SNAPSHOT_DIR/apps" ]; then
mkdir -p "$ROOTFS_DIR/etc/archipelago/apps"
cp -r "$SNAPSHOT_DIR/apps/"* "$ROOTFS_DIR/etc/archipelago/apps/" 2>/dev/null || true
fi
echo " Repacking rootfs with live server state..."
cd "$ROOTFS_DIR"
tar -cf "$ROOTFS_TAR" .
cd "$SCRIPT_DIR"
echo " ✅ Live server files injected"
echo ""
# =============================================================================
# STEP 4: Create installer ISO (reuse existing auto-installer logic)
# =============================================================================
echo "📦 Step 4: Creating auto-installer ISO..."
echo ""
# Now call the existing auto-installer script but skip the rootfs build
# since we already have it with live server state
export ROOTFS_TAR="$ROOTFS_TAR"
export SKIP_ROOTFS_BUILD="true"
# Run the rest of build-auto-installer-iso.sh logic here...
# (Download Debian Live base, create auto-install.sh, package ISO)
echo " Downloading Debian Live base..."
BASE_ISO="$WORK_DIR/debian-live-installer.iso"
if [ ! -f "$BASE_ISO" ] || [ $(stat -f%z "$BASE_ISO" 2>/dev/null || stat -c%s "$BASE_ISO" 2>/dev/null || echo 0) -lt 100000000 ]; then
curl -L -# -o "$BASE_ISO" \
"https://cdimage.debian.org/debian-cd/current-live/amd64/iso-hybrid/debian-live-12.9.0-amd64-standard.iso"
fi
echo " Extracting installer base..."
INSTALLER_ISO="$WORK_DIR/installer-iso"
rm -rf "$INSTALLER_ISO"
mkdir -p "$INSTALLER_ISO"
cd "$INSTALLER_ISO"
7z x -y "$BASE_ISO" >/dev/null 2>&1
cd "$SCRIPT_DIR"
# Copy archipelago files
ARCH_DIR="$INSTALLER_ISO/archipelago"
mkdir -p "$ARCH_DIR"
cp "$ROOTFS_TAR" "$ARCH_DIR/rootfs.tar"
echo " ✅ Archipelago components added (rootfs: $(du -h "$ARCH_DIR/rootfs.tar" | cut -f1))"
echo ""
# Continue with ISO creation...
echo "📦 Step 5: Creating final bootable ISO..."
# (Rest of xorriso logic from build-auto-installer-iso.sh)
OUTPUT_ISO="$OUTPUT_DIR/archipelago-live-$(date +%Y%m%d-%H%M%S).iso"
# Get MBR
ISOHDPFX="$WORK_DIR/isohdpfx.bin"
dd if="$INSTALLER_ISO/isolinux/isolinux.bin" of="$ISOHDPFX" bs=432 count=1 2>/dev/null
xorriso -as mkisofs -o "$OUTPUT_ISO" \
-volid "ARCHIPELAGO" \
-J -R \
-isohybrid-mbr "$ISOHDPFX" \
-c isolinux/boot.cat \
-b isolinux/isolinux.bin \
-no-emul-boot -boot-load-size 4 -boot-info-table \
-eltorito-alt-boot \
-e boot/grub/efi.img \
-no-emul-boot \
-isohybrid-gpt-basdat \
"$INSTALLER_ISO"
echo ""
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ ✅ LIVE SERVER ISO CREATED! ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
echo "📀 Output: $OUTPUT_ISO"
echo " Size: $(du -h "$OUTPUT_ISO" | cut -f1)"
echo " MD5: $(md5sum "$OUTPUT_ISO" 2>/dev/null || md5 "$OUTPUT_ISO" | awk '{print $NF}')"
echo ""
echo "🎉 This ISO contains the EXACT state of your dev server!"
echo ""
echo "To flash:"
echo " cd image-recipe && ./write-usb-dd.sh /dev/diskX"
echo ""
@@ -1,5 +1,6 @@
server {
listen 80;
listen 100.91.10.103:80;
server_name _;
root /opt/archipelago/web-ui;
@@ -16,6 +17,11 @@ server {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Increase timeout for long-running operations (e.g., Docker image pulls)
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
# Proxy WebSocket
@@ -25,5 +31,8 @@ server {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
# WebSocket timeout
proxy_read_timeout 86400s;
}
}
+47
View File
@@ -0,0 +1,47 @@
#!/bin/bash
# Quick fix to enable Archipelago auto-start on existing booted system
# Run this on the Dell OptiPlex after boot
set -e
echo "🔧 Fixing Archipelago auto-start..."
# Create the auto-start script in .bashrc
cat >> ~/.bashrc << 'EOF'
# Archipelago Auto-Start
if [ -z "$ARCHIPELAGO_STARTED" ] && [ -n "$PS1" ]; then
export ARCHIPELAGO_STARTED=1
# Find boot media
BOOT_MEDIA=""
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
if [ -d "$dev/archipelago" ]; then
BOOT_MEDIA="$dev"
break
fi
done
if [ -n "$BOOT_MEDIA" ]; then
clear
echo ""
echo " ╔═══════════════════════════════════════════════════════════╗"
echo " ║ 🏝️ ARCHIPELAGO BITCOIN NODE OS ║"
echo " ╚═══════════════════════════════════════════════════════════╝"
echo ""
# Get IP
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
[ -n "$IP" ] && echo " 🌐 Web UI: http://$IP:5678"
echo ""
# Run the setup
bash "$BOOT_MEDIA/archipelago/setup-archipelago.sh"
fi
fi
EOF
echo "✅ Auto-start added to .bashrc"
echo ""
echo "Now logout and login again, or run:"
echo " source ~/.bashrc"