From e03f3af01daee991a837744aeced6183c7385c00 Mon Sep 17 00:00:00 2001 From: Nickolaj Jepsen Date: Fri, 12 Dec 2025 04:30:57 +0100 Subject: [PATCH] refactor: move homelab config to module --- hosts/default.nix | 1 + hosts/homelab/configuration.nix | 1 + {hosts => modules}/homelab/arr.nix | 6 +- modules/homelab/default.nix | 19 ++++ {hosts => modules}/homelab/flame.nix | 9 +- {hosts => modules}/homelab/home-assistant.nix | 8 +- {hosts => modules}/homelab/nextcloud.nix | 4 +- {hosts => modules}/homelab/nginx.nix | 7 +- {hosts => modules}/homelab/plex.nix | 10 +- {hosts => modules}/homelab/postgres.nix | 7 +- {hosts => modules}/homelab/prometheus.nix | 6 +- {hosts => modules}/homelab/restic.nix | 4 +- {hosts => modules}/homelab/sso.nix | 6 +- {hosts => modules}/homelab/vaultwarden.nix | 9 +- modules/system/ssh.nix | 88 +++++++++--------- ...5b0ff06b3abca21a3a0c1535d1f-ssh-key-ao.age | Bin 2205 -> 0 bytes ...19251bb18b1001dc9edd0b65e8f-ssh-key-ao.age | Bin 2126 -> 0 bytes ...9b9ea4ca971c2fc9d12218c1ea7-k8s-ao-dev.age | Bin 0 -> 2129 bytes ...a5f283a7e7fcd797b29f5e5de0-k8s-ao-prod.age | Bin 0 -> 2055 bytes 19 files changed, 123 insertions(+), 62 deletions(-) rename {hosts => modules}/homelab/arr.nix (97%) create mode 100644 modules/homelab/default.nix rename {hosts => modules}/homelab/flame.nix (89%) rename {hosts => modules}/homelab/home-assistant.nix (98%) rename {hosts => modules}/homelab/nextcloud.nix (93%) rename {hosts => modules}/homelab/nginx.nix (84%) rename {hosts => modules}/homelab/plex.nix (81%) rename {hosts => modules}/homelab/postgres.nix (70%) rename {hosts => modules}/homelab/prometheus.nix (94%) rename {hosts => modules}/homelab/restic.nix (92%) rename {hosts => modules}/homelab/sso.nix (97%) rename {hosts => modules}/homelab/vaultwarden.nix (90%) delete mode 100644 secrets/hosts/bootstrap/.rekey/6cf125b0ff06b3abca21a3a0c1535d1f-ssh-key-ao.age delete mode 100644 secrets/hosts/homelab/.rekey/0caf919251bb18b1001dc9edd0b65e8f-ssh-key-ao.age create mode 100644 secrets/hosts/homelab/.rekey/2065d9b9ea4ca971c2fc9d12218c1ea7-k8s-ao-dev.age create mode 100644 secrets/hosts/homelab/.rekey/456a05a5f283a7e7fcd797b29f5e5de0-k8s-ao-prod.age diff --git a/hosts/default.nix b/hosts/default.nix index f78bf54..1ed31b1 100644 --- a/hosts/default.nix +++ b/hosts/default.nix @@ -44,6 +44,7 @@ with lib; let ../modules/system ../modules/programs ../modules/desktop + ../modules/homelab (mkSystemImports hostname) {nixpkgs.config.allowUnfree = true;} ] diff --git a/hosts/homelab/configuration.nix b/hosts/homelab/configuration.nix index 730d1d0..8ff34bb 100644 --- a/hosts/homelab/configuration.nix +++ b/hosts/homelab/configuration.nix @@ -4,6 +4,7 @@ ... }: { fireproof.dev.enable = true; + fireproof.homelab.enable = true; boot = { # Use grub as bootloader as it works better with mdadm diff --git a/hosts/homelab/arr.nix b/modules/homelab/arr.nix similarity index 97% rename from hosts/homelab/arr.nix rename to modules/homelab/arr.nix index b93fc89..80d64eb 100644 --- a/hosts/homelab/arr.nix +++ b/modules/homelab/arr.nix @@ -1,8 +1,10 @@ { config, + lib, username, ... -}: let +}: +lib.mkIf config.fireproof.homelab.enable (let user = "media"; group = "media"; @@ -80,4 +82,4 @@ in { }; prowlarr.enable = true; }; -} +}) diff --git a/modules/homelab/default.nix b/modules/homelab/default.nix new file mode 100644 index 0000000..e3cb769 --- /dev/null +++ b/modules/homelab/default.nix @@ -0,0 +1,19 @@ +{lib, ...}: { + options.fireproof.homelab = { + enable = lib.mkEnableOption "Enable homelab services (arr, nginx, postgres, prometheus, etc.)"; + }; + + imports = [ + ./arr.nix + ./flame.nix + ./home-assistant.nix + ./nextcloud.nix + ./nginx.nix + ./plex.nix + ./postgres.nix + ./prometheus.nix + ./restic.nix + ./sso.nix + ./vaultwarden.nix + ]; +} diff --git a/hosts/homelab/flame.nix b/modules/homelab/flame.nix similarity index 89% rename from hosts/homelab/flame.nix rename to modules/homelab/flame.nix index 3739109..6c4f398 100644 --- a/hosts/homelab/flame.nix +++ b/modules/homelab/flame.nix @@ -1,4 +1,9 @@ -_: let +{ + config, + lib, + ... +}: +lib.mkIf config.fireproof.homelab.enable (let dataDir = "/var/lib/flame"; domain = "flame.nickolaj.com"; in { @@ -29,4 +34,4 @@ in { }; }; }; -} +}) diff --git a/hosts/homelab/home-assistant.nix b/modules/homelab/home-assistant.nix similarity index 98% rename from hosts/homelab/home-assistant.nix rename to modules/homelab/home-assistant.nix index 853bd86..0fea1ab 100644 --- a/hosts/homelab/home-assistant.nix +++ b/modules/homelab/home-assistant.nix @@ -1,8 +1,10 @@ { pkgs, config, + lib, ... -}: let +}: +lib.mkIf config.fireproof.homelab.enable (let mosquittoPort = 1883; zigbee2mqttPort = 8180; homeAssistantPort = 8123; @@ -65,7 +67,7 @@ in { package = pkgs.home-assistant; customComponents = with pkgs.home-assistant-custom-components; [ adaptive_lighting - sleep_as_android + sleep_as_android_mqtt (pkgs.buildHomeAssistantComponent rec { owner = "Sian-Lee-SA"; domain = "switch_manager"; @@ -183,4 +185,4 @@ in { }; }; }; -} +}) diff --git a/hosts/homelab/nextcloud.nix b/modules/homelab/nextcloud.nix similarity index 93% rename from hosts/homelab/nextcloud.nix rename to modules/homelab/nextcloud.nix index 6f6be6d..77a12d6 100644 --- a/hosts/homelab/nextcloud.nix +++ b/modules/homelab/nextcloud.nix @@ -1,8 +1,10 @@ { config, pkgs, + lib, ... -}: { +}: +lib.mkIf config.fireproof.homelab.enable { age.secrets.nextcloud-admin-pass = { rekeyFile = ../../secrets/hosts/homelab/nextcloud-admin-pass.age; owner = "nextcloud"; diff --git a/hosts/homelab/nginx.nix b/modules/homelab/nginx.nix similarity index 84% rename from hosts/homelab/nginx.nix rename to modules/homelab/nginx.nix index 7e02436..e930b27 100644 --- a/hosts/homelab/nginx.nix +++ b/modules/homelab/nginx.nix @@ -1,4 +1,9 @@ -_: { +{ + config, + lib, + ... +}: +lib.mkIf config.fireproof.homelab.enable { networking.firewall.allowedTCPPorts = [80 443]; services.nginx = { diff --git a/hosts/homelab/plex.nix b/modules/homelab/plex.nix similarity index 81% rename from hosts/homelab/plex.nix rename to modules/homelab/plex.nix index b001acf..9a6b2e3 100644 --- a/hosts/homelab/plex.nix +++ b/modules/homelab/plex.nix @@ -1,4 +1,10 @@ -{pkgsUnstable, ...}: let +{ + config, + pkgsUnstable, + lib, + ... +}: +lib.mkIf config.fireproof.homelab.enable (let domain = "plex.nickolaj.com"; in { services.nginx.virtualHosts."${domain}" = { @@ -18,4 +24,4 @@ in { user = "media"; group = "media"; }; -} +}) diff --git a/hosts/homelab/postgres.nix b/modules/homelab/postgres.nix similarity index 70% rename from hosts/homelab/postgres.nix rename to modules/homelab/postgres.nix index 95e7d69..446f427 100644 --- a/hosts/homelab/postgres.nix +++ b/modules/homelab/postgres.nix @@ -1,4 +1,9 @@ -{config, ...}: { +{ + config, + lib, + ... +}: +lib.mkIf config.fireproof.homelab.enable { services = { restic.backups.homelab.paths = [config.services.postgresqlBackup.location]; diff --git a/hosts/homelab/prometheus.nix b/modules/homelab/prometheus.nix similarity index 94% rename from hosts/homelab/prometheus.nix rename to modules/homelab/prometheus.nix index 48bb919..7e3617a 100644 --- a/hosts/homelab/prometheus.nix +++ b/modules/homelab/prometheus.nix @@ -1,8 +1,10 @@ { config, hostname, + lib, ... -}: let +}: +lib.mkIf config.fireproof.homelab.enable (let mkScrapeConfig = name: { job_name = name; static_configs = [ @@ -49,4 +51,4 @@ in { ]; }; }; -} +}) diff --git a/hosts/homelab/restic.nix b/modules/homelab/restic.nix similarity index 92% rename from hosts/homelab/restic.nix rename to modules/homelab/restic.nix index 97e1cff..2539818 100644 --- a/hosts/homelab/restic.nix +++ b/modules/homelab/restic.nix @@ -1,8 +1,10 @@ { pkgs, config, + lib, ... -}: { +}: +lib.mkIf config.fireproof.homelab.enable { environment.systemPackages = with pkgs; [ restic ]; diff --git a/hosts/homelab/sso.nix b/modules/homelab/sso.nix similarity index 97% rename from hosts/homelab/sso.nix rename to modules/homelab/sso.nix index de20882..676013b 100644 --- a/hosts/homelab/sso.nix +++ b/modules/homelab/sso.nix @@ -1,8 +1,10 @@ { config, pkgsUnstable, + lib, ... -}: let +}: +lib.mkIf config.fireproof.homelab.enable (let port = 9190; rootDomain = "nickolaj.com"; zitadelDomain = "sso.${rootDomain}"; @@ -105,4 +107,4 @@ in { cookie-domain = ".${rootDomain}"; }; }; -} +}) diff --git a/hosts/homelab/vaultwarden.nix b/modules/homelab/vaultwarden.nix similarity index 90% rename from hosts/homelab/vaultwarden.nix rename to modules/homelab/vaultwarden.nix index c1d915b..1127b97 100644 --- a/hosts/homelab/vaultwarden.nix +++ b/modules/homelab/vaultwarden.nix @@ -1,4 +1,9 @@ -{config, ...}: let +{ + config, + lib, + ... +}: +lib.mkIf config.fireproof.homelab.enable (let domain = "bitwarden.nickolaj.com"; in { services = { @@ -27,4 +32,4 @@ in { }; }; }; -} +}) diff --git a/modules/system/ssh.nix b/modules/system/ssh.nix index 2355b68..4e2f9e4 100644 --- a/modules/system/ssh.nix +++ b/modules/system/ssh.nix @@ -30,50 +30,52 @@ in { forwardAgent = true; serverAliveInterval = 60; serverAliveCountMax = 10; - matchBlocks = { - "*" = { - identityFile = "${config.age.secrets.ssh-key.path}"; + matchBlocks = + { + "*" = { + identityFile = "${config.age.secrets.ssh-key.path}"; + }; + homelab = { + hostname = "x.nickolaj.com"; + user = "nickolaj"; + }; + } + // lib.optionalAttrs workEnabled { + # Work hostnames definded in ./networking.nix + "bastion.ao" = { + user = "nij"; + identityFile = "${config.age.secrets.ssh-key-ao.path}"; + }; + "clickhouse.ao" = { + user = "ubuntu"; + hostname = "51.158.205.48"; + identityFile = "${config.age.secrets.ssh-key-ao.path}"; + }; + "flex.ao" = { + user = "nij"; + hostname = "192.168.2.5"; + proxyJump = "bastion.ao"; + identityFile = "${config.age.secrets.ssh-key-ao.path}"; + }; + "scw.ao" = { + user = "nij"; + hostname = "51.15.81.1"; + proxyJump = lib.mkDefault "dev.ao"; + identityFile = "${config.age.secrets.ssh-key-ao.path}"; + }; + "dev.ao" = { + user = "nij"; + hostname = "192.168.2.28"; + proxyJump = lib.mkDefault "bastion.ao"; + identityFile = "${config.age.secrets.ssh-key-ao.path}"; + }; + "staging.ao" = { + user = "staging"; + hostname = "172.16.2.102"; + proxyJump = lib.mkDefault "bastion.ao"; + identityFile = "${config.age.secrets.ssh-key-ao.path}"; + }; }; - homelab = { - hostname = "x.nickolaj.com"; - user = "nickolaj"; - }; - } // lib.optionalAttrs workEnabled { - # Work hostnames definded in ./networking.nix - "bastion.ao" = { - user = "nij"; - identityFile = "${config.age.secrets.ssh-key-ao.path}"; - }; - "clickhouse.ao" = { - user = "ubuntu"; - hostname = "51.158.205.48"; - identityFile = "${config.age.secrets.ssh-key-ao.path}"; - }; - "flex.ao" = { - user = "nij"; - hostname = "192.168.2.5"; - proxyJump = "bastion.ao"; - identityFile = "${config.age.secrets.ssh-key-ao.path}"; - }; - "scw.ao" = { - user = "nij"; - hostname = "51.15.81.1"; - proxyJump = lib.mkDefault "dev.ao"; - identityFile = "${config.age.secrets.ssh-key-ao.path}"; - }; - "dev.ao" = { - user = "nij"; - hostname = "192.168.2.28"; - proxyJump = lib.mkDefault "bastion.ao"; - identityFile = "${config.age.secrets.ssh-key-ao.path}"; - }; - "staging.ao" = { - user = "staging"; - hostname = "172.16.2.102"; - proxyJump = lib.mkDefault "bastion.ao"; - identityFile = "${config.age.secrets.ssh-key-ao.path}"; - }; - }; }; }; diff --git a/secrets/hosts/bootstrap/.rekey/6cf125b0ff06b3abca21a3a0c1535d1f-ssh-key-ao.age b/secrets/hosts/bootstrap/.rekey/6cf125b0ff06b3abca21a3a0c1535d1f-ssh-key-ao.age deleted file mode 100644 index 5b697254081911993d12678a9240652341232f44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2205 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14F3!+RO))YxHMCUlH1x9w2~{>=kY`>RY?>ta%#m1UNgXOi!j=j~aLo6n`ItE-^z>{b~S6=_nQ6yRTJ zQS9y!>Fa42n31>`B818IoRLs>lf6c80S1uK>3pQu(t=?YZoUlx> z`8b=!mOvl5RL`k8xssgw&;LvLV(DN$SCu`-VeY|1~q59?<|duAU#VQk--^fhbt1lxs`%kBkOT;II+-y+?& z%NAE9aQ4LCTNciv{b`=oiQm4edtLcT&x-Lg6wEK2t82Xc=d$^$&sFr^UHVnM@UQXi z6~|vjxm}ojP3O+(89GVF1%*#=WL*)^W$4&cB^;Sl!S{Dx-BJC>)f+3bzNgDg+}U7V zGbeQGm%`P@f9csxKDV&Lo2IzN&q32&>f{bidxocn z)|_vYZMl@W??k-YJWqZDriZr=%X_(MoEYSIelt!g+swUSvw4_AdQwwrk1j_FuZ`^?~2}8)xl?M=uNaNls45*9woC zC0AyqqPIboeP3Vrl#VS|a%7ceM?KZ|O`dyBKsW7Pdvo}w47MA8c@9*oweVfketTo7 z#`!A(&Hq{FTydYi&S$D?ws5TKGCP532eQ1+uS>hj`FhpE<1SB^?DgL#&2#dbb#j~T z>sQkqer8`fc=Aq&*S?y~ylYaOJI-uFE=<^dV=K=srZsY6Wq}gQ`%RUCjhcEy0tLl1rtDp07`y54S#EMN3|VZr`@%7b5h z?EWR1_5^N>4BgtwcPDaLSxo##qfakpE?d5KVtTx&!g7ht9tN7$|6*B>vf1j}XiH|t zKbff@{dD41rnwHYLvKwME&aVNHG}KXBny>_$Z!8`b`>yxU)`CX5yCMcjy=D!?5dNj z8>d+%%Q10ZmhT%{L&~{UY*C)RE7;V%$YYhUm!;~azt`Ta3Yb!(>U`eDvv8x0o?LGG zq{A!|3wNx$uJYlrYo_OJ*0opP*sq>cB5~CvV~=az?9T8)|qPJRZX;*v@Dm>S6XS^h9iiw?n z(Q?-m500F#$M!2LN4*T=DtoHq=l`=rVpsK^&&kGuCg=Y#1W#c2v1eaz#GNB9ZkHA| zoU)ow@k3GDOKH+_wlDbwZNeEe_6Tt=l!Zd08lczX7*?a*L-VUhG>UHbZa zOs5%}zO1WIy|YLDov6u{Ql|Niw{Kq-)p;Ju<*M#2R$h_gMVwBs``L>;Z)pI^PX5oCxzf0&EJ}i`yb*J=XDC3{6eg_MMm`Ep2;55 zb&k!*K3kP4*k|u+Z(t<9L!^jrZ(NMx6W0Y%zoa+ZKi;(E>ZSh~9QB6^OuEJP*!^2D zJ0k^Q6js5Ufd=ECfi=eC|a)4f)y5zzFMrTd-fkxaZ% zVZXd*Uw)Qf_4QBM*YCWS?oiLQI?KMoOiOXnuH>9@AI+}oce(#mzb|F^IW0x^#rH+* zp7zTOP6o`H^?{wSIwv~hbc9KeNW{!%;>I17nV&BxNu8+bUj5x%O)Gn5kD-`y^7m>t z-Gc$v9K~%RCzyBfSj7k5k_}$E_-e`H+GED<3g;574n*bNV&2UovX84ET)BPwhA;u$ z4gXTp2>dt*42q|r|c(dJe7;)soNl#qtvXJr=JkLXrEy0d8N{wTfgp2NiO;O zIU>Z$=`iE2CXHu{Pj&?eo=;C&Hf1WW%kmN-R$Yl#;cSN{30mief7L8DSd-r`c`zdA TP^E+4DF)dVZc#7LxAoSYaIIn-@@6<(uQ} z9B6J?p5w@+tE;O}<>=z!UG9`=T$S%XlouY7 zTN24-dB(O*NXx1HS#*b=K4-gkfoiW)k)qK(m#l+ku2pAySW2`-`Zg-q-N|rE5Edy? zV7ffZ|82C4UH($Vz?#c9cu#UI6Md?9``MbMLYKYDlAc%9KW$>zYx}>>on_9O@U;D^ zCO21}d8%BJ_tnE`^-=b1ii~ql=FEwlb6hW`Ug)-B_~Q?P$Iix zgYLxdU=mrbl$p5PY~N#!8ID((UI-t{DA1d`#{P6%!Rr}2jwf?Zo8K#@zxHcsOm~NY ztk#)NAD+al4ppCX@2&8K)Qx(|N%!NHb3K^5`qiUK!#~z8+e9WCC-0rK>B!As`?xf= zT_;YIv|R1nzG$`Aqj1jMjYZ58%TyL6=W>KM2;XC!`X%|ci}$mi3pS*l(!YAT?L^fi zF8dh6+-nib<^FcWNT?Prxud$woaIFu|CNqwo7*_KyaO0#)!$Uv@bQlOT5!=OByEgMQ~;O?cTCoVAYc=mL28ddlFY4*1vyFc#`yi z>h`a@mc3wiH$3RE@6P)f=?s_nHY|S=Hv6zq5nJWoJa}{mPalWbmTYVF z+|6A&W=u1BQo2=;2;x6J5`{%0HcQvH__f?KUU7pUnN>ts|$#9bBN)++I7YG~H}1`*2$ z<>`wKT#u08uw2CSa^Zo=+g=yFby;4t{`PszH-F-dJZxn$_f{nquke2LgpvPfN8}^X zC;vQERZo8HIhxz*xKu>SggcyZ;*O%pdY1fK*1SG)=JvgtqO8?dIp(jjek-f~BguDj zZMyiSFzvLH`=d|&y*mBSL}O#Oi~m+P3+&(e*=|4MxyP(Ko8_0?nZDpcqZHCti?-Hsb*2Q)gBYs}XDQ~uG(XF+Y)^|t!g4&PUK zS4Fo828tAY)mr#vG@c&*;Erh!#@-Oh&h ziasLJ85zep+UAmv-{y4&G9ldso(SFnu{kfNU-Wp zD_m{%v54hFylfzw*ot$%)m}SKQQCLmuD@8kP0%&h?6YE=8+ji}ADwdeui&)ZpUy2$ zeObnK+j!!HryciXEH^w`-DkU*^~#oYZpsR2{F0Nz4u`Tlbk?2Xzu0^BdhZ`C?(xj0 z`YpUg=LTj5a@8{KSl+0$xNt?Al%t!>_SittxKC%}znSp7p0Gd8*1qTj&)*ZiRo59M zHWc)EUt8(HI_+zJt7+WbeUl=Dqgk{Cj%}Ev?3DBIWL}UC?=IzaO_dUBKGw&7ek#B3 z){-;ZX19L7B!7@Srb4DQHNRX#Ls@8k^S1QYt1S}cFP)MV_0m+>|2^s7p_%8-7@a=c zY@f@zN!PDNVoQI+1M9epW@7gw3L+UU8-A9WoSkiOdd|-I9MYQ~bjDN%wn%;Qd|mgl zw0x^l;L}SdWuMwC)Vv_DT&`pJvb^xSoE{lBo@yEjRSDg7wEi)n@$sBX6&+T#ryTBk zclXPg%S{nnvvuLuT?NIKDgk@4l_wv6tK?9uvO(+T@2f9nMRLo``F!HyDbo)s!cn`{ z{bZdXJnvLxkFdmtH_PvI@|@2-@r6@#fr_#9|Ku$T1C5r51|CmhWE1oXUH!cCv+bLG zspc#OX-lRrU$8t;nEQeikEV!#pZ^;@sf$&y3Cz`+T51;);@2x{U2`qSab}S2WLkJD zoK5iJ#3}dq))beqPGQ;8J5x`VyPEGW>-{H(v#wOGo14L4*<$Wnxc<_YA34WPUA4{* z=BOBdP;#2P-E z@H(FN;V+jAH`Jy5aLaoz!ssEi=Eo tkE!vUdvQVY&k3I%*Hy-<=34zxU};<|v9w~vwwun0Yr|)_ce2as0079h(_8=m diff --git a/secrets/hosts/homelab/.rekey/2065d9b9ea4ca971c2fc9d12218c1ea7-k8s-ao-dev.age b/secrets/hosts/homelab/.rekey/2065d9b9ea4ca971c2fc9d12218c1ea7-k8s-ao-dev.age new file mode 100644 index 0000000000000000000000000000000000000000..eeab8047ea78f77cc5bffede9fb7e9d42ddc074d GIT binary patch literal 2129 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 dGi-_y4~OjLjADU