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");
|
||||
}
|
||||
|
||||
// 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 = {
|
||||
// Method 1: nvpn status (most accurate)
|
||||
let status_ip = tokio::process::Command::new("nvpn")
|
||||
.args(["status"])
|
||||
.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
|
||||
let cfg_ip = read_nvpn_config_value("node", "tunnel_ip").await;
|
||||
if cfg_ip.is_some() {
|
||||
cfg_ip
|
||||
} else {
|
||||
// Method 2: config file
|
||||
let cfg_ip = read_nvpn_config_value("node", "tunnel_ip").await;
|
||||
if cfg_ip.is_some() {
|
||||
cfg_ip
|
||||
} else {
|
||||
// Method 3: interface IP
|
||||
tokio::process::Command::new("ip")
|
||||
.args(["-4", "addr", "show", "nvpn0"])
|
||||
.output()
|
||||
.await
|
||||
.ok()
|
||||
.and_then(|o| {
|
||||
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())
|
||||
})
|
||||
}
|
||||
// Fallback: read from network interface
|
||||
tokio::process::Command::new("ip")
|
||||
.args(["-4", "addr", "show", "nvpn0"])
|
||||
.output()
|
||||
.await
|
||||
.ok()
|
||||
.and_then(|o| {
|
||||
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
|
||||
echo "📦 Step 3b: Bundling core containers only (UNBUNDLED mode)"
|
||||
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"
|
||||
mkdir -p "$IMAGES_DIR"
|
||||
# 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/
|
||||
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
|
||||
cp -r "$BOOT_MEDIA/archipelago/apps" /mnt/target/etc/archipelago/
|
||||
fi
|
||||
|
||||
@ -48,6 +48,63 @@ SCRIPT_DIR_FBC="$(cd "$(dirname "$0")" && pwd)"
|
||||
# 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"
|
||||
|
||||
# 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}')
|
||||
[ -z "$TARGET_IP" ] && TARGET_IP="127.0.0.1"
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user