#!/bin/bash set -e # 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. echo "=== IndeedHub Container Fix Script ===" # Detect node IP (Tailscale or LAN) NODE_IP=$(hostname -I | awk '{for(i=1;i<=NF;i++) if($i ~ /^100\./) print $i}') if [ -z "$NODE_IP" ]; then NODE_IP=$(hostname -I | awk '{print $1}') fi echo "Node IP: $NODE_IP" NETWORK="indeedhub-build_indeedhub-network" # Load custom images if tar exists if [ -f /tmp/indeedhub-images.tar ]; then echo "Loading custom images from tar..." sudo podman load < /tmp/indeedhub-images.tar 2>&1 | tail -5 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 if ! sudo podman image exists "$img" 2>/dev/null; then echo "ERROR: Missing image $img" exit 1 fi done echo "All images verified." # Ensure network exists if ! sudo podman network exists "$NETWORK" 2>/dev/null; then echo "Creating network $NETWORK..." sudo podman network create "$NETWORK" 2>/dev/null || true fi # Stop all affected containers echo "Stopping containers..." for c in indeedhub indeedhub-build_api_1 indeedhub-build_ffmpeg-worker_1 indeedhub-relay indeedhub-redis indeedhub-minio indeedhub-postgres searxng; do sudo podman stop "$c" 2>/dev/null || true done # Remove all affected containers echo "Removing containers..." for c in indeedhub indeedhub-build_api_1 indeedhub-build_ffmpeg-worker_1 indeedhub-relay indeedhub-redis indeedhub-minio indeedhub-postgres searxng; do sudo podman rm -f "$c" 2>/dev/null || true done # 1. PostgreSQL (must start first — others depend on it) echo "Creating postgres..." sudo podman run -d --name indeedhub-postgres \ --restart unless-stopped \ --network "$NETWORK" --network-alias postgres \ -v indeedhub-postgres-data:/var/lib/postgresql/data \ -e POSTGRES_USER=indeedhub \ -e POSTGRES_PASSWORD=indeehhub-archy-2026 \ -e POSTGRES_DB=indeedhub \ docker.io/library/postgres:16-alpine # Wait for postgres to be ready echo "Waiting for postgres..." for i in $(seq 1 15); do if sudo podman exec indeedhub-postgres pg_isready -U indeedhub 2>/dev/null; then echo "Postgres ready." break fi sleep 2 done # 2. Redis echo "Creating redis..." sudo podman run -d --name indeedhub-redis \ --restart unless-stopped \ --network "$NETWORK" --network-alias redis \ -v indeedhub-redis-data:/data \ docker.io/library/redis:7-alpine \ redis-server --appendonly yes # 3. MinIO echo "Creating minio..." sudo podman run -d --name indeedhub-minio \ --restart unless-stopped \ --network "$NETWORK" --network-alias minio \ -v indeedhub-minio-data:/data \ -e MINIO_ROOT_USER=indeeadmin \ -e MINIO_ROOT_PASSWORD=indeeadmin2026 \ docker.io/minio/minio:latest \ server /data --console-address ":9001" # 4. Nostr Relay echo "Creating relay..." sudo 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 # 5. API echo "Creating api..." sudo podman run -d --name indeedhub-build_api_1 \ --restart unless-stopped \ --network "$NETWORK" --network-alias api \ -e ENVIRONMENT=production \ -e PORT=4000 \ -e DOMAIN="$NODE_IP" \ -e FRONTEND_URL="http://$NODE_IP" \ -e DATABASE_HOST=postgres \ -e DATABASE_PORT=5432 \ -e DATABASE_USER=indeedhub \ -e DATABASE_PASSWORD=indeehhub-archy-2026 \ -e DATABASE_NAME=indeedhub \ -e QUEUE_HOST=redis \ -e QUEUE_PORT=6379 \ -e "QUEUE_PASSWORD=" \ -e S3_ENDPOINT=http://minio:9000 \ -e AWS_REGION=us-east-1 \ -e AWS_ACCESS_KEY=indeeadmin \ -e AWS_SECRET_KEY=indeeadmin2026 \ -e S3_PRIVATE_BUCKET_NAME=indeedhub-private \ -e S3_PUBLIC_BUCKET_NAME=indeedhub-public \ -e S3_PUBLIC_BUCKET_URL=/storage \ -e "BTCPAY_URL=" \ -e "BTCPAY_API_KEY=" \ -e "BTCPAY_STORE_ID=" \ -e "BTCPAY_WEBHOOK_SECRET=" \ -e NOSTR_JWT_SECRET=archipelago-indeehhub-jwt-secret-2026 \ -e NOSTR_JWT_EXPIRES_IN=7d \ -e AES_MASTER_SECRET=0123456789abcdef0123456789abcdef \ -e "ADMIN_API_KEY=" \ -e NODE_OPTIONS=--max-old-space-size=1024 \ --health-cmd "wget --no-verbose --tries=1 --spider http://localhost:4000/nostr-auth/health || exit 1" \ --health-interval 60s \ --health-timeout 30s \ --health-retries 5 \ --health-start-period 60s \ localhost/indeedhub-build_api:latest \ 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 echo "Creating ffmpeg-worker..." sudo podman run -d --name indeedhub-build_ffmpeg-worker_1 \ --restart unless-stopped \ --network "$NETWORK" --network-alias ffmpeg-worker \ -e ENVIRONMENT=production \ -e DATABASE_HOST=postgres \ -e DATABASE_PORT=5432 \ -e DATABASE_USER=indeedhub \ -e DATABASE_PASSWORD=indeehhub-archy-2026 \ -e DATABASE_NAME=indeedhub \ -e QUEUE_HOST=redis \ -e QUEUE_PORT=6379 \ -e "QUEUE_PASSWORD=" \ -e S3_ENDPOINT=http://minio:9000 \ -e AWS_REGION=us-east-1 \ -e AWS_ACCESS_KEY=indeeadmin \ -e AWS_SECRET_KEY=indeeadmin2026 \ -e S3_PRIVATE_BUCKET_NAME=indeedhub-private \ -e S3_PUBLIC_BUCKET_NAME=indeedhub-public \ -e S3_PUBLIC_BUCKET_URL=/storage \ -e AES_MASTER_SECRET=0123456789abcdef0123456789abcdef \ localhost/indeedhub-build_ffmpeg-worker:latest # 7. IndeedHub Frontend echo "Creating indeedhub frontend..." sudo podman run -d --name indeedhub \ --restart unless-stopped \ --network "$NETWORK" \ -p 7777:7777 \ --label "com.archipelago.app=indeedhub" \ --label "com.archipelago.title=IndeedHub" \ --label "com.archipelago.version=0.1.0" \ --label "com.archipelago.category=media" \ --label "com.archipelago.port=7777" \ localhost/indeedhub:latest # Fix IndeedHub for iframe: remove X-Frame-Options, inject nostr-provider, hardcode container IPs sleep 3 if sudo podman ps --format '{{.Names}}' 2>/dev/null | grep -q "^indeedhub$"; then sudo podman exec indeedhub sed -i "/X-Frame-Options/d" /etc/nginx/conf.d/default.conf 2>/dev/null || true # Inject nostr-provider.js if available if [ -f /opt/archipelago/web-ui/nostr-provider.js ]; then sudo podman cp /opt/archipelago/web-ui/nostr-provider.js indeedhub:/usr/share/nginx/html/nostr-provider.js 2>/dev/null || true fi # Add nostr-provider location block + sub_filter if ! sudo podman exec indeedhub grep -q "nostr-provider" /etc/nginx/conf.d/default.conf 2>/dev/null; then sudo podman exec indeedhub cat /etc/nginx/conf.d/default.conf > /tmp/ih-nginx.conf 2>/dev/null sed -i "/location = \/sw.js {/i\\ location = /nostr-provider.js {\n add_header Cache-Control \"no-cache, no-store, must-revalidate\";\n expires off;\n }\n" /tmp/ih-nginx.conf sed -i "/try_files.*index.html/a\\ sub_filter_once on;\n sub_filter '' '';" /tmp/ih-nginx.conf sudo podman cp /tmp/ih-nginx.conf indeedhub:/etc/nginx/conf.d/default.conf 2>/dev/null || true rm -f /tmp/ih-nginx.conf fi # Replace DNS-based upstream resolution with hardcoded container IPs # (podman DNS resolver 127.0.0.11 is unreliable, causing 502 errors) API_IP=$(sudo podman inspect indeedhub-build_api_1 --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null) MINIO_IP=$(sudo podman inspect indeedhub-minio --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null) RELAY_IP=$(sudo podman inspect indeedhub-relay --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null) if [ -n "$API_IP" ] && [ -n "$MINIO_IP" ] && [ -n "$RELAY_IP" ]; then sudo podman exec indeedhub cat /etc/nginx/conf.d/default.conf > /tmp/ih-nginx.conf 2>/dev/null sed -i "s|resolver 127.0.0.11 valid=30s ipv6=off;||g" /tmp/ih-nginx.conf sed -i "s|set \$api_upstream http://api:4000;|set \$api_upstream http://$API_IP:4000;|g" /tmp/ih-nginx.conf sed -i "s|set \$minio_upstream http://minio:9000;|set \$minio_upstream http://$MINIO_IP:9000;|g" /tmp/ih-nginx.conf sed -i "s|set \$relay_upstream http://relay:8080;|set \$relay_upstream http://$RELAY_IP:8080;|g" /tmp/ih-nginx.conf sed -i "s|proxy_set_header Host \$host;|proxy_set_header Host \$http_host;|g" /tmp/ih-nginx.conf sudo podman cp /tmp/ih-nginx.conf indeedhub:/etc/nginx/conf.d/default.conf 2>/dev/null || true rm -f /tmp/ih-nginx.conf echo "Patched IndeedHub nginx with container IPs (API=$API_IP MINIO=$MINIO_IP RELAY=$RELAY_IP)" fi sudo podman exec indeedhub nginx -s reload 2>/dev/null || true echo "Applied IndeedHub iframe fix." fi # 8. SearXNG (standalone — no cap-drop ALL, searxng needs write access to /etc/searxng/) echo "Creating searxng..." sudo podman run -d --name searxng \ --restart unless-stopped \ -p 8888:8080 \ docker.io/searxng/searxng:latest echo "" echo "=== Verifying container status ===" sleep 5 sudo podman ps -a --filter name=indeedhub --filter name=searxng --format "table {{.Names}}\t{{.Status}}" 2>&1 echo "" echo "=== FIX COMPLETE ==="