- Add automatic UID mapping fix to deploy script: uses sudo chown to
set host UIDs matching rootless podman's subuid mapping (container
UID 0→100000, 70→100070, 101→100101, 472→100472, 999→100999)
- Fix rpcallowip: rootless podman uses 10.89.0.0/16 not 10.88.0.0/16,
changed to 0.0.0.0/0 (safe: only accessible via port mapping)
- ProtectHome=no + no PrivateTmp: rootless podman needs shared /tmp
and writable ~/.local/share/containers
All 22 containers now running under rootless podman with working
Bitcoin RPC at block 941163.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
RestrictNamespaces and SystemCallFilter block rootless podman from
creating user namespaces needed for container isolation. Removed these
along with RestrictSUIDSGID (implied by NoNewPrivileges). ProtectHome
set to no (rootless podman needs ~/.local/share/containers writable).
Remaining active protections: NoNewPrivileges, ProtectSystem=strict,
ReadWritePaths, RestrictAddressFamilies, MemoryDenyWriteExecute,
RestrictRealtime, SystemCallArchitectures=native.
Also reduced initial scan delay from 15s to 3s for faster container
visibility after boot, and removed Ollama from auto-deploy.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The security hardening (NoNewPrivileges, RestrictAddressFamilies,
MemoryDenyWriteExecute, RestrictRealtime, ProtectSystem=strict) all
blocked podman container management via sudo. These are temporarily
disabled until TASK-11 (rootless podman migration) is complete.
Remaining active protections: ProtectSystem=true (/usr, /boot),
ProtectHome=yes, PrivateTmp=yes, PrivateDevices=no (mesh radio).
Also adds TASK-11 to MASTER_PLAN.md for tracking the rootless podman
migration that will allow re-enabling full security hardening.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added containers_scanned flag to StatusInfo in the data model. Starts
false, set to true after the first Podman scan completes (~15s after
boot). Marketplace now shows a shimmer "Checking..." indicator on app
buttons until the scan finishes, preventing users from accidentally
re-installing apps that are already present but not yet enumerated.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CARGO_PKG_VERSION already contains -alpha from Cargo.toml, so the
format!("{}-alpha", ...) was producing 1.2.0-alpha-alpha. Use the
Cargo version directly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add https: to CSP frame-src so external site iframes (BotFights,
484 Kitchen, etc.) load without being blocked by Content-Security-Policy
- Show spinner + "Starting..." on marketplace cards for containers that
are booting up, preventing users from re-installing running apps
- Add spinner to transitional state badges (starting/stopping/installing)
on installed app cards in Apps view
- Add "What's New" button to Settings version card with release notes
modal covering recent highlights in layman-friendly language
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: systemd PrivateDevices=yes hid /dev/ttyUSB* from the service,
preventing .198 from connecting to its Heltec V3 after the security hardening.
Changes:
- Set PrivateDevices=no in systemd service (serial access needs physical devices;
other hardening layers remain: NoNewPrivileges, ProtectSystem, RestrictNamespaces)
- Add SupplementaryGroups=dialout for explicit serial permissions
- Add fallback auto-detect when configured serial path fails to open
- Add exponential backoff on reconnect (5s→60s cap) to reduce log spam
- Add pre-open device existence check with actionable error messages
- Add udev rule (99-mesh-radio.rules) for stable /dev/mesh-radio symlink
- Add /dev/mesh-radio to serial candidate list (checked first)
- Add Connect button per detected device in Mesh UI
- Deploy udev rule to both servers and ISO build
- Fix FEDI_HASH unbound variable in deploy script
- Fix deploy binary step to handle hung service stop gracefully
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bitcoin Knots: added -proxy=127.0.0.1:9050 for P2P connections through Tor
- LND: enabled tor.active=true, tor.socks, tor.streamisolation in lnd.conf
- Tor setup handled by existing archipelago-setup-tor.service at first boot
- .onion display and Tor toggle already present in Settings UI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- SecretsManager: raw key stored in Zeroizing<[u8; 32]>, auto-zeroed on drop
- SecretsManager: replaced thread_rng with OsRng (CSPRNG) for nonces
- Remember-me secret: derived from machine-id via SHA-256 (deterministic, no
plaintext key storage)
- Bitcoin ecash balance: uses checked_add with u64::MAX saturation on overflow
- TOTP setup/confirm: added to EndpointRateLimiter (3 and 5 per 5min)
- AppId validation and Tor service name validation already existed
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CSP: removed unsafe-eval, tightened frame-src to self + host ports,
added frame-ancestors, base-uri, form-action directives
- X-Frame-Options: SAMEORIGIN added after proxy_hide_header on all app proxies
- HSTS: max-age=31536000; includeSubDomains on all server blocks
- Rate limiting: 20r/s on /rpc/ with burst=40, 3r/s auth zone
- Added X-DNS-Prefetch-Control, Permissions-Policy payment=() header
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- VPN key gen: replaced sh -c with format string (command injection) with
safe stdin piping to wg pubkey
- Secrets manager: replaced .unwrap() on path.parent() with proper error
- Tor proxy: replaced .expect("valid proxy") with continue on error
- Image verifier: added require_signatures flag, strict mode rejects
unsigned images and missing cosign binary
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Generate unique random passwords at first boot for Bitcoin RPC, all database
services (mempool, btcpay, immich, penpot, mysql-root), and Fedimint gateway.
Credentials stored in /var/lib/archipelago/secrets/ with 600 permissions.
Scripts: first-boot-containers.sh, deploy-to-target.sh, deploy-bitcoin-knots.sh,
container-doctor.sh all read from secrets files instead of hardcoded values.
Rust backend: new bitcoin_rpc module reads password from secrets file, env var,
or dev fallback. All .basic_auth() calls and container config strings now use
the shared credential reader instead of hardcoded "archipelago123".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Frontend store (mesh.ts):
- Add typed message interfaces: InvoiceData, AlertData, CoordinateData,
SessionStatus, AlertStatus, MeshMessageTypeLabel
- New actions: sendInvoice, sendCoordinate, sendAlert, getSessionStatus,
rotatePrekeys
Mesh.vue UI:
- Typed message rendering in chat bubbles:
- Invoice: orange card with sats amount, memo, bolt11 preview, paid badge
- Alert: red card (emergency/dead_man) or blue (status), signed badge,
GPS link to OpenStreetMap
- Coordinate: blue card with lat/lng, label, OSM map link
- Block header: purple inline with chain icon
- Session badge in chat header: green shield (Double Ratchet),
yellow (static encryption), gray (none)
- Session status fetched on peer selection via mesh.session-status RPC
Mock backend:
- Messages now include message_type and typed_payload fields
- Mix of text, invoice (paid + unpaid), alert (emergency + status),
coordinate, and block_header messages for testing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bitcoin relay (mesh/bitcoin_relay.rs):
- BlockHeaderCache: stores latest block headers from internet peers for SPV
- RelayTracker: tracks in-flight TX and Lightning relay requests
- Builder functions: block header announcements (Ed25519 signed),
TX relay request/response, Lightning invoice relay/response
- All amounts as u64 sats, never float
- 4 unit tests
Emergency alerts (mesh/alerts.rs):
- AlertConfig: dead man switch settings, GPS, emergency contacts
- DeadManSwitch: background timer, auto-trigger after configurable interval
(default 6h), signed alert broadcast with GPS coordinates
- check_in() resets timer, is_triggered() checks elapsed time
- GPS as integer microdegrees (Coordinate type from message_types)
- Disk persistence for config
- 4 unit tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend (6 new RPC endpoints):
- mesh.send-invoice: create Lightning invoice, send bolt11 to mesh peer
- mesh.send-coordinate: send GPS coordinates (integer microdegrees)
- mesh.send-alert: send signed emergency alert (with optional GPS)
- mesh.outbox: list pending store-and-forward messages
- mesh.session-status: get Double Ratchet session info per peer
- mesh.rotate-prekeys: force X3DH prekey rotation
Mock backend: matching dev mode responses for all 6 new endpoints
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create mesh/session.rs: SessionManager for Double Ratchet state lifecycle
- Lazy-loads sessions from disk on first message
- Saves after every encrypt/decrypt (chain key advancement)
- Per-DID storage at {data_dir}/ratchet/{sha256(did)}.json
- Session info API for RPC status reporting
- Zeroize on drop for all key material
- Tests: store+load roundtrip, encrypt/decrypt through manager, session removal
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Federation: 3 federated nodes with full state snapshots (apps, CPU, disk, uptime)
- Federation invite/join/sync/set-trust/remove/deploy-app mock handlers
- DWN status with 3 protocols, message counts, sync state
- Enables testing Federation.vue and Web5.vue in local dev mode
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add off-grid (mesh only) toggle to Mesh.vue with orange OFF-GRID banner
- Add per-peer transport indicator in Federation.vue (mesh/lan/tor icons)
- Add sync_with_peer_via_transport() for CBOR delta sync via transport router
- Fetch transport store on mount in both Mesh and Federation views
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Resolve stash conflicts in Cargo.toml, rpc/mod.rs, AppDetails.vue, Apps.vue
- Fix ScopedIp conversion in LAN transport (mdns-sd compatibility)
- Fix String vs &str in transport RPC send handler
- Remove duplicate mod transport declaration
- Remove stale mesh.discover route (replaced by mesh.peers/messages/send)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Private repo needs auth — pass GITEA_TOKEN as env var in Portainer,
never hardcoded. Or make the repo public to skip auth entirely.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No submodule needed — the Dockerfile clones the IndeedHub repo
directly during build. Works with Portainer without any manual steps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
IndeedHub source included as git submodule at ./indeedhub/.
Demo compose builds all services from source — no registry needed.
Stack: app, api, postgres, redis, minio, relay.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Just pull git.tx1138.com/lfg2025/indeedhub:latest directly.
No source build, no backend stack needed for demo.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
IndeedHub builds from source instead of registry images. Clone the
indeedhub repo as a sibling directory:
git clone https://git.tx1138.com/lfg2025/indeehub.git indeedhub
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full 8-service IndeedHub stack: app (frontend), api (NestJS), postgres,
redis, minio (S3), minio-init, ffmpeg-worker, nostr-relay.
All env vars have sensible defaults for demo — override in Portainer
env vars for production. IndeedHub builds from ../Indeedhub Prototype
source. Frontend on port 7777 with NIP-07 nostr-provider.js for
signing via Archipelago's identity system.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The toggle handler only tried `podman restart archy-tor` which fails
on servers running Tor as a systemd service. Now tries
`systemctl restart tor` first (like the rotation handler already does),
falling back to container restart.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every enabled Tor service now shows a Rotate button that instantly
creates a new .onion address and decommissions the old one. Previously
only the main 'archipelago' service had this button.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix .onion address overflow: add min-width:0 to flex children
- Reduce field font size for long addresses
- Auto-select Local Network mode when Tor unavailable
- Fix Tor hidden service paths on Arch 1/3 (was /var/lib/tor/,
backend reads /var/lib/archipelago/tor/)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When tor_onion is null in the connect info response, automatically
switch dropdown to "REST (Local Network)" and show a helpful message
instead of "Tor not configured for LND" error.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- fetchConnectInfo: use window.location.protocol instead of hardcoded http://
- getBackendUrl: default to current origin when no ?backend= param
- Fixes mixed content errors on HTTPS Tailscale servers
- Also fixed: nginx needed reload on Tailscale servers, Arch 2 missing
/lnd-connect-info nginx location
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- LND UI: replace cdn.tailwindcss.com with local tailwind.css (CSP fix)
- LND UI: make asset paths relative for nginx proxy compatibility
- Web5 wallet: add QR code for on-chain receive addresses (qrcode npm)
- Web5 wallet: hide incoming transactions after 3 confirmations
- Apps: add "Services" tab to separate backend containers from user apps
- Home: null guard on packages.value to prevent TypeError on load
- First-boot: auto-create Bitcoin Knots wallet (no longer auto-created)
- AppSession: add mempool-electrs to port mapping
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>