fix: ISO boot, container installs, VPN, nginx, companion input
All checks were successful
Build Archipelago ISO (dev) / build-iso (push) Successful in 30m53s

- LUKS auto-unlock: initramfs hook + systemd service + nofail fstab
- Rootfs packages: add passt, aardvark-dns, netavark, nftables for Podman 5.x
- nginx: resolver + variable proxy_pass for external domains (DNS at boot)
- Boot: loglevel=0 suppresses kernel warnings, serial console for QEMU
- Container installs: write configs before chown, sudo chown for LUKS volumes
- Container installs: build UI sidecars locally (not from registry) for auth injection
- Bitcoin UI: inject RPC auth from secrets file, --no-cache rebuild
- Secrets: chown to archipelago user in first-boot (backend needs read access)
- Podman: image_copy_tmp_dir for read-only /var/tmp in user namespace
- NostrVPN: enable service in auto-install, always include public relays
- NostrVPN: read tunnel IP from nvpn status (not just config file)
- VPN invite: v2 base64 no-pad format matching phone app
- Companion input: relay always active, kiosk skips relay listener (prevents double input)
- dev-start.sh: production build includes AIUI deployment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-04-10 03:10:49 -04:00
parent 82419c52ab
commit 7393c5f158
10 changed files with 328 additions and 89 deletions

View File

@@ -274,6 +274,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
podman \
uidmap \
slirp4netns \
passt \
aardvark-dns \
netavark \
nftables \
fuse-overlayfs \
tor \
python3 \
@@ -922,10 +926,20 @@ else
echo " Capturing backend binary from live server..."
fi
# Try to get from live server first (unless BUILD_FROM_SOURCE=1)
# Try to get backend binary: local release build → local install → remote → container build
BACKEND_CAPTURED=0
if [ "$BUILD_FROM_SOURCE" != "1" ]; then
# Direct copy from ARCHIPELAGO_BIN env, local install, or remote
# Check for local release binary first (works for both BUILD_FROM_SOURCE and normal mode)
LOCAL_RELEASE="$(cd "$SCRIPT_DIR/.." && pwd)/core/target/release/archipelago"
if [ -f "$LOCAL_RELEASE" ]; then
cp "$LOCAL_RELEASE" "$ARCH_DIR/bin/archipelago"
chmod +x "$ARCH_DIR/bin/archipelago"
echo " ✅ Backend from local release build ($(du -h "$ARCH_DIR/bin/archipelago" | cut -f1))"
BACKEND_CAPTURED=1
fi
if [ "$BACKEND_CAPTURED" = "0" ] && [ "$BUILD_FROM_SOURCE" != "1" ]; then
# Direct copy from ARCHIPELAGO_BIN env or local install
BIN="${ARCHIPELAGO_BIN:-/usr/local/bin/archipelago}"
if [ -f "$BIN" ]; then
cp "$BIN" "$ARCH_DIR/bin/archipelago"
@@ -2006,12 +2020,65 @@ DATA_UUID=$(blkid -s UUID -o value "$DATA_PART")
echo "# LUKS2 encrypted data — auto-unlock with key file" > /mnt/target/etc/crypttab
echo "archipelago-data UUID=$DATA_UUID /root/.luks-archipelago.key luks,discard" >> /mnt/target/etc/crypttab
# Configure LUKS auto-unlock: three layers to ensure it works
# Layer 1: cryptsetup-initramfs config (tells update-initramfs to embed key)
mkdir -p /mnt/target/etc/cryptsetup-initramfs
cat > /mnt/target/etc/cryptsetup-initramfs/conf <<'CRYPTCONF'
KEYFILE_PATTERN="/root/.luks-*.key"
UMASK=0077
CRYPTCONF
# Layer 2: initramfs hook to force-copy key file
mkdir -p /mnt/target/etc/initramfs-tools/hooks
cat > /mnt/target/etc/initramfs-tools/hooks/archipelago-luks <<'LUKSHOOK'
#!/bin/sh
PREREQ=""
prereqs() { echo "$PREREQ"; }
case $1 in prereqs) prereqs; exit 0;; esac
. /usr/share/initramfs-tools/hook-functions
if [ -f /root/.luks-archipelago.key ]; then
mkdir -p "${DESTDIR}/root"
cp /root/.luks-archipelago.key "${DESTDIR}/root/.luks-archipelago.key"
chmod 600 "${DESTDIR}/root/.luks-archipelago.key"
fi
if [ -f /etc/crypttab ]; then
mkdir -p "${DESTDIR}/etc"
cp /etc/crypttab "${DESTDIR}/etc/crypttab"
fi
copy_exec /sbin/cryptsetup
LUKSHOOK
chmod +x /mnt/target/etc/initramfs-tools/hooks/archipelago-luks
# Layer 3: systemd service as fallback — unlocks LUKS early if initramfs missed it
cat > /mnt/target/etc/systemd/system/archipelago-luks-unlock.service <<'LUKSUNIT'
[Unit]
Description=Unlock Archipelago LUKS data partition
DefaultDependencies=no
Before=local-fs-pre.target
After=systemd-udevd.service
Wants=systemd-udevd.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c '\
if [ -e /dev/mapper/archipelago-data ]; then exit 0; fi; \
DATA_DEV=$(blkid -t TYPE=crypto_LUKS -o device 2>/dev/null | head -1); \
if [ -z "$DATA_DEV" ]; then exit 0; fi; \
cryptsetup open --type luks2 --key-file /root/.luks-archipelago.key "$DATA_DEV" archipelago-data'
[Install]
WantedBy=local-fs-pre.target
LUKSUNIT
chroot /mnt/target systemctl enable archipelago-luks-unlock.service 2>/dev/null || \
ln -sf /etc/systemd/system/archipelago-luks-unlock.service /mnt/target/etc/systemd/system/local-fs-pre.target.wants/archipelago-luks-unlock.service
# Create fstab
cat > /mnt/target/etc/fstab <<EOF
# Archipelago Bitcoin Node OS
UUID=$(blkid -s UUID -o value "$ROOT_PART") / ext4 errors=remount-ro 0 1
UUID=$(blkid -s UUID -o value "$EFI_PART") /boot/efi vfat umask=0077 0 1
/dev/mapper/archipelago-data /var/lib/archipelago ext4 defaults 0 2
/dev/mapper/archipelago-data /var/lib/archipelago ext4 defaults,nofail,x-systemd.device-timeout=60 0 2
EOF
# Configure hostname
@@ -2055,7 +2122,13 @@ if [ -f /mnt/target/usr/lib/podman/netavark ]; then
cat > /mnt/target/home/archipelago/.config/containers/containers.conf <<'CONTAINERSCONF'
[network]
network_backend = "netavark"
default_rootless_network_cmd = "pasta"
[engine]
image_copy_tmp_dir = "/var/lib/archipelago/containers/tmp"
CONTAINERSCONF
mkdir -p /mnt/target/var/lib/archipelago/containers/tmp
chown -R 1000:1000 /mnt/target/var/lib/archipelago/containers/tmp
chown -R 1000:1000 /mnt/target/home/archipelago/.config/containers
echo " Configured netavark backend (container DNS enabled)"
else
@@ -2623,15 +2696,9 @@ if [ -d "$BOOT_MEDIA/archipelago/plymouth-theme" ]; then
chroot /mnt/target plymouth-set-default-theme archipelago 2>/dev/null || \
ln -sf /usr/share/plymouth/themes/archipelago/archipelago.plymouth \
/mnt/target/etc/alternatives/default.plymouth 2>/dev/null || true
# Enable splash and ACPI in GRUB
if ! grep -q "splash" /mnt/target/etc/default/grub; then
sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"/GRUB_CMDLINE_LINUX_DEFAULT="\1 splash"/' \
/mnt/target/etc/default/grub 2>/dev/null || true
fi
if ! grep -q "acpi=force" /mnt/target/etc/default/grub; then
sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"/GRUB_CMDLINE_LINUX_DEFAULT="\1 acpi=force"/' \
/mnt/target/etc/default/grub 2>/dev/null || true
fi
# Configure clean boot: splash, suppress kernel noise, hide cursor
sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT=".*"/GRUB_CMDLINE_LINUX_DEFAULT="quiet splash loglevel=0 rd.systemd.show_status=false vt.global_cursor_default=0 acpi=force"/' \
/mnt/target/etc/default/grub 2>/dev/null || true
echo " Installed Archipelago Plymouth theme on target"
fi
@@ -2816,6 +2883,7 @@ chroot /mnt/target systemctl enable archipelago-load-images.service 2>/dev/null
chroot /mnt/target systemctl enable archipelago-setup-tor.service 2>/dev/null || true
chroot /mnt/target systemctl enable archipelago-first-boot-containers.service 2>/dev/null || true
chroot /mnt/target systemctl enable archipelago-kiosk.service 2>/dev/null || true
chroot /mnt/target systemctl enable nostr-vpn.service 2>/dev/null || true
# Enable claude-api-proxy (create symlink manually — chroot systemctl can fail)
chroot /mnt/target systemctl enable claude-api-proxy.service 2>/dev/null || \
ln -sf /etc/systemd/system/claude-api-proxy.service /mnt/target/etc/systemd/system/multi-user.target.wants/claude-api-proxy.service 2>/dev/null || true
@@ -3079,15 +3147,21 @@ fi
set timeout=5
set default=0
# Serial console for QEMU/headless testing
insmod serial
serial --unit=0 --speed=115200
terminal_input serial console
terminal_output serial console
# Load font for graphical menu — fallback to text mode on hardware without gfxterm
if loadfont ($root)/boot/grub/font.pf2; then
set gfxmode=auto
set gfxpayload=keep
insmod gfxterm
insmod png
terminal_output gfxterm
terminal_output gfxterm serial
else
terminal_output console
terminal_output console serial
fi
# Archipelago GRUB theme
@@ -3103,7 +3177,7 @@ else
fi
menuentry "Install Archipelago" --hotkey=i {
linux ($root)/live/vmlinuz boot=live components quiet splash loglevel=0 rd.systemd.show_status=false vt.global_cursor_default=0 acpi=force
linux ($root)/live/vmlinuz boot=live components quiet splash loglevel=0 rd.systemd.show_status=false vt.global_cursor_default=0 acpi=force console=ttyS0,115200 console=tty0
initrd ($root)/live/initrd.img
}

View File

@@ -3,6 +3,10 @@ limit_req_zone $binary_remote_addr zone=rpc:10m rate=20r/s;
limit_req_zone $binary_remote_addr zone=auth:10m rate=3r/s;
limit_req_zone $binary_remote_addr zone=peer:10m rate=10r/s;
# Resolve external domains at request time (not startup) to prevent boot failures
resolver 1.1.1.1 8.8.8.8 valid=300s ipv6=off;
resolver_timeout 5s;
server {
listen 80;
server_name _;
@@ -46,7 +50,9 @@ server {
# AIUI OpenRouter API proxy (API key managed by proxy, no session gate needed)
location /aiui/api/openrouter/ {
proxy_pass https://openrouter.ai/api/;
set $upstream_1 "https://openrouter.ai/api/";
proxy_pass $upstream_1;
proxy_http_version 1.1;
proxy_set_header Host openrouter.ai;
proxy_ssl_server_name on;
@@ -175,6 +181,20 @@ server {
error_page 504 = @backend_timeout;
}
# LND REST proxy — backend handles auth + CORS
location /proxy/lnd/ {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 10s;
proxy_read_timeout 10s;
proxy_send_timeout 5s;
error_page 502 503 = @backend_unavailable;
error_page 504 = @backend_timeout;
}
# Content sharing — peer access over Tor (no auth)
location /content {
limit_req zone=peer burst=20 nodelay;
@@ -662,7 +682,9 @@ server {
# External site proxies — strip X-Frame-Options so iframe embedding works.
# add_header here prevents inheritance of server-level X-Frame-Options.
location /ext/botfights/ {
proxy_pass https://botfights.net/;
set $upstream_2 "https://botfights.net/";
proxy_pass $upstream_2;
proxy_http_version 1.1;
proxy_set_header Host botfights.net;
proxy_set_header Accept-Encoding "";
@@ -684,7 +706,9 @@ server {
sub_filter '</head>' '<script src="/nostr-provider.js"></script></head>';
}
location /ext/484-kitchen/ {
proxy_pass https://484.kitchen/;
set $upstream_3 "https://484.kitchen/";
proxy_pass $upstream_3;
proxy_http_version 1.1;
proxy_set_header Host 484.kitchen;
proxy_set_header Accept-Encoding "";
@@ -703,7 +727,9 @@ server {
sub_filter '</head>' '<script src="/nostr-provider.js"></script></head>';
}
location /ext/arch-presentation/ {
proxy_pass https://present.l484.com/;
set $upstream_4 "https://present.l484.com/";
proxy_pass $upstream_4;
proxy_http_version 1.1;
proxy_set_header Host present.l484.com;
proxy_set_header Accept-Encoding "";
@@ -722,7 +748,9 @@ server {
sub_filter '</head>' '<script src="/nostr-provider.js"></script></head>';
}
location /ext/nostrudel/ {
proxy_pass https://nostrudel.ninja/;
set $upstream_5 "https://nostrudel.ninja/";
proxy_pass $upstream_5;
proxy_http_version 1.1;
proxy_set_header Host nostrudel.ninja;
proxy_set_header Accept-Encoding "";
@@ -818,7 +846,9 @@ server {
proxy_send_timeout 120s;
}
location /aiui/api/openrouter/ {
proxy_pass https://openrouter.ai/api/;
set $upstream_6 "https://openrouter.ai/api/";
proxy_pass $upstream_6;
proxy_http_version 1.1;
proxy_set_header Host openrouter.ai;
proxy_ssl_server_name on;
@@ -886,6 +916,20 @@ server {
error_page 504 = @backend_timeout;
}
# LND REST proxy — backend handles auth + CORS
location /proxy/lnd/ {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 10s;
proxy_read_timeout 10s;
proxy_send_timeout 5s;
error_page 502 503 = @backend_unavailable;
error_page 504 = @backend_timeout;
}
# Content sharing — peer access over Tor (no auth)
location /content {
limit_req zone=peer burst=20 nodelay;
@@ -1038,7 +1082,9 @@ server {
# External site proxies — strip X-Frame-Options so iframe embedding works.
# add_header here prevents inheritance of server-level X-Frame-Options.
location /ext/botfights/ {
proxy_pass https://botfights.net/;
set $upstream_7 "https://botfights.net/";
proxy_pass $upstream_7;
proxy_http_version 1.1;
proxy_set_header Host botfights.net;
proxy_set_header Accept-Encoding "";
@@ -1060,7 +1106,9 @@ server {
sub_filter '</head>' '<script src="/nostr-provider.js"></script></head>';
}
location /ext/484-kitchen/ {
proxy_pass https://484.kitchen/;
set $upstream_8 "https://484.kitchen/";
proxy_pass $upstream_8;
proxy_http_version 1.1;
proxy_set_header Host 484.kitchen;
proxy_set_header Accept-Encoding "";
@@ -1079,7 +1127,9 @@ server {
sub_filter '</head>' '<script src="/nostr-provider.js"></script></head>';
}
location /ext/arch-presentation/ {
proxy_pass https://present.l484.com/;
set $upstream_9 "https://present.l484.com/";
proxy_pass $upstream_9;
proxy_http_version 1.1;
proxy_set_header Host present.l484.com;
proxy_set_header Accept-Encoding "";
@@ -1098,7 +1148,9 @@ server {
sub_filter '</head>' '<script src="/nostr-provider.js"></script></head>';
}
location /ext/nostrudel/ {
proxy_pass https://nostrudel.ninja/;
set $upstream_10 "https://nostrudel.ninja/";
proxy_pass $upstream_10;
proxy_http_version 1.1;
proxy_set_header Host nostrudel.ninja;
proxy_set_header Accept-Encoding "";
@@ -1139,7 +1191,9 @@ server {
listen 8901;
server_name _;
location / {
proxy_pass https://botfights.net;
set $upstream_11 "https://botfights.net";
proxy_pass $upstream_11;
proxy_http_version 1.1;
proxy_set_header Host botfights.net;
proxy_set_header Accept-Encoding "";
@@ -1164,7 +1218,9 @@ server {
listen 8902;
server_name _;
location / {
proxy_pass https://484.kitchen;
set $upstream_12 "https://484.kitchen";
proxy_pass $upstream_12;
proxy_http_version 1.1;
proxy_set_header Host 484.kitchen;
proxy_set_header Accept-Encoding "";
@@ -1185,7 +1241,9 @@ server {
listen 8903;
server_name _;
location / {
proxy_pass https://present.l484.com;
set $upstream_13 "https://present.l484.com";
proxy_pass $upstream_13;
proxy_http_version 1.1;
proxy_set_header Host present.l484.com;
proxy_set_header Accept-Encoding "";