[1;33m[WARNING][0m No existing semantic tags found. Starting from v0.0.0
v0.0.1 - Reorganize ISO build tree, add docs/plans/scripts, and stage Phase 2 Slice B+C service integration artifacts
This commit is contained in:
644
plans/slice_bc_fips_crelay.md
Normal file
644
plans/slice_bc_fips_crelay.md
Normal file
@@ -0,0 +1,644 @@
|
||||
# Slice B + C: Add fips and c-relay to the n-OS-tr ISO
|
||||
|
||||
## Status: **Ready for implementation**
|
||||
|
||||
This document specifies the work required to enable the [fips](../includes/fips)
|
||||
mesh-routing daemon and the [c-relay](../includes/c-relay) Nostr relay on the
|
||||
live ISO built by [`build.sh`](../build.sh), replacing the current Slice A
|
||||
(ginxsom + nginx only) with the full three-service stack planned in
|
||||
[`iso_architecture.md`](./iso_architecture.md).
|
||||
|
||||
---
|
||||
|
||||
## 1. Design Decisions (captured from user)
|
||||
|
||||
| # | Topic | Decision |
|
||||
|---|---|---|
|
||||
| 1 | Source of c-relay binary | User-provided, already downloaded into [`includes/c-relay/`](../includes/c-relay) |
|
||||
| 2 | Source of fips binaries | Build locally via `cargo deb` during `build.sh` |
|
||||
| 3 | c-relay admin nsec strategy | **Ephemeral** — c-relay self-provisions per boot, admin nsec captured from journald |
|
||||
| 4 | fips identity | **Ephemeral** — new npub per boot, no persistent key management for this slice |
|
||||
| 5 | fips peer config | Connect to the same public bootstrap node used elsewhere in the repo: `npub1qmc3cvfz0yu2hx96nq3gp55zdan2qclealn7xshgr448d3nh6lks7zel98` at `217.77.8.91:2121` (UDP), per [`examples/sidecar-nostr-relay/.env`](../includes/fips/examples/sidecar-nostr-relay/.env:9) et al. |
|
||||
| 6 | fips transport | **Ethernet** enabled, plus UDP for the static peer |
|
||||
| 7 | fips-gateway | Disabled (default) |
|
||||
| 8 | c-relay exposure | nginx reverse-proxies `wss://host/relay` → `ws://127.0.0.1:8888/`; nginx reverse-proxies `/admin/` → `http://127.0.0.1:8888/api/` |
|
||||
| 9 | Scope | Full Slice B+C — services, nginx wiring, package deps, smoke test, MOTD, README updates |
|
||||
| 10 | Key management / identity continuity | Out of scope for this slice — revisit in a later pass |
|
||||
|
||||
---
|
||||
|
||||
## 2. What Already Exists (Slice A baseline)
|
||||
|
||||
Confirmed present and working, per source inspection:
|
||||
|
||||
- [`iso/auto/config`](../iso/auto/config) — live-build config
|
||||
- [`iso/config/package-lists/base.list.chroot`](../iso/config/package-lists/base.list.chroot) — nginx-light, spawn-fcgi, ca-certificates, curl, jq, vim, htop
|
||||
- [`iso/config/includes.chroot/etc/systemd/system/ginxsom.service`](../iso/config/includes.chroot/etc/systemd/system/ginxsom.service)
|
||||
- [`iso/config/includes.chroot/etc/systemd/system/n-os-tr-firstboot.service`](../iso/config/includes.chroot/etc/systemd/system/n-os-tr-firstboot.service)
|
||||
- [`iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf`](../iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf) — `:443` TLS, Blossom routing, static landing page
|
||||
- [`iso/config/includes.chroot/usr/local/sbin/n-os-tr-firstboot`](../iso/config/includes.chroot/usr/local/sbin/n-os-tr-firstboot) — generates ginxsom nsec + self-signed TLS
|
||||
- [`iso/config/includes.chroot/usr/local/bin/n-os-tr-smoketest`](../iso/config/includes.chroot/usr/local/bin/n-os-tr-smoketest) — 5 PASS + 8 SKIP placeholder
|
||||
- [`iso/config/includes.chroot/usr/local/bin/nak`](../iso/config/includes.chroot/usr/local/bin/nak) — Nostr CLI helper
|
||||
- [`iso/config/includes.chroot/usr/local/bin/ginxsom/ginxsom-fcgi`](../iso/config/includes.chroot/usr/local/bin/ginxsom/ginxsom-fcgi) — Blossom FastCGI binary
|
||||
- [`iso/config/hooks/live/0020-enable-services.hook.chroot`](../iso/config/hooks/live/0020-enable-services.hook.chroot) — enables nginx, ginxsom, firstboot
|
||||
|
||||
Slice A smoke test passes `5 PASS, 0 FAIL, 8 SKIP` on a freshly-booted USB.
|
||||
|
||||
---
|
||||
|
||||
## 3. What Needs to Change (target state)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Build [Build-time build.sh]
|
||||
BS[build.sh]
|
||||
CDB[cargo deb in<br/>includes/fips]
|
||||
FDeb[iso/local-artifacts/fips_0.3.0_amd64.deb]
|
||||
CRX[includes/c-relay/c_relay_x86]
|
||||
CRC[iso/local-artifacts/c_relay_x86]
|
||||
BS --> CDB --> FDeb
|
||||
BS --> CRC
|
||||
end
|
||||
subgraph Chroot [live-build chroot phase]
|
||||
H1[0010-fetch-artifacts.hook.chroot]
|
||||
FDeb --> H1
|
||||
CRC --> H1
|
||||
H1 -->|dpkg -i| FInst[/usr/bin/fips etc]
|
||||
H1 -->|install -m 0755| CInst[/opt/c-relay/c_relay_x86]
|
||||
H1 -->|adduser --system| CUsr[c-relay system user]
|
||||
H1 -->|write fips.yaml| FCfg[/etc/fips/fips.yaml]
|
||||
end
|
||||
subgraph Boot [Runtime at boot]
|
||||
Fb[n-os-tr-firstboot]
|
||||
Fips[fips.service]
|
||||
FDns[fips-dns.service]
|
||||
CRel[c-relay.service]
|
||||
Gx[ginxsom.service]
|
||||
Ng[nginx.service]
|
||||
Fb --> Gx
|
||||
Fips --> FDns
|
||||
Ng -->|wss /relay| CRel
|
||||
Ng -->|http /admin/| CRel
|
||||
end
|
||||
```
|
||||
|
||||
### Summary of changes
|
||||
|
||||
| Area | Change |
|
||||
|---|---|
|
||||
| Build system | [`build.sh`](../build.sh) gains a pre-build step: build fips `.deb` via `cargo deb` and stage artifacts into [`iso/local-artifacts/`](../iso/local-artifacts) |
|
||||
| Artifact layout | New directory [`iso/local-artifacts/`](../iso/local-artifacts) holds `fips_*_amd64.deb` and `c_relay_x86` — gitignored |
|
||||
| Chroot hook (new) | [`iso/config/hooks/live/0010-fetch-artifacts.hook.chroot`](../iso/config/hooks/live/0010-fetch-artifacts.hook.chroot) installs those two artifacts into the chroot |
|
||||
| Package list | [`iso/config/package-lists/base.list.chroot`](../iso/config/package-lists/base.list.chroot) adds runtime deps: `libdbus-1-3`, `iproute2`, `nftables` (optional for gateway mode later) |
|
||||
| fips config | New [`iso/config/includes.chroot/etc/fips/fips.yaml`](../iso/config/includes.chroot/etc/fips/fips.yaml) overriding the package default with ethernet + static UDP peer enabled |
|
||||
| c-relay service | New [`iso/config/includes.chroot/etc/systemd/system/c-relay.service`](../iso/config/includes.chroot/etc/systemd/system/c-relay.service) — adapted from [upstream unit](../includes/c-relay/systemd/c-relay.service) |
|
||||
| c-relay user | Chroot hook creates `c-relay` system user + `/opt/c-relay/` working dir |
|
||||
| nginx config | [`iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf`](../iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf) gains `/relay` wss upgrade and `/admin/` proxy locations |
|
||||
| Service-enable hook | [`0020-enable-services.hook.chroot`](../iso/config/hooks/live/0020-enable-services.hook.chroot) also enables `fips.service`, `fips-dns.service`, `c-relay.service` |
|
||||
| Smoke test | [`n-os-tr-smoketest`](../iso/config/includes.chroot/usr/local/bin/n-os-tr-smoketest) replaces the 8 SKIPs with real checks |
|
||||
| MOTD / README | First-boot script and docs updated to surface how to find c-relay admin nsec and fips identity |
|
||||
| `.gitignore` | Add `iso/local-artifacts/` |
|
||||
|
||||
---
|
||||
|
||||
## 4. Concrete Artifact Details
|
||||
|
||||
### 4.1 c-relay static binary
|
||||
|
||||
- **Source:** [`includes/c_relay_static_x86_64`](../includes/c_relay_static_x86_64) — user-downloaded static-musl build, already present at the top level of `includes/` (NOT inside `includes/c-relay/`). Filename confirmed by directory listing.
|
||||
- **Staged as:** `iso/config/includes.chroot_before_packages/live-artifacts/c_relay_x86` (canonical name used by the chroot hook and systemd unit — we rename on copy so `c-relay.service` can reference a stable filename regardless of which upstream build variant the user drops in).
|
||||
- **Target in chroot:** `/opt/c-relay/c_relay_x86`, mode `0755`, owner `c-relay:c-relay`.
|
||||
- **Copied by:** `build.sh` copies [`includes/c_relay_static_x86_64`](../includes/c_relay_static_x86_64) → staging area → chroot hook installs to `/opt/c-relay/`.
|
||||
|
||||
### 4.2 `iso/local-artifacts/fips_0.3.0_amd64.deb`
|
||||
|
||||
- **Source:** built by `build.sh` via `cd includes/fips && packaging/debian/build-deb.sh`. Requires `cargo-deb` installed on the build host (`cargo install cargo-deb` if absent; `build.sh` will check and fail clearly).
|
||||
- **Contents (per [`Cargo.toml`](../includes/fips/Cargo.toml:70-83)):**
|
||||
- `/usr/bin/fips`, `/usr/bin/fipsctl`, `/usr/bin/fipstop`, `/usr/bin/fips-gateway`
|
||||
- `/etc/fips/fips.yaml` (package default — will be overridden by our includes.chroot version)
|
||||
- `/etc/fips/hosts`
|
||||
- `/lib/systemd/system/fips.service`, `/lib/systemd/system/fips-dns.service`, `/lib/systemd/system/fips-gateway.service`
|
||||
- `/usr/lib/fips/fips-dns-setup`, `/usr/lib/fips/fips-dns-teardown`
|
||||
- `/usr/lib/tmpfiles.d/fips.conf`
|
||||
- **Runtime deps (per Cargo.toml):** `libc6, systemd, libdbus-1-3`, recommends `bluez` (skipped — not needed for non-BLE).
|
||||
- **Installed by:** chroot hook runs `dpkg -i /tmp/artifacts/fips_*_amd64.deb` then cleans up. The postinst enables `fips.service` and `fips-dns.service` automatically.
|
||||
|
||||
### 4.3 `iso/config/includes.chroot/etc/fips/fips.yaml`
|
||||
|
||||
Overrides the Debian-packaged default at `/etc/fips/fips.yaml`. The live-build
|
||||
`includes.chroot` mechanism copies this on top after package install. Content:
|
||||
|
||||
```yaml
|
||||
# n-OS-tr fips configuration.
|
||||
# Ephemeral identity: new keypair every boot (default).
|
||||
# To make identity persistent across reboots on a live USB with a
|
||||
# persistence partition, set node.identity.persistent: true.
|
||||
|
||||
node:
|
||||
identity:
|
||||
# ephemeral by default
|
||||
|
||||
tun:
|
||||
enabled: true
|
||||
name: fips0
|
||||
mtu: 1280
|
||||
|
||||
dns:
|
||||
enabled: true
|
||||
port: 5354
|
||||
|
||||
transports:
|
||||
udp:
|
||||
bind_addr: "0.0.0.0:2121"
|
||||
tcp:
|
||||
bind_addr: "0.0.0.0:8443"
|
||||
ethernet:
|
||||
# Ethernet transport auto-discovers LAN peers.
|
||||
# interface: omitted → fips picks the first non-loopback interface.
|
||||
# Override with an explicit interface name if your board uses
|
||||
# something other than the default (e.g. enp5s0, eno1, eth0).
|
||||
discovery: true
|
||||
announce: true
|
||||
auto_connect: true
|
||||
accept_connections: true
|
||||
|
||||
# Static peer for internet bootstrap.
|
||||
# Matches the same "fips-test-node" / "vps-chi" public node used across
|
||||
# the repo's example configs (see includes/fips/examples/... and
|
||||
# includes/fips/testing/sidecar/.env).
|
||||
peers:
|
||||
- npub: "npub1qmc3cvfz0yu2hx96nq3gp55zdan2qclealn7xshgr448d3nh6lks7zel98"
|
||||
alias: "fips-test-node"
|
||||
addresses:
|
||||
- transport: udp
|
||||
addr: "217.77.8.91:2121"
|
||||
connect_policy: auto_connect
|
||||
```
|
||||
|
||||
Notes:
|
||||
- Omitting `ethernet.interface` relies on fips's auto-selection logic. If that
|
||||
doesn't pick a sensible interface, add `interface: "eth0"` (verified post-boot
|
||||
via `ip link show`).
|
||||
- Keeping the `udp` bootstrap peer in addition to `ethernet` gives the mesh
|
||||
internet reachability even when the LAN has no other fips peers.
|
||||
|
||||
### 4.4 `iso/config/includes.chroot/etc/systemd/system/c-relay.service`
|
||||
|
||||
Adapted from [upstream](../includes/c-relay/systemd/c-relay.service) with
|
||||
minor tweaks for the live environment:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=C Nostr Relay (n-OS-tr slice C)
|
||||
Documentation=file:///usr/share/doc/n-os-tr/README
|
||||
After=network.target n-os-tr-firstboot.service
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=c-relay
|
||||
Group=c-relay
|
||||
WorkingDirectory=/opt/c-relay
|
||||
Environment=DEBUG_LEVEL=0
|
||||
# c-relay self-provisions admin + relay keys on first start and prints
|
||||
# the admin nsec to stdout (captured by journald).
|
||||
ExecStart=/opt/c-relay/c_relay_x86 --debug-level=${DEBUG_LEVEL}
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=c-relay
|
||||
|
||||
# Hardening
|
||||
NoNewPrivileges=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ReadWritePaths=/opt/c-relay
|
||||
PrivateTmp=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectControlGroups=true
|
||||
RestrictAddressFamilies=AF_INET AF_INET6
|
||||
LimitNOFILE=65536
|
||||
LimitNPROC=4096
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### 4.5 Updated nginx site — `/relay` wss + `/admin/` proxy
|
||||
|
||||
New locations appended to [`iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf`](../iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf) inside the existing `server { listen 443 ssl; ... }` block, before the ginxsom FastCGI blocks:
|
||||
|
||||
```nginx
|
||||
# --- c-relay reverse proxy (slice C) ---------------------------------
|
||||
|
||||
# Nostr relay WebSocket: wss://host/relay → ws://127.0.0.1:8888/
|
||||
# The client library expects a WebSocket upgrade on /relay; c-relay
|
||||
# itself listens on "/" so we rewrite and proxy to its root.
|
||||
location = /relay {
|
||||
proxy_pass http://127.0.0.1:8888/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 86400;
|
||||
proxy_send_timeout 86400;
|
||||
}
|
||||
|
||||
# NIP-11 relay info doc (available at wss://host/relay with
|
||||
# Accept: application/nostr+json). Proxied to the same backend.
|
||||
# If you want /relay (GET without upgrade) to return NIP-11 too,
|
||||
# the location above already handles it — c-relay's NIP-11 handler
|
||||
# triggers based on the Accept header, not the path.
|
||||
|
||||
# c-relay embedded web admin UI: https://host/admin/ → http://127.0.0.1:8888/api/
|
||||
location /admin/ {
|
||||
proxy_pass http://127.0.0.1:8888/api/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
- The `/admin/` path deliberately overlaps with a Blossom admin path, but
|
||||
Blossom's admin routes go via the FastCGI `@ginxsom` named location and
|
||||
c-relay's admin is explicitly reverse-proxied — nginx's longest-prefix
|
||||
match means `/admin/` → c-relay wins for GET/POST, and ginxsom admin is
|
||||
reached via a different path (if ginxsom has one). **Potential conflict
|
||||
with Slice A** — need to confirm ginxsom doesn't rely on `/admin/`.
|
||||
Current [n-os-tr.conf:53](../iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf:53) has `location /admin/ { try_files $uri @ginxsom; }` — this will need to be **removed or renamed** (e.g. `/blossom-admin/`) to avoid collision. See §6 Open Questions.
|
||||
- The landing page at `/` (static `/var/www/html/index.html`) is unaffected.
|
||||
|
||||
### 4.6 New chroot hook — `0010-fetch-artifacts.hook.chroot`
|
||||
|
||||
```sh
|
||||
#!/bin/sh
|
||||
# Install c-relay and fips into the chroot from iso/local-artifacts/.
|
||||
set -e
|
||||
|
||||
ART=/live-artifacts
|
||||
|
||||
if [ ! -d "$ART" ]; then
|
||||
echo "[fetch-artifacts] no $ART; skipping" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- c-relay -----------------------------------------------------------
|
||||
if [ -f "$ART/c_relay_x86" ]; then
|
||||
echo "[fetch-artifacts] installing c-relay binary"
|
||||
# Create system user and directory
|
||||
if ! getent passwd c-relay >/dev/null 2>&1; then
|
||||
adduser --system --no-create-home --group --home /opt/c-relay c-relay
|
||||
fi
|
||||
mkdir -p /opt/c-relay
|
||||
install -m 0755 -o c-relay -g c-relay \
|
||||
"$ART/c_relay_x86" /opt/c-relay/c_relay_x86
|
||||
chown -R c-relay:c-relay /opt/c-relay
|
||||
else
|
||||
echo "[fetch-artifacts] WARNING: $ART/c_relay_x86 not found" >&2
|
||||
fi
|
||||
|
||||
# --- fips --------------------------------------------------------------
|
||||
FIPS_DEB=$(ls "$ART"/fips_*_amd64.deb 2>/dev/null | head -1 || true)
|
||||
if [ -n "$FIPS_DEB" ] && [ -f "$FIPS_DEB" ]; then
|
||||
echo "[fetch-artifacts] installing fips from $FIPS_DEB"
|
||||
dpkg -i "$FIPS_DEB" || apt-get -f install -y
|
||||
else
|
||||
echo "[fetch-artifacts] WARNING: no fips_*_amd64.deb in $ART" >&2
|
||||
fi
|
||||
```
|
||||
|
||||
How `$ART` gets populated in the chroot: live-build copies
|
||||
[`iso/local-artifacts/`](../iso/local-artifacts) into
|
||||
`/live-artifacts/` inside the chroot via an `includes.chroot_before_packages/`
|
||||
entry that bind-mounts or symlinks the directory, OR more simply, we place
|
||||
the artifacts directly under
|
||||
`iso/config/includes.chroot_before_packages/live-artifacts/` so live-build
|
||||
copies them before package install. See §5 step 2 for the exact location.
|
||||
|
||||
### 4.7 Updated `build.sh`
|
||||
|
||||
Inserted **before** the `sudo "$REPO_ROOT/lb-wrapper.sh" config` line:
|
||||
|
||||
```bash
|
||||
# --- Stage Slice B artifacts ------------------------------------------------
|
||||
ARTIFACTS="$WORKSPACE_ISO_DIR/config/includes.chroot_before_packages/live-artifacts"
|
||||
mkdir -p "$ARTIFACTS"
|
||||
|
||||
# 1. c-relay: copy the user-provided binary from includes/c-relay/
|
||||
CRELAY_SRC=""
|
||||
for candidate in \
|
||||
"$REPO_ROOT/includes/c-relay/c_relay_x86" \
|
||||
"$REPO_ROOT/includes/c-relay/build/c_relay_x86" \
|
||||
"$REPO_ROOT/includes/c-relay/c-relay" ; do
|
||||
if [[ -x "$candidate" ]]; then CRELAY_SRC="$candidate"; break; fi
|
||||
done
|
||||
if [[ -z "$CRELAY_SRC" ]]; then
|
||||
echo "[build.sh] ERROR: no c-relay binary found. Looked for:" >&2
|
||||
echo " includes/c-relay/c_relay_x86" >&2
|
||||
echo " includes/c-relay/build/c_relay_x86" >&2
|
||||
echo " includes/c-relay/c-relay" >&2
|
||||
exit 1
|
||||
fi
|
||||
cp "$CRELAY_SRC" "$ARTIFACTS/c_relay_x86"
|
||||
chmod 0755 "$ARTIFACTS/c_relay_x86"
|
||||
echo "[build.sh] staged c-relay from $CRELAY_SRC"
|
||||
|
||||
# 2. fips: build the .deb (requires cargo-deb)
|
||||
if ! command -v cargo-deb >/dev/null 2>&1; then
|
||||
echo "[build.sh] ERROR: cargo-deb not installed. Run: cargo install cargo-deb" >&2
|
||||
exit 1
|
||||
fi
|
||||
pushd "$REPO_ROOT/includes/fips" >/dev/null
|
||||
packaging/debian/build-deb.sh
|
||||
popd >/dev/null
|
||||
FIPS_DEB=$(ls "$REPO_ROOT/includes/fips/deploy"/fips_*_amd64.deb | sort | tail -1)
|
||||
if [[ -z "$FIPS_DEB" || ! -f "$FIPS_DEB" ]]; then
|
||||
echo "[build.sh] ERROR: fips .deb build produced no artifact" >&2
|
||||
exit 1
|
||||
fi
|
||||
cp "$FIPS_DEB" "$ARTIFACTS/"
|
||||
echo "[build.sh] staged fips .deb: $(basename "$FIPS_DEB")"
|
||||
```
|
||||
|
||||
### 4.8 Updated package list — `base.list.chroot`
|
||||
|
||||
Add runtime deps needed by fips (already pulled in transitively by the .deb
|
||||
but explicit is safer) and by the smoke test:
|
||||
|
||||
```
|
||||
nginx-light
|
||||
spawn-fcgi
|
||||
libfcgi-bin
|
||||
ca-certificates
|
||||
openssl
|
||||
curl
|
||||
jq
|
||||
vim
|
||||
htop
|
||||
# Slice B/C additions:
|
||||
libdbus-1-3
|
||||
iproute2
|
||||
nftables
|
||||
```
|
||||
|
||||
### 4.9 Updated `0020-enable-services.hook.chroot`
|
||||
|
||||
```sh
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Nginx
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
ln -sf /etc/nginx/sites-available/n-os-tr.conf /etc/nginx/sites-enabled/n-os-tr.conf
|
||||
systemctl enable nginx.service
|
||||
|
||||
# Slice A
|
||||
systemctl enable ginxsom.service
|
||||
systemctl enable n-os-tr-firstboot.service
|
||||
|
||||
# Slice B (fips) — units installed by the .deb postinst already enable
|
||||
# them, but we're explicit for idempotence:
|
||||
systemctl enable fips.service || true
|
||||
systemctl enable fips-dns.service || true
|
||||
|
||||
# Slice C (c-relay)
|
||||
systemctl enable c-relay.service
|
||||
```
|
||||
|
||||
### 4.10 Updated smoke test
|
||||
|
||||
Replace the fips and c-relay SKIP blocks in [`n-os-tr-smoketest`](../iso/config/includes.chroot/usr/local/bin/n-os-tr-smoketest) with real checks:
|
||||
|
||||
```bash
|
||||
# -------------------- fips mesh daemon -----------------------------
|
||||
section "fips mesh daemon"
|
||||
|
||||
check "fips.service active" systemctl is-active fips.service
|
||||
check "fips-dns.service active" systemctl is-active fips-dns.service
|
||||
check "fips0 interface present" ip link show fips0
|
||||
|
||||
# fipsctl identity should return an npub-shaped string
|
||||
npub=$(fipsctl identity 2>/dev/null | head -1 | tr -d '[:space:]')
|
||||
case "$npub" in
|
||||
npub1*) pass "fipsctl identity returns npub" "${npub:0:20}..." ;;
|
||||
*) fail "fipsctl identity returns npub" "got: ${npub:-<empty>}" ;;
|
||||
esac
|
||||
|
||||
# fips UDP transport should be listening
|
||||
check "fips UDP bound on :2121" bash -c 'ss -ulnp 2>/dev/null | grep -q ":2121"'
|
||||
|
||||
# -------------------- c-relay nostr relay --------------------------
|
||||
section "c-relay nostr relay"
|
||||
|
||||
check "c-relay.service active" systemctl is-active c-relay.service
|
||||
check "c-relay listening on :8888" bash -c 'ss -tlnp 2>/dev/null | grep -q ":8888"'
|
||||
|
||||
# The admin nsec should have been logged during first startup
|
||||
if journalctl -u c-relay.service --no-pager 2>/dev/null | \
|
||||
grep -q "Admin Private Key:"; then
|
||||
pass "admin nsec logged in journal" "found"
|
||||
else
|
||||
fail "admin nsec logged in journal" "grep miss"
|
||||
fi
|
||||
|
||||
# wss end-to-end via nginx, using the shipped nak:
|
||||
if timeout 10 nak req --relay wss://localhost/relay -k 1 -l 1 \
|
||||
>/dev/null 2>&1; then
|
||||
pass "wss://localhost/relay answers REQ" "ok"
|
||||
else
|
||||
fail "wss://localhost/relay answers REQ" "timeout or error"
|
||||
fi
|
||||
|
||||
# NIP-11 relay info doc
|
||||
nip11=$(curl -sk -H 'Accept: application/nostr+json' \
|
||||
https://localhost/relay 2>/dev/null)
|
||||
if echo "$nip11" | jq -e '.name' >/dev/null 2>&1; then
|
||||
pass "NIP-11 info doc reachable" "name=$(echo "$nip11" | jq -r .name)"
|
||||
else
|
||||
fail "NIP-11 info doc reachable" "no JSON .name"
|
||||
fi
|
||||
|
||||
# c-relay embedded admin UI via nginx
|
||||
status=$(curl -sk -o /dev/null -w '%{http_code}' https://localhost/admin/ 2>/dev/null)
|
||||
case "$status" in
|
||||
200|302|401) pass "admin UI reachable via nginx" "HTTP $status" ;;
|
||||
*) fail "admin UI reachable via nginx" "HTTP $status" ;;
|
||||
esac
|
||||
```
|
||||
|
||||
Target final summary: `~15 PASS / 0 FAIL / 0 SKIP`.
|
||||
|
||||
### 4.11 MOTD and README updates
|
||||
|
||||
The [`n-os-tr-firstboot`](../iso/config/includes.chroot/usr/local/sbin/n-os-tr-firstboot) script's MOTD block gains additional hints:
|
||||
|
||||
```
|
||||
n-OS-tr — Nostr-addressed mesh node (preview)
|
||||
|
||||
Ginxsom (Blossom) server pubkey (hex):
|
||||
$GINXSOM_SERVER_PUBKEY
|
||||
retrieve nsec: cat /var/lib/n-os-tr/keys/ginxsom.nsec
|
||||
|
||||
c-relay Nostr relay:
|
||||
wss://$(hostname)/relay (admin nsec: journalctl -u c-relay | grep 'Admin Private Key')
|
||||
https://$(hostname)/admin/ (web admin UI)
|
||||
|
||||
fips mesh daemon:
|
||||
fipsctl identity (show npub)
|
||||
fipsctl peers (list peers)
|
||||
|
||||
Quick health check: n-os-tr-smoketest
|
||||
```
|
||||
|
||||
The [`iso/config/includes.chroot/usr/share/doc/n-os-tr/README`](../iso/config/includes.chroot/usr/share/doc/n-os-tr/README) gets corresponding additions.
|
||||
|
||||
---
|
||||
|
||||
## 5. Build & Deploy Sequence
|
||||
|
||||
1. **Place c-relay binary** at `includes/c-relay/c_relay_x86` (or one of the
|
||||
fallback paths `build.sh` checks). Ensure it's `chmod +x` and runs standalone.
|
||||
2. **Install `cargo-deb`** on the build host: `cargo install cargo-deb`.
|
||||
3. **Edit** all files listed in §3 according to §4.
|
||||
4. **Move artifacts staging location:**
|
||||
- New directory: `iso/config/includes.chroot_before_packages/live-artifacts/`
|
||||
— gitignored.
|
||||
- `build.sh` writes c-relay binary and fips .deb here.
|
||||
- `0010-fetch-artifacts.hook.chroot` reads from `/live-artifacts/` inside
|
||||
the chroot (live-build copies the `includes.chroot_before_packages` tree
|
||||
into the chroot root before packages install).
|
||||
5. **Add** `iso/config/includes.chroot_before_packages/live-artifacts/` to
|
||||
[`.gitignore`](../.gitignore).
|
||||
6. **Full clean build:** `sudo ./build.sh --clean` (needed because package
|
||||
list changed).
|
||||
7. **Burn** the resulting `iso/live-image-amd64.hybrid.iso` to USB with `dd`.
|
||||
8. **Boot** on the B650I machine.
|
||||
9. **Verify:** run `n-os-tr-smoketest` — expect all checks to PASS.
|
||||
|
||||
---
|
||||
|
||||
## 6. Open Questions / Known Conflicts
|
||||
|
||||
### 6.1 nginx `/admin/` path collision
|
||||
Slice A's [n-os-tr.conf:53](../iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf:53)
|
||||
routes `/admin/` to ginxsom. Slice C wants `/admin/` for c-relay.
|
||||
**Resolution proposed:** change Slice A's Blossom admin to `/blossom/` (if
|
||||
ginxsom supports path rewriting) or `/blossom-admin/`. Need to check
|
||||
ginxsom's source to see whether its admin endpoints are hardcoded to `/admin/`
|
||||
or whether the FastCGI layer can remap them.
|
||||
|
||||
### 6.2 Fips ethernet auto-interface selection
|
||||
If the B650I's Ethernet shows up as `enp5s0` or similar and fips's
|
||||
"auto-pick first non-loopback" heuristic grabs the wrong interface (e.g. Wi-Fi
|
||||
— though we explicitly said runtime Wi-Fi is fine, we don't want fips
|
||||
scanning it), we may need to hardcode `ethernet.interface: "enp5s0"` in
|
||||
[fips.yaml](../iso/config/includes.chroot/etc/fips/fips.yaml). **Resolution:**
|
||||
check `ip link show` on first boot; update if needed.
|
||||
|
||||
### 6.3 Stray file `=4` in [`includes/c-relay/`](../includes/c-relay)
|
||||
Shown in the directory listing but not the c-relay binary (the real binary
|
||||
is [`includes/c_relay_static_x86_64`](../includes/c_relay_static_x86_64)
|
||||
at the top level of `includes/`). Likely a shell-redirect typo artifact
|
||||
(`command >=4 file` or similar). Safe to delete during cleanup; does not
|
||||
affect the build.
|
||||
|
||||
### 6.4 c-relay writable database location
|
||||
c-relay writes `.nrdb` files to its `WorkingDirectory` (`/opt/c-relay/`). In
|
||||
a live session with ephemeral rootfs this works — the writes go to the
|
||||
tmpfs union layer. For persistence-partition boots we'd want `/opt/c-relay/`
|
||||
on the persistence mount. **Not addressed in this slice** per decision #10.
|
||||
|
||||
### 6.5 fips running as root
|
||||
The fips Debian package runs fips as root (needs TUN + raw sockets). The
|
||||
hardening in [`fips.service`](../includes/fips/packaging/debian/fips.service:17-22)
|
||||
is meaningful but fips itself is privileged. Acceptable for this slice.
|
||||
|
||||
### 6.6 Reverse proxy's X-Forwarded-Proto and c-relay's NIP-42
|
||||
NIP-42 requires the relay to know its own URL (for the `["relay", "url"]` tag
|
||||
in the AUTH challenge). c-relay has [logic](../includes/c-relay/src/nip042.c:103)
|
||||
that falls back to `ws://127.0.0.1:PORT` — this means NIP-42 challenges will
|
||||
reference the internal address, not `wss://host/relay`. Clients may then
|
||||
fail auth. **Mitigation:** c-relay has a configurable `relay_url` config
|
||||
key (set via admin event). Post-boot procedure documented in updated README
|
||||
for users who want NIP-42 to work correctly. **Not blocking for basic
|
||||
operation** — the relay accepts unauthenticated connections by default.
|
||||
|
||||
---
|
||||
|
||||
## 7. Success Criteria
|
||||
|
||||
From a booted USB on fresh hardware with wired Ethernet:
|
||||
|
||||
- [ ] `systemctl status fips-dns ginxsom c-relay nginx n-os-tr-firstboot` — all active
|
||||
- [ ] `fipsctl identity` — prints a valid npub
|
||||
- [ ] `fipsctl peers` — at minimum lists `fips-test-node` (may show as "connecting" if UDP blocked)
|
||||
- [ ] `ip link show fips0` — fips0 TUN interface up
|
||||
- [ ] `journalctl -u c-relay | grep 'Admin Private Key'` — returns the nsec (once)
|
||||
- [ ] `curl -k https://localhost/` — landing page
|
||||
- [ ] `curl -k -I https://localhost/admin/` — returns 200 or 302 (c-relay UI)
|
||||
- [ ] `nak req --relay wss://localhost/relay -k 1 -l 1` — returns `["EOSE",...]` after an empty result
|
||||
- [ ] `curl -ksI https://localhost/0000000000000000000000000000000000000000000000000000000000000000` — 404 (ginxsom still works)
|
||||
- [ ] `n-os-tr-smoketest` — `15 PASS / 0 FAIL / 0 SKIP`
|
||||
|
||||
---
|
||||
|
||||
## 8. Rollback
|
||||
|
||||
If something goes sideways during development:
|
||||
|
||||
- The entire Slice A → Slice B+C diff is confined to these files/directories:
|
||||
```
|
||||
build.sh (additive step)
|
||||
iso/config/hooks/live/0010-fetch-artifacts.hook.chroot (new)
|
||||
iso/config/hooks/live/0020-enable-services.hook.chroot (edited)
|
||||
iso/config/package-lists/base.list.chroot (edited)
|
||||
iso/config/includes.chroot/etc/fips/ (new dir)
|
||||
iso/config/includes.chroot/etc/systemd/system/c-relay.service (new)
|
||||
iso/config/includes.chroot/etc/nginx/sites-available/n-os-tr.conf (edited)
|
||||
iso/config/includes.chroot/usr/local/sbin/n-os-tr-firstboot (edited motd)
|
||||
iso/config/includes.chroot/usr/local/bin/n-os-tr-smoketest (edited)
|
||||
iso/config/includes.chroot/usr/share/doc/n-os-tr/README (edited)
|
||||
iso/config/includes.chroot_before_packages/ (new, gitignored)
|
||||
.gitignore (edited)
|
||||
```
|
||||
- A revert is a `git checkout` of those paths plus removal of
|
||||
`iso/config/includes.chroot_before_packages/`.
|
||||
|
||||
---
|
||||
|
||||
## 9. Out of Scope (deferred to later slices)
|
||||
|
||||
- Persistent identity (ginxsom nsec, c-relay admin nsec, fips npub survive reboots).
|
||||
- Gitea release fetch for artifacts (current plan is local-only).
|
||||
- c-relay `relay_url` auto-configuration for NIP-42 (manual admin event for now).
|
||||
- `/admin/` conflict resolution if ginxsom truly hardcodes that path.
|
||||
- fips-gateway service (disabled; users can enable manually for LAN translation).
|
||||
- Tor transport for fips (transport is available but not wired into the config).
|
||||
- Installer variant (live-only for now).
|
||||
- arm64 build.
|
||||
- Signed / reproducible builds.
|
||||
- Hardening tests: SELinux, AppArmor profiles.
|
||||
|
||||
---
|
||||
|
||||
## 10. References
|
||||
|
||||
- [`plans/iso_architecture.md`](./iso_architecture.md) — overall target design
|
||||
- [`plans/network_boot.md`](./network_boot.md) — sibling plan, paused
|
||||
- [`build.sh`](../build.sh) / [`lb-wrapper.sh`](../lb-wrapper.sh) — build entry
|
||||
- [`iso/auto/config`](../iso/auto/config) — live-build options
|
||||
- [`includes/fips/packaging/debian/build-deb.sh`](../includes/fips/packaging/debian/build-deb.sh)
|
||||
- [`includes/fips/packaging/common/fips.yaml`](../includes/fips/packaging/common/fips.yaml)
|
||||
- [`includes/fips/packaging/debian/fips.service`](../includes/fips/packaging/debian/fips.service)
|
||||
- [`includes/c-relay/systemd/c-relay.service`](../includes/c-relay/systemd/c-relay.service)
|
||||
- [`includes/c-relay/README.md`](../includes/c-relay/README.md)
|
||||
- [`includes/c-relay/API.md`](../includes/c-relay/API.md)
|
||||
- [Live-build manual — includes.chroot_before_packages](https://live-team.pages.debian.net/live-manual/html/live-manual/customizing-contents.en.html)
|
||||
Reference in New Issue
Block a user