This commit is contained in:
mjallen18
2026-03-30 16:09:25 -05:00
parent 8d8d49bd38
commit a88736cf6e
23 changed files with 273 additions and 58 deletions

185
lib/network/default.nix Normal file
View File

@@ -0,0 +1,185 @@
# Central network topology registry.
#
# Exposed as lib.<namespace>.network.* (Snowfall Lib merges lib/ sub-directories
# automatically, so this file is reachable as lib.mjallen.network inside any
# NixOS module, home-manager module, or package that receives `lib`).
#
# Usage examples:
#
# let net = lib.mjallen.network; in
# net.hosts.nas.lan # "10.0.1.3"
# net.hosts.nas.lan4 # "10.0.1.3/24" (CIDR notation)
# net.hosts.nuc.lan # "10.0.1.4"
# net.hosts.pi5.nebula # "10.1.1.1"
# net.subnet.lan # "10.0.1.0/24"
# net.subnet.nebula # "10.1.1.0/24"
# net.ports.nas.nextcloud # 9988
# net.domain # "mjallen.dev"
#
# All attributes intentionally use plain strings / ints so they can be
# interpolated with `toString` or used directly in any context.
{ ... }:
{
network = {
# -----------------------------------------------------------------------
# Global domain
# -----------------------------------------------------------------------
domain = "mjallen.dev";
# -----------------------------------------------------------------------
# Subnets
# -----------------------------------------------------------------------
subnet = {
lan = "10.0.1.0/24";
nebula = "10.1.1.0/24";
# Docker / container bridge used by Home Assistant
docker = "172.30.33.0/24";
};
# -----------------------------------------------------------------------
# Hosts
# Each host exposes:
# lan — bare IPv4 address (no prefix length)
# lan4 — IPv4 address with /24 CIDR suffix (for static IP config)
# nebula — Nebula overlay IP (where applicable)
# -----------------------------------------------------------------------
hosts = {
# ---- Raspberry Pi 5 (pi5) — DNS / Nebula lighthouse ----------------
pi5 = {
hostname = "pi5";
lan = "10.0.1.2";
lan4 = "10.0.1.2/24";
nebula = "10.1.1.1";
gateway = "10.0.1.1";
};
# ---- NAS (jallen-nas) — primary server -----------------------------
nas = {
hostname = "jallen-nas";
lan = "10.0.1.3";
lan4 = "10.0.1.3/24";
nebula = "10.1.1.3";
gateway = "10.0.1.1";
};
# ---- Intel NUC (nuc-nixos) — Home Assistant host -------------------
nuc = {
hostname = "nuc-nixos";
lan = "10.0.1.4";
lan4 = "10.0.1.4/24";
nebula = "10.1.1.4";
gateway = "10.0.1.1";
};
# ---- MacBook Pro (macbook-pro-nixos) — Apple Silicon laptop --------
macbook = {
hostname = "macbook-pro-nixos";
nebula = "10.1.1.8";
};
# ---- ASUS ROG Ally X (allyx) ----------------------------------------
allyx = {
hostname = "allyx";
nebula = "10.1.1.10";
};
# ---- Router / gateway / AdGuard upstream ---------------------------
router = {
hostname = "router";
lan = "10.0.1.1";
lan4 = "10.0.1.1/24";
};
};
# -----------------------------------------------------------------------
# Service ports
# Grouped by host. Every entry matches the port set in apps.nix / the
# corresponding mkModule option so there is a single source of truth.
# -----------------------------------------------------------------------
ports = {
# ---- pi5 services --------------------------------------------------
pi5 = {
adguard = 3000;
nebula = 4242;
dns = 53;
};
# ---- NAS services --------------------------------------------------
nas = {
actual = 3333;
attic = 9012;
authentik = 9000;
authentikRac = 4823;
calibre = 8084;
calibreWeb = 8083;
codeServer = 4444;
cockpit = 9091;
collabora = 9980;
coturn = 3478;
crowdsec = 8181;
dispatcharr = 9191;
elasticsearch = 9200;
gitea = 3000;
giteaSsh = 2222;
glance = 5555;
glances = 61208;
grafana = 9999;
grimmory = 6066;
guacd = 4822;
headscale = 2112;
immich = 2283;
jellyfin = 8096;
jellyseerr = 5055;
kavita = 5000;
llamaCpp = 8127;
lubelogger = 6754;
manyfold = 3214;
mariadb = 3306;
matrix = 8448;
mongodb = 27017;
nebula = 4242;
netbootxyz = 4000;
netbootxyzWeb = 4080;
nextcloud = 9988;
ntfy = 2586;
nutUpsd = 3493;
ocis = 9200;
onlyoffice = 9943;
opencloud = 9200;
orcaSlicer = 3100;
paperless = 28981;
paperlessAi = 28982;
postgresql = 5432;
protonmailSmtp = 1025;
protonmailImap = 1143;
redisCcache = 6363;
redisManyfold = 6380;
redisOnlyoffice = 6381;
resticServer = 8008;
sabnzbd = 8280;
sonarr = 8989;
radarr = 7878;
sparkyFitnessFe = 3004;
sparkyFitnessBe = 3010;
sunshine = 47989;
tdarr = 8265;
tdarrServer = 8266;
termix = 7777;
tunarr = 8000;
unmanic = 8265;
uptimeKuma = 3001;
wyomingPiper = 10200;
wyomingWhisper = 10300;
};
# ---- NUC services --------------------------------------------------
nuc = {
homeAssistant = 8123;
mqtt = 1883;
otbr = 8880;
otbrRest = 8881;
esphome = 6052;
};
};
};
}

View File

@@ -8,10 +8,13 @@
# lib.${namespace}.nixSettings.commonSettings
# lib.${namespace}.nixSettings.commonGc
{ lib, ... }:
let
net = lib.mjallen.network;
in
{
nixSettings = {
commonSubstituters = [
"http://10.0.1.3:9012/nas-cache"
"http://${net.hosts.nas.lan}:${toString net.ports.nas.attic}/nas-cache"
"https://nixos-apple-silicon.cachix.org"
"https://nixos-raspberrypi.cachix.org"
"https://nix-community.cachix.org"

View File

@@ -7,6 +7,7 @@
}:
let
cfg = config.${namespace}.programs.opencode;
net = lib.${namespace}.network;
in
{
options.${namespace}.programs.opencode = {
@@ -19,7 +20,7 @@ in
sops.templates."hass-mcp.env" = {
mode = "0600";
content = ''
HA_URL=http://10.0.1.4:8123
HA_URL=http://${net.hosts.nuc.lan}:${toString net.ports.nuc.homeAssistant}
HA_TOKEN=${config.sops.placeholder."hass-mcp/token"}
'';
};
@@ -33,7 +34,7 @@ in
npm = "@ai-sdk/openai-compatible";
name = "llama-server (local)";
options = {
baseURL = "http://10.0.1.3:8127/v1";
baseURL = "http://${net.hosts.nas.lan}:${toString net.ports.nas.llamaCpp}/v1";
};
models = {
Qwen3-Coder-Next-Q4_0 = {

View File

@@ -6,6 +6,7 @@
}:
let
cfg = config.${namespace}.shell-aliases;
net = lib.${namespace}.network;
in
{
options.${namespace}.shell-aliases = {
@@ -13,7 +14,7 @@ in
buildHost = lib.mkOption {
type = lib.types.str;
default = "admin@10.0.1.3";
default = "admin@${net.hosts.nas.lan}";
description = "Build host for nixos-rebuild commands";
};
@@ -50,8 +51,8 @@ in
) "nix flake update ${lib.concatStringsSep " " cfg.flakeInputs} --flake /etc/nixos";
# NAS management
update-nas = "nixos-rebuild switch --use-remote-sudo --target-host admin@10.0.1.3 --build-host admin@10.0.1.3 --flake ~/nix-config#jallen-nas";
nas-ssh = "kitten ssh admin@10.0.1.3";
update-nas = "nixos-rebuild switch --use-remote-sudo --target-host admin@${net.hosts.nas.lan} --build-host admin@${net.hosts.nas.lan} --flake ~/nix-config#jallen-nas";
nas-ssh = "kitten ssh admin@${net.hosts.nas.lan}";
}
// cfg.extraAliases;
};

View File

@@ -8,6 +8,7 @@
with lib;
let
cfg = config.${namespace}.services.home-assistant;
net = lib.${namespace}.network;
in
{
# disabledModules = [
@@ -348,16 +349,15 @@ in
http = {
use_x_forwarded_for = true;
trusted_proxies = [
"172.30.33.0/24"
"10.0.1.4"
"10.0.1.3"
"10.0.1.18"
"10.0.1.0/24"
net.subnet.docker
net.hosts.nuc.lan
net.hosts.nas.lan
net.subnet.lan
];
};
recorder = {
db_url = "postgresql://homeassistant@10.0.1.3/homeassistant";
db_url = "postgresql://homeassistant@${net.hosts.nas.lan}/homeassistant";
purge_keep_days = 180;
};

View File

@@ -9,6 +9,7 @@ with lib;
let
name = "caddy";
cfg = config.${namespace}.services.${name};
net = lib.${namespace}.network;
caddyPackage = pkgs.caddy.withPlugins {
plugins = [
@@ -45,7 +46,7 @@ let
@hass host hass.mjallen.dev
handle @hass {
reverse_proxy http://10.0.1.4:8123
reverse_proxy http://${net.hosts.nuc.lan}:${toString net.ports.nuc.homeAssistant}
}
'';
};
@@ -53,12 +54,12 @@ let
"sonarr.mjallen.dev" = {
extraConfig = ''
@sonarr {
remote_ip 10.0.1.0/24 10.1.1.0/16
remote_ip ${net.subnet.lan} ${net.subnet.nebula}
host sonarr.mjallen.dev
}
handle @sonarr {
reverse_proxy 10.0.1.3:8989
reverse_proxy ${net.hosts.nas.lan}:${toString net.ports.nas.sonarr}
}
handle {

View File

@@ -8,6 +8,7 @@
let
name = "cockpit";
cfg = config.${namespace}.services.${name};
net = lib.${namespace}.network;
cockpitConfig = lib.${namespace}.mkModule {
inherit config name;
@@ -18,9 +19,9 @@ let
port = cfg.port;
openFirewall = cfg.openFirewall;
allowed-origins = [
"https://10.0.1.3:${toString cfg.port}"
"https://jallen-nas:${toString cfg.port}"
"https://jallen-nas.local:${toString cfg.port}"
"https://${net.hosts.nas.lan}:${toString cfg.port}"
"https://${net.hosts.nas.hostname}:${toString cfg.port}"
"https://${net.hosts.nas.hostname}.local:${toString cfg.port}"
];
plugins = with pkgs.${namespace}; [
# cockpit-benchmark

View File

@@ -7,6 +7,7 @@
let
name = "collabora";
cfg = config.${namespace}.services.${name};
topology = lib.${namespace}.network;
collaboraConfig = lib.${namespace}.mkModule {
inherit config name;
@@ -30,8 +31,8 @@ let
post_allow.host = [
"cloud.mjallen.dev"
"office.mjallen.dev"
"10.0.1.3"
"10.0.1.0/24"
topology.hosts.nas.lan
topology.subnet.lan
];
frame_ancestors = "cloud.mjallen.dev";
};

View File

@@ -7,6 +7,7 @@
let
name = "glance";
cfg = config.${namespace}.services.${name};
net = lib.${namespace}.network;
glanceConfig = lib.${namespace}.mkModule {
inherit config name;
@@ -117,7 +118,7 @@ let
}
{
title = "AdGuard Home";
url = "http://10.0.1.2:3000/";
url = "http://${net.hosts.pi5.lan}:${toString net.ports.pi5.adguard}/";
icon = "si:adguard";
allow-insecure = true;
}
@@ -128,13 +129,13 @@ let
}
{
title = "Manyfold";
url = "http://10.0.1.3:3214/collections";
url = "http://${net.hosts.nas.lan}:${toString net.ports.nas.manyfold}/collections";
icon = "sh:manyfold";
allow-insecure = true;
}
{
title = "Code Server";
url = "http://10.0.1.3:4444/";
url = "http://${net.hosts.nas.lan}:${toString net.ports.nas.codeServer}/";
icon = "si:vscodium";
allow-insecure = true;
}
@@ -146,7 +147,7 @@ let
}
{
title = "Sonarr";
url = "http://10.0.1.3:8989/";
url = "http://${net.hosts.nas.lan}:${toString net.ports.nas.sonarr}/";
icon = "si:sonarr";
allow-insecure = true;
basic-auth = {
@@ -156,7 +157,7 @@ let
}
{
title = "Radarr";
url = "http://10.0.1.3:7878/";
url = "http://${net.hosts.nas.lan}:${toString net.ports.nas.radarr}/";
icon = "si:radarr";
allow-insecure = true;
basic-auth = {
@@ -166,7 +167,7 @@ let
}
{
title = "Sabnzbd";
url = "http://10.0.1.3:8280/";
url = "http://${net.hosts.nas.lan}:${toString net.ports.nas.sabnzbd}/";
icon = "si:sabnzbd";
allow-insecure = true;
basic-auth = {

View File

@@ -6,6 +6,7 @@
}:
let
cfg = config.${namespace}.services.grimmory;
net = lib.${namespace}.network;
in
{
imports = [
@@ -23,7 +24,7 @@ in
USER_ID = "1000";
GROUP_ID = "1000";
TZ = "UTC";
DATABASE_URL = "jdbc:mariadb://10.0.1.3:3306/grimmory";
DATABASE_URL = "jdbc:mariadb://${net.hosts.nas.lan}:${toString net.ports.nas.mariadb}/grimmory";
DATABASE_USERNAME = "grimmory";
DATABASE_PASSWORD = "Lucifer008!";
};

View File

@@ -8,6 +8,7 @@ with lib;
let
name = "immich";
cfg = config.${namespace}.services.${name};
net = lib.${namespace}.network;
dbPassword = config.sops.secrets."jallen-nas/immich/db-password".path;
immichConfig = lib.${namespace}.mkModule {
@@ -26,7 +27,7 @@ let
environment = {
IMMICH_HOST = lib.mkForce cfg.listenAddress;
IMMICH_TRUSTED_PROXIES = "10.0.1.3";
IMMICH_TRUSTED_PROXIES = net.hosts.nas.lan;
TZ = "America/Chicago";
};

View File

@@ -9,6 +9,7 @@ with lib;
let
name = "nextcloud";
cfg = config.${namespace}.services.${name};
net = lib.${namespace}.network;
nextcloudConfig = lib.${namespace}.mkModule {
inherit config name;
@@ -90,13 +91,13 @@ let
log_type = "file";
default_phone_region = "US";
trusted_proxies = [
"10.0.1.3"
net.hosts.nas.lan
"127.0.0.1"
"::1"
];
trusted_domains = [
"cloud.mjallen.dev"
"10.0.1.3:${toString cfg.port}"
"${net.hosts.nas.lan}:${toString cfg.port}"
];
enabledPreviewProviders = [
"OC\\Preview\\PNG"

View File

@@ -7,6 +7,7 @@
let
name = "onlyoffice";
cfg = config.${namespace}.services.${name};
net = lib.${namespace}.network;
jwtSecretFile = config.sops.secrets."jallen-nas/onlyoffice-key".path;
onlyofficeConfig = lib.${namespace}.mkModule {
@@ -21,7 +22,7 @@ let
hostname = "office.mjallen.dev";
jwtSecretFile = jwtSecretFile;
securityNonceFile = jwtSecretFile;
postgresHost = "10.0.1.3";
postgresHost = net.hosts.nas.lan;
postgresUser = "onlyoffice";
postgresName = "onlyoffice";
};

View File

@@ -8,6 +8,7 @@ with lib;
let
name = "opencloud";
cfg = config.${namespace}.services.${name};
net = lib.${namespace}.network;
opencloudConfig = lib.${namespace}.mkModule {
inherit config name;
@@ -26,8 +27,8 @@ let
PROXY_TLS = "false"; # disable https when behind reverse-proxy
INITIAL_ADMIN_PASSWORD = "BogieDudie1";
OC_DB_TYPE = "postgres";
OC_DB_HOST = "10.0.1.3";
OC_DB_PORT = "5432";
OC_DB_HOST = net.hosts.nas.lan;
OC_DB_PORT = toString net.ports.nas.postgresql;
OC_DB_USER = "opencloud";
OC_DB_NAME = "opencloud";
OC_INSECURE = "true";

View File

@@ -7,6 +7,7 @@
with lib;
let
cfg = config.${namespace}.services.ocis;
net = lib.${namespace}.network;
in
{
options.${namespace}.services.ocis = {
@@ -71,7 +72,7 @@ in
environment = {
OCIS_INSECURE = "true";
PROXY_HTTP_ADDR = "0.0.0.0:9200";
OCIS_URL = "https://10.0.1.3:9988";
OCIS_URL = "https://${net.hosts.nas.lan}:${toString net.ports.nas.nextcloud}";
OCIS_ADMIN_PASSWORD = "BogieDudie1";
OCIS_LDAP_BIND_PASSWORD = "BogieDudie1";
PROXY_OIDC_CLIENT_SECRET = "BogieDudie1";

View File

@@ -6,6 +6,7 @@
}:
let
inherit (lib.${namespace}) mkContainerService mkSopsEnvFile;
net = lib.${namespace}.network;
serverName = "sparky-fitness-server";
frontendName = "sparky-fitness";
@@ -50,15 +51,15 @@ in
SPARKY_FITNESS_LOG_LEVEL = "0";
ALLOW_PRIVATE_NETWORK_CORS = "false";
SPARKY_FITNESS_DB_USER = "sparkyfitness";
SPARKY_FITNESS_DB_HOST = "10.0.1.3";
SPARKY_FITNESS_DB_HOST = net.hosts.nas.lan;
SPARKY_FITNESS_DB_NAME = "sparkyfitness";
SPARKY_FITNESS_APP_DB_USER = "sparkyfitness";
SPARKY_FITNESS_DB_PORT = "5432";
SPARKY_FITNESS_DB_PORT = toString net.ports.nas.postgresql;
SPARKY_FITNESS_FRONTEND_URL = "https://sparky.mjallen.dev";
SPARKY_FITNESS_DISABLE_SIGNUP = "true";
SPARKY_FITNESS_ADMIN_EMAIL = "jalle008@proton.me";
SPARKY_FITNESS_FORCE_EMAIL_LOGIN = "true";
SPARKY_FITNESS_EXTRA_TRUSTED_ORIGINS = "http://10.0.1.3:${toString serverCfg.port}";
SPARKY_FITNESS_EXTRA_TRUSTED_ORIGINS = "http://${net.hosts.nas.lan}:${toString serverCfg.port}";
SPARKY_FITNESS_OIDC_AUTH_ENABLED = "true";
};
})
@@ -69,8 +70,8 @@ in
image = "codewithcj/sparkyfitness";
internalPort = 80;
environment = {
SPARKY_FITNESS_FRONTEND_URL = "http://10.0.1.3:${toString frontendCfg.port}";
SPARKY_FITNESS_SERVER_HOST = "10.0.1.3";
SPARKY_FITNESS_FRONTEND_URL = "http://${net.hosts.nas.lan}:${toString frontendCfg.port}";
SPARKY_FITNESS_SERVER_HOST = net.hosts.nas.lan;
SPARKY_FITNESS_SERVER_PORT = "${toString serverCfg.port}";
};
})

View File

@@ -6,6 +6,7 @@
}:
let
cfg = config.${namespace}.services.termix;
net = lib.${namespace}.network;
inherit (lib.${namespace}) mkSopsEnvFile mkContainerService;
in
{
@@ -40,7 +41,7 @@ in
OIDC_AUTHORIZATION_URL = "https://authentik.mjallen.dev/application/o/authorize/";
OIDC_TOKEN_URL = "https://authentik.mjallen.dev/application/o/token/";
OIDC_FORCE_HTTPS = "true";
GUACD_HOST = "10.0.1.3";
GUACD_HOST = net.hosts.nas.lan;
};
})
];

View File

@@ -6,6 +6,7 @@
}:
let
inherit (lib.${namespace}) mkOpt mkModule;
net = lib.${namespace}.network;
name = "your-spotify";
cfg = config.${namespace}.services.${name};
in
@@ -36,7 +37,7 @@ in
# TODO: move Spotify API keys to sops secrets
SPOTIFY_PUBLIC = "e270589d72a6494680a17d325af8670d";
SPOTIFY_SECRET = "423cb7b69fe8486e89eccd01e0c22924";
MONGO_ENDPOINT = "mongodb://10.0.1.3:27017";
MONGO_ENDPOINT = "mongodb://${net.hosts.nas.lan}:${toString net.ports.nas.mongodb}";
};
};

View File

@@ -1,5 +1,6 @@
_:
{ lib, namespace, ... }:
let
net = lib.${namespace}.network;
defaultNetworkShareOptions = [
"sec=none"
"nofail"
@@ -16,19 +17,19 @@ in
fileSystems = {
# Network shares
"/media/nas/backup" = {
device = "//10.0.1.3/Backup";
device = "//${net.hosts.nas.lan}/Backup";
fsType = "cifs";
options = defaultNetworkShareOptions;
};
"/media/nas/isos" = {
device = "//10.0.1.3/isos";
device = "//${net.hosts.nas.lan}/isos";
fsType = "cifs";
options = defaultNetworkShareOptions;
};
"/media/nas/3d_printer" = {
device = "//10.0.1.3/3d_printer";
device = "//${net.hosts.nas.lan}/3d_printer";
fsType = "cifs";
options = defaultNetworkShareOptions;
};

View File

@@ -1,4 +1,7 @@
{ lib, ... }:
{ lib, namespace, ... }:
let
net = lib.${namespace}.network;
in
{
services.resolved.enable = lib.mkForce false;
services.adguardhome = {
@@ -30,7 +33,7 @@
trusted_proxies = [
"127.0.0.0/8"
"::1/128"
"10.0.1.3"
net.hosts.nas.lan
];
cache_optimistic = true;
};

View File

@@ -7,6 +7,9 @@
namespace,
...
}:
let
net = lib.${namespace}.network;
in
{
imports = [
./adguard.nix
@@ -119,11 +122,11 @@
# ###################################################
network = {
hostName = "pi5";
hostName = net.hosts.pi5.hostname;
ipv4 = {
method = "manual";
address = "10.0.1.2/24";
gateway = "10.0.1.1";
address = net.hosts.pi5.lan4;
gateway = net.hosts.pi5.gateway;
dns = "1.1.1.1";
interface = "end0";
};

View File

@@ -7,6 +7,7 @@
}:
let
inherit (lib.${namespace}) enabled disabled;
net = lib.${namespace}.network;
in
{
imports = [
@@ -122,11 +123,11 @@ in
# ###################################################
network = {
hostName = "jallen-nas";
hostName = net.hosts.nas.hostname;
ipv4 = {
address = "10.0.1.3";
address = net.hosts.nas.lan;
method = "manual";
gateway = "10.0.1.1";
gateway = net.hosts.nas.gateway;
dns = "1.1.1.1";
interface = "enp197s0";
};
@@ -215,6 +216,7 @@ in
samba = {
enable = true;
# Allow the LAN /24 subnet (strip the last octet from the NAS LAN IP for the prefix)
hostsAllow = "10.0.1. 127.0.0.1 localhost";
forceGroup = "jallen-nas";
forceUser = "nix-apps";

View File

@@ -1,4 +1,7 @@
{ namespace, ... }:
{ lib, namespace, ... }:
let
net = lib.${namespace}.network;
in
{
imports = [
./boot.nix
@@ -31,12 +34,12 @@
};
network = {
hostName = "nuc-nixos";
hostName = net.hosts.nuc.hostname;
ipv4 = {
method = "manual";
address = "10.0.1.4/24";
gateway = "10.0.1.1";
dns = "10.0.1.1";
address = net.hosts.nuc.lan4;
gateway = net.hosts.nuc.gateway;
dns = net.hosts.router.lan;
interface = "enp2s0";
};
firewall = {