diff --git a/modules/config/instances/config/acme.nix b/modules/config/instances/config/acme.nix index ca82ad7..23c15e1 100755 --- a/modules/config/instances/config/acme.nix +++ b/modules/config/instances/config/acme.nix @@ -2,7 +2,6 @@ let inherit (moduleFunctions.instancesFunctions) sslPath - sopsPath secretPath ; @@ -12,13 +11,16 @@ in { label = label; name = name; - paths = { - path0 = sslPath; - }; - secretPaths = { - path0 = secretPath; - }; - sops = { - path0 = "${sopsPath}/${name}"; + interfaces = { + interface0 = { + paths = { + mntPaths = { + path0 = sslPath; + }; + secretPaths = { + path0 = "${secretPath}/${name}"; + }; + }; + }; }; } diff --git a/modules/config/instances/config/audiobookshelf.nix b/modules/config/instances/config/audiobookshelf.nix index 71d11d3..3bb5b2b 100755 --- a/modules/config/instances/config/audiobookshelf.nix +++ b/modules/config/instances/config/audiobookshelf.nix @@ -2,37 +2,49 @@ let inherit (moduleFunctions.instancesFunctions) domain0 - servicePath + mntPath sslPath - sopsPath + secretPath ; - audiobookshelfLabel = "Audiobookshelf"; - audiobookshelfName = "audiobookshelf"; - audiobookshelfSubdomain = "books"; - audiobookshelfDomain = "${audiobookshelfSubdomain}.${domain0}"; + label = "Audiobookshelf"; + name = "audiobookshelf"; + subdomain = "books"; in { - label = audiobookshelfLabel; - name = audiobookshelfName; + label = label; + name = name; short = "Books"; - sops = { - path0 = "${sopsPath}/${audiobookshelfName}"; - }; - domains = { - url0 = audiobookshelfDomain; - }; - subdomain = audiobookshelfSubdomain; tags = [ - + name + "audiobooks" + "reading" ]; - paths = { - path0 = "${servicePath}/${audiobookshelfLabel}"; - }; ports = { port0 = 8000; }; - ssl = { - cert = "${sslPath}/${audiobookshelfSubdomain}.${domain0}/fullchain.pem"; - key = "${sslPath}/${audiobookshelfSubdomain}.${domain0}/key.pem"; + interfaces = { + interface0 = + let + domain = "${subdomain}.${domain0}"; + secret = "${secretPath}/${name}"; + ssl = "${sslPath}/${domain}"; + in + { + domain = domain; + subdomain = subdomain; + paths = { + mntPaths = { + path0 = "${mntPath}/${name}"; + }; + secretPaths = { + path0 = secret; + }; + }; + ssl = { + path = ssl; + cert = "${ssl}/fullchain.pem"; + key = "${ssl}/key.pem"; + }; + }; }; } diff --git a/modules/config/instances/config/caddy.nix b/modules/config/instances/config/caddy.nix index c46e6af..e99a9a5 100755 --- a/modules/config/instances/config/caddy.nix +++ b/modules/config/instances/config/caddy.nix @@ -1,7 +1,7 @@ { moduleFunctions }: let inherit (moduleFunctions.instancesFunctions) - sopsPath + dummy ; caddyLabel = "Caddy"; @@ -10,9 +10,7 @@ in { label = caddyLabel; name = caddyName; - sops = { - path0 = "${sopsPath}/${caddyName}"; - }; + short = dummy; ports = { port0 = 80; port1 = 443; diff --git a/modules/config/instances/config/comfyui.nix b/modules/config/instances/config/comfyui.nix index d5406b5..81fef7c 100755 --- a/modules/config/instances/config/comfyui.nix +++ b/modules/config/instances/config/comfyui.nix @@ -8,8 +8,6 @@ let ; label = "ComfyUI"; name = "comfyui"; - domain = "${name}.${domain0}"; - ssl = "${sslPath}/${domain}"; in { label = label; @@ -20,24 +18,33 @@ in "comfy" "ui" ]; - domains = { - url0 = domain; - }; ports = { port0 = 8188; }; - varPaths = { - path0 = "${varPath}/${name}"; - }; - mntPaths = { - path0 = "${mntPath}/${name}"; - }; - secretPaths = { - path0 = "/run/secrets"; - }; - ssl = { - path = ssl; - cert = "${ssl}/fullchain.pem"; - key = "${ssl}/key.pem"; + interfaces = { + interface0 = + let + domain = "${name}.${domain0}"; + ssl = "${sslPath}/${domain}"; + in + { + domain = domain; + paths = { + varPaths = { + path0 = "${varPath}/${name}"; + }; + mntPaths = { + path0 = "${mntPath}/${name}"; + }; + secretPaths = { + path0 = "/run/secrets"; + }; + }; + ssl = { + path = ssl; + cert = "${ssl}/fullchain.pem"; + key = "${ssl}/key.pem"; + }; + }; }; } diff --git a/modules/config/instances/config/firefly-iii.nix b/modules/config/instances/config/firefly-iii.nix index 5c59318..0188de4 100755 --- a/modules/config/instances/config/firefly-iii.nix +++ b/modules/config/instances/config/firefly-iii.nix @@ -35,12 +35,12 @@ in { microvm = { id = "vm-${name}"; - mac = "02:00:00:00:54:04"; + mac = "02:00:00:00:60:70"; idUser = "vmuser-firefly"; - macUser = "02:00:00:00:00:04"; - ip = "192.168.50.114"; + macUser = "02:00:00:00:00:70"; + ip = "192.168.50.70"; gate = "192.168.50.1"; - ssh = 2204; + ssh = 2570; }; email = "noreply@${domain0}"; domain = domain; diff --git a/modules/config/instances/config/glance.nix b/modules/config/instances/config/glance.nix index 1bf45de..8a87896 100755 --- a/modules/config/instances/config/glance.nix +++ b/modules/config/instances/config/glance.nix @@ -4,42 +4,50 @@ let domain0 servicePath sslPath - sopsPath + secretPath ; label = "Glance"; name = "glance"; - subdomain = "dashboard"; - domain = "${subdomain}.${domain0}"; in { label = label; name = name; short = label; - email = { - address0 = "noreply@${domain0}"; - }; - sops = { - path0 = "${sopsPath}/${name}"; - }; - domains = { - url0 = domain; - }; - subdomain = subdomain; tags = [ "glance" "dashboard" "weather" "podcasts" ]; - paths = { - path0 = "${servicePath}/${label}"; - }; ports = { port0 = 3434; }; - ssl = { - cert = "${sslPath}/${subdomain}.${domain0}/fullchain.pem"; - key = "${sslPath}/${subdomain}.${domain0}/key.pem"; + interfaces = { + interface0 = + let + subdomain = "dashboard"; + domain = "${subdomain}.${domain0}"; + secret = "${secretPath}/${name}"; + ssl = "${sslPath}/${domain}"; + in + { + domain = domain; + subdomain = subdomain; + email = "noreply@${domain0}"; + paths = { + mntPaths = { + path0 = "${servicePath}/${label}"; + }; + secretPath = { + path0 = secret; + }; + }; + ssl = { + path = ssl; + cert = "${ssl}/fullchain.pem"; + key = "${ssl}/key.pem"; + }; + }; }; } diff --git a/modules/config/instances/config/matrix.nix b/modules/config/instances/config/matrix.nix deleted file mode 100755 index aa26cce..0000000 --- a/modules/config/instances/config/matrix.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ moduleFunctions }: -let - inherit (moduleFunctions.instancesFunctions) - servicePath - sopsPath - ; - - label = "Matrix"; - name = "matrix"; -in -{ - label = label; - name = name; - short = label; - sops = { - path0 = "${sopsPath}/${name}"; - }; - subdomain = name; - tags = [ - - ]; - paths = { - path0 = "${servicePath}/${label}"; - path1 = ""; - path2 = ""; - }; -} diff --git a/modules/config/instances/config/opencloud.nix b/modules/config/instances/config/opencloud.nix index f4b5db0..bd68708 100755 --- a/modules/config/instances/config/opencloud.nix +++ b/modules/config/instances/config/opencloud.nix @@ -35,12 +35,12 @@ in subdomain = short; microvm = { id = "vm-${short}"; - mac = "02:00:00:00:56:09"; + mac = "02:00:00:00:66:76"; idUser = "vmuser-${short}"; - macUser = "02:00:00:00:00:09"; - ip = "192.168.50.119"; + macUser = "02:00:00:00:00:76"; + ip = "192.168.50.76"; gate = "192.168.50.1"; - ssh = 2209; + ssh = 2576; }; ssl = { path = ssl; diff --git a/modules/config/instances/config/owncast.nix b/modules/config/instances/config/owncast.nix deleted file mode 100755 index 41d692d..0000000 --- a/modules/config/instances/config/owncast.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ moduleFunctions }: -let - inherit (moduleFunctions.instancesFunctions) - domain1 - servicePath - sslPath - sopsPath - ; - - label = "Owncast"; - name = "owncast"; - subdomain = "stream"; - domain = "${subdomain}.${domain1}"; -in -{ - label = label; - name = name; - short = "Cast"; - sops = { - path0 = "${sopsPath}/${name}"; - }; - domains = { - url0 = domain; - }; - subdomain = subdomain; - tags = [ - - ]; - paths = { - path0 = "${servicePath}/${label}"; - path1 = "/mnt/media/storage/${name}"; - }; - ports = { - port0 = 9454; - port1 = 1935; - }; - ssl = { - cert = "${sslPath}/${subdomain}.${domain1}/fullchain.pem"; - key = "${sslPath}/${subdomain}.${domain1}/key.pem"; - }; -} diff --git a/modules/config/instances/config/peertube.nix b/modules/config/instances/config/peertube.nix index 08e404a..869e73b 100755 --- a/modules/config/instances/config/peertube.nix +++ b/modules/config/instances/config/peertube.nix @@ -2,36 +2,24 @@ let inherit (moduleFunctions.instancesFunctions) domain1 - servicePath + mntPath sslPath - sopsPath ; label = "PeerTube"; name = "peertube"; - subdomain = "video"; - domain = "${subdomain}.${domain1}"; in { label = label; name = name; short = "Peer"; - email = { - address0 = "noreply@${domain1}"; - }; - sops = { - path0 = "${sopsPath}/${name}"; - }; - domains = { - url0 = domain; - }; - subdomain = subdomain; + email = "noreply@${domain1}"; tags = [ - + name + "video" + "peer" + "fediverse" ]; - paths = { - path0 = "${servicePath}/${label}"; - }; ports = { port0 = 9000; # HTTP port1 = 1935; @@ -39,8 +27,30 @@ in port3 = 5432; port4 = 52800; }; - ssl = { - cert = "${sslPath}/${subdomain}.${domain1}/fullchain.pem"; - key = "${sslPath}/${subdomain}.${domain1}/key.pem"; + interfaces = { + interface0 = + let + subdomain = "video"; + domain = "${subdomain}.${domain1}"; + secret = "${sslPath}/${name}"; + ssl = "${sslPath}/${domain}"; + in + { + domain = domain; + subdomain = subdomain; + paths = { + mntPaths = { + path0 = "${mntPath}/${name}"; + }; + secretPath = { + path0 = secret; + }; + }; + ssl = { + path = ssl; + cert = "${ssl}/fullchain.pem"; + key = "${ssl}/key.pem"; + }; + }; }; } diff --git a/modules/config/instances/config/photoprism.nix b/modules/config/instances/config/photoprism.nix index 11ac3af..d89c52a 100644 --- a/modules/config/instances/config/photoprism.nix +++ b/modules/config/instances/config/photoprism.nix @@ -35,12 +35,12 @@ in subdomain = short; microvm = { id = "vm-${short}"; - mac = "02:00:00:00:56:11"; + mac = "02:00:00:00:69:79"; idUser = "vmuser-${short}"; - macUser = "02:00:00:00:00:11"; - ip = "192.168.50.121"; + macUser = "02:00:00:00:00:79"; + ip = "192.168.50.79"; gate = "192.168.50.1"; - ssh = 2211; + ssh = 2579; }; ssl = { path = ssl; diff --git a/modules/config/instances/config/searx.nix b/modules/config/instances/config/searx.nix index 50579ce..e03b748 100755 --- a/modules/config/instances/config/searx.nix +++ b/modules/config/instances/config/searx.nix @@ -2,43 +2,51 @@ let inherit (moduleFunctions.instancesFunctions) domain0 - servicePath + mntPath + secretPath sslPath - sopsPath ; label = "SearXNG"; name = "searx"; - subdomain = "search"; - domain = "${subdomain}.${domain0}"; in { label = label; name = name; short = "Sear"; - email = { - address0 = "noreply@${domain0}"; - }; - sops = { - path0 = "${sopsPath}/${name}"; - }; - domains = { - url0 = domain; - }; - subdomain = subdomain; tags = [ "search" "sear" "searx" ]; - paths = { - path0 = "${servicePath}/${label}"; - }; ports = { port0 = 8888; }; - ssl = { - cert = "${sslPath}/${subdomain}.${domain0}/fullchain.pem"; - key = "${sslPath}/${subdomain}.${domain0}/key.pem"; + interfaces = { + interface0 = + let + subdomain = "search"; + domain = "${subdomain}.${domain0}"; + ssl = "${sslPath}/${domain}"; + secret = "${secretPath}/${name}"; + in + { + domain = domain; + email = "noreply@${domain0}"; + subdomain = subdomain; + paths = { + mntPaths = { + path0 = "${mntPath}/${name}"; + }; + secretPaths = { + path0 = secret; + }; + }; + ssl = { + path = ssl; + cert = "${ssl}/fullchain.pem"; + key = "${ssl}/key.pem"; + }; + }; }; } diff --git a/modules/config/instances/config/syncthing.nix b/modules/config/instances/config/syncthing.nix index 105a86c..36ef5cf 100755 --- a/modules/config/instances/config/syncthing.nix +++ b/modules/config/instances/config/syncthing.nix @@ -38,12 +38,12 @@ in subdomain = name; microvm = { id = "vm-${id}"; - mac = "02:00:00:00:56:10"; + mac = "02:00:00:00:75:85"; idUser = "vmuser-${id}"; - macUser = "02:00:00:00:00:10"; - ip = "192.168.50.120"; + macUser = "02:00:00:00:00:85"; + ip = "192.168.50.85"; gate = "192.168.50.1"; - ssh = 2210; + ssh = 2585; }; ssl = { cert = "${ssl}/fullchain.pem"; diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index 721d117..bfb8db7 100755 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -86,6 +86,11 @@ in nas sambaEris ; + inherit (modules.guests.firefly-iii) fireflyNick; + inherit (modules.guests.opencloud) opencloudNick; + inherit (modules.guests.photoprism) photoprismNick; + inherit (modules.guests.vaultwarden) vaultwardenNick; + inherit (modules.guests.syncthing) syncthingNick; }; }; diff --git a/modules/nixos/homelab/acme/default.nix b/modules/nixos/homelab/acme/default.nix index 791b61e..9754421 100755 --- a/modules/nixos/homelab/acme/default.nix +++ b/modules/nixos/homelab/acme/default.nix @@ -6,7 +6,7 @@ let inherit (flake.config.people) user0; inherit (flake.config.people.users.${user0}) email; inherit (flake.config.services) instances; - service = instances.acme; + serviceCfg = instances.acme; dns0 = instances.web.dns.provider0; dns1 = instances.web.dns.provider1; in @@ -29,7 +29,7 @@ in "pass" ]; sopsPath = secret: dns: { - path = "/var/lib/secrets/${instances.acme.name}/${dns}-${secret}"; + path = "/var/lib/secrets/${serviceCfg.name}/${dns}-${secret}"; owner = "root"; mode = "600"; }; @@ -50,7 +50,7 @@ in systemd = { tmpfiles.rules = [ - "Z ${service.sops.path0} 755 ${service.name} ${service.name} -" + "Z ${serviceCfg.secretPaths.path0} 755 ${serviceCfg.name} ${serviceCfg.name} -" ]; }; } diff --git a/modules/nixos/homelab/caddy/default.nix b/modules/nixos/homelab/caddy/default.nix index 82e08c6..2298b80 100755 --- a/modules/nixos/homelab/caddy/default.nix +++ b/modules/nixos/homelab/caddy/default.nix @@ -1,7 +1,7 @@ { flake, ... }: let inherit (flake.config.services) instances; - service = instances.caddy; + serviceCfg = instances.caddy; importList = let @@ -26,8 +26,8 @@ in networking = { firewall = { allowedTCPPorts = [ - service.ports.port0 # 80 - service.ports.port1 # 443 + serviceCfg.ports.port0 # 80 + serviceCfg.ports.port1 # 443 ]; }; }; diff --git a/modules/nixos/homelab/guests/firefly-iii/default.nix b/modules/nixos/homelab/guests/firefly-iii/default.nix index 1fc5d4c..f8af911 100755 --- a/modules/nixos/homelab/guests/firefly-iii/default.nix +++ b/modules/nixos/homelab/guests/firefly-iii/default.nix @@ -6,12 +6,15 @@ ... }: let + inherit (labHelpers) guestPath; inherit (import ./config { inherit config flake pkgs; }) fireflyVM; inherit (flake.config.people) user0; inherit (flake.config.people.users.${user0}) email; inherit (flake.config.services.instances) firefly-iii; interface0Cfg = firefly-iii.interfaces.interface0; +in +{ fireflyNick = fireflyVM { user = user0; ip = interface0Cfg.microvm.ip; @@ -19,7 +22,7 @@ let userMac = interface0Cfg.microvm.macUser; ssh = interface0Cfg.microvm.ssh0; host = interface0Cfg.domain; - mnt = ""; + mnt = guestPath user0; owner = email.address2; }; @@ -44,7 +47,4 @@ let # host = ""; # owner = ""; # }; - -in -fireflyNick -# // fireflyStacie // fireflyGarnet +} diff --git a/modules/nixos/homelab/guests/forgejo/default.nix b/modules/nixos/homelab/guests/forgejo/default.nix index 9d92aaf..9a1f68f 100644 --- a/modules/nixos/homelab/guests/forgejo/default.nix +++ b/modules/nixos/homelab/guests/forgejo/default.nix @@ -5,21 +5,21 @@ ... }: let + inherit (labHelpers) mntPath; inherit (import ./config { inherit flake pkgs; }) forgejoVM; inherit (flake.config.people) user0; inherit (flake.config.services) instances; interface0Cfg = instances.forgejo.interfaces.interface0; - +in +{ forgejoNick = forgejoVM { user = user0; ip = interface0Cfg.microvm.ip; mac = interface0Cfg.microvm.mac; userMac = interface0Cfg.microvm.macUser; ssh = interface0Cfg.microvm.ssh; - mnt = ""; + mnt = mntPath; host = interface0Cfg.domain; }; -in -forgejoNick -# // forgejoStacie // forgejoGarnet +} diff --git a/modules/nixos/homelab/guests/helpers.nix b/modules/nixos/homelab/guests/helpers.nix index 34b14d3..14af7d4 100644 --- a/modules/nixos/homelab/guests/helpers.nix +++ b/modules/nixos/homelab/guests/helpers.nix @@ -1,5 +1,6 @@ { labHelpers = { + mntPath = "/mnt/storage"; guestPath = user: "/mnt/storage/users/${user}/guests"; docsPath = user: "/mnt/storage/users/${user}/home/docs"; mediaPath = user: "/mnt/storage/users/${user}/home/media"; diff --git a/modules/nixos/homelab/guests/jellyfin/default.nix b/modules/nixos/homelab/guests/jellyfin/default.nix index 8ce516f..8b70057 100644 --- a/modules/nixos/homelab/guests/jellyfin/default.nix +++ b/modules/nixos/homelab/guests/jellyfin/default.nix @@ -5,21 +5,22 @@ ... }: let + inherit (labHelpers) mntPath; inherit (import ./config { inherit flake pkgs; }) jellyfinVM; inherit (flake.config.people) user0; inherit (flake.config.services) instances; interface0Cfg = instances.jellyfin.interfaces.interface0; +in +{ jellyfinNick = jellyfinVM { user = user0; ip = interface0Cfg.microvm.ip; mac = interface0Cfg.microvm.mac; userMac = interface0Cfg.microvm.macUser; ssh = interface0Cfg.microvm.ssh; - mnt = ""; + mnt = mntPath; host = interface0Cfg.domain; }; -in -jellyfinNick -# // forgejoStacie // forgejoGarnet +} diff --git a/modules/nixos/homelab/guests/mastodon/default.nix b/modules/nixos/homelab/guests/mastodon/default.nix index 215307f..7c56b0e 100644 --- a/modules/nixos/homelab/guests/mastodon/default.nix +++ b/modules/nixos/homelab/guests/mastodon/default.nix @@ -5,21 +5,22 @@ ... }: let + inherit (labHelpers) mntPath; inherit (import ./config { inherit flake pkgs; }) mastodonVM; inherit (flake.config.people) user0; inherit (flake.config.services) instances; interface0Cfg = instances.mastodon.interfaces.interface0; +in +{ mastodonNick = mastodonVM { user = user0; ip = interface0Cfg.microvm.ip; mac = interface0Cfg.microvm.mac; userMac = interface0Cfg.microvm.macUser; ssh = interface0Cfg.microvm.ssh; - mnt = ""; + mnt = mntPath; host = interface0Cfg.domain; }; -in -mastodonNick -# // mastodonStacie // mastodonGarnet +} diff --git a/modules/nixos/homelab/guests/minecraft/default.nix b/modules/nixos/homelab/guests/minecraft/default.nix index e685b92..472c874 100755 --- a/modules/nixos/homelab/guests/minecraft/default.nix +++ b/modules/nixos/homelab/guests/minecraft/default.nix @@ -5,10 +5,13 @@ ... }: let + inherit (labHelpers) mntPath; inherit (import ./config { inherit flake pkgs; }) minecraftVM; inherit (flake.config.services) instances; inherit (flake.config.people) user0; +in +{ minecraftNick01 = let interfaceCfg = instances.minecraft.interfaces.interface0; @@ -20,7 +23,7 @@ let userMac = interfaceCfg.microvm.macUser; ssh = interfaceCfg.microvm.ssh; port = interfaceCfg.microvm.port; - mnt = ""; + mnt = mntPath; worldNumber = "01"; config = { allow-flight = false; @@ -67,7 +70,7 @@ let userMac = interfaceCfg.microvm.macUser; ssh = interfaceCfg.microvm.ssh; port = interfaceCfg.microvm.port; - mnt = ""; + mnt = mntPath; worldNumber = "02"; config = { allow-flight = false; @@ -101,5 +104,4 @@ let }; }; -in -minecraftNick01 // minecraftNick02 +} diff --git a/modules/nixos/homelab/guests/opencloud/default.nix b/modules/nixos/homelab/guests/opencloud/default.nix index 3d58e20..4139333 100755 --- a/modules/nixos/homelab/guests/opencloud/default.nix +++ b/modules/nixos/homelab/guests/opencloud/default.nix @@ -5,22 +5,36 @@ ... }: let + inherit (labHelpers) mntPath guestPath; inherit (import ./config { inherit flake pkgs; }) opencloudVM; inherit (flake.config.people) user0; inherit (flake.config.services.instances) opencloud; interface0Cfg = opencloud.interfaces.interface0; + interface1Cfg = opencloud.interfaces.interface1; +in +{ opencloudNick = opencloudVM { user = user0; ip = interface0Cfg.microvm.ip; mac = interface0Cfg.microvm.mac; userMac = interface0Cfg.microvm.macUser; ssh = interface0Cfg.microvm.ssh; - mnt = ""; + mnt = guestPath user0; host = interface0Cfg.domain; }; + opencloudProject = opencloudVM { + user = user0; + ip = interface1Cfg.microvm.ip; + mac = interface1Cfg.microvm.mac; + userMac = interface1Cfg.microvm.macUser; + ssh = interface1Cfg.microvm.ssh; + mnt = mntPath; + host = "${interface0Cfg.subdomain}.${flake.inputs.linkpage.secrets.domains.projectsite}"; + }; + # opencloudStacie = opencloudVM { # user = "stacie"; # ip = ipAddress id1; @@ -40,7 +54,4 @@ let # mnt = guestPath "garnet"; # host = ""; # }; - -in -opencloudNick -# // opencloudStacie // opencloudGarnet +} diff --git a/modules/nixos/homelab/guests/photoprism/config/default.nix b/modules/nixos/homelab/guests/photoprism/config/default.nix index 90b349c..5cd39d0 100755 --- a/modules/nixos/homelab/guests/photoprism/config/default.nix +++ b/modules/nixos/homelab/guests/photoprism/config/default.nix @@ -38,7 +38,6 @@ in passwordFile = "/run/secrets/${user}-pass"; storagePath = "/var/lib/${serviceCfg.name}"; originalsPath = "/var/lib/${serviceCfg.name}-media"; - importPath = "photos"; address = "0.0.0.0"; }; openssh = { diff --git a/modules/nixos/homelab/guests/photoprism/default.nix b/modules/nixos/homelab/guests/photoprism/default.nix index 6eed982..2557200 100755 --- a/modules/nixos/homelab/guests/photoprism/default.nix +++ b/modules/nixos/homelab/guests/photoprism/default.nix @@ -5,19 +5,22 @@ ... }: let + inherit (labHelpers) guestPath mediaPath; inherit (import ./config { inherit flake lib; }) photoprismVM; inherit (flake.config.services.instances) photoprism; inherit (flake.config.people) user0; interface0Cfg = photoprism.interfaces.interface0; +in +{ photoprismNick = photoprismVM { user = user0; ip = interface0Cfg.microvm.ip; mac = interface0Cfg.microvm.mac; userMac = interface0Cfg.microvm.macUser; ssh = interface0Cfg.microvm.ssh; - mnt = ""; - data = ""; + mnt = guestPath user0; + data = mediaPath user0; host = interface0Cfg.domain; }; @@ -41,6 +44,4 @@ let # data = mediaPath "stacie"; # }; -in -photoprismNick -# // photoprismStacie // photoprismGarnet +} diff --git a/modules/nixos/homelab/guests/qbittorrent/default.nix b/modules/nixos/homelab/guests/qbittorrent/default.nix index 5b8725a..74ee376 100644 --- a/modules/nixos/homelab/guests/qbittorrent/default.nix +++ b/modules/nixos/homelab/guests/qbittorrent/default.nix @@ -5,19 +5,22 @@ ... }: let + inherit (labHelpers) mntPath; inherit (import ./config { inherit flake pkgs; }) qbittorrentVM; inherit (flake.config.people) user0; inherit (flake.config.services) instances; interface0Cfg = instances.qbittorrent.interfaces.interface0; - qbittorrentNick = qbittorrentVM { +in +{ + qbittorrentCeres = qbittorrentVM { user = user0; ip = interface0Cfg.microvm.ip; mac = interface0Cfg.microvm.mac; userMac = interface0Cfg.microvm.macUser; ssh = interface0Cfg.microvm.ssh; - mnt = ""; + mnt = mntPath; host = interface0Cfg.domain; port = 51820; endpoint = "185.111.110.1"; @@ -25,6 +28,4 @@ let dns = [ "10.2.0.1" ]; key = "QPfiwJQmt5VLEOh1ufLbi1lj6LUnwQY0tgDSh3pWx1k="; }; -in -qbittorrentNick -# // qbittorrentStacie // qbittorrentGarnet +} diff --git a/modules/nixos/homelab/guests/syncthing/default.nix b/modules/nixos/homelab/guests/syncthing/default.nix index 4bb78b6..1c2191d 100755 --- a/modules/nixos/homelab/guests/syncthing/default.nix +++ b/modules/nixos/homelab/guests/syncthing/default.nix @@ -4,6 +4,12 @@ ... }: let + inherit (labHelpers) + docsPath + guestPath + mediaPath + miscPath + ; inherit (import ./config { inherit flake; }) syncthingVM; inherit (flake.config.services) instances; inherit (flake.config.people) user0; @@ -52,19 +58,19 @@ let { mountPoint = "/var/lib/${serviceCfg.name}/docs"; proto = "virtiofs"; - source = ""; + source = docsPath user; tag = "${serviceCfg.name}_${user}_docs"; } { mountPoint = "/var/lib/${serviceCfg.name}/media"; proto = "virtiofs"; - source = ""; + source = mediaPath user; tag = "${serviceCfg.name}_${user}_media"; } { mountPoint = "/var/lib/${serviceCfg.name}/misc"; proto = "virtiofs"; - source = ""; + source = miscPath user; tag = "${serviceCfg.name}_${user}_misc"; } ]; @@ -75,6 +81,8 @@ let "d /var/lib/${serviceCfg.name}/misc 0755 ${serviceCfg.name} ${serviceCfg.name} -" ]; +in +{ syncthingNick = let phoneID = "OALKHLZ-OODUWVX-PAC2LI7-UMZMSZO-FELLRCD-RS4DHJS-PVA5YQK-WTFXXQI"; @@ -85,7 +93,7 @@ let mac = interface0Cfg.microvm.mac; userMac = interface0Cfg.microvm.macUser; ssh = interface0Cfg.microvm.ssh; - mnt = ""; + mnt = guestPath user0; host = interface0Cfg.domain; folders = foldersHelper user0; devices = devicesHelper user0 phoneID "Phone" "192.168.50.8"; @@ -112,7 +120,4 @@ let # syncID = ""; # deviceIP = ""; # }; - -in -syncthingNick -# // syncthingStacie // syncthingGarnet +} diff --git a/modules/nixos/homelab/guests/vaultwarden/default.nix b/modules/nixos/homelab/guests/vaultwarden/default.nix index 56b02db..191ccbb 100755 --- a/modules/nixos/homelab/guests/vaultwarden/default.nix +++ b/modules/nixos/homelab/guests/vaultwarden/default.nix @@ -4,19 +4,22 @@ ... }: let + inherit (labHelpers) guestPath; inherit (import ./config { inherit flake; }) vaultwardenVM; inherit (flake.config.people) user0; inherit (flake.config.services.instances) vaultwarden; interface0Cfg = vaultwarden.interfaces.interface0; +in +{ vaultwardenNick = vaultwardenVM { user = user0; ip = interface0Cfg.microvm.ip; mac = interface0Cfg.microvm.mac; userMac = interface0Cfg.microvm.macUser; ssh = interface0Cfg.microvm.ssh; - mnt = ""; + mnt = guestPath user0; host = interface0Cfg.domain; }; @@ -40,6 +43,4 @@ let # host = ""; # }; -in -vaultwardenNick -# // vaultwardenStacie // vaultwardenGarnet +} diff --git a/modules/nixos/homelab/guests/website/default.nix b/modules/nixos/homelab/guests/website/default.nix index 3a7076f..77571b0 100644 --- a/modules/nixos/homelab/guests/website/default.nix +++ b/modules/nixos/homelab/guests/website/default.nix @@ -8,7 +8,9 @@ let inherit (import ./config { inherit flake pkgs; }) websiteVM; inherit (flake.config.services) instances; - websiteNick = +in +{ + websiteUpRoot = let websitePkg = flake.self.packages.${pkgs.system}.website; interfaceCfg = instances.website.interfaces.interface0; @@ -34,5 +36,4 @@ let package = websitePkg; }; -in -websiteNick // websiteProject +} diff --git a/modules/nixos/homelab/guests/zookeeper/default.nix b/modules/nixos/homelab/guests/zookeeper/default.nix index c26ccfe..e97234d 100644 --- a/modules/nixos/homelab/guests/zookeeper/default.nix +++ b/modules/nixos/homelab/guests/zookeeper/default.nix @@ -9,7 +9,9 @@ let inherit (flake.config.services) instances; interfaceCfg = instances.zookeeper.interfaces.interface0; - zookeeperNick = +in +{ + zookeeperBot = let appPackage = flake.self.packages.${pkgs.system}.zookeeper; in @@ -21,5 +23,4 @@ let package = appPackage; }; -in -zookeeperNick +} diff --git a/modules/nixos/homelab/restic/default.nix b/modules/nixos/homelab/restic/default.nix index 9993783..cbdf8fa 100755 --- a/modules/nixos/homelab/restic/default.nix +++ b/modules/nixos/homelab/restic/default.nix @@ -24,20 +24,18 @@ in }; paths = let - inst = instance: instances.${instance}.mntPaths.path0; + inst = instance: interface: instances.${instance}.interfaces.${interface}.paths.mntPaths.path0; in [ "/home/${user0}/.ssh" - (inst "firefly-iii") - (inst "forgejo") - (inst "mastodon") - (inst "opencloud1") - (inst "minecraft0") - (inst "minecraft1") - (inst "vaultwarden") - ((inst "jellyfin") + "/cache") - ((inst "jellyfin") + "/data") - ((inst "jellyfin") + "/media/music") + (inst "forgejo" "interface0") + (inst "mastodon" "interface0") + (inst "opencloud" "interface1") + (inst "minecraft" "interface0") + (inst "minecraft" "interface1") + ((inst "jellyfin" "interface0") + "/cache") + ((inst "jellyfin" "interface0") + "/data") + ((inst "jellyfin" "interface0") + "/media/music") ]; }; }; diff --git a/modules/nixos/server/default.nix b/modules/nixos/server/default.nix deleted file mode 100755 index a779bca..0000000 --- a/modules/nixos/server/default.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ - flake, - config, - pkgs, - lib, - ... -}: -let - serverHelpers = { - ipAddress = ip: "192.168.50.${ip}"; - mntPath = "/mnt/storage"; - minecraft = { - id0 = 40; - id1 = 41; - id2 = 42; - ssh0 = 2440; - ssh1 = 2441; - ssh2 = 2442; - }; - }; - - minecraft = import ./guests/firefly-iii { inherit serverHelpers; }; - -in -{ - imports = [ - minecraft - ]; -} diff --git a/modules/nixos/services/postgresql/default.nix b/modules/nixos/services/postgresql/default.nix deleted file mode 100755 index da65bd2..0000000 --- a/modules/nixos/services/postgresql/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -let - importList = - let - content = builtins.readDir ./.; - dirContent = builtins.filter (n: content.${n} == "directory") (builtins.attrNames content); - in - map (name: ./. + "/${name}") dirContent; -in -{ - imports = importList; -} diff --git a/modules/nixos/services/postgresql/postgresCeres/default.nix b/modules/nixos/services/postgresql/postgresCeres/default.nix deleted file mode 100755 index 5b64182..0000000 --- a/modules/nixos/services/postgresql/postgresCeres/default.nix +++ /dev/null @@ -1,84 +0,0 @@ -{ - flake, - lib, - pkgs, - ... -}: -let - inherit (flake.config.machines.devices) ceres; - inherit (flake.config.services) instances; - - service = instances.postgresql; - # backupPath = "${instances.syncthing.paths.path1}/${service.name}"; -in -{ - services = { - postgresqlBackup = { - enable = true; - # location = backupPath; - # compression = "zstd"; - startAt = "*-*-* 07:00:00"; - databases = [ - instances.mastodon.name - instances.firefly-iii.name - ]; - }; - postgresql = { - enable = true; - }; - }; - networking = { - firewall = { - allowedTCPPorts = [ - service.ports.port0 - ]; - }; - }; - - fileSystems."/var/lib/postgresql" = { - device = service.paths.path0; - fsType = "none"; - options = [ - "bind" - ]; - depends = [ - ceres.storage0.mount - ]; - }; - - users.users.${service.name}.extraGroups = [ - instances.mastodon.name - instances.forgejo.name - instances.syncthing.name - ]; - - systemd.services.sync-postgres-backups = { - description = "Sync PostgreSQL backups to Syncthing"; - after = [ - "postgresqlBackup-firefly-iii.service" - "postgresqlBackup-mastodon.service" - ]; - serviceConfig = { - Type = "oneshot"; - User = instances.syncthing.name; - Group = instances.syncthing.name; - }; - script = '' - ${pkgs.rsync}/bin/rsync -av --delete \ - /var/backup/postgresql/ \ - ${instances.syncthing.paths.path1}/${service.name}/ - - ${pkgs.rsync}/bin/rsync -av --delete \ - /var/lib/${instances.firefly-iii.name}/storage/ \ - ${instances.syncthing.paths.path1}/${service.name}/firefly-iii-storage/ - ''; - }; - - systemd.timers.sync-postgres-backups = { - wantedBy = [ "timers.target" ]; - timerConfig = { - OnCalendar = "*-*-* 22:10:00"; # 10 mins after backup - Persistent = true; - }; - }; -} diff --git a/modules/nixos/services/postgresql/postgresEris/default.nix b/modules/nixos/services/postgresql/postgresEris/default.nix deleted file mode 100755 index 892ca14..0000000 --- a/modules/nixos/services/postgresql/postgresEris/default.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ - flake, - ... -}: -let - inherit (flake.config.services) instances; - - service = instances.postgresql; -in -{ - services = { - postgresqlBackup = { - enable = true; - startAt = "*-*-* 07:00:00"; - }; - postgresql = { - enable = true; - }; - }; - - networking = { - firewall = { - allowedTCPPorts = [ - service.ports.port0 - ]; - }; - }; - -} diff --git a/modules/nixos/services/template/default.nix b/modules/nixos/services/template/default.nix deleted file mode 100755 index 82f1ba2..0000000 --- a/modules/nixos/services/template/default.nix +++ /dev/null @@ -1,616 +0,0 @@ -# ============================================================================ -# MicroVM Service Template - Production-Ready Configuration -# ============================================================================ -# This template is based on proven, working configurations from: -# - Vaultwarden (simple service with environment file) -# - Forgejo (complex service with separate secret files) -# - Jellyfin (media service with multiple mounts and tmpfiles) -# -# CRITICAL SUCCESS FACTORS (learned from production deployments): -# 1. Use serviceCfg.name for all service references (not hardcoded strings) -# 2. Secrets MUST use service-specific subdirectories: /run/secrets/${serviceCfg.name}/ -# 3. Host directories MUST exist with correct permissions BEFORE VM starts -# 4. Use 0777 permissions when VM service runs as non-root user with different UID -# 5. systemd.tmpfiles can be used INSIDE the VM for VM-internal directories -# 6. Host and VM tmpfiles rules serve different purposes - use both when needed -# -# Architecture Overview: -# ┌────────────────────────────────────────────────┐ -# │ Host (NixOS Server) │ -# │ │ -# │ ┌──────────────┐ ┌──────────────┐ │ -# │ │ Caddy │ │ br-vms │ │ -# │ │ (Reverse │──────│ Bridge │ │ -# │ │ Proxy) │ │ 192.168.50 │ │ -# │ │ TLS Term │ │ .240 │ │ -# │ └──────────────┘ └──────┬───────┘ │ -# │ :443 │ │ -# │ │ ┌─────▼──────┐ │ -# │ │ │ vm-NAME │ │ -# │ │ │ (TAP) │ │ -# │ │ └─────┬──────┘ │ -# │ │ │ │ -# │ ┌─────▼──────────────────────▼────────────┐ │ -# │ │ │ │ -# │ │ MicroVM Guest │ │ -# │ │ ┌────────────┐ ┌────────────┐ │ │ -# │ │ │ Service │ │ enp0s5 │ │ │ -# │ │ │ :PORT │ │192.168.50 │ │ │ -# │ │ │ │ │ .1XX │ │ │ -# │ │ └────────────┘ └────────────┘ │ │ -# │ │ │ │ -# │ │ VirtioFS Mounts: │ │ -# │ │ • /nix/.ro-store → Host /nix/store │ │ -# │ │ • /var/lib/NAME → Host /mnt/storage │ │ -# │ │ • /run/secrets → Host /run/secrets/NAME│ │ -# │ └─────────────────────────────────────────┘ │ -# │ │ -# └────────────────────────────────────────────────┘ -# -# Network Flow: -# 1. Internet → Router:443 (port forward) → Host:443 (Caddy) -# 2. Caddy terminates TLS using ACME certificates -# 3. Caddy proxies HTTP to VM's LAN IP (e.g., 192.168.50.151:8085) -# 4. Request: br-vms → TAP (vm-NAME) → VM enp0s5 → Service -# 5. Response follows same path in reverse -# -# IMPORTANT: Split-DNS for LAN Access -# - External users: DNS resolves to public IP → router forwards to host -# - Internal users: MUST have DNS resolve to 192.168.50.240 (host bridge IP) -# OR use /etc/hosts entries, otherwise NAT hairpinning may fail -# -# ============================================================================ - -{ - config, - flake, - ... -}: -let - # ============================================================================ - # CONFIGURATION REFERENCES - # ============================================================================ - # These pull from your centralized instance definitions - # Located in: modules/config/instances/config/*.nix - - inherit (flake.config.people) user0; - inherit (flake.config.services) instances; - - # REPLACE 'service' with your actual service name identifier - # This should match the attribute name in your instances configuration - # Examples: vaultwarden, forgejo, jellyfin, etc. - serviceCfg = instances.service; # CHANGE THIS - - # SMTP configuration (if your service needs email) - # Remove this line if your service doesn't use SMTP - smtpCfg = instances.smtp; - - # Host/web configuration for routing and DNS - hostCfg = instances.web; - - # Service domain (e.g., "service.example.com") - host = serviceCfg.domains.url0; - - # DNS provider for ACME DNS-01 challenge - dns0 = instances.web.dns.provider0; - dns0Path = "dns/${dns0}"; -in -{ - # ============================================================================ - # HOST-SIDE CONFIGURATION - # ============================================================================ - # These configurations run on the HOST, not inside the VM - # They MUST be configured BEFORE the VM starts - - # ────────────────────────────────────────────────────────────────────────── - # 1. Caddy Group Membership - # ────────────────────────────────────────────────────────────────────────── - # Allow Caddy to read ACME certificates - users.users.caddy.extraGroups = [ "acme" ]; - - # ────────────────────────────────────────────────────────────────────────── - # 2. ACME TLS Certificate - # ────────────────────────────────────────────────────────────────────────── - # Request Let's Encrypt certificate using DNS-01 challenge - security.acme.certs."${host}" = { - dnsProvider = dns0; - environmentFile = config.sops.secrets.${dns0Path}.path; - group = "caddy"; - }; - - # ────────────────────────────────────────────────────────────────────────── - # 3. Host Storage Directories - # ────────────────────────────────────────────────────────────────────────── - # Create directories on the host BEFORE VM starts - # The VM will mount these via VirtioFS - # - # PERMISSION PATTERNS (choose based on your service): - # - 0755: Safe default when VM service runs as root - # - 0777: Required when VM service runs as non-root with different UID - # (e.g., jellyfin runs as UID 999 inside VM) - # - # EXAMPLES FROM WORKING CONFIGS: - # Vaultwarden: "d ${serviceCfg.mntPaths.path0} 0777 root root -" - # Forgejo: "d ${serviceCfg.mntPaths.path0} 0777 root root -" - # Jellyfin: "d ${serviceCfg.mntPaths.path0} 0777 root root -" - # "d ${serviceCfg.mntPaths.path0}/cache 0777 root root -" - systemd.tmpfiles.rules = [ - # Main data directory - "d ${serviceCfg.mntPaths.path0} 0777 root root -" - - # OPTIONAL: Additional directories if needed (like Jellyfin's cache) - # "d ${serviceCfg.mntPaths.path0}/cache 0777 root root -" - ]; - - # ────────────────────────────────────────────────────────────────────────── - # 4. Secrets Management (SOPS) - # ────────────────────────────────────────────────────────────────────────── - # Configure secrets decryption on the host - # SOPS-nix will decrypt these to /run/secrets/${serviceCfg.name}/* - # - # CRITICAL: Always use ${serviceCfg.name} for the path prefix! - # This prevents conflicts between multiple VMs - # - # PATTERN 1: Single environment file (like Vaultwarden) - # sops.secrets = { - # "${serviceCfg.name}/env" = { - # owner = "root"; - # mode = "0600"; - # }; - # }; - # - # PATTERN 2: Multiple secret files (like Forgejo) - # sops.secrets = { - # "${serviceCfg.name}/smtp" = { - # owner = "root"; - # mode = "0600"; - # }; - # "${serviceCfg.name}/database" = { - # owner = "root"; - # mode = "0600"; - # }; - # }; - # - # PATTERN 3: No secrets (like Jellyfin - if service doesn't need secrets) - # sops.secrets = {}; - - sops.secrets = { - # CHOOSE ONE OF THE PATTERNS ABOVE AND UNCOMMENT - # "${serviceCfg.name}/env" = { - # owner = "root"; - # mode = "0600"; - # }; - }; - - # ============================================================================ - # CADDY REVERSE PROXY (Host-Side) - # ============================================================================ - # Caddy terminates TLS and proxies to the VM - services.caddy.virtualHosts."${host}" = { - extraConfig = '' - # Forward all requests to the VM's IP and port - reverse_proxy ${serviceCfg.interface.ip}:${toString serviceCfg.ports.port0} { - # Pass the real client IP to the service - header_up X-Real-IP {remote_host} - } - - # Use ACME certificate managed by NixOS - tls ${serviceCfg.ssl.cert} ${serviceCfg.ssl.key} - - # Compress responses - encode zstd gzip - ''; - }; - - # ============================================================================ - # MICROVM DEFINITION - # ============================================================================ - # Everything below defines the VM's configuration - - microvm.vms.${serviceCfg.name} = { - # VM Lifecycle - autostart = true; # Start VM automatically on host boot - restartIfChanged = true; # Restart VM when configuration changes - - # ────────────────────────────────────────────────────────────────────── - # VM Guest Configuration - # ────────────────────────────────────────────────────────────────────── - # Everything inside 'config' runs INSIDE the VM - config = { - # NixOS version (should match host or be compatible) - system.stateVersion = "24.05"; - - # Timezone (should match host for consistent logging) - time.timeZone = "America/Winnipeg"; - - # SSH Access - allow SSH into VM using host user's keys - users.users.root.openssh.authorizedKeys.keys = flake.config.people.users.${user0}.sshKeys; - - # ──────────────────────────────────────────────────────────────────── - # Services Configuration - # ──────────────────────────────────────────────────────────────────── - services = { - # ══════════════════════════════════════════════════════════════════ - # YOUR SERVICE CONFIGURATION GOES HERE - # ══════════════════════════════════════════════════════════════════ - # Choose one of the patterns below based on your service type: - - # ┌───────────────────────────────────────────────────────────────── - # │ PATTERN 1: Simple Service (Vaultwarden-style) - # │ - Uses environment file for secrets - # │ - Single configuration block - # └───────────────────────────────────────────────────────────────── - # vaultwarden = { - # enable = true; - # dbBackend = "sqlite"; - # config = { - # DOMAIN = "https://${host}"; - # - # # Email Configuration - # SMTP_AUTH_MECHANISM = "Plain"; - # SMTP_EMBED_IMAGES = true; - # SMTP_FROM = serviceCfg.email.address0; - # SMTP_FROM_NAME = serviceCfg.label; - # SMTP_HOST = smtpCfg.hostname; - # SMTP_PORT = smtpCfg.ports.port1; - # SMTP_SECURITY = smtpCfg.records.record1; - # SMTP_USERNAME = smtpCfg.email.address0; - # - # # Security Configuration - # DISABLE_ADMIN_TOKEN = false; - # - # # Web Server Settings - # ROCKET_ADDRESS = "0.0.0.0"; - # ROCKET_PORT = serviceCfg.ports.port0; - # }; - # - # # Mount secrets from host - # environmentFile = "/run/secrets/env"; - # }; - - # ┌───────────────────────────────────────────────────────────────── - # │ PATTERN 2: Complex Service (Forgejo-style) - # │ - Uses separate secret files - # │ - More complex settings structure - # └───────────────────────────────────────────────────────────────── - # forgejo = { - # enable = true; - # lfs.enable = true; - # - # # Separate secret files (not environment variables) - # secrets = { - # mailer.PASSWD = "/run/secrets/smtp"; - # }; - # - # dump = { - # interval = "5:00"; - # type = "zip"; - # file = "forgejo-backup"; - # enable = true; - # }; - # - # settings = { - # server = { - # DOMAIN = host; - # ROOT_URL = "https://${host}/"; - # HTTP_PORT = serviceCfg.ports.port0; - # }; - # - # service.DISABLE_REGISTRATION = true; - # - # actions = { - # ENABLED = true; - # DEFAULT_ACTIONS_URL = "github"; - # }; - # - # mirror = { - # ENABLED = true; - # }; - # - # mailer = { - # ENABLED = true; - # SMTP_ADDR = smtpCfg.hostname; - # FROM = smtpCfg.email.address1; - # USER = smtpCfg.email.address1; - # PROTOCOL = "${smtpCfg.name}+${smtpCfg.records.record1}"; - # SMTP_PORT = smtpCfg.ports.port1; - # SEND_AS_PLAIN_TEXT = true; - # USE_CLIENT_CERT = false; - # }; - # }; - # }; - - # ┌───────────────────────────────────────────────────────────────── - # │ PATTERN 3: Media Service (Jellyfin-style) - # │ - Simple enable, uses openFirewall - # │ - No secrets needed - # └───────────────────────────────────────────────────────────────── - # jellyfin = { - # enable = true; - # openFirewall = true; - # }; - - # ══════════════════════════════════════════════════════════════════ - # SSH Server (for VM management) - ALWAYS INCLUDE - # ══════════════════════════════════════════════════════════════════ - openssh = { - enable = true; - settings = { - PasswordAuthentication = false; - PermitRootLogin = "prohibit-password"; - }; - }; - }; - - # ──────────────────────────────────────────────────────────────────── - # Firewall Configuration - # ──────────────────────────────────────────────────────────────────── - # Open necessary ports inside the VM - # - # EXAMPLES: - # Vaultwarden: [22, 25, 139, 587, 2525, serviceCfg.ports.port0] - # Forgejo: [22, 25, 139, 587, 2525, serviceCfg.ports.port0] - # Jellyfin: [22, serviceCfg.ports.port0, port1, port2] - networking.firewall.allowedTCPPorts = [ - 22 # SSH (always include) - serviceCfg.ports.port0 # Main service port - - # OPTIONAL: SMTP ports if service sends email - # 25 # SMTP - # 587 # SMTP Submission - # 2525 # Alternative SMTP - - # OPTIONAL: Additional ports (like Jellyfin's discovery ports) - # serviceCfg.ports.port1 - # serviceCfg.ports.port2 - ]; - - # ──────────────────────────────────────────────────────────────────── - # OPTIONAL: Temporary Filesystem - # ──────────────────────────────────────────────────────────────────── - # Some services need a large /tmp (e.g., Forgejo for large Git operations) - # Jellyfin also uses this pattern - # - # UNCOMMENT IF NEEDED: - # fileSystems."/tmp" = { - # device = "tmpfs"; - # fsType = "tmpfs"; - # options = [ - # "size=4G" # Adjust size as needed - # "mode=1777" # Sticky bit for multi-user access - # ]; - # }; - - # ──────────────────────────────────────────────────────────────────── - # Systemd Configuration - # ──────────────────────────────────────────────────────────────────── - systemd = { - # Network Configuration (systemd-networkd) - # Configure the VM's network interface - # - # INTERFACE NAME: "enp0s5" is typical for QEMU with q35 machine - # To verify: SSH into VM and run: ip link show - network = { - enable = true; - - networks."20-lan" = { - # Match the network interface created by QEMU - matchConfig.Name = "enp0s5"; - - # Static IP Configuration - # MUST be on same subnet as host bridge (e.g., 192.168.50.0/24) - addresses = [ - { Address = "${serviceCfg.interface.ip}/24"; } - ]; - - # Default route for internet access - # PATTERN 1: Use "0.0.0.0/0" (Forgejo) - # PATTERN 2: Use "${hostCfg.localhost.address1}/0" (Vaultwarden, Jellyfin) - # Both work - choose one - routes = [ - { - Destination = "0.0.0.0/0"; # or "${hostCfg.localhost.address1}/0" - Gateway = serviceCfg.interface.gate; - } - ]; - - # DNS servers - dns = [ - "1.1.1.1" # Cloudflare - "8.8.8.8" # Google - ]; - }; - }; - - # OPTIONAL: VM-internal tmpfiles (Jellyfin and Forgejo use this) - # This creates directories INSIDE the VM, separate from host tmpfiles - # Used when the service needs specific ownership/permissions inside VM - # - # EXAMPLES: - # Jellyfin: "d ${serviceCfg.varPaths.path0}/media 0755 ${serviceCfg.name} ${serviceCfg.name} -" - # Forgejo: "d ${serviceCfg.varPaths.path0} 0755 ${serviceCfg.name} ${serviceCfg.name} -" - # - # UNCOMMENT IF NEEDED: - # tmpfiles.rules = [ - # "d ${serviceCfg.varPaths.path0} 0755 ${serviceCfg.name} ${serviceCfg.name} -" - # ]; - }; - - # Ensure systemd-networkd starts on boot - systemd.services.systemd-networkd.wantedBy = [ "multi-user.target" ]; - - # ──────────────────────────────────────────────────────────────────── - # MicroVM Hardware Configuration - # ──────────────────────────────────────────────────────────────────── - microvm = { - # Virtual CPU cores - # Adjust based on service needs: - # - Light services (Vaultwarden, Forgejo): 2 cores - # - Heavy services (Jellyfin): 6 cores - vcpu = 2; - - # Memory in MB - # Adjust based on service needs: - # - Light services (Vaultwarden): 3072 MB (3 GB) - # - Medium services (Forgejo): 3072 MB (3 GB) - # - Heavy services (Jellyfin): 8192 MB (8 GB) - mem = 3072; - - # Hypervisor - QEMU with KVM provides best performance - hypervisor = "qemu"; - - # ────────────────────────────────────────────────────────────────── - # Network Interfaces - # ────────────────────────────────────────────────────────────────── - # All working configs use TWO interfaces: TAP + User-mode - interfaces = [ - # Primary Interface: TAP (LAN Connectivity) - { - type = "tap"; - id = serviceCfg.interface.id; # e.g., "vm-service" - mac = serviceCfg.interface.mac; # e.g., "02:00:00:00:00:51" - } - - # Secondary Interface: User-mode (NAT/Fallback) - { - type = "user"; - id = serviceCfg.interface.idUser; # e.g., "vmuser-service" - mac = serviceCfg.interface.macUser; # e.g., "02:00:00:00:01:51" - } - ]; - - # ────────────────────────────────────────────────────────────────── - # Port Forwarding (Host → VM) - # ────────────────────────────────────────────────────────────────── - # Forward SSH from host to VM for easy access - # Access via: ssh -p 22XX root@localhost (from host) - forwardPorts = [ - { - from = "host"; - host.port = serviceCfg.interface.ssh; # e.g., 2201 - guest.port = 22; - } - ]; - - # ────────────────────────────────────────────────────────────────── - # Shared Directories (VirtioFS) - # ────────────────────────────────────────────────────────────────── - # Share directories from host to VM - # - # IMPORTANT: All source paths must exist on host BEFORE VM starts - # Use systemd.tmpfiles.rules (in host section) to create directories - shares = [ - # ┌─────────────────────────────────────────────────────────────── - # │ Nix Store (Read-Only) - ALWAYS INCLUDE - # └─────────────────────────────────────────────────────────────── - { - mountPoint = "/nix/.ro-store"; - proto = "virtiofs"; - source = "/nix/store"; - tag = "read_only_nix_store"; - } - - # ┌─────────────────────────────────────────────────────────────── - # │ Service Data (Read-Write) - # └─────────────────────────────────────────────────────────────── - # CHOOSE ONE PATTERN: - # - # PATTERN 1: Direct path (Vaultwarden) - # { - # mountPoint = "/var/lib/bitwarden_rs"; - # proto = "virtiofs"; - # source = serviceCfg.mntPaths.path0; - # tag = "${serviceCfg.name}_data"; - # } - # - # PATTERN 2: Use serviceCfg.name (Forgejo) - # { - # mountPoint = "/var/lib/${serviceCfg.name}"; - # proto = "virtiofs"; - # source = serviceCfg.mntPaths.path0; - # tag = "${serviceCfg.name}_data"; - # } - # - # PATTERN 3: Use serviceCfg.varPaths (Jellyfin) - # { - # mountPoint = serviceCfg.varPaths.path0; - # proto = "virtiofs"; - # source = serviceCfg.mntPaths.path0; - # tag = "${serviceCfg.name}_data"; - # } - - { - mountPoint = "/var/lib/${serviceCfg.name}"; # ADJUST THIS - proto = "virtiofs"; - source = serviceCfg.mntPaths.path0; - tag = "${serviceCfg.name}_data"; - } - - # ┌─────────────────────────────────────────────────────────────── - # │ OPTIONAL: Additional Data Mounts (like Jellyfin's cache) - # └─────────────────────────────────────────────────────────────── - # UNCOMMENT IF NEEDED: - # { - # mountPoint = serviceCfg.varPaths.path1; - # proto = "virtiofs"; - # source = "${serviceCfg.mntPaths.path0}/cache"; - # tag = "${serviceCfg.name}_cache"; - # } - - # ┌─────────────────────────────────────────────────────────────── - # │ Secrets (Read-Only) - INCLUDE IF SERVICE NEEDS SECRETS - # └─────────────────────────────────────────────────────────────── - # CRITICAL: Source must use service-specific subdirectory! - # This matches the sops.secrets configuration above - # - # UNCOMMENT IF SERVICE NEEDS SECRETS: - # { - # mountPoint = "/run/secrets"; - # proto = "virtiofs"; - # source = "/run/secrets/${serviceCfg.name}"; - # tag = "host_secrets"; - # } - ]; - }; - }; - }; -} - -# ============================================================================ -# QUICK REFERENCE: Pattern Comparison -# ============================================================================ -# -# ┌──────────────┬─────────────┬──────────────┬─────────────┐ -# │ Aspect │ Vaultwarden │ Forgejo │ Jellyfin │ -# ├──────────────┼─────────────┼──────────────┼─────────────┤ -# │ vCPU │ 2 │ 2 │ 6 │ -# │ Memory │ 3072 MB │ 3072 MB │ 8192 MB │ -# │ Secrets │ env file │ sep. files │ none │ -# │ /tmp mount │ no │ yes (4G) │ yes (4G) │ -# │ VM tmpfiles │ no │ yes │ yes │ -# │ Host perms │ 0777 │ 0777 │ 0777 │ -# │ Data mounts │ 1 │ 1 │ 2 │ -# │ Secrets mnt │ yes │ yes │ no │ -# └──────────────┴─────────────┴──────────────┴─────────────┘ -# -# ============================================================================ -# CHECKLIST: Steps to Create New Service -# ============================================================================ -# -# 1. [ ] Copy this template to modules/nixos/services/YOUR-SERVICE/default.nix -# 2. [ ] Replace 'service' with your service name in instances reference -# 3. [ ] Uncomment and configure your service in services = { ... } -# 4. [ ] Adjust vcpu/mem based on service requirements -# 5. [ ] Configure secrets (if needed) - both sops.secrets and shares -# 6. [ ] Set correct mountPoint for service data (check service docs) -# 7. [ ] Adjust firewall ports based on service needs -# 8. [ ] Add /tmp mount if service needs large temporary space -# 9. [ ] Test build: sudo nixos-rebuild build --flake .#YOUR-HOST -# 10. [ ] Deploy: sudo nixos-rebuild switch --flake .#YOUR-HOST -# 11. [ ] Verify TAP exists: ip link show vm-YOUR-SERVICE -# 12. [ ] SSH to VM: ssh -p 22XX root@localhost -# 13. [ ] Check network in VM: ip addr show enp0s5 -# 14. [ ] Test service: curl http://VM-IP:PORT -# 15. [ ] Test external access: https://YOUR-SERVICE.example.com -# -# ============================================================================