diff --git a/image-recipe/_archived/build-auto-installer-iso.sh b/image-recipe/_archived/build-auto-installer-iso.sh index d3078656..a85e8880 100755 --- a/image-recipe/_archived/build-auto-installer-iso.sh +++ b/image-recipe/_archived/build-auto-installer-iso.sh @@ -1349,21 +1349,29 @@ if [ "$UNBUNDLED" = "1" ]; then # Clean stale images from previous builds (e.g. bundled build tars leaking into unbundled) rm -rf "$IMAGES_DIR" mkdir -p "$IMAGES_DIR" - # FileBrowser is a core dependency (powers the Cloud file manager) — always bundle it - CORE_IMAGE="${FILEBROWSER_IMAGE}" - CORE_FILE="filebrowser.tar" - if [ -f "$IMAGES_DIR/$CORE_FILE" ]; then - echo " ✅ Using cached: $CORE_FILE" - else - echo " Pulling $CORE_IMAGE ($CONTAINER_PLATFORM)..." - if container_pull "$CORE_IMAGE"; then - $CONTAINER_CMD save "$CORE_IMAGE" -o "$IMAGES_DIR/$CORE_FILE" 2>/dev/null && \ - echo " ✅ Saved core: $CORE_FILE ($(du -h "$IMAGES_DIR/$CORE_FILE" | cut -f1))" || \ - echo " ⚠️ Failed to save $CORE_IMAGE" + # Core baseline apps created by first-boot-containers.sh even in + # unbundled mode — their images must ride on the ISO so a fresh install + # works with no internet: FileBrowser (Cloud file manager) and fmcd + # (fedimint-clientd, ecash/sats out of the box). + CORE_BUNDLE=" +${FILEBROWSER_IMAGE} filebrowser.tar +${FMCD_IMAGE} fmcd.tar +" + echo "$CORE_BUNDLE" | while read -r CORE_IMAGE CORE_FILE; do + [ -n "$CORE_IMAGE" ] || continue + if [ -f "$IMAGES_DIR/$CORE_FILE" ]; then + echo " ✅ Using cached: $CORE_FILE" else - echo " ⚠️ Failed to pull $CORE_IMAGE — Cloud will not work until installed" + echo " Pulling $CORE_IMAGE ($CONTAINER_PLATFORM)..." + if container_pull "$CORE_IMAGE"; then + $CONTAINER_CMD save "$CORE_IMAGE" -o "$IMAGES_DIR/$CORE_FILE" 2>/dev/null && \ + echo " ✅ Saved core: $CORE_FILE ($(du -h "$IMAGES_DIR/$CORE_FILE" | cut -f1))" || \ + echo " ⚠️ Failed to save $CORE_IMAGE" + else + echo " ⚠️ Failed to pull $CORE_IMAGE — baseline app won't work offline" + fi fi - fi + done else echo "📦 Step 3b: Bundling container images for offline use..." @@ -1472,6 +1480,13 @@ LOADSERVICE cat > "$WORK_DIR/load-container-images.sh" <<'LOADSCRIPT' #!/bin/bash # Load pre-bundled container images into Podman +# +# CRITICAL: all Archipelago containers run ROOTLESS as the archipelago user. +# This script runs as root (systemd oneshot), so a plain `podman load` here +# puts the images into root's storage where the rootless runtime can never +# see them — containers then silently depend on registry pulls, and a fresh +# install without internet gets no apps at all. Always load into the +# archipelago user's storage. IMAGES_DIR="/opt/archipelago/container-images" LOG_FILE="/var/log/archipelago-images.log" @@ -1483,21 +1498,32 @@ if [ ! -d "$IMAGES_DIR" ]; then exit 0 fi +ARCH_UID=$(id -u archipelago) +# Linger gives the archipelago user a runtime dir (/run/user/UID) at boot, +# before any login — required for rootless podman. +loginctl enable-linger archipelago 2>/dev/null || true +for _ in $(seq 1 30); do + [ -d "/run/user/$ARCH_UID" ] && break + sleep 1 +done +PODMAN="runuser -u archipelago -- env XDG_RUNTIME_DIR=/run/user/$ARCH_UID podman" +$PODMAN system migrate >> "$LOG_FILE" 2>&1 || true + for tarfile in "$IMAGES_DIR"/*.tar; do if [ -f "$tarfile" ]; then echo "$(date): Loading $(basename "$tarfile")..." >> "$LOG_FILE" - podman load -i "$tarfile" >> "$LOG_FILE" 2>&1 && \ + $PODMAN load -i "$tarfile" >> "$LOG_FILE" 2>&1 && \ echo "$(date): Successfully loaded $(basename "$tarfile")" >> "$LOG_FILE" || \ echo "$(date): Failed to load $(basename "$tarfile")" >> "$LOG_FILE" fi done # Ensure archy-net exists for mempool stack (db, api, frontend) -podman network create archy-net 2>/dev/null || true +$PODMAN network create archy-net 2>/dev/null || true echo "$(date): Container image load complete" >> "$LOG_FILE" echo "$(date): Available images:" >> "$LOG_FILE" -podman images >> "$LOG_FILE" 2>&1 +$PODMAN images >> "$LOG_FILE" 2>&1 LOADSCRIPT chmod +x "$WORK_DIR/load-container-images.sh" diff --git a/neode-ui/src/views/discover/curatedApps.ts b/neode-ui/src/views/discover/curatedApps.ts index ce038e53..3e0c6a5e 100644 --- a/neode-ui/src/views/discover/curatedApps.ts +++ b/neode-ui/src/views/discover/curatedApps.ts @@ -105,6 +105,7 @@ export function getCuratedAppList(): MarketplaceApp[] { { id: 'netbird', title: 'NetBird', version: '0.71.2', description: 'Self-hosted WireGuard mesh VPN control plane with dashboard, embedded identity provider, management API, signal, relay, and STUN.', icon: '/assets/img/app-icons/netbird.svg', author: 'NetBird', dockerImage: 'docker.io/netbirdio/dashboard:v2.38.0', repoUrl: 'https://github.com/netbirdio/netbird' }, { id: 'electrumx', title: 'ElectrumX', version: '1.18.0', description: 'Electrum protocol server. Index the blockchain for fast wallet lookups, privately.', icon: '/assets/img/app-icons/electrumx.png', author: 'Luke Childs', dockerImage: `${R}/electrumx:v1.18.0`, repoUrl: 'https://github.com/spesmilo/electrumx' }, { id: 'fedimint', title: 'Fedimint Guardian', version: '0.10.0', description: 'Federated Bitcoin mint. Private, scalable Bitcoin through federated guardians.', icon: '/assets/img/app-icons/fedimint.png', author: 'Fedimint', dockerImage: `${R}/fedimintd:v0.10.0`, repoUrl: 'https://github.com/fedimint/fedimint' }, + { id: 'fedimint-clientd', title: 'Fedimint Client', version: '0.8.0', description: 'Fedimint ecash client daemon (fmcd). Lets the node hold Fedimint ecash and join federations; the wallet talks to it over a local REST API.', icon: '/assets/img/app-icons/fedimint.png', author: 'Fedimint', dockerImage: `${R}/fmcd:0.8.1`, repoUrl: 'https://github.com/minmoto/fmcd' }, { id: 'indeedhub', title: 'Indeehub', version: '1.0.0', description: 'Bitcoin documentary streaming with Nostr identity. Stream sovereignty content.', icon: '/assets/img/app-icons/indeedhub.png', author: 'Indeehub Team', dockerImage: `${R}/indeedhub:1.0.0`, repoUrl: 'https://github.com/indeedhub/indeedhub' }, { id: 'nostrudel', title: 'noStrudel', version: '0.40.0', category: 'nostr', description: 'Feature-rich Nostr web client. Browse feeds, post notes, manage relays with NIP-07.', icon: '/assets/img/app-icons/nostrudel.svg', author: 'hzrd149', dockerImage: '', repoUrl: 'https://github.com/hzrd149/nostrudel', webUrl: 'https://nostrudel.ninja' }, { id: 'botfights', title: 'BotFights', version: '1.0.0', category: 'community', description: 'Bot arena + 2-player arcade fighter with controller support. AI bots battle in trivia, humans duke it out with controllers.', icon: '/assets/img/app-icons/botfights.svg', author: 'BotFights', dockerImage: `${R}/botfights:1.1.0`, repoUrl: 'https://botfights.net' }, @@ -122,6 +123,7 @@ export const INSTALLED_ALIASES: Record = { immich: ['immich-server', 'immich-app', 'immich_server'], nextcloud: ['nextcloud-aio', 'nextcloud-server'], fedimint: ['fedimint-gateway'], + 'fedimint-clientd': ['fedimint-clientd'], electrumx: ['electrumx'], grafana: ['grafana'], jellyfin: ['jellyfin'], diff --git a/scripts/first-boot-containers.sh b/scripts/first-boot-containers.sh index 3d51c005..9ea047e9 100755 --- a/scripts/first-boot-containers.sh +++ b/scripts/first-boot-containers.sh @@ -112,6 +112,13 @@ if [ -f "$UNBUNDLED_MARKER" ]; then # Helper: pull image with fallback registry pull_with_fallback() { local img="$1" + # Pre-bundled ISO images are already loaded into the rootless + # storage by archipelago-load-images.service — use them and skip + # the network entirely (fresh installs must work offline). + if $DOCKER image exists "$img" 2>/dev/null; then + log " Image already present locally: $img" + return 0 + fi log " Pulling $img..." if $DOCKER pull "$img" 2>>"$LOG"; then return 0 diff --git a/scripts/image-versions.sh b/scripts/image-versions.sh index d8f25951..3b6640cf 100644 --- a/scripts/image-versions.sh +++ b/scripts/image-versions.sh @@ -59,9 +59,10 @@ ADGUARDHOME_IMAGE="$ARCHY_REGISTRY/adguardhome:v0.107.55" FEDIMINT_IMAGE="$ARCHY_REGISTRY/fedimintd:v0.10.0" FEDIMINT_GATEWAY_IMAGE="$ARCHY_REGISTRY/gatewayd:v0.10.0" # fmcd = Fedimint client daemon (iroh-capable, fedimint-client 0.8.2). Built -# from minmoto/fmcd. NOT yet added to the bundled CONTAINER_IMAGES list / first- -# boot auto-create: bundling fleet-wide needs a fleet-reachable default -# federation first (the interim default is node-local). See docs/dual-ecash-design.md. +# from minmoto/fmcd. Bundled on the ISO in BOTH modes (full CONTAINER_IMAGES +# list and the unbundled core bundle) and auto-created by first-boot as a +# baseline app so ecash works offline out of the box. +# See docs/dual-ecash-design.md. FMCD_IMAGE="$ARCHY_REGISTRY/fmcd:0.8.1" # Ark (bark)