feat: deploy-to-target supports .253 + mesh/federation/VPN updates
Some checks failed
Build Archipelago ISO (dev) / build-iso (push) Failing after 3m27s
Some checks failed
Build Archipelago ISO (dev) / build-iso (push) Failing after 3m27s
- Add deploy_secondary() function for deploying to multiple LAN nodes - --both now deploys to .198 and .253 (previously .198 only) - Fleet deploy updated for 3 LAN nodes - Mesh DM fixes: protocol frame format, DM-via-channel routing - Federation pending requests, discover modal - VPN status UI improvements - Image versions and container specs updates Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
# ./scripts/deploy-to-target.sh # Sync and rebuild
|
||||
# ./scripts/deploy-to-target.sh --quick # Sync only, no rebuild
|
||||
# ./scripts/deploy-to-target.sh --live # Deploy to live system (default: 192.168.1.228)
|
||||
# ./scripts/deploy-to-target.sh --both # Deploy to 228, then copy to 198
|
||||
# ./scripts/deploy-to-target.sh --both # Deploy to 228, then copy to 198 + 253
|
||||
# ./scripts/deploy-to-target.sh --frontend-only # Frontend-only deploy (skip Rust build + container rebuilds)
|
||||
# ./scripts/deploy-to-target.sh --demo # Demo mode: Bitcoin pruning enabled (smaller disk)
|
||||
# ./scripts/deploy-to-target.sh --dry-run --live # Show what would be deployed without executing
|
||||
@@ -55,6 +55,7 @@ CANARY=false
|
||||
TAILSCALE=false
|
||||
TAILSCALE_NODE=""
|
||||
FLEET=false
|
||||
RESET_MESH=false
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--quick) QUICK=true ;;
|
||||
@@ -68,6 +69,7 @@ for arg in "$@"; do
|
||||
--tailscale-node=*) TAILSCALE_NODE="${arg#*=}" ;;
|
||||
--fleet) FLEET=true ;;
|
||||
--all) FLEET=true ;;
|
||||
--reset-mesh) RESET_MESH=true ;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -93,8 +95,8 @@ if [ "$FLEET" = true ]; then
|
||||
echo "FAILED: .228 unreachable"; exit 1
|
||||
fi
|
||||
echo ""
|
||||
echo "Phase 2: Copy to .198 (LAN secondary — skip if unreachable)"
|
||||
"$0" --both 2>/dev/null || echo " .198 unreachable, skipping"
|
||||
echo "Phase 2: Copy to .198 + .253 (LAN secondaries — skip if unreachable)"
|
||||
"$0" --both 2>/dev/null || echo " LAN secondaries unreachable, skipping"
|
||||
echo ""
|
||||
echo "Phase 3: Deploy to all Tailscale nodes (Arch 1/2/3)"
|
||||
"$SCRIPT_DIR/deploy-tailscale.sh" --all || { echo "WARNING: Some Tailscale nodes failed"; }
|
||||
@@ -333,22 +335,19 @@ if [ "$CANARY" = true ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# When --both: deploy to 228 first, then copy to 198
|
||||
if [ "$BOTH" = true ]; then
|
||||
echo "Deploying to both servers (228, then 198)..."
|
||||
# Release lock so the recursive --live call can acquire it
|
||||
rm -rf "$LOCK_DIR" 2>/dev/null; trap - EXIT
|
||||
"$0" --live
|
||||
# ── deploy_secondary: copy built binary+frontend from .228 to a secondary node ──
|
||||
# Usage: deploy_secondary <user@ip> <short_label> (e.g. deploy_secondary archipelago@192.168.1.198 198)
|
||||
deploy_secondary() {
|
||||
local SEC_TARGET="$1"
|
||||
local SEC_LABEL="$2"
|
||||
local SEC_IP="${SEC_TARGET#*@}"
|
||||
|
||||
echo ""
|
||||
echo "📤 Copying to 192.168.1.198 (no rsync/cargo on that node)..."
|
||||
TARGET_198="archipelago@192.168.1.198"
|
||||
if ! scp $SSH_OPTS "archipelago@192.168.1.228:$TARGET_DIR/core/target/release/archipelago" /tmp/archipelago-both 2>/dev/null; then
|
||||
echo " ERROR: Failed to copy binary from .228 — is the build available?"
|
||||
exit 1
|
||||
fi
|
||||
scp $SSH_OPTS /tmp/archipelago-both "$TARGET_198:/tmp/archipelago-new"
|
||||
ssh $SSH_OPTS "archipelago@192.168.1.228" "cd '$TARGET_DIR' && tar cf - web/dist/neode-ui 2>/dev/null" | ssh $SSH_OPTS "$TARGET_198" "mkdir -p /tmp/web-deploy && cd /tmp/web-deploy && tar xf -"
|
||||
ssh $SSH_OPTS "$TARGET_198" '
|
||||
echo "📤 Copying to $SEC_IP (no rsync/cargo on that node)..."
|
||||
|
||||
scp $SSH_OPTS /tmp/archipelago-both "$SEC_TARGET:/tmp/archipelago-new"
|
||||
ssh $SSH_OPTS "archipelago@192.168.1.228" "cd '$TARGET_DIR' && tar cf - web/dist/neode-ui 2>/dev/null" | ssh $SSH_OPTS "$SEC_TARGET" "mkdir -p /tmp/web-deploy && cd /tmp/web-deploy && tar xf -"
|
||||
ssh $SSH_OPTS "$SEC_TARGET" '
|
||||
sudo systemctl stop archipelago
|
||||
sudo cp /tmp/archipelago-new /usr/local/bin/archipelago
|
||||
sudo chmod +x /usr/local/bin/archipelago
|
||||
@@ -358,49 +357,49 @@ if [ "$BOTH" = true ]; then
|
||||
sudo chown -R 1000:1000 /opt/archipelago/web-ui
|
||||
'
|
||||
|
||||
# Deploy AIUI to 198 if available
|
||||
# Deploy AIUI if available
|
||||
AIUI_DIST="$PROJECT_DIR/../AIUI/packages/app/dist"
|
||||
if [ -d "$AIUI_DIST" ] && [ -f "$AIUI_DIST/index.html" ]; then
|
||||
echo " Deploying AIUI to 198..."
|
||||
ssh $SSH_OPTS "$TARGET_198" "sudo mkdir -p /opt/archipelago/web-ui/aiui && sudo rm -rf /opt/archipelago/web-ui/aiui/*"
|
||||
cd "$AIUI_DIST" && tar --no-xattrs -cf - . | ssh $SSH_OPTS "$TARGET_198" "sudo tar xf - -C /opt/archipelago/web-ui/aiui/"
|
||||
echo " Deploying AIUI to .$SEC_LABEL..."
|
||||
ssh $SSH_OPTS "$SEC_TARGET" "sudo mkdir -p /opt/archipelago/web-ui/aiui && sudo rm -rf /opt/archipelago/web-ui/aiui/*"
|
||||
cd "$AIUI_DIST" && tar --no-xattrs -cf - . | ssh $SSH_OPTS "$SEC_TARGET" "sudo tar xf - -C /opt/archipelago/web-ui/aiui/"
|
||||
cd "$PROJECT_DIR"
|
||||
ssh $SSH_OPTS "$TARGET_198" "sudo chown -R 1000:1000 /opt/archipelago/web-ui/aiui"
|
||||
ssh $SSH_OPTS "$SEC_TARGET" "sudo chown -R 1000:1000 /opt/archipelago/web-ui/aiui"
|
||||
fi
|
||||
|
||||
# Sync nginx config + snippets + fixes to 198
|
||||
# Sync nginx config + snippets
|
||||
NGINX_CFG="$PROJECT_DIR/image-recipe/configs/nginx-archipelago.conf"
|
||||
SNIPPETS_DIR="$PROJECT_DIR/image-recipe/configs/snippets"
|
||||
if [ -f "$NGINX_CFG" ]; then
|
||||
echo " Syncing nginx config to 198..."
|
||||
scp $SSH_OPTS "$NGINX_CFG" "$TARGET_198:/tmp/nginx-archipelago.conf" 2>/dev/null || true
|
||||
ssh $SSH_OPTS "$TARGET_198" '
|
||||
echo " Syncing nginx config to .$SEC_LABEL..."
|
||||
scp $SSH_OPTS "$NGINX_CFG" "$SEC_TARGET:/tmp/nginx-archipelago.conf" 2>/dev/null || true
|
||||
ssh $SSH_OPTS "$SEC_TARGET" '
|
||||
sudo cp /tmp/nginx-archipelago.conf /etc/nginx/sites-available/archipelago
|
||||
sudo rm -f /etc/nginx/conf.d/external-app-proxies.conf
|
||||
sudo sed -i "s|proxy_pass http://127.0.0.1:3141/;|proxy_pass http://127.0.0.1:3142/;|g" /etc/nginx/sites-available/archipelago
|
||||
rm -f /tmp/nginx-archipelago.conf
|
||||
' 2>/dev/null || true
|
||||
fi
|
||||
# Sync nginx snippets to 198
|
||||
if [ -d "$SNIPPETS_DIR" ]; then
|
||||
echo " Syncing nginx snippets to 198..."
|
||||
ssh $SSH_OPTS "$TARGET_198" "sudo mkdir -p /etc/nginx/snippets" 2>/dev/null || true
|
||||
echo " Syncing nginx snippets to .$SEC_LABEL..."
|
||||
ssh $SSH_OPTS "$SEC_TARGET" "sudo mkdir -p /etc/nginx/snippets" 2>/dev/null || true
|
||||
for f in "$SNIPPETS_DIR"/*.conf; do
|
||||
[ -f "$f" ] && scp $SSH_OPTS "$f" "$TARGET_198:/tmp/nginx-snippet-$(basename "$f")" 2>/dev/null || true
|
||||
[ -f "$f" ] && scp $SSH_OPTS "$f" "$SEC_TARGET:/tmp/nginx-snippet-$(basename "$f")" 2>/dev/null || true
|
||||
done
|
||||
ssh $SSH_OPTS "$TARGET_198" '
|
||||
ssh $SSH_OPTS "$SEC_TARGET" '
|
||||
for f in /tmp/nginx-snippet-*.conf; do
|
||||
[ -f "$f" ] && sudo mv "$f" "/etc/nginx/snippets/$(basename "$f" | sed "s/^nginx-snippet-//")"
|
||||
done
|
||||
' 2>/dev/null || true
|
||||
fi
|
||||
ssh $SSH_OPTS "$TARGET_198" 'sudo nginx -t 2>&1 && echo " nginx config OK" || echo " nginx config test failed"' 2>/dev/null || true
|
||||
# Sync systemd service file to 198
|
||||
ssh $SSH_OPTS "$SEC_TARGET" 'sudo nginx -t 2>&1 && echo " nginx config OK" || echo " nginx config test failed"' 2>/dev/null || true
|
||||
|
||||
# Sync systemd service file
|
||||
SERVICE_FILE="$PROJECT_DIR/image-recipe/configs/archipelago.service"
|
||||
if [ -f "$SERVICE_FILE" ]; then
|
||||
echo " Syncing systemd service to 198..."
|
||||
scp $SSH_OPTS "$SERVICE_FILE" "$TARGET_198:/tmp/archipelago.service" 2>/dev/null || true
|
||||
ssh $SSH_OPTS "$TARGET_198" '
|
||||
echo " Syncing systemd service to .$SEC_LABEL..."
|
||||
scp $SSH_OPTS "$SERVICE_FILE" "$SEC_TARGET:/tmp/archipelago.service" 2>/dev/null || true
|
||||
ssh $SSH_OPTS "$SEC_TARGET" '
|
||||
if ! diff -q /tmp/archipelago.service /etc/systemd/system/archipelago.service >/dev/null 2>&1; then
|
||||
sudo cp /tmp/archipelago.service /etc/systemd/system/archipelago.service
|
||||
sudo systemctl daemon-reload
|
||||
@@ -412,12 +411,12 @@ if [ "$BOTH" = true ]; then
|
||||
' 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Deploy udev rule for mesh radio to 198
|
||||
# Deploy udev rule for mesh radio
|
||||
UDEV_RULE="$PROJECT_DIR/image-recipe/configs/99-mesh-radio.rules"
|
||||
if [ -f "$UDEV_RULE" ]; then
|
||||
echo " Syncing udev rule to 198..."
|
||||
scp $SSH_OPTS "$UDEV_RULE" "$TARGET_198:/tmp/99-mesh-radio.rules" 2>/dev/null || true
|
||||
ssh $SSH_OPTS "$TARGET_198" '
|
||||
echo " Syncing udev rule to .$SEC_LABEL..."
|
||||
scp $SSH_OPTS "$UDEV_RULE" "$SEC_TARGET:/tmp/99-mesh-radio.rules" 2>/dev/null || true
|
||||
ssh $SSH_OPTS "$SEC_TARGET" '
|
||||
if ! diff -q /tmp/99-mesh-radio.rules /etc/udev/rules.d/99-mesh-radio.rules >/dev/null 2>&1; then
|
||||
sudo cp /tmp/99-mesh-radio.rules /etc/udev/rules.d/99-mesh-radio.rules
|
||||
sudo udevadm control --reload-rules
|
||||
@@ -430,8 +429,8 @@ if [ "$BOTH" = true ]; then
|
||||
' 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Dev mode + FileBrowser on 198
|
||||
ssh $SSH_OPTS "$TARGET_198" '
|
||||
# Dev mode + FileBrowser
|
||||
ssh $SSH_OPTS "$SEC_TARGET" '
|
||||
# Dev mode
|
||||
if ! grep -q "ARCHIPELAGO_DEV_MODE=true" /etc/systemd/system/archipelago.service.d/override.conf 2>/dev/null; then
|
||||
sudo mkdir -p /etc/systemd/system/archipelago.service.d
|
||||
@@ -454,9 +453,10 @@ if [ "$BOTH" = true ]; then
|
||||
fi
|
||||
' 2>/dev/null || true
|
||||
|
||||
# Write deploy manifest to .198
|
||||
# Write deploy manifest
|
||||
local DEPLOY_TS
|
||||
DEPLOY_TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
ssh $SSH_OPTS "$TARGET_198" "sudo tee /opt/archipelago/deploy-manifest.json > /dev/null" << MANIFEST_198_EOF
|
||||
ssh $SSH_OPTS "$SEC_TARGET" "sudo tee /opt/archipelago/deploy-manifest.json > /dev/null" <<-MANIFEST_SEC_EOF
|
||||
{
|
||||
"commit": "$DEPLOY_COMMIT_FULL",
|
||||
"commit_short": "$DEPLOY_COMMIT",
|
||||
@@ -464,30 +464,50 @@ if [ "$BOTH" = true ]; then
|
||||
"dirty": $DEPLOY_DIRTY,
|
||||
"deployed_at": "$DEPLOY_TS",
|
||||
"deployed_from": "$(hostname)",
|
||||
"target": "$TARGET_198"
|
||||
"target": "$SEC_TARGET"
|
||||
}
|
||||
MANIFEST_198_EOF
|
||||
MANIFEST_SEC_EOF
|
||||
|
||||
ssh $SSH_OPTS "$TARGET_198" "sudo systemctl start archipelago && sudo systemctl restart nginx"
|
||||
ssh $SSH_OPTS "$SEC_TARGET" "sudo systemctl start archipelago && sudo systemctl restart nginx"
|
||||
|
||||
# Run container doctor on .198
|
||||
echo " Running container doctor on .198..."
|
||||
"$SCRIPT_DIR/container-doctor.sh" "$TARGET_198" 2>&1 | sed 's/^/ /' || true
|
||||
# Run container doctor
|
||||
echo " Running container doctor on .$SEC_LABEL..."
|
||||
"$SCRIPT_DIR/container-doctor.sh" "$SEC_TARGET" 2>&1 | sed 's/^/ /' || true
|
||||
|
||||
# Post-deploy health check on .198
|
||||
echo " Checking .198 health..."
|
||||
HEALTH_198="fail"
|
||||
# Post-deploy health check
|
||||
echo " Checking .$SEC_LABEL health..."
|
||||
local HEALTH="fail"
|
||||
for i in $(seq 1 12); do
|
||||
sleep 5
|
||||
HEALTH_198=$(curl -s --max-time 5 "http://192.168.1.198/health" 2>/dev/null || { echo "WARNING: Health check failed for 192.168.1.198" >&2; echo ""; })
|
||||
if [ "$HEALTH_198" = "OK" ]; then
|
||||
echo " ✅ 192.168.1.198 deployed (health OK after $((i * 5))s)"
|
||||
HEALTH=$(curl -s --max-time 5 "http://$SEC_IP/health" 2>/dev/null || { echo "WARNING: Health check failed for $SEC_IP" >&2; echo ""; })
|
||||
if [ "$HEALTH" = "OK" ]; then
|
||||
echo " ✅ $SEC_IP deployed (health OK after $((i * 5))s)"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ "$HEALTH_198" != "OK" ]; then
|
||||
echo " ⚠️ 192.168.1.198 deployed but health check failed after 60s"
|
||||
if [ "$HEALTH" != "OK" ]; then
|
||||
echo " ⚠️ $SEC_IP deployed but health check failed after 60s"
|
||||
fi
|
||||
}
|
||||
|
||||
# When --both: deploy to 228 first, then copy to 198 + 253
|
||||
if [ "$BOTH" = true ]; then
|
||||
echo "Deploying to all LAN servers (228, then 198 + 253)..."
|
||||
# Release lock so the recursive --live call can acquire it
|
||||
rm -rf "$LOCK_DIR" 2>/dev/null; trap - EXIT
|
||||
"$0" --live
|
||||
echo ""
|
||||
|
||||
# Fetch built binary from .228 (shared by all secondary nodes)
|
||||
if ! scp $SSH_OPTS "archipelago@192.168.1.228:$TARGET_DIR/core/target/release/archipelago" /tmp/archipelago-both 2>/dev/null; then
|
||||
echo " ERROR: Failed to copy binary from .228 — is the build available?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Deploy to each secondary node
|
||||
deploy_secondary "archipelago@192.168.1.198" "198"
|
||||
deploy_secondary "archipelago@192.168.1.253" "253"
|
||||
|
||||
rm -f /tmp/archipelago-both
|
||||
exit 0
|
||||
fi
|
||||
@@ -547,6 +567,10 @@ if [ "$LIVE" = true ]; then
|
||||
elif ssh $SSH_OPTS "$TARGET_HOST" "[ -f $TARGET_DIR/core/target/release/archipelago ]" 2>/dev/null; then
|
||||
progress "Deploying backend binary"
|
||||
ssh $SSH_OPTS "$TARGET_HOST" 'sudo systemctl stop archipelago --no-block 2>/dev/null; sleep 2; sudo kill -9 $(pgrep -x archipelago) 2>/dev/null; sleep 1; true'
|
||||
if [ "$RESET_MESH" = true ]; then
|
||||
echo " Wiping mesh cache (peers/messages/sessions) per --reset-mesh"
|
||||
ssh $SSH_OPTS "$TARGET_HOST" 'sudo rm -f /var/lib/archipelago/messages.json /var/lib/archipelago/sessions.json /var/lib/archipelago/mesh-outbox.json 2>/dev/null; true'
|
||||
fi
|
||||
ssh $SSH_OPTS "$TARGET_HOST" "sudo cp $TARGET_DIR/core/target/release/archipelago /usr/local/bin/"
|
||||
fi
|
||||
|
||||
|
||||
@@ -109,13 +109,13 @@ if [ -f "$UNBUNDLED_MARKER" ]; then
|
||||
log "Creating FileBrowser (noauth)..."
|
||||
mkdir -p /var/lib/archipelago/filebrowser /var/lib/archipelago/filebrowser-data
|
||||
mkdir -p /var/lib/archipelago/filebrowser/{Documents,Photos,Music,Videos,Downloads}
|
||||
chown -R 1000:1000 /var/lib/archipelago/filebrowser
|
||||
chown -R 1000:1000 /var/lib/archipelago/filebrowser-data
|
||||
chown -R 100000:100000 /var/lib/archipelago/filebrowser
|
||||
chown -R 100000:100000 /var/lib/archipelago/filebrowser-data
|
||||
# Write config with database on persistent volume
|
||||
cat > /var/lib/archipelago/filebrowser-data/.filebrowser.json <<'FBEOF'
|
||||
{"port":80,"baseURL":"","address":"0.0.0.0","database":"/data/filebrowser.db","root":"/srv","log":"stdout"}
|
||||
FBEOF
|
||||
chown 1000:1000 /var/lib/archipelago/filebrowser-data/.filebrowser.json
|
||||
chown 100000:100000 /var/lib/archipelago/filebrowser-data/.filebrowser.json
|
||||
pull_with_fallback "${FILEBROWSER_IMAGE}"
|
||||
$DOCKER run -d --name filebrowser --restart unless-stopped \
|
||||
--network archy-net \
|
||||
@@ -141,25 +141,25 @@ FBEOF
|
||||
chown -R 1000:1000 /var/lib/archipelago/secrets
|
||||
fi
|
||||
|
||||
# Generate WireGuard keys for VPN
|
||||
if [ ! -f /var/lib/archipelago/wireguard/wg0.conf ]; then
|
||||
# Generate WireGuard keys for standalone VPN (archipelago-wg service)
|
||||
WG_DIR="/var/lib/archipelago/wireguard"
|
||||
if [ ! -f "$WG_DIR/private.key" ]; then
|
||||
log "Generating WireGuard keys..."
|
||||
mkdir -p /var/lib/archipelago/wireguard /etc/wireguard
|
||||
PRIVKEY=$(wg genkey)
|
||||
PUBKEY=$(echo "$PRIVKEY" | wg pubkey)
|
||||
cat > /var/lib/archipelago/wireguard/wg0.conf <<WGEOF
|
||||
[Interface]
|
||||
PrivateKey = $PRIVKEY
|
||||
Address = 10.0.0.1/24
|
||||
ListenPort = 51820
|
||||
WGEOF
|
||||
cp /var/lib/archipelago/wireguard/wg0.conf /etc/wireguard/wg0.conf
|
||||
chmod 600 /etc/wireguard/wg0.conf /var/lib/archipelago/wireguard/wg0.conf
|
||||
chown -R 1000:1000 /var/lib/archipelago/wireguard
|
||||
systemctl enable wg-quick@wg0 2>/dev/null || true
|
||||
wg-quick up wg0 2>>"$LOG" || true
|
||||
log " WireGuard configured: pubkey=$PUBKEY"
|
||||
mkdir -p "$WG_DIR"
|
||||
wg genkey > "$WG_DIR/private.key" 2>/dev/null
|
||||
chmod 600 "$WG_DIR/private.key"
|
||||
wg pubkey < "$WG_DIR/private.key" > "$WG_DIR/public.key"
|
||||
chown -R 1000:1000 "$WG_DIR"
|
||||
log " WireGuard keypair generated: pubkey=$(cat "$WG_DIR/public.key")"
|
||||
fi
|
||||
# Start standalone WireGuard service (wg0:51820 on 10.44.0.1/16)
|
||||
modprobe wireguard 2>/dev/null || true
|
||||
systemctl enable --now archipelago-wg 2>/dev/null || true
|
||||
systemctl enable --now archipelago-wg-address 2>/dev/null || true
|
||||
if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "Status: active"; then
|
||||
ufw allow 51820/udp >/dev/null 2>&1 || true
|
||||
fi
|
||||
log " Standalone WireGuard started (wg0:51820)"
|
||||
|
||||
log "Unbundled first-boot complete"
|
||||
exit 0
|
||||
@@ -242,98 +242,10 @@ else
|
||||
log "nostr-rs-relay binary not found — skipping relay setup"
|
||||
fi
|
||||
|
||||
# ── NostrVPN: configure native system service with node identity ──────
|
||||
# The nvpn binary may have GLIBC mismatch (built for newer glibc than target OS).
|
||||
# Write config.toml directly as fallback — the Rust backend reads it for vpn.invite/status.
|
||||
NOSTR_SECRET=$(cat /var/lib/archipelago/identity/nostr_secret 2>/dev/null)
|
||||
NOSTR_PUBKEY=$(cat /var/lib/archipelago/identity/nostr_pubkey 2>/dev/null)
|
||||
if [ -n "$NOSTR_SECRET" ]; then
|
||||
NVPN_CONFIG_DIR="/home/archipelago/.config/nvpn"
|
||||
DAEMON_CONFIG_DIR="/var/lib/archipelago/nostr-vpn/.config/nvpn"
|
||||
mkdir -p "$NVPN_CONFIG_DIR" "$DAEMON_CONFIG_DIR"
|
||||
|
||||
# Try nvpn CLI first (may fail with GLIBC mismatch)
|
||||
NVPN_CLI_OK=false
|
||||
if command -v nvpn >/dev/null 2>&1; then
|
||||
if [ ! -f "$NVPN_CONFIG_DIR/config.toml" ]; then
|
||||
if su -l archipelago -c "nvpn init" 2>/dev/null; then
|
||||
NVPN_CLI_OK=true
|
||||
su -l archipelago -c "nvpn set --config '$NVPN_CONFIG_DIR/config.toml'" 2>/dev/null || true
|
||||
else
|
||||
log "NostrVPN: nvpn init failed (likely GLIBC mismatch) — using direct config"
|
||||
fi
|
||||
else
|
||||
NVPN_CLI_OK=true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Get server's public IP for WireGuard endpoint
|
||||
HOST_IP=$(cat /var/lib/archipelago/host-ip.env 2>/dev/null | grep ARCHIPELAGO_HOST_IP | cut -d= -f2)
|
||||
[ -z "$HOST_IP" ] && HOST_IP=$(curl -s --connect-timeout 5 https://api.ipify.org 2>/dev/null || hostname -I | awk '{print $1}')
|
||||
|
||||
if $NVPN_CLI_OK && [ -f "$NVPN_CONFIG_DIR/config.toml" ]; then
|
||||
# nvpn CLI works — use it to configure
|
||||
su -l archipelago -c "nvpn set --endpoint '${HOST_IP}:51821'" 2>/dev/null || true
|
||||
# Direct relay (public IP) — only if not behind NAT
|
||||
if [ -n "$HOST_IP" ] && ! echo "$HOST_IP" | grep -qE '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)'; then
|
||||
su -l archipelago -c "nvpn relay add 'ws://${HOST_IP}:7777'" 2>/dev/null || true
|
||||
fi
|
||||
RELAY_ONION=$(cat /var/lib/archipelago/tor-hostnames/relay 2>/dev/null)
|
||||
if [ -n "$RELAY_ONION" ]; then
|
||||
su -l archipelago -c "nvpn relay add 'ws://${RELAY_ONION}:7777'" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback: write config.toml directly if it doesn't exist yet.
|
||||
# Uses hex keys — the Rust backend converts hex to npub1/nsec1 at read time.
|
||||
if [ ! -f "$DAEMON_CONFIG_DIR/config.toml" ] && [ ! -f "$NVPN_CONFIG_DIR/config.toml" ]; then
|
||||
# Build relay list
|
||||
RELAYS=""
|
||||
RELAY_ONION=$(cat /var/lib/archipelago/tor-hostnames/relay 2>/dev/null)
|
||||
if [ -n "$RELAY_ONION" ]; then
|
||||
RELAYS="\"ws://${RELAY_ONION}:7777\""
|
||||
fi
|
||||
if [ -n "$HOST_IP" ] && ! echo "$HOST_IP" | grep -qE '^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)'; then
|
||||
[ -n "$RELAYS" ] && RELAYS="$RELAYS, "
|
||||
RELAYS="${RELAYS}\"ws://${HOST_IP}:7777\""
|
||||
fi
|
||||
[ -z "$RELAYS" ] && RELAYS='"wss://relay.damus.io", "wss://relay.primal.net"'
|
||||
|
||||
cat > "$DAEMON_CONFIG_DIR/config.toml" <<NVPNCONF
|
||||
[nostr]
|
||||
public_key = "${NOSTR_PUBKEY}"
|
||||
secret_key = "${NOSTR_SECRET}"
|
||||
relays = [${RELAYS}]
|
||||
|
||||
[[networks]]
|
||||
network_id = "archipelago"
|
||||
participants = []
|
||||
NVPNCONF
|
||||
chmod 600 "$DAEMON_CONFIG_DIR/config.toml"
|
||||
log "NostrVPN: wrote config.toml directly (hex keys, backend converts)"
|
||||
fi
|
||||
|
||||
# Sync user config to daemon dir if nvpn CLI created it
|
||||
if [ -f "$NVPN_CONFIG_DIR/config.toml" ] && [ ! -f "$DAEMON_CONFIG_DIR/config.toml" ]; then
|
||||
cp "$NVPN_CONFIG_DIR/config.toml" "$DAEMON_CONFIG_DIR/config.toml"
|
||||
fi
|
||||
chown -R archipelago:archipelago /var/lib/archipelago/nostr-vpn
|
||||
|
||||
# Ensure env file exists for the service
|
||||
mkdir -p /var/lib/archipelago/nostr-vpn
|
||||
cat > /var/lib/archipelago/nostr-vpn/env <<NVPNENV
|
||||
NOSTR_SECRET=${NOSTR_SECRET}
|
||||
NOSTR_PUBKEY=${NOSTR_PUBKEY}
|
||||
NVPNENV
|
||||
chmod 600 /var/lib/archipelago/nostr-vpn/env
|
||||
|
||||
# Start NostrVPN mesh service (standalone WG already started above)
|
||||
systemctl reset-failed nostr-vpn 2>/dev/null || true
|
||||
systemctl enable --now nostr-vpn 2>/dev/null || true
|
||||
log "NostrVPN configured with node identity and started"
|
||||
else
|
||||
log "NostrVPN: no Nostr identity yet — will configure after onboarding"
|
||||
fi
|
||||
# ── NostrVPN: DISABLED — using standalone WireGuard only ──────────────
|
||||
# NostrVPN (nvpn) is disabled for now. Standalone WireGuard (archipelago-wg)
|
||||
# handles VPN with QR-based peer provisioning via the web UI.
|
||||
log "NostrVPN disabled — standalone WireGuard only (wg0:51820)"
|
||||
|
||||
# Wait for a container to be healthy (accepting connections)
|
||||
wait_for_container() {
|
||||
@@ -497,6 +409,8 @@ grep -q "^archipelago:" /etc/subuid 2>/dev/null || {
|
||||
echo "archipelago:100000:65536" >> /etc/subgid
|
||||
log " subuid/subgid configured"
|
||||
}
|
||||
# Apply podman migrations after subuid/subgid changes (per official tutorial)
|
||||
$DOCKER system migrate 2>/dev/null || true
|
||||
# Ensure /etc/hosts is readable (rootless podman needs it)
|
||||
chmod 644 /etc/hosts 2>/dev/null
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
# to verify against the registry.
|
||||
|
||||
# Archipelago app registries (primary + fallback)
|
||||
ARCHY_REGISTRY="23.182.128.160:3000/lfg2025"
|
||||
ARCHY_REGISTRY_FALLBACK="git.tx1138.com/lfg2025"
|
||||
ARCHY_REGISTRY="git.tx1138.com/lfg2025"
|
||||
ARCHY_REGISTRY_FALLBACK="23.182.128.160:3000/lfg2025"
|
||||
|
||||
# Bitcoin stack
|
||||
BITCOIN_KNOTS_IMAGE="$ARCHY_REGISTRY/bitcoin-knots:latest"
|
||||
|
||||
Reference in New Issue
Block a user