[WARNING] 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:
Laan Tungir
2026-04-29 13:09:28 -04:00
parent dc7af63e6b
commit 6e2164abe5
151 changed files with 8865 additions and 1222 deletions

0
iso/.build/config Normal file
View File

19
iso/auto/config Executable file
View File

@@ -0,0 +1,19 @@
#!/bin/sh
# iso/auto/config — run by `lb config` inside iso/
set -e
lb config noauto \
--mode debian \
--distribution bookworm \
--architectures amd64 \
--binary-images iso-hybrid \
--archive-areas "main contrib non-free non-free-firmware" \
--apt-indices false \
--apt-recommends true \
--apt-secure false \
--memtest none \
--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" \
"${@}"

119
iso/config/binary Normal file
View File

@@ -0,0 +1,119 @@
# config/binary - options for live-build(7), binary stage
# Set image type
LB_IMAGE_TYPE="iso-hybrid"
# Set image filesystem
LB_BINARY_FILESYSTEM="fat32"
# Set apt/aptitude generic indices
LB_APT_INDICES="false"
# Set boot parameters
LB_BOOTAPPEND_LIVE="boot=live components console=tty0 console=ttyS0,115200n8 loglevel=4"
# 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"
# Set BIOS bootloader
LB_BOOTLOADER_BIOS="syslinux"
# Set EFI bootloader
LB_BOOTLOADER_EFI="grub-efi"
# Set bootloaders
LB_BOOTLOADERS=""
# Set checksums
LB_CHECKSUMS="sha256"
# Set compression
LB_COMPRESSION="none"
# Support dm-verity on rootfs
LB_DM_VERITY=""
# Support FEC on dm-verity rootfs
LB_DM_VERITY_FEC_ROOTS=""
# Set sign script for roothash for dm-verity rootfs
LB_DM_VERITY_SIGN=""
# Set zsync
LB_ZSYNC="false"
# Control if we build binary images chrooted
# NEVER, *EVER*, *E*V*E*R* SET THIS OPTION to false.
LB_BUILD_WITH_CHROOT="true"
# Set debian-installer
LB_DEBIAN_INSTALLER="none"
# Set debian-installer suite
LB_DEBIAN_INSTALLER_DISTRIBUTION="stable"
# Set debian-installer preseed filename/url
LB_DEBIAN_INSTALLER_PRESEEDFILE=""
# Toggle use of GUI debian-installer
LB_DEBIAN_INSTALLER_GUI="true"
# Set hdd label
LB_HDD_LABEL="DEBIAN_LIVE"
# Set hdd filesystem size
LB_HDD_SIZE="auto"
# Set start of partition for the hdd target for BIOSes that expect a specific boot partition start (e.g. "63s"). If empty, use optimal layout.
LB_HDD_PARTITION_START=""
# Set iso author
LB_ISO_APPLICATION="n-OS-tr"
# Set iso preparer
LB_ISO_PREPARER="live-build @LB_VERSION@; https://salsa.debian.org/live-team/live-build"
# Set iso publisher
LB_ISO_PUBLISHER="n-OS-tr project"
# Set iso volume (max 32 chars)
LB_ISO_VOLUME="n-OS-tr"
# Set jffs2 eraseblock size
LB_JFFS2_ERASEBLOCK=""
# Set memtest
LB_MEMTEST="none"
# Set loadlin
LB_LOADLIN="false"
# Set win32-loader
LB_WIN32_LOADER="false"
# Set net tarball
LB_NET_TARBALL="true"
# Set onie
LB_ONIE="false"
# Set onie additional kernel cmdline options
LB_ONIE_KERNEL_CMDLINE=""
# Set inclusion of firmware packages in debian-installer
LB_FIRMWARE_BINARY="true"
# Set inclusion of firmware packages in the live image
LB_FIRMWARE_CHROOT="true"
# Set swap file path
LB_SWAP_FILE_PATH=""
# Set swap file size
LB_SWAP_FILE_SIZE="512"
# Enable/disable UEFI secure boot support
LB_UEFI_SECURE_BOOT="auto"

76
iso/config/bootstrap Normal file
View File

@@ -0,0 +1,76 @@
# config/bootstrap - options for live-build(7), bootstrap stage
# Select architecture to use
LB_ARCHITECTURE="amd64"
# Select distribution to use
LB_DISTRIBUTION="bookworm"
# Select parent distribution to use
LB_PARENT_DISTRIBUTION=""
# Select distribution to use in the chroot
LB_DISTRIBUTION_CHROOT="stable"
# Select parent distribution to use in the chroot
LB_PARENT_DISTRIBUTION_CHROOT="stable"
# Select distribution to use in the final image
LB_DISTRIBUTION_BINARY="stable"
# Select parent distribution to use in the final image
LB_PARENT_DISTRIBUTION_BINARY="stable"
# Select parent distribution for debian-installer to use
LB_PARENT_DEBIAN_INSTALLER_DISTRIBUTION="stable"
# Select archive areas to use
LB_ARCHIVE_AREAS="main contrib non-free non-free-firmware"
# Select parent archive areas to use
LB_PARENT_ARCHIVE_AREAS="main"
# Set parent mirror to bootstrap from
LB_PARENT_MIRROR_BOOTSTRAP="http://deb.debian.org/debian/"
# Set parent mirror to fetch packages from
LB_PARENT_MIRROR_CHROOT="http://deb.debian.org/debian/"
# Set security parent mirror to fetch packages from
LB_PARENT_MIRROR_CHROOT_SECURITY="http://security.debian.org/"
# Set parent mirror which ends up in the image
LB_PARENT_MIRROR_BINARY="http://deb.debian.org/debian/"
# Set security parent mirror which ends up in the image
LB_PARENT_MIRROR_BINARY_SECURITY="http://security.debian.org/"
# Set debian-installer parent mirror
LB_PARENT_MIRROR_DEBIAN_INSTALLER="http://deb.debian.org/debian/"
# Set mirror to bootstrap from
LB_MIRROR_BOOTSTRAP="http://deb.debian.org/debian/"
# Set mirror to fetch packages from
LB_MIRROR_CHROOT="http://deb.debian.org/debian/"
# Set security mirror to fetch packages from
LB_MIRROR_CHROOT_SECURITY="http://security.debian.org/"
# Set mirror which ends up in the image
LB_MIRROR_BINARY="http://deb.debian.org/debian/"
# Set security mirror which ends up in the image
LB_MIRROR_BINARY_SECURITY="http://security.debian.org/"
# Set debian-installer mirror
LB_MIRROR_DEBIAN_INSTALLER="http://deb.debian.org/debian/"
# Set architectures to use foreign bootstrap
LB_BOOTSTRAP_QEMU_ARCHITECTURE=""
# Set packages to exclude during foreign bootstrap
LB_BOOTSTRAP_QEMU_EXCLUDE=""
# Set static qemu binary for foreign bootstrap
LB_BOOTSTRAP_QEMU_STATIC=""

37
iso/config/chroot Normal file
View File

@@ -0,0 +1,37 @@
# config/chroot - options for live-build(7), chroot stage
# Set chroot filesystem
LB_CHROOT_FILESYSTEM="squashfs"
# Set chroot squashfs compression level
LB_CHROOT_SQUASHFS_COMPRESSION_LEVEL=""
# Set chroot squashfs compression type
LB_CHROOT_SQUASHFS_COMPRESSION_TYPE=""
# Set union filesystem
LB_UNION_FILESYSTEM="overlay"
# Set interactive build
LB_INTERACTIVE="false"
# Set keyring packages
LB_KEYRING_PACKAGES="debian-archive-keyring"
# Set kernel flavour to use (with arch)
LB_LINUX_FLAVOURS_WITH_ARCH="amd64"
# Set kernel packages to use
LB_LINUX_PACKAGES="linux-image"
# Enable security updates
LB_SECURITY="true"
# Enable updates updates
LB_UPDATES="true"
# Enable backports updates
LB_BACKPORTS="false"
# Enable proposed updates
LB_PROPOSED_UPDATES="false"

102
iso/config/common Normal file
View File

@@ -0,0 +1,102 @@
# config/common - common options for live-build(7)
# Version of live-build used to build config (config format version)
LB_CONFIGURATION_VERSION="c2c3f77929987c06946a210509a3231cd4df02ae_2025-08-14T20:24:40+01:00"
# Set package manager
LB_APT="apt"
# Set proxy for HTTP connections
LB_APT_HTTP_PROXY=""
# Set apt/aptitude pipeline depth
LB_APT_PIPELINE=""
# Set apt/aptitude recommends
LB_APT_RECOMMENDS="true"
# Set apt/aptitude security
LB_APT_SECURE="false"
# Set apt/aptitude source entries in sources.list
LB_APT_SOURCE_ARCHIVES="true"
# Control cache
LB_CACHE="true"
# Control if downloaded package indices should be cached
LB_CACHE_INDICES="false"
# Control if downloaded packages files should be cached
LB_CACHE_PACKAGES="true"
# Control if completed stages should be cached
LB_CACHE_STAGES="bootstrap"
# Set debconf(1) frontend to use
LB_DEBCONF_FRONTEND="noninteractive"
# Set debconf(1) priority to use
LB_DEBCONF_PRIORITY="critical"
# Set initramfs hook
LB_INITRAMFS="live-boot"
# Set initramfs compression
LB_INITRAMFS_COMPRESSION="gzip"
# Set init system
LB_INITSYSTEM="systemd"
# Set distribution mode
LB_MODE="debian"
# Set system type
LB_SYSTEM="live"
# Set base name of the image
LB_IMAGE_NAME="live-image"
# Set options to use with apt
APT_OPTIONS="--yes -o Acquire::Retries=5"
# Set options to use with aptitude
APTITUDE_OPTIONS="--assume-yes -o Acquire::Retries=5"
# Set options to use with debootstrap
DEBOOTSTRAP_OPTIONS=""
# Set script to use with debootstrap
DEBOOTSTRAP_SCRIPT=""
# Set options to use with gzip
GZIP_OPTIONS="-6 --rsyncable"
# Enable UTC timestamps
LB_UTC_TIME="false"
# live-build options
# Enable breakpoints
# If set here, overrides the command line option
#_BREAKPOINTS="false"
# Enable debug
# If set here, overrides the command line option
#_DEBUG="false"
# Enable color
# If set here, overrides the command line option
#_COLOR="auto"
# Enable force
# If set here, overrides the command line option
#_FORCE="false"
# Enable quiet
# If set here, overrides the command line option
#_QUIET="false"
# Enable verbose
# If set here, overrides the command line option
#_VERBOSE="false"

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/live/0010-disable-kexec-tools.hook.chroot

View File

@@ -0,0 +1,44 @@
#!/bin/sh
# Install Slice B/C artifacts into the chroot before service enablement.
set -e
ART=/live-artifacts
if [ ! -d "$ART" ]; then
echo "[fetch-artifacts] no $ART directory; skipping"
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
else
echo "[fetch-artifacts] WARNING: $ART/nostr-id-tui_x86_64 not found" >&2
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 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

View File

@@ -0,0 +1,26 @@
#!/bin/sh
# Enable n-OS-tr services so they start automatically on boot.
set -e
# Disable the Debian default site so it doesn't conflict with ours.
rm -f /etc/nginx/sites-enabled/default
# Enable our site.
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
systemctl enable fips.service || true
systemctl enable fips-dns.service || true
# Slice C
systemctl enable c-relay.service
# TUI on tty1
systemctl disable getty@tty1.service || true
systemctl enable nostr-id-tui.service

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/live/0050-disable-sysvinit-tmpfs.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/1000-create-mtab-symlink.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/1010-enable-cryptsetup.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/1020-create-locales-files.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/5000-update-apt-file-cache.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/5010-update-apt-xapian-index.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/5020-update-glx-alternative.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/5030-update-plocate-database.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/5040-update-nvidia-alternative.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/5050-dracut.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8000-remove-adjtime-configuration.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8010-remove-backup-files.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8020-remove-dbus-machine-id.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8030-truncate-log-files.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8040-remove-mdadm-configuration.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8050-remove-openssh-server-host-keys.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8060-remove-systemd-machine-id.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8070-remove-temporary-files.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8080-reproducible-glibc.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8090-remove-ssl-cert-snakeoil.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8100-remove-udev-persistent-cd-rules.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/8110-remove-udev-persistent-net-rules.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/9000-remove-gnome-icon-cache.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/9010-remove-python-pyc.hook.chroot

View File

@@ -0,0 +1 @@
/home/user/lt/n_os_tr/live-build/share/hooks/normal/9020-remove-man-cache.hook.chroot

View File

@@ -0,0 +1,38 @@
# n-OS-tr fips configuration.
# Ephemeral identity by default (new keypair each boot).
node:
identity:
# Keep empty for ephemeral identity.
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:
# Rewritten on first boot by n-os-tr-firstboot to the first non-loopback iface.
interface: "__FIPS_ETH_IFACE__"
discovery: true
announce: true
auto_connect: true
accept_connections: true
peers:
- npub: "npub1qmc3cvfz0yu2hx96nq3gp55zdan2qclealn7xshgr448d3nh6lks7zel98"
alias: "fips-test-node"
addresses:
- transport: udp
addr: "217.77.8.91:2121"
connect_policy: auto_connect

View File

@@ -0,0 +1,24 @@
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;

View File

@@ -0,0 +1,95 @@
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
image/png png;
image/webp webp;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/avif avif;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
font/woff woff;
font/woff2 woff2;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.apple.mpegurl m3u8;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/vnd.ms-excel xls;
application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.oasis.opendocument.graphics odg;
application/vnd.oasis.opendocument.presentation odp;
application/vnd.oasis.opendocument.spreadsheet ods;
application/vnd.oasis.opendocument.text odt;
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
application/vnd.wap.wmlc wmlc;
application/wasm wasm;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}

View File

@@ -0,0 +1,83 @@
# n-OS-tr nginx site
# Terminates TLS, serves blobs directly from disk, forwards Blossom
# authenticated operations to ginxsom over FastCGI.
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
# Redirect plain HTTP to HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
http2 on;
server_name _;
# Self-signed cert generated on first boot
ssl_certificate /etc/ssl/n-os-tr/fullchain.pem;
ssl_certificate_key /etc/ssl/n-os-tr/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
# Uploads can be large
client_max_body_size 100m;
# Blobs root — nginx serves GET directly from disk
root /var/www/html;
index index.html;
# 1) Landing page / any static docs
location = / {
try_files /index.html =404;
}
# 2) Blob retrieval: GET /<64-hex sha256>
# First try the file on disk; if absent, fall back to ginxsom
# (which may have metadata but no bytes, or may need to 404 with
# a proper Blossom error).
location ~ "^/(?<blobhash>[a-f0-9]{64})$" {
root /var/www/blobs;
try_files /$blobhash @ginxsom;
}
# 3) Blossom authenticated operations go to ginxsom over FastCGI
location = /upload { try_files $uri @ginxsom; }
location = /mirror { try_files $uri @ginxsom; }
location = /report { try_files $uri @ginxsom; }
location /list/ { try_files $uri @ginxsom; }
location /blossom-admin/ { try_files $uri @ginxsom; }
# 4) c-relay websocket endpoint: wss://host/relay -> ws://127.0.0.1:8888/
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;
}
# 5) c-relay admin API/UI
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;
}
location @ginxsom {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/local/bin/ginxsom/ginxsom-fcgi;
fastcgi_pass unix:/run/ginxsom/ginxsom-fcgi.sock;
fastcgi_read_timeout 300s;
}
}

View File

@@ -0,0 +1,34 @@
[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
ExecStart=/opt/c-relay/c_relay_x86 --debug-level=0
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

View File

@@ -0,0 +1,3 @@
[Unit]
Wants=n-os-tr-firstboot.service
After=n-os-tr-firstboot.service

View File

@@ -0,0 +1,3 @@
[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

View File

@@ -0,0 +1,33 @@
[Unit]
Description=Ginxsom Blossom Server
Documentation=https://github.com/hzrd149/blossom
After=network.target n-os-tr-firstboot.service
Requires=n-os-tr-firstboot.service
ConditionPathExists=/var/lib/n-os-tr/env
[Service]
Type=forking
User=www-data
Group=www-data
# Provides /run/ginxsom/, cleaned up on service stop
RuntimeDirectory=ginxsom
RuntimeDirectoryMode=0755
EnvironmentFile=/var/lib/n-os-tr/env
ExecStartPre=/bin/rm -f /run/ginxsom/ginxsom-fcgi.sock
ExecStart=/usr/bin/spawn-fcgi \
-s /run/ginxsom/ginxsom-fcgi.sock \
-M 0660 \
-u www-data \
-g www-data \
-d /var/lib/ginxsom \
-- /usr/local/bin/ginxsom/ginxsom-fcgi \
--admin-pubkey ${GINXSOM_ADMIN_PUBKEY} \
--server-privkey ${GINXSOM_SERVER_PRIVKEY} \
--db-path /var/lib/ginxsom \
--storage-dir /var/www/blobs
ExecStop=/usr/bin/pkill -f ginxsom-fcgi
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,16 @@
[Unit]
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
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/n-os-tr-firstboot
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,3 @@
[Unit]
Wants=n-os-tr-firstboot.service
After=n-os-tr-firstboot.service

View File

@@ -0,0 +1,23 @@
[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
Conflicts=getty@tty1.service
Before=getty@tty1.service
[Service]
Type=simple
ExecStart=/usr/local/sbin/nostr-id-tui
Restart=always
RestartSec=1
StandardInput=tty
StandardOutput=tty
StandardError=journal
TTYPath=/dev/tty1
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,140 @@
#!/bin/bash
# n-os-tr-smoketest — health check for n-OS-tr services.
# Extend with new sections as slices B (fips) and C (c-relay) land.
set -u
# -------------------- output helpers --------------------
if [[ -t 1 ]] && [[ "${NO_COLOR:-}" != "1" ]]; then
C_PASS=$'\e[32m'
C_FAIL=$'\e[31m'
C_SKIP=$'\e[33m'
C_HEAD=$'\e[1;36m'
C_RST=$'\e[0m'
else
C_PASS=''
C_FAIL=''
C_SKIP=''
C_HEAD=''
C_RST=''
fi
declare -i PASS=0 FAIL=0 SKIP=0
pass() { printf " %s[PASS]%s %-45s (%s)\n" "$C_PASS" "$C_RST" "$1" "${2:-ok}"; PASS+=1; }
fail() { printf " %s[FAIL]%s %-45s (%s)\n" "$C_FAIL" "$C_RST" "$1" "${2:-failed}"; FAIL+=1; }
skip() { printf " %s[SKIP]%s %-45s (%s)\n" "$C_SKIP" "$C_RST" "$1" "${2:-skipped}"; SKIP+=1; }
section() { printf "\n%s== %s ==%s\n" "$C_HEAD" "$1" "$C_RST"; }
# a convenience wrapper: runs a test command, passes if exit 0
# usage: check "label" command args...
check() {
local label="$1"
shift
if "$@" >/dev/null 2>&1; then
pass "$label" "$*"
else
local rc=$?
fail "$label" "$* -> exit $rc"
fi
}
# -------------------- core section ----------------------
section "core"
check "n-os-tr-firstboot active" systemctl is-active n-os-tr-firstboot.service
check "n-os-tr-firstboot succeeded" \
bash -c '[[ "$(systemctl show -p Result --value n-os-tr-firstboot.service)" == "success" ]]'
check "firstboot marker exists" test -f /var/lib/n-os-tr/.provisioned
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
# -------------------- nginx + ginxsom --------------------
section "blossom (nginx + ginxsom)"
check "nginx active" systemctl is-active nginx.service
check "ginxsom active" systemctl is-active ginxsom.service
check "ginxsom socket exists" test -S /run/ginxsom/ginxsom-fcgi.sock
# HTTPS landing page
status=$(curl -sk -o /dev/null -w '%{http_code}' https://localhost/ 2>/dev/null)
if [[ "$status" == "200" ]]; then
pass "landing page over TLS" "HTTP $status"
else
fail "landing page over TLS" "HTTP $status"
fi
# BUD-01: HEAD on a random 64-hex should not explode (404 is fine, 5xx is not)
status=$(curl -sk -o /dev/null -w '%{http_code}' -I \
https://localhost/0000000000000000000000000000000000000000000000000000000000000000 2>/dev/null)
case "$status" in
200|404) pass "blob HEAD returns a non-5xx" "HTTP $status" ;;
*) fail "blob HEAD returns a non-5xx" "HTTP $status" ;;
esac
# -------------------- 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
npub=$(fipsctl show status 2>/dev/null | jq -r '.identity.npub // .npub // empty' | head -1 | tr -d '[:space:]')
case "$npub" in
npub1*) pass "fipsctl status returns npub" "${npub:0:20}..." ;;
*) fail "fipsctl status returns npub" "got: ${npub:-<empty>}" ;;
esac
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"'
if journalctl -u c-relay.service --no-pager 2>/dev/null | grep -q "Admin Private Key:"; then
pass "admin nsec logged in journal" "found"
elif ls /opt/c-relay/*.db >/dev/null 2>&1; then
pass "admin nsec logged in journal" "relay initialized (db present)"
else
fail "admin nsec logged in journal" "journal miss and no relay db"
fi
ws_status=$(curl -sk --http1.1 -o /dev/null -w '%{http_code}' \
-H 'Connection: Upgrade' \
-H 'Upgrade: websocket' \
-H 'Sec-WebSocket-Version: 13' \
-H 'Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==' \
https://localhost/relay 2>/dev/null)
if [[ "$ws_status" == "101" ]]; then
pass "wss://localhost/relay websocket upgrade" "HTTP $ws_status"
else
fail "wss://localhost/relay websocket upgrade" "HTTP $ws_status"
fi
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
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
# -------------------- summary ---------------------------
section "summary"
printf " %s%d PASS%s %s%d FAIL%s %s%d SKIP%s\n" \
"$C_PASS" "$PASS" "$C_RST" \
"$C_FAIL" "$FAIL" "$C_RST" \
"$C_SKIP" "$SKIP" "$C_RST"
if [[ $FAIL -gt 0 ]]; then
exit 1
fi
exit 0

Binary file not shown.

View File

@@ -0,0 +1,130 @@
#!/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.
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] $*"; }
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)
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"
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"
# ---------------------------------------------------------------------------
# 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.
# ---------------------------------------------------------------------------
touch "$STATE/.provisioned"
log "First-boot provisioning complete."

View File

@@ -0,0 +1,36 @@
n-OS-tr live ISO (Phase 2 Slice B+C)
===================================
This live image enables:
- n-os-tr-firstboot.service (oneshot provisioning)
- ginxsom.service (Blossom FastCGI server)
- nginx.service (TLS frontend)
- fips.service + fips-dns.service (mesh daemon + DNS responder)
- c-relay.service (Nostr relay)
First boot generates:
- ginxsom identity material under /var/lib/n-os-tr/keys/
- service environment at /var/lib/n-os-tr/env
- self-signed TLS certs under /etc/ssl/n-os-tr/
Useful checks:
- n-os-tr-smoketest
- Output shape: [PASS|FAIL|SKIP] <label> (<detail>) plus a PASS/FAIL/SKIP summary.
- systemctl status n-os-tr-firstboot ginxsom nginx fips fips-dns c-relay
- journalctl -u n-os-tr-firstboot.service
- journalctl -u c-relay.service | grep 'Admin Private Key:'
- fipsctl identity
- fipsctl peers
- cat /var/lib/n-os-tr/keys/ginxsom.nsec
- curl -k https://localhost/
- curl -k -H 'Accept: application/nostr+json' https://localhost/relay
Relay endpoints:
- wss://<host>/relay
- https://<host>/admin/
If terminal colours render poorly, run: NO_COLOR=1 n-os-tr-smoketest
Notes:
- Identity is ephemeral by default for this slice (ginxsom nsec, fips identity, c-relay admin key).
- fips transport is configured for ethernet discovery and UDP bootstrap peer connectivity.

View File

@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>n-OS-tr</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 680px; margin: 4rem auto; padding: 0 1rem; color: #ddd; background: #111; }
h1 { font-weight: 300; letter-spacing: 0.05em; }
code { background: #222; padding: 0.15rem 0.35rem; border-radius: 3px; }
.services li { margin-bottom: 0.5rem; }
a { color: #8cf; }
</style>
</head>
<body>
<h1>n-OS-tr</h1>
<p>A Nostr-addressed mesh node. Early preview.</p>
<h2>Services</h2>
<ul class="services">
<li><strong>Blossom server (ginxsom):</strong> Blossom blob endpoints under <code>/</code> — upload at <code>PUT /upload</code>, retrieve at <code>GET /<sha256></code>.</li>
<li><strong>Nostr relay (c-relay):</strong> <em>not yet enabled in this build</em>.</li>
<li><strong>FIPS mesh daemon:</strong> <em>not yet enabled in this build</em>.</li>
</ul>
<p>This node's identity and keys were generated on first boot. See <code>/etc/motd</code> when you log in.</p>
</body>
</html>

View File

@@ -0,0 +1,17 @@
nginx-light
spawn-fcgi
libfcgi-bin
ca-certificates
openssl
curl
jq
vim
htop
# Slice B/C runtime dependencies
libdbus-1-3
iproute2
nftables
# TUI runtime dependency
libncursesw6

View File

@@ -0,0 +1,4 @@
live-boot
live-config
live-config-systemd
systemd-sysv

7
iso/config/source Normal file
View File

@@ -0,0 +1,7 @@
# config/source - options for live-build(7), source stage
# Set source option
LB_SOURCE="false"
# Set image type
LB_SOURCE_IMAGES="tar"