fix: unbundled first-boot, fast VPN status, kiosk relay dedup
- Unbundled ISO: first-boot only creates FileBrowser (marker file .unbundled) Users install apps from Marketplace — no more bitcoin/mempool on clean install - VPN status: read tunnel IP from config file (instant) instead of nvpn status (22s) - Kiosk: App.vue skips remote relay on /kiosk path (prevents duplicate input) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7393c5f158
commit
02ab398726
@ -322,46 +322,26 @@ async fn get_nostr_vpn_status() -> Result<VpnStatus> {
|
|||||||
anyhow::bail!("nostr-vpn service not running");
|
anyhow::bail!("nostr-vpn service not running");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get tunnel IP: try nvpn status first, fall back to config, then interface
|
// Get tunnel IP: config file first (instant), fall back to interface
|
||||||
|
// NOTE: Do NOT call `nvpn status` — it blocks for 20+ seconds connecting to relays
|
||||||
let ip = {
|
let ip = {
|
||||||
// Method 1: nvpn status (most accurate)
|
let cfg_ip = read_nvpn_config_value("node", "tunnel_ip").await;
|
||||||
let status_ip = tokio::process::Command::new("nvpn")
|
if cfg_ip.is_some() {
|
||||||
.args(["status"])
|
cfg_ip
|
||||||
.env("HOME", "/var/lib/archipelago/nostr-vpn")
|
|
||||||
.env("XDG_CONFIG_HOME", "/var/lib/archipelago/nostr-vpn/.config")
|
|
||||||
.output()
|
|
||||||
.await
|
|
||||||
.ok()
|
|
||||||
.and_then(|o| {
|
|
||||||
let out = String::from_utf8_lossy(&o.stdout).to_string();
|
|
||||||
out.lines()
|
|
||||||
.find(|l| l.starts_with("tunnel_ip:"))
|
|
||||||
.map(|l| l.split(':').nth(1).unwrap_or("").trim().to_string())
|
|
||||||
})
|
|
||||||
.filter(|s| !s.is_empty());
|
|
||||||
|
|
||||||
if status_ip.is_some() {
|
|
||||||
status_ip
|
|
||||||
} else {
|
} else {
|
||||||
// Method 2: config file
|
// Fallback: read from network interface
|
||||||
let cfg_ip = read_nvpn_config_value("node", "tunnel_ip").await;
|
tokio::process::Command::new("ip")
|
||||||
if cfg_ip.is_some() {
|
.args(["-4", "addr", "show", "nvpn0"])
|
||||||
cfg_ip
|
.output()
|
||||||
} else {
|
.await
|
||||||
// Method 3: interface IP
|
.ok()
|
||||||
tokio::process::Command::new("ip")
|
.and_then(|o| {
|
||||||
.args(["-4", "addr", "show", "nvpn0"])
|
let out = String::from_utf8_lossy(&o.stdout).to_string();
|
||||||
.output()
|
out.lines()
|
||||||
.await
|
.find(|l| l.contains("inet "))
|
||||||
.ok()
|
.and_then(|l| l.split_whitespace().nth(1))
|
||||||
.and_then(|o| {
|
.map(|s| s.to_string())
|
||||||
let out = String::from_utf8_lossy(&o.stdout).to_string();
|
})
|
||||||
out.lines()
|
|
||||||
.find(|l| l.contains("inet "))
|
|
||||||
.and_then(|l| l.split_whitespace().nth(1))
|
|
||||||
.map(|s| s.to_string())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1150,6 +1150,8 @@ echo ""
|
|||||||
if [ "$UNBUNDLED" = "1" ]; then
|
if [ "$UNBUNDLED" = "1" ]; then
|
||||||
echo "📦 Step 3b: Bundling core containers only (UNBUNDLED mode)"
|
echo "📦 Step 3b: Bundling core containers only (UNBUNDLED mode)"
|
||||||
echo " Optional apps will be downloaded on-demand from the Marketplace after install."
|
echo " Optional apps will be downloaded on-demand from the Marketplace after install."
|
||||||
|
# Marker file: first-boot-containers.sh checks this to skip app creation
|
||||||
|
touch "$ARCH_DIR/.unbundled"
|
||||||
IMAGES_DIR="$ARCH_DIR/container-images"
|
IMAGES_DIR="$ARCH_DIR/container-images"
|
||||||
mkdir -p "$IMAGES_DIR"
|
mkdir -p "$IMAGES_DIR"
|
||||||
# FileBrowser is a core dependency (powers the Cloud file manager) — always bundle it
|
# FileBrowser is a core dependency (powers the Cloud file manager) — always bundle it
|
||||||
@ -2154,6 +2156,12 @@ if [ -d "$BOOT_MEDIA/archipelago/web-ui" ]; then
|
|||||||
cp -r "$BOOT_MEDIA/archipelago/web-ui" /mnt/target/opt/archipelago/
|
cp -r "$BOOT_MEDIA/archipelago/web-ui" /mnt/target/opt/archipelago/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Mark unbundled mode so first-boot only creates FileBrowser (user installs apps from Marketplace)
|
||||||
|
if [ -f "$BOOT_MEDIA/archipelago/.unbundled" ]; then
|
||||||
|
touch /mnt/target/opt/archipelago/.unbundled
|
||||||
|
echo " Unbundled mode: apps install on-demand from Marketplace"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -d "$BOOT_MEDIA/archipelago/apps" ]; then
|
if [ -d "$BOOT_MEDIA/archipelago/apps" ]; then
|
||||||
cp -r "$BOOT_MEDIA/archipelago/apps" /mnt/target/etc/archipelago/
|
cp -r "$BOOT_MEDIA/archipelago/apps" /mnt/target/etc/archipelago/
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -48,6 +48,63 @@ SCRIPT_DIR_FBC="$(cd "$(dirname "$0")" && pwd)"
|
|||||||
# as root (rootful podman), the backend can't see them at all.
|
# as root (rootful podman), the backend can't see them at all.
|
||||||
DOCKER="runuser -u archipelago -- env XDG_RUNTIME_DIR=/run/user/$(id -u archipelago) podman"
|
DOCKER="runuser -u archipelago -- env XDG_RUNTIME_DIR=/run/user/$(id -u archipelago) podman"
|
||||||
|
|
||||||
|
# UNBUNDLED mode: only create FileBrowser, skip all other containers.
|
||||||
|
# Users install apps on-demand from the Marketplace.
|
||||||
|
UNBUNDLED_MARKER="/opt/archipelago/.unbundled"
|
||||||
|
if [ -f "$UNBUNDLED_MARKER" ]; then
|
||||||
|
log "UNBUNDLED mode detected — creating FileBrowser only (apps install from Marketplace)"
|
||||||
|
|
||||||
|
# Core setup: secrets, podman prerequisites, FileBrowser
|
||||||
|
SECRETS_DIR="/var/lib/archipelago/secrets"
|
||||||
|
mkdir -p "$SECRETS_DIR" && chmod 700 "$SECRETS_DIR"
|
||||||
|
if [ ! -f "$SECRETS_DIR/bitcoin-rpc-password" ]; then
|
||||||
|
openssl rand -hex 16 > "$SECRETS_DIR/bitcoin-rpc-password"
|
||||||
|
chmod 600 "$SECRETS_DIR/bitcoin-rpc-password"
|
||||||
|
fi
|
||||||
|
# Generate all DB passwords upfront so they're stable
|
||||||
|
for svc in mempool btcpay mysql-root; do
|
||||||
|
if [ ! -f "$SECRETS_DIR/${svc}-db-password" ]; then
|
||||||
|
openssl rand -hex 16 > "$SECRETS_DIR/${svc}-db-password"
|
||||||
|
chmod 600 "$SECRETS_DIR/${svc}-db-password"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
chown -R 1000:1000 "$SECRETS_DIR"
|
||||||
|
|
||||||
|
# Podman prerequisites
|
||||||
|
loginctl enable-linger archipelago 2>/dev/null || true
|
||||||
|
DOCKER="runuser -u archipelago -- env XDG_RUNTIME_DIR=/run/user/$(id -u archipelago) podman"
|
||||||
|
$DOCKER system migrate 2>/dev/null || true
|
||||||
|
|
||||||
|
# Ensure archy-net exists
|
||||||
|
$DOCKER network create archy-net 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create FileBrowser only
|
||||||
|
if ! $DOCKER ps -a --format '{{.Names}}' 2>/dev/null | grep -q filebrowser; then
|
||||||
|
log "Creating FileBrowser..."
|
||||||
|
mkdir -p /var/lib/archipelago/filebrowser /var/lib/archipelago/filebrowser-data
|
||||||
|
mkdir -p /var/lib/archipelago/data/cloud/{Documents,Photos,Music,Videos,Downloads}
|
||||||
|
sudo chown -R 100000:100000 /var/lib/archipelago/filebrowser
|
||||||
|
sudo chown -R 100000:100000 /var/lib/archipelago/filebrowser-data
|
||||||
|
sudo chown -R 100000:100000 /var/lib/archipelago/data
|
||||||
|
$DOCKER run -d --name filebrowser --restart unless-stopped \
|
||||||
|
--cap-drop=ALL --cap-add=DAC_OVERRIDE --cap-add=NET_BIND_SERVICE \
|
||||||
|
--security-opt=no-new-privileges:true \
|
||||||
|
--health-cmd='curl -sf http://localhost:80/ || exit 1' \
|
||||||
|
--health-interval=30s --health-timeout=5s --health-retries=3 \
|
||||||
|
--memory=256m \
|
||||||
|
-p 8083:80 \
|
||||||
|
-v /var/lib/archipelago/filebrowser:/srv \
|
||||||
|
-v /var/lib/archipelago/filebrowser-data:/data \
|
||||||
|
-v /var/lib/archipelago/data/cloud:/srv/cloud \
|
||||||
|
${FILEBROWSER_IMAGE} \
|
||||||
|
--database=/data/database.db --root=/srv --address=0.0.0.0 --port=80 2>>"$LOG" && \
|
||||||
|
log " FileBrowser created" || log " WARNING: FileBrowser creation failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Unbundled first-boot complete"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
TARGET_IP=$(hostname -I 2>/dev/null | awk '{print $1}')
|
TARGET_IP=$(hostname -I 2>/dev/null | awk '{print $1}')
|
||||||
[ -z "$TARGET_IP" ] && TARGET_IP="127.0.0.1"
|
[ -z "$TARGET_IP" ] && TARGET_IP="127.0.0.1"
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user