feat: ISO networking stack — relay + nvpn v0.3.7 + WireGuard
Some checks failed
Build Archipelago ISO (dev) / build-iso (push) Failing after 12m6s
Some checks failed
Build Archipelago ISO (dev) / build-iso (push) Failing after 12m6s
Add nostr-rs-relay as native system service (port 7777) for VPN signaling. Every node runs its own private relay from first boot. Update nvpn binary from v0.3.4 to v0.3.7 (fixes mesh event processing). Add WireGuard helper and address service for peer VPN. First-boot script configures relay, nvpn identity, relay URLs (direct + Tor onion), and syncs daemon config. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -370,6 +370,8 @@ COPY archipelago-tor-helper.service /etc/systemd/system/archipelago-tor-helper.s
|
||||
COPY archipelago-tor-helper.path /etc/systemd/system/archipelago-tor-helper.path
|
||||
COPY nostr-vpn.service /etc/systemd/system/nostr-vpn.service
|
||||
COPY archipelago-wg-address.service /etc/systemd/system/archipelago-wg-address.service
|
||||
COPY nostr-relay.service /etc/systemd/system/nostr-relay.service
|
||||
COPY nostr-relay-config.toml /etc/archipelago/nostr-relay-config.toml
|
||||
|
||||
# WireGuard kernel module auto-load on boot
|
||||
RUN echo "wireguard" >> /etc/modules-load.d/wireguard.conf
|
||||
@@ -396,6 +398,7 @@ RUN systemctl enable NetworkManager || true && \
|
||||
systemctl enable archipelago-doctor.timer || true && \
|
||||
systemctl enable archipelago-reconcile.timer || true && \
|
||||
systemctl enable archipelago-tor-helper.path || true && \
|
||||
systemctl enable nostr-relay || true && \
|
||||
systemctl enable nostr-vpn || true && \
|
||||
systemctl enable archipelago-wg-address || true
|
||||
|
||||
@@ -403,10 +406,11 @@ RUN systemctl enable NetworkManager || true && \
|
||||
RUN rm -f /usr/sbin/policy-rc.d
|
||||
|
||||
# Create directories (including Cloud storage for FileBrowser)
|
||||
RUN mkdir -p /var/lib/archipelago/{data,config,containers} && \
|
||||
RUN mkdir -p /var/lib/archipelago/{data,config,containers,nostr-relay,nostr-vpn} && \
|
||||
mkdir -p /etc/archipelago && \
|
||||
mkdir -p /opt/archipelago/{bin,scripts,web-ui} && \
|
||||
mkdir -p /var/lib/archipelago/data/cloud/{Documents,Photos,Music,Videos,Downloads} && \
|
||||
cp /etc/archipelago/nostr-relay-config.toml /var/lib/archipelago/nostr-relay/config.toml && \
|
||||
chown -R archipelago:archipelago /var/lib/archipelago /opt/archipelago
|
||||
|
||||
# Clean up
|
||||
@@ -495,6 +499,16 @@ NGINXCONF
|
||||
echo " Using archipelago-wg-address.service from configs/"
|
||||
fi
|
||||
|
||||
# Copy private Nostr relay service (native, for NostrVPN signaling)
|
||||
if [ -f "$SCRIPT_DIR/configs/nostr-relay.service" ]; then
|
||||
cp "$SCRIPT_DIR/configs/nostr-relay.service" "$WORK_DIR/nostr-relay.service"
|
||||
echo " Using nostr-relay.service from configs/"
|
||||
fi
|
||||
if [ -f "$SCRIPT_DIR/configs/nostr-relay-config.toml" ]; then
|
||||
cp "$SCRIPT_DIR/configs/nostr-relay-config.toml" "$WORK_DIR/nostr-relay-config.toml"
|
||||
echo " Using nostr-relay-config.toml from configs/"
|
||||
fi
|
||||
|
||||
# Copy WireGuard helper script (privileged peer management)
|
||||
if [ -f "$SCRIPT_DIR/../scripts/archipelago-wg" ]; then
|
||||
cp "$SCRIPT_DIR/../scripts/archipelago-wg" "$WORK_DIR/archipelago-wg"
|
||||
@@ -966,6 +980,22 @@ else
|
||||
echo " ⚠ NostrVPN image not available — nvpn binary will be missing"
|
||||
fi
|
||||
|
||||
# Extract nostr-rs-relay binary from container image (native system service for VPN signaling)
|
||||
echo " Extracting nostr-rs-relay binary..."
|
||||
RELAY_IMAGE="$($CONTAINER_CMD images -q 80.71.235.15:3000/archipelago/nostr-rs-relay:0.9.0 2>/dev/null)"
|
||||
if [ -z "$RELAY_IMAGE" ]; then
|
||||
$CONTAINER_CMD pull 80.71.235.15:3000/archipelago/nostr-rs-relay:0.9.0 2>/dev/null || true
|
||||
fi
|
||||
RELAY_CONTAINER=$($CONTAINER_CMD create 80.71.235.15:3000/archipelago/nostr-rs-relay:0.9.0 2>/dev/null) || true
|
||||
if [ -n "$RELAY_CONTAINER" ]; then
|
||||
$CONTAINER_CMD cp "$RELAY_CONTAINER:/usr/local/bin/nostr-rs-relay" "$ARCH_DIR/bin/nostr-rs-relay" 2>/dev/null && \
|
||||
chmod +x "$ARCH_DIR/bin/nostr-rs-relay" && \
|
||||
echo " ✅ nostr-rs-relay binary extracted ($(du -h "$ARCH_DIR/bin/nostr-rs-relay" | cut -f1))"
|
||||
$CONTAINER_CMD rm "$RELAY_CONTAINER" 2>/dev/null || true
|
||||
else
|
||||
echo " ⚠ nostr-rs-relay image not available — relay binary will be missing"
|
||||
fi
|
||||
|
||||
# Copy WireGuard helper script
|
||||
if [ -f "$WORK_DIR/archipelago-wg" ]; then
|
||||
cp "$WORK_DIR/archipelago-wg" "$ARCH_DIR/bin/archipelago-wg"
|
||||
|
||||
14
image-recipe/configs/archipelago-wg-address.service
Normal file
14
image-recipe/configs/archipelago-wg-address.service
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Assign WireGuard server address to wg0
|
||||
After=nostr-vpn.service
|
||||
Wants=nostr-vpn.service
|
||||
ConditionPathExists=/sys/class/net/wg0
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/bin/bash -c 'ip address show dev wg0 | grep -q "10.44.0.1" || ip address add 10.44.0.1/16 dev wg0'
|
||||
ExecStart=/bin/bash -c 'iptables -t nat -C POSTROUTING -s 10.44.0.0/16 ! -o wg0 -j MASQUERADE 2>/dev/null || iptables -t nat -A POSTROUTING -s 10.44.0.0/16 ! -o wg0 -j MASQUERADE'
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
19
image-recipe/configs/nostr-relay-config.toml
Normal file
19
image-recipe/configs/nostr-relay-config.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[info]
|
||||
relay_url = "ws://0.0.0.0:7777/"
|
||||
name = "Archipelago Private Relay"
|
||||
description = "Private Nostr relay for Archipelago mesh VPN peer discovery"
|
||||
|
||||
[database]
|
||||
data_directory = "/var/lib/archipelago/nostr-relay"
|
||||
in_memory = true
|
||||
|
||||
[network]
|
||||
address = "0.0.0.0"
|
||||
port = 7777
|
||||
ping_interval = 120
|
||||
|
||||
[limits]
|
||||
messages_per_sec = 50
|
||||
max_event_bytes = 65536
|
||||
max_ws_message_bytes = 65536
|
||||
max_ws_frame_bytes = 65536
|
||||
24
image-recipe/configs/nostr-relay.service
Normal file
24
image-recipe/configs/nostr-relay.service
Normal file
@@ -0,0 +1,24 @@
|
||||
[Unit]
|
||||
Description=Archipelago Private Nostr Relay
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
Before=nostr-vpn.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=archipelago
|
||||
ExecStartPre=/bin/bash -c 'mkdir -p /var/lib/archipelago/nostr-relay'
|
||||
ExecStart=/usr/local/bin/nostr-rs-relay --config /var/lib/archipelago/nostr-relay/config.toml
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
TimeoutStopSec=10
|
||||
|
||||
# Resource limits — relay is lightweight (in-memory mode)
|
||||
MemoryMax=512M
|
||||
LimitNOFILE=4096
|
||||
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
58
scripts/archipelago-wg
Executable file
58
scripts/archipelago-wg
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
# archipelago-wg — Privileged WireGuard helper for the Archipelago backend.
|
||||
# Installed to /usr/local/bin/archipelago-wg with a sudoers rule so the
|
||||
# unprivileged archipelago/debian service user can manage wg0 without
|
||||
# full root or disabling NoNewPrivileges.
|
||||
#
|
||||
# Usage:
|
||||
# archipelago-wg setup <privkey-file> — Create wg0 interface
|
||||
# archipelago-wg add-peer <pubkey> <ip> — Add peer to wg0
|
||||
# archipelago-wg remove-peer <pubkey> — Remove peer from wg0
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
case "${1:-}" in
|
||||
setup)
|
||||
KEY_FILE="${2:?Usage: archipelago-wg setup <privkey-file>}"
|
||||
[ -f "$KEY_FILE" ] || { echo "Key file not found: $KEY_FILE" >&2; exit 1; }
|
||||
|
||||
# Ensure kernel module is loaded
|
||||
modprobe wireguard 2>/dev/null || true
|
||||
|
||||
# Create interface
|
||||
ip link add dev wg0 type wireguard 2>/dev/null || true
|
||||
wg set wg0 listen-port 51820 private-key "$KEY_FILE"
|
||||
# Assign server address if not already set
|
||||
ip address show dev wg0 | grep -q "10.44.0.1" || ip address add 10.44.0.1/16 dev wg0
|
||||
ip link set up dev wg0
|
||||
|
||||
# NAT masquerade for VPN clients
|
||||
iptables -t nat -C POSTROUTING -s 10.44.0.0/16 ! -o wg0 -j MASQUERADE 2>/dev/null ||
|
||||
iptables -t nat -A POSTROUTING -s 10.44.0.0/16 ! -o wg0 -j MASQUERADE
|
||||
|
||||
# Open firewall port
|
||||
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
|
||||
|
||||
echo "wg0 configured"
|
||||
;;
|
||||
|
||||
add-peer)
|
||||
PUBKEY="${2:?Usage: archipelago-wg add-peer <pubkey> <allowed-ip>}"
|
||||
ALLOWED_IP="${3:?Usage: archipelago-wg add-peer <pubkey> <allowed-ip>}"
|
||||
wg set wg0 peer "$PUBKEY" allowed-ips "$ALLOWED_IP"
|
||||
echo "peer added"
|
||||
;;
|
||||
|
||||
remove-peer)
|
||||
PUBKEY="${2:?Usage: archipelago-wg remove-peer <pubkey>}"
|
||||
wg set wg0 peer "$PUBKEY" remove
|
||||
echo "peer removed"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: archipelago-wg {setup|add-peer|remove-peer}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -86,6 +86,20 @@ done
|
||||
chown -R archipelago:archipelago "$TOR_HOSTNAMES" 2>/dev/null
|
||||
log "Tor hostnames populated: $(ls $TOR_HOSTNAMES 2>/dev/null | tr '\n' ' ')"
|
||||
|
||||
# ── Private Nostr Relay: start for VPN signaling and general use ──────
|
||||
if command -v nostr-rs-relay >/dev/null 2>&1; then
|
||||
# Relay config is pre-installed by ISO at /var/lib/archipelago/nostr-relay/config.toml
|
||||
mkdir -p /var/lib/archipelago/nostr-relay
|
||||
if [ ! -f /var/lib/archipelago/nostr-relay/config.toml ] && [ -f /etc/archipelago/nostr-relay-config.toml ]; then
|
||||
cp /etc/archipelago/nostr-relay-config.toml /var/lib/archipelago/nostr-relay/config.toml
|
||||
fi
|
||||
chown -R archipelago:archipelago /var/lib/archipelago/nostr-relay
|
||||
systemctl enable --now nostr-relay 2>/dev/null || true
|
||||
log "Private Nostr relay started on port 7777"
|
||||
else
|
||||
log "nostr-rs-relay binary not found — skipping relay setup"
|
||||
fi
|
||||
|
||||
# ── NostrVPN: configure native system service with node identity ──────
|
||||
if command -v nvpn >/dev/null 2>&1; then
|
||||
NOSTR_SECRET=$(cat /var/lib/archipelago/identity/nostr_secret 2>/dev/null)
|
||||
@@ -107,7 +121,26 @@ if command -v nvpn >/dev/null 2>&1; then
|
||||
|
||||
# Configure nvpn with node identity and endpoint
|
||||
if [ -f "$NVPN_CONFIG_DIR/config.toml" ]; then
|
||||
su -l archipelago -c "nvpn set --endpoint '${HOST_IP}:51820'" 2>/dev/null || true
|
||||
su -l archipelago -c "nvpn set --endpoint '${HOST_IP}:51821'" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Add this node's own relay as a signaling relay
|
||||
# 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
|
||||
# Tor relay (works behind NAT)
|
||||
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
|
||||
|
||||
# Sync config to daemon HOME so the service finds it
|
||||
# (service runs with HOME=/var/lib/archipelago/nostr-vpn)
|
||||
DAEMON_CONFIG_DIR="/var/lib/archipelago/nostr-vpn/.config/nvpn"
|
||||
mkdir -p "$DAEMON_CONFIG_DIR"
|
||||
if [ -f "$NVPN_CONFIG_DIR/config.toml" ]; then
|
||||
cp "$NVPN_CONFIG_DIR/config.toml" "$DAEMON_CONFIG_DIR/config.toml"
|
||||
fi
|
||||
|
||||
# Ensure env file exists for the service
|
||||
|
||||
Reference in New Issue
Block a user