Files
Sovran_SystemsOS/modules/core/sovran-hub.nix
2026-04-02 15:43:32 -05:00

240 lines
12 KiB
Nix

{ config, lib, pkgs, ... }:
let
cfg = config.sovran_systemsOS;
monitoredServices =
# ── Infrastructure (always present) ────────────────────────
[
{ name = "Caddy"; unit = "caddy.service"; type = "system"; icon = "caddy"; enabled = true; category = "infrastructure"; credentials = []; }
{ name = "Tor"; unit = "tor.service"; type = "system"; icon = "tor"; enabled = true; category = "infrastructure"; credentials = []; }
{ name = "System Passwords"; unit = "root-password-setup.service"; type = "system"; icon = "system"; enabled = true; category = "infrastructure"; credentials = [
{ label = "Free Account Username"; value = "free"; }
{ label = "Free Account Password"; file = "/var/lib/secrets/free-password"; }
{ label = "Root Password"; file = "/var/lib/secrets/root-password"; }
{ label = "SSH Local Access"; value = "ssh root@localhost / Passphrase: gosovransystems"; }
]; }
]
# ── Bitcoin Base (node implementations) ────────────────────
++ [
{ name = "Bitcoin Knots + BIP110"; unit = "bitcoind.service"; type = "system"; icon = "bip110"; enabled = cfg.features.bip110; category = "bitcoin-base"; credentials = [
{ label = "Tor Address"; file = "/var/lib/tor/onion/bitcoind/hostname"; }
]; }
{ name = "Bitcoin Knots"; unit = "bitcoind.service"; type = "system"; icon = "bitcoind"; enabled = cfg.services.bitcoin && !cfg.features.bitcoin-core && !cfg.features.bip110; category = "bitcoin-base"; credentials = [
{ label = "Tor Address"; file = "/var/lib/tor/onion/bitcoind/hostname"; }
]; }
{ name = "Bitcoin Core"; unit = "bitcoind.service"; type = "system"; icon = "bitcoin-core"; enabled = cfg.features.bitcoin-core; category = "bitcoin-base"; credentials = [
{ label = "Tor Address"; file = "/var/lib/tor/onion/bitcoind/hostname"; }
]; }
]
# ── Bitcoin Apps (services on top of the node) ─────────────
++ [
{ name = "Electrs"; unit = "electrs.service"; type = "system"; icon = "electrs"; enabled = cfg.services.bitcoin; category = "bitcoin-apps"; credentials = [
{ label = "Tor Address"; file = "/var/lib/tor/onion/electrs/hostname"; }
{ label = "Port"; value = "50001"; }
]; }
{ name = "LND"; unit = "lnd.service"; type = "system"; icon = "lnd"; enabled = cfg.services.bitcoin; category = "bitcoin-apps"; credentials = []; }
{ name = "Ride The Lightning"; unit = "rtl.service"; type = "system"; icon = "rtl"; enabled = cfg.services.bitcoin; category = "bitcoin-apps"; credentials = [
{ label = "Tor Access"; file = "/var/lib/tor/onion/rtl/hostname"; prefix = "http://"; }
{ label = "Local Network"; file = "/var/lib/secrets/internal-ip"; prefix = "http://"; suffix = ":3050"; }
{ label = "Password"; file = "/etc/nix-bitcoin-secrets/rtl-password"; }
]; }
{ name = "BTCPayserver"; unit = "btcpayserver.service"; type = "system"; icon = "btcpayserver"; enabled = cfg.services.bitcoin; category = "bitcoin-apps"; credentials = [
{ label = "URL"; file = "/var/lib/domains/btcpayserver"; prefix = "https://"; }
{ label = "Note"; value = "Create your admin account on first visit"; }
]; }
{ name = "Mempool"; unit = "mempool.service"; type = "system"; icon = "mempool"; enabled = cfg.features.mempool; category = "bitcoin-apps"; credentials = [
{ label = "Tor Access"; file = "/var/lib/tor/onion/mempool-frontend/hostname"; prefix = "http://"; }
{ label = "Local Network"; file = "/var/lib/secrets/internal-ip"; prefix = "http://"; suffix = ":60847"; }
]; }
]
# ── Communication ──────────────────────────────────────────
++ [
{ name = "Matrix-Synapse"; unit = "matrix-synapse.service"; type = "system"; icon = "synapse"; enabled = cfg.services.synapse; category = "communication"; credentials = [
{ label = "Users"; file = "/var/lib/secrets/matrix-users"; multiline = true; }
]; }
{ name = "Element-Call"; unit = "livekit.service"; type = "system"; icon = "livekit"; enabled = cfg.features.element-calling; category = "communication"; credentials = []; }
]
# ── Self-Hosted Apps ───────────────────────────────────────
++ [
{ name = "VaultWarden"; unit = "vaultwarden.service"; type = "system"; icon = "vaultwarden"; enabled = cfg.services.vaultwarden; category = "apps"; credentials = [
{ label = "URL"; file = "/var/lib/domains/vaultwarden"; prefix = "https://"; }
{ label = "Admin Panel"; file = "/var/lib/domains/vaultwarden"; prefix = "https://"; suffix = "/admin"; }
{ label = "Admin Token"; file = "/var/lib/secrets/vaultwarden/vaultwarden.env"; extract = "ADMIN_TOKEN"; }
]; }
{ name = "Nextcloud"; unit = "phpfpm-nextcloud.service"; type = "system"; icon = "nextcloud"; enabled = cfg.services.nextcloud; category = "apps"; credentials = [
{ label = "Credentials"; file = "/var/lib/secrets/nextcloud-admin"; multiline = true; }
]; }
{ name = "WordPress"; unit = "phpfpm-wordpress.service"; type = "system"; icon = "wordpress"; enabled = cfg.services.wordpress; category = "apps"; credentials = [
{ label = "Credentials"; file = "/var/lib/secrets/wordpress-admin"; multiline = true; }
]; }
]
# ── Nostr / Relay ──────────────────────────────────────────
++ [
{ name = "Haven Relay"; unit = "haven-relay.service"; type = "system"; icon = "haven"; enabled = cfg.features.haven; category = "nostr"; credentials = []; }
];
activeRole =
if cfg.roles.desktop then "desktop"
else if cfg.roles.node then "node"
else "server_plus_desktop";
generatedConfig = pkgs.writeText "sovran-hub-config.json"
(builtins.toJSON {
refresh_interval = 5;
command_method = "systemctl";
role = activeRole;
services = monitoredServices;
});
# ── Update wrapper script ──────────────────────────────────────
update-script = pkgs.writeShellScript "sovran-hub-update.sh" ''
set -uo pipefail
export PATH="${lib.makeBinPath [ pkgs.nix pkgs.nixos-rebuild pkgs.git pkgs.flatpak pkgs.coreutils ]}:$PATH"
LOG="/var/log/sovran-hub-update.log"
STATUS="/var/log/sovran-hub-update.status"
# Mark as RUNNING
echo "RUNNING" > "$STATUS"
# Truncate the log and redirect ALL output (stdout + stderr) into it
: > "$LOG"
exec > >(tee -a "$LOG") 2>&1
echo ""
echo " Sovran_SystemsOS Update $(date)"
echo ""
echo ""
RC=0
echo " Step 1/3: nix flake update "
if ! nix flake update --flake /etc/nixos --print-build-logs 2>&1; then
echo "[ERROR] nix flake update failed"
RC=1
fi
echo ""
if [ "$RC" -eq 0 ]; then
echo " Step 2/3: nixos-rebuild switch "
if ! nixos-rebuild switch --flake /etc/nixos --print-build-logs 2>&1; then
echo "[ERROR] nixos-rebuild switch failed"
RC=1
fi
echo ""
fi
if [ "$RC" -eq 0 ]; then
echo " Step 3/3: flatpak update "
if ! flatpak update -y 2>&1; then
echo "[WARNING] flatpak update failed (non-fatal)"
fi
echo ""
fi
if [ "$RC" -eq 0 ]; then
echo ""
echo " Update completed successfully"
echo ""
echo "SUCCESS" > "$STATUS"
else
echo ""
echo " Update failed see errors above"
echo ""
echo "FAILED" > "$STATUS"
fi
exit "$RC"
'';
sovran-hub-web = pkgs.python3Packages.buildPythonApplication {
pname = "sovran-systemsos-hub-web";
version = "1.0.0";
format = "other";
src = ../../app;
propagatedBuildInputs = with pkgs.python3Packages; [
fastapi
uvicorn
jinja2
python-multipart
];
dontBuild = true;
installPhase = ''
runHook preInstall
# Python source
install -d $out/lib/sovran-hub-web
cp -r sovran_systemsos_web $out/lib/sovran-hub-web/
# Generated config
cp ${generatedConfig} $out/lib/sovran-hub-web/config.json
# Icons (SVG)
install -d $out/share/sovran-hub/icons
cp icons/* $out/share/sovran-hub/icons/ 2>/dev/null || true
# Launcher script
install -d $out/bin
cat > $out/bin/sovran-hub-web <<LAUNCHER
#!${pkgs.python3}/bin/python3
import os, sys
base = os.path.join("$out", "lib", "sovran-hub-web")
sys.path.insert(0, base)
os.environ["SOVRAN_HUB_CONFIG"] = os.path.join(base, "config.json")
os.environ["SOVRAN_HUB_ICONS"] = os.path.join("$out", "share", "sovran-hub", "icons")
import uvicorn
uvicorn.run(
"sovran_systemsos_web.server:app",
host="0.0.0.0",
port=8937,
log_level="info",
)
LAUNCHER
chmod +x $out/bin/sovran-hub-web
runHook postInstall
'';
meta = {
description = "Sovran_SystemsOS Hub web-based systemd service manager";
mainProgram = "sovran-hub-web";
};
};
in
{
config = {
# ── Web server as a systemd service ────────────────────────
systemd.services.sovran-hub-web = {
description = "Sovran_SystemsOS Hub Web Interface";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
ExecStart = "${sovran-hub-web}/bin/sovran-hub-web";
Restart = "on-failure";
RestartSec = "5s";
User = "root";
StandardOutput = "journal";
StandardError = "journal";
};
};
# ── System update as a detached oneshot ─────────────────────
systemd.services.sovran-hub-update = {
description = "Sovran_SystemsOS System Update";
serviceConfig = {
Type = "oneshot";
ExecStart = "${update-script}";
};
};
# ── Open firewall port ─────────────────────────────────────
networking.firewall.allowedTCPPorts = [ 8937 ];
};
}