diff --git a/.cursor/rules/Development-Workflow.mdc b/.cursor/rules/Development-Workflow.mdc index 4831d917..f8be59ba 100644 --- a/.cursor/rules/Development-Workflow.mdc +++ b/.cursor/rules/Development-Workflow.mdc @@ -11,7 +11,11 @@ alwaysApply: true 1. **Make the change** the user requests 2. **SSH and build to live server** - Run `./scripts/deploy-to-target.sh --live` once done -3. **Test that it works** - Verify apps launch and show their UI in a new browser tab on their server port (e.g. http://192.168.1.228:4080 for Mempool) +3. **Test that it works** - Verify apps launch: iframe for most apps, new tab for BTCPay/Home Assistant + +## App Launcher (iframe + new tab fallback) + +Most apps launch in the iframe overlay. BTCPay (port 23000) and Home Assistant (port 8123) set `X-Frame-Options` and don't support subpath proxying—they open in a new tab instead. 4. **If broken, fix and repeat** - Debug, fix, redeploy, and test again until complete 5. **End loop** only when everything works diff --git a/core/archipelago/src/api/rpc.rs b/core/archipelago/src/api/rpc.rs index daa38ba4..c321354a 100644 --- a/core/archipelago/src/api/rpc.rs +++ b/core/archipelago/src/api/rpc.rs @@ -1251,8 +1251,8 @@ fn get_app_config( "ELECTRUM_TLS_ENABLED=false".to_string(), format!("CORE_RPC_HOST={}", host_ip), "CORE_RPC_PORT=8332".to_string(), - "CORE_RPC_USERNAME=bitcoin".to_string(), - "CORE_RPC_PASSWORD=bitcoinpass".to_string(), + "CORE_RPC_USERNAME=archipelago".to_string(), + "CORE_RPC_PASSWORD=archipelago123".to_string(), "DATABASE_ENABLED=true".to_string(), "DATABASE_HOST=archy-mempool-db".to_string(), "DATABASE_DATABASE=mempool".to_string(), @@ -1271,7 +1271,7 @@ fn get_app_config( "--daemon-rpc-addr".to_string(), format!("{}:8332", host_ip), "--cookie".to_string(), - "bitcoin:bitcoinpass".to_string(), + "archipelago:archipelago123".to_string(), "--jsonrpc-import".to_string(), "--electrum-rpc-addr".to_string(), "0.0.0.0:50001".to_string(), @@ -1428,8 +1428,8 @@ fn get_app_config( vec!["/var/lib/archipelago/fedimint:/data".to_string()], vec![ "FM_DATA_DIR=/data".to_string(), - "FM_BITCOIND_USERNAME=bitcoin".to_string(), - "FM_BITCOIND_PASSWORD=bitcoinpass".to_string(), + "FM_BITCOIND_USERNAME=archipelago".to_string(), + "FM_BITCOIND_PASSWORD=archipelago123".to_string(), "FM_BITCOIN_NETWORK=bitcoin".to_string(), "FM_BIND_P2P=0.0.0.0:8173".to_string(), "FM_BIND_API=0.0.0.0:8174".to_string(), diff --git a/image-recipe/build-auto-installer-iso.sh b/image-recipe/build-auto-installer-iso.sh index acc9d197..5a4d2e55 100755 --- a/image-recipe/build-auto-installer-iso.sh +++ b/image-recipe/build-auto-installer-iso.sh @@ -499,7 +499,7 @@ mkdir -p "$IMAGES_DIR" IMAGES_CAPTURED_FROM_SERVER=0 if [ -n "$DEV_SERVER" ] && [ "$DEV_SERVER" != "localhost" ] && [ "$DEV_SERVER" != "127.0.0.1" ]; then echo " Capturing container images from live server ($DEV_SERVER)..." - CAPTURE_PATTERNS="bitcoin-ui bitcoin-knots lnd lnd-ui filebrowser mempool mempool-electrs tailscale homeassistant btcpayserver nostr-rs-relay strfry alpine-tor" + CAPTURE_PATTERNS="bitcoin-ui bitcoin-knots lnd lnd-ui filebrowser mempool mempool-electrs tailscale homeassistant btcpayserver nbxplorer postgres nostr-rs-relay strfry alpine-tor" REMOTE_TMP="/tmp/archipelago-image-capture-$$" SAVED_LIST=$(ssh "$DEV_SERVER" "mkdir -p $REMOTE_TMP && for p in $CAPTURE_PATTERNS; do img=\$(sudo podman images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -i \"\$p\" | head -1); [ -n \"\$img\" ] && sudo podman save -o \"$REMOTE_TMP/\$p.tar\" \"\$img\" 2>/dev/null && echo \"\$p\"; done" 2>/dev/null) || true for p in $SAVED_LIST; do @@ -521,6 +521,8 @@ bitcoinknots/bitcoin:29 bitcoin-knots.tar lightninglabs/lnd:v0.18.4-beta lnd.tar ghcr.io/home-assistant/home-assistant:stable homeassistant.tar btcpayserver/btcpayserver:latest btcpayserver.tar +docker.io/nicolasdorier/nbxplorer:2.6.0 nbxplorer.tar +docker.io/library/postgres:16 postgres-btcpay.tar mempool/frontend:latest mempool-frontend.tar mempool/backend:v2.5.0 mempool-backend.tar mempool/electrs:latest mempool-electrs.tar diff --git a/neode-ui/dev-dist/sw.js b/neode-ui/dev-dist/sw.js index 33e219c6..90c13824 100644 --- a/neode-ui/dev-dist/sw.js +++ b/neode-ui/dev-dist/sw.js @@ -82,7 +82,7 @@ define(['./workbox-21a80088'], (function (workbox) { 'use strict'; "revision": "3ca0b8505b4bec776b69afdba2768812" }, { "url": "index.html", - "revision": "0.uegfpird2pk" + "revision": "0.dbmr9lf4rv4" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { diff --git a/neode-ui/public/assets/video/Kratter.MP3 b/neode-ui/public/assets/video/Kratter.MP3 new file mode 100644 index 00000000..3c79dbf5 Binary files /dev/null and b/neode-ui/public/assets/video/Kratter.MP3 differ diff --git a/neode-ui/src/stores/appLauncher.ts b/neode-ui/src/stores/appLauncher.ts index ba57d1c3..98a38645 100644 --- a/neode-ui/src/stores/appLauncher.ts +++ b/neode-ui/src/stores/appLauncher.ts @@ -1,13 +1,27 @@ import { defineStore } from 'pinia' import { ref } from 'vue' +/** BTCPay and Home Assistant set X-Frame-Options and don't support subpath proxy - open in new tab */ +function mustOpenInNewTab(url: string): boolean { + try { + const u = new URL(url) + return u.port === '23000' || u.port === '8123' + } catch { + return false + } +} + export const useAppLauncherStore = defineStore('appLauncher', () => { const isOpen = ref(false) const url = ref('') const title = ref('') let previousActiveElement: HTMLElement | null = null - function open(payload: { url: string; title: string }) { + function open(payload: { url: string; title: string; openInNewTab?: boolean }) { + if (payload.openInNewTab || mustOpenInNewTab(payload.url)) { + window.open(payload.url, '_blank', 'noopener,noreferrer') + return + } previousActiveElement = (document.activeElement as HTMLElement) || null url.value = payload.url title.value = payload.title diff --git a/neode-ui/src/views/AppDetails.vue b/neode-ui/src/views/AppDetails.vue index 94975ebe..847ee50e 100644 --- a/neode-ui/src/views/AppDetails.vue +++ b/neode-ui/src/views/AppDetails.vue @@ -635,8 +635,8 @@ function launchApp() { prod: 'http://localhost:8332' }, 'btcpay-server': { - dev: 'http://localhost:14142', - prod: 'http://localhost:14142' + dev: 'http://localhost:23000', + prod: 'http://localhost:23000' }, 'homeassistant': { dev: 'http://localhost:8123', diff --git a/scripts/deploy-to-target.sh b/scripts/deploy-to-target.sh index 52e31a27..c267bc70 100755 --- a/scripts/deploy-to-target.sh +++ b/scripts/deploy-to-target.sh @@ -202,7 +202,8 @@ if [ "$LIVE" = true ]; then TARGET_IP='$TARGET_IP' NET_OPT='--network archy-net' # Clean any duplicate/old mempool containers (user may have two versions) - for c in mempool mempool-api mempool-electrs mempool-web archy-mempool-api archy-mempool-web; do + # EXCLUDE mempool-electrs - indexing takes days, do not recreate on every deploy + for c in mempool mempool-api mempool-web archy-mempool-api archy-mempool-web; do sudo \$DOCKER stop \$c 2>/dev/null sudo \$DOCKER rm -f \$c 2>/dev/null done @@ -223,26 +224,35 @@ if [ "$LIVE" = true ]; then MYSQL_CNT=\${MYSQL_CNT:-archy-mempool-db} # Ensure DB is on archy-net so mempool-api can resolve it sudo \$DOCKER network connect archy-net \$MYSQL_CNT 2>/dev/null || true - # Create mempool-electrs (indexer - connects to Bitcoin, exposes Electrum protocol on 50001) - for c in \$(sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep mempool-electrs); do - echo ' Recreating mempool-electrs...' - sudo \$DOCKER stop \"\$c\" 2>/dev/null - sudo \$DOCKER rm -f \"\$c\" 2>/dev/null - done + # Create mempool-electrs ONLY if missing - do NOT recreate (indexing takes days, data is 800GB+) + # One-time migration: if on bridge (wrong network), recreate with archy-net so it can reach bitcoin-knots + if sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q mempool-electrs; then + MEMPOOL_ELECTRS_NET=\$(sudo \$DOCKER inspect mempool-electrs --format '{{range \$k, \$v := .NetworkSettings.Networks}}{{\$k}}{{end}}' 2>/dev/null || true) + if [ \"\$MEMPOOL_ELECTRS_NET\" = \"bridge\" ] || [ \"\$MEMPOOL_ELECTRS_NET\" = \"\" ]; then + echo ' Migrating mempool-electrs to archy-net (preserving 800GB+ index)...' + sudo \$DOCKER stop mempool-electrs 2>/dev/null + sudo \$DOCKER rm mempool-electrs 2>/dev/null + fi + fi if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q mempool-electrs; then - echo ' Creating mempool-electrs (indexer - may take hours to sync)...' - sudo mkdir -p /var/lib/archipelago/mempool-electrs - # Use host IP to reach Bitcoin (TARGET_IP:8332) - more reliable than container DNS (bitcoin-knots) - sudo \$DOCKER run -d --name mempool-electrs --restart unless-stopped \ - -p 50001:50001 \ - -v /var/lib/archipelago/mempool-electrs:/data \ - docker.io/mempool/electrs:latest \ - --daemon-rpc-addr \$TARGET_IP:8332 \ - --cookie archipelago:archipelago123 \ - --jsonrpc-import \ - --electrum-rpc-addr 0.0.0.0:50001 \ - --db-dir /data \ - --lightmode + if sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q mempool-electrs; then + echo ' Starting existing mempool-electrs (preserving index)...' + sudo \$DOCKER start mempool-electrs 2>/dev/null || true + else + echo ' Creating mempool-electrs (indexer - may take days to sync, do not recreate)...' + sudo mkdir -p /var/lib/archipelago/mempool-electrs + # Use archy-net + bitcoin-knots for reliable Bitcoin connectivity (not host IP from bridge) + sudo \$DOCKER run -d --name mempool-electrs --restart unless-stopped \$NET_OPT \ + -p 50001:50001 \ + -v /var/lib/archipelago/mempool-electrs:/data \ + docker.io/mempool/electrs:latest \ + --daemon-rpc-addr bitcoin-knots:8332 \ + --cookie archipelago:archipelago123 \ + --jsonrpc-import \ + --electrum-rpc-addr 0.0.0.0:50001 \ + --db-dir /data \ + --lightmode + fi fi # Create/recreate mempool-api (backend on 8999) - required for mempool to work for c in \$(sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E 'mempool-api|archy-mempool-api'); do @@ -288,7 +298,7 @@ if [ "$LIVE" = true ]; then fi " 2>&1 | sed 's/^/ /' || true - # Fix BTCPay Server: requires PostgreSQL; create archy-btcpay-db, recreate btcpay-server with BTCPAY_POSTGRES + # Fix BTCPay Server: requires PostgreSQL + NBXplorer (BTCPay needs NBXplorer for block indexing) echo " Fixing BTCPay Server stack..." TARGET_IP="$(echo "$TARGET_HOST" | cut -d@ -f2)" sshpass -p "$ARCHIPELAGO_PASSWORD" ssh $SSH_OPTS "$TARGET_HOST" " @@ -297,6 +307,8 @@ if [ "$LIVE" = true ]; then TARGET_IP='$TARGET_IP' sudo \$DOCKER network create archy-net 2>/dev/null || true NET_OPT='--network archy-net' + # Ensure bitcoin-knots is on archy-net for NBXplorer/BTCPay to reach it + sudo \$DOCKER network connect archy-net bitcoin-knots 2>/dev/null || true # Create PostgreSQL for BTCPay if missing if ! sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -qE 'archy-btcpay-db|postgres-btcpay'; then echo ' Creating archy-btcpay-db (PostgreSQL)...' @@ -309,12 +321,38 @@ if [ "$LIVE" = true ]; then docker.io/postgres:15-alpine sleep 3 fi - # Recreate btcpay-server with PostgreSQL and Bitcoin RPC - for c in \$(sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -E 'btcpay-server|archy-btcpay'); do - echo ' Recreating btcpay-server with PostgreSQL...' - sudo \$DOCKER stop \"\$c\" 2>/dev/null - sudo \$DOCKER rm -f \"\$c\" 2>/dev/null - break + # Create NBXplorer database in PostgreSQL (NBXplorer needs its own DB) + sudo \$DOCKER exec archy-btcpay-db psql -U postgres -tc \"SELECT 1 FROM pg_database WHERE datname='nbxplorer'\" 2>/dev/null | grep -q 1 || \ + sudo \$DOCKER exec -e PGPASSWORD=btcpaypass archy-btcpay-db psql -U postgres -c \"CREATE DATABASE nbxplorer;\" 2>/dev/null || true + # Create NBXplorer (required by BTCPay - indexes blocks for payment tracking) + if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q archy-nbxplorer; then + if sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q archy-nbxplorer; then + sudo \$DOCKER start archy-nbxplorer 2>/dev/null || true + else + echo ' Creating archy-nbxplorer...' + sudo mkdir -p /var/lib/archipelago/nbxplorer + sudo \$DOCKER run -d --name archy-nbxplorer --restart unless-stopped \$NET_OPT \ + -p 32838:32838 \ + -v /var/lib/archipelago/nbxplorer:/data \ + -e NBXPLORER_DATADIR=/data \ + -e NBXPLORER_NETWORK=mainnet \ + -e NBXPLORER_CHAINS=btc \ + -e NBXPLORER_BIND=0.0.0.0:32838 \ + -e NBXPLORER_BTCRPCURL=http://bitcoin-knots:8332 \ + -e NBXPLORER_BTCRPCUSER=archipelago \ + -e NBXPLORER_BTCRPCPASSWORD=archipelago123 \ + -e NBXPLORER_POSTGRES='User ID=btcpay;Password=btcpaypass;Host=archy-btcpay-db;Port=5432;Database=nbxplorer;Include Error Detail=true' \ + docker.io/nicolasdorier/nbxplorer:2.6.0 + sleep 5 + fi + fi + # Recreate btcpay-server with PostgreSQL, NBXplorer URL, and Bitcoin RPC + for c in btcpay-server archy-btcpay; do + if sudo \$DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -qx \"\$c\"; then + echo ' Recreating btcpay-server with NBXplorer...' + sudo \$DOCKER stop \"\$c\" 2>/dev/null + sudo \$DOCKER rm -f \"\$c\" 2>/dev/null + fi done if ! sudo \$DOCKER ps --format '{{.Names}}' 2>/dev/null | grep -q btcpay-server; then echo ' Creating btcpay-server on 23000...' @@ -326,7 +364,8 @@ if [ "$LIVE" = true ]; then -e BTCPAY_PROTOCOL=http \ -e BTCPAY_HOST=\$TARGET_IP:23000 \ -e BTCPAY_CHAINS=btc \ - -e BTCPAY_BTCRPCURL=http://\$TARGET_IP:8332 \ + -e BTCPAY_BTCEXPLORERURL=http://archy-nbxplorer:32838 \ + -e BTCPAY_BTCRPCURL=http://bitcoin-knots:8332 \ -e BTCPAY_BTCRPCUSER=archipelago \ -e BTCPAY_BTCRPCPASSWORD=archipelago123 \ -e BTCPAY_POSTGRES='User ID=btcpay;Password=btcpaypass;Host=archy-btcpay-db;Port=5432;Database=btcpay;Include Error Detail=true' \