v0.0.3 - Add loglevel=1 to live boot args to suppress TTY console noise

This commit is contained in:
Laan Tungir
2026-05-07 10:20:50 -04:00
parent adebb27c62
commit 0f74671529
59985 changed files with 8508144 additions and 4402 deletions

4
iso/SHA256SUMS.tier3 Normal file
View File

@@ -0,0 +1,4 @@
# Tier 3 binary checksums — verified at ISO build time
# Format: sha256 relative-path-from-live-artifacts/
# TODO: compute actual checksum from verified download
0000000000000000000000000000000000000000000000000000000000000000 nak-v0.19.7-linux-amd64

View File

@@ -15,5 +15,6 @@ lb config noauto \
--iso-application "n-OS-tr" \
--iso-volume "n-OS-tr" \
--iso-publisher "n-OS-tr project" \
--bootappend-live "boot=live components console=tty0 console=ttyS0,115200n8 loglevel=4" \
--bootappend-live "boot=live components console=tty0 vt.gpm_allowed=0 loglevel=1" \
--bootappend-live-failsafe "boot=live components console=tty0 vt.gpm_allowed=0 loglevel=1" \
"${@}"

View File

@@ -10,13 +10,13 @@ LB_BINARY_FILESYSTEM="fat32"
LB_APT_INDICES="false"
# Set boot parameters
LB_BOOTAPPEND_LIVE="boot=live components console=tty0 console=ttyS0,115200n8 loglevel=4"
LB_BOOTAPPEND_LIVE="boot=live components console=tty0 vt.gpm_allowed=0 loglevel=1"
# Set boot parameters
LB_BOOTAPPEND_INSTALL=""
# Set boot parameters
LB_BOOTAPPEND_LIVE_FAILSAFE="boot=live components memtest noapic noapm nodma nomce nosmp nosplash vga=788"
LB_BOOTAPPEND_LIVE_FAILSAFE="boot=live components console=tty0 vt.gpm_allowed=0 loglevel=1"
# Set BIOS bootloader
LB_BOOTLOADER_BIOS="syslinux"

View File

@@ -1,44 +1,51 @@
#!/bin/sh
# Install Slice B/C artifacts into the chroot before service enablement.
set -e
ART=/live-artifacts
ARTIFACTS="/live-artifacts"
SUMS="$ARTIFACTS/SHA256SUMS"
if [ ! -d "$ART" ]; then
echo "[fetch-artifacts] no $ART directory; skipping"
echo "n-OS-tr: Installing artifacts from $ARTIFACTS"
if [ ! -d "$ARTIFACTS" ]; then
echo " WARN: $ARTIFACTS not found, skipping artifact installation"
exit 0
fi
# --- c-relay ---------------------------------------------------------------
if [ -f "$ART/c_relay_x86" ]; then
echo "[fetch-artifacts] installing c-relay binary"
if ! getent passwd c-relay >/dev/null 2>&1; then
adduser --system --no-create-home --group --home /opt/c-relay c-relay
fi
# --- nostr-id-tui -----------------------------------------------------------
if [ -f "$ART/nostr-id-tui_x86_64" ]; then
echo "[fetch-artifacts] installing nostr-id-tui binary"
install -m 0755 -o root -g root \
"$ART/nostr-id-tui_x86_64" /usr/local/sbin/nostr-id-tui
# Verify checksums if manifest exists
if [ -f "$SUMS" ]; then
echo " Verifying SHA256 checksums..."
(cd "$ARTIFACTS" && sha256sum -c SHA256SUMS) || {
echo " ERROR: checksum verification failed!"
exit 1
}
fi
# Install function
install_bin() {
local src="$ARTIFACTS/$1"
local dst="$2"
if [ -f "$src" ]; then
mkdir -p "$(dirname "$dst")"
cp "$src" "$dst"
chmod 755 "$dst"
echo " Installed: $1 -> $dst"
else
echo "[fetch-artifacts] WARNING: $ART/nostr-id-tui_x86_64 not found" >&2
echo " SKIP: $1 not found in artifacts"
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
# Core signer
install_bin "n_signer" "/usr/local/bin/n_signer"
install_bin "nostr-id-tui" "/usr/local/sbin/nostr-id-tui"
# --- 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 package $FIPS_DEB"
# Non-interactive: keep current /etc/fips/fips.yaml (provided by includes.chroot)
DEBIAN_FRONTEND=noninteractive dpkg -i --force-confold "$FIPS_DEB"
else
echo "[fetch-artifacts] WARNING: no fips_*_amd64.deb found under $ART" >&2
fi
# Service daemons
install_bin "ginxsom-fcgi" "/usr/local/bin/ginxsom/ginxsom-fcgi"
install_bin "fips" "/usr/local/bin/fips"
install_bin "didactyl" "/usr/local/bin/didactyl"
# User CLI tools
install_bin "nt" "/usr/local/bin/nt"
install_bin "otp" "/usr/local/bin/otp"
install_bin "nak" "/usr/local/bin/nak"
echo "n-OS-tr: Artifact installation complete"

View File

@@ -1,5 +1,5 @@
#!/bin/sh
# Configure boot-time enable/disable posture for n-OS-tr services.
# Configure manual-start posture: boot to plain Debian login.
set -eu
# Disable the Debian default site so it doesn't conflict with ours.
@@ -8,13 +8,21 @@ rm -f /etc/nginx/sites-enabled/default
# Enable our site symlink only. Runtime nginx startup is user-selected in TUI.
ln -sf /etc/nginx/sites-available/n-os-tr.conf /etc/nginx/sites-enabled/n-os-tr.conf
# TTY handoff: identity TUI owns tty1 before getty.
systemctl disable getty@tty1.service || true
# Keep Debian getty ownership on tty1/tty2/tty3 in manual-start mode.
systemctl enable getty@tty1.service || true
systemctl enable getty@tty2.service || true
systemctl enable getty@tty3.service || true
# Always-on boot pipeline.
systemctl enable n-os-tr-firstboot.service
systemctl enable nostr-id.service || true
systemctl enable nostr-id-tui.service
# Disable all n-OS-tr units at boot; user starts stack manually after login.
for unit in \
n-os-tr-firstboot.service \
nostr-id.service \
nostr-id-tui.service \
nostr-id-tui-services.service \
didactyl.service
do
systemctl disable "$unit" 2>/dev/null || true
done
# Explicitly keep optional services disabled at boot.
for unit in \
@@ -31,5 +39,9 @@ for unit in \
systemctl disable "$unit" 2>/dev/null || true
done
# Keep gpm disabled/masked to avoid mouse escape/noise on virtual consoles.
systemctl disable gpm.service 2>/dev/null || true
systemctl mask gpm.service 2>/dev/null || true
# Apply preset policy for any additional units.
systemctl preset-all --preset-mode=enable-only 2>/dev/null || true
systemctl preset-all 2>/dev/null || true

View File

@@ -0,0 +1,6 @@
# n-OS-tr console font tuning
ACTIVE_CONSOLES="/dev/tty[1-6]"
CHARMAP="UTF-8"
CODESET="Lat15"
FONTFACE="Terminus"
FONTSIZE="20x10"

View File

@@ -0,0 +1,2 @@
n-OS-tr · SHELL · \l

View File

@@ -7,3 +7,4 @@ l nostr-config-loader.service config-loader off -
w nostr-config-writer.service config-writer off nostr-config-loader.service
s ssh.service ssh off -
t tor.service tor off -
d didactyl.service didactyl off -

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Set per-TTY prompt so the user always knows which terminal they're on.
# Only applies to interactive login shells on tty3..tty6.
case "$(tty)" in
/dev/tty[3-6])
PS1='[tty\l \w]\$ '
;;
esac

View File

@@ -1,10 +1,11 @@
# n-OS-tr service posture: only identity + firstboot + TUI start automatically.
# Optional services are loaded/installed but disabled by default.
enable n-os-tr-firstboot.service
enable nostr-id.service
enable nostr-id-tui.service
# n-OS-tr manual-start posture: boot to plain Debian login.
# All n-OS-tr services are disabled by default and started explicitly by user.
disable n-os-tr-firstboot.service
disable nostr-id.service
disable nostr-id-tui-services.service
disable nostr-id-tui.service
disable didactyl.service
disable c-relay.service
disable ginxsom.service
disable fips.service

View File

@@ -0,0 +1,5 @@
[Service]
ExecStartPre=/usr/local/bin/n-os-tr-await-signer
ExecStartPre=/bin/sh -c '/usr/local/bin/n-os-tr-get-key 1 > /run/c-relay.env'
EnvironmentFile=-/run/c-relay.env
ExecStartPost=/bin/rm -f /run/c-relay.env

View File

@@ -0,0 +1,23 @@
[Unit]
Description=Didactyl — Nostr-native AI agent
Documentation=https://git.laantungir.net/laantungir/didactyl
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStartPre=/usr/local/bin/n-os-tr-await-signer
ExecStartPre=/usr/local/bin/n-os-tr-render-didactyl-genesis 5
ExecStart=/usr/local/bin/didactyl --genesis /run/didactyl/genesis.jsonc
RuntimeDirectory=didactyl
# Memory hygiene
MemoryDenyWriteExecute=yes
LockPersonality=yes
ProtectKernelTunables=yes
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,5 @@
[Service]
ExecStartPre=/usr/local/bin/n-os-tr-await-signer
ExecStartPre=/bin/sh -c '/usr/local/bin/n-os-tr-get-key 3 > /run/fips.env'
EnvironmentFile=-/run/fips.env
ExecStartPost=/bin/rm -f /run/fips.env

View File

@@ -1,3 +1,2 @@
[Unit]
# If the TUI binary exists, do not start tty1 getty so tty1 is reserved for nostr-id-tui.
ConditionPathExists=!/usr/local/sbin/nostr-id-tui
# Manual-start posture: keep default Debian getty on tty1 enabled.

View File

@@ -0,0 +1,2 @@
[Unit]
# Manual-start posture: keep default Debian getty on tty2 enabled.

View File

@@ -0,0 +1,5 @@
[Service]
ExecStartPre=/usr/local/bin/n-os-tr-await-signer
ExecStartPre=/bin/sh -c '/usr/local/bin/n-os-tr-get-key 2 > /run/ginxsom.env'
EnvironmentFile=-/run/ginxsom.env
ExecStartPost=/bin/rm -f /run/ginxsom.env

View File

@@ -2,8 +2,7 @@
Description=n-OS-tr first-boot key and TLS provisioning
Documentation=file:///usr/share/doc/n-os-tr/README
ConditionPathExists=!/var/lib/n-os-tr/.provisioned
Before=ginxsom.service nginx.service
Wants=ginxsom.service nginx.service
# Manual-start posture: do not pull other daemons at boot.
[Service]
Type=oneshot

View File

@@ -0,0 +1,2 @@
[Service]
ExecStartPre=/usr/local/bin/n-os-tr-await-signer

View File

@@ -0,0 +1,21 @@
[Unit]
Description=n-OS-tr post-unlock service selection menu
Conflicts=getty@tty2.service
Before=getty@tty2.service
[Service]
Type=simple
ExecStartPre=/usr/bin/setterm -term linux -background blue -store
ExecStart=/usr/local/sbin/nostr-id-tui --mode=services-only
Restart=always
RestartSec=1
StandardInput=tty
StandardOutput=tty
StandardError=journal
TTYPath=/dev/tty2
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
[Install]
WantedBy=multi-user.target

View File

@@ -1,8 +1,8 @@
[Unit]
Description=n-OS-tr Nostr Identity TUI
Documentation=file:///usr/share/doc/n-os-tr/README
After=systemd-user-sessions.service network-online.target n-os-tr-firstboot.service
Wants=network-online.target n-os-tr-firstboot.service
After=systemd-user-sessions.service n-os-tr-firstboot.service
Wants=n-os-tr-firstboot.service
Conflicts=getty@tty1.service
Before=getty@tty1.service

View File

@@ -0,0 +1,21 @@
#!/bin/bash
# n-os-tr-await-signer: block until nsigner's abstract socket @n_os_tr is reachable.
# Used as ExecStartPre= by services that depend on the signer.
set -euo pipefail
SOCKET_NAME="n_os_tr"
TIMEOUT="${NSIGNER_AWAIT_TIMEOUT:-120}"
INTERVAL=1
ELAPSED=0
while [ "$ELAPSED" -lt "$TIMEOUT" ]; do
# Try to connect to the abstract socket. socat will exit 0 on success.
if socat -u OPEN:/dev/null ABSTRACT-CONNECT:"$SOCKET_NAME" 2>/dev/null; then
exit 0
fi
sleep "$INTERVAL"
ELAPSED=$((ELAPSED + INTERVAL))
done
echo "n-os-tr-await-signer: timed out after ${TIMEOUT}s waiting for @${SOCKET_NAME}" >&2
exit 1

View File

@@ -0,0 +1,50 @@
#!/bin/bash
# n-os-tr-get-key: request a role's secret key from nsigner via @n_os_tr
# Usage: n-os-tr-get-key <role_name>
# Outputs: 64-char hex private key on stdout
# Exit 1 on failure.
set -euo pipefail
ROLE="${1:?usage: n-os-tr-get-key <role_name>}"
SOCKET="n_os_tr"
TIMEOUT="${NSIGNER_KEY_TIMEOUT:-30}"
# Wait for socket to be available
ELAPSED=0
while [ "$ELAPSED" -lt "$TIMEOUT" ]; do
if socat -u OPEN:/dev/null ABSTRACT-CONNECT:"$SOCKET" 2>/dev/null; then
break
fi
sleep 1
ELAPSED=$((ELAPSED + 1))
done
if [ "$ELAPSED" -ge "$TIMEOUT" ]; then
echo "n-os-tr-get-key: timed out waiting for @${SOCKET}" >&2
exit 1
fi
# Build the framed request (4-byte big-endian length prefix + JSON payload)
PAYLOAD='{"id":"1","method":"get_secret_key","params":[{"role":"'"$ROLE"'"}]}'
PAYLOAD_LEN=${#PAYLOAD}
# Use printf to create the 4-byte length prefix and send via socat
RESPONSE=$(printf '%08x' "$PAYLOAD_LEN" | xxd -r -p | cat - <(echo -n "$PAYLOAD") | \
socat -t5 - ABSTRACT-CONNECT:"$SOCKET" 2>/dev/null | tail -c +5)
# Check for error
if echo "$RESPONSE" | grep -q '"error"'; then
ERROR=$(echo "$RESPONSE" | grep -o '"message":"[^"]*"' | cut -d'"' -f4)
echo "n-os-tr-get-key: signer error: ${ERROR:-unknown}" >&2
exit 1
fi
# Extract the hex private key from the result field
KEY=$(echo "$RESPONSE" | grep -oP '"result"\s*:\s*"[a-f0-9]{64}"' | grep -o '[a-f0-9]\{64\}')
if [ -z "$KEY" ] || [ ${#KEY} -ne 64 ]; then
echo "n-os-tr-get-key: failed to extract valid key from response" >&2
exit 1
fi
echo "$KEY"

View File

@@ -0,0 +1,30 @@
#!/bin/sh
# Render didactyl genesis.jsonc from n_signer-derived key
# Usage: n-os-tr-render-didactyl-genesis <nostr_index>
set -e
NOSTR_INDEX="${1:?Usage: $0 <nostr_index>}"
OUTDIR="/run/didactyl"
OUTFILE="$OUTDIR/genesis.jsonc"
# Get the hex secret key from n_signer
HEX_KEY=$(/usr/local/bin/n-os-tr-get-key "$NOSTR_INDEX")
if [ -z "$HEX_KEY" ] || [ ${#HEX_KEY} -ne 64 ]; then
echo "ERROR: failed to get valid key from n_signer (index=$NOSTR_INDEX)" >&2
exit 1
fi
mkdir -p "$OUTDIR"
cat > "$OUTFILE" <<GENESIS_EOF
{
// Auto-generated by n-os-tr-render-didactyl-genesis
// Key derived from n_signer at nostr_index=$NOSTR_INDEX
"nsec_hex": "$HEX_KEY",
"relays": ["ws://127.0.0.1:7777"]
}
GENESIS_EOF
chmod 600 "$OUTFILE"
echo "Rendered $OUTFILE (nostr_index=$NOSTR_INDEX)"

View File

@@ -39,6 +39,16 @@ check() {
fi
}
# framed JSON-RPC helper for n_signer abstract socket @n_os_tr
rpc_call_nsigner() {
local payload="$1"
local payload_len
payload_len=${#payload}
printf '%08x' "$payload_len" | xxd -r -p | cat - <(printf '%s' "$payload") | \
socat -t3 - ABSTRACT-CONNECT:n_os_tr 2>/dev/null | tail -c +5
}
# -------------------- core section ----------------------
section "core"
@@ -50,6 +60,49 @@ check "ginxsom nsec exists" test -f /var/lib/n-os-tr/keys/ginxsom.nsec
check "env file readable by www-data" \
sudo -u www-data test -r /var/lib/n-os-tr/env
# -------------------- n_signer integration ----------------------
section "n_signer integration"
SIGNER_RUNNING=0
if pgrep -x n_signer >/dev/null 2>&1; then
pass "n_signer process running" "pgrep"
SIGNER_RUNNING=1
else
skip "n_signer process running" "not running in this environment"
skip "@n_os_tr socket reachable" "signer absent"
skip "get_public_key(nostr_index=0, caller=uid:0) returns valid 64-hex" "signer absent"
skip "sign_event non-preapproved nostr_index denied/prompted" "signer absent"
printf " (note: signer checks skipped because n_signer is not running)\n"
fi
if [[ "$SIGNER_RUNNING" -eq 1 ]]; then
if ss -xl 2>/dev/null | grep -q '@n_os_tr' || socat -u OPEN:/dev/null ABSTRACT-CONNECT:n_os_tr >/dev/null 2>&1; then
pass "@n_os_tr socket reachable" "ss/socat"
else
fail "@n_os_tr socket reachable" "abstract socket not visible/reachable"
fi
PUBKEY_RESP=$(rpc_call_nsigner '{"id":"smoke-pub","method":"get_public_key","params":[{"nostr_index":0}]}' || true)
PUBKEY=$(echo "$PUBKEY_RESP" | grep -oE '"result"\s*:\s*"[0-9a-f]{64}"' | grep -oE '[0-9a-f]{64}' | head -n1)
if [[ ${#PUBKEY} -eq 64 ]]; then
pass "get_public_key(nostr_index=0, caller=uid:0) returns valid 64-hex" "${PUBKEY:0:16}..."
else
fail "get_public_key(nostr_index=0, caller=uid:0) returns valid 64-hex" "response=${PUBKEY_RESP:-<empty>}"
fi
SIGN_REQ='{"id":"smoke-sign","method":"sign_event","params":[{"nostr_index":99,"event":{"kind":1,"created_at":1700000000,"tags":[],"content":"n-os-tr smoketest"}}]}'
SIGN_RESP=$(rpc_call_nsigner "$SIGN_REQ" || true)
if [[ -z "$SIGN_RESP" ]]; then
pass "sign_event non-preapproved nostr_index denied/prompted" "no immediate auto-allow response"
elif echo "$SIGN_RESP" | grep -qiE 'denied|prompt|"error"'; then
pass "sign_event non-preapproved nostr_index denied/prompted" "${SIGN_RESP:0:80}"
elif echo "$SIGN_RESP" | grep -q '"result"'; then
fail "sign_event non-preapproved nostr_index denied/prompted" "unexpected auto-allow result"
else
fail "sign_event non-preapproved nostr_index denied/prompted" "unexpected response=${SIGN_RESP:0:120}"
fi
fi
# -------------------- nginx + ginxsom --------------------
section "blossom (nginx + ginxsom)"

View File

@@ -1,130 +1,27 @@
#!/bin/bash
# n-OS-tr first-boot provisioning.
# Runs once per boot-without-persistence. Generates per-node secrets
# and writes them to /var/lib/n-os-tr/ where the service units read them.
# n-os-tr-firstboot: one-shot provisioning for directory structure and TLS.
# Identity and key generation are handled by interactive n_signer (manual start on tty1).
# This script is independent of signer startup.
set -euo pipefail
STATE=/var/lib/n-os-tr
KEYS=$STATE/keys
ENVFILE=$STATE/env
TLS_DIR=/etc/ssl/n-os-tr
BLOBS=/var/www/blobs
GINXSOM_DB=/var/lib/ginxsom
log() { echo "[firstboot] $*"; }
# 1. Create required directories
mkdir -p "$STATE" /var/www/blobs /var/lib/c-relay /var/lib/ginxsom
mkdir -p "$STATE" "$KEYS" "$TLS_DIR" "$BLOBS" "$GINXSOM_DB"
chmod 0700 "$KEYS"
chmod 0755 "$BLOBS" "$GINXSOM_DB"
# ---------------------------------------------------------------------------
# 1. Ginxsom server keypair.
# We use nak (pre-shipped at /usr/local/bin/nak) to generate and decode.
# ---------------------------------------------------------------------------
if [[ ! -f "$KEYS/ginxsom.nsec" ]]; then
log "Generating ginxsom server keypair"
/usr/local/bin/nak key generate > "$KEYS/ginxsom.nsec"
chmod 0400 "$KEYS/ginxsom.nsec"
fi
GINXSOM_SECRET=$(tr -d '[:space:]' < "$KEYS/ginxsom.nsec")
# nak key generate currently emits raw hex, but we also accept bech32 nsec.
case "$GINXSOM_SECRET" in
nsec1*)
GINXSOM_SERVER_PRIVKEY=$(/usr/local/bin/nak decode "$GINXSOM_SECRET" | jq -r .private_key)
;;
*)
GINXSOM_SERVER_PRIVKEY="$GINXSOM_SECRET"
;;
esac
GINXSOM_SERVER_PUBKEY=$(/usr/local/bin/nak key public "$GINXSOM_SERVER_PRIVKEY" | tr -d '[:space:]')
# The admin pubkey for this build is the same as the server pubkey.
# This is a simplification for Slice A (every node is its own admin).
# Slice C (c-relay) will introduce a separate admin keypair.
GINXSOM_ADMIN_PUBKEY=$GINXSOM_SERVER_PUBKEY
log "ginxsom server pubkey (hex): $GINXSOM_SERVER_PUBKEY"
# ---------------------------------------------------------------------------
# 2. Self-signed TLS cert.
# ---------------------------------------------------------------------------
if [[ ! -f "$TLS_DIR/fullchain.pem" ]]; then
log "Generating self-signed TLS certificate"
HN=$(hostname)
# 2. Self-signed TLS cert if none exists
if [[ ! -f /etc/ssl/n-os-tr/fullchain.pem ]]; then
mkdir -p /etc/ssl/n-os-tr
openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
-subj "/CN=$HN" \
-addext "subjectAltName=DNS:$HN,DNS:localhost,IP:127.0.0.1,IP:::1" \
-keyout "$TLS_DIR/privkey.pem" \
-out "$TLS_DIR/fullchain.pem" >/dev/null 2>&1
chmod 0640 "$TLS_DIR/privkey.pem"
chmod 0644 "$TLS_DIR/fullchain.pem"
chown root:www-data "$TLS_DIR/privkey.pem"
-subj "/CN=$(hostname)" \
-keyout /etc/ssl/n-os-tr/privkey.pem \
-out /etc/ssl/n-os-tr/fullchain.pem 2>/dev/null
chmod 0600 /etc/ssl/n-os-tr/privkey.pem
fi
# ---------------------------------------------------------------------------
# 3. Write environment file consumed by ginxsom.service.
# ---------------------------------------------------------------------------
log "Writing $ENVFILE"
umask 077
cat > "$ENVFILE" <<EOKEY
GINXSOM_SERVER_PRIVKEY=$GINXSOM_SERVER_PRIVKEY
GINXSOM_ADMIN_PUBKEY=$GINXSOM_ADMIN_PUBKEY
EOKEY
chmod 0440 "$ENVFILE"
chown root:www-data "$ENVFILE"
# 3. Ownership
chown -R www-data:www-data /var/www/blobs 2>/dev/null || true
chown -R c-relay:c-relay /var/lib/c-relay 2>/dev/null || true
# ---------------------------------------------------------------------------
# 4. Configure fips ethernet interface (required by current fips schema).
# ---------------------------------------------------------------------------
FIPS_CFG=/etc/fips/fips.yaml
if [[ -f "$FIPS_CFG" ]] && grep -q "__FIPS_ETH_IFACE__" "$FIPS_CFG"; then
FIPS_ETH_IFACE=$(ip -o link show | awk -F': ' '$2 != "lo" {name=$2; sub(/@.*/, "", name); print name; exit}')
if [[ -z "${FIPS_ETH_IFACE:-}" ]]; then
log "No non-loopback network interface found for fips ethernet transport"
exit 1
fi
log "Configuring fips ethernet interface: $FIPS_ETH_IFACE"
sed -i "s/__FIPS_ETH_IFACE__/$FIPS_ETH_IFACE/g" "$FIPS_CFG"
fi
# ---------------------------------------------------------------------------
# 5. Ownership of runtime directories ginxsom will write to.
# ---------------------------------------------------------------------------
chown -R www-data:www-data "$BLOBS" "$GINXSOM_DB"
# ---------------------------------------------------------------------------
# 6. Update the MOTD with the generated identity so the user can find it.
# ---------------------------------------------------------------------------
cat > /etc/motd <<EOMOTD
n-OS-tr — Nostr-addressed mesh node (preview)
Blossom (ginxsom) 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/API)
fips mesh daemon:
fipsctl identity (show npub)
fipsctl peers (list peers)
Service status: systemctl status fips-dns ginxsom c-relay nginx n-os-tr-firstboot
Quick health check: n-os-tr-smoketest
Identity is ephemeral unless you use a persistence partition or
install to disk. See /usr/share/doc/n-os-tr/README for details.
EOMOTD
# ---------------------------------------------------------------------------
# 7. Marker so systemd's ConditionPathExists= skips us on subsequent boots.
# ---------------------------------------------------------------------------
# 4. Mark provisioned
touch "$STATE/.provisioned"
log "First-boot provisioning complete."

View File

@@ -13,8 +13,12 @@ libdbus-1-3
iproute2
nftables
# TUI runtime dependency
# TUI/runtime dependencies
libncursesw6
libsecp256k1-2
fonts-terminus
console-setup
# Service-menu optional stack
tor