act_runner runs non-interactive shells where nvm isn't loaded.
Cargo steps already source .cargo/env but frontend steps were missing
the equivalent nvm.sh sourcing, causing "npm: command not found".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Linux-only option that mirrors ISO install exactly: builds backend
(release), frontend (with typecheck), syncs all configs, and restarts
all system services (Tor, WireGuard, NostrVPN, nginx, backend).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ISO boot failed in emergency mode because:
- fsck.ext4 binary missing (no e2fsprogs in rootfs)
- LUKS data volume never opened (no cryptsetup-initramfs in initramfs)
Both packages were in the installer debootstrap but not the target rootfs
Dockerfile. The initramfs regeneration at install time now includes LUKS
support since cryptsetup-initramfs is present.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update all references from Debian 12 (Bookworm) to Debian 13 (Trixie)
- Enable SystemCallArchitectures, RestrictAddressFamilies, RestrictRealtime
in archipelago.service (safe on systemd 256+ which respects NoNewPrivileges=no)
- Update GLIBC compatibility checks from 2.36 to 2.40
- ISO filename, build container, and docs updated throughout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ISO build no longer copies netavark from build host (Debian 13/GLIBC 2.41)
which broke container networking on Debian 12 targets. Rootfs already
installs netavark from Debian 12 repos — just configure the backend.
Install RPC now adopts existing containers (from first-boot) instead of
erroring on duplicates. Container scanner extracts real versions from
image tags and detects available updates against pinned versions.
Frontend shows update button with version info when updates are available.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend: cache status in RwLock, refresh every 15s via background task.
Eliminates per-request TCP race to ElectrumX that caused volatile errors.
Fix error classification so "Failed to read" is transient, not hard error.
Frontend: keep last-known-good data across failed polls, persist Tor
onion once discovered, adaptive polling (5s active / 30s synced).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace aardvark-dns container names with host.containers.internal
for all cross-app connections (LND→Bitcoin, ElectrumX→Bitcoin,
Mempool→ElectrumX, Fedimint→Bitcoin, NBXplorer→Bitcoin P2P+RPC)
- Add BTCPay multi-container stack installer (postgres + nbxplorer +
btcpay-server) with proper secrets, data dir ownership, NOAUTH
- Add Mempool multi-container stack installer (mariadb + mempool-api +
mempool-frontend) with host.containers.internal for RPC
- Immediately remove apps from state on uninstall (no 3-min ghost delay)
- Include archy-bitcoin-ui in bitcoin uninstall container list
- Fix LND UI port 8081 (was 8080, conflicting with LND gRPC)
- Fix ElectrumX UI: proxy /electrs-status to backend, cache-busting
headers, graceful fallback when backend returns HTML
- Add Tor hidden services for ElectrumX and LND in torrc template
- Remove unused detect_bitcoin_container_name() (replaced by
host.containers.internal)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Standalone WireGuard (wg0:51820):
- New archipelago-wg.service creates wg0 independent of NostrVPN
- Keypair generated on first-boot, persisted on LUKS partition
- vpn.create-peer uses wg genkey/pubkey (no nvpn dependency)
- wg-address service depends on archipelago-wg, not nostr-vpn
Networking fixes:
- Remove nos.lol from default relays (requires PoW, events rejected)
- Add Tor hidden service for private relay (port 7777) — NAT'd peers
can reach relay over Tor for NostrVPN signaling
- Fix Tor hostname sync race: wait loop before copying hostname files
- Add tor-hostnames + wireguard dirs to LUKS partition setup
- Include relay in hostname sync loops (setup-tor.sh + first-boot)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace disconnected "Generate Invite" + "Add participant" with a 2-step
wizard: enter phone npub → get invite QR + mesh details. Backend vpn.invite
now accepts optional npub param to add participant in the same call. Modal
shows network ID, node npub, and relay URLs for manual app configuration.
Also includes nostr-vpn service hardening (rate-limit restarts, reset-failed
before enable).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
polkit denies reboot/shutdown for non-root users without a local seat
(e.g. SSH sessions). Since archipelago has NOPASSWD sudo, add shell
aliases so reboot/shutdown/halt/poweroff transparently use sudo.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two issues on fresh ISO install:
1. nostr-vpn.service was enabled in rootfs but env file doesn't exist
until first-boot generates Nostr identity — crash-loop on boot.
Now only enabled by first-boot-containers.sh after identity exists.
2. LUKS encrypted partition mounts over /var/lib/archipelago/, hiding
the relay config.toml the Dockerfile put there. Now copies relay
config and creates nostr-relay/nostr-vpn dirs on the LUKS partition.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The nvpn daemon config at /var/lib/archipelago/nostr-vpn/ is owned by
root, but the backend runs as archipelago. Direct write silently failed,
so adding a second phone's npub never reached the daemon — service
restarted with stale config. Now falls back to sudo cp for root-owned
paths, and first-boot sets ownership to archipelago.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
podman export creates paths without ./ prefix, but tar tf checks
used ./etc/... which never matched. List once, grep without prefix.
Also fix git commands to use $HOME/archy (workspace has no .git).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dockerfile RUN steps execute under /bin/sh (dash on Debian), which
doesn't support brace expansion {a,b,c}. The nostr-relay directory
was never created, causing the config copy to fail (build #444).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Runner is Debian 13 (glibc 2.41), ISO rootfs is Debian 12/bookworm
(glibc 2.36). Dynamic binary crashes with GLIBC_2.41 not found.
Musl static build eliminates the dependency entirely.
Also set GRUB_DISTRIBUTOR="Archipelago" so installed system boot
menu says "Archipelago" not "Debian GNU/Linux".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
- VPN card: relay URLs, device management, invite QR, add participant
- Backend: vpn.invite, vpn.add-participant, vpn.peer-config RPCs
- nvpn v0.3.7 system service (fixes event processing bug in v0.3.4)
- First-boot: auto-configure nvpn with node identity and endpoint
- Service: AF_NETLINK for WireGuard, NoNewPrivileges=no for sudo wg
- TASK-50: networking stack reliability from first install
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Revert CI to normal cargo build --release (musl was false positive)
- Add acpid + acpi-support-base to rootfs packages
- Add acpi=force to GRUB and ISOLINUX boot params (installer + installed)
- Fixes "Maybe missing ACPI. Shutdown not powering off" on some hardware
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Install progress bar replaces action buttons (no overlay)
- Hide status badge during install/uninstall
- Uninstall keeps progress state until container disappears from WebSocket
- Uninstall RPC timeout increased to 660s (Bitcoin UTXO flush)
- Installing apps appear in My Apps immediately as placeholders
- Auto-configure Tor hidden service for every app on install
- Widen Tor module visibility for install hooks
- Only clear stale install entries on error status
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Build server (Debian 13) has GLIBC 2.41 but ISO targets Debian 12
(GLIBC 2.36). Switching to x86_64-unknown-linux-musl produces a
fully static binary that runs on any Linux.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
nvpn status command hangs for seconds (connects to relays), causing
the Network page to never finish loading. Read tunnel_ip from the
local config file instead (instant).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove ReadWritePaths sandbox (causes namespace error when /run/nostr-vpn
doesn't exist after reboot — /run is tmpfs)
- Detect both 'active' and 'activating' states in VPN status check
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prevents burst of health checks, scans, and snapshots after slow
podman responses by using MissedTickBehavior::Skip. Bumps container
scan interval from 30s to 60s to reduce DB lock contention.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add vpn.create-peer, vpn.list-peers, vpn.remove-peer RPC methods
- Generate WireGuard config + QR code (SVG) for mobile device connection
- Add "Add Device" modal on Network page with QR scanner support
- Remove old build-iso.yml (replaced by build-iso-dev.yml)
- Remove container-tests.yml (tests run in dev workflow)
- Remove container orchestration tests from dev workflow (redundant)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Build in $HOME/archy to reuse target/ cache across CI runs
- Skip apt-get install when ISO build deps already present
- Cargo tests also use persistent target dir
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Kiosk was redirecting /kiosk → /dashboard, bypassing RootRedirect
and BootScreen entirely. This caused the kiosk to land on Login.vue
showing "server is starting up" in a loop instead of the proper
terminal-style boot progression screen.
Now /kiosk → / → RootRedirect → BootScreen, matching what remote
browsers see.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
nvpn binary writes to $HOME/.config/nvpn. Set HOME to data dir,
create runtime dirs in ExecStartPre, remove overly restrictive
ProtectSystem/ProtectHome that blocked the binary.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix vpnStatus type mismatch (provider: string|undefined vs string|null)
- Remove redundant history_dirty assignment in health_monitor.rs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add system.settings.get/set RPC methods for Claude API key management
- Save key to secrets/claude-api-key, restart claude-api-proxy service
- Home Network card now fetches VPN status via vpn.status RPC
- Shows provider name (nostr-vpn, tailscale) instead of just "Connected"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FIPS stays in the marketplace as an installable container app.
NostrVPN is the native system service; FIPS is a separate optional app.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Convert NostrVPN from container app to native systemd service
- Auto-configure VPN with node's Nostr identity after onboarding
- Add nostr-vpn.service with proper capabilities (NET_ADMIN, NET_RAW)
- Remove FIPS from marketplace, container config, nginx, image-versions
(consolidated into NostrVPN — same mesh VPN concept)
- Add AIUI inclusion step to dev CI workflow
- AIUI installed on VPS build server for ISO inclusion
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add NostrVPN as a native systemd service (extracted from container)
- Add VPN status detection for nostr-vpn in backend vpn.rs
- ISO build extracts nvpn binary from container image
- First-boot auto-configures NostrVPN with node's Nostr identity
- Change Claude Auth from login iframe to API key input field
- Remove duplicate ChangePasswordSection from Settings.vue
- FIPS and Routstr remain as installable container apps
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- FIPS container expects FIPS_NSEC/FIPS_NPUB, not FIPS_NOSTR_SECRET
- NostrVPN container doesn't have a 'start' binary — use image default
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove MemoryDenyWriteExecute=yes from archipelago.service — ring
(rustls) and secp256k1 (bitcoin/nostr) crypto libraries need
executable memory mappings that this restriction blocks
- Add + prefix to ExecStartPre so mkdir/chown run as root
- Use $HOME/archy instead of /home/archipelago/archy in CI workflows
so builds work on both .228 and VPS CI runners
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded /run/user/1000 with $(id -u archipelago) so first-boot
works regardless of the archipelago user's UID.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add three new marketplace apps:
- Routstr (v0.4.3): Decentralized AI inference proxy with Cashu payments
- Nostr VPN (v0.3.4): Mesh VPN with Nostr signaling + WireGuard tunnels
- FIPS (v0.1.0): Self-organizing encrypted mesh network
Includes status UI dashboards for headless apps (nostr-vpn-ui, fips-ui)
with usage instructions, node identity display, and container logs.
Nostr identity injected via env vars for all three apps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Deploy backend binary + frontend to VPS after successful build
- Fix ISO ownership to use runner's UID instead of hardcoded 1000
- FileBrowser on VPS serves ISOs at :8083
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>