fix: WebSocket reconnect state refresh, listener leak fixes, pin container images

- F4: Fetch fresh server state after WebSocket reconnect
- F5: Guard message polling timer with auth check, stop on logout
- F6: Remove NIP-07 listener in appLauncher close()
- F7: Initialize audio player once to prevent listener stacking
- S3: Pin all container images to specific versions, create image-versions.sh

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-21 01:32:28 +00:00
parent 4d17c60da7
commit 3b7d541224
13 changed files with 233 additions and 110 deletions

View File

@@ -20,6 +20,10 @@
set -o pipefail
# Source pinned image versions (single source of truth)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
[ -f "$SCRIPT_DIR/image-versions.sh" ] && . "$SCRIPT_DIR/image-versions.sh"
FIXES_APPLIED=0
CHECKS_PASSED=0
FIX_NAMES=()
@@ -194,7 +198,7 @@ fix_searxng() {
-v searxng-cache:/var/cache/searxng:rw \
-p "${host_port}:8080" \
--memory=512m \
docker.io/searxng/searxng:latest 2>&1 || true
"${SEARXNG_IMAGE:-docker.io/searxng/searxng:2024.11.17}" 2>&1 || true
log "SearXNG recreated (no readonly, no cap-drop ALL)"
return 0

View File

@@ -9,6 +9,10 @@
set -e
# Source pinned image versions (single source of truth)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
[ -f "$SCRIPT_DIR/image-versions.sh" ] && . "$SCRIPT_DIR/image-versions.sh"
# Read per-installation Bitcoin RPC credentials
SECRETS_DIR="/var/lib/archipelago/secrets"
sudo mkdir -p "$SECRETS_DIR" && sudo chmod 700 "$SECRETS_DIR"
@@ -48,7 +52,7 @@ podman run -d \
--label "com.archipelago.icon=/assets/img/app-icons/bitcoin-knots.webp" \
--label "com.archipelago.port=8332" \
--label "com.archipelago.repo=https://github.com/bitcoinknots/bitcoin" \
docker.io/bitcoinknots/bitcoin:latest \
"${BITCOIN_KNOTS_IMAGE:-docker.io/bitcoinknots/bitcoin:v28.1}" \
-server=1 \
-txindex=1 \
-rpcallowip=127.0.0.1/32 -rpcallowip=10.88.0.0/16 \
@@ -89,7 +93,7 @@ EOF
cp /home/archipelago/archy/docker/bitcoin-ui/index.html "$BUILD_DIR/"
# Build the image
podman build -t localhost/bitcoin-ui:latest "$BUILD_DIR"
podman build -t localhost/bitcoin-ui:local "$BUILD_DIR"
# Deploy UI container
podman run -d \
@@ -98,7 +102,7 @@ podman run -d \
-p 8334:80 \
--label "com.archipelago.app=bitcoin-ui" \
--label "com.archipelago.parent=bitcoin-knots" \
localhost/bitcoin-ui:latest
localhost/bitcoin-ui:local
echo " ✅ Bitcoin UI deployed on port 8334"

View File

@@ -21,6 +21,9 @@ TARGET_DIR="/home/archipelago/archy"
# Load deploy config (gitignored)
[ -f "$SCRIPT_DIR/deploy-config.sh" ] && . "$SCRIPT_DIR/deploy-config.sh"
# Source pinned image versions (single source of truth)
[ -f "$SCRIPT_DIR/image-versions.sh" ] && . "$SCRIPT_DIR/image-versions.sh"
SSH_KEY="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}"
SSH_OPTS="-o StrictHostKeyChecking=no -o ServerAliveInterval=15 -o ServerAliveCountMax=4 -o ConnectTimeout=10 -i $SSH_KEY"
BUILD_SOURCE="archipelago@192.168.1.228"
@@ -155,7 +158,7 @@ deploy_node() {
HAS_IMG=$(ssh $SSH_OPTS "$BUILD_SOURCE" "podman images --format '{{.Repository}}' 2>/dev/null | grep -q '$ui_img' && echo yes || echo no" 2>/dev/null)
if [ "$HAS_IMG" = "yes" ]; then
echo " $ui_img..."
ssh $SSH_OPTS "$BUILD_SOURCE" "podman save 'localhost/${ui_img}:latest'" > "/tmp/${ui_img}.tar"
ssh $SSH_OPTS "$BUILD_SOURCE" "podman save 'localhost/${ui_img}:local'" > "/tmp/${ui_img}.tar"
ssh $SSH_OPTS "$TARGET" "podman load" < "/tmp/${ui_img}.tar" 2>&1 | tail -1
rm -f "/tmp/${ui_img}.tar"
fi
@@ -471,7 +474,7 @@ deploy_node() {
--security-opt no-new-privileges:true \
-p 8332:8332 -p 8333:8333 \
-v /var/lib/archipelago/bitcoin:/home/bitcoin/.bitcoin \
docker.io/bitcoinknots/bitcoin:latest \
${BITCOIN_KNOTS_IMAGE:-docker.io/bitcoinknots/bitcoin:v28.1} \
-server=1 \$BTC_EXTRA_ARGS \
-rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 \
-rpcuser=$BITCOIN_RPC_USER -rpcpassword=$BITCOIN_RPC_PASS \
@@ -764,7 +767,7 @@ LNDCONF
else
\$DOCKER run -d --name searxng --restart unless-stopped \
--cap-drop ALL --security-opt no-new-privileges:true \
-p 8888:8080 docker.io/searxng/searxng:latest
-p 8888:8080 ${SEARXNG_IMAGE:-docker.io/searxng/searxng:2024.11.17}
fi
fi
# FileBrowser
@@ -800,7 +803,7 @@ LNDCONF
--security-opt no-new-privileges:true \
-p 2342:2342 -v /var/lib/archipelago/photoprism:/photoprism/storage \
-e PHOTOPRISM_ADMIN_PASSWORD=archipelago -e PHOTOPRISM_DEFAULT_LOCALE=en \
docker.io/photoprism/photoprism:latest
${PHOTOPRISM_IMAGE:-docker.io/photoprism/photoprism:240915}
fi
fi
# OnlyOffice
@@ -826,7 +829,7 @@ LNDCONF
-p 81:81 -p 8084:80 -p 8443:443 \
-v /var/lib/archipelago/nginx-proxy-manager/data:/data \
-v /var/lib/archipelago/nginx-proxy-manager/letsencrypt:/etc/letsencrypt \
docker.io/jc21/nginx-proxy-manager:latest
${NPM_IMAGE:-docker.io/jc21/nginx-proxy-manager:2}
fi
fi
# Portainer
@@ -872,7 +875,7 @@ LNDCONF
-e PENPOT_OBJECTS_STORAGE_BACKEND=fs \
-e PENPOT_OBJECTS_STORAGE_FS_DIRECTORY=/opt/data/assets \
-e PENPOT_FLAGS='disable-email-verification enable-smtp enable-prepl-server disable-secure-session-cookies' \
docker.io/penpotapp/backend:latest
${PENPOT_BACKEND_IMAGE:-docker.io/penpotapp/backend:2.4.2}
sleep 5
fi
if ! \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q penpot-exporter; then
@@ -880,7 +883,7 @@ LNDCONF
-e PENPOT_SECRET_KEY=archipelago-penpot-secret-key-change-in-production \
-e PENPOT_PUBLIC_URI=http://penpot-frontend:8080 \
-e PENPOT_REDIS_URI=redis://penpot-valkey/0 \
docker.io/penpotapp/exporter:latest
${PENPOT_EXPORTER_IMAGE:-docker.io/penpotapp/exporter:2.4.2}
sleep 2
fi
if ! \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q penpot-frontend; then
@@ -888,7 +891,7 @@ LNDCONF
-p 9001:8080 -v /var/lib/archipelago/penpot-assets:/opt/data/assets \
-e PENPOT_PUBLIC_URI=http://\${TARGET_IP}:9001 \
-e PENPOT_FLAGS='disable-email-verification enable-smtp enable-prepl-server disable-secure-session-cookies' \
docker.io/penpotapp/frontend:latest
${PENPOT_FRONTEND_IMAGE:-docker.io/penpotapp/frontend:2.4.2}
fi
fi
@@ -906,9 +909,9 @@ LNDCONF
esac
if [ -d \"$TARGET_DIR/docker/\$ui\" ]; then
echo \" Building \$ui...\"
if \$DOCKER build --no-cache -t \"\$ui:latest\" \"$TARGET_DIR/docker/\$ui\" 2>/dev/null; then
if \$DOCKER build --no-cache -t \"\$ui:local\" \"$TARGET_DIR/docker/\$ui\" 2>/dev/null; then
\$DOCKER stop \"\$CONTAINER_NAME\" 2>/dev/null; \$DOCKER rm -f \"\$CONTAINER_NAME\" 2>/dev/null
\$DOCKER run -d --name \"\$CONTAINER_NAME\" \$PORT_ARG --restart unless-stopped \$NET_ARG \"\$ui:latest\"
\$DOCKER run -d --name \"\$CONTAINER_NAME\" \$PORT_ARG --restart unless-stopped \$NET_ARG \"\$ui:local\"
echo \" \$ui created\"
fi
elif \$DOCKER images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -q \"\$ui\"; then

View File

@@ -22,6 +22,9 @@ PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
# Load deploy config (password etc.) - deploy-config.sh is gitignored
[ -f "$SCRIPT_DIR/deploy-config.sh" ] && . "$SCRIPT_DIR/deploy-config.sh"
# Source pinned image versions (single source of truth)
[ -f "$SCRIPT_DIR/image-versions.sh" ] && . "$SCRIPT_DIR/image-versions.sh"
# Configuration
TARGET_HOST="${ARCHIPELAGO_TARGET:-archipelago@192.168.1.228}"
TARGET_DIR="/home/archipelago/archy"
@@ -839,7 +842,7 @@ MANIFEST_EOF
else
# Rebuild and recreate LND UI container (port 8081 so Launch from UI and http://host:8081 both work)
progress "Rebuilding LND UI"
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/lnd-ui && (command -v podman >/dev/null 2>&1 && podman build --no-cache -t lnd-ui:latest . || docker build --no-cache -t lnd-ui:latest .)" 2>&1 | tail -12 | sed 's/^/ /'; then
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/lnd-ui && (command -v podman >/dev/null 2>&1 && podman build --no-cache -t lnd-ui:local . || docker build --no-cache -t lnd-ui:local .)" 2>&1 | tail -12 | sed 's/^/ /'; then
echo " Recreating LND UI container (port 8081)..."
ssh $SSH_OPTS "$TARGET_HOST" '
DOCKER=podman
@@ -847,13 +850,13 @@ MANIFEST_EOF
for c in $($DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -i lnd-ui); do
[ -n "$c" ] && $DOCKER stop "$c" 2>/dev/null; $DOCKER rm -f "$c" 2>/dev/null
done
$DOCKER run -d --name archy-lnd-ui -p 8081:80 --restart unless-stopped lnd-ui:latest
$DOCKER run -d --name archy-lnd-ui -p 8081:80 --restart unless-stopped lnd-ui:local
' 2>&1 | sed 's/^/ /' || true
fi
# Rebuild and recreate ElectrumX UI container (port 50002)
progress "Rebuilding ElectrumX UI"
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/electrs-ui && (command -v podman >/dev/null 2>&1 && podman build --no-cache -t electrs-ui:latest . || docker build --no-cache -t electrs-ui:latest .)" 2>&1 | tail -12 | sed 's/^/ /'; then
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/electrs-ui && (command -v podman >/dev/null 2>&1 && podman build --no-cache -t electrs-ui:local . || docker build --no-cache -t electrs-ui:local .)" 2>&1 | tail -12 | sed 's/^/ /'; then
echo " Recreating ElectrumX UI container (port 50002, host network)..."
ssh $SSH_OPTS "$TARGET_HOST" '
DOCKER=podman
@@ -861,7 +864,7 @@ MANIFEST_EOF
for c in $($DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -i electrs-ui); do
[ -n "$c" ] && $DOCKER stop "$c" 2>/dev/null; $DOCKER rm -f "$c" 2>/dev/null
done
$DOCKER run -d --name archy-electrs-ui --network host --restart unless-stopped electrs-ui:latest
$DOCKER run -d --name archy-electrs-ui --network host --restart unless-stopped electrs-ui:local
' 2>&1 | sed 's/^/ /' || true
fi
@@ -877,7 +880,7 @@ MANIFEST_EOF
sed -i "s|__BITCOIN_RPC_AUTH__|${AUTH_B64}|g" '"$TARGET_DIR"'/docker/bitcoin-ui/nginx.conf
fi
' 2>/dev/null || true
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/bitcoin-ui && (command -v podman >/dev/null 2>&1 && podman build --no-cache -t bitcoin-ui:latest . || docker build --no-cache -t bitcoin-ui:latest .)" 2>&1 | tail -12 | sed 's/^/ /'; then
if ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/docker/bitcoin-ui && (command -v podman >/dev/null 2>&1 && podman build --no-cache -t bitcoin-ui:local . || docker build --no-cache -t bitcoin-ui:local .)" 2>&1 | tail -12 | sed 's/^/ /'; then
echo " Recreating Bitcoin UI container (port 8334, host network)..."
ssh $SSH_OPTS "$TARGET_HOST" '
DOCKER=podman
@@ -885,7 +888,7 @@ MANIFEST_EOF
for c in $($DOCKER ps -a --format "{{.Names}}" 2>/dev/null | grep -i bitcoin-ui); do
[ -n "$c" ] && $DOCKER stop "$c" 2>/dev/null; $DOCKER rm -f "$c" 2>/dev/null
done
$DOCKER run -d --name archy-bitcoin-ui --network host --restart unless-stopped bitcoin-ui:latest
$DOCKER run -d --name archy-bitcoin-ui --network host --restart unless-stopped bitcoin-ui:local
' 2>&1 | sed 's/^/ /' || true
fi
@@ -965,7 +968,7 @@ MANIFEST_EOF
--security-opt no-new-privileges:true \
-p 8332:8332 -p 8333:8333 \
-v /var/lib/archipelago/bitcoin:/home/bitcoin/.bitcoin \
docker.io/bitcoinknots/bitcoin:latest \
${BITCOIN_KNOTS_IMAGE:-docker.io/bitcoinknots/bitcoin:v28.1} \
-server=1 \$BTC_EXTRA_ARGS \
-rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 \
-dbcache=\$BTC_DBCACHE
@@ -1563,7 +1566,7 @@ LNDCONF
$DOCKER run -d --name searxng --restart unless-stopped \
--cap-drop ALL --security-opt no-new-privileges:true \
-p 8888:8080 \
docker.io/searxng/searxng:latest
${SEARXNG_IMAGE:-docker.io/searxng/searxng:2024.11.17}
fi
else
echo " SearXNG already running"

View File

@@ -11,6 +11,9 @@ LOG="/var/log/archipelago-first-boot.log"
DOCKER=podman
command -v podman >/dev/null 2>&1 || DOCKER=docker
# Source pinned image versions (single source of truth)
source /opt/archipelago/image-versions.sh 2>/dev/null || true
# Must run as root for podman
[ "$(id -u)" -eq 0 ] || { echo "Must run as root" >&2; exit 1; }
@@ -252,7 +255,7 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -qE 'bitcoin-knots|arch
--security-opt no-new-privileges:true \
-p 8332:8332 -p 8333:8333 \
-v /var/lib/archipelago/bitcoin:/home/bitcoin/.bitcoin \
docker.io/bitcoinknots/bitcoin:latest \
"${BITCOIN_KNOTS_IMAGE:-docker.io/bitcoinknots/bitcoin:v28.1}" \
-server=1 $BTC_EXTRA_ARGS \
-rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0:8332 \
-proxy=host.containers.internal:9050 -listen=1 -bind=0.0.0.0:8333 \
@@ -339,16 +342,16 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q electrs-ui; then
log "Starting ElectrumX UI from pre-built image..."
$DOCKER run -d --name archy-electrs-ui --network host --restart unless-stopped \
--health-cmd="curl -sf http://localhost:80/ || exit 1" --health-interval=30s --health-timeout=5s --health-retries=3 \
localhost/electrs-ui:latest 2>>"$LOG" || \
localhost/electrs-ui:local 2>>"$LOG" || \
$DOCKER run -d --name archy-electrs-ui --network host --restart unless-stopped \
--health-cmd="curl -sf http://localhost:80/ || exit 1" --health-interval=30s --health-timeout=5s --health-retries=3 \
electrs-ui:latest 2>>"$LOG" || true
electrs-ui:local 2>>"$LOG" || true
elif [ -d /opt/archipelago/docker/electrs-ui ]; then
log "Building and starting ElectrumX UI from source..."
$DOCKER build -t electrs-ui:latest /opt/archipelago/docker/electrs-ui 2>>"$LOG" && \
$DOCKER build -t electrs-ui:local /opt/archipelago/docker/electrs-ui 2>>"$LOG" && \
$DOCKER run -d --name archy-electrs-ui --network host --restart unless-stopped \
--health-cmd="curl -sf http://localhost:80/ || exit 1" --health-interval=30s --health-timeout=5s --health-retries=3 \
electrs-ui:latest 2>>"$LOG" || true
electrs-ui:local 2>>"$LOG" || true
else
log "ElectrumX UI: no image or source found, skipping"
fi
@@ -583,7 +586,7 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q photoprism; then
--security-opt no-new-privileges:true \
-p 2342:2342 -v /var/lib/archipelago/photoprism:/photoprism/storage \
-e PHOTOPRISM_ADMIN_PASSWORD=archipelago -e PHOTOPRISM_DEFAULT_LOCALE=en \
docker.io/photoprism/photoprism:latest 2>>"$LOG" || true
"${PHOTOPRISM_IMAGE:-docker.io/photoprism/photoprism:240915}" 2>>"$LOG" || true
fi
if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q ollama; then
log "Creating Ollama..."
@@ -594,7 +597,7 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q ollama; then
--cap-drop ALL --security-opt no-new-privileges:true \
--read-only --tmpfs /tmp:rw,noexec,nosuid,size=256m --tmpfs /run:rw,noexec,nosuid,size=64m \
-p 11434:11434 -v /var/lib/archipelago/ollama:/root/.ollama \
docker.io/ollama/ollama:latest 2>>"$LOG" || true
"${OLLAMA_IMAGE:-docker.io/ollama/ollama:0.5.4}" 2>>"$LOG" || true
fi
if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q vaultwarden; then
log "Creating Vaultwarden..."
@@ -626,7 +629,7 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q searxng; then
--cap-drop ALL --security-opt no-new-privileges:true \
--read-only --tmpfs /tmp:rw,noexec,nosuid,size=256m --tmpfs /run:rw,noexec,nosuid,size=64m \
-p 8888:8080 \
docker.io/searxng/searxng:latest 2>>"$LOG" || true
"${SEARXNG_IMAGE:-docker.io/searxng/searxng:2024.11.17}" 2>>"$LOG" || true
fi
if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q onlyoffice; then
log "Creating OnlyOffice..."
@@ -658,7 +661,7 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q nginx-proxy-manager;
-p 81:81 -p 8084:80 -p 8443:443 \
-v /var/lib/archipelago/nginx-proxy-manager/data:/data \
-v /var/lib/archipelago/nginx-proxy-manager/letsencrypt:/etc/letsencrypt \
docker.io/jc21/nginx-proxy-manager:latest 2>>"$LOG" || true
"${NPM_IMAGE:-docker.io/jc21/nginx-proxy-manager:2}" 2>>"$LOG" || true
fi
if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q portainer; then
log "Creating Portainer..."
@@ -772,7 +775,7 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q penpot-frontend; the
-e PENPOT_OBJECTS_STORAGE_BACKEND=fs \
-e PENPOT_OBJECTS_STORAGE_FS_DIRECTORY=/opt/data/assets \
-e PENPOT_FLAGS=disable-email-verification enable-smtp enable-prepl-server disable-secure-session-cookies \
docker.io/penpotapp/backend:latest 2>>"$LOG" || true
"${PENPOT_BACKEND_IMAGE:-docker.io/penpotapp/backend:2.4.2}" 2>>"$LOG" || true
sleep 5
fi
if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q penpot-exporter; then
@@ -782,7 +785,7 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q penpot-frontend; the
-e PENPOT_SECRET_KEY=archipelago-penpot-secret-key-change-in-production \
-e PENPOT_PUBLIC_URI=http://penpot-frontend:8080 \
-e PENPOT_REDIS_URI=redis://penpot-valkey/0 \
docker.io/penpotapp/exporter:latest 2>>"$LOG" || true
"${PENPOT_EXPORTER_IMAGE:-docker.io/penpotapp/exporter:2.4.2}" 2>>"$LOG" || true
sleep 2
fi
if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q penpot-frontend; then
@@ -792,7 +795,7 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q penpot-frontend; the
-p 9001:8080 -v /var/lib/archipelago/penpot-assets:/opt/data/assets \
-e PENPOT_PUBLIC_URI="http://${TARGET_IP}:9001" \
-e PENPOT_FLAGS=disable-email-verification enable-smtp enable-prepl-server disable-secure-session-cookies \
docker.io/penpotapp/frontend:latest 2>>"$LOG" || true
"${PENPOT_FRONTEND_IMAGE:-docker.io/penpotapp/frontend:2.4.2}" 2>>"$LOG" || true
fi
fi
@@ -806,7 +809,7 @@ if $DOCKER images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -q 'nos
--health-cmd="curl -sf http://localhost:8080/ || exit 1" --health-interval=30s --health-timeout=5s --health-retries=3 \
--memory=$(mem_limit nostr-rs-relay) \
-p 7047:7047 -v /var/lib/archipelago/nostr-rs-relay:/data \
scsibug/nostr-rs-relay:latest 2>>"$LOG" || true
"${NOSTR_RS_RELAY_IMAGE:-docker.io/scsibug/nostr-rs-relay:0.9.0}" 2>>"$LOG" || true
fi
fi
if $DOCKER images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -q 'strfry'; then
@@ -817,7 +820,7 @@ if $DOCKER images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -q 'str
--health-cmd="curl -sf http://localhost:7777/ || exit 1" --health-interval=30s --health-timeout=5s --health-retries=3 \
--memory=$(mem_limit strfry) \
-p 7777:7777 -v /var/lib/archipelago/strfry:/data \
hoytech/strfry:latest 2>>"$LOG" || true
"${STRFRY_IMAGE:-docker.io/pluja/strfry:latest}" 2>>"$LOG" || true
fi
fi
@@ -826,10 +829,10 @@ if ! $DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q indeedhub; then
INDEEDHUB_IMAGE=""
# Try local image first (pre-built or loaded from ISO)
if $DOCKER images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -q 'localhost/indeedhub'; then
INDEEDHUB_IMAGE="localhost/indeedhub:latest"
INDEEDHUB_IMAGE="localhost/indeedhub:local"
# Try registry image
elif $DOCKER pull git.tx1138.com/lfg2025/indeedhub:latest 2>>"$LOG"; then
INDEEDHUB_IMAGE="git.tx1138.com/lfg2025/indeedhub:latest"
elif $DOCKER pull git.tx1138.com/lfg2025/indeedhub:local 2>>"$LOG"; then
INDEEDHUB_IMAGE="git.tx1138.com/lfg2025/indeedhub:local"
fi
if [ -n "$INDEEDHUB_IMAGE" ]; then
log "Creating Indeehub from $INDEEDHUB_IMAGE..."
@@ -871,13 +874,13 @@ for ui in bitcoin-ui lnd-ui; do
$DOCKER run -d --name "$CONTAINER_NAME" $PORT_ARG --restart unless-stopped --memory=$(mem_limit "$CONTAINER_NAME") $NET_ARG "$IMG" 2>>"$LOG" || true
elif [ -d "/opt/archipelago/docker/$ui" ]; then
log "Building $ui from source (/opt/archipelago/docker/$ui)..."
if $DOCKER build -t "$ui:latest" "/opt/archipelago/docker/$ui" 2>>"$LOG"; then
$DOCKER run -d --name "$CONTAINER_NAME" $PORT_ARG --restart unless-stopped --memory=$(mem_limit "$CONTAINER_NAME") $NET_ARG "$ui:latest" 2>>"$LOG" || true
if $DOCKER build -t "$ui:local" "/opt/archipelago/docker/$ui" 2>>"$LOG"; then
$DOCKER run -d --name "$CONTAINER_NAME" $PORT_ARG --restart unless-stopped --memory=$(mem_limit "$CONTAINER_NAME") $NET_ARG "$ui:local" 2>>"$LOG" || true
fi
elif [ -d "/home/archipelago/archy/docker/$ui" ]; then
log "Building $ui from source (/home/archipelago/archy/docker/$ui)..."
if $DOCKER build -t "$ui:latest" "/home/archipelago/archy/docker/$ui" 2>>"$LOG"; then
$DOCKER run -d --name "$CONTAINER_NAME" $PORT_ARG --restart unless-stopped --memory=$(mem_limit "$CONTAINER_NAME") $NET_ARG "$ui:latest" 2>>"$LOG" || true
if $DOCKER build -t "$ui:local" "/home/archipelago/archy/docker/$ui" 2>>"$LOG"; then
$DOCKER run -d --name "$CONTAINER_NAME" $PORT_ARG --restart unless-stopped --memory=$(mem_limit "$CONTAINER_NAME") $NET_ARG "$ui:local" 2>>"$LOG" || true
fi
else
log "$ui: no image or source found, skipping"

View File

@@ -1,6 +1,10 @@
#!/bin/bash
set -e
# Source pinned image versions (single source of truth)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
[ -f "$SCRIPT_DIR/image-versions.sh" ] && . "$SCRIPT_DIR/image-versions.sh"
# Fix corrupted IndeedHub containers + SearXNG
# All images were exported as the same (wrong) image during multi-node deploy.
# This script: stops broken containers, removes them, recreates with correct images.
@@ -24,7 +28,7 @@ fi
# Verify correct images are available
echo "Verifying images..."
for img in "docker.io/library/redis:7-alpine" "docker.io/minio/minio:latest" "docker.io/library/postgres:16-alpine" "docker.io/scsibug/nostr-rs-relay:latest" "docker.io/searxng/searxng:latest" "localhost/indeedhub:latest" "localhost/indeedhub-build_api:latest" "localhost/indeedhub-build_ffmpeg-worker:latest"; do
for img in "${INDEEDHUB_REDIS_IMAGE:-docker.io/library/redis:7-alpine}" "${MINIO_IMAGE:-docker.io/minio/minio:RELEASE.2024-11-07T00-52-20Z}" "${INDEEDHUB_POSTGRES_IMAGE:-docker.io/library/postgres:16-alpine}" "${NOSTR_RS_RELAY_IMAGE:-docker.io/scsibug/nostr-rs-relay:0.9.0}" "${SEARXNG_IMAGE:-docker.io/searxng/searxng:2024.11.17}" "localhost/indeedhub:local" "localhost/indeedhub-build_api:local" "localhost/indeedhub-build_ffmpeg-worker:local"; do
if ! podman image exists "$img" 2>/dev/null; then
echo "ERROR: Missing image $img"
exit 1
@@ -88,7 +92,7 @@ podman run -d --name indeedhub-minio \
-v indeedhub-minio-data:/data \
-e MINIO_ROOT_USER=indeeadmin \
-e MINIO_ROOT_PASSWORD=indeeadmin2026 \
docker.io/minio/minio:latest \
"${MINIO_IMAGE:-docker.io/minio/minio:RELEASE.2024-11-07T00-52-20Z}" \
server /data --console-address ":9001"
# 4. Nostr Relay
@@ -97,7 +101,7 @@ podman run -d --name indeedhub-relay \
--restart unless-stopped \
--network "$NETWORK" --network-alias relay \
-v indeedhub-relay-data:/usr/src/app/db \
docker.io/scsibug/nostr-rs-relay:latest
"${NOSTR_RS_RELAY_IMAGE:-docker.io/scsibug/nostr-rs-relay:0.9.0}"
# 5. API
echo "Creating api..."
@@ -137,7 +141,7 @@ podman run -d --name indeedhub-build_api_1 \
--health-timeout 30s \
--health-retries 5 \
--health-start-period 60s \
localhost/indeedhub-build_api:latest \
localhost/indeedhub-build_api:local \
sh -c "echo 'Running database migrations...' && npx typeorm migration:run -d dist/database/ormconfig.js && echo 'Migrations complete.' && npm run start:prod"
# 6. FFmpeg Worker
@@ -162,7 +166,7 @@ podman run -d --name indeedhub-build_ffmpeg-worker_1 \
-e S3_PUBLIC_BUCKET_NAME=indeedhub-public \
-e S3_PUBLIC_BUCKET_URL=/storage \
-e AES_MASTER_SECRET=0123456789abcdef0123456789abcdef \
localhost/indeedhub-build_ffmpeg-worker:latest
localhost/indeedhub-build_ffmpeg-worker:local
# 7. IndeedHub Frontend
echo "Creating indeedhub frontend..."
@@ -175,7 +179,7 @@ podman run -d --name indeedhub \
--label "com.archipelago.version=0.1.0" \
--label "com.archipelago.category=media" \
--label "com.archipelago.port=7777" \
localhost/indeedhub:latest
localhost/indeedhub:local
# Fix IndeedHub for iframe: remove X-Frame-Options, inject nostr-provider, hardcode container IPs
sleep 3
@@ -223,7 +227,7 @@ echo "Creating searxng..."
podman run -d --name searxng \
--restart unless-stopped \
-p 8888:8080 \
docker.io/searxng/searxng:latest
"${SEARXNG_IMAGE:-docker.io/searxng/searxng:2024.11.17}"
echo ""
echo "=== Verifying container status ==="

67
scripts/image-versions.sh Normal file
View File

@@ -0,0 +1,67 @@
#!/bin/bash
# Container image versions — single source of truth
# Source this file from all scripts that create containers
#
# Usage: source /opt/archipelago/image-versions.sh 2>/dev/null || true
# source "$(dirname "$0")/image-versions.sh" 2>/dev/null || true
# Bitcoin stack
BITCOIN_KNOTS_IMAGE="docker.io/bitcoinknots/bitcoin:v28.1"
LND_IMAGE="docker.io/lightninglabs/lnd:v0.18.5-beta"
ELECTRUMX_IMAGE="docker.io/lukechilds/electrumx:v1.16.0"
# Mempool stack
MEMPOOL_API_IMAGE="docker.io/mempool/frontend:v3.0.0"
MEMPOOL_WEB_IMAGE="docker.io/mempool/frontend:v3.0.0"
MARIADB_IMAGE="docker.io/library/mariadb:11.4"
# BTCPay
BTCPAY_IMAGE="docker.io/btcpayserver/btcpayserver:1.14.5"
NBXPLORER_IMAGE="docker.io/nicolasdorier/nbxplorer:2.5.13"
POSTGRES_IMAGE="docker.io/library/postgres:16"
# Apps
HOMEASSISTANT_IMAGE="ghcr.io/home-assistant/home-assistant:2024.12"
GRAFANA_IMAGE="docker.io/grafana/grafana:11.4.0"
UPTIME_KUMA_IMAGE="docker.io/louislam/uptime-kuma:1"
JELLYFIN_IMAGE="docker.io/jellyfin/jellyfin:10.10.3"
PHOTOPRISM_IMAGE="docker.io/photoprism/photoprism:240915"
OLLAMA_IMAGE="docker.io/ollama/ollama:0.5.4"
VAULTWARDEN_IMAGE="docker.io/vaultwarden/server:1.32.5"
NEXTCLOUD_IMAGE="docker.io/library/nextcloud:30"
SEARXNG_IMAGE="docker.io/searxng/searxng:2024.11.17"
ONLYOFFICE_IMAGE="docker.io/onlyoffice/documentserver:8.2"
FILEBROWSER_IMAGE="docker.io/filebrowser/filebrowser:v2"
NPM_IMAGE="docker.io/jc21/nginx-proxy-manager:2"
PORTAINER_IMAGE="docker.io/portainer/portainer-ce:2.21.5"
# Networking
TAILSCALE_IMAGE="docker.io/tailscale/tailscale:v1.78.3"
ALPINE_TOR_IMAGE="docker.io/andrius/alpine-tor:0.4.8.13"
ADGUARDHOME_IMAGE="docker.io/adguard/adguardhome:v0.107.55"
# Fedimint
FEDIMINT_IMAGE="docker.io/fedimint/fedimintd:v0.5.1"
FEDIMINT_GATEWAY_IMAGE="docker.io/fedimint/gatewayd:v0.5.1"
# Media
IMMICH_IMAGE="ghcr.io/immich-app/immich-server:v1.123.0"
REDIS_IMAGE="docker.io/library/redis:7"
# Penpot
PENPOT_BACKEND_IMAGE="docker.io/penpotapp/backend:2.4.2"
PENPOT_FRONTEND_IMAGE="docker.io/penpotapp/frontend:2.4.2"
PENPOT_EXPORTER_IMAGE="docker.io/penpotapp/exporter:2.4.2"
VALKEY_IMAGE="docker.io/valkey/valkey:8"
# Nostr
NOSTR_RS_RELAY_IMAGE="docker.io/scsibug/nostr-rs-relay:0.9.0"
STRFRY_IMAGE="docker.io/pluja/strfry:latest" # No stable tag available yet
# IndeedHub stack (local builds use :local tag, not :latest)
MINIO_IMAGE="docker.io/minio/minio:RELEASE.2024-11-07T00-52-20Z"
INDEEDHUB_POSTGRES_IMAGE="docker.io/library/postgres:16-alpine"
INDEEDHUB_REDIS_IMAGE="docker.io/library/redis:7-alpine"
# Base images
NGINX_ALPINE_IMAGE="docker.io/library/nginx:alpine"