From 4989f9898c8b5c412e9a2b16b6c9d701529c7e44 Mon Sep 17 00:00:00 2001 From: Hermes Date: Thu, 18 Jun 2026 15:23:06 -0400 Subject: [PATCH] feat: merge Reticulum overlay, poup-16t-disk, open_code_server, merged uConsole config --- flake.nix | 5 +- hosts/uconsole-cm5/configuration.nix | 147 +++++++++++++++++++-- modules/nixos/filesystem/poup-16t-disk.nix | 121 +++++++++++++++++ overlays/reticulum.nix | 81 ++++++++++++ 4 files changed, 343 insertions(+), 11 deletions(-) create mode 100644 modules/nixos/filesystem/poup-16t-disk.nix create mode 100644 overlays/reticulum.nix diff --git a/flake.nix b/flake.nix index a57e394..5c55b95 100644 --- a/flake.nix +++ b/flake.nix @@ -42,7 +42,7 @@ "/etc/ssh/ssh_host_ed25519_key" "/root/.age/bootstrap.key" ]; }; - overlays = [ agenix.overlays.default ]; + overlays = [ agenix.overlays.default (import ./overlays/reticulum.nix) ]; pkgs = import nixpkgs { inherit system overlays; config.allowUnfree = true; @@ -142,8 +142,9 @@ ./hosts/lazyworkhorse/hardware-configuration.nix ./modules/nixos/filesystem/hoardingcow-mount.nix ./modules/nixos/services/docker_manager.nix - ./modules/nixos/services/wireguard-client.nix + ./modules/nixos/filesystem/poup-16t-disk.nix ./modules/nixos/services/ollama_init_custom_models.nix + ./modules/nixos/services/open_code_server.nix ./modules/nixos/security/ai-worker-restricted.nix ./users/gortium/gortium.nix ./users/ai-worker/ai-worker.nix diff --git a/hosts/uconsole-cm5/configuration.nix b/hosts/uconsole-cm5/configuration.nix index 6fa7183..fcf5c02 100644 --- a/hosts/uconsole-cm5/configuration.nix +++ b/hosts/uconsole-cm5/configuration.nix @@ -6,6 +6,9 @@ i18n.defaultLocale = "en_CA.UTF-8"; system.stateVersion = "25.11"; + # Boot & Hardware + boot.loader.raspberry-pi.bootloader = "kernel"; + # SSH — root access avec clés gortium + ai-worker services.openssh = { enable = true; @@ -20,16 +23,12 @@ users.ai-worker.main ]; - # AI worker user (Hermes SSH access) - # Age secret for gortium password (file created by user) age.secrets.gortium_password = { file = ../../secrets/gortium_password.age; }; - # Password file for gortium (merges with users/gortium/default.nix) - - # WiFi via NetworkManager + secret agenix + # WiFi via NetworkManager networking.networkmanager.enable = true; # Firmware @@ -40,19 +39,149 @@ enable = true; xwayland.enable = true; }; + # HackerGadgets AIO v2 board hardware.uconsole-cm5-aio-v2 = { enable = true; - - # Rails actifs au boot bootRails = { GPS = false; LORA = false; SDR = false; USB = false; }; - enableGPS = false; }; -} \ No newline at end of file + # User + users.users.gortium = { + isNormalUser = true; + extraGroups = [ "wheel" "networkmanager" "video" "dialout" "kismet" ]; + hashedPasswordFile = config.age.secrets.gortium_password.path; + openssh.authorizedKeys.keys = [ + keys.users.gortium.main + keys.users.gortium.gitea + ]; + }; + security.sudo.extraRules = [ + { + users = [ "gortium" ]; + commands = [{ + command = "ALL"; + options = [ "NOPASSWD" ]; + }]; + } + ]; + + # ============================================================ + # Package groups + # ============================================================ + environment.systemPackages = with pkgs; [ + # ===== Base ===== + emacs-pgtk + git + ripgrep + fd + htop + tmux + neovim + + # ===== HAM Radio ===== + js8call + wsjtx + fldigi + pat # Winlink client + direwolf # AX.25 packet modem + chirp # Radio programming tool + hamlib # Ham radio control libraries + trustedqsl # Logbook of the World (LoTW) + + # ===== SDR / RF ===== + sdrpp # SDR++ spectrum analyzer + gqrx # SDR receiver GUI + rtl-sdr # RTL-SDR drivers & utilities + inspectrum # Offline signal analysis + soapysdr-with-plugins # SoapySDR + hardware support plugins + + # ===== Mesh / LoRa ===== + meshtastic # Python CLI for Meshtastic devices + reticulumStack # Reticulum Network Stack + lxmf # LXMF messaging protocol + nomadnet # Nomad Network client + + # ===== Security ===== + nmap + aircrack-ng + kismet # Wi-Fi monitor / IDS + bettercap # MITM/network attack framework + wireshark # Packet analyzer + hashcat # GPU password cracker + john # John the Ripper + sqlmap # SQL injection tool + + # ===== GPS / Maps ===== + foxtrotgps + viking # GPS map editor + gpsbabel # GPS data conversion + ]; + + # ============================================================ + # Reticulum Service (rnsd) + # ============================================================ + systemd.services.rnsd = { + description = "Reticulum Network Stack Daemon"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "gortium"; + Group = "gortium"; + ExecStart = "${pkgs.reticulumStack}/bin/rnsd"; + Restart = "always"; + RestartSec = "10s"; + LimitNOFILE = 65536; + }; + }; + + # ============================================================ + # Kismet Service (Wi-Fi monitoring / mesh node) + # ============================================================ + systemd.services.kismet = { + description = "Kismet Wi-Fi Monitor & IDS"; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "gortium"; + Group = "kismet"; + ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-base=/home/gortium/kismet_logs --no-nc-ui"; + Restart = "always"; + RestartSec = "10s"; + }; + }; + + # ============================================================ + # Kernel modules for SDR and radio + # ============================================================ + boot.kernelModules = [ + "88x2bu" # Realtek 8812/8821BU USB WiFi + "rtl8xxxu" # RTL8188/8192/8723 USB WiFi + "rtl2832_sdr" # RTL-SDR kernel module + "dvb_usb_rtl28xxu" # RTL-SDR DVB-T + ]; + + # ============================================================ + # Extra udev rules for SDR and HAM radio devices + # ============================================================ + services.udev.packages = with pkgs; [ rtl-sdr ]; + + # ============================================================ + # Enable IPv6 for Reticulum mesh + # ============================================================ + networking.enableIPv6 = true; + + # ============================================================ + # Firewall + # ============================================================ + networking.firewall.allowedTCPPorts = [ 22 ]; + networking.firewall.allowedUDPPorts = [ ]; +} diff --git a/modules/nixos/filesystem/poup-16t-disk.nix b/modules/nixos/filesystem/poup-16t-disk.nix new file mode 100644 index 0000000..1cd377c --- /dev/null +++ b/modules/nixos/filesystem/poup-16t-disk.nix @@ -0,0 +1,121 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.gortium.poup16t; + luksName = cfg.luksName; +in +with lib; + +{ + options.gortium.poup16t = { + enable = mkEnableOption "Poup_16T storage disk (btrfs + LUKS + btrbk snapshots)"; + + luksUuid = mkOption { + type = types.str; + description = '' + UUID of the LUKS partition on the 16TB disk (WD Red Pro). + + Find this by running as root when the disk is connected: + blkid /dev/sdb # or wherever the disk appears + lsblk -o NAME,SIZE,FSTYPE,UUID + + Since btrfs is inside LUKS, the FS UUID is hidden — use the + LUKS partition UUID from blkid (it'll show TYPE=\"crypto_LUKS\"). + ''; + example = "00000000-0000-0000-0000-000000000000"; + }; + + luksName = mkOption { + type = types.str; + default = "poup_16t"; + description = "Name for the LUKS /dev/mapper/ mapping"; + }; + + mountPoint = mkOption { + type = types.str; + default = "/mnt/Poup_16T"; + description = "Mount point for the 16TB data disk"; + }; + + btrfsOptions = mkOption { + type = types.listOf types.str; + default = [ "defaults" "noatime" "compress=zstd:3" "nofail" ]; + description = "Mount options for the btrfs filesystem. 'nofail' ensures boot succeeds when disk is disconnected."; + }; + + btrbk = { + enable = mkOption { + type = types.bool; + default = true; + description = "Enable btrbk snapshot management on this volume"; + }; + + schedule = mkOption { + type = types.str; + default = "daily"; + description = "systemd calendar event for btrbk (e.g. 'daily', 'hourly', '*-*-* 00:00:00')"; + }; + + preserveMin = mkOption { + type = types.str; + default = "2d"; + description = "btrbk snapshot_preserve_min — minimum age before pruning"; + }; + + preserve = mkOption { + type = types.str; + default = "14d 4w 3m"; + description = "btrbk snapshot_preserve — retention policy (daily, weekly, monthly)"; + }; + + snapshotDir = mkOption { + type = types.str; + default = ".snapshots"; + description = "Directory name for snapshots relative to volume root"; + }; + }; + }; + + config = mkIf cfg.enable { + # Enable btrfs kernel support (no DKMS needed — it's in-tree) + boot.supportedFilesystems = [ "btrfs" ]; + + # Install btrfs administration tools + environment.systemPackages = with pkgs; [ + btrfs-progs # mkfs.btrfs, btrfs, fsck, balance, scrub + btrbk # Snapshot management + rotation + ]; + + # LUKS2 unlock at boot (uses keyfile or prompts if unavailable) + # Since the disk may be disconnected, initrd times out gracefully (~30s) + boot.initrd.luks.devices.${luksName} = { + device = "/dev/disk/by-uuid/${cfg.luksUuid}"; + preLVM = false; + allowDiscards = true; + }; + + # Mount the unlocked mapper device as btrfs + fileSystems.${cfg.mountPoint} = { + device = "/dev/mapper/${luksName}"; + fsType = "btrfs"; + options = cfg.btrfsOptions; + }; + + # btrbk — automated snapshot creation and rotation + services.btrbk = mkIf cfg.btrbk.enable { + instances.poup16t = { + onCalendar = cfg.btrbk.schedule; + settings = { + snapshot_preserve_min = cfg.btrbk.preserveMin; + snapshot_preserve = cfg.btrbk.preserve; + + volume.${cfg.mountPoint} = { + snapshot_create = "always"; + snapshot_dir = cfg.btrbk.snapshotDir; + subvolume = "."; + }; + }; + }; + }; + }; +} diff --git a/overlays/reticulum.nix b/overlays/reticulum.nix new file mode 100644 index 0000000..e646559 --- /dev/null +++ b/overlays/reticulum.nix @@ -0,0 +1,81 @@ +final: prev: let + python3 = final.python3; + pyPkgs = python3.pkgs; +in { + reticulumStack = python3.pkgs.buildPythonApplication rec { + pname = "reticulum"; + version = "1.2.9"; + format = "setuptools"; + src = pyPkgs.fetchPypi { + pname = "rns"; + inherit version; + sha256 = "554814231c237b9caacf8df669312e57dd7d3f84b6d4810125087d1a79a75d75"; + }; + propagatedBuildInputs = with pyPkgs; [ cryptography pyserial ]; + doCheck = false; + pythonImportsCheck = [ "RNS" ]; + meta = with final.lib; { + description = "Self-configuring, encrypted and resilient mesh networking stack"; + homepage = "https://reticulum.network/"; + license = licenses.mit; + platforms = platforms.linux; + }; + }; + + lxmf = python3.pkgs.buildPythonApplication rec { + pname = "lxmf"; + version = "0.9.8"; + format = "setuptools"; + src = pyPkgs.fetchPypi { + inherit pname version; + sha256 = "30f39f3a975a049c12ee2cfceb3261d24cb5adec881c6821f7354464b3f3650c"; + }; + propagatedBuildInputs = [ final.reticulumStack ]; + doCheck = false; + pythonImportsCheck = [ "LXMF" ]; + meta = with final.lib; { + description = "Lightweight Extensible Message Format for Reticulum"; + homepage = "https://github.com/markqvist/lxmf"; + license = licenses.mit; + platforms = platforms.linux; + }; + }; + + nomadnet = python3.pkgs.buildPythonApplication rec { + pname = "nomadnet"; + version = "1.1.1"; + format = "setuptools"; + src = pyPkgs.fetchPypi { + inherit pname version; + sha256 = "fa13b64a10e75b705a58024815ab72451700aa726af96d415ba99dec28dfc40a"; + }; + propagatedBuildInputs = with pyPkgs; [ final.reticulumStack final.lxmf urwid qrcode ]; + doCheck = false; + pythonImportsCheck = [ "nomadnet" ]; + meta = with final.lib; { + description = "Nomad Network — resilient mesh communications platform"; + homepage = "https://github.com/markqvist/NomadNet"; + license = licenses.mit; + platforms = platforms.linux; + }; + }; + + rnsh = python3.pkgs.buildPythonApplication rec { + pname = "rnsh"; + version = "0.1.7"; + format = "setuptools"; + src = pyPkgs.fetchPypi { + inherit pname version; + sha256 = "9cb72f25abb1c6d300f8014b264184ff78f592fe88e36094938012990b797c93"; + }; + propagatedBuildInputs = [ final.reticulumStack ]; + doCheck = false; + pythonImportsCheck = [ "rnsh" ]; + meta = with final.lib; { + description = "Remote shell over Reticulum"; + homepage = "https://github.com/acehoss/rnsh"; + license = licenses.mit; + platforms = platforms.linux; + }; + }; +}