From 0fa3e1ec0ef186f7d714a53b3e18312d99a3f251 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 10 Nov 2025 15:58:08 -0600 Subject: [PATCH 001/149] fix (crowdsec): Scope of Journalctl access --- services/crowdsec.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/crowdsec.nix b/services/crowdsec.nix index f7e2e5a..d53f84e 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -18,9 +18,9 @@ in { services = { crowdsec = { enable = true; + allowLocalJournalAccess = true; settings = { api.server = { listen_uri = crowdsec-url; }; - allowLocalJournalAccess = true; crowdsec_service.acquisition_path = pkgs.writeText "acquisitions.yaml" (toMultiYAML [ { From 2ea0b6822143fddb4bdd918eea3b65aabe2662c6 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 10 Nov 2025 16:00:16 -0600 Subject: [PATCH 002/149] fix (crowdsec): API url --- services/crowdsec.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/crowdsec.nix b/services/crowdsec.nix index d53f84e..99c53b8 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -42,7 +42,7 @@ in { crowdsec-firewall-bouncer = { enable = true; settings = { - api_url = firewall-bouncer-name; + api_url = crowdsec-url; api_key = firewall-bouncer-key; }; }; From 4ca995f75a1933bab49f505314d727b204469174 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 10 Nov 2025 21:41:27 -0600 Subject: [PATCH 003/149] fix (crowdsec): Add hub update steps --- services/crowdsec.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/services/crowdsec.nix b/services/crowdsec.nix index 99c53b8..76c5024 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -80,6 +80,14 @@ in { set -eu set -o pipefail + # I had to run these commands in order to manually install collections + # using cscli. + # Not sure how often they should actually be run, but I would rather + # include this here. + # https://discourse.crowdsec.net/t/solved-cant-find-collections-appsec/1830 + cscli capi register + cscli hub update + ${pkgs.lib.concatMapStrings collection-check collections} ''; in [ From b2928eb81f660d617862766444f67753ce125b38 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 10 Nov 2025 21:47:29 -0600 Subject: [PATCH 004/149] fix (crowdsec): Proper URI syntax for API --- services/crowdsec.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/crowdsec.nix b/services/crowdsec.nix index 76c5024..378b2b4 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -1,6 +1,6 @@ { pkgs, config, ... }: let - crowdsec-url = "127.0.0.1:2763"; + crowdsec-port = "2763"; firewall-bouncer-name = "fw-bouncer"; # Although this key can be reproduced by anyone who actually cares to, the # Crowdsec API will not be exposed to the outside world, so keeping this key @@ -20,7 +20,7 @@ in { enable = true; allowLocalJournalAccess = true; settings = { - api.server = { listen_uri = crowdsec-url; }; + api.server = { listen_uri = "127.0.0.1:${crowdsec-port}"; }; crowdsec_service.acquisition_path = pkgs.writeText "acquisitions.yaml" (toMultiYAML [ { @@ -42,7 +42,7 @@ in { crowdsec-firewall-bouncer = { enable = true; settings = { - api_url = crowdsec-url; + api_url = "http://localhost:${crowdsec-port}"; api_key = firewall-bouncer-key; }; }; From 1fba4037317e7e9985c3bcae8ba71df6b7075cd0 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 10 Nov 2025 22:17:28 -0600 Subject: [PATCH 005/149] fix (crowdsec): Add sleep to avoid rate limits --- services/crowdsec.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/crowdsec.nix b/services/crowdsec.nix index 378b2b4..93627cb 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -63,6 +63,7 @@ in { if ! cscli collections list | grep -q "${collection}"; then cscli collections install "${collection}" + sleep 1 fi ''; @@ -86,7 +87,9 @@ in { # include this here. # https://discourse.crowdsec.net/t/solved-cant-find-collections-appsec/1830 cscli capi register + sleep 1 cscli hub update + sleep 1 ${pkgs.lib.concatMapStrings collection-check collections} ''; From f982232c99a38d3bc6a89946cb163b615b494adf Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 11 Nov 2025 21:39:34 -0600 Subject: [PATCH 006/149] fix (crowdsec): hub permissions issues --- services/crowdsec.nix | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/crowdsec.nix b/services/crowdsec.nix index 93627cb..6c33fce 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -86,10 +86,13 @@ in { # Not sure how often they should actually be run, but I would rather # include this here. # https://discourse.crowdsec.net/t/solved-cant-find-collections-appsec/1830 - cscli capi register - sleep 1 - cscli hub update - sleep 1 + # Unfortunately, this section is now causing permissions issues. I'm + # leaving the code here for reference, but commenting it out to allow + # Crowdsec to run + # cscli capi register + # sleep 1 + # cscli hub update + # sleep 1 ${pkgs.lib.concatMapStrings collection-check collections} ''; From 2c4e7097046bcf3b61adbab77009b8c8d04e88c5 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 11 Nov 2025 21:42:25 -0600 Subject: [PATCH 007/149] debug (crowdsec): Add verbose logging to Crowdsec collection install step --- services/crowdsec.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/crowdsec.nix b/services/crowdsec.nix index 6c33fce..8504da4 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -62,7 +62,7 @@ in { collection-check = collection: '' if ! cscli collections list | grep -q "${collection}"; then - cscli collections install "${collection}" + cscli collections --trace install "${collection}" sleep 1 fi From 3b9b7f684d10b61086ba7eb971b6943d0a0f297c Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 11 Nov 2025 21:59:28 -0600 Subject: [PATCH 008/149] Revert "fix (crowdsec): hub permissions issues" This reverts commit f982232c99a38d3bc6a89946cb163b615b494adf. --- services/crowdsec.nix | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/services/crowdsec.nix b/services/crowdsec.nix index 8504da4..6a54584 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -86,13 +86,10 @@ in { # Not sure how often they should actually be run, but I would rather # include this here. # https://discourse.crowdsec.net/t/solved-cant-find-collections-appsec/1830 - # Unfortunately, this section is now causing permissions issues. I'm - # leaving the code here for reference, but commenting it out to allow - # Crowdsec to run - # cscli capi register - # sleep 1 - # cscli hub update - # sleep 1 + cscli capi register + sleep 1 + cscli hub update + sleep 1 ${pkgs.lib.concatMapStrings collection-check collections} ''; From 4d563444468308476220868d202a39904aa45f4a Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 13 Nov 2025 14:36:19 -0600 Subject: [PATCH 009/149] secrets: Rekey secrets for secret purposes --- secrets.nix | 5 ++++- secrets/ansible-vault-password.age | 24 ++++++++++++------------ secrets/darwin-policies-json.age | Bin 834 -> 1214 bytes secrets/network-information.age | Bin 907 -> 907 bytes secrets/pihole.age | 28 ++++++++++++++-------------- secrets_file.enc | 16 +++++++--------- secrets_odyssey.enc | 13 ++++++++----- systems/darwin/corianne.nix | 7 +++++++ 8 files changed, 52 insertions(+), 41 deletions(-) diff --git a/secrets.nix b/secrets.nix index 3b3ede4..c0d5047 100644 --- a/secrets.nix +++ b/secrets.nix @@ -8,6 +8,8 @@ let "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKaDPqRJHoqgY2pseh/mnhjaGWXprHk2s5I52LhHpHcF millironx@bosephus"; odyssey-millironx = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9Aj7BtQp1Roa0tgopDrUo7g2am5WJ43lO1d1fDUz45 millironx@odyssey"; + corianne-host = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHKKkucebeb1GcerOZAAs5GQsgTS8kXw5W41b9Fy9+hp root@corianne.local"; corianne-millironx = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOgL2lO9RJBdQYANoxGyWXcNKi5/NZkRHHo/rNqaYMc/ millironx@corianne"; harmony-millironx = @@ -26,5 +28,6 @@ in { ++ [ bosephus-host ]; "secrets/pihole.age".publicKeys = system-administrators ++ [ bosephus-host ]; "secrets/ansible-vault-password.age".publicKeys = system-administrators; - "secrets/darwin-policies-json.age".publicKeys = system-administrators; + "secrets/darwin-policies-json.age".publicKeys = system-administrators + ++ [ corianne-host ]; } diff --git a/secrets/ansible-vault-password.age b/secrets/ansible-vault-password.age index 99a96bc..d833716 100644 --- a/secrets/ansible-vault-password.age +++ b/secrets/ansible-vault-password.age @@ -1,13 +1,13 @@ age-encryption.org/v1 --> ssh-ed25519 il3lzQ Ni2CHjeijXHfF62cUqVTm8MAOn6rRg8UrhqN6xvdkyk -DsT0Ysx88FlCLeRzoOGctX7KqatX9/UCr5WdtdLJAf4 --> ssh-ed25519 1g/xww jRn91F29sISMyi41anAlzVCzt1t1DnUqxtryqkTQPlM -cysgZLQR0YhiJYXBl59DjKbm+N8FnjA46wkQtnAzBFA --> ssh-ed25519 +kBihw t6wlSnDKGgSzGhNJnryXVbDR40DATaV3fHovtI/u7zo -zOyCZtzfLKeer9K6SMpfTxn6El4HB7gQFQqLOxIYB5U --> ssh-ed25519 dbKeHw cn+8WTwis58bYm2pfEra6LeLvzEZ8GhZrOEeN+kkhCM -fnlUAj8JtG8+r7Cj8xYUgF+JM6Pwqawn4sGI1LOeN78 --> ssh-ed25519 Svnssw zmDBR8TdRZ9NzNhwPYRN6c8naTxAkULyUZpKgk7Gshk -0XCwpegEIlGXhnzLLUtmciKQiYiZRgnSOSvCcYeXXk8 ---- D/lZ36n5sVste2NWfdOx8/klPh0CTmMjVQN74KIqDRY -]%C}NO"v#˱t_Q;^*!+<+dB/K` \ No newline at end of file +-> ssh-ed25519 il3lzQ 8BY+QUEGqILKLs6ROw7llEOhx0GgrfFeKDcEgHePUFw +SPiG48tkp5ewFc6/uNj+541B6YJODGmDFEbET2BfoZ0 +-> ssh-ed25519 1g/xww HyUG/jNJgHCceV/9vaaoSHc681x6Gg/uY+RIfQxIBxU +6XVufQ4A9r8HPU9QLZ/idx3NjDf+UeKVMhtk9+Awy4E +-> ssh-ed25519 +kBihw XjhEk6TF6M5OalqVQNpAemlmgMIJnfuH6M600DnJql0 +3zQPJZcsfnbUqRf5XWTJNbyqMb/rsSBIkS7YlYsyMcs +-> ssh-ed25519 dbKeHw nIG5Z+XdJ3dyMxFOxyFMHw5sUkRJ2dsooJbIScNwlxM +brJoiOSQcwgs3vNSk8eK6dzH3zfQGFNdEWj3jjMM5e0 +-> ssh-ed25519 Svnssw +VFbKj457mYT3GXQSacQ13J8MSkYe6A26ssNbqh8LAQ +rJzIG170BcRlsLERhnfaqgRFeAL4Yw7zvtb1gGvUkCU +--- ebIxmIBuNqNgfVWvOJc/0OpFBf3Q7pmApGgHYjrtJI8 +AeO:(7_x0׷ jfV /D.8⿀1ߠ[qf!7ht0Y \ No newline at end of file diff --git a/secrets/darwin-policies-json.age b/secrets/darwin-policies-json.age index 9fa2d2bb8cc42f93a14b737c82f652ccaa1914d0..eabc269965926dde0005b303d3d4c30974d04056 100644 GIT binary patch delta 1127 zcmZ9}`)?Bk003YZ1lb`mVqgLj8!(%!lwPmx+9mSn`fji9yX$%wq1Wrky0V0|*!~ju;5XO)Q#^3$^h40v;FKf3fC^v%$ zNvcbtsIW$Jc9)<|1Z8gqB9O4d zrlFiL3Hb?U?J0axsf+T`kl=76+ zY}QxQMAEO{slx;$8O6kKJ{7e%gP6UQMSV~XOXLv*4f|v-t=Cv-8Hd4?l>=J%Hb%?R z6h=WwCtjfQR58;c;&il_cJVQ_Iw>2R<`fxeZrl3O_@~3!v?El|6|xM+M%;c-5G@&+ zklMfiBGD;t7G5^tl*S#>c|zG{#IL9G5u!Dg#QZsL3Zo66R-grC24dUXC~4N30Lbj)iVjQ6 zkx7%yVUx%Tu6QD6X)UG6QW!U)TsCF5M+Bq675jgHoOCK-lfs(BIVDMxti{69gjr?wI;Gt$i~vBHVd*O{GIPSy|b& zY1xfObE^HP@S{U1;D@TK>TD0}0=JJ1Uf(TjyJ|nk=uh4nSUBqfFtxL~{6Vm1JF~ug3_5?YZp!MRd+l`}9qyRX)l%BbTmyT@ z$~yMLn>AA!8}|+L-FL8O?tOl)Gxh7+^2VP{nc-hrn(~9xr;c5{)w=eMNt^2T)*qQB zE$+);Lma}t7SnXv{uE~)IfDR^(?^%wd`^O2Ua@M~$iVH#Do?3u`|ehlk)b7DPea$7 zD{mOQ?wi}KzVRwKrugI5gvR-|PK>Ty*~=26Cuh}ubB#$nF`pdw%09=9@4H+;-bhqG z0rW4-+Z{jKpV*&Sfw>md*Id5PbA9BiP;uvz_a!)ZYw47O3s-gOzFYro-`|I{ix=r1 zjoW|r%I%@mZ`_^TKS&)a%$Ypg+O7Ne_-~VIr!ODgdfKKUsEi_h8VFaM(6c6ESK5 z!r~8-2tek!WC_e=eA$=@D9r)^!#*r2IPy-r8TM$p>C*`ijb{v`r6eimK}*7VWergn zOKxJMTjK@R;o8@&>qVDX=!Ib*&<)6Lv(@T`R8+6hU_B_99G)zr1R>He?o>^8J(vOv z(_*(g~s zfSML77lZL4?1u_fR4?a2zee~pG$!^3qG>KxQ5k?jWQX9C0UY3vh%YYUxmF{Kp%}y3 zEEb8DDnh9ha+VPkO_yWTXy4Ke89^h%v0xcwz_jfH(uBYvty(@2ZGak~seDqR-I`uZ z!4gV2q?Alry%{sENf6_S<|v*p;<^yVp^EMnsRpH+Mibzb011swE?qyEQTkO;@z;#3 zyN;_Rg~((gC@)~WaFd3#3TXN`w4dS=lFc~6d^MhrxJxA_3oD)q&B0c~E7#Oq&CABB zUWux)X-wweK!9_&T&`{sEcyYq5si>Cl#3R;plCHwqmm@yg43@?sB#DyY)H8@8)B-C zMEc^$*CT6g-`%=u>sTA}eD3^F_V}SoKNd-LS^nytnO0@sy)G&bMq z69N-AAAg>I^Z@P}yLP`}9eaFd|BHc7XN>W}o!K3o!>5-hl<=i}@2xKT`oHt{@IRYZ z9hkF=Pv<^NO`luX*fntC@b@hp+j)G5yl|Od!PSRmmt=N*6Suu%u56rYJM9k+Z4g zKoba&MgVv$9Wz9|ZsHD2$-Xk6*;U*De7;6g7_AS-m57vM*UM0rj*<0Rl3Hyvib+^s zwFr4ByS7g21K!tc2L(e7^Es-2P|I30Fd?F`#IR8+rRGwQvyG4wAjl8Gp;u754ymsw z%#dxv>Um+;%b)|Z-^2|*Di>UJVCl7BxJ=v$J`1_!!kJWL&UMY8Uk>L_wM{i%Z$N~O z4b4ZrQMT-iWrk`z#bTV6b zEW_9=j3~2XCM%#-lo@rft-Ex?5F&{mD^;Z+a)4qfnOw$Q0eEH8lLt;b6T_-nPtBIV ztAUASPzndcn1NCxcy4cAfHSqscYsk|^qZXLC?kuIY@aR!oOMu}YgnZvArs9_=Zi`^ z#AawU1U1yxt1%Y~+$>hxe6zXIrYKbs>k2-~0LkH!x+uk_8U(flRBGUj?{A-Sex&yvoH_sfpBMD+etvuZ&5etX+8=1g z+8du9y{CS1a_jW=%}0M9`S$ahuU>ny|NBUC50!uU`j5}$*mQU<wd2S%Ut05(o~u z9E5TOL#YqU!J6)2=Y#NSD#8kK4I+Rx`=XNQ>Bnny6|95j{lFOH17v*D$qieLy>xu3J z&=AHE7#`rraO^L85}W&o8%>ZpLii3W|CndwIe3ta8f>$c7O-8zvIa0E+Nr_q=BLVIUthcbUnj!o$sZ|nNz}eOS_8bx8y9BN< zaMz^xHe+*GyYl@0sOu;-o}*DpxSS_jTyj*K&ze+E1(&iz;l1&k8+lB*rA5yr$|*^0 zD7qCGZIg9bJf($x!D~%Gh0HwNE6^0}SUi-X>&|R!leljbEYlh`vm`bmbTqa-yA3oN z4Um@*L?euu+Klwg+)Jya*c;QS3tNJSNz!JE5fNm~3ISn&M>p?XetADX{?g9fQ!f_Z zJpXq7XSHAx_FR#)k zy;GOeiyh)Qlsc0<_BH*PaN@@shX+FZ>QmpEAK!ey`z1arvnSKzZ ssh-ed25519 il3lzQ Q+/uqZhUWs5pb5T1ocD+/qTSo4DJbd/W1exruQ34zAE -8HFRvEblGVrkoVaqAl/Af6wrDn6A+3unZIMBipEkwgA --> ssh-ed25519 1g/xww PqXxTvLaF6ZlcVov81VrVH130jFh2iGmHPRtBYV4ME4 -1VBknQzaNZyoz2wvgKX+IZGaOEnJ1xGvxPYxq10ar/U --> ssh-ed25519 +kBihw QXNxY9OQeIM98OqmHoa/S2kMZqSX+ndgxGyCJpHJ+gg -b3DmfUswyPQ09sp57v3QMNEF/Ka3w9Qj2s1kGUSinmQ --> ssh-ed25519 dbKeHw 5GzjKgjUX5e6Net7voWBykC17zRcdSFDFbDsSwp5FAU -GwTEg3YR9HdcQHPg+XjP2Lg1BpcWA4VunbZSBdxVaYU --> ssh-ed25519 Svnssw imRjD5CJu/jOac3t/APHbYBnsyJVQdebR6K52A6GdwM -n+Q9kEEkYRBuEzWlSwbjJNsjF8uKloeUEWYxHa29B4U --> ssh-ed25519 jb0ALQ 4qbGIofHcyhJVfL24peGqqzg0tFdxbWBHJFenwehIAI -Ta3ye4quyHvvE+2CGZwYvQMwWfdrLIdqADLvJYhllPY ---- 3hbht7PYqFafVmcQWQwv3q2gUXM8HXajtmAaMnrh59s - +X984R2,􈱨(#42#*, b禽H_z }߅x7A!))vʞ¨W-eX-G<@~Ek?kGlQK4c&*J9V_0 µz+ɰ¯C ўQGXkg* -jl31JMOE[=S \ No newline at end of file +-> ssh-ed25519 il3lzQ QKUv2QtA6XAVZMc/RET+iJp/IgChWjPnttkT00YNkgo +8wS1EJ6+H+1++dyzEGoq7B7JT7G4wg/NDSNRxDPoRdQ +-> ssh-ed25519 1g/xww I/jn9oDI27fOq7Pf4aMIe10IJUiLz45KQfxbwoV2Yl8 +guK9G+fDLoVxO21YvDeZa14H0gOpm5ma3s+1r7VF77U +-> ssh-ed25519 +kBihw 6uyyp7Jg70FDmlC8Sos+GY/PKPS3QQKR0p1ofODQmC4 +aQDzLv9H54Ucsa3tiVHWhxkV1F83fwNTXIt8k4V5ngs +-> ssh-ed25519 dbKeHw CPQh63MLby86GqOiZv8sxD6qMezQj17fCPLjigCMG0A +OgcvqThhfSUelRy2WZ5eALyJ8uQft8gYdbMuySUi+Ko +-> ssh-ed25519 Svnssw VAK1KKUe7aMf/Rj5r5KnjeobG1JZQXKzNWXjuXpgRyc +Udegl2sZBsVUhN+XwlfSbC1HrKu05uZolm8dsQberuU +-> ssh-ed25519 jb0ALQ M6bx55Kzp4VtQUTq6vkg31JXfew8E+QqHAuXVjFLrxw +wmoYs4tGa56+GuY4r0RtTfXpxW9XTqC2YJlmGsVEHIY +--- wzjCBOS1iGnQe8ZPgaKTs7PZvI0TnRZd11eL7yoaWL0 +$rzGM}(^M؏*lQ̢*U-f7Cc/9~:$ZSR@]htC7y1gaCM !*1B{> oBN& îW_s7&:LK鯵Of׭N1!Vt;QBgRy1j(hv \ No newline at end of file diff --git a/secrets_file.enc b/secrets_file.enc index 20df784..33fcb27 100644 --- a/secrets_file.enc +++ b/secrets_file.enc @@ -1,10 +1,8 @@ $ANSIBLE_VAULT;1.1;AES256 -65366137313461383534313965646333656565353061336361363661613033393264353661346337 -3838653162383134393463323631613439373663396363380a633339396236363962313333343465 -31623961393532666136616438633734366261353866383264323730383432326635626637343739 -3235313062623637380a386235316437396534353261383832643165316565386263396664363962 -62393364333335373631356161373263313930343565626433383539373030363662353630633933 -63336333613965653635313637336437653139616564313861336332323739653865383531356233 -31373530343766343131346663656566363038643230343462336332323135323337353539303763 -33366638393064323431323636346161343936643062323861313766613264336465326132333631 -33306666383561653965303539313366653030663330393363363565333439383133 +33613635643765623937663135313833396162343134383466343966333964386364356134663264 +3137633339396462633431316634623834646437646162360a626564313831373761636161656232 +35316566336232666336646231356665366633303530623961666465366163306166623336656364 +3835353035333031620a633332376237336530343134623832363534383761616564616138363766 +30306361383462353361636161636335313461313835663362393839623735313738316465656537 +66396635323432376530346532353238346139376261366237343763373535623364633731323830 +333730373965613131336166626230333263 diff --git a/secrets_odyssey.enc b/secrets_odyssey.enc index fba7129..a7a96da 100644 --- a/secrets_odyssey.enc +++ b/secrets_odyssey.enc @@ -1,6 +1,9 @@ $ANSIBLE_VAULT;1.1;AES256 -30343638643335363463653231623566623961613534323261393639623865633964653634333562 -3838613035393661656362383736313561366466396439390a383162366362643364636335613664 -39646137666437353762363764373562393736626530333336626261366232383063633732623238 -6531633638366335640a363461383535646663316533386137323966326237373836363561323462 -66646635383137333834363165666365366235333734646364616637383363666239 +61363033383536303833366237323662663236313163663033306138383162383062643830616466 +6531636430613462646161343939343363663533373737340a613433363666353432383463356439 +33656266633131336565613433653062656563656637656464346232656238646339303961373265 +6639643637303433380a393163366331373964353261383662656664643031626432366231346332 +34303964346137616233343930333331306363326332383465653163386539306430303965316437 +30343333373565623431653436653832356366343937653136346535316166383262623730343831 +62376532346237323465653261316339353034323633623632313630666531373839633665333637 +34356162356565396564 diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index db34258..66a74b8 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -15,6 +15,8 @@ in { rig-install ]; + age.secrets.firefox-policy.file = ./../../secrets/darwin-policies-json.age; + # Use a custom configuration.nix location. # $ darwin-rebuild switch -I darwin-config=$HOME/.config/nixpkgs/darwin/configuration.nix environment.darwinConfig = "$HOME/.config/home-manager/configuration.nix"; @@ -130,6 +132,11 @@ in { --user=${config.system.primaryUser} \ --set-home \ _rig-install ${r-version} + + echo "Applying custom defaults..." + /usr/bin/defaults import \ + /Library/Preferences/org.mozilla.firefox \ + ${config.age.secrets.firefox-policy.path} ''; nix.settings.experimental-features = [ "nix-command" "flakes" ]; From 71a086d07e3372078a739ed80cba6cb5b4ac6e15 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 13 Nov 2025 14:36:53 -0600 Subject: [PATCH 010/149] dock (corianne): Remove unavailable Chromium PWAs --- systems/darwin/corianne.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index 66a74b8..582ffdf 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -76,8 +76,6 @@ in { (sysApp "Logseq") (sysApp "Zed") (sysApp "Steam") - (chromeApp "Instinct Dashboard") - (chromeApp "Carestream") ]; show-process-indicators = true; show-recents = false; From be4ce6fe1fbef35c5ac12a63a6967da8cd8fe365 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 16 Nov 2025 18:07:44 -0600 Subject: [PATCH 011/149] pkgs (common): Install agenix cli via overlay --- flake.nix | 2 +- homes/common.nix | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index a5b90d9..3841859 100644 --- a/flake.nix +++ b/flake.nix @@ -61,7 +61,7 @@ pkgs = import nixpkgs { inherit system; config.allowUnfree = true; - overlays = [ nur.overlays.default ]; + overlays = [ nur.overlays.default agenix.overlays.default ]; }; pkgs-unstable = import nixpkgs-unstable { inherit system; diff --git a/homes/common.nix b/homes/common.nix index 2b452dd..a83cb2b 100644 --- a/homes/common.nix +++ b/homes/common.nix @@ -31,6 +31,7 @@ in { }; }; packages = with pkgs; [ + agenix btop cowsay figlet From e094a8ac6a87ea197a04377d350e21c0388dab87 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 16 Nov 2025 18:24:23 -0600 Subject: [PATCH 012/149] config (harmony): Remove Harmony/Asahi configs --- flake.nix | 6 -- homes/harmony.nix | 95 ----------------------------- inventory.yaml | 7 --- playbooks/packages.yaml | 69 ++++++--------------- playbooks/repos.yaml | 31 +--------- secrets.nix | 4 -- secrets/ansible-vault-password.age | 22 +++---- secrets/darwin-policies-json.age | Bin 1214 -> 1104 bytes secrets/network-information.age | 28 ++++----- secrets/pihole.age | Bin 926 -> 816 bytes secrets_harmony.enc | 6 -- 11 files changed, 46 insertions(+), 222 deletions(-) delete mode 100644 homes/harmony.nix delete mode 100644 secrets_harmony.enc diff --git a/flake.nix b/flake.nix index 3841859..680c30b 100644 --- a/flake.nix +++ b/flake.nix @@ -105,12 +105,6 @@ "tchristensen@beocat" = mkHomeConfiguration { hostname = "beocat"; }; - "millironx@harmony" = mkHomeConfiguration { - hostname = "harmony"; - arch = "aarch64"; - desktop = true; - }; - "millironx@odyssey" = mkHomeConfiguration { hostname = "odyssey"; desktop = true; diff --git a/homes/harmony.nix b/homes/harmony.nix deleted file mode 100644 index 2e48431..0000000 --- a/homes/harmony.nix +++ /dev/null @@ -1,95 +0,0 @@ -{ config, lib, pkgs, pkgs-unstable, ... }: { - # harmony is an Asahi Fedora box - # I don't use NixOS, so there are some programs that don't interact well with - # the base system (or won't even install) when installed from Nix. - # There is no uniform way to trigger dnf package installs from Nix, so I'm - # just going to list my packages here. I hope to create a custom script that - # mimics the ideas of a Brewfile someday - # TODO: Create a Brewfile equivalent for dnf - - # dnf repos: - # https://github.com/terrapkg/packages?tab=readme-ov-file - # https://pkgs.tailscale.com/stable/fedora/tailscale.repo - # https://packagecloud.io/filips/FirefoxPWA - - # copr repos: - # iucar/rstudio - - # dnf packages: - # apptainer - # chromium - # firefoxpwa - The nix version installs an "immutable" runtime, which simply launches extra browser windows on non-NixOS - # inkscape - # kate - # kdiff3 - # krita - # lutris - # musescore - # nextcloud-client - # nextcloud-client-dolphin - # obs-studio - # podman-compose - # podman-docker - # qownnotes - # qt - # rssguard - # rstudio-desktop - # steam - # supertuxkart - # tailscale - # thunderbird - # vlc - # vorta - The vorta package is aarch64 compatible, but you cannot see any icons, and it cannot access local ssh keys, so we have to use the dnf package instead - # yakuake - # zed - # zsh - # R - # https://downloads.sourceforge.net/project/mscorefonts2/rpms/msttcore-fonts-installer-2.6-1.noarch.rpm - home = { - username = "millironx"; - homeDirectory = "/home/millironx"; - # Signal desktop is not available in any other package repository for aarch64 linux - # Similarly, Bitwarden is non-functional in all other forms using a 16k page size - packages = with pkgs; [ - trayscale - veracrypt - pkgs-unstable.signal-desktop - pkgs.bitwarden-desktop - ]; - }; - programs = { - git = { - signing = { - key = "0x37A3041D1C8C4524!"; - signByDefault = true; - }; - }; - }; - services = { - gpg-agent = { sshKeys = [ "207D13371E19752A67AA2686C16354D9963821DB" ]; }; - }; - xdg = { - configFile = { - "nextflow.config".text = '' - params { - config_profile_description = 'harmony Asahi Linux local profile' - config_profile_contact = 'Thomas A. Christensen II <25492070+MillironX@users.noreply.github.com>' - config_profile_url = null - - max_memory = 12.GB - max_cpus = 12 - max_time = 7.d - } - - apptainer { - enabled = true - autoMounts = true - } - - process { - executor = 'local' - } - ''; - }; - }; -} diff --git a/inventory.yaml b/inventory.yaml index ba53698..63f1f3c 100644 --- a/inventory.yaml +++ b/inventory.yaml @@ -3,20 +3,13 @@ ungrouped: hosts: localhost: ansible_connection: local - harmony: - ansible_connection: local odyssey: ansible_connection: local -asahi: - hosts: - harmony: - amd64: hosts: odyssey: fedora: hosts: - harmony: odyssey: diff --git a/playbooks/packages.yaml b/playbooks/packages.yaml index 612acde..b3d0947 100644 --- a/playbooks/packages.yaml +++ b/playbooks/packages.yaml @@ -1,55 +1,9 @@ --- -# These are repos and packages that are useless or unavailable on Asahi Linux, -# or have completely separate install procedures. -- name: Configure amd64-specific dnf packages - hosts: amd64 - become: true - tasks: - - name: Install x86-specific dnf packages - ansible.builtin.dnf: - name: - - libdvdcss - - mkvtoolnix - - mpv - - protontricks - - x264 - - x264-libs - state: present - - name: Install VeraCrypt - ansible.builtin.dnf: - name: https://launchpad.net/veracrypt/trunk/1.26.20/+download/veracrypt-1.26.20-Fedora-40-x86_64.rpm - state: present - disable_gpg_check: true - -- name: Configure amd64-specific Flatpaks - hosts: amd64 - become: false - tasks: - - name: Install x86-specific Flatpaks - community.general.flatpak: - name: - - com.bitwarden.desktop - - com.slack.Slack - - dev.deedles.Trayscale - - org.signal.Signal - state: latest - method: user - remote: flathub - -- name: Configure Asahi Linux-specific dnf packages - hosts: asahi - become: true - tasks: - - name: Install aarch64-specific dnf packages - ansible.builtin.dnf: - name: - - veracrypt - -- name: Configure common (all arch) dnf packages +- name: Configure dnf packages hosts: fedora become: true tasks: - - name: Install common (all arch) dnf packages + - name: Install dnf packages ansible.builtin.dnf: name: - chromium @@ -64,15 +18,19 @@ - kdenlive - kdiff3 - krita + - libdvdcss - libjpeg-devel - libpng-devel - libtiff-devel - libwebp-devel + - mkvtoolnix + - mpv - musescore - nextcloud-client - nextcloud-client-dolphin - obs-studio - onedrive + - protontricks - qownnotes - qt - rssguard @@ -82,6 +40,8 @@ - thunderbird - vlc - vorta + - x264 + - x264-libs - yakuake - zed - zsh @@ -92,6 +52,11 @@ name: https://downloads.sourceforge.net/project/mscorefonts2/rpms/msttcore-fonts-installer-2.6-1.noarch.rpm state: present disable_gpg_check: true + - name: Install VeraCrypt + ansible.builtin.dnf: + name: https://launchpad.net/veracrypt/trunk/1.26.20/+download/veracrypt-1.26.20-Fedora-40-x86_64.rpm + state: present + disable_gpg_check: true - name: Install rig (R installation manager) ansible.builtin.dnf: name: https://github.com/r-lib/rig/releases/download/latest/r-rig-latest-1.{{ ansible_architecture }}.rpm @@ -109,19 +74,23 @@ name: "*" state: latest # noqa: package-latest -- name: Configure common (all arch) Flatpaks +- name: Configure Flatpaks hosts: fedora become: false tasks: - - name: Install common (all arch) Flatpaks + - name: Install Flatpaks community.general.flatpak: name: + - com.bitwarden.desktop - com.github.tchx84.Flatseal - com.logseq.Logseq + - com.slack.Slack + - dev.deedles.Trayscale - io.freetubeapp.FreeTube - io.github.alainm23.planify - io.github.dweymouth.supersonic - io.openrct2.OpenRCT2 + - org.signal.Signal - org.zulip.Zulip - net.ankiweb.Anki state: latest diff --git a/playbooks/repos.yaml b/playbooks/repos.yaml index b771518..36b2eb0 100644 --- a/playbooks/repos.yaml +++ b/playbooks/repos.yaml @@ -1,6 +1,6 @@ --- -- name: Configure amd64-specific package repositories - hosts: amd64 +- name: Configure dnf package repositories + hosts: fedora become: true tasks: - name: Install RPM Fusion free repository @@ -20,31 +20,6 @@ - name: Install Zotero COPR repository community.general.copr: name: "mozes/zotero7" - -# Asahi Linux comes with its own strange version of RPMFusion installed, so -# RPMFusion is installed only on amd64 systems. In addition, VeraCrypt and -# Zotero *are* available via COPR, but from different repos than their amd64 -# counterparts. -# Also, Asahi has its own version string, so we have to manually specify the -# chroot for COPR repos added via Ansible. This is handled automatically when -# using `dnf copr enable ...`, but not via Ansible. -- name: Configure Asahi Linux-specific package repositories - hosts: asahi - become: true - tasks: - - name: Install Zotero COPR repository - community.general.copr: - name: "isaksamsten/Zotero" - chroot: "fedora-{{ ansible_distribution_major_version }}-aarch64" - - name: Install VeraCrypt COPR repository - community.general.copr: - name: "architektapx/veracrypt" - chroot: "fedora-{{ ansible_distribution_major_version }}-aarch64" - -- name: Configure common (all arch) package repositories - hosts: fedora - become: true - tasks: - name: Install Tailscale repo ansible.builtin.yum_repository: name: tailscale-stable @@ -110,7 +85,7 @@ register: terra_priority changed_when: terra_priority.rc != 0 -- name: Configure Flathub remote +- name: Configure Flatpack remotes hosts: fedora become: false tasks: diff --git a/secrets.nix b/secrets.nix index c0d5047..1b118dd 100644 --- a/secrets.nix +++ b/secrets.nix @@ -12,15 +12,11 @@ let "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHKKkucebeb1GcerOZAAs5GQsgTS8kXw5W41b9Fy9+hp root@corianne.local"; corianne-millironx = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOgL2lO9RJBdQYANoxGyWXcNKi5/NZkRHHo/rNqaYMc/ millironx@corianne"; - harmony-millironx = - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFBYxsCkw+ObDzIvU8z/rSlYcQx0JIt1bCVxKcDxeNNZ millironx@harmony"; - system-administrators = [ anderson-millironx bosephus-millironx odyssey-millironx corianne-millironx - harmony-millironx ]; in { diff --git a/secrets/ansible-vault-password.age b/secrets/ansible-vault-password.age index d833716..9234dd3 100644 --- a/secrets/ansible-vault-password.age +++ b/secrets/ansible-vault-password.age @@ -1,13 +1,11 @@ age-encryption.org/v1 --> ssh-ed25519 il3lzQ 8BY+QUEGqILKLs6ROw7llEOhx0GgrfFeKDcEgHePUFw -SPiG48tkp5ewFc6/uNj+541B6YJODGmDFEbET2BfoZ0 --> ssh-ed25519 1g/xww HyUG/jNJgHCceV/9vaaoSHc681x6Gg/uY+RIfQxIBxU -6XVufQ4A9r8HPU9QLZ/idx3NjDf+UeKVMhtk9+Awy4E --> ssh-ed25519 +kBihw XjhEk6TF6M5OalqVQNpAemlmgMIJnfuH6M600DnJql0 -3zQPJZcsfnbUqRf5XWTJNbyqMb/rsSBIkS7YlYsyMcs --> ssh-ed25519 dbKeHw nIG5Z+XdJ3dyMxFOxyFMHw5sUkRJ2dsooJbIScNwlxM -brJoiOSQcwgs3vNSk8eK6dzH3zfQGFNdEWj3jjMM5e0 --> ssh-ed25519 Svnssw +VFbKj457mYT3GXQSacQ13J8MSkYe6A26ssNbqh8LAQ -rJzIG170BcRlsLERhnfaqgRFeAL4Yw7zvtb1gGvUkCU ---- ebIxmIBuNqNgfVWvOJc/0OpFBf3Q7pmApGgHYjrtJI8 -AeO:(7_x0׷ jfV /D.8⿀1ߠ[qf!7ht0Y \ No newline at end of file +-> ssh-ed25519 il3lzQ WthM+rK9ntTt0GkP6Z7kuFeOCMkYdY5OkoxtIY8xnk8 +howoRiqpwVW+K4ybhHngRfqobGOqSlye6da6+QJg2xU +-> ssh-ed25519 1g/xww 7iNs/T1MXDvZTtbz3s9Dx8CERfL4TBpn4fwhSv8j+yQ +cHXWpo3FEmkD2867IhdCpG4Pkq+LRkvi54OvTeSQA8s +-> ssh-ed25519 +kBihw HXgixNdqoB102vJDQ74UhC2wUIpYNv21ZvfFRgPmyX4 +09wYp8mUSl0ixLbtbK3E+u/7KVx8bYXTAwbzWN9TX/k +-> ssh-ed25519 dbKeHw PhePJgvp9fRMEJdtYwq3MV+CfNbEs1xJrQefJPQtl3Y +muMZYzYC8aHJBq96Z12pvxA32Cs4KFcG/0YHVT6tX8o +--- lunvYfBDg4+g00hMQJc6ZHQiBQ9k/qubJBYQ+p6aXhc +Ϛ:VnߛTFW=r TvM_=!՟Ǧ~N0 IPem̮.3/T[ \ No newline at end of file diff --git a/secrets/darwin-policies-json.age b/secrets/darwin-policies-json.age index eabc269965926dde0005b303d3d4c30974d04056..258d0b23b1fc8689c6a140a4b33da33f087ce132 100644 GIT binary patch delta 1035 zcmV+m1oZp93D5|TEPrW4Q$jIkY+++^H#1l_acWjeGH-ZyOKop5Y;8ZwgXsNK{aHZew&yGFDMiS2k~TL^DrnG)YloRdz~3Yc^?GR6}=cYHw#qNeV4K zAaiqQEoEdfH8n9gATehzcz1UoWMVZ^F;Fp8HaAXhYDi&ectuGg zR!>1sQ&m<)SwnAFH&$*`R#!4+HCi%uFl}r#Qgc~Pb8uF8WHxA6FjR!}ieS$btvIBRTkZFzrGc|m7uW?C|CHAi?ac5qitWiV({XJS%UMG9|6a8pY! zc{oZiG)7utW;9V#Pj`4mIYnW0IaGRbLpgJ6OKVe2XfZHCK?*G`Eg)2GbV*T2cy2>c zNl!>oT6Zx-Z8Jn!VM|J9Z8>FiLt;i|NK0sKQgAa*K?>CFSFm+bYg2!8>+`^%+YHD_ z;y$vi85eeh+r2o6Li02-7F#8P{JU~ZLsk}ZAb7{7Z?pQC{SQgy4LspddwK;HWbQ4s zfCL`>4eHQ_A3iOTft7F`EcUU}5qpl`q2_n;wI!8JmG&;s%vntWhrT$aC|bdEm!VujJ04X#r1w?;c~q~yv?)|@wzBM zMkq*4+hl8?X4!p!oK&x?OSDPVqI+=G&tROteJJE7of3l|JdOdZA~l({^T<8o=3S6_ zrBA??!eH1GWPL$7F*rE=@^C85^)PTr>{kZ1=MI{KJ5fE?pf7)BN7Z4P<5($4l{hF# zC6N^WM8uJ~Li#aKz8XKxT3XNvB? zyO@=`5L}c*a!X%?UP+v}(cLe+MibLbPU|fN1@kjNml}3}u~z@S9C@}-V*ehz{U{Bz zN|ge(hrBed7?1VI9VX)Gxz92Y&O6cHp}-=Uyr5y%8`l;e)QI~xs21f*{N9B0otHZR F;l8Nys2l(Q delta 1127 zcmZ9|`)?Bk0Kjn^M7Kj?#J~h5Hefc{D7{|WwM*pD^>ux}?yl=$0=-__yX)h6y}MrT zkPI9HhC)zS1Y-z_GXf5k4IP3~(J=u*aDa%W3^72|A%-y|f{~y72foSYd#3t}n$7du zn?Z#32IB#$kdu_G-D7TwCA`Ln)7@$d$L)y_mJa1H8{yBCY=FgOHN-7OK@@N#i71RY zX8~o-Zuh_-13I)m3>PwxPallYETCSb;(1D)AR&W6+oIB@G$lz=*wQf931T2!5(4kq}jzrz=q?j{^vIOc- z+FR0aS$|O*eeKrM5fMqnFe#F!VpeAebF^}(AIf3LJc6JRzv5#IS{tL_9+0x}K#S1E z>NtkRXei~x3rwCaW?Ceii51f>A+FJ+6raI)V62SaJZl^WLchzx&xpn zSu+eFw}C-KW+-0-cgjx5%kVlJVFBI<=LIf-#*4DqZBB(~h}MU&unZQw9O+1DlyEGV z^Mn%to%#Qh!o?iVODan14(q+)Y%>xtF!?CaYLBO|K+Z>Dj1km{jM$WcxHdORS{^1K zi=QvT);OF=lg$yc#EGs%GG}cqrO8qRH=%r%ayX)*$>@r2IrWfYOW}MI$&j4YDlmja zV(q>(sbP4#-lyb^K>~F`4k>9;Xp{#OJ)951o(Qk^mZYMX&M6wjB;rCzMw`qA0nsB( z1zF&{K2#5=)oK+Tu#^IX?13@bu1Q+snXu#z`hxBx=3p5wXks91J4BO&j?L(SswtiG z*Up*l-n`>p^ZxFd8Sw10ZIQ^cRAYrt*B@_OX#>YM-QPataYpw>a8&&3oz>+|@kDt= z_r|5yAIz={oWzd|Q^5BXSH;;8+zDFD6C_Q%RkscZUgm)X(b#a~TD zSD#%!bj?3!kLLO-)&;|fV_#Q zd<+;~n7b=+W+1sQvmA3RtgE_ozW3Vbm*L`$C-2Ih(9I>24=h;OrT=!_H~oJf)GbY}x<*-20x3!i=}ISJuxMn7DUI z^RfNY*dIR~^w&J|{G<(iRlW0>(L?n;J$3azpocy32sw6X_tAzywSrYUx`rn=b diff --git a/secrets/network-information.age b/secrets/network-information.age index bccc467..a1394fe 100644 --- a/secrets/network-information.age +++ b/secrets/network-information.age @@ -1,15 +1,15 @@ age-encryption.org/v1 --> ssh-ed25519 il3lzQ X/F7G7EJbo6QTCGBSp2irApe2qkFUmj2OytrpOVVQ2w -yjitkwkxhNJLxSK4zF25o2lhZO6drBkjwHYykcPnoIw --> ssh-ed25519 1g/xww HriK0yZF3EEh2mB8RpVWBGzuPiK1DB80BeXZAt5Runo -8ke05EDxykN/tu5wEzL3RvRnleBeWKpblm/iXb0pJ8U --> ssh-ed25519 +kBihw bG3XH77yhvMR+HsJMwi1WsXo4aSm5ez80gRlgkTosSo -/WhUI2gKt94naWkeDrXvxnc2fsJvqmcARJnnhrU9sjw --> ssh-ed25519 dbKeHw Bugbp/ovWaODwR6msKnGB3D/dT/ZMmFyr6Za0VAJqBQ -+FfFa1w5/Ok8rIhp+NOBxfqoGFFlGwt8hPhxzibAVf8 --> ssh-ed25519 Svnssw xpuVCV4OJi8G8R5vuSMio9hoRWmufOsCaEyhLMKarh0 -/82i3ZFwQtMonTj4wfa9KPig9qUIJomVYk3QlpB4rJk --> ssh-ed25519 jb0ALQ cbnyjqANs0f/CsiD/peCuJuMJfuaNKIIzbd/87OEV2Y -iQmJxEOQuharrlkiaOdQXnTSUcsq+b7BzSo+G35QJIw ---- eDJuMw4WC33Ihy5OBr2gkeewAFBpCa3gO3CYehr5bOo -VR@X[6gȣl ʑm.P4MiYt̾~ x\Y㒊UMGd܏{'mB,@[e]{NbN] a!*ͬ`YQn95 'q5]-6:FYL$} \ No newline at end of file +-> ssh-ed25519 il3lzQ DhOVslXJ/kZmHvfCLw3rPiRrR1NxTC6zV6Di9WOUY1o +i+OTfk7LWc3rT+T8yFGlPabsgVkddPAr3D6oc5hpe/Y +-> ssh-ed25519 1g/xww xiWVbXWJXtgPLnPWC5bRCvdgceKuY/7wrAbWGlBmZWA +C7rwIOD0xGzTpGRgAycHlspsGaLLwFG6j+6/vPkVtkI +-> ssh-ed25519 +kBihw E2rOacH/0J3YWuplB01z51r/MW3jF36l1C+QeqY6zls +162dh2KpWV71727zPZ2fpS7btQsQ/IL43kuViypZwWc +-> ssh-ed25519 dbKeHw k4ZekrotAzMlC6+RifphXj108iEra0AH4DrCxOSI/gg ++9eibvHzF88lm9Qi/FCfW87D9BW25+zkzQbnhe/F3Rw +-> ssh-ed25519 jb0ALQ Z8WYL7/D990/IWBHGKZInn3Rffol0jnraGQyQbqCdWE +LQa3mmMrA6Qx8wChzlWmB3M2OAtjVep5ryOZH3oZOMA +--- avI87pf1OwXk3BW8w9jW95NK4U/vfUg0pJoqjQ6eCS4 +75l7gϹNU%*-^$z1,4G԰@:~,Se@7p += >H0㭅m7mUW +W-y EÎ8+gM/- z 펈5%l0l صΙ|JEz y=a1jpIQfܝ3 \ No newline at end of file diff --git a/secrets/pihole.age b/secrets/pihole.age index dfe146e15d5f9d48bbcaed9310e1d30094e418cb..3e0bcc96880e77514de21d77a18bf0a24bef5682 100644 GIT binary patch delta 746 zcmZ9|OKZ~r007{6nKLR3L8hQs4_>UbP15usDyE5T(;^XX3_`WmCuM8aDHmMmIzSv~y2(IH= z8RXDhwpE6jNOCV{GKAxHq*x$&I4QK#fMn4f8N^~q1*c616TlP;3ZzWtnSR|SP)Oi- zKg(f0RWX3*?yzNP(S`yc2$%_jYRq%pu!00Wt9ml;St+pI*6O)7W+ip3iu+xKP1<^* zOWCrJOHly|pnklEx0zT=+|NpFpF6MnjWOt2#m+;IwPSImfO+0IRl6g9?}yaJTtL3$isAnkVpp!m@dV} z&0@Z$_uXRI9T8huAw4&~Y70ZmuX|UI-R1h#*Zut(%M<^=+dIb-3TP03~1VnNFU)nFlQK}Md!fH3uY`UY0 zqw!tJ0w?L1QbjbS$`vs!+oA*!_~+nZr)OABENGI=nrUQM85Lo)kj~-BJSvJbaDCfi z;gdMlpX5(8{%m}C@$1%E${s6~F!MD<-Ec(fwzu~!DG3O9zs s@TsBg%a`tL+IM$u|7sfvhf&c&j literal 926 zcmZY5-;3LH008g@QAfca5Bi`Un86t1LT$cn(xelHZF-lsN!ot%t7$+bZIf@3rcK-Y zYAVXX)IEsYgM-_Hdl?7%;^c&Z=tSiZ*%Z_lJq3M`>6khN6%>EJpMSvzJ|?pA)^xbY zW|13A9|{(zkbqqN6c&a~-WnAt3RE!HFZnBoL0(OYFshdIs%D78g0!LFZfjO(BG&17 z-Dwn!6@uuu$0*1#sSGw+WxRm{93N$?4KA3|HM*tH9GRj*yDqn-WxX3nBY0Q?sIW{^ ztXc4;m7v}%(spM~cWu%Xn-(CNE!7oPB*jB}IYXEvcGW+}wMg4Q-^T0N}c{WDS&KCPE zf5L^@Mx)u!<@0$gU3qM+BLkP4LW?oF$mErf?ixvxP^OYG0>BdJEHHZlk$d;WWA7i_ zdi&N7ik`F(;uzpV6%HL)0>^=X^0eyx&vNJ5a zPvPyBQ96!yl&=YqGtK3i*FzWew~Tc@{ovELuKynk`8_xO$5Li+e0NA^yBBJkhd wc=b}pzV_8OKYjK}`%iFmO^Y6e_ujexc?~`I%=u?eOW%Ezf$QGCC!A#eKLx)^)&Kwi diff --git a/secrets_harmony.enc b/secrets_harmony.enc deleted file mode 100644 index e91177d..0000000 --- a/secrets_harmony.enc +++ /dev/null @@ -1,6 +0,0 @@ -$ANSIBLE_VAULT;1.1;AES256 -38383539613238613864336630316433666436623334313334393762396536663530336264306661 -3338616565316138616666343862366638643134343931320a633366363539326461346636373738 -66393138653463663536313065623332383166386332303564323939336630333163623637386434 -6538393966633731660a616437356233643234363562366433663437383439326161353330356331 -63346432663036353332303266343361346266396437396131376531303265356233 From 160c8e82735da607de469cfd10fe4503e61516c7 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 16 Nov 2025 18:24:52 -0600 Subject: [PATCH 013/149] lint (ansible): Fix line length --- playbooks/nix.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/playbooks/nix.yaml b/playbooks/nix.yaml index 672725f..50d9952 100644 --- a/playbooks/nix.yaml +++ b/playbooks/nix.yaml @@ -45,7 +45,8 @@ register: home_manager_exists - name: Init home-manager ansible.builtin.shell: | - /nix/var/nix/profiles/default/bin/nix run home-manager -- switch --flake git+https://code.millironx.com/millironx/nix-dotfiles#{{ ansible_user_id }}@{{ ansible_hostname }} + /nix/var/nix/profiles/default/bin/nix run home-manager -- switch \ + --flake git+https://code.millironx.com/millironx/nix-dotfiles#{{ ansible_user_id }}@{{ ansible_hostname }} when: not home_manager_exists.stat.exists register: home_manager_init changed_when: home_manager_init.rc == 0 From d080b9d480456adbdc33955b6a04c36505c66f33 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 16 Nov 2025 18:25:13 -0600 Subject: [PATCH 014/149] lint (ansible): Fix template reference/location --- playbooks/config.yaml | 2 +- {templates => playbooks/templates}/policies.json | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename {templates => playbooks/templates}/policies.json (100%) diff --git a/playbooks/config.yaml b/playbooks/config.yaml index 4aa2dd4..156dc63 100644 --- a/playbooks/config.yaml +++ b/playbooks/config.yaml @@ -11,7 +11,7 @@ mode: "755" - name: Create Firefox DNS policy ansible.builtin.template: - src: "{{ playbook_dir }}/../templates/policies.json" + src: "policies.json" dest: /etc/firefox/policies/policies.json mode: "644" diff --git a/templates/policies.json b/playbooks/templates/policies.json similarity index 100% rename from templates/policies.json rename to playbooks/templates/policies.json From 65ee23cc363cee37be4ef035c1db8cbecc2e304b Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 16 Nov 2025 18:27:25 -0600 Subject: [PATCH 015/149] activation (common): remove git hash recorder I used to try to control Ansible's bootstrapping of home-manager by recording the current git hash of the home-manager repo, but I haven't allowed ansible to touch home-manager after initial setup for a while now, so remove the hash code. --- homes/common.nix | 8 -------- 1 file changed, 8 deletions(-) diff --git a/homes/common.nix b/homes/common.nix index a83cb2b..61ba3f1 100644 --- a/homes/common.nix +++ b/homes/common.nix @@ -87,14 +87,6 @@ in { }; sessionPath = [ "$HOME/.local/bin" ]; activation = { - recordHmGitHash = lib.hm.dag.entryAfter [ "writeBoundary" ] '' - cd "$HOME/.config/home-manager" || exit 1 - if [ -z "$(${pkgs.git}/bin/git status --porcelain --untracked-files=no)" ]; then - run echo "$(${pkgs.git}/bin/git rev-parse HEAD)" | tee $HOME/.cache/hm-git-hash - else - run echo '*' | tee $HOME/.cache/hm-git-hash - fi - ''; installRunic = lib.hm.dag.entryAfter [ "writeBoundary" ] '' run ${pkgs.julia-bin}/bin/julia --project=@runic --startup-file=no -e 'using Pkg; Pkg.add(name="Runic", version="${runic_version}")' ''; From 9fc8c9a8901e97aee77bddf803794f42f0cd4f54 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 16 Nov 2025 19:29:26 -0600 Subject: [PATCH 016/149] services (borgmatic): Add borgmatic service --- secrets.nix | 16 +++++++++----- secrets/borgmatic-passphrase.age | 15 +++++++++++++ secrets/borgmatic-ssh-config.age | 15 +++++++++++++ services/borgmatic.nix | 37 ++++++++++++++++++++++++++++++++ systems/linux/mcentire.nix | 1 + 5 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 secrets/borgmatic-passphrase.age create mode 100644 secrets/borgmatic-ssh-config.age create mode 100644 services/borgmatic.nix diff --git a/secrets.nix b/secrets.nix index 1b118dd..15c2329 100644 --- a/secrets.nix +++ b/secrets.nix @@ -6,12 +6,14 @@ let "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIxTfeg+GZsfmG8TuEV1xW1gXknAIKzZ3UjZ3guRY+EW root@nixos"; bosephus-millironx = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKaDPqRJHoqgY2pseh/mnhjaGWXprHk2s5I52LhHpHcF millironx@bosephus"; - odyssey-millironx = - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9Aj7BtQp1Roa0tgopDrUo7g2am5WJ43lO1d1fDUz45 millironx@odyssey"; corianne-host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHKKkucebeb1GcerOZAAs5GQsgTS8kXw5W41b9Fy9+hp root@corianne.local"; corianne-millironx = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOgL2lO9RJBdQYANoxGyWXcNKi5/NZkRHHo/rNqaYMc/ millironx@corianne"; + mcentire-host = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINT51tQgsKzTIQc9WSQj01h/gPRvAD3k9jRhXppY7xmd root@nixos"; + odyssey-millironx = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9Aj7BtQp1Roa0tgopDrUo7g2am5WJ43lO1d1fDUz45 millironx@odyssey"; system-administrators = [ anderson-millironx bosephus-millironx @@ -20,10 +22,14 @@ let ]; in { + "secrets/ansible-vault-password.age".publicKeys = system-administrators; + "secrets/borgmatic-passphrase.age".publicKeys = system-administrators + ++ [ mcentire-host ]; + "secrets/borgmatic-ssh-config.age".publicKeys = system-administrators + ++ [ mcentire-host ]; + "secrets/darwin-policies-json.age".publicKeys = system-administrators + ++ [ corianne-host ]; "secrets/network-information.age".publicKeys = system-administrators ++ [ bosephus-host ]; "secrets/pihole.age".publicKeys = system-administrators ++ [ bosephus-host ]; - "secrets/ansible-vault-password.age".publicKeys = system-administrators; - "secrets/darwin-policies-json.age".publicKeys = system-administrators - ++ [ corianne-host ]; } diff --git a/secrets/borgmatic-passphrase.age b/secrets/borgmatic-passphrase.age new file mode 100644 index 0000000..31b7e97 --- /dev/null +++ b/secrets/borgmatic-passphrase.age @@ -0,0 +1,15 @@ +age-encryption.org/v1 +-> ssh-ed25519 il3lzQ NZt+Qn166/k1xA8H+0i40Nf0QUcNoo/mPB4xEsbc52g +WDnvHlN0EAM3kcH4P0w9Fl6LaPYFLK9uhbL2C/asXkQ +-> ssh-ed25519 1g/xww 607VONmCuvQWVfbXOwtW36OrLDSmC1b3FJfcXG8coVk +aKmWBrjrk3cUfGJuEwmuzgiMfeqaDM4sFA9lSEyXb2A +-> ssh-ed25519 +kBihw mUCQloe1iMe4TupQmQRV/SsvDl7GYAy9qNgd/9QuRVs +pl5NvOjZpOmslTm34qhyIY8ihbGfvi5TUMNIN+KftQA +-> ssh-ed25519 dbKeHw mDRPmYMHU/U39xGm+cPt/DDX1VFwJR9q7Ej393eygjc +sneArlOp/HU1N9aXQjGunmcL2lSJ+uUfnLUKJrfuwWY +-> ssh-ed25519 +C0WRg +swZ49g3n/MdCXcaVVN+oJppbhVOeYyVhJBA/0O+zFI +PleOEzaPcOWCQKSULfZ1V8MIcuzS7W0J6KoqSQWuM44 +--- RtNvvt/RSfurXkC29xKp02PWD5+8Ikrdh3JJHzcUECM +r +ǔj &(F-WlEϮ3~K@BO,hJ-^ ,#yڦBn#qִr39PjsgdiÆв?o><^+E4< )K7;/xߎؔ +bh \ No newline at end of file diff --git a/secrets/borgmatic-ssh-config.age b/secrets/borgmatic-ssh-config.age new file mode 100644 index 0000000..cae035c --- /dev/null +++ b/secrets/borgmatic-ssh-config.age @@ -0,0 +1,15 @@ +age-encryption.org/v1 +-> ssh-ed25519 il3lzQ +g4/yAloij23EO70Lwv3NHdzUlI3yM17V+GZVet+DB4 +KoJqTEeF5ol4q+ZwcO+bWsP+hKszCMAUrok0yU+L6WU +-> ssh-ed25519 1g/xww aGc6VKpwoGQyjsPxc4hFPqc5sTzpOx/p7AJL2otF3QE +u5gZXqSUKLMxKsekgixy5h57GZVmIXChnxOTq5iFv9o +-> ssh-ed25519 +kBihw FESLL/bEja1rrQm4V2VIFM9pEuP8ydNSiHgatiEqWDk +Y5D1RoMCKuX3HxUpebwNUgJFQJnJR0GILNeg2DOPaDs +-> ssh-ed25519 dbKeHw EiccNUjhFewzAI+OWDrZnGNZbY1uoP99EJhvDn3AKyw +QQohrq0jZJIwXGkycvn7Q4JFJmkhUwxXZEB5HN217Tg +-> ssh-ed25519 +C0WRg rbfEQSHbKDIvm6p2o9CiJIMNRFWlKaQE7TALCdgauzs +6NWlDEKfWnYHFwleqOF6fSOzjxNkjdBFeFRl1Cj1L9A +--- E6T4y6crIEiWxE3G9OOQDrRky4919i7FM0zDnPiqUH4 +d bt=p(Wwx9r }&l +g`ep~kP$vUH"-,4&Nh#%8]@(I BJY 4eQs"wNr-Cmqx +!q \ No newline at end of file diff --git a/services/borgmatic.nix b/services/borgmatic.nix new file mode 100644 index 0000000..28b1b45 --- /dev/null +++ b/services/borgmatic.nix @@ -0,0 +1,37 @@ +{ pkgs, config, ... }: { + + # We don't want to expose the location where borg backups are going, so we + # will setup an encrypted ssh config that references the host/username + # combo as simply 'borgserver' + age.secrets = { + borgmatic-ssh-config = { file = ./../secrets/borgmatic-ssh-config.age; }; + borgmatic-passphrase = { file = ./../secrets/borgmatic-passphrase.age; }; + }; + + services.borgmatic = { + enable = true; + + # This is the bare-bones way to get Borgmatic up and running. Other services + # are expected to declare their stateful directories by adding to + # `services.borgmatic.configurations."${config.networking.hostName}".source_directories` + # and to add their databases to + # `services.borgmatic.configurations."${config.networking.hostName}".[mariadb|postgresql|etc]_databases` + + configurations."${config.networking.hostName}" = { + source_directories = [ "/home" "/root" ]; + repositories = [{ + label = "${config.networking.hostName}-default"; + path = "ssh://borgserver/./repo"; + }]; + ssh_command = + "${pkgs.openssh}/bin/ssh -F ${config.age.secrets.borgmatic-ssh-config.path}"; + encryption_passcommand = + "${pkgs.coreutils}/bin/cat ${config.age.secrets.borgmatic-passphrase.path}"; + retention = { + keep_daily = 7; + keep_weekly = 4; + keep_monthly = 6; + }; + }; + }; +} diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 07135d1..60fd158 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -4,6 +4,7 @@ imports = [ # Include the results of the hardware scan. ./hardware-configuration/mcentire.nix ./../../services/nixos-update.nix + ./../../services/borgmatic.nix ./../../services/crowdsec.nix ]; From ac57a31f06f41f67eb990d655f009e0e3277ee60 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 16 Nov 2025 19:39:29 -0600 Subject: [PATCH 017/149] lint (borgmatic): Move retention to global scope --- services/borgmatic.nix | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/services/borgmatic.nix b/services/borgmatic.nix index 28b1b45..c028df2 100644 --- a/services/borgmatic.nix +++ b/services/borgmatic.nix @@ -27,11 +27,9 @@ "${pkgs.openssh}/bin/ssh -F ${config.age.secrets.borgmatic-ssh-config.path}"; encryption_passcommand = "${pkgs.coreutils}/bin/cat ${config.age.secrets.borgmatic-passphrase.path}"; - retention = { - keep_daily = 7; - keep_weekly = 4; - keep_monthly = 6; - }; + keep_daily = 7; + keep_weekly = 4; + keep_monthly = 6; }; }; } From 4a8ddb0784e7242f9aa21cd3f27d0016d17d8c6e Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 19 Nov 2025 09:05:53 -0600 Subject: [PATCH 018/149] pkg (desktop): Remove ghostty --- homes/desktop.nix | 1 - playbooks/packages.yaml | 1 - programs/ghostty.nix | 19 ------------------- systems/darwin/corianne.nix | 1 - 4 files changed, 22 deletions(-) delete mode 100644 programs/ghostty.nix diff --git a/homes/desktop.nix b/homes/desktop.nix index 2a0790c..03229ed 100644 --- a/homes/desktop.nix +++ b/homes/desktop.nix @@ -2,7 +2,6 @@ imports = [ ./../programs/firefox.nix - ./../programs/ghostty.nix ./../programs/zed.nix ./../services/gpg-agent.nix ]; diff --git a/playbooks/packages.yaml b/playbooks/packages.yaml index b3d0947..d7a60d7 100644 --- a/playbooks/packages.yaml +++ b/playbooks/packages.yaml @@ -11,7 +11,6 @@ - fontconfig-devel - freetype-devel - fribidi-devel - - ghostty - inkscape - jq - kate diff --git a/programs/ghostty.nix b/programs/ghostty.nix deleted file mode 100644 index bd91415..0000000 --- a/programs/ghostty.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ pkgs, ... }: { - programs.ghostty = - let modifierKey = if pkgs.stdenv.isDarwin then "cmd" else "ctrl"; - in { - enable = true; - package = null; - enableBashIntegration = true; - enableZshIntegration = true; - settings = { - quick-terminal-position = "top"; - quick-terminal-screen = "main"; - quick-terminal-autohide = true; - quick-terminal-size = "50%,50%"; - keybind = "global:${modifierKey}+backquote=toggle_quick_terminal"; - macos-hidden = "always"; - linux-cgroup = "always"; - }; - }; -} diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index 582ffdf..e8292b7 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -192,7 +192,6 @@ in { "dolphin" "firefox" "freetube" - "ghostty" "inkscape" "iterm2" "logi-options+" From c8a1aa969263181c4483ea4b7e41e6f149e0d8cb Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 19 Nov 2025 09:12:53 -0600 Subject: [PATCH 019/149] addons (firefox): Install plasma-integration only on Linux --- programs/firefox.nix | 91 +++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/programs/firefox.nix b/programs/firefox.nix index 520a4ef..d5925d8 100644 --- a/programs/firefox.nix +++ b/programs/firefox.nix @@ -1,4 +1,4 @@ -{ firefox-addons, buildFirefoxXpiAddon, lib, ... }: { +{ pkgs, firefox-addons, buildFirefoxXpiAddon, lib, ... }: { programs.firefox = { enable = true; package = @@ -31,49 +31,52 @@ }; }; containersForce = true; - extensions.packages = with firefox-addons; [ - bitwarden - multi-account-containers - floccus - libredirect - old-reddit-redirect - plasma-integration - pwas-for-firefox - ublock-origin - user-agent-string-switcher - web-archives - zotero-connector - (buildFirefoxXpiAddon rec { - pname = "always_in_container"; - version = "1.0.7"; - addonId = "{a1e9543e-5f73-4763-b376-04e53fd12cbd}"; - url = - "https://addons.mozilla.org/firefox/downloads/file/4032840/${pname}-${version}.xpi"; - sha256 = "sha256-bLxjL2P6Sd06q98MSHYRTNigtcjGwn/C2r4ANWCqKrw="; - meta = with lib; { - homepage = "https://github.com/tiansh/always-in-container"; - description = - "Chose a container every time you try to open a page out of a container"; - license = licenses.mpl20; - platforms = platforms.all; - }; - }) - (buildFirefoxXpiAddon rec { - pname = "open_with"; - version = "7.2.6"; - addonId = "openwith@darktrojan.net"; - url = - "https://addons.mozilla.org/firefox/downloads/file/3831723/${pname}-${version}.xpi"; - sha256 = "sha256-f9eGhLxg4UyVn4o5e4DRkraLWzj11SGto/GOwsJa9kg="; - meta = with lib; { - homepage = "https://darktrojan.github.io/openwith/"; - description = - "Quickly test out your web pages in Chrome, Edge, Safari, or Opera. Open With opens the current page in your other browsers with just two clicks."; - license = licenses.mpl20; - platforms = platforms.all; - }; - }) - ]; + extensions.packages = with firefox-addons; + [ + bitwarden + multi-account-containers + floccus + libredirect + old-reddit-redirect + pwas-for-firefox + ublock-origin + user-agent-string-switcher + web-archives + zotero-connector + (buildFirefoxXpiAddon rec { + pname = "always_in_container"; + version = "1.0.7"; + addonId = "{a1e9543e-5f73-4763-b376-04e53fd12cbd}"; + url = + "https://addons.mozilla.org/firefox/downloads/file/4032840/${pname}-${version}.xpi"; + sha256 = "sha256-bLxjL2P6Sd06q98MSHYRTNigtcjGwn/C2r4ANWCqKrw="; + meta = with lib; { + homepage = "https://github.com/tiansh/always-in-container"; + description = + "Chose a container every time you try to open a page out of a container"; + license = licenses.mpl20; + platforms = platforms.all; + }; + }) + (buildFirefoxXpiAddon rec { + pname = "open_with"; + version = "7.2.6"; + addonId = "openwith@darktrojan.net"; + url = + "https://addons.mozilla.org/firefox/downloads/file/3831723/${pname}-${version}.xpi"; + sha256 = "sha256-f9eGhLxg4UyVn4o5e4DRkraLWzj11SGto/GOwsJa9kg="; + meta = with lib; { + homepage = "https://darktrojan.github.io/openwith/"; + description = + "Quickly test out your web pages in Chrome, Edge, Safari, or Opera. Open With opens the current page in your other browsers with just two clicks."; + license = licenses.mpl20; + platforms = platforms.all; + }; + }) + ] ++ (if pkgs.stdenv.hostPlatform.isDarwin then + [ ] + else + [ plasma-integration ]); search = { default = "Kagi"; privateDefault = "Milliron X Search"; From f9672236f53cc3f551740a23c5182378f02f5077 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 19 Nov 2025 09:13:25 -0600 Subject: [PATCH 020/149] addons (firefox): Remove Floccus addon --- programs/firefox.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/programs/firefox.nix b/programs/firefox.nix index d5925d8..974f27c 100644 --- a/programs/firefox.nix +++ b/programs/firefox.nix @@ -35,7 +35,6 @@ [ bitwarden multi-account-containers - floccus libredirect old-reddit-redirect pwas-for-firefox From ac6c552339c12c358fe0a07298226f28226c9049 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 19 Nov 2025 09:15:18 -0600 Subject: [PATCH 021/149] pkgs (firefoxpwa): Remove Firefox PWAs --- playbooks/packages.yaml | 1 - playbooks/repos.yaml | 8 -------- programs/firefox.nix | 3 --- systems/darwin/corianne.nix | 1 - 4 files changed, 13 deletions(-) diff --git a/playbooks/packages.yaml b/playbooks/packages.yaml index d7a60d7..58e7263 100644 --- a/playbooks/packages.yaml +++ b/playbooks/packages.yaml @@ -7,7 +7,6 @@ ansible.builtin.dnf: name: - chromium - - firefoxpwa - fontconfig-devel - freetype-devel - fribidi-devel diff --git a/playbooks/repos.yaml b/playbooks/repos.yaml index 36b2eb0..476dfdb 100644 --- a/playbooks/repos.yaml +++ b/playbooks/repos.yaml @@ -28,14 +28,6 @@ enabled: true gpgcheck: true gpgkey: https://pkgs.tailscale.com/stable/fedora/repo.gpg - - name: Install FirefoxPWA repository - ansible.builtin.yum_repository: - name: firefoxpwa - description: FirefoxPWA repository - baseurl: https://packagecloud.io/filips/FirefoxPWA/fedora/$releasever/$basearch - gpgcheck: true - gpgkey: https://packagecloud.io/filips/FirefoxPWA/gpgkey - enabled: true # Note that I still have to specify the chroot for COPR repos b/c of Asahi - name: Install RStudio copr repository community.general.copr: diff --git a/programs/firefox.nix b/programs/firefox.nix index 974f27c..d4b98e5 100644 --- a/programs/firefox.nix +++ b/programs/firefox.nix @@ -37,7 +37,6 @@ multi-account-containers libredirect old-reddit-redirect - pwas-for-firefox ublock-origin user-agent-string-switcher web-archives @@ -248,7 +247,6 @@ "floccus_handmadeideas_org-browser-action" "7esoorv3_alefvanoon_anonaddy_me-browser-action" "plasma-browser-integration_kde_org-browser-action" - "firefoxpwa_filips_si-browser-action" "_d07ccf11-c0cd-4938-a265-2a4d6ad01189_-browser-action" # Web Archives "openwith_darktrojan_net-browser-action" "zotero_chnm_gmu_edu-browser-action" @@ -284,7 +282,6 @@ "floccus_handmadeideas_org-browser-action" "7esoorv3_alefvanoon_anonaddy_me-browser-action" "plasma-browser-integration_kde_org-browser-action" - "firefoxpwa_filips_si-browser-action" "ublock0_raymondhill_net-browser-action" "_d07ccf11-c0cd-4938-a265-2a4d6ad01189_-browser-action" "zotero_chnm_gmu_edu-browser-action" diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index e8292b7..e4d4447 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -182,7 +182,6 @@ in { "docker" "docker-buildx" "docker-credential-helper" - "firefoxpwa" "mpv" ]; casks = [ From 8d188dea43d8e0d3fe3d203e91906b261330f4ae Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 19 Nov 2025 09:27:19 -0600 Subject: [PATCH 022/149] addons (firefox): Remove web archives addon --- programs/firefox.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/programs/firefox.nix b/programs/firefox.nix index d4b98e5..ed6705f 100644 --- a/programs/firefox.nix +++ b/programs/firefox.nix @@ -39,7 +39,6 @@ old-reddit-redirect ublock-origin user-agent-string-switcher - web-archives zotero-connector (buildFirefoxXpiAddon rec { pname = "always_in_container"; From 4a9eed6ecb2b9a122be0ddc4495e028e0918750a Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 24 Nov 2025 10:34:08 -0600 Subject: [PATCH 023/149] brew (corianne): Remove LogiOptions app --- systems/darwin/corianne.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index e4d4447..d294dcf 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -193,7 +193,6 @@ in { "freetube" "inkscape" "iterm2" - "logi-options+" "logseq" "macfuse" "musescore" From b6b514278ecf22d61780e8ace9935252ee8c2598 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 24 Nov 2025 11:02:47 -0600 Subject: [PATCH 024/149] defaults (Dock/Taskbar): Make taskbar and dock have the same Apps Except for Steam, because Steam is weird and will spawn extra windows that don't play well with Taskbar. --- programs/taskbar.nix | 6 ++++++ systems/darwin/corianne.nix | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/programs/taskbar.nix b/programs/taskbar.nix index 757d42d..cff7787 100644 --- a/programs/taskbar.nix +++ b/programs/taskbar.nix @@ -25,6 +25,10 @@ bundleIdentifier = "org.mozilla.thunderbird"; action = "launchOrActivateApp"; } + { + bundleIdentifier = "com.microsoft.Outlook"; + action = "launchOrActivateApp"; + } { bundleIdentifier = "dev.zed.Zed"; action = "launchOrActivateApp"; @@ -34,11 +38,13 @@ action = "launchOrActivateApp"; } { + # Instinct dashboard bundleIdentifier = "com.apple.Safari.WebApp.2F51A6D0-087A-438F-92D3-A73FE09CB4CC"; action = "launchOrActivateApp"; } { + # Carestream bundleIdentifier = "com.apple.Safari.WebApp.5EC6478E-03A6-4147-8A4D-6EF3DE3F06D3"; action = "launchOrActivateApp"; diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index d294dcf..dea0f34 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -73,9 +73,12 @@ in { in [ (sysApp "Firefox") (sysApp "Thunderbird") - (sysApp "Logseq") + (sysApp "Microsoft Outlook") (sysApp "Zed") + (sysApp "Logseq") (sysApp "Steam") + (localApp "Instinct Dashboard") + (localApp "Carestream") ]; show-process-indicators = true; show-recents = false; From f2069cacb9d3d5687da98ee9df494e9362b780b1 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 28 Nov 2025 10:40:10 -0600 Subject: [PATCH 025/149] secrets: Add mcentire-millironx ssh key --- secrets.nix | 5 ++++- secrets/ansible-vault-password.age | Bin 575 -> 685 bytes secrets/borgmatic-passphrase.age | Bin 781 -> 891 bytes secrets/borgmatic-ssh-config.age | 28 +++++++++++++-------------- secrets/darwin-policies-json.age | Bin 1104 -> 1214 bytes secrets/network-information.age | 30 +++++++++++++++-------------- secrets/pihole.age | Bin 816 -> 926 bytes 7 files changed, 34 insertions(+), 29 deletions(-) diff --git a/secrets.nix b/secrets.nix index 15c2329..1de9bc8 100644 --- a/secrets.nix +++ b/secrets.nix @@ -12,13 +12,16 @@ let "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOgL2lO9RJBdQYANoxGyWXcNKi5/NZkRHHo/rNqaYMc/ millironx@corianne"; mcentire-host = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINT51tQgsKzTIQc9WSQj01h/gPRvAD3k9jRhXppY7xmd root@nixos"; + mcentire-millironx = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOdC6eNx2nBi3PWK/n4GJMbVf+NlQJv13aUqxse/h1kL millironx@mcentire"; odyssey-millironx = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9Aj7BtQp1Roa0tgopDrUo7g2am5WJ43lO1d1fDUz45 millironx@odyssey"; system-administrators = [ anderson-millironx bosephus-millironx - odyssey-millironx corianne-millironx + mcentire-millironx + odyssey-millironx ]; in { diff --git a/secrets/ansible-vault-password.age b/secrets/ansible-vault-password.age index 9234dd3799ef7952f74be2fc64c5ee3c7388333d..c5b657899971cdff5c4f51077d04eee9528417c7 100644 GIT binary patch literal 685 zcmZY5JFk;q0LF0#Czi81Xe3T5sRc?~a4>1}(leD5`F<&a$dAa=IFw1@WdJEx1l~QD6}gmSh?2ZMj@e2wt19P}5{h%#^}o z*Bb~H5@kMH!&%Sa!yy;b(h!qHjTMG|_xRl9Zm{DlqM#ak13tsGA!S zg0GfjwRgwau*RA;iZiQG`0(P_Bz zcf52Fqlu(eqJ01 zGdL}Eq}S`AY_vayfxLCK!Ydj8j48&=EvXWOd7sL-PDF*62Pz=FS(=@9WRL HhJU+%Y*pp< delta 503 zcmV~$yN{D_007_^&xNS#O(u25%Ci(q&ZN*%N(%)_3qKr8DNkv66biJ%UG6{7nmFiS zTue;#mKz)#92{;r&&k=*#7zfX{k{)3J|8^2cVZNQ1h0ooT<8Vbj}*#kM;qQ9b5aBx z&>BZcT?_zS#}N$$NtI|}mR2(Z9+F!-5Mp2Rvc&F>v&nMnQqG)$Rnf=mDb#$}$n&7- zI(VyvF%8T|>Z)qALpeuuOftKrr5E;&;B%&1(_ByUMx@TBG3iyoq@gT#Cu)bzpMSk}Xb7es*0Pf&EQaEx*j3x)G~n=R zI!J+B;+R!>yyh#btw};CQ-PFTO(#n`7&k_C2vqvwLiW(;Lvcv{vS z0_Spa$S?W`3WS+X6(*fP&1SQ)+{7jD*sf2)K8gmCDlRBXP(xN_A|%_`A`3(nPN}&W zETEs?ULHJ{-FY8h{djey^Vf}|7k}25H!t*3`uq6k?)mrE`-`{xWBL5{DSB)0NqOh4 TKAv5ky}AEuPki}@=#Tyb(ao?* diff --git a/secrets/borgmatic-passphrase.age b/secrets/borgmatic-passphrase.age index 31b7e9786d18fa414940ff9583e1c5a3e362d7bb..ba13eb39250c07f4450f6815c5c08ecb87d3ddba 100644 GIT binary patch literal 891 zcmZY6&&%6%0LO6$gF!*WgD5H(+3BIw{A$vKxo5OZ)1>LIG)cd0Rj_HAZ+$HIcx@FyG{sAmT_ldJ%F-Yx3TF}9BfUaKHofW0!zMFo+Z}cjVLj;TM%^5wKtwri zsmzm3+mzLoJr1U&iO2YDC2atQf*sJsT#e=YEkBo4uA?{W%rp-Iw6+>#aduS0A-c^n zgjZb1FJiadFVbE(as4eZWyTgYb?T@RxelHam}_f31F+I)G#QuOM!UHYb-9{=FiNeF z#h0gcSIlu^h6@nTb?e0mK3F+cT%cvkbUKF;RrHrz7R5QH-;&b>Tu=D5%+ zMYR}ISFj2#s1I#`3#`-HNM(*EsAY3$thup0UV}D$_|X5fCI&_jS;LK#ND774jEHL# z10xqyk)#)O%M@wHiA|mqU~4Rsd{*j=Ib~{wMgvS0QpfqtVPXv@V>Zxc%ocaDjEuvG zP{r!uwn_yFHlvnC8QMg2>;_|{*Pljznp)!edpL$ z)ZU9f@BVu2!I^(Pesq2RyKfJ6pS((Z_VktKzI?f}bG+nY(dWi*f6?NFA6^%@(_dhp KoUL9s@zj6RnmmXA literal 781 zcmZY4OKZ~r003Zo3^WP@L2zCy3`B`FNs~T;Lv7RakuqEUg20Sxtwb`3;4#Za?XeJJ=lY=FBB>PAL5A5(34|>SW_4H)Ro3$$htFX{GEmfH z!T{vFJ1E&KOlBFhqn0opj_`t=sxurDUvmgVK?{_w){7a{lR7|?cI2Gj_B*I5>P0FfBPSdi7NcvuW}d-< zLKe4cB%=7R z=zuEUhw}M4A{8R4iuclF8^uv=WVBTvaJ8&&b6uz;A}rpl3+-a)I%*|h*C;R)b+;nY zl&^=8+}Ly@V7Y3+;Hz(ZfGy)^2^coxAtwsXP7S{m0&cclUkt zGtRezea60TE$i9Y`PJ9=zV3f@;==8V-tqG@r{03wN$mXoEi-@r>^e-Rk6nlE+<3e) dJh!s;>B_aKrG@#4$@QxXmjUJbyg9YB>mLnZ6Da@y diff --git a/secrets/borgmatic-ssh-config.age b/secrets/borgmatic-ssh-config.age index cae035c..ba01275 100644 --- a/secrets/borgmatic-ssh-config.age +++ b/secrets/borgmatic-ssh-config.age @@ -1,15 +1,15 @@ age-encryption.org/v1 --> ssh-ed25519 il3lzQ +g4/yAloij23EO70Lwv3NHdzUlI3yM17V+GZVet+DB4 -KoJqTEeF5ol4q+ZwcO+bWsP+hKszCMAUrok0yU+L6WU --> ssh-ed25519 1g/xww aGc6VKpwoGQyjsPxc4hFPqc5sTzpOx/p7AJL2otF3QE -u5gZXqSUKLMxKsekgixy5h57GZVmIXChnxOTq5iFv9o --> ssh-ed25519 +kBihw FESLL/bEja1rrQm4V2VIFM9pEuP8ydNSiHgatiEqWDk -Y5D1RoMCKuX3HxUpebwNUgJFQJnJR0GILNeg2DOPaDs --> ssh-ed25519 dbKeHw EiccNUjhFewzAI+OWDrZnGNZbY1uoP99EJhvDn3AKyw -QQohrq0jZJIwXGkycvn7Q4JFJmkhUwxXZEB5HN217Tg --> ssh-ed25519 +C0WRg rbfEQSHbKDIvm6p2o9CiJIMNRFWlKaQE7TALCdgauzs -6NWlDEKfWnYHFwleqOF6fSOzjxNkjdBFeFRl1Cj1L9A ---- E6T4y6crIEiWxE3G9OOQDrRky4919i7FM0zDnPiqUH4 -d bt=p(Wwx9r }&l -g`ep~kP$vUH"-,4&Nh#%8]@(I BJY 4eQs"wNr-Cmqx -!q \ No newline at end of file +-> ssh-ed25519 il3lzQ 9QYGvIhYSyGcFmNdjK6qo2PnX+/t4LnU7eO3+TilFk8 +/6TLFd43tAdI5JKOPVk5YgBLzqdoc++CHtpYqBVMus8 +-> ssh-ed25519 1g/xww RV80BUKnJCyP2CsExGXqnEmXk1XAPkSyVEN+hByUcDo +IpbyT1t33/DCt8iP3Jy64FC88SqQTeTLB1bur3g5qzk +-> ssh-ed25519 dbKeHw CjnqCn7n/6pLpSaF7Q1u2vFBoLOswOaYSoQYwEu0yik +CSykNB4CmGuLWURDJWSAhtAhLcJ4iaeaYNKVsG9w/S4 +-> ssh-ed25519 3qPtug yNNOpEPutJhoRfkXQVnyUJ28Rtyh0oSClXLBVT77mWQ +Yr5TcwBZZbskLUmudPYnyIFvtcxbe+xKnde/5fAW4Dg +-> ssh-ed25519 +kBihw wf+3MXdvYBGBXUci/SiBfL+VPbVkuM1kl9jOHOxr9x8 +3Cgmhh7uI/Hrv3474FrkqspOx0kooNZcG5untJguvYI +-> ssh-ed25519 +C0WRg XJILB7Fa+o5NQPy+sQTt5z5S/WcxzEKTqR4dadFnphU +sdrs/Yf2lf14Dy22hFpzaTgCwvaDaWaXWMlERS58izk +--- 8zj6q3V/OQPbTiHOfin0sXT9gbVNYMCRSWoXMKxYFDo +PVzRbc1Q1T:rU kbXTk䑡ɧ釣ךUG XRl~ҷ8B:.:z?ɐıxED OמQ} `uPI3p|W!3U{mG2F7T)2 \ No newline at end of file diff --git a/secrets/darwin-policies-json.age b/secrets/darwin-policies-json.age index 258d0b23b1fc8689c6a140a4b33da33f087ce132..77d73854bd711eab398e705e736311d2fd8e19b0 100644 GIT binary patch delta 1128 zcmZ9|`*YI-003a&P_S|cjK|Rsg-LkOc z_q$R`hDkuQ-UlK9KT;Jl8YN325vss*xCw_aN7`8L0mD{a1*X%kSRq%(X8}6uF-sCt z&ADkpZtzNavZfxh;CfPYn#@|ts?sf0%d(&ghai&)tWbkdeLj~{Hv~g?PAfa|F`mf* zT-Jx9R@m)}b6}APhhQK;GjSK3#6+hJQ4uto5=1PND9%p*YvD@s_{PDKTe z%8o%|m7|KUNK+IKrG*NwJxufZIzv*>BA##-$+%+(kYfc1JVem#a6rzWb=-si~K-*YEaUInuj)WYOt8s~63i z{O`72=J51p^=Ge^9*nho56*2q z`7(Q<@6qJ)-JAA8-*VbDB2fA0^!Bd5cdfb~r!?mLl|uht4_dCRU9#cUq?IF!*@08ZwgXsNK{aHZew&yGFDMiS2k~TL^DrnG)YloRdz~3Yc^?GR6}=cYHw#qNeV4K zAaiqQEoEdfH8n9gATehzcz1UoWMVZ^F;Fp8HaAXhYDi&ect%M=V|s6AdRcX4b4WLM zc{ep!X=F-dGgVbM3Suy0H)%LHFh^l!Xm4gTayDjUMpZ#KW^XcTFEUa~Mp1G{Q!!U{ zIZjGzlg$AaS9(x0H%(JZOj>JjR&i-KaCJ08PDxX8Zgg0Bb1^V-NLoT{H)l6;Idg3| z3VK#gK~GavRz+DuZ&){0Zd6uRGG;YeGIlU+Y&BAISx<9tR(NDKXjm{=k?|LQM>$$- zQBp~2VP$hiSwm+;WlTs|Zc0LFb7*N$T4-)-OGM5VrDc^Q%`qzMma@cbvaaeazi9fSgpXt4p*=)uMZF*3V#^zkMj=C!G?5A3Tl$tRgj;we!e5;^tkD zdZkammcn4z6l8rtIWagm{qk@s%=IvEN$gh!w&xC-gF8_@*Pt(dW=GXwn&Vh0NtHM# zNhOgK|3t)*xkCCqx7E6~(YFVzonXt!LP|mp!Y5ProF?(;a$-swts#8Gr=7jcki6|> zDg^la9rgs)86Du~gQcAS?&c)(J>lT)1Q?QgnS@u8*jmFQbe`*Nk?O92>}PKf9A}E| zz`K~0yAWKIL~=`CgkDLUxzXJ(yhan#O-}1A1qJgnK$jYJfU#Epz8rbBP-6ccy!|K* zv`Uo%wuihlt{9K?$sH!*>ABA`5zaf&-=V-FnY^H3*BjRsAJmBZH>einOZ?u1^qrSG G0O7t}|ETr= diff --git a/secrets/network-information.age b/secrets/network-information.age index a1394fe..c35cd60 100644 --- a/secrets/network-information.age +++ b/secrets/network-information.age @@ -1,15 +1,17 @@ age-encryption.org/v1 --> ssh-ed25519 il3lzQ DhOVslXJ/kZmHvfCLw3rPiRrR1NxTC6zV6Di9WOUY1o -i+OTfk7LWc3rT+T8yFGlPabsgVkddPAr3D6oc5hpe/Y --> ssh-ed25519 1g/xww xiWVbXWJXtgPLnPWC5bRCvdgceKuY/7wrAbWGlBmZWA -C7rwIOD0xGzTpGRgAycHlspsGaLLwFG6j+6/vPkVtkI --> ssh-ed25519 +kBihw E2rOacH/0J3YWuplB01z51r/MW3jF36l1C+QeqY6zls -162dh2KpWV71727zPZ2fpS7btQsQ/IL43kuViypZwWc --> ssh-ed25519 dbKeHw k4ZekrotAzMlC6+RifphXj108iEra0AH4DrCxOSI/gg -+9eibvHzF88lm9Qi/FCfW87D9BW25+zkzQbnhe/F3Rw --> ssh-ed25519 jb0ALQ Z8WYL7/D990/IWBHGKZInn3Rffol0jnraGQyQbqCdWE -LQa3mmMrA6Qx8wChzlWmB3M2OAtjVep5ryOZH3oZOMA ---- avI87pf1OwXk3BW8w9jW95NK4U/vfUg0pJoqjQ6eCS4 -75l7gϹNU%*-^$z1,4G԰@:~,Se@7p -= >H0㭅m7mUW -W-y EÎ8+gM/- z 펈5%l0l صΙ|JEz y=a1jpIQfܝ3 \ No newline at end of file +-> ssh-ed25519 il3lzQ YxgllrvBeqfXMCWKq2JF9aqyoq5CUTHXW5Y/DhxEDzE +55NxukxXnmQ27WqW/yjkvTLd/3QmcO8uxCxsGu95rHM +-> ssh-ed25519 1g/xww yIGdDpxlTv5I1LyueRLGY4LxpKHIYDVEN/fkcMlNvD4 +0vvuzTeqH59Kw+JFzmITJI8bgEevwJdPtqknuTx0QAU +-> ssh-ed25519 dbKeHw ZZEDohW79lqKjT4TTQSGvjav+n6mESo1RALb+Xbbcw8 +gwj6rEy0G95IYBAgB1F8W5wXhRP1n+1SUTIp6/XWCHU +-> ssh-ed25519 3qPtug 9kX4TyecOvRgb+KCk3FAC3QbhhxU55VRiQGNOytGFSM +LpBauBXhI4vfBHEfw/d1l4ao7qkEe/Daaow4CyDtpJM +-> ssh-ed25519 +kBihw Qiyi1AaxGLyXdsNFu+TcNQ/xxOLEkYUbTIWYClVw+Qg +ocPR0AsEh3OPRWa1kWTlXcoit/yv/iywHfcgJZh/iFA +-> ssh-ed25519 jb0ALQ 7OFB68omi4iWdrKdywc+f6f69mGThijWPTktuAbA2ws +XzZnyv3qsGFM/25KapNdM4n/poisk2sTzgy1ECqWODk +--- RCAULQI2W/aA4Smb0LaA0xrT1GiH+bOGrMRLVY8O41E +Y~2mEA)L+ b oX5Cѕ^Hvq]N $n)X¬xlVgT)%M6aT2YM5Y ~ +HpS n&x(̞i? +K C̔KpMbCq*v ಽMl$ \ No newline at end of file diff --git a/secrets/pihole.age b/secrets/pihole.age index 3e0bcc96880e77514de21d77a18bf0a24bef5682..1b2bc2533d7d7de5063e15de08cacfa0e5dd6df6 100644 GIT binary patch literal 926 zcmZ9~ON-nD003YWtr$u@C<-EMEXr2Hn8#!?31T6WWL}x)wHiu+u2=O+39LsdRK+FNAr|z)>7yg5R_Y5XYpTwKC@i|0 zm>2{Jbij0gVmR{R$;MKx8y=gND(0nem`}D~8mAS7bV!j+JYSbvD!!_rHk@Y}NT%gR zOET+xPfU=sn&Jr5@3mQaG%gV_o;75@KmwYe)DZ_jnrT~^fv~fd7(`U*aHY??lB*y- z7fG_0W0P^jNDMlZRyEV$t#$?msJa|8@kGvL&K^u6NNfhI-W7UXVkD5c&?hw8@1>~5 zMSwA(>3HcYbr&(Z2s(os94^o%PY(K##3-8?O2(eUY_=F~RjV$LTP6lee#1(c{c zbvDlXP>h>Q(ZHJ`yy#a`KB#*gAi%Q0R^rQ1b%j+97Ue9&K$chfAp+!&jp*G#cf}q}16hYLhPef5f1s@lc;p6O2_`WksuM8aDI;j~MzSv~y2(IH= z8RXDhwpE6jNOCu4GKAxHq*x$&I4QK#fMn4f8N^~q1*c616TlP;3ZzWtnSR|SP)Oi- zKg(f0RWX3*uCQfk(S`yc2$%_jYRq%pu!00Wt9ml;St+pI*6O)7W+ip3iu+xKP1<^* zOWCrJOHly|pnklEx0zT=+{;RBp3|fbh)3?jR4-6+$8%Bw)G} z8#jyjn%;MdWp_kuWrg(g*P%%UQ;}j?DLQVkpxQ#g#aT-h=^9;X3l_)Z^Nit^Q!>oU z0OC`wSY}jCgS}Rzf`Hj_%Xd&dLRksWD|n#WDsd_#Ad35c(q1W!Qk8HMR=b&I(;ZbD zjqg$xNKeL;DxxV>u83*b7A=@U8KMK!G%Uc4m2kpFh=K_fblXXR5k4b!2pQJ{DKScx zYLN(swD1 zK8s_0e)44F&xThQzipYO?6Fb_GY?g77um(fU*^e~^7#7u3l%6dL4;Pl3vOzSXR{|3 z24`RYjvpKk!RJSQjjcO!Xeuv;_A|>r-7qsBHsxM?9GK^x9!bBQ+s-@(_B|LLKYjVq zxvP!KFFQN@gw)&lBlPplg?-Cz-B~0D$7ZQxJJ^A#+LQDNX-#L@(TX%|uLxEaZmbQ% sbE~&4UAVV#&)u1k@6}fu4jg{;`ShL9H$zL_pE|tx?6uXe-wyQu0z0%0f&c&j From 1730970935d170d806fc82eebd1ab68b8db40dd3 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 28 Nov 2025 10:41:09 -0600 Subject: [PATCH 026/149] homes (mcentire): Add home-manager config for mcentire --- flake.nix | 2 ++ homes/mcentire.nix | 8 ++++++++ 2 files changed, 10 insertions(+) create mode 100644 homes/mcentire.nix diff --git a/flake.nix b/flake.nix index 680c30b..a703651 100644 --- a/flake.nix +++ b/flake.nix @@ -101,6 +101,8 @@ "millironx@anderson" = mkHomeConfiguration { hostname = "anderson"; }; + "millironx@mcentire" = mkHomeConfiguration { hostname = "mcentire"; }; + "millironx@bosephus" = mkHomeConfiguration { hostname = "bosephus"; }; "tchristensen@beocat" = mkHomeConfiguration { hostname = "beocat"; }; diff --git a/homes/mcentire.nix b/homes/mcentire.nix new file mode 100644 index 0000000..82adbbc --- /dev/null +++ b/homes/mcentire.nix @@ -0,0 +1,8 @@ +{ ... }: { + home = { + username = "millironx"; + homeDirectory = "/home/millironx"; + }; + programs = { }; + services = { }; +} From 3fd32ffa45c984a6eb09c6dfcf44d2fe0cd58406 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 28 Nov 2025 10:19:28 -0600 Subject: [PATCH 027/149] feat: Add podman-secrets module --- bin/secret-translator.jl | 30 ++++++++ modules/podman-secrets.nix | 154 +++++++++++++++++++++++++++++++++++++ systems/linux/mcentire.nix | 1 + 3 files changed, 185 insertions(+) create mode 100644 bin/secret-translator.jl create mode 100644 modules/podman-secrets.nix diff --git a/bin/secret-translator.jl b/bin/secret-translator.jl new file mode 100644 index 0000000..ce50af8 --- /dev/null +++ b/bin/secret-translator.jl @@ -0,0 +1,30 @@ +#!/usr/bin/env julia +using TOML: TOML + +function remove_podman_secrets() + run(`podman secret rm --all`) + return nothing +end #function + +function create_podman_secret(name, secret) + run( + Cmd( + `podman secret create --env=true --replace $name SECRET`; + env = Dict("SECRET" => secret), + ), + ) + return nothing +end #function + +function parse_toml_secrets(file) + foreach(f -> create_podman_secret(f[1], f[2]), TOML.parsefile(file)) + return nothing +end #function + +function main() + remove_podman_secrets() + foreach(parse_toml_secrets, ARGS) + return 0 +end #function + +main() diff --git a/modules/podman-secrets.nix b/modules/podman-secrets.nix new file mode 100644 index 0000000..41a01c5 --- /dev/null +++ b/modules/podman-secrets.nix @@ -0,0 +1,154 @@ +# Warning to my future self: This module was "vibe coded" by Claude Sonnet 4.5. +# I originally had a hand-written module in here that did the secrets +# translation as the root user. I knew that I would want to support multiple +# secrets files and multiple users, and thought I should be able to create an +# arbitrary number of them, similar to how you can have an arbitrary number +# of `programs.firefox.profiles`. Unfortunately, even after looking at lots of +# example modules, I could not figure out the syntax (Nix has a serious lack +# of minimum working examples), so I broke down and asked Claude to rewrite it +# for me. Based on everything that I read, this seems to be exactly what I asked +# for. +# +# Here is the prompt I used to get here: +# [@Per service isolation on NixOS with Traefik](zed:///agent/thread/94cb8a22-ff0c-4772-a1a1-018b0107f334?name=Per+service+isolation+on+NixOS+with+Traefik) +# +# [@podman-secrets.nix](file:///home/millironx/.config/home-manager/modules/podman-secrets.nix) +# +# I originally wrote this module assuming that I would use Podman as root for +# all containers. I would like to fix the module to have as many secrets files +# processed as needed with services setup for each secret that is run as the +# appropriate user. Ideally, the syntax for working with secrets to be +# translated would be +# +# ```nix +# { config, ... }: { +# age.secrets = { +# "caddy.toml" = { +# file = ./../secrets/caddy.toml.age; +# owner = "caddy"; +# group = "caddy"; +# }; +# +# "authentik.toml" = { +# file = ./../secrets/authentik.toml.age; +# owner = "authentik"; +# group = "authentik"; +# }; +# +# "freshrss.toml" = { +# file = ./../secrets/freshrss.toml.age; +# owner = "freshrss"; +# group = "freshrss"; +# }; +# }; +# +# millironx.podman-secrets = with config; { +# caddy = { +# user = "caddy"; +# secrets-files = [ +# ./../not-really-secret.toml +# age.secrets."caddy.toml".path +# ]; +# }; +# authentik = { +# user = "authentik"; +# secrets-files = [ +# age.secrets."authentik.toml".path +# ]; +# }; +# freshrss = { +# user = "freshrss"; +# secrets-files = [ +# age.secrets."freshrss.toml".path +# ]; +# }; +# }; +# } +# ``` +# +# Can you help me rewrite the module to accomplish this? +# +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.millironx.podman-secrets; + + secret-translator = pkgs.writeScriptBin "secret-translator" + (builtins.readFile ./../bin/secret-translator.jl); + + # Submodule type for each service's secrets configuration + serviceSecretsType = types.submodule { + options = { + user = mkOption { + type = types.str; + description = "User account to run the secrets translation service as"; + example = "caddy"; + }; + + secrets-files = mkOption { + type = types.listOf (types.either types.path types.string); + description = + "List of TOML files containing secrets to translate to Podman secrets"; + example = literalExpression '' + [ + "/run/agenix/caddy.toml" + ./../not-really-secret.toml + ] + ''; + default = [ ]; + }; + }; + }; + + # Generate a systemd service for each configured service + mkSecretsService = name: serviceCfg: + nameValuePair "podman-secrets-${name}" { + description = "Podman secrets converter service for ${name}"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "oneshot"; + User = serviceCfg.user; + ExecStart = "${secret-translator}/bin/secret-translator ${ + lib.concatStringsSep " " serviceCfg.secrets-files + }"; + Path = [ "${pkgs.podman}/bin" "${pkgs.julia-lts-bin}/bin" ]; + }; + }; + + # Filter out services with no secrets-files + enabledServices = + lib.filterAttrs (name: serviceCfg: serviceCfg.secrets-files != [ ]) cfg; + +in { + options.millironx.podman-secrets = mkOption { + type = types.attrsOf serviceSecretsType; + description = '' + Per-service Podman secrets configuration. + Each attribute creates a separate systemd service that translates TOML secrets + files into Podman secrets for the specified user. + ''; + example = literalExpression '' + { + caddy = { + user = "caddy"; + secrets-files = [ + ./../not-really-secret.toml + config.age.secrets."caddy.toml".path + ]; + }; + authentik = { + user = "authentik"; + secrets-files = [ + config.age.secrets."authentik.toml".path + ]; + }; + } + ''; + default = { }; + }; + + config = mkIf (enabledServices != { }) { + systemd.services = lib.mapAttrs' mkSecretsService enabledServices; + }; +} diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 60fd158..7c0634a 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -3,6 +3,7 @@ { imports = [ # Include the results of the hardware scan. ./hardware-configuration/mcentire.nix + ./../../modules/podman-secrets.nix ./../../services/nixos-update.nix ./../../services/borgmatic.nix ./../../services/crowdsec.nix From 2b0684863245e19fff61f3f9790ff69ec2852e56 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 28 Nov 2025 15:12:50 -0600 Subject: [PATCH 028/149] service (mcentire): Add authentik service --- flake.nix | 4 ++ secrets.nix | 2 + secrets/authentik.toml.age | Bin 0 -> 1222 bytes services/authentik.nix | 128 +++++++++++++++++++++++++++++++++++++ systems/linux/mcentire.nix | 5 ++ 5 files changed, 139 insertions(+) create mode 100644 secrets/authentik.toml.age create mode 100644 services/authentik.nix diff --git a/flake.nix b/flake.nix index a703651..204941e 100644 --- a/flake.nix +++ b/flake.nix @@ -138,9 +138,13 @@ "mcentire" = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; + specialArgs = { + home-manager-quadlet-nix = quadlet-nix.homeManagerModules.quadlet; + }; modules = [ ./systems/linux/mcentire.nix agenix.nixosModules.default + home-manager.nixosModules.home-manager quadlet-nix.nixosModules.quadlet crowdsec.nixosModules.crowdsec crowdsec.nixosModules.crowdsec-firewall-bouncer diff --git a/secrets.nix b/secrets.nix index 1de9bc8..8042bf6 100644 --- a/secrets.nix +++ b/secrets.nix @@ -26,6 +26,8 @@ let in { "secrets/ansible-vault-password.age".publicKeys = system-administrators; + "secrets/authentik.toml.age".publicKeys = system-administrators + ++ [ mcentire-host ]; "secrets/borgmatic-passphrase.age".publicKeys = system-administrators ++ [ mcentire-host ]; "secrets/borgmatic-ssh-config.age".publicKeys = system-administrators diff --git a/secrets/authentik.toml.age b/secrets/authentik.toml.age new file mode 100644 index 0000000000000000000000000000000000000000..1ef8f6e277acf7a7b989bfa87f553f5f1d1d0ac8 GIT binary patch literal 1222 zcmZY4>u(bU003~zNPtQJGXe}9)UhD$GJ0+AXm33Gyz66qTzh>DNUpu>_1f!o?e*?@ zhs%KBruZPTY>o(sKsF;j!ec-NI6t5P1p=6W43LPB03w6ML;_|Qzs|qlmmkT{jWnMs zDXnF;z%MP77@efoG_KMLLZ*?X3^1%mv@B=j)S%X+Qyo~v>MND-v>Hu#Q;5L?O5w7> z73Z2=B3@*&32z`mazs!=mLzXBg^CK1T}Gt6Qa<7aqXB`;M4eE~nr|g5E{POv8AqXc zqNZnb6IRS6bL!?<_j?{&PLLmh3V$^LSEl{#Z|95L_)KcC8=6A}x!71b6m_KZhz`T=l z`Qf0sxsXqZVW&C7ILa)Xb!a;7-?tA{bz_~-o`vtdFb~hEIkJEITMc`r9~@+xc0L+= zspZeZdBeyi&6$JacV0e(u0Co~77wm&Upr;20a;zc&YC=@2637veS$6+?5Yba;x9Zs zwe8n|@Y3q4f}FWd^%It?XYTFKuJ`L3>VeJ=HtxE5ZPn&(_(jck;PLt}d2Y0K^SuxE z%(~IHb?>4lwGSV>{xs43)2j1b>XOj|-We^`$IgB<^6bWgTlzkcJU!(?!u8G%l|QI? zEv}~9na9%1sprZYzQ1zMzVnN5vcB`EZsE`ncXeIgordSzB0G1lNRiIRTX#P^eAx7U zsrOx>|D=UFxsSWKa`+H@v8C>ERMiTaSC0SU9-qAUY3Yy|J$w2MY1{g{Z|>@rR=jp9 zf4cY9`oYi7cMeRFo}C>2XZx33;fwye$CmUVJ=-^=91bXXbabG4?nAk1?QhDJX&p!O zYij*Vt<$?+eRk>je0oP{9`n_SGvM3KsR!qsBS(g>W#sgwj>#K79$aqtbj|E7?FZi3 zdpYJ?vGMWp9^?Ftwfl}WAk{NRcGUfR;?Xzq!j{^WzXu+)&7L7{s&Bf#u3c%X3r_R& zT->rAnxoJ4OdT2@oqID$2ET1<;<0{pezZ4S9vcaUYq=`Jg0_|I9bY@IpZR@klKsh# J`)~X;@-Hw|+A;tD literal 0 HcmV?d00001 diff --git a/services/authentik.nix b/services/authentik.nix new file mode 100644 index 0000000..30ee781 --- /dev/null +++ b/services/authentik.nix @@ -0,0 +1,128 @@ +{ config, home-manager-quadlet-nix, ... }: +let + user = "authentik"; + state-directory = "/var/lib/authentik"; + port = "9000"; + +in { + # Secrets are translated in the system scope, but performed by the user, + # so are available in the user's Podman secrets + age.secrets = { + "authentik.toml" = { + file = ./../secrets/authentik.toml.age; + owner = "${user}"; + }; + }; + + millironx.podman-secrets.authentik = { + user = "${user}"; + secrets-files = [ config.age.secrets."authentik.toml".path ]; + }; + + systemd.tmpfiles.rules = [ "d ${state-directory} 1775 ${user} ${user} -" ]; + + services.caddy.virtualHosts."auth.millironx.com".extraConfig = '' + reverse_proxy http://127.0.0.1:${port} + ''; + + # Create a dedicated user for this service + users.users."${user}" = { + group = "${user}"; + isSystemUser = true; + linger = true; + autoSubUidGidRange = true; + }; + users.groups."${user}" = {}; + + home-manager.users."${user}" = { config, ... }: { + imports = [ home-manager-quadlet-nix ]; + + home.stateVersion = "25.05"; + + virtualisation.quadlet.containers = { + authentik-db = { + autoStart = true; + containerConfig = { + image = "docker.io/library/postgres:16"; + environments = { + POSTGRES_DB = "${user}"; + POSTGRES_USER = "${user}"; + }; + secrets = [ + "AUTHENTIK_POSTGRESQL__PASSWORD,type=env,target=POSTGRES_PASSWORD" + ]; + healthCmd = "pg_isready -d \${POSTGRES_DB} -U \${POSTGRES_USER}"; + healthInterval = "30s"; + healthRetries = 5; + healthStartPeriod = "20s"; + volumes = [ "${state-directory}/database:/var/lib/postgresql/data" ]; + }; + }; + + authentik-worker = { + autoStart = true; + containerConfig = { + image = "ghcr.io/goauthentik/server:2025.10.2"; + environments = { + AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; + AUTHENTIK_POSTGRESQL__NAME = "${user}"; + AUTHENTIK_POSTGRESQL__USER = "${user}"; + }; + exec = "worker"; + secrets = [ + "AUTHENTIK_POSTGRESQL__PASSWORD,type=env" + "AUTHENTIK_SECRET_KEY,type=env" + ]; + volumes = [ + "${state-directory}/media:/media" + "${state-directory}/custom-templates:/templates" + "${state-directory}/certs:/certs" + ]; + }; + unitConfig.Requires = [ + config.virtualisation.quadlet.containers.authentik-db.ref + "network-online.target" + ]; + unitConfig.After = [ + config.virtualisation.quadlet.containers.authentik-db.ref + "network-online.target" + ]; + }; + + authentik = { + autoStart = true; + containerConfig = { + image = "ghcr.io/goauthentik/server:2025.10.2"; + environments = { + AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; + AUTHENTIK_POSTGRESQL__NAME = "${user}"; + AUTHENTIK_POSTGRESQL__USER = "${user}"; + }; + secrets = [ + "AUTHENTIK_POSTGRESQL__PASSWORD,type=env" + "AUTHENTIK_SECRET_KEY,type=env" + "AUTHENTIK_EMAIL__HOST,type=env" + "AUTHENTIK_EMAIL__PORT,type=env" + "AUTHENTIK_EMAIL__USERNAME,type=env" + "AUTHENTIK_EMAIL__PASSWORD,type=env" + "AUTHENTIK_EMAIL__USE_SSL,type=env" + "AUTHENTIK_EMAIL__FROM,type=env" + ]; + publishPorts = [ "127.0.0.1:${port}:${port}" ]; + volumes = [ + "${state-directory}/media:/media" + "${state-directory}/custom-templates:/templates" + ]; + }; + unitConfig.Requires = [ + config.virtualisation.quadlet.containers.authentik-db.ref + "network-online.target" + ]; + unitConfig.After = [ + config.virtualisation.quadlet.containers.authentik-db.ref + "network-online.target" + ]; + }; + }; + }; +} diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 7c0634a..4a1b09a 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -7,6 +7,7 @@ ./../../services/nixos-update.nix ./../../services/borgmatic.nix ./../../services/crowdsec.nix + ./../../services/authentik.nix ]; # Use the GRUB 2 boot loader. @@ -17,6 +18,7 @@ useDHCP = false; interfaces.eth0.useDHCP = true; hostName = "mcentire"; # Define your hostname. + firewall.allowedTCPPorts = [ 80 443 ]; }; # Set your time zone. @@ -56,8 +58,11 @@ services = { openssh.enable = true; tailscale.enable = true; + caddy.enable = true; }; + virtualisation.quadlet.enable = true; + system.stateVersion = "25.05"; # Did you read the comment? nix = { extraOptions = "experimental-features = nix-command flakes"; }; } From 72e4f04b317c7d9fdf553266c475e8d684d6b55e Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 28 Nov 2025 15:51:53 -0600 Subject: [PATCH 029/149] fix (podman-secrets): Use explicit Julia call --- modules/podman-secrets.nix | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/podman-secrets.nix b/modules/podman-secrets.nix index 41a01c5..9e7028a 100644 --- a/modules/podman-secrets.nix +++ b/modules/podman-secrets.nix @@ -73,7 +73,7 @@ with lib; let cfg = config.millironx.podman-secrets; - secret-translator = pkgs.writeScriptBin "secret-translator" + secret-translator-script = pkgs.writeText "secret-translator.jl" (builtins.readFile ./../bin/secret-translator.jl); # Submodule type for each service's secrets configuration @@ -109,10 +109,11 @@ let serviceConfig = { Type = "oneshot"; User = serviceCfg.user; - ExecStart = "${secret-translator}/bin/secret-translator ${ + ExecStart = + "${pkgs.julia-lts-bin}/bin/julia --startup-file=no ${secret-translator-script} ${ lib.concatStringsSep " " serviceCfg.secrets-files }"; - Path = [ "${pkgs.podman}/bin" "${pkgs.julia-lts-bin}/bin" ]; + Path = [ "${pkgs.podman}/bin" ]; }; }; From 1f322921bdb7fd1638eff149a4370e99a6035a8a Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 28 Nov 2025 16:02:49 -0600 Subject: [PATCH 030/149] fix (podman-secrets): Use explicit pkg references in script --- bin/secret-translator.jl | 30 ------------------------------ modules/podman-secrets.nix | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 35 deletions(-) delete mode 100644 bin/secret-translator.jl diff --git a/bin/secret-translator.jl b/bin/secret-translator.jl deleted file mode 100644 index ce50af8..0000000 --- a/bin/secret-translator.jl +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env julia -using TOML: TOML - -function remove_podman_secrets() - run(`podman secret rm --all`) - return nothing -end #function - -function create_podman_secret(name, secret) - run( - Cmd( - `podman secret create --env=true --replace $name SECRET`; - env = Dict("SECRET" => secret), - ), - ) - return nothing -end #function - -function parse_toml_secrets(file) - foreach(f -> create_podman_secret(f[1], f[2]), TOML.parsefile(file)) - return nothing -end #function - -function main() - remove_podman_secrets() - foreach(parse_toml_secrets, ARGS) - return 0 -end #function - -main() diff --git a/modules/podman-secrets.nix b/modules/podman-secrets.nix index 9e7028a..c6a3eaa 100644 --- a/modules/podman-secrets.nix +++ b/modules/podman-secrets.nix @@ -73,8 +73,38 @@ with lib; let cfg = config.millironx.podman-secrets; - secret-translator-script = pkgs.writeText "secret-translator.jl" - (builtins.readFile ./../bin/secret-translator.jl); + secret-translator = pkgs.writeScriptBin "secret-translator" '' + #!${pkgs.julia-lts-bin}/bin/julia + using TOML: TOML + + function remove_podman_secrets() + run(`${pkgs.podman}/bin/podman secret rm --all`) + return nothing + end #function + + function create_podman_secret(name, secret) + run( + Cmd( + `${pkgs.podman}/bin/podman secret create --env=true --replace $name SECRET`; + env = Dict("SECRET" => secret), + ), + ) + return nothing + end #function + + function parse_toml_secrets(file) + foreach(f -> create_podman_secret(f[1], f[2]), TOML.parsefile(file)) + return nothing + end #function + + function main() + remove_podman_secrets() + foreach(parse_toml_secrets, ARGS) + return 0 + end #function + + main() + ''; # Submodule type for each service's secrets configuration serviceSecretsType = types.submodule { @@ -109,11 +139,9 @@ let serviceConfig = { Type = "oneshot"; User = serviceCfg.user; - ExecStart = - "${pkgs.julia-lts-bin}/bin/julia --startup-file=no ${secret-translator-script} ${ + ExecStart = "${secret-translator}/bin/secret-translator ${ lib.concatStringsSep " " serviceCfg.secrets-files }"; - Path = [ "${pkgs.podman}/bin" ]; }; }; From 49a2f7cd3566a4e5f079012b956b48af3a564235 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 28 Nov 2025 16:12:20 -0600 Subject: [PATCH 031/149] fix (podman-secrets): Create home directory for authentik user --- services/authentik.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/authentik.nix b/services/authentik.nix index 30ee781..ce924b6 100644 --- a/services/authentik.nix +++ b/services/authentik.nix @@ -29,10 +29,12 @@ in { users.users."${user}" = { group = "${user}"; isSystemUser = true; + home = "${state-directory}"; + createHome = true; linger = true; autoSubUidGidRange = true; }; - users.groups."${user}" = {}; + users.groups."${user}" = { }; home-manager.users."${user}" = { config, ... }: { imports = [ home-manager-quadlet-nix ]; From 8e5734469c044381fc36748da1ff0c6d53cea1d1 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 28 Nov 2025 17:46:17 -0600 Subject: [PATCH 032/149] fix (podman-secrets): setuid path NixOS does some weird stuff with setting security bits in wrappers, rather than in packages themselves, and this was breaking podman. Add the wrappers directory to the PATH of the secrets service. --- bin/secret-translator.jl | 32 ++++++++++++++++++++++++++++++++ modules/podman-secrets.nix | 38 ++++++-------------------------------- 2 files changed, 38 insertions(+), 32 deletions(-) create mode 100644 bin/secret-translator.jl diff --git a/bin/secret-translator.jl b/bin/secret-translator.jl new file mode 100644 index 0000000..c5dee39 --- /dev/null +++ b/bin/secret-translator.jl @@ -0,0 +1,32 @@ +#!/usr/bin/env julia +using TOML: TOML + +@show ENV["PATH"] + +function remove_podman_secrets() + run(`podman secret rm --all`) + return nothing +end #function + +function create_podman_secret(name, secret) + run( + addenv( + `podman secret create --env=true --replace $name SECRET`, + Dict("SECRET" => secret), + ), + ) + return nothing +end #function + +function parse_toml_secrets(file) + foreach(f -> create_podman_secret(f[1], f[2]), TOML.parsefile(file)) + return nothing +end #function + +function main() + remove_podman_secrets() + foreach(parse_toml_secrets, ARGS) + return 0 +end #function + +main() diff --git a/modules/podman-secrets.nix b/modules/podman-secrets.nix index c6a3eaa..83073b3 100644 --- a/modules/podman-secrets.nix +++ b/modules/podman-secrets.nix @@ -73,38 +73,8 @@ with lib; let cfg = config.millironx.podman-secrets; - secret-translator = pkgs.writeScriptBin "secret-translator" '' - #!${pkgs.julia-lts-bin}/bin/julia - using TOML: TOML - - function remove_podman_secrets() - run(`${pkgs.podman}/bin/podman secret rm --all`) - return nothing - end #function - - function create_podman_secret(name, secret) - run( - Cmd( - `${pkgs.podman}/bin/podman secret create --env=true --replace $name SECRET`; - env = Dict("SECRET" => secret), - ), - ) - return nothing - end #function - - function parse_toml_secrets(file) - foreach(f -> create_podman_secret(f[1], f[2]), TOML.parsefile(file)) - return nothing - end #function - - function main() - remove_podman_secrets() - foreach(parse_toml_secrets, ARGS) - return 0 - end #function - - main() - ''; + secret-translator = pkgs.writeScriptBin "secret-translator" + (builtins.readFile ./../bin/secret-translator.jl); # Submodule type for each service's secrets configuration serviceSecretsType = types.submodule { @@ -139,9 +109,13 @@ let serviceConfig = { Type = "oneshot"; User = serviceCfg.user; + ProtectProc = "invisible"; ExecStart = "${secret-translator}/bin/secret-translator ${ lib.concatStringsSep " " serviceCfg.secrets-files }"; + Environment = "PATH=/run/wrappers/bin:${ + lib.makeBinPath (with pkgs; [ shadow podman julia-lts-bin ]) + }"; }; }; From ce174b61fd21266da3fd8fab9d0f204432facc6f Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 08:36:00 -0600 Subject: [PATCH 033/149] meta: Add gitignore --- .gitignore | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd099b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,74 @@ +### Linux gitignore ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# Metadata left by Dolphin file manager, which comes with KDE Plasma +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# Log files created by default by the nohup command +nohup.out + +### MacOS gitignore ### +# General +.DS_Store +__MACOSX/ +.AppleDouble +.LSOverride +Icon[] + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Nix gitignore ### +# Ignore build outputs from performing a nix-build or `nix build` command +result +result-* + +# Ignore automatically generated direnv output +.direnv + +### Vim gitignore ### +# Swap +[._]*.s[a-v][a-z] +# comment out the next line if you don't need vector files +!*.svg +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ From 70f98a6200c09f281884d8dbf48c0082ad4a09b4 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 08:57:54 -0600 Subject: [PATCH 034/149] meta: Add README --- README.md | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..58c9d60 --- /dev/null +++ b/README.md @@ -0,0 +1,166 @@ +# nix-dotfiles + +System and home configurations for my machines. + ++----------+-----------------+--------+---------+--------------------------------+ +| Machine | Role | OS | Arch | Configuration tool | +| | | | |-----------------+--------------+ +| | | | | System | Home | ++==========+=================+--------+---------+=================+==============+ +| anderson | server | linux | x86_64 | dpkg/Docker | home-manager | +| | | | | (not this repo) | | ++----------+-----------------+--------+---------+-----------------+--------------+ +| bosephus | server | linux | x86_64 | NixOS | home-manager | ++----------+-----------------+--------+---------+-----------------+--------------+ +| corianne | MacBook | darwin | aarch64 | nix-darwin | home-manager | ++----------+-----------------+--------+---------+-----------------+--------------+ +| harmony | MacBook (Asahi) | linux | aarch64 | Ansible | home-manager | ++----------+-----------------+--------+---------+-----------------+--------------+ +| odyssey | workstation | linux | x86_64 | Ansible | home-manager | ++----------+-----------------+--------+---------+-----------------+--------------+ + +## Quickstart + +### Home dotfiles + +> ![WARNING] +> Fedora systems will set this up automagically via Ansible. Follow the +[Fedora quickstart] instructions. + +Ensure Nix is installed, with the `nix` command and flakes enabled. I try to use +the [Determinate Nix installer] (with upstream Nix) to install Nix with these +options turned on by default. + +```bash +curl -fsSL https://install.determinate.systems/nix | sh -s -- install +``` + +Once Nix is installed, clone the repository to `~/.config/home-manager` and +initiate home-manager. + +```bash +git clone https://code.millironx.com/millironx/nix-dotfiles.git ~/.config/home-manager +nix run home-manager -- switch --flake ~/.config/home-manager#$USER@$(hostname -s) +``` + +In the case that the host has not been assigned a configuration within this repo +yet, pick a hostname with the same system OS, arch, and role as the target +system to get temporary dotfiles up and running. + +```bash +nix run home-manager -- switch --flake ~/.config/home-manager#millironx@anderson +``` + +Once an SSH (with or without GPG) key has been setup and added to the authorized +keys of the git server, switch the upstream to track an authorized (i.e. +read/write) version of the repo. + +```bash +cd ~/.config/home-manager +git remote set-url origin git@code.millironx.com:millironx/nix-dotfiles.git +cd - +``` + +### NixOS + +Switching to a flake-based config requires running as root. All of the following +commands are assumed to be running as root. + +Ensure that the `nix` command and flakes are enabled. + +```bash +sed -i '/^}/i nix.settings.experimental-features = [ "nix-command" "flakes" ];' /etc/nixos/configuration.nix +nixos-rebuild switch +``` + +> ![NOTE] +> To allow secret decryption in the system, the *machine*-specific SSH key must +> be added to the publicKeys attribute of all applicable secrets, and the +> `hardware-configuration.nix` file must be added to git. Copying arbitrary +> strings like SSH keys or disk UUIDs between systems can be painful, so it might +> be worth setting up the [home dotfiles] immediately after enabling flakes, +> then running these steps on the same machine to avoid typos. Alternatively, I +> might someday be smart enough to create an installer CD that automagically +> sets this up for me. + +Get the machine-specific public SSH key. + +```bash +cat /etc/ssh/ssh_host_ed25519_key.pub +``` + +On a separate machine, add the machine's SSH key to `./secrets.nix` and assign +it to any secrets it would need. + +```nix +let + bosephus-host = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIxTfeg+GZsfmG8TuEV1xW1gXknAIKzZ3UjZ3guRY+EW root@nixos"; + bosephus-millironx = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKaDPqRJHoqgY2pseh/mnhjaGWXprHk2s5I52LhHpHcF millironx@bosephus"; + odyssey-millironx = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9Aj7BtQp1Roa0tgopDrUo7g2am5WJ43lO1d1fDUz45 millironx@odyssey"; + + system-administrators = [ + bosephus-millironx + odyssey-millironx + ]; +in { + "secrets/network-information.age".publicKeys = system-administrators + ++ [ bosephus-host ]; +} +``` + +Rekey the secrets, and push the updated secrets to the upstream repo. + +```bash +nix run github:ryantm/agenix -- --rekey +git add secrets.nix secrets/* +git commit -m "added $NEW_HOST to secrets" +git push +``` + +Copy the target machine's `hardware-configuration.nix` file to this repo's +`./systems/linux/hardware-configuration/$NEW_HOST.nix`, and be sure to update +the configuration to import its own `hardware-configuration`. + +```bash +cp /etc/nixos/hardware-configuration.nix ./systems/linux/hardware-configuration/$NEW_HOST.nix +``` + +```nix +{ config, pkgs, ... }: { + imports = [ + ./hardware-configuration/bosephus.nix + ]; +} +``` + +Commit and push the hardware configuration to the upstream repo. + +```bash +git add systems/linux/* +git commit -m "added $NEW_HOST hardware configuration" +git push +``` + +Now switch to the flake by pulling and switching in one step. + + +```bash +nixos-rebuild switch --flake git+https://code.millironx.com/millironx/nix-dotfiles#$(hostname -s) +``` + +### Fedora + +Fedora systems are managed using Ansible. + +TODO + +## Home settings + +TODO + +[determinate nix installer]: https://github.com/DeterminateSystems/nix-installer +[fedora quickstart]: #fedora +[home dotfiles]: #home-dotfiles From 4e84e57e3b5cc0590a4d8073e25460c47b6c9383 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:06:23 -0600 Subject: [PATCH 035/149] docs: Convert README table to pipe format --- README.md | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 58c9d60..c6c80bd 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,13 @@ System and home configurations for my machines. -+----------+-----------------+--------+---------+--------------------------------+ -| Machine | Role | OS | Arch | Configuration tool | -| | | | |-----------------+--------------+ -| | | | | System | Home | -+==========+=================+--------+---------+=================+==============+ -| anderson | server | linux | x86_64 | dpkg/Docker | home-manager | -| | | | | (not this repo) | | -+----------+-----------------+--------+---------+-----------------+--------------+ -| bosephus | server | linux | x86_64 | NixOS | home-manager | -+----------+-----------------+--------+---------+-----------------+--------------+ -| corianne | MacBook | darwin | aarch64 | nix-darwin | home-manager | -+----------+-----------------+--------+---------+-----------------+--------------+ -| harmony | MacBook (Asahi) | linux | aarch64 | Ansible | home-manager | -+----------+-----------------+--------+---------+-----------------+--------------+ -| odyssey | workstation | linux | x86_64 | Ansible | home-manager | -+----------+-----------------+--------+---------+-----------------+--------------+ +| Machine | Role | OS | Arch | System config tool | Home config tool | +| -------- | --------------- | ------ | ------- | --------------------------- | ---------------- | +| anderson | server | linux | x86_64 | dpkg/Docker (not this repo) | home-manager | +| bosephus | server | linux | x86_64 | NixOS | home-manager | +| corianne | MacBook | darwin | aarch64 | nix-darwin | home-manager | +| harmony | MacBook (Asahi) | linux | aarch64 | Ansible | home-manager | +| odyssey | workstation | linux | x86_64 | Ansible | home-manager | ## Quickstart From e9b1841f7b438851933c88e7850a19b921821577 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:07:15 -0600 Subject: [PATCH 036/149] docs: Remove harmony reference --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index c6c80bd..4f810a9 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ System and home configurations for my machines. | anderson | server | linux | x86_64 | dpkg/Docker (not this repo) | home-manager | | bosephus | server | linux | x86_64 | NixOS | home-manager | | corianne | MacBook | darwin | aarch64 | nix-darwin | home-manager | -| harmony | MacBook (Asahi) | linux | aarch64 | Ansible | home-manager | | odyssey | workstation | linux | x86_64 | Ansible | home-manager | ## Quickstart From fa6b537a3c828ca5a90668fa6eb9797e9bec24fb Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:17:07 -0600 Subject: [PATCH 037/149] docs: Add mcentire to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4f810a9..d650f9b 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ System and home configurations for my machines. | -------- | --------------- | ------ | ------- | --------------------------- | ---------------- | | anderson | server | linux | x86_64 | dpkg/Docker (not this repo) | home-manager | | bosephus | server | linux | x86_64 | NixOS | home-manager | +| mcentire | server | linux | x86_64 | NixOS | home-manager | | corianne | MacBook | darwin | aarch64 | nix-darwin | home-manager | | odyssey | workstation | linux | x86_64 | Ansible | home-manager | From 8d96ef7684bac912cd5508e1e73288279b33d0ea Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 12:01:45 -0600 Subject: [PATCH 038/149] fix (podman-secrets): Use user systemd unit User systemd units cannot wait for system units. Fix race condition bugs in user Quadlet services by using a user service that the Quadlet services can use as a `After=` or `Requires=` directive. --- modules/podman-secrets.nix | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/modules/podman-secrets.nix b/modules/podman-secrets.nix index 83073b3..fb99285 100644 --- a/modules/podman-secrets.nix +++ b/modules/podman-secrets.nix @@ -77,7 +77,7 @@ let (builtins.readFile ./../bin/secret-translator.jl); # Submodule type for each service's secrets configuration - serviceSecretsType = types.submodule { + serviceSecretsType = types.submodule ({ config, name, ... }: { options = { user = mkOption { type = types.str; @@ -97,18 +97,28 @@ let ''; default = [ ]; }; - }; - }; - # Generate a systemd service for each configured service + ref = mkOption { + type = types.str; + description = + "Reference to the systemd service name for declaring dependencies"; + readOnly = true; + default = "podman-secrets-${name}.service"; + example = "podman-secrets-caddy.service"; + }; + }; + }); + + # Generate a systemd user service for each configured service mkSecretsService = name: serviceCfg: nameValuePair "podman-secrets-${name}" { description = "Podman secrets converter service for ${name}"; - wantedBy = [ "multi-user.target" ]; + wantedBy = [ "default.target" ]; + + unitConfig.ConditionUser = "${serviceCfg.user}"; serviceConfig = { Type = "oneshot"; - User = serviceCfg.user; ProtectProc = "invisible"; ExecStart = "${secret-translator}/bin/secret-translator ${ lib.concatStringsSep " " serviceCfg.secrets-files @@ -128,8 +138,8 @@ in { type = types.attrsOf serviceSecretsType; description = '' Per-service Podman secrets configuration. - Each attribute creates a separate systemd service that translates TOML secrets - files into Podman secrets for the specified user. + Each attribute creates a separate systemd user service that translates TOML secrets + files into Podman secrets. ''; example = literalExpression '' { @@ -152,6 +162,6 @@ in { }; config = mkIf (enabledServices != { }) { - systemd.services = lib.mapAttrs' mkSecretsService enabledServices; + systemd.user.services = lib.mapAttrs' mkSecretsService enabledServices; }; } From b2477b9f24d650cc13cda7abd0523234e4d54c9f Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 12:03:20 -0600 Subject: [PATCH 039/149] fix (authentik): Too many fixes to list Bad on me, but I have spent way too long making edits that are all required on mcentire to get Authentik semi-working. There are lots of notes in here on reasoning of why stuff is the way it is. Backup still needs to be configured, and potentially Crowdsec. --- services/authentik.nix | 225 ++++++++++++++++++++++++++--------------- 1 file changed, 141 insertions(+), 84 deletions(-) diff --git a/services/authentik.nix b/services/authentik.nix index ce924b6..ee57695 100644 --- a/services/authentik.nix +++ b/services/authentik.nix @@ -5,8 +5,8 @@ let port = "9000"; in { - # Secrets are translated in the system scope, but performed by the user, - # so are available in the user's Podman secrets + # Secrets are translated in the system NixOS scope, but performed by the user, + # via a user systemd unit, so are available in the user's Podman secrets age.secrets = { "authentik.toml" = { file = ./../secrets/authentik.toml.age; @@ -19,7 +19,15 @@ in { secrets-files = [ config.age.secrets."authentik.toml".path ]; }; - systemd.tmpfiles.rules = [ "d ${state-directory} 1775 ${user} ${user} -" ]; + # Podman, unlike Docker apparently, does not automatically create mount points + # within folders, so every mounted folder needs to be specified here. + systemd.tmpfiles.rules = [ + "d ${state-directory} 1775 ${user} ${user} -" + "d ${state-directory}/database 1775 ${user} ${user} -" + "d ${state-directory}/media 1775 ${user} ${user} -" + "d ${state-directory}/certs 1775 ${user} ${user} -" + "d ${state-directory}/custom-templates 1775 ${user} ${user} -" + ]; services.caddy.virtualHosts."auth.millironx.com".extraConfig = '' reverse_proxy http://127.0.0.1:${port} @@ -27,104 +35,153 @@ in { # Create a dedicated user for this service users.users."${user}" = { + # Group is technically not mandatory, but NixOS complains that an unset + # group is "unsafe." The group has to be declared below group = "${user}"; - isSystemUser = true; + + # System users don't have a shell. For security purposes, that *would* be + # superior, but that means that, e.g. borgmatic can't `sudo` into the + # account to access Podman commands + isNormalUser = true; + + # A home directory is mandatory in order to allow systemd user units to be + # created and run home = "${state-directory}"; createHome = true; + + # Settings for running containers while a login shell is not active linger = true; autoSubUidGidRange = true; }; users.groups."${user}" = { }; - home-manager.users."${user}" = { config, ... }: { + home-manager.users."${user}" = { config, osConfig, ... }: { imports = [ home-manager-quadlet-nix ]; home.stateVersion = "25.05"; - virtualisation.quadlet.containers = { - authentik-db = { - autoStart = true; - containerConfig = { - image = "docker.io/library/postgres:16"; - environments = { - POSTGRES_DB = "${user}"; - POSTGRES_USER = "${user}"; + virtualisation.quadlet = { + containers = { + authentik-db = { + autoStart = true; + containerConfig = { + image = "docker.io/library/postgres:16"; + environments = { + POSTGRES_DB = "${user}"; + POSTGRES_USER = "${user}"; + }; + secrets = [ + # POSTGRES_PASSWORD is used by the container to setup the + # database, PGPASSWORD is used by pg_dump to authenticate for + # backup purposes + "AUTHENTIK_POSTGRESQL__PASSWORD,type=env,target=POSTGRES_PASSWORD" + "AUTHENTIK_POSTGRESQL__PASSWORD,type=env,target=PGPASSWORD" + ]; + + # Double dollarsigns are required for use of *container* environment + # variables, Nix escaping creates the weird $\${} syntax + healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"; + healthInterval = "30s"; + healthRetries = 5; + healthStartPeriod = "20s"; + + # Volumes have to be bound with the :U label to allow for username + # remapping in rootless containers. :Z/:z is not needed b/c NixOS + # does not support SELinux + volumes = + [ "${state-directory}/database:/var/lib/postgresql/data:U" ]; + + # A network is actually required for these containers to talk to one + # another. I suppose the more idiomatic way would be for these + # related containers to be in a "pod," but I'm still struggling + # learning the idiosyncrasies of quadlet/rootless/podman, so we'll + # stick with this for now + networks = + [ config.virtualisation.quadlet.networks.authentik-net.ref ]; + }; - secrets = [ - "AUTHENTIK_POSTGRESQL__PASSWORD,type=env,target=POSTGRES_PASSWORD" - ]; - healthCmd = "pg_isready -d \${POSTGRES_DB} -U \${POSTGRES_USER}"; - healthInterval = "30s"; - healthRetries = 5; - healthStartPeriod = "20s"; - volumes = [ "${state-directory}/database:/var/lib/postgresql/data" ]; + + # Allowing this container to start before the secrets are translated + # will lead to errors. Use osConfig b/c secrets are declared in the + # system NixOS scope, even though it is a user process. + unitConfig.Requires = + [ osConfig.millironx.podman-secrets.authentik.ref ]; + unitConfig.After = + [ osConfig.millironx.podman-secrets.authentik.ref ]; + }; + + authentik-worker = { + autoStart = true; + containerConfig = { + image = "ghcr.io/goauthentik/server:2025.10.2"; + environments = { + AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; + AUTHENTIK_POSTGRESQL__NAME = "${user}"; + AUTHENTIK_POSTGRESQL__USER = "${user}"; + }; + exec = "worker"; + secrets = [ + "AUTHENTIK_POSTGRESQL__PASSWORD,type=env" + "AUTHENTIK_SECRET_KEY,type=env" + ]; + volumes = [ + "${state-directory}/media:/media:U" + "${state-directory}/custom-templates:/templates:U" + "${state-directory}/certs:/certs:U" + ]; + networks = + [ config.virtualisation.quadlet.networks.authentik-net.ref ]; + }; + unitConfig.Requires = + [ config.virtualisation.quadlet.containers.authentik-db.ref ]; + unitConfig.After = + [ config.virtualisation.quadlet.containers.authentik-db.ref ]; + }; + + authentik = { + autoStart = true; + containerConfig = { + image = "ghcr.io/goauthentik/server:2025.10.2"; + environments = { + AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; + AUTHENTIK_POSTGRESQL__NAME = "${user}"; + AUTHENTIK_POSTGRESQL__USER = "${user}"; + }; + exec = "server"; + secrets = [ + "AUTHENTIK_POSTGRESQL__PASSWORD,type=env" + "AUTHENTIK_SECRET_KEY,type=env" + "AUTHENTIK_EMAIL__HOST,type=env" + "AUTHENTIK_EMAIL__PORT,type=env" + "AUTHENTIK_EMAIL__USERNAME,type=env" + "AUTHENTIK_EMAIL__PASSWORD,type=env" + "AUTHENTIK_EMAIL__USE_SSL,type=env" + "AUTHENTIK_EMAIL__FROM,type=env" + ]; + + # Change from Traefik: publish ports to localhost only via 127.0.0.1 + # and then reverse proxy to that port. Authentik does not appear to + # have a way to configure the port, so we will use the default of + # 9000 for non-secured traffic. + publishPorts = [ "127.0.0.1:${port}:${port}" ]; + volumes = [ + "${state-directory}/media:/media:U" + "${state-directory}/custom-templates:/templates:U" + ]; + networks = + [ config.virtualisation.quadlet.networks.authentik-net.ref ]; + }; + unitConfig.Requires = + [ config.virtualisation.quadlet.containers.authentik-db.ref ]; + unitConfig.After = + [ config.virtualisation.quadlet.containers.authentik-db.ref ]; }; }; - authentik-worker = { - autoStart = true; - containerConfig = { - image = "ghcr.io/goauthentik/server:2025.10.2"; - environments = { - AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; - AUTHENTIK_POSTGRESQL__NAME = "${user}"; - AUTHENTIK_POSTGRESQL__USER = "${user}"; - }; - exec = "worker"; - secrets = [ - "AUTHENTIK_POSTGRESQL__PASSWORD,type=env" - "AUTHENTIK_SECRET_KEY,type=env" - ]; - volumes = [ - "${state-directory}/media:/media" - "${state-directory}/custom-templates:/templates" - "${state-directory}/certs:/certs" - ]; - }; - unitConfig.Requires = [ - config.virtualisation.quadlet.containers.authentik-db.ref - "network-online.target" - ]; - unitConfig.After = [ - config.virtualisation.quadlet.containers.authentik-db.ref - "network-online.target" - ]; - }; + networks.authentik-net = { }; - authentik = { - autoStart = true; - containerConfig = { - image = "ghcr.io/goauthentik/server:2025.10.2"; - environments = { - AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; - AUTHENTIK_POSTGRESQL__NAME = "${user}"; - AUTHENTIK_POSTGRESQL__USER = "${user}"; - }; - secrets = [ - "AUTHENTIK_POSTGRESQL__PASSWORD,type=env" - "AUTHENTIK_SECRET_KEY,type=env" - "AUTHENTIK_EMAIL__HOST,type=env" - "AUTHENTIK_EMAIL__PORT,type=env" - "AUTHENTIK_EMAIL__USERNAME,type=env" - "AUTHENTIK_EMAIL__PASSWORD,type=env" - "AUTHENTIK_EMAIL__USE_SSL,type=env" - "AUTHENTIK_EMAIL__FROM,type=env" - ]; - publishPorts = [ "127.0.0.1:${port}:${port}" ]; - volumes = [ - "${state-directory}/media:/media" - "${state-directory}/custom-templates:/templates" - ]; - }; - unitConfig.Requires = [ - config.virtualisation.quadlet.containers.authentik-db.ref - "network-online.target" - ]; - unitConfig.After = [ - config.virtualisation.quadlet.containers.authentik-db.ref - "network-online.target" - ]; - }; + # One of the main advantages of using Quadlet + autoUpdate.enable = true; }; }; } From 6a1cc7877ce1e59dd199776e893c8f91d338225e Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:52:06 -0600 Subject: [PATCH 040/149] users (mcentire): Add millironx to adm group --- systems/linux/mcentire.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 4a1b09a..9171e5a 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -44,7 +44,7 @@ millironx = { isNormalUser = true; description = "Thomas A. Christensen II"; - extraGroups = [ "wheel" ]; + extraGroups = [ "adm" "wheel" ]; }; }; From a3a8ea9a34e8d4772445fbcebce9d9f1d53285e8 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 14:03:20 -0600 Subject: [PATCH 041/149] services (linux): Remove nixos-update service --- services/nixos-update.nix | 50 -------------------------------------- systems/linux/bosephus.nix | 1 - systems/linux/mcentire.nix | 1 - 3 files changed, 52 deletions(-) delete mode 100644 services/nixos-update.nix diff --git a/services/nixos-update.nix b/services/nixos-update.nix deleted file mode 100644 index f0678ec..0000000 --- a/services/nixos-update.nix +++ /dev/null @@ -1,50 +0,0 @@ -# This file is designed to be used in the imports -{ pkgs, config, ... }: - -{ - environment.systemPackages = [ - (pkgs.writeScriptBin "update-nixos" '' - #!${pkgs.bash}/bin/bash - echo "Requesting system update..." - ${pkgs.systemd}/bin/systemctl start nixos-update.service - '') - ]; - - # Service to update NixOS configuration from git repo - systemd.services."nixos-update" = { - description = "Update NixOS configuration from git repository"; - path = with pkgs; [ coreutils ]; - script = '' - # Rebuild the system directly from the remote flake - ${pkgs.nixos-rebuild}/bin/nixos-rebuild switch --flake git+https://code.millironx.com/millironx/nix-dotfiles.git#${config.networking.hostName} - ''; - serviceConfig = { - Type = "oneshot"; - User = "root"; - }; - }; - - # Timer to run the update service daily at 3am - systemd.timers."nixos-update" = { - wantedBy = [ "timers.target" ]; - description = "Run NixOS update daily at 3am"; - timerConfig = { - OnCalendar = "3:00"; - Persistent = true; - Unit = "nixos-update.service"; - }; - }; - - # Polkit rule to allow non-root users to trigger the update - security.polkit.extraConfig = '' - polkit.addRule(function(action, subject) { - if (action.id == "org.freedesktop.systemd1.manage-units" && - action.lookup("unit") == "nixos-update.service" && - action.lookup("verb") == "start" && - subject.isInGroup("wheel")) { - return polkit.Result.YES; - } - }); - ''; - -} diff --git a/systems/linux/bosephus.nix b/systems/linux/bosephus.nix index 3a0a271..98cf0e7 100644 --- a/systems/linux/bosephus.nix +++ b/systems/linux/bosephus.nix @@ -8,7 +8,6 @@ imports = [ ./hardware-configuration/bosephus.nix ./hardware-configuration/bosephus-external-drives.nix - ./../../services/nixos-update.nix ./../../services/samba.nix ./../../services/pihole.nix ]; diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 9171e5a..81be915 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -4,7 +4,6 @@ imports = [ # Include the results of the hardware scan. ./hardware-configuration/mcentire.nix ./../../modules/podman-secrets.nix - ./../../services/nixos-update.nix ./../../services/borgmatic.nix ./../../services/crowdsec.nix ./../../services/authentik.nix From 8b5fa1dfe9d3858b5804264c7226199ab46e223f Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 15:01:45 -0600 Subject: [PATCH 042/149] service (authentik): Add Borgmatic config --- services/authentik.nix | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/services/authentik.nix b/services/authentik.nix index ee57695..85d7ea1 100644 --- a/services/authentik.nix +++ b/services/authentik.nix @@ -1,4 +1,4 @@ -{ config, home-manager-quadlet-nix, ... }: +{ config, pkgs, home-manager-quadlet-nix, ... }: let user = "authentik"; state-directory = "/var/lib/authentik"; @@ -33,6 +33,22 @@ in { reverse_proxy http://127.0.0.1:${port} ''; + services.borgmatic.configurations."${config.networking.hostName}" = { + source_directories = [ + "${state-directory}/media" + "${state-directory}/certs" + "${state-directory}/custom-templates" + ]; + + postgresql_databases = [{ + name = "authentik"; + pg_dump_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec authentik-db pg_dump --username=${user}"; + pg_restore_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec authentik-db pg_restore --username=${user}"; + }]; + }; + # Create a dedicated user for this service users.users."${user}" = { # Group is technically not mandatory, but NixOS complains that an unset From 1301fd94b33ce55017a36790dbbacfba6a46e61e Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 15:09:48 -0600 Subject: [PATCH 043/149] fix (borgmatic): Add postgresql config --- systems/linux/mcentire.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 81be915..4bd52f3 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -58,6 +58,10 @@ openssh.enable = true; tailscale.enable = true; caddy.enable = true; + + # Do not "enable" database services, but include the package configuration + # so that borgmatic does not freak out about unset variables + postgresql.package = pkgs.postgresql_17; }; virtualisation.quadlet.enable = true; From 086cae0a56e4203822e9005d25581c6a5d639d24 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 1 Dec 2025 15:14:01 -0600 Subject: [PATCH 044/149] fix (borgmatic): Add psql command --- services/authentik.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/authentik.nix b/services/authentik.nix index 85d7ea1..f507dac 100644 --- a/services/authentik.nix +++ b/services/authentik.nix @@ -42,6 +42,8 @@ in { postgresql_databases = [{ name = "authentik"; + psql_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec authentik-db psql --username=${user}"; pg_dump_command = "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec authentik-db pg_dump --username=${user}"; pg_restore_command = From c49474d8ce7b0612523d6bde593bc843e7fe2687 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 2 Dec 2025 09:56:36 -0600 Subject: [PATCH 045/149] flake: Upgrade nixpkgs to nixos-25.11 family This commit upgrades nixpkgs to nixos-25.11, and all other management systems (home-manager, nix-darwin, etc.) to the equivalent tag, and also upgrades any syntax within the modules to follow new syntax. 1. Upgrades nixpkgs to nixos-25.11 2. Upgrades nixpkgs-darwin to nixpkgs-25.11-darwin 3. Upgrades home-manger to release-25.11 4. Upgrades nix-darwin to 25.11 5. Implements conditional to use nixpkgs on Linux and nixpkgs-darwin on Darwin 6. Replace micromamba with mamba-cpp and set alias, see 7. Replace asitop with its new name: macpm 8. Remove ollama package and launchd service. ollama was removed from Linux in 275270cef7, but remained in Darwin. The build process technically did not fail, but it did extend build time and is unused, so it was removed. 9. Switch git program module to use new syntax 10. Switch to NixOS-provided Crowdsec module 11. Switch logind lidSwitch settings to use new syntax 12. Switch sabma module to use new syntax --- flake.lock | 122 ++++++++++------------------------- flake.nix | 22 +++---- homes/common.nix | 3 +- homes/darwin.nix | 18 +----- homes/desktop.nix | 1 - programs/git.nix | 8 ++- programs/shells.nix | 2 +- services/crowdsec.nix | 128 +++++++++++-------------------------- services/samba.nix | 1 - systems/linux/bosephus.nix | 4 +- 10 files changed, 91 insertions(+), 218 deletions(-) diff --git a/flake.lock b/flake.lock index a1cd1d3..982ba78 100644 --- a/flake.lock +++ b/flake.lock @@ -14,11 +14,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1754433428, - "narHash": "sha256-NA/FT2hVhKDftbHSwVnoRTFhes62+7dxZbxj5Gxvghs=", + "lastModified": 1762618334, + "narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=", "owner": "ryantm", "repo": "agenix", - "rev": "9edb1787864c4f59ae5074ad498b6272b3ec308d", + "rev": "fcdea223397448d35d9b31f798479227e80183f6", "type": "github" }, "original": { @@ -27,27 +27,6 @@ "type": "github" } }, - "crowdsec": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1752497357, - "narHash": "sha256-9epXn1+T6U4Kfyw8B9zMzbERxDB3VfaPXhVebtai6CE=", - "ref": "refs/heads/main", - "rev": "84db7dcea77f7f477d79e69e35fb0bb560232667", - "revCount": 42, - "type": "git", - "url": "https://codeberg.org/kampka/nix-flake-crowdsec.git" - }, - "original": { - "type": "git", - "url": "https://codeberg.org/kampka/nix-flake-crowdsec.git" - } - }, "flake-parts": { "inputs": { "nixpkgs-lib": [ @@ -69,23 +48,6 @@ "type": "github" } }, - "flake-utils": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "id": "flake-utils", - "type": "indirect" - } - }, "home-manager": { "inputs": { "nixpkgs": [ @@ -93,16 +55,16 @@ ] }, "locked": { - "lastModified": 1756679287, - "narHash": "sha256-Xd1vOeY9ccDf5VtVK12yM0FS6qqvfUop8UQlxEB+gTQ=", + "lastModified": 1764613336, + "narHash": "sha256-L979az28t/+SXvYw9qhOno5HLlDwkZOpz6LzCLnjmRM=", "owner": "nix-community", "repo": "home-manager", - "rev": "07fc025fe10487dd80f2ec694f1cd790e752d0e8", + "rev": "f3902b5d8767985680875ad86d028371100faeb3", "type": "github" }, "original": { "owner": "nix-community", - "ref": "release-25.05", + "ref": "release-25.11", "repo": "home-manager", "type": "github" } @@ -114,59 +76,59 @@ ] }, "locked": { - "lastModified": 1757432263, - "narHash": "sha256-qHn+/0+IOz5cG68BZUwL9BV3EO/e9eNKCjH3+N7wMdI=", + "lastModified": 1764161084, + "narHash": "sha256-HN84sByg9FhJnojkGGDSrcjcbeioFWoNXfuyYfJ1kBE=", "owner": "LnL7", "repo": "nix-darwin", - "rev": "1fef4404de4d1596aa5ab2bd68078370e1b9dcdb", + "rev": "e95de00a471d07435e0527ff4db092c84998698e", "type": "github" }, "original": { "owner": "LnL7", - "ref": "nix-darwin-25.05", + "ref": "nix-darwin-25.11", "repo": "nix-darwin", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1757545623, - "narHash": "sha256-mCxPABZ6jRjUQx3bPP4vjA68ETbPLNz9V2pk9tO7pRQ=", + "lastModified": 1764522689, + "narHash": "sha256-SqUuBFjhl/kpDiVaKLQBoD8TLD+/cTUzzgVFoaHrkqY=", "owner": "nixos", "repo": "nixpkgs", - "rev": "8cd5ce828d5d1d16feff37340171a98fc3bf6526", + "rev": "8bb5646e0bed5dbd3ab08c7a7cc15b75ab4e1d0f", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-25.05", + "ref": "nixos-25.11", "repo": "nixpkgs", "type": "github" } }, "nixpkgs-darwin": { "locked": { - "lastModified": 1757590060, - "narHash": "sha256-EWwwdKLMZALkgHFyKW7rmyhxECO74+N+ZO5xTDnY/5c=", + "lastModified": 1764572236, + "narHash": "sha256-hLp6T/vKdrBQolpbN3EhJOKTXZYxJZPzpnoZz+fEGlE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "0ef228213045d2cdb5a169a95d63ded38670b293", + "rev": "b0924ea1889b366de6bb0018a9db70b2c43a15f8", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixpkgs-25.05-darwin", + "ref": "nixpkgs-25.11-darwin", "repo": "nixpkgs", "type": "github" } }, "nixpkgs-unstable": { "locked": { - "lastModified": 1757034884, - "narHash": "sha256-PgLSZDBEWUHpfTRfFyklmiiLBE1i1aGCtz4eRA3POao=", + "lastModified": 1764642553, + "narHash": "sha256-mvbFFzVBhVK1FjyPHZGMAKpNiqkr7k++xIwy+p/NQvA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "ca77296380960cd497a765102eeb1356eb80fed0", + "rev": "f720de59066162ee879adcc8c79e15c51fe6bfb4", "type": "github" }, "original": { @@ -184,11 +146,11 @@ ] }, "locked": { - "lastModified": 1757647720, - "narHash": "sha256-qf/utP3d1qBDl5R4yWUCt7E7CHTkw2NY8BEsS7lJ0dc=", + "lastModified": 1764683664, + "narHash": "sha256-Mr5HKf/bjAJ8H7/H0qJSk2BEV/OILkDIFKrGK0dUVUk=", "owner": "nix-community", "repo": "NUR", - "rev": "ef767aa25f9f917fe25d3848051f0e54ae42349f", + "rev": "b8b40e258cf4c959b06b7322648c87674633629b", "type": "github" }, "original": { @@ -207,11 +169,11 @@ ] }, "locked": { - "lastModified": 1756632588, - "narHash": "sha256-ydam6eggXf3ZwRutyCABwSbMAlX+5lW6w1SVZQ+kfSo=", + "lastModified": 1763909441, + "narHash": "sha256-56LwV51TX/FhgX+5LCG6akQ5KrOWuKgcJa+eUsRMxsc=", "owner": "nix-community", "repo": "plasma-manager", - "rev": "d47428e5390d6a5a8f764808a4db15929347cd77", + "rev": "b24ed4b272256dfc1cc2291f89a9821d5f9e14b4", "type": "github" }, "original": { @@ -222,11 +184,11 @@ }, "quadlet-nix": { "locked": { - "lastModified": 1754008153, - "narHash": "sha256-MYT1mDtSkiVg343agxgBFsnuNU3xS8vRy399JXX1Vw0=", + "lastModified": 1763141753, + "narHash": "sha256-XAHkOkLEWbRQZ6t/SowwOukrUfIneNQOC/UEQlTaPBU=", "owner": "SEIAROTg", "repo": "quadlet-nix", - "rev": "1b2d27d460d8c7e4da5ba44ede463b427160b5c4", + "rev": "211b5c626cf9ea91403b510e2ac5ca03a7194566", "type": "github" }, "original": { @@ -238,7 +200,6 @@ "root": { "inputs": { "agenix": "agenix", - "crowdsec": "crowdsec", "home-manager": "home-manager", "nix-darwin": "nix-darwin", "nixpkgs": "nixpkgs", @@ -258,11 +219,11 @@ }, "locked": { "dir": "pkgs/firefox-addons", - "lastModified": 1757591399, - "narHash": "sha256-OlvNzfsqDok0y5PDY+2dK5T53GsxAdm1YGdYHjxAiHM=", + "lastModified": 1764648280, + "narHash": "sha256-xniOnxIx/qhm+maO4mb9BZ7FytcUhNeTm1Y/QBjNf8o=", "owner": "rycee", "repo": "nur-expressions", - "rev": "b7d4f61ce9db44ba82859e15f6e1c175959948e3", + "rev": "119826bd51ad1a8012e0585f3a073571a35a812e", "type": "gitlab" }, "original": { @@ -286,21 +247,6 @@ "repo": "default", "type": "github" } - }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 204941e..bbd1632 100644 --- a/flake.nix +++ b/flake.nix @@ -3,8 +3,8 @@ inputs = { # Specify the source of Home Manager and Nixpkgs. - nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05"; - nixpkgs-darwin.url = "github:nixos/nixpkgs/nixpkgs-25.05-darwin"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11"; + nixpkgs-darwin.url = "github:nixos/nixpkgs/nixpkgs-25.11-darwin"; nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable"; # Inputs for both darwin and linux systems @@ -17,7 +17,7 @@ }; }; home-manager = { - url = "github:nix-community/home-manager/release-25.05"; + url = "github:nix-community/home-manager/release-25.11"; inputs.nixpkgs.follows = "nixpkgs"; }; nur = { @@ -30,10 +30,6 @@ }; # Linux-specific inputs - crowdsec = { - url = "git+https://codeberg.org/kampka/nix-flake-crowdsec.git"; - inputs.nixpkgs.follows = "nixpkgs"; - }; plasma-manager = { url = "github:nix-community/plasma-manager"; inputs = { @@ -45,20 +41,21 @@ # Darwin-specific inputs nix-darwin = { - url = "github:LnL7/nix-darwin/nix-darwin-25.05"; + url = "github:LnL7/nix-darwin/nix-darwin-25.11"; inputs.nixpkgs.follows = "nixpkgs-darwin"; }; }; outputs = { self, nix-darwin, nixpkgs, nixpkgs-darwin, nixpkgs-unstable - , home-manager, agenix, rycee-nurpkgs, nur, crowdsec, plasma-manager - , quadlet-nix, ... }: + , home-manager, agenix, rycee-nurpkgs, nur, plasma-manager, quadlet-nix, ... + }: let mkHomeConfiguration = { hostname, arch ? "x86_64", os ? "linux" , desktop ? false, extraModules ? [ ] }: let system = "${arch}-${os}"; - pkgs = import nixpkgs { + syspkg = if os == "darwin" then nixpkgs-darwin else nixpkgs; + pkgs = import syspkg { inherit system; config.allowUnfree = true; overlays = [ nur.overlays.default agenix.overlays.default ]; @@ -146,9 +143,6 @@ agenix.nixosModules.default home-manager.nixosModules.home-manager quadlet-nix.nixosModules.quadlet - crowdsec.nixosModules.crowdsec - crowdsec.nixosModules.crowdsec-firewall-bouncer - { nixpkgs.overlays = [ crowdsec.overlays.default ]; } ]; }; }; diff --git a/homes/common.nix b/homes/common.nix index 61ba3f1..078bdd5 100644 --- a/homes/common.nix +++ b/homes/common.nix @@ -45,7 +45,7 @@ in { jq julia-bin lynx - micromamba + mamba-cpp most nextflow p7zip @@ -84,6 +84,7 @@ in { "tailscale set --exit-node=$(tailscale exit-node suggest | awk '{print $4}' | head -n1)"; # tsed - TailScale Exit node Disconnect tsed = "tailscale set --exit-node="; + micromamba = "mamba"; }; sessionPath = [ "$HOME/.local/bin" ]; activation = { diff --git a/homes/darwin.nix b/homes/darwin.nix index d3c2982..9cabb63 100644 --- a/homes/darwin.nix +++ b/homes/darwin.nix @@ -7,7 +7,7 @@ ]; home = { packages = with pkgs; [ - asitop + macpm pinentry_mac (pkgs.writeShellScriptBin "uq" '' xattr -rdv com.apple.quarantine "/Applications/$1.app" @@ -34,22 +34,6 @@ launchd = { enable = true; agents = { - ollama = { - enable = true; - config = { - Label = "local.home-manager.ollama"; - ProgramArguments = [ "${pkgs.ollama}/bin/ollama" "serve" ]; - RunAtLoad = true; - KeepAlive = true; - StandardOutPath = - "${config.home.homeDirectory}/Library/Logs/ollama.log"; - StandardErrorPath = - "${config.home.homeDirectory}/Library/Logs/ollama-error.log"; - EnvironmentVariables = { - PATH = "${lib.makeBinPath [ pkgs.ollama ]}:$PATH"; - }; - }; - }; freetube-sync = { enable = true; diff --git a/homes/desktop.nix b/homes/desktop.nix index 03229ed..7b1b2ad 100644 --- a/homes/desktop.nix +++ b/homes/desktop.nix @@ -22,7 +22,6 @@ nil nixd nixfmt-classic - ollama quarto roboto-slab shellcheck diff --git a/programs/git.nix b/programs/git.nix index b4d790d..173e5f1 100644 --- a/programs/git.nix +++ b/programs/git.nix @@ -1,9 +1,11 @@ { ... }: { programs.git = { enable = true; - userName = "Thomas A. Christensen II"; - userEmail = "25492070+MillironX@users.noreply.github.com"; - extraConfig = { + settings = { + user = { + name = "Thomas A. Christensen II"; + email = "25492070+MillironX@users.noreply.github.com"; + }; core = { editor = "nvim"; }; credential = { helper = "store"; }; color = { ui = "auto"; }; diff --git a/programs/shells.nix b/programs/shells.nix index 93b2d9d..6745cf4 100644 --- a/programs/shells.nix +++ b/programs/shells.nix @@ -1,7 +1,7 @@ { pkgs, ... }: let conda_init = shell: '' - eval "$(${pkgs.micromamba}/bin/micromamba shell hook --shell ${shell})" + eval "$(${pkgs.mamba-cpp}/bin/mamba shell hook --shell ${shell})" ''; nd_bash_function = '' diff --git a/services/crowdsec.nix b/services/crowdsec.nix index 6a54584..5c3e279 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -1,101 +1,49 @@ -{ pkgs, config, ... }: -let - crowdsec-port = "2763"; - firewall-bouncer-name = "fw-bouncer"; - # Although this key can be reproduced by anyone who actually cares to, the - # Crowdsec API will not be exposed to the outside world, so keeping this key - # super secret really isn't that important to me. Still make it look random - # so that hungry botnets can't just slurp up the password in plaintext. - firewall-bouncer-key = builtins.hashString "sha256" - "${config.networking.hostName}-crowdsec-bouncer-salt"; - toMultiYAML = items: - pkgs.lib.concatMapStrings (item: - '' - - --- - '' + (pkgs.lib.generators.toYAML { } item) + "\n") items; -in { +{ pkgs, config, ... }: { services = { crowdsec = { enable = true; - allowLocalJournalAccess = true; - settings = { - api.server = { listen_uri = "127.0.0.1:${crowdsec-port}"; }; - crowdsec_service.acquisition_path = pkgs.writeText "acquisitions.yaml" - (toMultiYAML [ - { - source = "journalctl"; - journalctl_filter = [ "_SYSTEMD_UNIT=sshd.service" ]; - labels.type = "syslog"; - } - { - filenames = [ "/var/log/auth.log" ]; - labels.type = "syslog"; - } - { - filenames = [ "/var/log/syslog" "/var/log/kern.log" ]; - labels.type = "syslog"; - } - ]); + localConfig = { + acquisitions = [ + { + source = "journalctl"; + journalctl_filter = [ "_SYSTEMD_UNIT=sshd.service" ]; + labels.type = "syslog"; + } + { + filenames = [ "/var/log/auth.log" ]; + labels.type = "syslog"; + } + { + filenames = [ "/var/log/syslog" "/var/log/kern.log" ]; + labels.type = "syslog"; + } + ]; }; + hub = { + collections = [ + "crowdsecurity/base-http-scenarios" + "crowdsecurity/http-cve" + "crowdsecurity/http-dos" + "crowdsecurity/iptables" + "crowdsecurity/linux" + "crowdsecurity/sshd" + "crowdsecurity/whitelist-good-actors" + ]; + }; + settings = { + general = { api.server.enable = true; }; + # See https://github.com/NixOS/nixpkgs/issues/445342 + lapi.credentialsFile = "/var/lib/crowdsec/lapi-credentials.yaml"; + }; + autoUpdateService = true; }; + crowdsec-firewall-bouncer = { enable = true; - settings = { - api_url = "http://localhost:${crowdsec-port}"; - api_key = firewall-bouncer-key; - }; + registerBouncer.enable = true; }; }; - systemd.services.crowdsec.serviceConfig = { - ExecStartPre = let - bouncer-script = pkgs.writeScriptBin "register-bouncer" '' - #!${pkgs.runtimeShell} - set -eu - set -o pipefail - - if ! cscli bouncers list | grep -q "${firewall-bouncer-name}"; then - cscli bouncers add "${firewall-bouncer-name}" --key "${firewall-bouncer-key}" - fi - ''; - collection-check = collection: '' - - if ! cscli collections list | grep -q "${collection}"; then - cscli collections --trace install "${collection}" - sleep 1 - fi - - ''; - collections = [ - "crowdsecurity/base-http-scenarios" - "crowdsecurity/http-cve" - "crowdsecurity/http-dos" - "crowdsecurity/iptables" - "crowdsecurity/linux" - "crowdsecurity/sshd" - "crowdsecurity/whitelist-good-actors" - ]; - collection-script = pkgs.writeScriptBin "install-collections" '' - #!${pkgs.runtimeShell} - set -eu - set -o pipefail - - # I had to run these commands in order to manually install collections - # using cscli. - # Not sure how often they should actually be run, but I would rather - # include this here. - # https://discourse.crowdsec.net/t/solved-cant-find-collections-appsec/1830 - cscli capi register - sleep 1 - cscli hub update - sleep 1 - - ${pkgs.lib.concatMapStrings collection-check collections} - ''; - in [ - "${bouncer-script}/bin/register-bouncer" - "${collection-script}/bin/install-collections" - ]; - }; + systemd.tmpfiles.rules = let cfg = config.services.crowdsec; + in [ "d /var/lib/crowdsec 0755 ${cfg.user} ${cfg.group}" ]; } diff --git a/services/samba.nix b/services/samba.nix index e6fa607..b248d33 100644 --- a/services/samba.nix +++ b/services/samba.nix @@ -2,7 +2,6 @@ services.samba = { enable = true; package = pkgs.sambaFull; - securityType = "user"; openFirewall = true; settings = { global = { diff --git a/systems/linux/bosephus.nix b/systems/linux/bosephus.nix index 98cf0e7..79dcf54 100644 --- a/systems/linux/bosephus.nix +++ b/systems/linux/bosephus.nix @@ -17,8 +17,8 @@ boot.loader.efi.canTouchEfiVariables = true; # Ignore lid - so I can close without having the system go into sleep mode - services.logind.lidSwitch = "ignore"; - services.logind.lidSwitchDocked = "ignore"; + services.logind.settings.Login.HandleLidSwitch = "ignore"; + services.logind.settings.Login.HandleLidSwitchDocked = "ignore"; # Secrets age.secrets = { From 24d7b7d533c875f9bb47a1062352268dcebb5147 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 4 Dec 2025 08:59:53 -0600 Subject: [PATCH 046/149] programs (zed): Add build+preview on demand support for LaTeX --- programs/zed.nix | 25 ++++++++++++++++++++++++- systems/darwin/corianne.nix | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/programs/zed.nix b/programs/zed.nix index 19beb45..b3f7fd6 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -1,4 +1,4 @@ -{ ... }: { +{ pkgs, ... }: { programs.zed-editor = { enable = true; extensions = [ @@ -58,6 +58,22 @@ initialization_options.formatting.command = [ "nixfmt" ]; settings.nix.flake.autoArchive = true; }; + texlab = { + settings = { + build = { + onSave = false; + forwardSearchAfter = true; + }; + forwardSearch = if pkgs.stdenv.hostPlatform.isDarwin then { + executable = + "/Applications/Skim.app/Contents/SharedSupport/displayline"; + args = [ "-r" "%l" "%p" "%f" "-g" ]; + } else { + executable = "/usr/bin/okular"; + args = [ "--unique" "file:%p#src:%l%f" ]; + }; + }; + }; tinymist = { settings = { exportPdf = "onSave"; @@ -81,5 +97,12 @@ ui_font_size = 16; wrap_guides = [ 80 92 120 ]; }; + userTasks = [{ + label = "latexmk (project)"; + command = "latexmk"; + args = [ "-synctex=1" "-pdf" "-recorder" ]; + cwd = "$ZED_DIRNAME"; + tags = [ "latex-build" ]; + }]; }; } diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index dea0f34..df713b7 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -206,6 +206,7 @@ in { "rig" "rstudio" "signal" + "skim" "slack" "stats" "steam" From ac837750c9aeafa1d29e85ec89dcbd8b7e981e14 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 4 Dec 2025 09:00:37 -0600 Subject: [PATCH 047/149] nix-builder (corianne): Add rosetta builder --- flake.lock | 59 +++++++++++++++++++++++++++++++++++++ flake.nix | 15 +++++++--- systems/darwin/corianne.nix | 24 +++++++++++++-- 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/flake.lock b/flake.lock index 982ba78..6141529 100644 --- a/flake.lock +++ b/flake.lock @@ -90,6 +90,64 @@ "type": "github" } }, + "nix-rosetta-builder": { + "inputs": { + "nixos-generators": "nixos-generators", + "nixpkgs": [ + "nixpkgs-darwin" + ] + }, + "locked": { + "lastModified": 1756177999, + "narHash": "sha256-aSbB7/jrt7ujiJ55f2uGhOo+usGxVSkqbAMVgg2jDls=", + "owner": "cpick", + "repo": "nix-rosetta-builder", + "rev": "ebb7162a975074fb570a2c3ac02bc543ff2e9df4", + "type": "github" + }, + "original": { + "owner": "cpick", + "repo": "nix-rosetta-builder", + "type": "github" + } + }, + "nixlib": { + "locked": { + "lastModified": 1736643958, + "narHash": "sha256-tmpqTSWVRJVhpvfSN9KXBvKEXplrwKnSZNAoNPf/S/s=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "1418bc28a52126761c02dd3d89b2d8ca0f521181", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixos-generators": { + "inputs": { + "nixlib": "nixlib", + "nixpkgs": [ + "nix-rosetta-builder", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1737057290, + "narHash": "sha256-3Pe0yKlCc7EOeq1X/aJVDH0CtNL+tIBm49vpepwL1MQ=", + "owner": "nix-community", + "repo": "nixos-generators", + "rev": "d002ce9b6e7eb467cd1c6bb9aef9c35d191b5453", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-generators", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1764522689, @@ -202,6 +260,7 @@ "agenix": "agenix", "home-manager": "home-manager", "nix-darwin": "nix-darwin", + "nix-rosetta-builder": "nix-rosetta-builder", "nixpkgs": "nixpkgs", "nixpkgs-darwin": "nixpkgs-darwin", "nixpkgs-unstable": "nixpkgs-unstable", diff --git a/flake.nix b/flake.nix index bbd1632..59c9ce0 100644 --- a/flake.nix +++ b/flake.nix @@ -44,11 +44,15 @@ url = "github:LnL7/nix-darwin/nix-darwin-25.11"; inputs.nixpkgs.follows = "nixpkgs-darwin"; }; + nix-rosetta-builder = { + url = "github:cpick/nix-rosetta-builder"; + inputs.nixpkgs.follows = "nixpkgs-darwin"; + }; }; outputs = { self, nix-darwin, nixpkgs, nixpkgs-darwin, nixpkgs-unstable - , home-manager, agenix, rycee-nurpkgs, nur, plasma-manager, quadlet-nix, ... - }: + , home-manager, agenix, rycee-nurpkgs, nur, plasma-manager, quadlet-nix + , nix-rosetta-builder, ... }: let mkHomeConfiguration = { hostname, arch ? "x86_64", os ? "linux" , desktop ? false, extraModules ? [ ] }: @@ -119,8 +123,11 @@ }; agenix = agenix; }; - modules = - [ ./systems/darwin/corianne.nix agenix.darwinModules.default ]; + modules = [ + ./systems/darwin/corianne.nix + agenix.darwinModules.default + nix-rosetta-builder.darwinModules.default + ]; }; nixosConfigurations = { diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index df713b7..f1c1eb2 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -26,9 +26,27 @@ in { }; # Auto upgrade nix package and the daemon service. - nix.enable = true; - #services.nix-daemon.tempDir = "/nix/tmp"; - nix.package = pkgs.nix; + nix = { + enable = true; + gc = { + automatic = true; + interval = { Weekday = 1; }; + options = '' + --delete-older-than 14d + ''; + }; + # Needed for rosetta-builder, see + # + # + linux-builder = { + enable = true; + ephemeral = true; + }; + extraOptions = '' + extra-platforms = x86_64-darwin + ''; + }; + nix-rosetta-builder.onDemand = true; # Create /etc/zshrc that loads the nix-darwin environment. programs.zsh.enable = true; # default shell on catalina From 91083619640f3f1df55a554bc453c9ca601bc5ba Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 4 Dec 2025 09:00:54 -0600 Subject: [PATCH 048/149] pkgs (desktop): add nixos-rebuild package --- homes/desktop.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/homes/desktop.nix b/homes/desktop.nix index 7b1b2ad..255db78 100644 --- a/homes/desktop.nix +++ b/homes/desktop.nix @@ -22,6 +22,7 @@ nil nixd nixfmt-classic + nixos-rebuild quarto roboto-slab shellcheck From 0571d801edfe6009b430207bed9ba06682de736a Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 4 Dec 2025 09:07:16 -0600 Subject: [PATCH 049/149] services (bosephus): Remove pihole service --- services/pihole.nix | 27 --------------------------- systems/linux/bosephus.nix | 1 - 2 files changed, 28 deletions(-) delete mode 100644 services/pihole.nix diff --git a/services/pihole.nix b/services/pihole.nix deleted file mode 100644 index ed4cd19..0000000 --- a/services/pihole.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ config, ... }: - -{ - age.secrets = { - pihole-credentials = { - file = ./../secrets/pihole.age; - owner = "root"; - group = "root"; - }; - }; - virtualisation = { - quadlet = { - containers = { - pihole = { - containerConfig = { - image = "docker.io/pihole/pihole:2025.06.2"; - publishPorts = - [ "53:53/tcp" "53:53/udp" "80:80/tcp" "443:443/tcp" ]; - environmentFiles = [ config.age.secrets.pihole-credentials.path ]; - networks = [ "bridge" ]; - dns = [ "127.0.0.1" "194.242.2.9" "9.9.9.9" ]; - }; - }; - }; - }; - }; -} diff --git a/systems/linux/bosephus.nix b/systems/linux/bosephus.nix index 79dcf54..6c8d181 100644 --- a/systems/linux/bosephus.nix +++ b/systems/linux/bosephus.nix @@ -9,7 +9,6 @@ ./hardware-configuration/bosephus.nix ./hardware-configuration/bosephus-external-drives.nix ./../../services/samba.nix - ./../../services/pihole.nix ]; # Bootloader. From a0175f565bd07dcade50fc431660c0d37152efc3 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 8 Dec 2025 08:11:43 -0600 Subject: [PATCH 050/149] secrets! (pihole): Remove pihole secrets --- secrets.nix | 1 - secrets/pihole.age | Bin 926 -> 0 bytes 2 files changed, 1 deletion(-) delete mode 100644 secrets/pihole.age diff --git a/secrets.nix b/secrets.nix index 8042bf6..1e0ec3d 100644 --- a/secrets.nix +++ b/secrets.nix @@ -36,5 +36,4 @@ in { ++ [ corianne-host ]; "secrets/network-information.age".publicKeys = system-administrators ++ [ bosephus-host ]; - "secrets/pihole.age".publicKeys = system-administrators ++ [ bosephus-host ]; } diff --git a/secrets/pihole.age b/secrets/pihole.age deleted file mode 100644 index 1b2bc2533d7d7de5063e15de08cacfa0e5dd6df6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 926 zcmZ9~ON-nD003YWtr$u@C<-EMEXr2Hn8#!?31T6WWL}x)wHiu+u2=O+39LsdRK+FNAr|z)>7yg5R_Y5XYpTwKC@i|0 zm>2{Jbij0gVmR{R$;MKx8y=gND(0nem`}D~8mAS7bV!j+JYSbvD!!_rHk@Y}NT%gR zOET+xPfU=sn&Jr5@3mQaG%gV_o;75@KmwYe)DZ_jnrT~^fv~fd7(`U*aHY??lB*y- z7fG_0W0P^jNDMlZRyEV$t#$?msJa|8@kGvL&K^u6NNfhI-W7UXVkD5c&?hw8@1>~5 zMSwA(>3HcYbr&(Z2s(os94^o%PY(K##3-8?O2(eUY_=F~RjV$LTP6lee#1(c{c zbvDlXP>h>Q(ZHJ`yy#a`KB#*gAi%Q0R^rQ1b%j+97Ue9&K$chfAp+!&jp* Date: Mon, 8 Dec 2025 14:44:22 -0600 Subject: [PATCH 051/149] service (freshrss): Add freshrss service --- secrets.nix | 2 + secrets/freshrss.toml.age | Bin 0 -> 1285 bytes services/freshrss.nix | 124 +++++++++++++++++++++++++++++++++++++ systems/linux/mcentire.nix | 1 + 4 files changed, 127 insertions(+) create mode 100644 secrets/freshrss.toml.age create mode 100644 services/freshrss.nix diff --git a/secrets.nix b/secrets.nix index 1e0ec3d..45783ee 100644 --- a/secrets.nix +++ b/secrets.nix @@ -34,6 +34,8 @@ in { ++ [ mcentire-host ]; "secrets/darwin-policies-json.age".publicKeys = system-administrators ++ [ corianne-host ]; + "secrets/freshrss.toml.age".publicKeys = system-administrators + ++ [ mcentire-host ]; "secrets/network-information.age".publicKeys = system-administrators ++ [ bosephus-host ]; } diff --git a/secrets/freshrss.toml.age b/secrets/freshrss.toml.age new file mode 100644 index 0000000000000000000000000000000000000000..9bfa06c148bbaa685ffb520116db0ee1f6964663 GIT binary patch literal 1285 zcmZY2`)?Bk003YE1h+0LkPQeLvQlLul+s<>>w~~d*Vnb(wY^@i*DEB@_O93V+Fl>m z_O1}ZcuaJX06N$phz`ic28huOofE?VB`{FKQwL)Rh%BNI351z|zt8U<_<}Sgr&8gp zkmh1+YAKtg6$L;fZ;<42Q8`5_K@iYOVhL5Egh+5ZWR{V>dV?1=nMnc9vj!~;CyPF7AcE;&1>nuFkTpm|DK(6zQjkfb#bYsb#AhaC8YeP& z184GiQkn}1IM&1!g z(s`$hnY^hoZZ1ztQZa)kX15@KTL|d+JVXSnc8$ZU5Fp-)+9^C+G5}FK0t()u$l{H8 zG0usg@w7HU>5^_ISO}|1O)hHyRbiNqF*t(OFbC)hhRK_ZX^cgSlAswQ^C}Sb+qsm+ zqq8WIE~}fisC{G(H1nWK=wmdNhYWox0aaao1QpEx?TaAfU*<@-xp zryUvWyDoivC)Kos+jmiPue-NXc-8UA=5s?2?q3)^<*Vr)t6kGvR&`6%I<$8721RGb zgY8xC{C(o=)xU23AdYW&Ffn!JiMmbAvtGRAxqa~clM%XX&Unq6W5S_@<#Q@$x1oF6 z;kS3xZDTIANc;NEzoKR#=K74Iy*tzx3Wz(J?95txP z*H=tH^FzH=ElLA19T;9w=W5HooNwI!FwwIP*0=v#`Au4~NlARP5c^f~^}XD;$yI@^ z8%OR|HY@gYtlz19a`W1THBY;O15(>}AUI0y>FkQOFOrR2s>Jp&ORML~-S&-VD#q!> zTgJ8rrkovqI*~b=71e-Di}X-gZ|~-nktJ<|Aw>MSY{u}48T}tb$_K9Y3?T2mH@Bhr zy0$vK$hoMZ0%s*>_`|(#M5T|92bcXOJ{+3zu=~leN4t-Yw@e>CG0_;~X4Xmf+O+LM zP4TV+8l&yJXZO){*uaxJ>ve-XzT=C^2`hQ!M(zAQ)9MCl+5)(?A!}{j1rD@7 YLKB}BFMJ%nQT5@0^545&+b Date: Mon, 8 Dec 2025 17:22:33 -0600 Subject: [PATCH 052/149] fix (freshrss): Set OIDC variables --- secrets/freshrss.toml.age | Bin 1285 -> 1652 bytes services/freshrss.nix | 18 +++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/secrets/freshrss.toml.age b/secrets/freshrss.toml.age index 9bfa06c148bbaa685ffb520116db0ee1f6964663..9fc2f10451f6ba0748e727945e1c5e1e0668054f 100644 GIT binary patch delta 1569 zcmV++2HyFF3iJ$+EPpq8Nl!&)MQ&|jMNeT#GHEn5O)^qcSx!lAcSdq;V^3yhL25@+ zVMtV0X9_h-Ic!vTbV*ilL`-8vWO!#%Rdz^KP*hhnGBkNFbb3!sGi73VMlnxkRSGRW zAaiqQEoEdfH8n9gATehzcz1UoRCz&RVt8#yNo#3RLuhGDI7V_&XJvIZOlEIGGgmla zNlj@~Q*lBtT6I!u3TjkDGizBkQg}!(V>32WNkVp0NNZMdO>8eYT61euaW8CaR&Qu> zF-}c1k?|K-cvfp=cvm@dVsuPSR&POCI5jYGSTHzYH8C%6bwzA4Y(`{od2VkwcR^N|ZDC|EH!*rjcrS8tQ8Q9cZ&+knP*_)RIdW)hQCc@RdTC>mUjY|aR&PNy zR!L?`Lu6D}SZzmjW@l4!a6)=aFL^I{O;2KNFLG^cGFoO)aWZcTaaUP%VK+BdF=j6{ zN^3|}aZyKaM^IKlIY&%pNn~nsVK7Z-XJspHS8sEZ%>fvHLQP0@W<+&KFi=cROhY+K zK}bbKT32!}ZB9~8NN`n2Suj#;F;;nXML`N{ZBKVXVMSCpI5=@ZbSp)7GdD6xGEFou zI9G5oFHB`ZQ*uycNpeF=XE+KiJ|J^*Xf0)AGBq_ZIUp-TFjrD%Aa!OhVR1)MXmD0W zIZIS+czQ2?c}{OKRVz1eM{`$jLNskJXJ{{1b4xN)X9{6SdSOv)LUB@YOm1#@QZ_Yh zaY<5YP%=eUSZh&aH$zrxNm+13F;_)&Zwf6fEg)7mGg2}`M0a8`M^0`wNNPrSLT7Jb zdR9keN?J=$PjPp3XI58wZEkZ}FbcW1l)wDe@Wl#$Gq4W$K|7M?WR~j263nSlO( zmtM~sX)J_?T)aw{0@QyN&|5kOHGyO@8&F{OxbaF#G+*PoiSd!Y(eutUqLgFJ!9ZBe z!H){7-g;K_4IA2DoMW*&DR&Pv0gz{a2AeE)Qh=}%!Qlmbg>7!B_hw+|xX8W28oW~h z0OhZL#xItLH@ze_HavoHHu*pPn{OLvrd}O|u;EvgMZw`lC7F54CEG?q39(UMvJ9zl zvz=<)x?7# z)F0(l_BFG+DWT-m8_sMS?!mWRu{-t7%>LP(fJEWK zDwLUd9T&jubm&?+D#v7usMKgb*kAt(8YZMJz+{vSbHt>`+#|hZLWMAP@Ld8R&bZY? zV9}9pS^9+yKiV`Xb&RplSMBRzKPWIGh;Adpor|jAJ8$G?7Sjp?w`N!in%x~)CX*e1 zt3D}I22~bW^N_m6OvuqD62FngU1E;YAMAujEElS~KuNMyaA+pKhNj5PzK6R92sIlq zoRaeA7jlszyVm{H4u=v<6RU3DHdwq28}&4KB#^0VfdqYaL6$7@QJMhkGz+dL4(w&e ztwhh5=wUj!$<>1Cbk^QH(GljOrj9G}rdx@}w+aNxQ_|Ii?FHz!jdgV;bzBGGJixvh+I(IxQBHWNAd z`6GkJ^NLIael`mwbr}_sMvlsSkc46)Eua>II|SAV=-oGYeo4_9S=q9OzVGpW8Dq5s z-IV#f#N}-d%F(H|{_59Jx^X2^Wc{jm&CFU;K6OM>tS9=JnM;B+f@Ymot-c2lXA`JN zq|}?IpfFuHWuGf9V`+0>Q7@q*K@4@SbG_o>wEA3>suwixEKVy<69^@ukDS9ovJ8eo zV^jPX)6uqz54IA(wRy(CfRVs|ifEZ?1SsXuzF3yxXONJBx8|V>D4F_xyM?Cfy;fPJ zJ(OONxG9v;Xa^#?D6N}6DyCenC7}@^q_`LXSsBZw1Sr*R$wPXoNo~Y>PH76F(rW;9 z04u>ER$=8|_jcw@oArL`RX1=ELPJgkTkW!NDm5s6V~MmGTTyn>SBhL1#)TO^>eMj7 TQp=5l-tjk9811F4Ea9H#b} zbcU3IP9{S^iz6Y6)g&@pSZIl+(lVC>0U$&djxla;Mo;G(l8hLXC!H#~KI4ibVk~U0 zGek8w9rSqhYPfB(f{^DiNgTrL@t{zjU~KM$0R!!_2oz4#q>MUoIcx#={z#4%8muBbUY(humP5fI;0vcYY9Z@tX0VDT05VvniUp@n1fg&X7&@QyhainPyuoKce4#ji zT7`a;RBK_}uea4n=(>C+ud}%21kL0mq$=ml_+gzZ?hU(C{|^vqYY3F)$6W>l$`X`a zn57t!V_fEf)rn|HUDlvZxJZOHiEZYP)SQw><$wXRdL>~gh`AYpQEiQ%G^26^Gh-QoNTYgl0!J|$ zMFXp;`*7u}p|-JtQ8@6=tK^T>JCF-&%Zta`e`Z7iUQ=MtnWFX3_=K>8_pB4sO||E5 z4>ewT34A%dr#Zjn3ip|Iz{v~FXgIol(aHn)Z8MJ!_1_RYxf`ormf3#^xZl&)#l7nM zWb66ihYv1}opx6Cj90B|EGoMVv<$DGw@KX9`LMO@y}wVMyH@z?)(^aJ)5ED5b52%o zX`K7w9rVtj4^IW?qWKe*Z;x|_7Z=Yjo!5@->ww>FtKPv}ZWi?SUwBb+79Bm`x~8M5 z`q_ekt$olRU-gb|NF2Go+-KeP=Zcxn4~=Q$)a$FJpoQMPvSz7!|0akbXTl!6cU)UlgKU$3c%K!R)`rGIl_qNTW_evYZdpkGoR8HQyzG>alZqJ~= z^c@I}QG2_(gB?qR($kVChu@q1VGR=a+MSXo+ zR|l504|x&Z=fc?|t7Z>u4-^kx>m5Yi|Dd9_@rJTIvBbKhq)B_p?KGnVF`tNU+|1@yt z@yg?8deI1Ai8QvHTlrvk=fS|eUqrh{7qn1aOHUEE%deh3RI;5nH*f7ZwgDfUyt`2~ z#1d^^luj9`t2e8v7WV7b*7|2If~#s%#+KdSV8>%D@@ekk$G)3oyABrr-u>DE-q3&D C6W@&h diff --git a/services/freshrss.nix b/services/freshrss.nix index e1da1ef..93272aa 100644 --- a/services/freshrss.nix +++ b/services/freshrss.nix @@ -101,8 +101,19 @@ in { CRON_MIN = "2,32"; LISTEN = "0.0.0.0:${port}"; OIDC_ENABLED = "1"; + OIDC_PROVIDER_METADATA_URL = + "https://auth.millironx.com/application/o/freshrss/.well-known/openid-configuration"; + OIDC_REMOTE_USER_CLAIM = "preferred_username"; + # OIDC_SCOPES = "openid profile"; + # OIDC_X_FORWARDED_HEADERS = "X-Forwarded-Host X-Forwarded-Port X-Forwarded-Proto"; }; - secrets = [ "FRESHRSS_INSTALL,type=env" "FRESHRSS_USER,type=env" ]; + secrets = [ + "FRESHRSS_INSTALL,type=env" + "FRESHRSS_USER,type=env" + "OIDC_CLIENT_ID,type=env" + "OIDC_CLIENT_SECRET,type=env" + "OIDC_CLIENT_CRYPTO_KEY,type=env" + ]; healthCmd = "cli/health.php"; healthTimeout = "10s"; healthStartPeriod = "60s"; @@ -111,14 +122,15 @@ in { healthRetries = 3; networks = [ networks."${serviceContainer}".ref ]; }; - unitConfig.Requires = [ containers."${serviceContainer}-db".ref ]; - unitConfig.After = [ containers."${serviceContainer}-db".ref ]; + unitConfig.Requires = [ secrets.ref containers."${serviceContainer}-db".ref ]; + unitConfig.After = [ secrets.ref containers."${serviceContainer}-db".ref ]; }; }; networks."${serviceContainer}" = { }; autoUpdate.enable = true; + autoEscape = true; }; }; } From 1eebebdeb0848b48a7db2f157e8cf6454c2e2895 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 8 Dec 2025 17:25:48 -0600 Subject: [PATCH 053/149] fix (freshrss): Bind port --- services/freshrss.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/services/freshrss.nix b/services/freshrss.nix index 93272aa..8f4d193 100644 --- a/services/freshrss.nix +++ b/services/freshrss.nix @@ -121,6 +121,7 @@ in { healthInterval = "75s"; healthRetries = 3; networks = [ networks."${serviceContainer}".ref ]; + publishPorts = [ "127.0.0.1:${port}:${port}" ]; }; unitConfig.Requires = [ secrets.ref containers."${serviceContainer}-db".ref ]; unitConfig.After = [ secrets.ref containers."${serviceContainer}-db".ref ]; From 3f35901fd31c5862fa6791f6e7588d1150369712 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 8 Dec 2025 17:29:00 -0600 Subject: [PATCH 054/149] fix (freshrss): Uncomment required variables --- services/freshrss.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/freshrss.nix b/services/freshrss.nix index 8f4d193..b2985db 100644 --- a/services/freshrss.nix +++ b/services/freshrss.nix @@ -104,8 +104,8 @@ in { OIDC_PROVIDER_METADATA_URL = "https://auth.millironx.com/application/o/freshrss/.well-known/openid-configuration"; OIDC_REMOTE_USER_CLAIM = "preferred_username"; - # OIDC_SCOPES = "openid profile"; - # OIDC_X_FORWARDED_HEADERS = "X-Forwarded-Host X-Forwarded-Port X-Forwarded-Proto"; + OIDC_SCOPES = "openid profile"; + OIDC_X_FORWARDED_HEADERS = "X-Forwarded-Host X-Forwarded-Port X-Forwarded-Proto"; }; secrets = [ "FRESHRSS_INSTALL,type=env" From 1fc358b482ce80a3e0ba8528a2be9eed9f84362d Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 8 Dec 2025 20:40:27 -0600 Subject: [PATCH 055/149] fix (freshrss): Networking stack fixes --- services/freshrss.nix | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/services/freshrss.nix b/services/freshrss.nix index b2985db..aa1210b 100644 --- a/services/freshrss.nix +++ b/services/freshrss.nix @@ -25,7 +25,9 @@ in { }; services.caddy.virtualHosts."feeds.millironx.com".extraConfig = '' - reverse_proxy http://127.0.0.1:${port} + reverse_proxy http://127.0.0.1:${port} { + header_up X-Forwarded-Port 443 + } ''; systemd.tmpfiles.rules = builtins.map createTmpfilesRule @@ -96,16 +98,21 @@ in { autoStart = true; containerConfig = { image = "docker.io/freshrss/freshrss:1"; + # Required to allow the container to talk to the host ports, in + # other words, to resolve Authentik correctly + addHosts = [ "auth.millironx.com:host-gateway" ]; environments = { TZ = osConfig.time.timeZone; CRON_MIN = "2,32"; LISTEN = "0.0.0.0:${port}"; + TRUSTED_PROXY = "172.16.0.1/12 192.168.0.1/16"; OIDC_ENABLED = "1"; OIDC_PROVIDER_METADATA_URL = "https://auth.millironx.com/application/o/freshrss/.well-known/openid-configuration"; OIDC_REMOTE_USER_CLAIM = "preferred_username"; - OIDC_SCOPES = "openid profile"; - OIDC_X_FORWARDED_HEADERS = "X-Forwarded-Host X-Forwarded-Port X-Forwarded-Proto"; + OIDC_SCOPES = "openid email profile"; + OIDC_X_FORWARDED_HEADERS = + "X-Forwarded-Host X-Forwarded-Port X-Forwarded-Proto"; }; secrets = [ "FRESHRSS_INSTALL,type=env" @@ -123,8 +130,10 @@ in { networks = [ networks."${serviceContainer}".ref ]; publishPorts = [ "127.0.0.1:${port}:${port}" ]; }; - unitConfig.Requires = [ secrets.ref containers."${serviceContainer}-db".ref ]; - unitConfig.After = [ secrets.ref containers."${serviceContainer}-db".ref ]; + unitConfig.Requires = + [ secrets.ref containers."${serviceContainer}-db".ref ]; + unitConfig.After = + [ secrets.ref containers."${serviceContainer}-db".ref ]; }; }; From 6fbf0f2b7d209ad5bd60c1cc2d7f05bfe3125115 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 9 Dec 2025 08:47:04 -0600 Subject: [PATCH 056/149] fix (freshrss): OIDC config mounting After much troubleshooting, I figured out that FreshRSS does not actually support OIDC with the use of the environment variables for configuration. Instead, the config files actually have to be set with the web wizard and persisted with a volume mount. Do that. --- secrets/freshrss.toml.age | Bin 1652 -> 1185 bytes services/freshrss.nix | 14 +++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/secrets/freshrss.toml.age b/secrets/freshrss.toml.age index 9fc2f10451f6ba0748e727945e1c5e1e0668054f..e253b881a3ab7741cedfcd65baaf390014ecedea 100644 GIT binary patch delta 1099 zcmZ9}>u(bU003}7B3eMjOa=t7VwS-&0ly|&kONL}x)*RJdPx_dBE z4DbPDB7rO#AIl=T3^v6DV$dLv@YrT1%xp0*6eB@JKpBJKkgDJP{R_Xl3wxe;yRkwV zT`=Hs(-8-6@R2z0PoR2)@MR0F6dVdUXsg$%fW|E2lX;aVizxzWNA(1pC}v&yc$v0= zpr6xaas+@&e!ClWx{_%Z2L@Hzm(`_GQp>TB!JxCKbvz)6qB=qg?h+ia;^jbz1Sz9v z_v`eW#hf5;)Jtht!9qb$u&qq_Y@~|gm0}Bu#;sB`V`8vu8uZ$A0E7fRN}Rw_P=GX0 zSw&+ITupnYYUxD4m5fN}@tf`8B$_r@t;RG3DGJ2<*(MyYp+ObiE|fJS zD`*P-6q1IBq%nsS`7o|&$pKPp0;Wx9Ims2%oJ-snn^Q}NfdXnM!hwvH#A&L%-2`%^ z3~0g_YA!|dCcm5mQW>ORNjO|8o{3n(h!o6%vKPzdNspTk$U+uG87o2(PLC7Aynd&F z5ToM0(K)ph#)zUVb`Fs7h%HWO^6de$E@@+pZrNuNO(h~6@;M7EE959xWy@wV8Yin@ zrW9vu;~Ys;iicWwEE(`5K-8t!y+tBvH6cZY`Tu|h0ck(4&H`kJY0b5;Kb1L!UF)NZ_KV$BTmHHsd@wwJLC>QN(U1QLJ@Q3O{e%9Y zz4^~s$%Bq>yXJgmviH`O*UhBd7+c1!pZ;W-P$>*5!wa@mmQU{)&Q~t4K(ELH-);C_ zf4g&X)_kXWBhgoPdGaauxvKPTqRsZJcA&Z+Y9M}+R8Z`+dHU>*pyY$V!)N^? zq55NTH)!l);;MMUC+I_@;`Ldwif^Z delta 1570 zcmV+-2Hp9g3G@t*EPpq8Nl!&)MQ&|jMNeT#GHEn5O)^qcSx!lAcSdq;V^3yhL25@+ zVMtV0X9_h-Ic!vTbV*ilL`-8vWO!#%Rdz^KP*hhnGBkNFbb3!sGi73VMlnxkRSGRW zAaiqQEoEdfH8n9gATehzcz1UoRCz&RVt8#yNo#3RLuhGDI7V_&XJvIZOlEIGGgmla zNlj@~Q*lBtT6I!u3TjkDGizBkQg}!(V>32WNkVp0NNZMdO>8eYT61euaW8CaR&Qu> zF-}c1k?|K-cvfp=cvm@dVsuPSR&POCI5jYGSTHzYH8C%6bwzA4Y(`{od2VkwcR^N|ZDC|EH!*rjcrS8tQ8Q9cZ&+knP*_)RIdW)hQCc@RdTC>mUjY|aR&PNy zR!L?`Lu6D}SZzmjW@l4!a6)=aFL^I{O;2KNFLG^cGFoO)aWZcTaaUP%VK+BdF=j6{ zN^3|}aZyKaM^IKlIY&%pNn~nsVK7Z-XJspHS8sEZ%>fsGVM0wvb!J3$Nia}MPE12N zOF>9QMOs&KFKtdzPe^c8Nm(#bY%x}Obwxo6Yi&<=LSaQzI5;?QL3ArccQZFKNit0| zFF03lGA~SJLQ`^3Wl3^FOJ_I=Ej}P~b7(DPWHL21F*zVBLoioTXCQTEFJW;cO zd6!<#8)+Cn2$j!J&J=iDX56ND{|JM3@$q*^A9w@?R_|?RN zA=Dq`RrWQryD6dM)#Uw!tW%gf2~tVxh?(Di6HYp;Ya7mN8}7lkU9mg$&dmPVoq$B) z!YY)Rc^wzP?R4l`IV#6wjHuLTKiFUY3mPV*F2H1z4Rge#$lN2nWkQ88cJN&SAkMhe zL}1a8Z&~_<4L{m6D0Pgn&{ys2VLvD^BZzJz!<~z&;5%>RXBN{61Gi>a3!2>>StgTz z9jiVmR0dTRS@V#(#!Sf3CKA7q#$95L(;w`FM=TeryFf{@Rd8q~zlNsB&Ax}b2M9GA zF`Sa}=NEF3BD>c8)eeUeOcSea-!@ph3>)<{c_fgjYk>rPc0rab^HG`r>@*9mCl2go z$E`%qnCM|TxyjXn>2%iKJkb&6qoQ>-WYnVCz1G=gTGR;|7V5oZ&q zNu<=9r=T!hIAxzJE@NqPU{NojBS8#xu5-QO;k5c(l&Tjr?<`I$P7??vqK}-zLb42o zLSs|>7}L?Vix0LEz_oeCz<`l|z=~*@Y6K|d(7srf;%AVMg16?O3n-cTe!GRH>%CT4 zr9G5hk+><8(P#%Ex+txiKPskNt|g%nA*8q%0a+Q#rUWR}ZplM>s!46cdQNEyqS9*s zbpR{DAy#4KU-x$AO`G+8>Qy&z5kf;w1zYX1a4Iz@eq)KW8Cy|y(pQQZT*ieNKI+sk U!BdvvGu&uI%oixil6p9*qiI{35C8xG diff --git a/services/freshrss.nix b/services/freshrss.nix index aa1210b..2f142ff 100644 --- a/services/freshrss.nix +++ b/services/freshrss.nix @@ -7,10 +7,9 @@ let serviceContainer = "freshrss"; stateSubDir = subDir: "${stateDirectory}/${subDir}"; createTmpfilesRule = subDir: "d ${stateSubDir subDir} 1755 ${user} ${user}"; - volumeMount = subDir: bindDir: "${stateDirectory}/${subDir}:${bindDir}:U"; dbDirectories = [ "database" ]; - serviceDirectories = [ ]; + serviceDirectories = [ "data" "extensions" ]; in { age.secrets = { "freshrss.toml" = { @@ -85,9 +84,8 @@ in { healthInterval = "30s"; healthRetries = 5; healthStartPeriod = "20s"; - volumes = pkgs.lib.imap0 (i: sub: - volumeMount sub - (builtins.elemAt [ "/var/lib/postgresql/data" ] i)) dbDirectories; + volumes = + [ "${stateDirectory}/database:/var/lib/postgresql/data:U" ]; networks = [ networks."${serviceContainer}".ref ]; }; unitConfig.Requires = [ secrets.ref ]; @@ -115,8 +113,6 @@ in { "X-Forwarded-Host X-Forwarded-Port X-Forwarded-Proto"; }; secrets = [ - "FRESHRSS_INSTALL,type=env" - "FRESHRSS_USER,type=env" "OIDC_CLIENT_ID,type=env" "OIDC_CLIENT_SECRET,type=env" "OIDC_CLIENT_CRYPTO_KEY,type=env" @@ -129,6 +125,10 @@ in { healthRetries = 3; networks = [ networks."${serviceContainer}".ref ]; publishPorts = [ "127.0.0.1:${port}:${port}" ]; + volumes = [ + "${stateDirectory}/data:/var/www/FreshRSS/data:U" + "${stateDirectory}/extensions:/var/www/FreshRSS/extensions:U" + ]; }; unitConfig.Requires = [ secrets.ref containers."${serviceContainer}-db".ref ]; From 9fcc736104c91155d321c5efd20578f0247e8404 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:40:41 -0600 Subject: [PATCH 057/149] config (zed): Switch to external Nix formatter --- programs/zed.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/programs/zed.nix b/programs/zed.nix index b3f7fd6..9477d87 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -52,12 +52,12 @@ }; }; }; + Nix = { + formatter.external.command = "${pkgs.nixfmt-classic}/bin/nixfmt"; + }; }; lsp = { - nil = { - initialization_options.formatting.command = [ "nixfmt" ]; - settings.nix.flake.autoArchive = true; - }; + nil = { settings.nix.flake.autoArchive = true; }; texlab = { settings = { build = { From d40b20d8cc0b2af586ee3e3f3f9436fea285c024 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:44:14 -0600 Subject: [PATCH 058/149] config (zed): Switch default model to Claude Sonnet 4.5 --- programs/zed.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/zed.nix b/programs/zed.nix index 9477d87..4b97b71 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -23,7 +23,7 @@ use_modifier_to_send = true; default_model = { provider = "zed.dev"; - model = "claude-3-7-sonnet"; + model = "claude-sonnet-4-5"; }; default_profile = "minimal"; }; From c7f76d5c1c921d95b8a62540f6ef253c6bd97ed8 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:46:29 -0600 Subject: [PATCH 059/149] config (zed): Add new git_hosting_providers key --- programs/zed.nix | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/programs/zed.nix b/programs/zed.nix index 4b97b71..30f2bcb 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -30,6 +30,18 @@ buffer_font_family = "FiraCode Nerd Font"; buffer_font_size = 11; features = { edit_prediction_provider = "zed"; }; + git_hosting_providers = [ + { + provider = "forgejo"; + base_url = "https://code.millironx.com"; + name = "Milliron X Code"; + } + { + provider = "forgejo"; + base_url = "https://codeberg.org"; + name = "Codeberg"; + } + ]; languages = { Julia = { formatter = { From 20465843e45d377581a65b25bda7505b54558830 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:50:14 -0600 Subject: [PATCH 060/149] config (git): Add ssh rewrites --- programs/git.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/programs/git.nix b/programs/git.nix index 173e5f1..244e916 100644 --- a/programs/git.nix +++ b/programs/git.nix @@ -42,6 +42,11 @@ }; merge = { conflictstyle = "zdiff3"; }; pull = { rebase = true; }; + "url \"ssh://git@github.com/\"".insteadOf = "https://github.com/"; + "url \"ssh://git@gitlab.com/\"".insteadOf = "https://gitlab.com/"; + "url \"ssh://git@codeberg.com/\"".insteadOf = "https://codeberg.com/"; + "url \"ssh://git@code.millironx.com/\"".insteadOf = + "https://code.millironx.com/"; }; }; } From 69205e695fc529a0e4fc90d067172aa9ae9732a2 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:50:44 -0600 Subject: [PATCH 061/149] shell: Add git clone shortcut function --- programs/shells.nix | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/programs/shells.nix b/programs/shells.nix index 6745cf4..6d226b9 100644 --- a/programs/shells.nix +++ b/programs/shells.nix @@ -10,13 +10,32 @@ let } ''; + sourceCodeDirectory = + if pkgs.stdenv.hostPlatform.isDarwin then "~/Developer" else "~/src"; + clone_bash_function = '' + unalias gc + function gc() { + REPO_ID="$(echo "''${1}" | \ + awk '{ + sub(/^git@/, ""); + sub(/^https:\/\//, ""); + sub (/:/, "/"); + sub(/\.git$/, ""); + print + }')" + git clone "https://''${REPO_ID}.git" ${sourceCodeDirectory}/''${REPO_ID} + cd ${sourceCodeDirectory}/''${REPO_ID} + } + + ''; in { programs = { bash = { enable = true; - initExtra = conda_init "bash" + nd_bash_function + '' - export PS1="[\[\e[32m\]\u\[\e[m\]@\[\e[33m\]\h\[\e[m\] \[\e[34m\]\W\[\e[m\]] \\$ " - ''; + initExtra = conda_init "bash" + nd_bash_function + clone_bash_function + + '' + export PS1="[\[\e[32m\]\u\[\e[m\]@\[\e[33m\]\h\[\e[m\] \[\e[34m\]\W\[\e[m\]] \\$ " + ''; }; zsh = { enable = true; @@ -37,7 +56,7 @@ in { "zsh-users/zsh-completions" ]; }; - initContent = conda_init "zsh" + nd_bash_function; + initContent = conda_init "zsh" + nd_bash_function + clone_bash_function; }; }; } From 8e283c2288e46a25b73ef31118b594de6bbdcc6b Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 21 Dec 2025 16:16:57 -0600 Subject: [PATCH 062/149] config (zed): Enable Typst previews --- programs/zed.nix | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/programs/zed.nix b/programs/zed.nix index 30f2bcb..dba9b38 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -87,6 +87,7 @@ }; }; tinymist = { + initialization_options = { preview.background.enabled = true; }; settings = { exportPdf = "onSave"; outputPath = "$root/$name"; @@ -109,12 +110,28 @@ ui_font_size = 16; wrap_guides = [ 80 92 120 ]; }; - userTasks = [{ - label = "latexmk (project)"; - command = "latexmk"; - args = [ "-synctex=1" "-pdf" "-recorder" ]; - cwd = "$ZED_DIRNAME"; - tags = [ "latex-build" ]; - }]; + userTasks = [ + { + label = "latexmk (project)"; + command = "latexmk"; + args = [ "-synctex=1" "-pdf" "-recorder" ]; + cwd = "$ZED_DIRNAME"; + tags = [ "latex-build" ]; + } + { + label = "Open Typst preview"; + command = "${ + if pkgs.stdenv.hostPlatform.isDarwin then "open" else "xdg-open" + } http://127.0.0.1:23635/"; + use_new_terminal = true; + allow_concurrent_runs = false; + reveal = "never"; + reveal_target = "dock"; + hide = "always"; + shell = "system"; + show_summary = true; + show_command = true; + } + ]; }; } From b6a67cfa987bf959ab7425305c05c875c8716fc6 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 21 Dec 2025 16:18:00 -0600 Subject: [PATCH 063/149] shell: Add repo_init function --- programs/shells.nix | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/programs/shells.nix b/programs/shells.nix index 6d226b9..edb0f18 100644 --- a/programs/shells.nix +++ b/programs/shells.nix @@ -28,14 +28,37 @@ let } ''; + repo_init_function = '' + function rinit() { + REPO_ID="$(echo "''${1}" | \ + awk '{ + sub(/^git@/, ""); + sub(/^https:\/\//, ""); + sub (/:/, "/"); + sub(/\.git$/, ""); + print + }')" + + mkdir -p ${sourceCodeDirectory}/''${REPO_ID} + cd ${sourceCodeDirectory}/''${REPO_ID} + + git init + + git remote add origin git@''${REPO_ID/\//:}.git + } + + ''; + + shell_functions = shell: + (conda_init shell) + nd_bash_function + clone_bash_function + + repo_init_function; in { programs = { bash = { enable = true; - initExtra = conda_init "bash" + nd_bash_function + clone_bash_function - + '' - export PS1="[\[\e[32m\]\u\[\e[m\]@\[\e[33m\]\h\[\e[m\] \[\e[34m\]\W\[\e[m\]] \\$ " - ''; + initExtra = shell_functions "bash" + '' + export PS1="[\[\e[32m\]\u\[\e[m\]@\[\e[33m\]\h\[\e[m\] \[\e[34m\]\W\[\e[m\]] \\$ " + ''; }; zsh = { enable = true; @@ -56,7 +79,7 @@ in { "zsh-users/zsh-completions" ]; }; - initContent = conda_init "zsh" + nd_bash_function + clone_bash_function; + initContent = shell_functions "zsh"; }; }; } From 01cf1735738d562f7375706a59f82381e4a0ea13 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 21 Dec 2025 16:19:35 -0600 Subject: [PATCH 064/149] brew (corianne): Install Vienna --- systems/darwin/corianne.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index f1c1eb2..b4755c9 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -234,6 +234,7 @@ in { "ungoogled-chromium" "veracrypt" "vlc" + "vienna" "vorta" "zed" "zotero" From 117cf076970c939852e43091b1e32da783003f87 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 21 Dec 2025 16:19:52 -0600 Subject: [PATCH 065/149] brew (corianne): Remove Musescore --- systems/darwin/corianne.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index b4755c9..d4787fe 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -216,7 +216,6 @@ in { "iterm2" "logseq" "macfuse" - "musescore" "nextcloud" "openrct2" "qownnotes" From 7e65bc03b38bd3a35b51509982247f0402c40043 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 21 Dec 2025 16:20:07 -0600 Subject: [PATCH 066/149] brew (corianne): Remove Anki --- systems/darwin/corianne.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index d4787fe..c83a9a1 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -207,7 +207,6 @@ in { ]; casks = [ "alt-tab" - "anki" "db-browser-for-sqlite" "dolphin" "firefox" From 8c313aae3766137a709f7e1f3dd6dc7dcf6d4cb2 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 21 Dec 2025 16:20:58 -0600 Subject: [PATCH 067/149] dnf (fedora): Remove musescore --- playbooks/packages.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/playbooks/packages.yaml b/playbooks/packages.yaml index 58e7263..34f40c8 100644 --- a/playbooks/packages.yaml +++ b/playbooks/packages.yaml @@ -23,7 +23,6 @@ - libwebp-devel - mkvtoolnix - mpv - - musescore - nextcloud-client - nextcloud-client-dolphin - obs-studio From 7d8843c399f9e4fa17005953fc40c6b7451e12c9 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 21 Dec 2025 16:21:10 -0600 Subject: [PATCH 068/149] flatpak (fedora): Remove Anki --- playbooks/packages.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/playbooks/packages.yaml b/playbooks/packages.yaml index 34f40c8..f13c01b 100644 --- a/playbooks/packages.yaml +++ b/playbooks/packages.yaml @@ -89,7 +89,6 @@ - io.openrct2.OpenRCT2 - org.signal.Signal - org.zulip.Zulip - - net.ankiweb.Anki state: latest method: user remote: flathub From 8336b25291c679848f1ce0a5216432c980917d22 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 26 Dec 2025 20:47:15 -0600 Subject: [PATCH 069/149] fix (zed): Make LaTeX preview open in background The order of the arguments matters to make Skip.app open in the background for LaTeX documents, so fix the order. --- programs/zed.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/zed.nix b/programs/zed.nix index dba9b38..dfbbef0 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -79,7 +79,7 @@ forwardSearch = if pkgs.stdenv.hostPlatform.isDarwin then { executable = "/Applications/Skim.app/Contents/SharedSupport/displayline"; - args = [ "-r" "%l" "%p" "%f" "-g" ]; + args = [ "-r" "-g" "%l" "%p" "%f" ]; } else { executable = "/usr/bin/okular"; args = [ "--unique" "file:%p#src:%l%f" ]; From 05ad4dc62f2b89a3e0a7998c9a32db5b88cc41bd Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sat, 20 Dec 2025 20:18:12 -0600 Subject: [PATCH 070/149] feat (linux-desktop): Convert Plasma settings into plasma-manager --- dotfiles/dolphinrc | 24 ------ dotfiles/konsolerc | 9 --- flake.nix | 2 +- homes/linux-desktop.nix | 8 -- programs/konsole.nix | 23 ++++++ programs/plasma.nix | 170 ++++++++++++++++++++++++++++++++++++++++ programs/yakuake.nix | 19 +++++ 7 files changed, 213 insertions(+), 42 deletions(-) delete mode 100644 dotfiles/dolphinrc delete mode 100644 dotfiles/konsolerc create mode 100644 programs/konsole.nix create mode 100644 programs/yakuake.nix diff --git a/dotfiles/dolphinrc b/dotfiles/dolphinrc deleted file mode 100644 index 2f11ee4..0000000 --- a/dotfiles/dolphinrc +++ /dev/null @@ -1,24 +0,0 @@ -MenuBar=Disabled - -[DetailsMode] -PreviewSize=16 - -[General] -BrowseThroughArchives=true -EditableUrl=true -GlobalViewProps=false -ShowFullPath=true -ShowStatusBar=FullWidth -ShowZoomSlider=true -Version=202 - - -[KFileDialog Settings] -Places Icons Auto-resize=false -Places Icons Static Size=22 - -[MainWindow] -MenuBar=Disabled - -[PreviewSettings] -Plugins=audiothumbnail,avif,blenderthumbnail,comicbookthumbnail,cursorthumbnail,djvuthumbnail,ebookthumbnail,exrthumbnail,directorythumbnail,fontthumbnail,imagethumbnail,jpegthumbnail,jxl,kraorathumbnail,windowsexethumbnail,windowsimagethumbnail,mobithumbnail,opendocumentthumbnail,gsthumbnail,rawthumbnail,svgthumbnail,gdk-pixbuf-thumbnailer,ffmpegthumbs,gsf-office diff --git a/dotfiles/konsolerc b/dotfiles/konsolerc deleted file mode 100644 index 7f417e8..0000000 --- a/dotfiles/konsolerc +++ /dev/null @@ -1,9 +0,0 @@ -[Desktop Entry] -DefaultProfile=My Default.profile - -[MainWindow] -StatusBar=Disabled -ToolBarsMovable=Disabled - -[UiSettings] -ColorScheme=Default diff --git a/flake.nix b/flake.nix index 59c9ce0..3b4f7b7 100644 --- a/flake.nix +++ b/flake.nix @@ -81,7 +81,7 @@ ] ++ (if desktop then [ ./homes/desktop.nix ] else [ ]) ++ (if (desktop && os == "linux") then [ ./homes/linux-desktop.nix - plasma-manager.homeManagerModules.plasma-manager + plasma-manager.homeModules.plasma-manager ] else [ ]) ++ extraModules; extraSpecialArgs = { diff --git a/homes/linux-desktop.nix b/homes/linux-desktop.nix index 6d78716..2516d48 100644 --- a/homes/linux-desktop.nix +++ b/homes/linux-desktop.nix @@ -113,20 +113,12 @@ in { configFile = { "plasma-workspace/env/ZED_WINDOW_DECORATIONS.sh".text = "export ZED_WINDOW_DECORATIONS=server"; - "dolphinrc".source = - mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/dolphinrc"; - "konsolerc".source = - mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/konsolerc"; "onedrive/config".text = '' force_session_upload = "true" delay_inotify_processing = "true" ''; - "yakuakerc".source = - mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/yakuakerc"; }; dataFile = { - "konsole/My Default.profile".source = - mkOutOfStoreSymlink "${home-manager-repo}/dotfiles/MyDefault.profile"; "kio/servicemenus/kate.desktop".source = ./../dotfiles/kate.desktop; "kio/servicemenus/vlc.desktop".source = ./../dotfiles/vlc.desktop; "kio/servicemenus/word-to-pdf.desktop".source = diff --git a/programs/konsole.nix b/programs/konsole.nix new file mode 100644 index 0000000..66043de --- /dev/null +++ b/programs/konsole.nix @@ -0,0 +1,23 @@ +{ ... }: { + programs.konsole = { + enable = true; + defaultProfile = "millironx"; + profiles.millironx = { + colorScheme = "Breeze"; + font = { + name = "MesloLGS NF"; + size = 10; + }; + extraConfig = { + "Cursor Options".CursorShape = 1; + General.RemoteTabTitleFormat = "[SSH] %H"; + "Interaction Options" = { + CopyTextAsHTML = false; + MouseWheelZoomEnabled = false; + UnderlineFilesEnabled = true; + }; + "Terminal Features".BlinkingCursorEnabled = true; + }; + }; + }; +} diff --git a/programs/plasma.nix b/programs/plasma.nix index ea0b6e7..2fdd769 100644 --- a/programs/plasma.nix +++ b/programs/plasma.nix @@ -1,7 +1,177 @@ { config, ... }: { + + imports = [ ./konsole.nix ./yakuake.nix ]; + programs.plasma = { enable = true; + overrideConfig = true; + shortcuts = { yakuake.toggle-window-state = "Ctrl+`"; }; + configFile = { + dolphinrc = { + DetailsMode.PreviewSize = 16; + General = { + BrowseThroughArchives = true; + EditableUrl = true; + GlobalViewProps = false; + ShowFullPath = true; + ShowStatusBar = "FullWidth"; + ShowZoomSlider = true; + }; + "KFileDialog Settings" = { + "Places Icons Auto-resize" = false; + "Places Icons Static Size" = 22; + }; + PreviewSettings.Plugins = + "audiothumbnail,avif,blenderthumbnail,comicbookthumbnail,cursorthumbnail,djvuthumbnail,ebookthumbnail,exrthumbnail,directorythumbnail,fontthumbnail,imagethumbnail,jpegthumbnail,jxl,kraorathumbnail,windowsexethumbnail,windowsimagethumbnail,mobithumbnail,opendocumentthumbnail,gsthumbnail,rawthumbnail,svgthumbnail,gdk-pixbuf-thumbnailer,ffmpegthumbs,gsf-office"; + }; + }; + input.mice = [{ + enable = true; + name = "Logitech M705"; + vendorId = "046d"; + productId = "406d"; + naturalScroll = true; + }]; + kwin = { + cornerBarrier = false; + titlebarButtons = { + left = [ "close" "minimize" "maximize" ]; + right = [ "help" ]; + }; + virtualDesktops = { + number = 2; + rows = 1; + }; + }; + panels = [ + ### Screen 0 panels ### + ##### Top: Fedora menu | App switcher | Menu bar | CPU monitor | Memory monitor | Network monitor | System tray | clock ##### + { + location = "top"; + floating = true; + height = 27; + lengthMode = "fill"; + opacity = "adaptive"; + hiding = "normalpanel"; + screen = 0; + widgets = [ + { kickoff = { icon = "fedora-logo-icon"; }; } + "org.kde.plasma.marginsseparator" + "org.kde.plasma.windowlist" + "org.kde.plasma.appmenu" + "org.kde.plasma.panelspacer" + { + name = "org.kde.plasma.systemmonitor.cpu"; + config = { + Appearance.chartFace = "org.kde.ksysguard.barchart"; + Sensors.highPrioritySensorIds = "[${ + builtins.concatStringsSep "," (builtins.genList + (i: ''"cpu/cpu${builtins.toString i}/usage"'') 12) + }]"; + }; + } + { + name = "org.kde.plasma.systemmonitor.memory"; + config.Appearance.chartFace = "org.kde.ksysguard.horizontalbars"; + } + { + name = "org.kde.plasma.systemmonitor.net"; + config = { + Appearance.chartFace = "org.kde.ksysguard.horizontalbars"; + Sensors.highPrioritySensorIds = + ''[ "network/all/download","network/all/upload" ]''; + # These are the values needed to make the network indicator + # actually useful, but it appears that plasma-manager doesn't + # support nesting this deep yet. Disable for now. + # "org.kde.ksysguard.horizontalbars".General = { + # rangeAuto = false; + # rangeFromMultiplier = 1048576; + # rangeFromUnit = 202; + # rangeToMultiplier = 1048576; + # rangeToUnit = 202; + # }; + }; + } + { systemTray = { }; } + { digitalClock = { }; } + ]; + } + ##### Bottom: Virtual desktop pager | Full-name taskbar w/ pins | Downloads folder | Trash folder + { + location = "bottom"; + floating = true; + height = 44; + lengthMode = "fill"; + opacity = "adaptive"; + hiding = "normalpanel"; + screen = 0; + widgets = [ + "org.kde.plasma.pager" + { + iconTasks = { + iconsOnly = false; + behavior.showTasks.onlyInCurrentScreen = true; + launchers = [ + "applications:systemsettings.desktop" + "applications:org.kde.discover.desktop" + "preferred://filemanager" + "preferred://browser" + "applications:net.thunderbird.Thunderbird.desktop" + "applications:io.github.alainm23.planify.desktop" + "applications:dev.zed.Zed.desktop" + "applications:com.logseq.Logseq.desktop" + "applications:net.lutris.Lutris.desktop" + ]; + }; + } + "org.kde.plasma.panelspacer" + "org.kde.plasma.marginsseparator" + { + name = "org.kde.plasma.folder"; + config = { + General.url = "file://${config.home.homeDirectory}/Downloads"; + }; + } + "org.kde.plasma.trash" + ]; + } + + ### Screen 1 panels ### + ##### Top: App switcher | Menu bar ##### + { + location = "top"; + floating = true; + height = 27; + lengthMode = "fill"; + opacity = "adaptive"; + hiding = "normalpanel"; + screen = 1; + widgets = [ "org.kde.plasma.windowlist" "org.kde.plasma.appmenu" ]; + } + ##### Bottom: Virtual desktop pager | Full-name taskbar w/o pins ##### + { + location = "bottom"; + floating = true; + height = 44; + lengthMode = "fill"; + opacity = "adaptive"; + hiding = "normalpanel"; + screen = 1; + widgets = [ + "org.kde.plasma.pager" + { + iconTasks = { + iconsOnly = false; + behavior.showTasks.onlyInCurrentScreen = true; + launchers = [ ]; + }; + } + ]; + } + ]; + powerdevil.AC.autoSuspend.action = "nothing"; workspace = { + lookAndFeel = "org.kde.breezedark.desktop"; wallpaperFillMode = "preserveAspectCrop"; wallpaperSlideShow = { interval = 86400; diff --git a/programs/yakuake.nix b/programs/yakuake.nix new file mode 100644 index 0000000..f8b86a7 --- /dev/null +++ b/programs/yakuake.nix @@ -0,0 +1,19 @@ +# Note: this file uses the lower-level `programs.plasma.configFile` syntax +# since plasma-manager does not yet support a high-level module for Yakuake +{ ... }: { + programs.plasma.configFile.yakuakerc = { + "Desktop Entry".DefaultProfile = "millironx.profile"; + Shortcuts = { + next-session = "Shift+Right; Ctrl+Shift+Tab"; + previous-terminal = "none"; + }; + Window = { + DynamicTabTitles = true; + Height = 60; + Screen = 1; + ShowSystrayIcon = false; + Width = 60; + }; + Dialogs.FirstRun = false; + }; +} From 9628c7b433e295eb8b7e94c8335a7888dc86b7b5 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sat, 20 Dec 2025 21:33:58 -0600 Subject: [PATCH 071/149] pkgs (common): Add Runic.jl cli --- homes/common.nix | 25 ++----------------------- pkgs/default.nix | 1 + pkgs/runic.nix | 12 ++++++++++++ 3 files changed, 15 insertions(+), 23 deletions(-) create mode 100644 pkgs/runic.nix diff --git a/homes/common.nix b/homes/common.nix index 078bdd5..50a33e0 100644 --- a/homes/common.nix +++ b/homes/common.nix @@ -1,13 +1,4 @@ -{ config, lib, pkgs, pkgs-unstable, ... }: -let - runic_version = "1.5.0"; - runic = pkgs.fetchFromGitHub { - owner = "fredrikekre"; - repo = "Runic.jl"; - rev = "v${runic_version}"; - hash = "sha256-y+kiBA94vUMHH0fEEBg7+c9PEgzjGqh6nCuSRnawhQI="; - }; -in { +{ config, lib, pkgs, pkgs-unstable, custom-pkgs, ... }: { imports = [ ./../programs/shells.nix ./../programs/bat.nix @@ -20,16 +11,6 @@ in { ]; home = { stateVersion = "23.11"; - file = { - ".local/bin/runic" = { - source = runic + "/bin/runic"; - executable = true; - }; - ".local/bin/git-runic" = { - source = runic + "/bin/git-runic"; - executable = true; - }; - }; packages = with pkgs; [ agenix btop @@ -53,6 +34,7 @@ in { pipx python3 zulu17 + custom-pkgs.runic ]; sessionVariables = { PAGER = "most"; @@ -88,9 +70,6 @@ in { }; sessionPath = [ "$HOME/.local/bin" ]; activation = { - installRunic = lib.hm.dag.entryAfter [ "writeBoundary" ] '' - run ${pkgs.julia-bin}/bin/julia --project=@runic --startup-file=no -e 'using Pkg; Pkg.add(name="Runic", version="${runic_version}")' - ''; installJuliaFormatter = lib.hm.dag.entryAfter [ "writeBoundary" ] '' run ${pkgs.julia-bin}/bin/julia --project=@JuliaFormatter --startup-file=no -e 'using Pkg; Pkg.add(name="JuliaFormatter", version="2.1.6")' ''; diff --git a/pkgs/default.nix b/pkgs/default.nix index 2e0c11e..80d0fad 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -2,5 +2,6 @@ { ark = pkgs.callPackage ./ark.nix { }; + runic = pkgs.callPackage ./runic.nix {}; sc4pac = pkgs.callPackage ./sc4pac.nix { }; } diff --git a/pkgs/runic.nix b/pkgs/runic.nix new file mode 100644 index 0000000..b91b550 --- /dev/null +++ b/pkgs/runic.nix @@ -0,0 +1,12 @@ +{ pkgs, ... }: +with pkgs; +let + juliaWithRunic = + julia-bin.withPackages.override { setDefaultDepot = false; } [ "Runic" ]; + depotWithRunic = runCommand "getRunicDepot" { } '' + ${juliaWithRunic}/bin/julia -e 'println(first(DEPOT_PATH))' | tee $out + ''; +in writeShellScriptBin "runic" '' + export JULIA_DEPOT_PATH=$(< ${depotWithRunic}) + exec ${juliaWithRunic}/bin/julia --startup-file=no -e 'using Runic; exit(Runic.main(ARGS))' -- "$@" +'' From 55ea13d49b7943be338bb36739b6f7cd810fea7f Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sat, 20 Dec 2025 22:56:02 -0600 Subject: [PATCH 072/149] pkgs (common): Add JuliaFormatter.jl cli --- homes/common.nix | 1 + pkgs/default.nix | 10 +++++----- pkgs/jlfmt.nix | 12 ++++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 pkgs/jlfmt.nix diff --git a/homes/common.nix b/homes/common.nix index 50a33e0..a7566a9 100644 --- a/homes/common.nix +++ b/homes/common.nix @@ -34,6 +34,7 @@ pipx python3 zulu17 + custom-pkgs.jlfmt custom-pkgs.runic ]; sessionVariables = { diff --git a/pkgs/default.nix b/pkgs/default.nix index 80d0fad..8178242 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -1,7 +1,7 @@ { pkgs, ... }: - -{ - ark = pkgs.callPackage ./ark.nix { }; - runic = pkgs.callPackage ./runic.nix {}; - sc4pac = pkgs.callPackage ./sc4pac.nix { }; +with pkgs; { + ark = callPackage ./ark.nix { }; + jlfmt = callPackage ./jlfmt.nix { }; + runic = callPackage ./runic.nix { }; + sc4pac = callPackage ./sc4pac.nix { }; } diff --git a/pkgs/jlfmt.nix b/pkgs/jlfmt.nix new file mode 100644 index 0000000..21916a4 --- /dev/null +++ b/pkgs/jlfmt.nix @@ -0,0 +1,12 @@ +{ pkgs, ... }: +with pkgs; +let + juliaWithPkgs = julia-bin.withPackages.override { setDefaultDepot = false; } + [ "JuliaFormatter" ]; + depotWithPkgs = runCommand "getDepot" { } '' + ${juliaWithPkgs}/bin/julia -e 'println(first(DEPOT_PATH))' | tee $out + ''; +in writeShellScriptBin "jlfmt" '' + export JULIA_DEPOT_PATH=$(< ${depotWithPkgs}) + exec ${juliaWithPkgs}/bin/julia --startup-file=no -e 'using JuliaFormatter; print(format_text(String(read(stdin))));' -- "$@" +'' From e823b4804cba31a0b4ac9c6adb67f8688933121b Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 2 Jan 2026 11:56:07 -0600 Subject: [PATCH 073/149] shell: Remove JuliaFormatter project --- homes/common.nix | 5 ----- 1 file changed, 5 deletions(-) diff --git a/homes/common.nix b/homes/common.nix index a7566a9..78d70a0 100644 --- a/homes/common.nix +++ b/homes/common.nix @@ -70,11 +70,6 @@ micromamba = "mamba"; }; sessionPath = [ "$HOME/.local/bin" ]; - activation = { - installJuliaFormatter = lib.hm.dag.entryAfter [ "writeBoundary" ] '' - run ${pkgs.julia-bin}/bin/julia --project=@JuliaFormatter --startup-file=no -e 'using Pkg; Pkg.add(name="JuliaFormatter", version="2.1.6")' - ''; - }; }; programs = { home-manager.enable = true; From bdedf7a69e0f511c5ba912e152a8947b4e983c69 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 2 Jan 2026 11:56:23 -0600 Subject: [PATCH 074/149] config (zed): Switch Julia syntax formatting to cli --- programs/zed.nix | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/programs/zed.nix b/programs/zed.nix index dfbbef0..6985d69 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -43,19 +43,7 @@ } ]; languages = { - Julia = { - formatter = { - external = { - command = "julia"; - arguments = [ - "--project=@JuliaFormatter" - "--startup-file=no" - "-e" - "using JuliaFormatter; print(format_text(String(read(stdin))));" - ]; - }; - }; - }; + Julia = { formatter = { external = { command = "jlfmt"; }; }; }; LaTeX = { formatter = { external = { From 74e2bde66f9727d4e4374af2d32f98d27b93ca1c Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 2 Jan 2026 14:49:20 -0600 Subject: [PATCH 075/149] secrets: Rekey for new odyssey ssh key --- secrets.nix | 2 +- secrets/ansible-vault-password.age | Bin 685 -> 685 bytes secrets/authentik.toml.age | Bin 1222 -> 1222 bytes secrets/borgmatic-passphrase.age | Bin 891 -> 891 bytes secrets/borgmatic-ssh-config.age | 29 ++++++++++++++-------------- secrets/darwin-policies-json.age | Bin 1214 -> 1214 bytes secrets/freshrss.toml.age | Bin 1185 -> 1185 bytes secrets/network-information.age | 30 ++++++++++++++--------------- 8 files changed, 30 insertions(+), 31 deletions(-) diff --git a/secrets.nix b/secrets.nix index 45783ee..ed1352e 100644 --- a/secrets.nix +++ b/secrets.nix @@ -15,7 +15,7 @@ let mcentire-millironx = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOdC6eNx2nBi3PWK/n4GJMbVf+NlQJv13aUqxse/h1kL millironx@mcentire"; odyssey-millironx = - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9Aj7BtQp1Roa0tgopDrUo7g2am5WJ43lO1d1fDUz45 millironx@odyssey"; + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKM5Q2zl3b91j+foqcVeQT+wb5DFEp+MbgotTTaKqZZi millironx@odyssey"; system-administrators = [ anderson-millironx bosephus-millironx diff --git a/secrets/ansible-vault-password.age b/secrets/ansible-vault-password.age index c5b657899971cdff5c4f51077d04eee9528417c7..6c1379f07a11ae876f03ba95fae500711d156c79 100644 GIT binary patch literal 685 zcmZ9_JCBoa008h!BVWLk!NG)7pp=6yCf5Sx(H^fBN}~hthw_G_yq!&4FFLw7I664# z=Hls~$;}#L;&{3723MW?`vO0E?~T07E&HMh^XySx?$HK^MvvjcAsBgJOp^E%4ih37 zR9Mf?*P0ywwA&aSS}>_95Yd|4V#&Ib+n}cdw;E%98zvKIQ(J{3V^@h^isu08*b|GVm8TP{a~NY)+ZTTMJ^e z%6BYvCk89QkMN$~7i*wzaB{$wfJDb_f}O6FGt4|`k2g+J8{rhTCxcZL7H2Hb}pXtx(s?mZIn#KgTP*Do@29Ah{fKn z%V`K%lg4P48FN}|Lnz88Gd-JP*-o2pVzNmKK~q-cOHIK-dytLx2NU3yWhY3xF|pV E0|CkGTL1t6 literal 685 zcmZY5JFk;q0LF0#Czi81Xe3T5sRc?~a4>1}(leD5`F<&a$dAa=IFw1@WdJEx1l~QD6}gmSh?2ZMj@e2wt19P}5{h%#^}o z*Bb~H5@kMH!&%Sa!yy;b(h!qHjTMG|_xRl9Zm{DlqM#ak13tsGA!S zg0GfjwRgwau*RA;iZiQG`0(P_Bz zcf52Fqlu(eqJ01 zGdL}Eq}S`AY_vayfxLCK!Ydj8j48&=EvXWOd7sL-PDF*62Pz=FS(=@9WRL HhJU+%Y*pp< diff --git a/secrets/authentik.toml.age b/secrets/authentik.toml.age index 1ef8f6e277acf7a7b989bfa87f553f5f1d1d0ac8..d3c91cca5c23bc224a0f53a2dfff20c254edd975 100644 GIT binary patch literal 1222 zcmZ9_`)?Bk003ZufLj-aFtZ4Qt|A0NDZOiZj{;fj7650`Gtz&}|X(&U`Iuk$ee|hY3;=Q&vO5yQ_(yKV9+^!#T*o zVVH#5S;7#2w8CPhOgtWts|Lx(SNV0q0b)1+CqV-XCJG|k<@e|cEf*zJ!L;JU4b0f9 zx^Bs$Vn)N>45SV3bw43ke+)7Zp~?+OXHZb5mslqzx+Z@wMH(+N=Qic%pi7AgAG z5aCNpXw>5+bfYRnJtlW9oC0vL%$95ZDCXiRD&RtBAsZmwbT(cIVPTpj(=KO+KRR)9 zDjlVA#v%a#UhNk2@allmAF+C}-E^WIj)C5C5@lF06qhvyauWG4<}uN=!0J_U0ryC} zjH!IYkdPQziPS`w41#nd$T-Q2*j~mu z>2TMA)(Qz#GmMEK*c8|mq~nZixWh8huG(cv(%>2pP~otWkMSAO4r4|N zb4}c=K7fs7ENCKMDR6L=u|*led*w#)SI<0A z+Z@itmNaR{7QS-vwfT>mW^X(7^8KS%v3bKa-|;i4 z;jvh~_}fe;DE1uupoBWKK?do+1OIA*A{P4}A(=Wa8#hnM2 z4>#9MZ@NEFzrz9i!ml-(&OP4}q&joJD^o7r zTs~RyuTj=1%gM1j4W}m65#|%hq@!)NLo)Vic3xAm4hwz2nT4OP-dx_d=80FG_1(6X z`M2kewf?<-ytS_LwzZm{ab?$LEc9u*d2#C~&H4VhUYGCrruf2OGym4kv->uWTs(J; z$^JQZa>bS(<_xuczu>^ylkd{UrXh`E{hpiqxb-&{9$CNZ>#Jw3n9CRUPKh*>=a`S| HJ$dkdKC95P literal 1222 zcmZY4>u(bU003~zNPtQJGXe}9)UhD$GJ0+AXm33Gyz66qTzh>DNUpu>_1f!o?e*?@ zhs%KBruZPTY>o(sKsF;j!ec-NI6t5P1p=6W43LPB03w6ML;_|Qzs|qlmmkT{jWnMs zDXnF;z%MP77@efoG_KMLLZ*?X3^1%mv@B=j)S%X+Qyo~v>MND-v>Hu#Q;5L?O5w7> z73Z2=B3@*&32z`mazs!=mLzXBg^CK1T}Gt6Qa<7aqXB`;M4eE~nr|g5E{POv8AqXc zqNZnb6IRS6bL!?<_j?{&PLLmh3V$^LSEl{#Z|95L_)KcC8=6A}x!71b6m_KZhz`T=l z`Qf0sxsXqZVW&C7ILa)Xb!a;7-?tA{bz_~-o`vtdFb~hEIkJEITMc`r9~@+xc0L+= zspZeZdBeyi&6$JacV0e(u0Co~77wm&Upr;20a;zc&YC=@2637veS$6+?5Yba;x9Zs zwe8n|@Y3q4f}FWd^%It?XYTFKuJ`L3>VeJ=HtxE5ZPn&(_(jck;PLt}d2Y0K^SuxE z%(~IHb?>4lwGSV>{xs43)2j1b>XOj|-We^`$IgB<^6bWgTlzkcJU!(?!u8G%l|QI? zEv}~9na9%1sprZYzQ1zMzVnN5vcB`EZsE`ncXeIgordSzB0G1lNRiIRTX#P^eAx7U zsrOx>|D=UFxsSWKa`+H@v8C>ERMiTaSC0SU9-qAUY3Yy|J$w2MY1{g{Z|>@rR=jp9 zf4cY9`oYi7cMeRFo}C>2XZx33;fwye$CmUVJ=-^=91bXXbabG4?nAk1?QhDJX&p!O zYij*Vt<$?+eRk>je0oP{9`n_SGvM3KsR!qsBS(g>W#sgwj>#K79$aqtbj|E7?FZi3 zdpYJ?vGMWp9^?Ftwfl}WAk{NRcGUfR;?Xzq!j{^WzXu+)&7L7{s&Bf#u3c%X3r_R& zT->rAnxoJ4OdT2@oqID$2ET1<;<0{pezZ4S9vcaUYq=`Jg0_|I9bY@IpZR@klKsh# J`)~X;@-Hw|+A;tD diff --git a/secrets/borgmatic-passphrase.age b/secrets/borgmatic-passphrase.age index ba13eb39250c07f4450f6815c5c08ecb87d3ddba..c3969d2a005182a25adf2b4d779cb3b58e148be1 100644 GIT binary patch literal 891 zcmZ9}&CA;a0LO6!K?n+7=I|f{4?CFEG)dd!89GSXrb*f~?@1e#(KIj3dy}?#6EEBF z>_9v?5k%Q!h!5!DL6pgy;6xb;G9Twba2|#Sck&>3aOeI5zt0c83(sje$uh6kTR%-+ zNOKP^5TJDy+-z1Y$40wd8C>!W zcpVEfZwNHjL|e>-A)MNrzav#vZWjqvh#VOZo>=M;K18$C!`;<x#XFeeUDl5lJ8AE(Orb)9v z4YL?1oP-IcZiM@qZH*nK1QEU1>RMiTs#2@n%&zMLZdn(s>Dtkn%F##}jPM2LEe#3a zl#!D=Zqld7RIz%Kp*oq;P%If0X6R}+E(Z9(ZVGzcZ1y!Q6Sq4L99gMC@m4z@$9>Lp zh-5)DZ4*@$fpJ4IoEe@RMQSH&!W7sZ$X%<=1TH_F)n&uPi)KI>S>g5unqSk7ScX;3 zrbhbk*@>8QpJwKL5*Ut$yS9lS@bNm-XpuJMp-6?ut4(xN#x5`+jlsrt>Xw=l0dN>^sm8 zpZ|XS?(FHam*Howl{a3d?l&K`E&)g1)z97g;+r$QudY9F5&q-w!RsHq`qE>!Ui&l6djN?Q{1Y`R`Zpvqv@V<3F!nIDG0DxuS;u Gw*Lpx-aY96 literal 891 zcmZY6&&%6%0LO6$gF!*WgD5H(+3BIw{A$vKxo5OZ)1>LIG)cd0Rj_HAZ+$HIcx@FyG{sAmT_ldJ%F-Yx3TF}9BfUaKHofW0!zMFo+Z}cjVLj;TM%^5wKtwri zsmzm3+mzLoJr1U&iO2YDC2atQf*sJsT#e=YEkBo4uA?{W%rp-Iw6+>#aduS0A-c^n zgjZb1FJiadFVbE(as4eZWyTgYb?T@RxelHam}_f31F+I)G#QuOM!UHYb-9{=FiNeF z#h0gcSIlu^h6@nTb?e0mK3F+cT%cvkbUKF;RrHrz7R5QH-;&b>Tu=D5%+ zMYR}ISFj2#s1I#`3#`-HNM(*EsAY3$thup0UV}D$_|X5fCI&_jS;LK#ND774jEHL# z10xqyk)#)O%M@wHiA|mqU~4Rsd{*j=Ib~{wMgvS0QpfqtVPXv@V>Zxc%ocaDjEuvG zP{r!uwn_yFHlvnC8QMg2>;_|{*Pljznp)!edpL$ z)ZU9f@BVu2!I^(Pesq2RyKfJ6pS((Z_VktKzI?f}bG+nY(dWi*f6?NFA6^%@(_dhp KoUL9s@zj6RnmmXA diff --git a/secrets/borgmatic-ssh-config.age b/secrets/borgmatic-ssh-config.age index ba01275..63dd59f 100644 --- a/secrets/borgmatic-ssh-config.age +++ b/secrets/borgmatic-ssh-config.age @@ -1,15 +1,16 @@ age-encryption.org/v1 --> ssh-ed25519 il3lzQ 9QYGvIhYSyGcFmNdjK6qo2PnX+/t4LnU7eO3+TilFk8 -/6TLFd43tAdI5JKOPVk5YgBLzqdoc++CHtpYqBVMus8 --> ssh-ed25519 1g/xww RV80BUKnJCyP2CsExGXqnEmXk1XAPkSyVEN+hByUcDo -IpbyT1t33/DCt8iP3Jy64FC88SqQTeTLB1bur3g5qzk --> ssh-ed25519 dbKeHw CjnqCn7n/6pLpSaF7Q1u2vFBoLOswOaYSoQYwEu0yik -CSykNB4CmGuLWURDJWSAhtAhLcJ4iaeaYNKVsG9w/S4 --> ssh-ed25519 3qPtug yNNOpEPutJhoRfkXQVnyUJ28Rtyh0oSClXLBVT77mWQ -Yr5TcwBZZbskLUmudPYnyIFvtcxbe+xKnde/5fAW4Dg --> ssh-ed25519 +kBihw wf+3MXdvYBGBXUci/SiBfL+VPbVkuM1kl9jOHOxr9x8 -3Cgmhh7uI/Hrv3474FrkqspOx0kooNZcG5untJguvYI --> ssh-ed25519 +C0WRg XJILB7Fa+o5NQPy+sQTt5z5S/WcxzEKTqR4dadFnphU -sdrs/Yf2lf14Dy22hFpzaTgCwvaDaWaXWMlERS58izk ---- 8zj6q3V/OQPbTiHOfin0sXT9gbVNYMCRSWoXMKxYFDo -PVzRbc1Q1T:rU kbXTk䑡ɧ釣ךUG XRl~ҷ8B:.:z?ɐıxED OמQ} `uPI3p|W!3U{mG2F7T)2 \ No newline at end of file +-> ssh-ed25519 il3lzQ 6815+wa1JjdVUu8U8vaRah8kVsjR3Fsot99HKWl4SSA +hPYVZuN1yTKQYFIQvIRdmr400aijXleA22Bxh1nXKdc +-> ssh-ed25519 1g/xww BPxSszlrjPTVJC+YOvo1N6ICUUdL7WKZX3DeambLjBY +JkJQFPGtxDtqeGj8Z1YtVq/pm6hgYKwzMW9MbtkvOwY +-> ssh-ed25519 dbKeHw PU5cZrKCkAvUjI/opkboDQKSWJ8osAOQiI62f9lbfRY +ef1z6ZcBASkhC4fdcN+RRE7q28rB/DN8CVdoNVkC81I +-> ssh-ed25519 3qPtug RWCMZiLQlS+bOOIBRGmoECOfqEI2uoaWCq/4ZuI86B4 +VOaLaH1VYnGoQzjb8seU6wVviB94W3qCdYW9Wf4PGIc +-> ssh-ed25519 FRQvIA LCDwNMNVtTcI3GHPR2mcgtR16yAYYwLplI2nKUwNxDQ +vwXBIDlK7FBOsKt48Zv8mp0WFA/TKH2UJxtUxZoxzMI +-> ssh-ed25519 +C0WRg a/R13LfNMjVjJxt2TtTHaqZOhsYJLY+HUGMHEDnkZWo +T2EfeE/a4W4bFvauynfh+4aJL1jhCpO8iBG2aTmKtyM +--- o7tyupfhbxh3dwSrBLsYX0V61va0USlqxheNsdBjVuQ +A q,:_aɪ)j12 #t,G* +XT(U5t6B皩80 *i׆^ߨ@aB@̃+oFwPci27YSXd g̲J \ No newline at end of file diff --git a/secrets/darwin-policies-json.age b/secrets/darwin-policies-json.age index 77d73854bd711eab398e705e736311d2fd8e19b0..3f900dd98f12f2c4188a731b966770860ab1de37 100644 GIT binary patch literal 1214 zcmZY2>vPit003}M*|>7Y*a12Ou^hw4mC{GrB|(Kt`hKRbHR%AQP0}Q7(l%|9rbWDC zdMb(&PbzODM(yC zwRvhP6dA>GTxixPx*KR>dzyEKvXn^NgA@KF&y3$pj6p4z zwGyHh#=s&bKPQjIicy<7x0SW%H+n~h`{(I|luX$EjS#HY(pz>-4C zXjd0K@hu39weg43^WJudD*FWBdk) zAxUPma3l~{Q@lhAW*0@~?3jwD1V_Lt1#AlC&qb-ABcDmoHl9dm3~W|MD|sUZ6H<$W zyAv&D)SQTs1;kfWti^N=6jBC^z;n6m_{|v!D;`8!Qoy_}T?FikF#~`ymX&1)KxG-k zMRV0=m*prCCK7p;XF28<6k!KH#`; zQaU(s$iMS$*X*DF2@jv1c;~*Ot!r-#4sKn)5}Nv)vV6uLPiq?nq1ui<@6~e$9y6SI z+4Rw;?*MbhUaxZ>>*qeMnX_#1rQL<@OMCF?SLTs3cHiE=Y^-BN?dI7v;TO>_Gq+5C zPMD4zfgEQKtZRgh`-Wee)_ISa3B3A-*xFl}d2t?c=Vl$Wrsw3o%X6q56Amo@aAfDG zcm8B%Nqzgu*=^I?J+;@5)J#jSAVEbQe@Sp(~sQUl1kU~ ze}IJQ8asCNO@0V%-4GqVXI{T8J-}TVIo#8E+!;LRG&UTad+UAez|BGU5Ze1Wv$}EM zOkeWMrgQLv-+f(i)IUFKQrCNXU)XL zSq+Ql)t6pc9RB;f1K-MbZ87brOx{!9JAC-ms_s`tEgQQHsY5dyOSfmHxO;r`!nay) zhfegu7m2||k3Y5d$#3>mrv4D>+-{$=;PD{%x-e97=Yp>VdwQH}}$8CVF*T>!Zy7qc~ zF)3u@p+XoDidVI*MOku@}Xpoo=MLD{S;Q7Sa?d60>DOp?Ub zb8d!|<6cQeH8kTELPv>CqY0p`D(xb*EDPF57&aQAS~V2Y6$=G*JQOAhfb1wHc(wp? zc^`pU5w|bNL1i`)M!+D$CS6Dx7o9d#MKXbmAmZUXCy^LWE4ahQBN9&r6v`(M{%o@g z5tv+1K^qJk?@S5k84=8ox}>8ligwl*G6^{7#F9d&$rP6ZhEj&I=qWBq7a6;%wrq6P zyCjT9Q;{g-$vX&#J9SxrErPbNQWe1z-(XLB@ih3a{m|F^D2aquyPlMSCt|qXiozn(`5U z0P_1nX)7bUX)I*nRa&i9Es&l71&c()MTXN1Vl^64icA#ZGKJRDL78zhVQ7?sgQ-$l zHTS9UGq*IJ?ntw8`|W|RViVIV7H+z&8TU)&%Jt4~KHTxdq)Yg#cls_L=~*&7|ID5h z^Jh~|#4(_44kKZrJBdq;IG?&$A&aBJtK-`qP^e+F{fbaz`X zRvqiza`w4r`VX{HjvGf@k?V5@_kFRQs(X6IamTXCHqDQ_5j3lQTMKlVpWU#0T9;ND zkvezyK_$81^zaMso$9F`tWqDMC$(T7Uzl98eEghE-ACsn_FrUsf^$b5`aQNADSy9e zU}>@LY_I#tfe(P{pAQ92R~8K?GegI#=bc~DX4S7Tuj@QmGY8kaw8Q)S$*G}ke4M-; z9@{TnbHTg3+C^8VPjv!=XF2ztp`|sCoyt7Abo1Jc%2sA`BY8}7cuJf4)0ZpvM_ayy zX0@GqF>t>3;e?vq>-WN6bHGXwtb2H7Yv+3q^er9tM;;jW)1&uW6wgWO4*A+WVt(Jde6*#plUHRg z-WrK~nO~oBg?D1>+O-?q8{eG0;_f~vz1Xs82DmTAUE6QatX=_6(qx1f_G1_=$k9XkLmVW_Z)y3KX diff --git a/secrets/freshrss.toml.age b/secrets/freshrss.toml.age index e253b881a3ab7741cedfcd65baaf390014ecedea..096f601ffcbf9a110d7d380b888a0096598e795e 100644 GIT binary patch literal 1185 zcmZ9_>u(bU003|asN0D%K|yq2D#8@I?H;}Bwc%x7*K2!yUAy*LWZ1j*`ndMm-d*q7 zBeG!#3=kX)km(0QoERPvOw=IiWCUV@I2dS@!3R+s2@r%3o{8Z1{r-VpDx2xZh@8}@ zDEYG3S(dV(3IiQW4YHi;$fOYrgRO>q(NxsKhDgZjS5YocmW#Q7SJTO`Es2Ij6tBj8 zMMZ;g2}KhGO8FudfI?Dk&KOB6pq;^zNDvenX3cMj;bwugIY^_Cwz+H$EGSBr$s3#n z>zZcBHS`z}ClcqK5TblJ{NX@`|!7j>?O~`7r9Ik*SGExYZYN@Ko zk}fTaIf5X}BQon z-i!_?PG=2@NL32HOswF|d+qfE>`S?5)|!)?M#)=Ac-@5Gj+>)JCT#NqafhB}E3UGa zt;GXTMNWWh%@GYj8P#N!os^67J0iGO)~rrH(9zLhC=zrin!O*7 zkPIZeQiE$wY_l%xq1(x>U;iDqUv)RV4!&`xb?wo*wDq+E|NU}k zZ*_Q0N_e#R%x(L?p|J-~p8EdL+vkMS%cVKXof@Z+hLfqt>? z&&V}1aoYj_)ZMird-C2)beZS=!kZJN?>bjBP5fNG7S7C>-8Oyp(1B60@9ygTEx+B^ zHMsTo1%1os7uS6;PMO=CqZeCUEjPydpS^BvU)owv-1=t4p2FDB_9It5cu(bU003}| z6jv520$7K2hL`o#YR15Gh{*)o^x3>IuhDwi>_I_~HyU>drT|R}!8C5fsDN1RWY9>& z6}9{A8e|sPfGX&GBB4pN6E{+5x*~dvsan(lK|vla6e*BYf=(~)_GEG%9tuy_U;$KQ zSs#x|-YOcmleJKlh8VLPgpIt-nx;tH&j6fcV-O^quQ34!t>Xo)lEm?pT}c!yEFtC~ zzY_)#EbP-#6p=+jw22Wlz$AIvrfXcv$Gc^HI^@a36@SHfaWBi9L!=lgvywUSVf4DK(YubooO^`!D|`5lH)z{bj?_% zq?(|Qfo0rOK|=*QO-7k|-2(Bn3IZ_#w^kD+OHeI>*#cI!rClDKz{YJcObLsS>LG`nZ0Vj zB3r6dED~^+IZi4vsLml43V@r_2uqfC=vxTveRz> z21SE{UIgg~n}j(U7OLi)S@k&t9_1M}i?I%yxq!P;sWJzL0ue~ou?3ICt}+2W4WuyC z;;YLjz{tFrtI|lWyjoFlx z0HQLjEMN`Xzp_6ZyKIar4KDOzq`EY1PZmh!5p8t# zrtXCk+eb^?mlold)#2~fd~dwfJ3eK-)3}}_A$npA;R^ zanw3-e9Osj10Dct2Sph(M82J#(K}qyM1hL*M*ql z+*0?cx$2s(uE}}b9pTf-#?CvJRt`b8{^-TKp|vA_&zOXFExGda@{y0m`^Y1``wu ssh-ed25519 il3lzQ YxgllrvBeqfXMCWKq2JF9aqyoq5CUTHXW5Y/DhxEDzE -55NxukxXnmQ27WqW/yjkvTLd/3QmcO8uxCxsGu95rHM --> ssh-ed25519 1g/xww yIGdDpxlTv5I1LyueRLGY4LxpKHIYDVEN/fkcMlNvD4 -0vvuzTeqH59Kw+JFzmITJI8bgEevwJdPtqknuTx0QAU --> ssh-ed25519 dbKeHw ZZEDohW79lqKjT4TTQSGvjav+n6mESo1RALb+Xbbcw8 -gwj6rEy0G95IYBAgB1F8W5wXhRP1n+1SUTIp6/XWCHU --> ssh-ed25519 3qPtug 9kX4TyecOvRgb+KCk3FAC3QbhhxU55VRiQGNOytGFSM -LpBauBXhI4vfBHEfw/d1l4ao7qkEe/Daaow4CyDtpJM --> ssh-ed25519 +kBihw Qiyi1AaxGLyXdsNFu+TcNQ/xxOLEkYUbTIWYClVw+Qg -ocPR0AsEh3OPRWa1kWTlXcoit/yv/iywHfcgJZh/iFA --> ssh-ed25519 jb0ALQ 7OFB68omi4iWdrKdywc+f6f69mGThijWPTktuAbA2ws -XzZnyv3qsGFM/25KapNdM4n/poisk2sTzgy1ECqWODk ---- RCAULQI2W/aA4Smb0LaA0xrT1GiH+bOGrMRLVY8O41E -Y~2mEA)L+ b oX5Cѕ^Hvq]N $n)X¬xlVgT)%M6aT2YM5Y ~ -HpS n&x(̞i? -K C̔KpMbCq*v ಽMl$ \ No newline at end of file +-> ssh-ed25519 il3lzQ nMWnoZD14ATpcKx1ahDxWQTvgs/58FsiAyVMkCP4kGM +N2VoaUiAxAmwY0gHSveE+LnsgYpUdXnwoT4xtLbe8LM +-> ssh-ed25519 1g/xww ZxXXcLbTTeGemgBkk8gDT2137C041/vpfEtVnW8c+EU +CmXD00jt0xQ9bEOXSZIJ8HjnDKPujJ8/JnRVIxYfEw8 +-> ssh-ed25519 dbKeHw V0Z06Hl6E0J2y/D5U/3m4pIOa7w1Ja9w/R5joR7xRS4 +jSxNxMhgeho8OFyOhe3Ha3pa8BohO9gF1o5y/Ho1grI +-> ssh-ed25519 3qPtug PWzembnWLaMz2gq2rzbmRXW8HHuiJMHgfoXlkLy5M1o +8zSuzvJwdDP2K+PBkH85/0Y9LACIhbxAxE9UBUdbT+8 +-> ssh-ed25519 FRQvIA 2CVWLyG/XvphNqABxcO/K2KLZmvFydPaXG3xP7PytXI +3Uozzj/e/ANvuL2WYjpATf3Oh5kQPAwUrAGanACLSOY +-> ssh-ed25519 jb0ALQ DK8euAthdXCXDiIA8+dWOWyx17CFUh1SlwrXT2me718 +5ucvnjUSC8aKGI+vfUPbBD2CATTQq155mGRpRz0aD7s +--- 1qYd6bwSytOqJLrWin7RSjqindVSb+zoT1tKK3s3k98 +%Îv-/P<Wy,SD6HWkk/c]!EqEl)h8fuV9xf[ʴ)ͻ|{Vkb=ԍ`f],kx%Qsu5i獚FU–x^Nn \ No newline at end of file From 1d33dd3cece0de68bfb4398483d5c5ec1ba0e52b Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sat, 17 Jan 2026 15:52:11 -0600 Subject: [PATCH 076/149] flake: Update flake.lock --- flake.lock | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/flake.lock b/flake.lock index 6141529..c741c4c 100644 --- a/flake.lock +++ b/flake.lock @@ -55,11 +55,11 @@ ] }, "locked": { - "lastModified": 1764613336, - "narHash": "sha256-L979az28t/+SXvYw9qhOno5HLlDwkZOpz6LzCLnjmRM=", + "lastModified": 1768603898, + "narHash": "sha256-vRV1dWJOCpCal3PRr86wE2WTOMfAhTu6G7bSvOsryUo=", "owner": "nix-community", "repo": "home-manager", - "rev": "f3902b5d8767985680875ad86d028371100faeb3", + "rev": "2a63d0e9d2c72ac4d4150ebb242cf8d86f488c8c", "type": "github" }, "original": { @@ -76,11 +76,11 @@ ] }, "locked": { - "lastModified": 1764161084, - "narHash": "sha256-HN84sByg9FhJnojkGGDSrcjcbeioFWoNXfuyYfJ1kBE=", + "lastModified": 1767634391, + "narHash": "sha256-owcSz2ICqTSvhBbhPP+1eWzi88e54rRZtfCNE5E/wwg=", "owner": "LnL7", "repo": "nix-darwin", - "rev": "e95de00a471d07435e0527ff4db092c84998698e", + "rev": "08585aacc3d6d6c280a02da195fdbd4b9cf083c2", "type": "github" }, "original": { @@ -150,11 +150,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1764522689, - "narHash": "sha256-SqUuBFjhl/kpDiVaKLQBoD8TLD+/cTUzzgVFoaHrkqY=", + "lastModified": 1768621446, + "narHash": "sha256-6YwHV1cjv6arXdF/PQc365h1j+Qje3Pydk501Rm4Q+4=", "owner": "nixos", "repo": "nixpkgs", - "rev": "8bb5646e0bed5dbd3ab08c7a7cc15b75ab4e1d0f", + "rev": "72ac591e737060deab2b86d6952babd1f896d7c5", "type": "github" }, "original": { @@ -166,11 +166,11 @@ }, "nixpkgs-darwin": { "locked": { - "lastModified": 1764572236, - "narHash": "sha256-hLp6T/vKdrBQolpbN3EhJOKTXZYxJZPzpnoZz+fEGlE=", + "lastModified": 1767962478, + "narHash": "sha256-7ywwapHmJ2/dtP0j1t9fV9KQc+byL9W9X9oG3aDS4qg=", "owner": "nixos", "repo": "nixpkgs", - "rev": "b0924ea1889b366de6bb0018a9db70b2c43a15f8", + "rev": "35588f29848c57ea8ac86699278d2a410dab0adb", "type": "github" }, "original": { @@ -182,11 +182,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1764642553, - "narHash": "sha256-mvbFFzVBhVK1FjyPHZGMAKpNiqkr7k++xIwy+p/NQvA=", + "lastModified": 1768569498, + "narHash": "sha256-bB6Nt99Cj8Nu5nIUq0GLmpiErIT5KFshMQJGMZwgqUo=", "owner": "nixos", "repo": "nixpkgs", - "rev": "f720de59066162ee879adcc8c79e15c51fe6bfb4", + "rev": "be5afa0fcb31f0a96bf9ecba05a516c66fcd8114", "type": "github" }, "original": { @@ -204,11 +204,11 @@ ] }, "locked": { - "lastModified": 1764683664, - "narHash": "sha256-Mr5HKf/bjAJ8H7/H0qJSk2BEV/OILkDIFKrGK0dUVUk=", + "lastModified": 1768680744, + "narHash": "sha256-8mC5CSIG/FqwPYBMGFsE0o6GW+mVvGQJVjUqhlSBOHU=", "owner": "nix-community", "repo": "NUR", - "rev": "b8b40e258cf4c959b06b7322648c87674633629b", + "rev": "9bbd09ceb26cc0d806571f4682b17e1565fc2486", "type": "github" }, "original": { @@ -227,11 +227,11 @@ ] }, "locked": { - "lastModified": 1763909441, - "narHash": "sha256-56LwV51TX/FhgX+5LCG6akQ5KrOWuKgcJa+eUsRMxsc=", + "lastModified": 1767662275, + "narHash": "sha256-d5Q1GmQ+sW1Bt8cgDE0vOihzLaswsm8cSdg8124EqXE=", "owner": "nix-community", "repo": "plasma-manager", - "rev": "b24ed4b272256dfc1cc2291f89a9821d5f9e14b4", + "rev": "51816be33a1ff0d4b22427de83222d5bfa96d30e", "type": "github" }, "original": { @@ -242,11 +242,11 @@ }, "quadlet-nix": { "locked": { - "lastModified": 1763141753, - "narHash": "sha256-XAHkOkLEWbRQZ6t/SowwOukrUfIneNQOC/UEQlTaPBU=", + "lastModified": 1767469290, + "narHash": "sha256-VuxV4TzPXKFFvbqsaT9gCFsN30yx9dfMs5iZhL7sYrY=", "owner": "SEIAROTg", "repo": "quadlet-nix", - "rev": "211b5c626cf9ea91403b510e2ac5ca03a7194566", + "rev": "f5dd07b6a491b67d4f0742e6a8f46d92ff92cdc7", "type": "github" }, "original": { @@ -278,11 +278,11 @@ }, "locked": { "dir": "pkgs/firefox-addons", - "lastModified": 1764648280, - "narHash": "sha256-xniOnxIx/qhm+maO4mb9BZ7FytcUhNeTm1Y/QBjNf8o=", + "lastModified": 1768622624, + "narHash": "sha256-Em6PP667PeXbEjidbV2LnNwmUYohbrSFvVPLYLUDHms=", "owner": "rycee", "repo": "nur-expressions", - "rev": "119826bd51ad1a8012e0585f3a073571a35a812e", + "rev": "8061c6d9199dc6cc0727d4241959eea28f2fa0a6", "type": "gitlab" }, "original": { From 308f1e23b0c033aa2a39858c3b5f97a09d9b3986 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sat, 17 Jan 2026 15:52:29 -0600 Subject: [PATCH 077/149] feat: Don't use Nix version of Zed binary --- programs/zed.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/zed.nix b/programs/zed.nix index 6985d69..8b4fc69 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -1,6 +1,7 @@ { pkgs, ... }: { programs.zed-editor = { enable = true; + package = null; extensions = [ "basher" "clean-vscode-icons" From d36885d834acb4b9810ef854fb4939c60df77a99 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 23 Jan 2026 09:07:01 -0600 Subject: [PATCH 078/149] brew: Zap Dolphin --- systems/darwin/corianne.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index c83a9a1..5a2edbd 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -208,7 +208,6 @@ in { casks = [ "alt-tab" "db-browser-for-sqlite" - "dolphin" "firefox" "freetube" "inkscape" From 642967c9968dc3f6fb15139fc5e25e0a6616c507 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 23 Jan 2026 09:13:34 -0600 Subject: [PATCH 079/149] pkg: Remove FreeTube --- homes/darwin.nix | 92 ------------------------------------- homes/linux-desktop.nix | 91 ------------------------------------ playbooks/packages.yaml | 1 - programs/firefox.nix | 1 - systems/darwin/corianne.nix | 1 - 5 files changed, 186 deletions(-) diff --git a/homes/darwin.nix b/homes/darwin.nix index 9cabb63..32cc0e2 100644 --- a/homes/darwin.nix +++ b/homes/darwin.nix @@ -31,98 +31,6 @@ tailscale = "/Applications/Tailscale.app/Contents/MacOS/Tailscale"; }; }; - launchd = { - enable = true; - agents = { - - freetube-sync = { - enable = true; - config = { - Label = "local.home-manager.freetube-sync"; - ProgramArguments = [ - "/bin/sh" - "-c" - '' - FREETUBE_CONFIG_DIR="$HOME/Library/Application Support/FreeTube" - NEXTCLOUD_DIR="$HOME/Nextcloud/Settings/FreeTube" - - # Create directories if they don't exist - mkdir -p "$FREETUBE_CONFIG_DIR" - mkdir -p "$NEXTCLOUD_DIR" - - # List of database files to sync - DB_FILES=("settings.db" "history.db" "playlists.db" "subscriptions.db" "profiles.db") - - # Initial sync if Nextcloud has db files but FreeTube doesn't - if [ -n "$(ls $NEXTCLOUD_DIR/*.db 2>/dev/null)" ] && [ ! -n "$(ls $FREETUBE_CONFIG_DIR/*.db 2>/dev/null)" ]; then - echo "Performing initial sync from Nextcloud to FreeTube" - for DB_FILE in "''${DB_FILES[@]}"; do - if [ -f "$NEXTCLOUD_DIR/$DB_FILE" ]; then - rsync -av --checksum "$NEXTCLOUD_DIR/$DB_FILE" "$FREETUBE_CONFIG_DIR/$DB_FILE" - fi - done - # If Nextcloud is empty but FreeTube has db files, copy to Nextcloud - elif [ ! -n "$(ls $NEXTCLOUD_DIR/*.db 2>/dev/null)" ] && [ -n "$(ls $FREETUBE_CONFIG_DIR/*.db 2>/dev/null)" ]; then - echo "Performing initial sync from FreeTube to Nextcloud" - for DB_FILE in "''${DB_FILES[@]}"; do - if [ -f "$FREETUBE_CONFIG_DIR/$DB_FILE" ]; then - rsync -av --checksum "$FREETUBE_CONFIG_DIR/$DB_FILE" "$NEXTCLOUD_DIR/$DB_FILE" - fi - done - else - # Process each database file individually - for DB_FILE in "''${DB_FILES[@]}"; do - FT_PATH="$FREETUBE_CONFIG_DIR/$DB_FILE" - NC_PATH="$NEXTCLOUD_DIR/$DB_FILE" - - # Skip if neither file exists - if [ ! -f "$FT_PATH" ] && [ ! -f "$NC_PATH" ]; then - continue - fi - - # If only one exists, copy it - if [ -f "$FT_PATH" ] && [ ! -f "$NC_PATH" ]; then - echo "Copying $DB_FILE from FreeTube to Nextcloud" - rsync -av "$FT_PATH" "$NC_PATH" - continue - fi - - if [ ! -f "$FT_PATH" ] && [ -f "$NC_PATH" ]; then - echo "Copying $DB_FILE from Nextcloud to FreeTube" - rsync -av "$NC_PATH" "$FT_PATH" - continue - fi - - # Both files exist, check which is newer - if [ "$FT_PATH" -nt "$NC_PATH" ]; then - echo "Syncing newer $DB_FILE from FreeTube to Nextcloud" - rsync -av --update "$FT_PATH" "$NC_PATH" - elif [ "$NC_PATH" -nt "$FT_PATH" ]; then - echo "Syncing newer $DB_FILE from Nextcloud to FreeTube" - rsync -av --update "$NC_PATH" "$FT_PATH" - else - # Same modification time, compare checksums - echo "Verifying $DB_FILE with checksum comparison" - rsync -av --checksum "$NC_PATH" "$FT_PATH" - rsync -av --checksum "$FT_PATH" "$NC_PATH" - fi - done - fi - '' - ]; - RunAtLoad = true; - StartInterval = 300; # Run every 5 minutes (300 seconds) - StandardOutPath = - "${config.home.homeDirectory}/Library/Logs/freetube-sync.log"; - StandardErrorPath = - "${config.home.homeDirectory}/Library/Logs/freetube-sync-error.log"; - EnvironmentVariables = { - PATH = "${lib.makeBinPath [ pkgs.rsync pkgs.findutils ]}:$PATH"; - }; - }; - }; - }; - }; programs = { bash = { profileExtra = '' diff --git a/homes/linux-desktop.nix b/homes/linux-desktop.nix index 2516d48..8d25100 100644 --- a/homes/linux-desktop.nix +++ b/homes/linux-desktop.nix @@ -18,97 +18,6 @@ in { ''; }; }; - systemd.user = { - services = { - freetube-sync = { - Unit = { - Description = "Sync FreeTube settings with Nextcloud"; - After = [ "network.target" ]; - }; - Service = { - Type = "oneshot"; - ExecStart = "${pkgs.writeShellScript "freetube-sync.sh" '' - FREETUBE_CONFIG_DIR="$HOME/.var/app/io.freetubeapp.FreeTube/config/FreeTube" - NEXTCLOUD_DIR="$HOME/Nextcloud/Settings/FreeTube" - - # Create directories if they don't exist - mkdir -p "$FREETUBE_CONFIG_DIR" - mkdir -p "$NEXTCLOUD_DIR" - - # List of database files to sync - DB_FILES=("settings.db" "history.db" "playlists.db" "subscriptions.db" "profiles.db") - - # Initial sync if Nextcloud has db files but FreeTube doesn't - if [ -n "$(ls -A $NEXTCLOUD_DIR/*.db 2>/dev/null)" ] && [ ! -n "$(ls -A $FREETUBE_CONFIG_DIR/*.db 2>/dev/null)" ]; then - echo "Performing initial sync from Nextcloud to FreeTube" - for DB_FILE in "''${DB_FILES[@]}"; do - if [ -f "$NEXTCLOUD_DIR/$DB_FILE" ]; then - rsync -av --checksum "$NEXTCLOUD_DIR/$DB_FILE" "$FREETUBE_CONFIG_DIR/$DB_FILE" - fi - done - # If Nextcloud is empty but FreeTube has db files, copy to Nextcloud - elif [ ! -n "$(ls -A $NEXTCLOUD_DIR/*.db 2>/dev/null)" ] && [ -n "$(ls -A $FREETUBE_CONFIG_DIR/*.db 2>/dev/null)" ]; then - echo "Performing initial sync from FreeTube to Nextcloud" - for DB_FILE in "''${DB_FILES[@]}"; do - if [ -f "$FREETUBE_CONFIG_DIR/$DB_FILE" ]; then - rsync -av --checksum "$FREETUBE_CONFIG_DIR/$DB_FILE" "$NEXTCLOUD_DIR/$DB_FILE" - fi - done - else - # Process each database file individually - for DB_FILE in "''${DB_FILES[@]}"; do - FT_PATH="$FREETUBE_CONFIG_DIR/$DB_FILE" - NC_PATH="$NEXTCLOUD_DIR/$DB_FILE" - - # Skip if neither file exists - if [ ! -f "$FT_PATH" ] && [ ! -f "$NC_PATH" ]; then - continue - fi - - # If only one exists, copy it - if [ -f "$FT_PATH" ] && [ ! -f "$NC_PATH" ]; then - echo "Copying $DB_FILE from FreeTube to Nextcloud" - rsync -av "$FT_PATH" "$NC_PATH" - continue - fi - - if [ ! -f "$FT_PATH" ] && [ -f "$NC_PATH" ]; then - echo "Copying $DB_FILE from Nextcloud to FreeTube" - rsync -av "$NC_PATH" "$FT_PATH" - continue - fi - - # Both files exist, check which is newer - if [ "$FT_PATH" -nt "$NC_PATH" ]; then - echo "Syncing newer $DB_FILE from FreeTube to Nextcloud" - rsync -av --update "$FT_PATH" "$NC_PATH" - elif [ "$NC_PATH" -nt "$FT_PATH" ]; then - echo "Syncing newer $DB_FILE from Nextcloud to FreeTube" - rsync -av --update "$NC_PATH" "$FT_PATH" - else - # Same modification time, compare checksums - echo "Verifying $DB_FILE with checksum comparison" - rsync -av --checksum "$NC_PATH" "$FT_PATH" - rsync -av --checksum "$FT_PATH" "$NC_PATH" - fi - done - fi - ''}"; - }; - }; - }; - - timers = { - freetube-sync = { - Unit = { Description = "Timer for FreeTube settings sync"; }; - Timer = { - OnBootSec = "1m"; - OnUnitActiveSec = "5m"; - }; - Install = { WantedBy = [ "timers.target" ]; }; - }; - }; - }; xdg = { configFile = { "plasma-workspace/env/ZED_WINDOW_DECORATIONS.sh".text = diff --git a/playbooks/packages.yaml b/playbooks/packages.yaml index f13c01b..f293815 100644 --- a/playbooks/packages.yaml +++ b/playbooks/packages.yaml @@ -83,7 +83,6 @@ - com.logseq.Logseq - com.slack.Slack - dev.deedles.Trayscale - - io.freetubeapp.FreeTube - io.github.alainm23.planify - io.github.dweymouth.supersonic - io.openrct2.OpenRCT2 diff --git a/programs/firefox.nix b/programs/firefox.nix index ed6705f..dcf0553 100644 --- a/programs/firefox.nix +++ b/programs/firefox.nix @@ -35,7 +35,6 @@ [ bitwarden multi-account-containers - libredirect old-reddit-redirect ublock-origin user-agent-string-switcher diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index 5a2edbd..a029992 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -209,7 +209,6 @@ in { "alt-tab" "db-browser-for-sqlite" "firefox" - "freetube" "inkscape" "iterm2" "logseq" From 0837009c2d821b714583e350ccffaf9b8d50a3a7 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 18 Feb 2026 15:47:11 -0600 Subject: [PATCH 080/149] chore: Update flake.lock --- flake.lock | 98 +++++++++++++++++------------------------------------- 1 file changed, 30 insertions(+), 68 deletions(-) diff --git a/flake.lock b/flake.lock index c741c4c..5ffff1e 100644 --- a/flake.lock +++ b/flake.lock @@ -14,11 +14,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1762618334, - "narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=", + "lastModified": 1770165109, + "narHash": "sha256-9VnK6Oqai65puVJ4WYtCTvlJeXxMzAp/69HhQuTdl/I=", "owner": "ryantm", "repo": "agenix", - "rev": "fcdea223397448d35d9b31f798479227e80183f6", + "rev": "b027ee29d959fda4b60b57566d64c98a202e0feb", "type": "github" }, "original": { @@ -55,11 +55,11 @@ ] }, "locked": { - "lastModified": 1768603898, - "narHash": "sha256-vRV1dWJOCpCal3PRr86wE2WTOMfAhTu6G7bSvOsryUo=", + "lastModified": 1770260404, + "narHash": "sha256-3iVX1+7YUIt23hBx1WZsUllhbmP2EnXrV8tCRbLxHc8=", "owner": "nix-community", "repo": "home-manager", - "rev": "2a63d0e9d2c72ac4d4150ebb242cf8d86f488c8c", + "rev": "0d782ee42c86b196acff08acfbf41bb7d13eed5b", "type": "github" }, "original": { @@ -92,17 +92,16 @@ }, "nix-rosetta-builder": { "inputs": { - "nixos-generators": "nixos-generators", "nixpkgs": [ "nixpkgs-darwin" ] }, "locked": { - "lastModified": 1756177999, - "narHash": "sha256-aSbB7/jrt7ujiJ55f2uGhOo+usGxVSkqbAMVgg2jDls=", + "lastModified": 1770491098, + "narHash": "sha256-ZfhynJqgV3A9hEivcgOEZa+TZnJPc26lIUjzKsSchgI=", "owner": "cpick", "repo": "nix-rosetta-builder", - "rev": "ebb7162a975074fb570a2c3ac02bc543ff2e9df4", + "rev": "50e6070082e0b4fbaf67dd8f346892a1a9ed685c", "type": "github" }, "original": { @@ -111,50 +110,13 @@ "type": "github" } }, - "nixlib": { - "locked": { - "lastModified": 1736643958, - "narHash": "sha256-tmpqTSWVRJVhpvfSN9KXBvKEXplrwKnSZNAoNPf/S/s=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "1418bc28a52126761c02dd3d89b2d8ca0f521181", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", - "type": "github" - } - }, - "nixos-generators": { - "inputs": { - "nixlib": "nixlib", - "nixpkgs": [ - "nix-rosetta-builder", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1737057290, - "narHash": "sha256-3Pe0yKlCc7EOeq1X/aJVDH0CtNL+tIBm49vpepwL1MQ=", - "owner": "nix-community", - "repo": "nixos-generators", - "rev": "d002ce9b6e7eb467cd1c6bb9aef9c35d191b5453", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixos-generators", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1768621446, - "narHash": "sha256-6YwHV1cjv6arXdF/PQc365h1j+Qje3Pydk501Rm4Q+4=", + "lastModified": 1771208521, + "narHash": "sha256-X01Q3DgSpjeBpapoGA4rzKOn25qdKxbPnxHeMLNoHTU=", "owner": "nixos", "repo": "nixpkgs", - "rev": "72ac591e737060deab2b86d6952babd1f896d7c5", + "rev": "fa56d7d6de78f5a7f997b0ea2bc6efd5868ad9e8", "type": "github" }, "original": { @@ -166,11 +128,11 @@ }, "nixpkgs-darwin": { "locked": { - "lastModified": 1767962478, - "narHash": "sha256-7ywwapHmJ2/dtP0j1t9fV9KQc+byL9W9X9oG3aDS4qg=", + "lastModified": 1771352457, + "narHash": "sha256-CCItBNMyLmtWqxTVaDAeeaIigbuaiZuN3WO8PZNkGBc=", "owner": "nixos", "repo": "nixpkgs", - "rev": "35588f29848c57ea8ac86699278d2a410dab0adb", + "rev": "f8a68d8ce473ec59300d9fb510a1b545c1290939", "type": "github" }, "original": { @@ -182,11 +144,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1768569498, - "narHash": "sha256-bB6Nt99Cj8Nu5nIUq0GLmpiErIT5KFshMQJGMZwgqUo=", + "lastModified": 1771177547, + "narHash": "sha256-trTtk3WTOHz7hSw89xIIvahkgoFJYQ0G43IlqprFoMA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "be5afa0fcb31f0a96bf9ecba05a516c66fcd8114", + "rev": "ac055f38c798b0d87695240c7b761b82fc7e5bc2", "type": "github" }, "original": { @@ -204,11 +166,11 @@ ] }, "locked": { - "lastModified": 1768680744, - "narHash": "sha256-8mC5CSIG/FqwPYBMGFsE0o6GW+mVvGQJVjUqhlSBOHU=", + "lastModified": 1771425294, + "narHash": "sha256-owiQE9oINf1cgaulbrr2sMjelk2cmR8rkxLRPYYL6Kg=", "owner": "nix-community", "repo": "NUR", - "rev": "9bbd09ceb26cc0d806571f4682b17e1565fc2486", + "rev": "242d44cd6af365da2dfa77422263b29d0ac9f39f", "type": "github" }, "original": { @@ -227,11 +189,11 @@ ] }, "locked": { - "lastModified": 1767662275, - "narHash": "sha256-d5Q1GmQ+sW1Bt8cgDE0vOihzLaswsm8cSdg8124EqXE=", + "lastModified": 1770766818, + "narHash": "sha256-12RCFLyAedyMOdenUi7cN3ioJPEGjA/ZG1BLjugfUVs=", "owner": "nix-community", "repo": "plasma-manager", - "rev": "51816be33a1ff0d4b22427de83222d5bfa96d30e", + "rev": "44b928068359b7d2310a34de39555c63c93a2c90", "type": "github" }, "original": { @@ -242,11 +204,11 @@ }, "quadlet-nix": { "locked": { - "lastModified": 1767469290, - "narHash": "sha256-VuxV4TzPXKFFvbqsaT9gCFsN30yx9dfMs5iZhL7sYrY=", + "lastModified": 1770606362, + "narHash": "sha256-6pOOPOQr4rtgShBtkLkSDTql5rRqcUgTRz8O+axK2eM=", "owner": "SEIAROTg", "repo": "quadlet-nix", - "rev": "f5dd07b6a491b67d4f0742e6a8f46d92ff92cdc7", + "rev": "f4ae60350ea6015b6560cbd0e1f11f7e195c993d", "type": "github" }, "original": { @@ -278,11 +240,11 @@ }, "locked": { "dir": "pkgs/firefox-addons", - "lastModified": 1768622624, - "narHash": "sha256-Em6PP667PeXbEjidbV2LnNwmUYohbrSFvVPLYLUDHms=", + "lastModified": 1771301023, + "narHash": "sha256-0XauSmXBLOqn8SYHRWOL7Z9O7m5qtF0Yw6rqXVHkEnw=", "owner": "rycee", "repo": "nur-expressions", - "rev": "8061c6d9199dc6cc0727d4241959eea28f2fa0a6", + "rev": "1cf8b4f42720573ef35dcd7d2ba0fd80e40954e9", "type": "gitlab" }, "original": { From db070d2702b2e3189d49b12f1bc3880226486448 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 18 Feb 2026 15:48:59 -0600 Subject: [PATCH 081/149] feat: Add audiobookshelf service --- secrets.nix | 2 + secrets/millironx-books-s3.age | Bin 0 -> 824 bytes services/audiobookshelf.nix | 78 +++++++++++++++++++++++++++++++++ systems/linux/mcentire.nix | 1 + 4 files changed, 81 insertions(+) create mode 100644 secrets/millironx-books-s3.age create mode 100644 services/audiobookshelf.nix diff --git a/secrets.nix b/secrets.nix index ed1352e..ffbb9ab 100644 --- a/secrets.nix +++ b/secrets.nix @@ -36,6 +36,8 @@ in { ++ [ corianne-host ]; "secrets/freshrss.toml.age".publicKeys = system-administrators ++ [ mcentire-host ]; + "secrets/millironx-books-s3.age".publicKeys = system-administrators + ++ [ mcentire-host ]; "secrets/network-information.age".publicKeys = system-administrators ++ [ bosephus-host ]; } diff --git a/secrets/millironx-books-s3.age b/secrets/millironx-books-s3.age new file mode 100644 index 0000000000000000000000000000000000000000..2f57e3ae29051542b4d9b6f2745b4b1fe21f633d GIT binary patch literal 824 zcmZ9_z02cd008hq;W#4rx}3`)7bl0(%U9E+i;%oclQe1b(WGgMgK0jVyiN1*Ah_uvxH@B>7hvRzOxE`(bj8YgnBluA4j655QeF>ltHi>@iv*;vY zsPL8^KX=H90m@G2>cL>3M6|F;WUigsvurP!V{=aBymY=%fH-v>eyNLAoT3#-yr^}j zl1fRNSR_xR+NhZ`bH>)zCQ)P=3c!4%cmr0Si4D&!7$zutK+hM_b{U{Ba1B4&*IY%? z+eGKjw{WjTN{6r0Q>W|ZB(hKb#Gb;#h~$WkFCl?A$h{6?=!U)0MT|#c-qJ7Zm|urA zpR!!ATN~T(uvfH@?xxO4myZy#?O|&7t$MyO&}>?O7o4zJjZ9`rlSPaqfpth&sGCs= z$AA>rMZzddpJW3DsF*>Tno~Ks=Yx*UX|nhE)Daqv5=U_(?8${ArU$sFTUj{YX10Y? z0iVMW5npDmLd+V8B*3^fDBzc4u#%OP99GMbdzzukRbmU+)`t!kgNmh8({z`p?fQO_ z$21$JZAMwUEDBG{F6}1JJ>LeGq-O(M@y9-ixLs$3l$_6TicT!y(S1nsOjUi?9*9{RS`xd!-pbOy??30chfjWf@5@KZXYYJ}QC@ub|7-d@ zdwlcb@1EXx Date: Fri, 20 Feb 2026 10:07:14 -0600 Subject: [PATCH 082/149] fix: Audiobookshelf file permissions --- services/audiobookshelf.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/audiobookshelf.nix b/services/audiobookshelf.nix index c4f5070..c81b0dd 100644 --- a/services/audiobookshelf.nix +++ b/services/audiobookshelf.nix @@ -21,6 +21,9 @@ in { "use_path_request_style" "url=https://us-east-1.linodeobjects.com/" "passwd_file=${config.age.secrets.millironx-books-s3-token.path}" + "uid=${user}" + "gid=${user}" + "umask=0022" ]; }; From 02e115937f48088d7a938df5815034bdfd6c43fc Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 20 Feb 2026 16:06:33 -0600 Subject: [PATCH 083/149] feat: Add navidrome service --- secrets.nix | 4 ++ secrets/millironx-music-s3.age | Bin 0 -> 824 bytes secrets/navidrome.toml.age | Bin 0 -> 869 bytes services/navidrome.nix | 104 +++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+) create mode 100644 secrets/millironx-music-s3.age create mode 100644 secrets/navidrome.toml.age create mode 100644 services/navidrome.nix diff --git a/secrets.nix b/secrets.nix index ffbb9ab..ce66958 100644 --- a/secrets.nix +++ b/secrets.nix @@ -38,6 +38,10 @@ in { ++ [ mcentire-host ]; "secrets/millironx-books-s3.age".publicKeys = system-administrators ++ [ mcentire-host ]; + "secrets/millironx-music-s3.age".publicKeys = system-administrators + ++ [ mcentire-host ]; + "secrets/navidrome.toml.age".publicKeys = system-administrators + ++ [ mcentire-host ]; "secrets/network-information.age".publicKeys = system-administrators ++ [ bosephus-host ]; } diff --git a/secrets/millironx-music-s3.age b/secrets/millironx-music-s3.age new file mode 100644 index 0000000000000000000000000000000000000000..14e9b6480b10c88b175f5d07b915dfa899bd98e4 GIT binary patch literal 824 zcmZY6yNlBR0LO6`Imv;OI*G*Dt7)3#dUZI+qiLE))1+zB#zE31&7*0a%@Yw+L=XfK zMa03u)dwPucP_Wwf1u|mPA5+1AR_8~{skYtzn^ZIHPfHPWw>$z|8fvpPzD3FZ7@mf znrSpJ3~qsrhj^6)W(g(J1RP-+V^ITE!~8%>^Z^86B{v#z6-g7m*Kdi_kp$#O6``9f z>UT4m4Q)1G=1n27sCK(P>CJHlX$I-mL{F*;J+8qPROC5mW};9`MqH-ki6pw&vXhy7 zjwOuHK>`|f350W4!<}$c7l`@Em@Qntr~+x8p^?F5Niz+gLd0i0-ZCsg$<=-w&AsHf zW=uJg$w5ky`*v)_4CRp8Oh}sYI8|bf^Xt5uM|9UHHb>H|K2>oP$h5#GChAn>4Us74 z2}_C%#Wg66a}_D&19(0gLk4omAf@9P67^T91$r2*qOuD$JBo}?Jvm^+YA7hIVNT0> zdlQ!7tc-18VUGnM&O^SQt!P8%ILTN1>{{3BizVb-aaUNS%__|67ulrL2pC zaW2(yHpGKQV^ErmS~zJB(80m?%~1vlfS>L?cKk7>fJ5)?T^#&rw1qY ZH_l&A*PrswpB#a!wZ~U(-#GmF>Mxgm9c2Ij literal 0 HcmV?d00001 diff --git a/secrets/navidrome.toml.age b/secrets/navidrome.toml.age new file mode 100644 index 0000000000000000000000000000000000000000..23319853d2194d799444462a70718142dcbe0cce GIT binary patch literal 869 zcmZY2&#T*X003|qOfjx5fogp4!0KnFDRDH^Z1QaJqYZB-OYdOR~ zPKt9h>&`o18N~$(W<$&8`4ps1S{F=h)|69w(CQ46(;L09@*>2Gxwo}NeIuapWYuIx zltqtcG;-A#+R55Q`tDGqc#^Kf5!MXEBPxK5=9L8D>H{K$wB`BE(IBK?BnTr{9^NARpU(hBVW^SU{)D=Gv)EN@K|K;NA@)IXFzG^P^AG{Af z`uDAGp8vY_2Dd2RIs4(IGr=oQ-griP?T+;6h3}sGQu&)&8Fd+NgH_x}0# h;mr*=xp~XI_v{aQckUl+ul{*A`+~W(`0;~l{{!OzEB*ig literal 0 HcmV?d00001 diff --git a/services/navidrome.nix b/services/navidrome.nix new file mode 100644 index 0000000..bd8bc94 --- /dev/null +++ b/services/navidrome.nix @@ -0,0 +1,104 @@ +{ config, pkgs, home-manager-quadlet-nix, ... }: +let + user = "navidrome"; + port = "4533"; + authentikPort = "9000"; + stateDirectory = "/var/lib/${user}"; + s3BucketName = "millironx-music"; + s3MountDirectory = "/mount/s3/${s3BucketName}"; +in { + age.secrets = { + millironx-music-s3-token.file = ./../secrets/millironx-music-s3.age; + "navidrome.toml" = { + file = ./../secrets/navidrome.toml.age; + owner = user; + }; + }; + + millironx.podman-secrets.navidrome = { + inherit user; + secrets-files = [ config.age.secrets."navidrome.toml".path ]; + }; + + environment.systemPackages = [ pkgs.s3fs ]; + + fileSystems."${s3BucketName}" = { + device = s3BucketName; + mountPoint = s3MountDirectory; + fsType = "fuse./run/current-system/sw/bin/s3fs"; + noCheck = true; + options = [ + "_netdev" + "allow_other" + "use_path_request_style" + "url=https://us-east-1.linodeobjects.com/" + "passwd_file=${config.age.secrets.millironx-music-s3-token.path}" + "uid=${user}" + "gid=${user}" + "umask=0022" + ]; + }; + + systemd.tmpfiles.rules = + map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") [ "" "data" ]; + + services.borgmatic.configurations."${config.networking.hostName}" = { + source_directories = map (d: "${stateDirectory}/${d}") [ "data" ]; + }; + + services.caddy.virtualHosts."music.millironx.com".extraConfig = '' + # Authentik output endpoint + reverse_proxy /outpost.goauthentik.io/* http://127.0.0.1:${authentikPort} + + # Protect everything except share and subsonic endpoints + @protected not path /share/* /rest/* + forward_auth @protected http://127.0.0.1:${authentikPort} { + uri /outpost.goauthentik.io/auth/caddy + copy_headers X-Authentik-Username>Remote-User + } + + # Forward everything to Navidrome + reverse_proxy 127.0.0.1:${port} + ''; + + users.users."${user}" = { + group = "${user}"; + isNormalUser = true; + home = stateDirectory; + createHome = true; + linger = true; + autoSubUidGidRange = true; + }; + users.groups."${user}" = { }; + + home-manager.users."${user}" = { config, osConfig, ... }: { + imports = [ home-manager-quadlet-nix ]; + + home.stateVersion = "25.05"; + + virtualisation.quadlet = { + autoUpdate.enable = true; + containers.navidrome = { + autoStart = true; + containerConfig = { + image = "docker.io/deluan/navidrome:latest"; + environments = { + ND_BASEURL = "https://music.millironx.com"; + ND_EXTAUTH_TRUSTEDSOURCES = "10.0.0.0/8"; + }; + secrets = + map (s: "${s},type=env") [ "ND_LASTFM_APIKEY" "ND_LASTFM_SECRET" ]; + volumes = [ + "${s3MountDirectory}:/music:Uro" + "${stateDirectory}/data:/data:U" + ]; + publishPorts = [ "127.0.0.1:${port}:${port}" ]; + unitConfig.Requires = + [ osConfig.millironx.podman-secrets.navidrome.ref ]; + unitConfig.After = + [ osConfig.millironx.podman-secrets.navidrome.ref ]; + }; + }; + }; + }; +} From 9960aaf117c16fd5cdbfdd1c43ca84b1473261aa Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 20 Feb 2026 21:00:28 -0600 Subject: [PATCH 084/149] fix: Scope of Navidrome service dependencies --- services/navidrome.nix | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/services/navidrome.nix b/services/navidrome.nix index bd8bc94..f71f0ce 100644 --- a/services/navidrome.nix +++ b/services/navidrome.nix @@ -93,11 +93,10 @@ in { "${stateDirectory}/data:/data:U" ]; publishPorts = [ "127.0.0.1:${port}:${port}" ]; - unitConfig.Requires = - [ osConfig.millironx.podman-secrets.navidrome.ref ]; - unitConfig.After = - [ osConfig.millironx.podman-secrets.navidrome.ref ]; }; + unitConfig.Requires = + [ osConfig.millironx.podman-secrets.navidrome.ref ]; + unitConfig.After = [ osConfig.millironx.podman-secrets.navidrome.ref ]; }; }; }; From 3a748e980f511e4eed39ef4c0a24dd939522a940 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 20 Feb 2026 21:00:39 -0600 Subject: [PATCH 085/149] fix: Hook up Navidrome --- systems/linux/mcentire.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index cd3bb0f..c259c27 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -9,6 +9,7 @@ ./../../services/authentik.nix ./../../services/audiobookshelf.nix ./../../services/freshrss.nix + ./../../services/navidrome.nix ]; # Use the GRUB 2 boot loader. From 22f12f00715ff6277c534811d110967650bd7665 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 20 Feb 2026 21:33:35 -0600 Subject: [PATCH 086/149] fix: Navidrome secret names --- secrets/navidrome.toml.age | Bin 869 -> 875 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/secrets/navidrome.toml.age b/secrets/navidrome.toml.age index 23319853d2194d799444462a70718142dcbe0cce..dfbf16763cba2e425729767f24f9254b62f8d7c1 100644 GIT binary patch literal 875 zcmZ9_%gfsY008je#SssFI2@uf;>Cfbrb*kRIXLK-q)GE=^J>xrL7Ftpqe+wI-8dgN z#iJ+jAfm{WAv(Uv1VtS~od=OA2!ePRYz!2pBFHBS-uwFpehb%WI~zOQCAlAOo{Uo$ zDq)~~4$LyI?JSXgAI3pH?1qg5T5yCW0l#nwnDbpo#wrOL;vA{!SzQ>Iz)U{RKy0fdT}8nO!2u90FX?Tke~8;k3FK(mN*hzM{V z6jik>cyGMFEiKMrDiB-bjer%%r)&Vn1z9B)#bH1xM9RuNJaH7eN=tWTk5NJ0mKhc=q79{G z``bvC%JC4KDq0_tB&xfvb*=P-XsU}-7K#g@bcDb$RIGu9P|^?e7|5G+plrNpmYXBY z+hWFu?YZ(UBPWr>G>N2DLpwIZI&8)JTZ`!EvJ1+%I4SL}3C|F?wJHaisS#@iQG1hA z@_Eb%;PGfNL`!Nm05Z&gMv+dqRZCx*u}612ZPlk_2A?=08E{so##6rOt<)LNZnr_w zg_jsV8LlfM32GmrhZ|1L$e{<>ktoxcht!jRZaj`KfKM*|a~6O4;PkyWTGx-hzO7nE z&p!3C(D~3m9&~QL_UnI-UBNG%Q!g*SIsX3Y@0X3|9{l^QdoDe3|9h+FzbNiLeE0pc z_nkO%>iBi#VEXX`r_O&VU-|iS@`IB%|9#`+55nWs#TU;!LZ3f4{n4wR{c?ijlB3^% oJKw(3zHsZ^XOf?&w_kYk&mS**)#8Zn9)0N3SN^)TdP)1^e|%drW&i*H literal 869 zcmZY2&#T*X003|qOfjx5fogp4!0KnFDRDH^Z1QaJqYZB-OYdOR~ zPKt9h>&`o18N~$(W<$&8`4ps1S{F=h)|69w(CQ46(;L09@*>2Gxwo}NeIuapWYuIx zltqtcG;-A#+R55Q`tDGqc#^Kf5!MXEBPxK5=9L8D>H{K$wB`BE(IBK?BnTr{9^NARpU(hBVW^SU{)D=Gv)EN@K|K;NA@)IXFzG^P^AG{Af z`uDAGp8vY_2Dd2RIs4(IGr=oQ-griP?T+;6h3}sGQu&)&8Fd+NgH_x}0# h;mr*=xp~XI_v{aQckUl+ul{*A`+~W(`0;~l{{!OzEB*ig From a2fc6caf0d7ed29f598ce1949b9c878dd77b767e Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 20 Feb 2026 21:34:20 -0600 Subject: [PATCH 087/149] fix: Navidrome secret names --- secrets/navidrome.toml.age | Bin 875 -> 874 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/secrets/navidrome.toml.age b/secrets/navidrome.toml.age index dfbf16763cba2e425729767f24f9254b62f8d7c1..272a3dacc1cd8cfb4e2d52878bc663f68c8fd543 100644 GIT binary patch literal 874 zcmZY6+pF6I0LO8JDH;Vq5PT2}!q}j6x%Mo9qmWD6T${FOnkEcg)1*n7TXRo}55wbN zibHXTpn^l0w-;aZX>9l~L?(y>88XFpQD3|b5oCKl`wKpNf4`;cbe(vWwcEl^;uA^c zLKOmZp9S;W>pC{t>melQhgi6qfXFW6_QHzn_Uz9B7a*jRXYovI{~6OHBarD(`zepo|XsHtm^-KZM8w$?s8 zDwf#XYzU{HQN#$t_F)Sx7zhcZ6HE(Mv!9_mA08n4kH_n)Vi1ASg+6FlbV1jz=?Fu zgp3juG{H)sn(U|@EfQCZIYWwoiWrSu2u(1mUE{EZrQ@P>L6#zsAd5V6#?LCZnlG6q z6UI{F42>1avoVdWN)k4bDqI0BnKrs^)`X&1DH6;~5v%BdPM4-MY55K&uD^;%N|4r381lByDlIaLY)D# z6b9+^q|On!F1Q=oXZzR?ok62L)Z0Y(;kFI~>r)qOs)lIz+?`UJT9A^GHX^j3hmGFO z7b(9BtGFLxBL|+f6kzw8vae+85sAAb?{{tyI9g;PJLP(rDo->c<2J3#>EgnvaA5!1`Oj}0$%W&OJ@xna`{%xT zAnAV6{P*6EPrmZCfbrb*kRIXLK-q)GE=^J>xrL7Ftpqe+wI-8dgN z#iJ+jAfm{WAv(Uv1VtS~od=OA2!ePRYz!2pBFHBS-uwFpehb%WI~zOQCAlAOo{Uo$ zDq)~~4$LyI?JSXgAI3pH?1qg5T5yCW0l#nwnDbpo#wrOL;vA{!SzQ>Iz)U{RKy0fdT}8nO!2u90FX?Tke~8;k3FK(mN*hzM{V z6jik>cyGMFEiKMrDiB-bjer%%r)&Vn1z9B)#bH1xM9RuNJaH7eN=tWTk5NJ0mKhc=q79{G z``bvC%JC4KDq0_tB&xfvb*=P-XsU}-7K#g@bcDb$RIGu9P|^?e7|5G+plrNpmYXBY z+hWFu?YZ(UBPWr>G>N2DLpwIZI&8)JTZ`!EvJ1+%I4SL}3C|F?wJHaisS#@iQG1hA z@_Eb%;PGfNL`!Nm05Z&gMv+dqRZCx*u}612ZPlk_2A?=08E{so##6rOt<)LNZnr_w zg_jsV8LlfM32GmrhZ|1L$e{<>ktoxcht!jRZaj`KfKM*|a~6O4;PkyWTGx-hzO7nE z&p!3C(D~3m9&~QL_UnI-UBNG%Q!g*SIsX3Y@0X3|9{l^QdoDe3|9h+FzbNiLeE0pc z_nkO%>iBi#VEXX`r_O&VU-|iS@`IB%|9#`+55nWs#TU;!LZ3f4{n4wR{c?ijlB3^% oJKw(3zHsZ^XOf?&w_kYk&mS**)#8Zn9)0N3SN^)TdP)1^e|%drW&i*H From ffb44a20e05ca81c844aed5178fc7d01163ff4ee Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 20 Feb 2026 21:36:14 -0600 Subject: [PATCH 088/149] fix: Navidrome secret names --- secrets/navidrome.toml.age | Bin 874 -> 870 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/secrets/navidrome.toml.age b/secrets/navidrome.toml.age index 272a3dacc1cd8cfb4e2d52878bc663f68c8fd543..95d0fc881b1a36c8a68bbfdf3f3ad77685b4e1f4 100644 GIT binary patch literal 870 zcmZY5%ZuD}0KoB{(?xnx6v2Q{kT51Qd2OUFP9~d7GD#+nd5ecklF8&bc}#vk|)fz1ZD&(kL%aGK@oNY>V$I~hMr1?7qza3HgydXq)cm+GV(af zj-x^!SJ`&h)G0~kP=uvkM$vZUT9qW-^pt3FD2qw=4{`@4c-=Z$aGU_Rxt)F2F7D= zdQsyIy%PJdiluZBC?>mWXwLElYGo3(z$MvMW#nqPlU#MQ6hoxTdyr=)CA)N^AtLJ* zSs0lcGNjt)c@*_+9n%+D;`%th)y4m{Ap>k~cyPTEvRP%C#2%Q|OrR!fzp1Kvv{cll z?1h@BwCr?;BS|Pi`6QJCE~n8&rf_p9W!+IL9MV}mn`FT0vPqALv|~!{0~_jeI&kSI z@gOdydpZ+VwiK~5u5i;4f4m&(l_{99l8B`Rka3@Y9C23&d;CTi=Vmr9l~L?(y>88XFpQD3|b5oCKl`wKpNf4`;cbe(vWwcEl^;uA^c zLKOmZp9S;W>pC{t>melQhgi6qfXFW6_QHzn_Uz9B7a*jRXYovI{~6OHBarD(`zepo|XsHtm^-KZM8w$?s8 zDwf#XYzU{HQN#$t_F)Sx7zhcZ6HE(Mv!9_mA08n4kH_n)Vi1ASg+6FlbV1jz=?Fu zgp3juG{H)sn(U|@EfQCZIYWwoiWrSu2u(1mUE{EZrQ@P>L6#zsAd5V6#?LCZnlG6q z6UI{F42>1avoVdWN)k4bDqI0BnKrs^)`X&1DH6;~5v%BdPM4-MY55K&uD^;%N|4r381lByDlIaLY)D# z6b9+^q|On!F1Q=oXZzR?ok62L)Z0Y(;kFI~>r)qOs)lIz+?`UJT9A^GHX^j3hmGFO z7b(9BtGFLxBL|+f6kzw8vae+85sAAb?{{tyI9g;PJLP(rDo->c<2J3#>EgnvaA5!1`Oj}0$%W&OJ@xna`{%xT zAnAV6{P*6EPrmZ Date: Mon, 23 Feb 2026 09:08:32 -0600 Subject: [PATCH 089/149] fix: Navidrome reverse proxy config --- services/navidrome.nix | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/services/navidrome.nix b/services/navidrome.nix index f71f0ce..9ac3bdf 100644 --- a/services/navidrome.nix +++ b/services/navidrome.nix @@ -46,6 +46,11 @@ in { source_directories = map (d: "${stateDirectory}/${d}") [ "data" ]; }; + # Modified from + # - + # - + # Modifications are exclusively changes from Docker hostnames to 127.0.0.1 and + # port numbers services.caddy.virtualHosts."music.millironx.com".extraConfig = '' # Authentik output endpoint reverse_proxy /outpost.goauthentik.io/* http://127.0.0.1:${authentikPort} @@ -57,8 +62,31 @@ in { copy_headers X-Authentik-Username>Remote-User } + # Authentik uses the Authorization header if present, so should be able to + # authenticate subsonic clients that support BasicAuth. Requests from the + # Navidrome Web App will be authenticated via the existing session cookie. + # If you want to have Navidrome authenticate subsonic requests, remove this + # forward_auth block. + @subsonic path /rest/* + forward_auth @subsonic http://127.0.0.1:${authentikPort} { + uri /outpost.goauthentik.io/auth/caddy + copy_headers X-Authentik-Username>Remote-User + + # Some clients that claim to support basicauth still expect a subsonic + # response in case of authentication failure instead of a proper basicauth + # response. + @error status 1xx 3xx 4xx 5xx + handle_response @error { + respond < + + + SUBSONICERR 200 + } + } + # Forward everything to Navidrome - reverse_proxy 127.0.0.1:${port} + reverse_proxy http://127.0.0.1:${port} ''; users.users."${user}" = { @@ -84,7 +112,8 @@ in { image = "docker.io/deluan/navidrome:latest"; environments = { ND_BASEURL = "https://music.millironx.com"; - ND_EXTAUTH_TRUSTEDSOURCES = "10.0.0.0/8"; + # pasta appears to use the static host IP so trust that + ND_EXTAUTH_TRUSTEDSOURCES = "23.239.13.247/24"; }; secrets = map (s: "${s},type=env") [ "ND_LASTFM_APIKEY" "ND_LASTFM_SECRET" ]; From 41025b4b5574eb4f4df1eb831ec7441934fb2f27 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:10:46 -0600 Subject: [PATCH 090/149] fix: Navidrome mount point --- services/navidrome.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/navidrome.nix b/services/navidrome.nix index 9ac3bdf..9db322a 100644 --- a/services/navidrome.nix +++ b/services/navidrome.nix @@ -118,7 +118,7 @@ in { secrets = map (s: "${s},type=env") [ "ND_LASTFM_APIKEY" "ND_LASTFM_SECRET" ]; volumes = [ - "${s3MountDirectory}:/music:Uro" + "${s3MountDirectory}:/music:ro" "${stateDirectory}/data:/data:U" ]; publishPorts = [ "127.0.0.1:${port}:${port}" ]; From 38e851620cfc5af308e596ab449cd23e90840268 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 24 Feb 2026 10:36:42 -0600 Subject: [PATCH 091/149] feat: Add redis database --- systems/linux/mcentire.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index c259c27..5d80ada 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -65,6 +65,8 @@ # Do not "enable" database services, but include the package configuration # so that borgmatic does not freak out about unset variables postgresql.package = pkgs.postgresql_17; + + redis.servers.redis.enable = true; }; virtualisation.quadlet.enable = true; From dcf59faaf6413bb31eef9c7fb3f9324dc6de20cf Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 24 Feb 2026 10:59:48 -0600 Subject: [PATCH 092/149] feat: Add fireflyiii --- docker-compose.yaml | 136 ++++++++++++++++++++++++++++++ secrets.nix | 2 + secrets/fireflyiii.toml.age | Bin 0 -> 1230 bytes services/fireflyiii.nix | 162 ++++++++++++++++++++++++++++++++++++ systems/linux/mcentire.nix | 1 + 5 files changed, 301 insertions(+) create mode 100644 docker-compose.yaml create mode 100644 secrets/fireflyiii.toml.age create mode 100644 services/fireflyiii.nix diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..39e97af --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,136 @@ +networks: + fireflyiii: + +services: + fireflyiii-db: + image: "mariadb:10" + container_name: "fireflyiii-db" + restart: always + networks: + - fireflyiii + volumes: + - "/var/lib/fireflyiii/mysql:/var/lib/mysql" + healthcheck: + test: "healthcheck.sh --connect" + interval: 30s + timeout: 1s + retries: 10 + environment: + - "MYSQL_ROOT_PASSWORD=${FIREFLY_III_MYSQL_ROOT_PASSWORD}" + - "MYSQL_PASSWORD=${FIREFLY_III_MYSQL_PASSWORD}" + - "MYSQL_DATABASE=${FIREFLY_III_MYSQL_DB}" + - "MYSQL_USER=${FIREFLY_III_MYSQL_USER}" + + fireflyiii: + image: fireflyiii/core:version-6 + container_name: "fireflyiii" + restart: always + networks: + - web + - fireflyiii + - redis + volumes: + - "/var/fireflyiii:/var/www/html/storage/upload" + depends_on: + fireflyiii-db: + condition: service_healthy + redis: + condition: service_healthy + labels: + - "traefik.enable=true" + - "traefik.docker.network=traefik_proxy" + - "traefik.http.routers.fireflyiii.rule=Host(`money.millironx.com`)" + - "traefik.http.routers.fireflyiii.tls=true" + - "traefik.http.routers.fireflyiii.tls.certresolver=letsencrypt" + - "traefik.http.services.fireflyiii.loadbalancer.server.port=8080" + environment: + - APP_ENV=local + - SITE_OWNER=${ADMIN_EMAIL} + - APP_KEY=${FIREFLY_III_APP_KEY} + - DEFAULT_LANGUAGE=en_US + - TZ=America/New_York + - TRUSTED_PROXIES=* + - DB_CONNECTION=mysql + - DB_HOST=fireflyiii-db + - DB_PORT=3306 + - DB_DATABASE=${FIREFLY_III_MYSQL_DB} + - DB_USERNAME=${FIREFLY_III_MYSQL_USER} + - DB_PASSWORD=${FIREFLY_III_MYSQL_PASSWORD} + - CACHE_DRIVER=redis + - SESSION_DRIER=redis + - REDIS_SCHEME=tcp + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_USERNAME='' + - REDIS_PASSWORD=${REDIS_PASSWORD} + - REDIS_DB="0" + - REDIS_CACHE_DB="1" + - MAIL_MAILER=smtp + - MAIL_HOST=${NOREPLY_EMAIL_HOST} + - MAIL_PORT=${NOREPLY_EMAIL_PORT} + - MAIL_FROM=${NOREPLY_EMAIL} + - MAIL_USERNAME=${NOREPLY_EMAIL_USERNAME} + - MAIL_PASSWORD=${NOREPLY_EMAIL_PASSWORD} + - MAIL_ENCRYPTION=ssl + - APP_URL=https://money.millironx.com + - APP_LOG_LEVEL=debug + - STATIC_CRON_TOKEN=${FIREFLY_III_CRON_TOKEN} + + fireflyiii-importer: + image: fireflyiii/data-importer:version-1.5 + container_name: "fireflyiii-importer" + restart: always + networks: + - fireflyiii + - redis + - web + depends_on: + - fireflyiii + - redis + labels: + - "traefik.enable=true" + - "traefik.docker.network=traefik_proxy" + - "traefik.http.routers.fireflyiiiimport.rule=Host(`moneyimport.millironx.com`)" + - "traefik.http.routers.fireflyiiiimport.tls=true" + - "traefik.http.services.fireflyiiiimport.loadbalancer.server.port=8080" + environment: + FIREFLY_III_URL: http://fireflyiii:8080 + VANITY_URL: https://money.millironx.com + FIREFLY_III_ACCESS_TOKEN: ${FIREFLY_III_IMPORT_TOKEN} + AUTO_IMPORT_SECRET: ${FIREFLY_III_IMPORT_SECRET} + TRUSTED_PROXIES: "*" + TZ: America/New_York + MAIL_MAILER: smtp + MAIL_HOST: ${NOREPLY_EMAIL_HOST} + MAIL_PORT: ${NOREPLY_EMAIL_PORT} + MAIL_FROM: ${NOREPLY_EMAIL} + MAIL_USERNAME: ${NOREPLY_EMAIL_USERNAME} + MAIL_PASSWORD: ${NOREPLY_EMAIL_PASSWORD} + MAIL_ENCRYPTION: ssl + CACHE_DRIVER: redis + SESSION_DRIER: redis + REDIS_SCHEME: tcp + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_USERNAME: "" + REDIS_PASSWORD: ${REDIS_PASSWORD} + REDIS_DB: "0" + REDIS_CACHE_DB: "1" + + fireflyiii-cron: + image: alpine:latest + container_name: "fireflyiii-cron" + restart: always + networks: + - fireflyiii + depends_on: + - fireflyiii + command: sh -c " + apk add tzdata + && ln -s /usr/share/zoneinfo/$${TZ} /etc/localtime + | echo \"0 3 * * * wget -qO- http://fireflyiii:8080/api/v1/cron/$${CRON_TOKEN};echo\" + | crontab - + && crond -f -L /dev/stdout" + environment: + TZ: America/New_York + CRON_TOKEN: ${FIREFLY_III_CRON_TOKEN} diff --git a/secrets.nix b/secrets.nix index ce66958..7f4bd23 100644 --- a/secrets.nix +++ b/secrets.nix @@ -34,6 +34,8 @@ in { ++ [ mcentire-host ]; "secrets/darwin-policies-json.age".publicKeys = system-administrators ++ [ corianne-host ]; + "secrets/fireflyiii.toml.age".publicKeys = system-administrators + ++ [ mcentire-host ]; "secrets/freshrss.toml.age".publicKeys = system-administrators ++ [ mcentire-host ]; "secrets/millironx-books-s3.age".publicKeys = system-administrators diff --git a/secrets/fireflyiii.toml.age b/secrets/fireflyiii.toml.age new file mode 100644 index 0000000000000000000000000000000000000000..5a2630c52e5bfa8900ba88dee01f9c431a7b167d GIT binary patch literal 1230 zcmZY6>u(bU003|mR46KDz?i_a1Hyu5x$E`1_9PJdxa;+CZLg2DH%z40d-ZwkUDubH zP6*?@C;}2doWn5&;}OULhKF%MhhIeCG+a6=momAS zl%6HY0+`pTG;`I8B5F7m*6X#XI+oNW%aoeXYIzU@3Z`rw4#iv|Ti~40BBBTe)+H*u zEavJ{4P}6cLq-*ua?;Ky=Fg(}aIDehErGn*<#AIkt)6Bq&T@coq)Rz%8Lg*>Ygz#; z77FTwCs-c}W+N#NW=0b}Qjc3A!E($AHsp;+BI7qu9BnaL1HL$=N{B@ia+FbzHtRQ< zm=MCEa*UI*xYcV&z^LLt4KRqH;S^2{*I35M5d}5b81_l_B%*IfNi0rUf{c?*7f2M9 z#BfHz&7eKO<%?Dr^&u)4ht0lZBh3U*(U+7kuaStzInGa8>yvm3C?;)2f@9W6tKe=S=)w>+G+d z^-4?Djy+nvX6E_qkN@>b*Cg-n#SaTML$;zbt+^kyGz$U0StW)nbn{BQr-gwapJ(Y{%9; z`F`Y;<*T>%c*pfnul9ESb+zsFZ}#80oxAkKyVrrPrW3Q`om^ktZx=_csQ6=QB@*w3 z$vN8&cbuB>_BCwrggHkaPYWKrTR9!)VgtaRei&)ZIXa%>?7>^S#KWqAdy^dx RxcE=q@05nFk0BmT`44?y;2;11 literal 0 HcmV?d00001 diff --git a/services/fireflyiii.nix b/services/fireflyiii.nix new file mode 100644 index 0000000..704f4fc --- /dev/null +++ b/services/fireflyiii.nix @@ -0,0 +1,162 @@ +{ config, pkgs, home-manager-quadlet-nix, ... }: +let + user = "fireflyiii"; + port = "34733"; + containerPort = "8080"; + authentikPort = "9000"; + stateDirectory = "/var/lib/${user}"; + servicePaths = [ "upload" ]; + databasePaths = [ "database" ]; +in { + age.secrets."fireflyiii.toml" = { + file = ./../secrets/fireflyiii.toml.age; + owner = user; + }; + + millironx.podman-secrets.fireflyiii = { + inherit user; + secrets-files = [ config.age.secrets."fireflyiii.toml".path ]; + }; + + systemd.tmpfiles.rules = + map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") [ "" ] + ++ servicePaths ++ databasePaths; + + services.borgmatic.configurations."${config.networking.hostName}" = { + source_directories = map (d: "${stateDirectory}/${d}") servicePaths; + postgresql_databases = [{ + name = user; + psql_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db psql --username=${user}"; + pg_dump_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_dump --username=${user}"; + pg_restore_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_restore --username=${user}"; + }]; + }; + + services.caddy.virtualHosts."money.millironx.com".extraConfig = '' + reverse_proxy /outpost.goauthentik.io/* http://127.0.0.1:${authentikPort} + forward_auth http://127.0.0.1:${authentikPort} { + uri /outpost.goauthentik.io/auth/caddy + copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Entitlements X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version + } + reverse_proxy http://127.0.0.1:${port} + ''; + + users.users."${user}" = { + group = user; + isNormalUser = true; + home = stateDirectory; + createHome = true; + linger = true; + autoSubUidGidRange = true; + }; + users.groups."${user}" = { }; + + home-manager.users."${user}" = { config, osConfig, ... }: { + imports = [ home-manager-quadlet-nix ]; + + home.stateVersion = "25.05"; + + systemd.user = let inherit (config.virtualisation.quadlet) containers; + in { + services."${user}-cron" = { + Unit = { + Description = "Firefly III cron"; + Requires = [ containers."${user}".ref ]; + After = [ containers."${user}".ref ]; + }; + Service.ExecStart = + "${pkgs.podman}/bin/podman exec ${user} /usr/local/bin/php /var/www/html/artisan firefly-iii:cron"; + }; + timers."${user}-cron" = { + Unit.Description = "Firefly III cron"; + Timer.OnCalendar = "daily"; + }; + }; + + virtualisation.quadlet = let + inherit (config.virtualisation.quadlet) containers; + inherit (config.virtualisation.quadlet) networks; + secrets = osConfig.millironx.podman-secrets.freshrss; + in { + autoUpdate.enable = true; + autoEscape = true; + + networks."${user}" = { }; + + containers = { + "${user}-db" = { + autoStart = true; + containerConfig = { + image = "docker.io/library/postgres:16"; + environments = { + POSTGRES_DB = user; + POSTGRES_USER = user; + }; + secrets = [ + "POSTGRES_PASSWORD,type=env" + "POSTGRES_PASSWORD,type=env,target=PGPASSWORD" + ]; + healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"; + healthInterval = "30s"; + healthRetries = 5; + healthStartPeriod = "20s"; + volumes = + [ "${stateDirectory}/database:/var/lib/postgresql/data:U" ]; + networks = [ networks."${user}".ref ]; + }; + unitConfig.Requires = [ secrets.ref ]; + unitConfig.After = [ secrets.ref ]; + }; + + "${user}" = { + autoStart = true; + containerConfig = { + image = "docker.io/fireflyiii/core:version-6"; + environments = { + APP_ENV = "local"; + DEFAULT_LANGUAGE = "en_US"; + TZ = "America/New_York"; + TRUSTED_PROXIES = "*"; + DB_CONNECTION = "pgsql"; + DB_HOST = "${user}-db"; + DB_PORT = "5432"; + DB_DATABASE = user; + DB_USERNAME = user; + CACHE_DRIVER = "redis"; + SESSION_DRIVER = "redis"; + REDIS_SCHEME = "tcp"; + REDIS_HOST = "host.docker.internal"; + REDIS_PORT = "6379"; + REDIS_DB = "0"; + REDIS_CACHE_DB = "1"; + MAIL_MAILER = "smtp"; + APP_URL = "https://money.millironx.com"; + AUTHENTICATION_GUARD = "remote_user_guard"; + AUTHENTICATION_GUARD_HEADER = "HTTP_X_AUTHENTIK_USERNAME"; + AUTHENTICATION_GUARD_EMAIL = "HTTP_X_AUTHENTIK_EMAIL"; + }; + secrets = map (s: "${s},type=env") [ + "SITE_OWNER" + "APP_KEY" + "DB_PASSWORD" + "MAIL_HOST" + "MAIL_PORT" + "MAIL_FROM" + "MAIL_USERNAME" + "MAIL_PASSWORD" + "MAIL_ENCRYPTION" + ]; + volumes = [ "${stateDirectory}/upload:/var/html/storage/upload:U" ]; + networks = [ networks."${user}".ref ]; + publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; + }; + unitConfig.Requires = [ secrets.ref containers."${user}".ref ]; + unitConfig.After = [ secrets.ref containers."${user}".ref ]; + }; + }; + }; + }; +} diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 5d80ada..5861114 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -8,6 +8,7 @@ ./../../services/crowdsec.nix ./../../services/authentik.nix ./../../services/audiobookshelf.nix + ./../../services/fireflyiii.nix ./../../services/freshrss.nix ./../../services/navidrome.nix ]; From 63ceb8af21023f67e44144833c996d4161c5d2a8 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 24 Feb 2026 11:19:20 -0600 Subject: [PATCH 093/149] fix: fireflyiii file creation --- services/fireflyiii.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/fireflyiii.nix b/services/fireflyiii.nix index 704f4fc..b8a859d 100644 --- a/services/fireflyiii.nix +++ b/services/fireflyiii.nix @@ -19,8 +19,8 @@ in { }; systemd.tmpfiles.rules = - map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") [ "" ] - ++ servicePaths ++ databasePaths; + map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") + ([ "" ] ++ servicePaths ++ databasePaths); services.borgmatic.configurations."${config.networking.hostName}" = { source_directories = map (d: "${stateDirectory}/${d}") servicePaths; From c95f57360277d748a0cf23416cb3c7c28bc76169 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 24 Feb 2026 11:24:33 -0600 Subject: [PATCH 094/149] fix: Remove temp docker-compose file --- docker-compose.yaml | 136 -------------------------------------------- 1 file changed, 136 deletions(-) delete mode 100644 docker-compose.yaml diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index 39e97af..0000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,136 +0,0 @@ -networks: - fireflyiii: - -services: - fireflyiii-db: - image: "mariadb:10" - container_name: "fireflyiii-db" - restart: always - networks: - - fireflyiii - volumes: - - "/var/lib/fireflyiii/mysql:/var/lib/mysql" - healthcheck: - test: "healthcheck.sh --connect" - interval: 30s - timeout: 1s - retries: 10 - environment: - - "MYSQL_ROOT_PASSWORD=${FIREFLY_III_MYSQL_ROOT_PASSWORD}" - - "MYSQL_PASSWORD=${FIREFLY_III_MYSQL_PASSWORD}" - - "MYSQL_DATABASE=${FIREFLY_III_MYSQL_DB}" - - "MYSQL_USER=${FIREFLY_III_MYSQL_USER}" - - fireflyiii: - image: fireflyiii/core:version-6 - container_name: "fireflyiii" - restart: always - networks: - - web - - fireflyiii - - redis - volumes: - - "/var/fireflyiii:/var/www/html/storage/upload" - depends_on: - fireflyiii-db: - condition: service_healthy - redis: - condition: service_healthy - labels: - - "traefik.enable=true" - - "traefik.docker.network=traefik_proxy" - - "traefik.http.routers.fireflyiii.rule=Host(`money.millironx.com`)" - - "traefik.http.routers.fireflyiii.tls=true" - - "traefik.http.routers.fireflyiii.tls.certresolver=letsencrypt" - - "traefik.http.services.fireflyiii.loadbalancer.server.port=8080" - environment: - - APP_ENV=local - - SITE_OWNER=${ADMIN_EMAIL} - - APP_KEY=${FIREFLY_III_APP_KEY} - - DEFAULT_LANGUAGE=en_US - - TZ=America/New_York - - TRUSTED_PROXIES=* - - DB_CONNECTION=mysql - - DB_HOST=fireflyiii-db - - DB_PORT=3306 - - DB_DATABASE=${FIREFLY_III_MYSQL_DB} - - DB_USERNAME=${FIREFLY_III_MYSQL_USER} - - DB_PASSWORD=${FIREFLY_III_MYSQL_PASSWORD} - - CACHE_DRIVER=redis - - SESSION_DRIER=redis - - REDIS_SCHEME=tcp - - REDIS_HOST=redis - - REDIS_PORT=6379 - - REDIS_USERNAME='' - - REDIS_PASSWORD=${REDIS_PASSWORD} - - REDIS_DB="0" - - REDIS_CACHE_DB="1" - - MAIL_MAILER=smtp - - MAIL_HOST=${NOREPLY_EMAIL_HOST} - - MAIL_PORT=${NOREPLY_EMAIL_PORT} - - MAIL_FROM=${NOREPLY_EMAIL} - - MAIL_USERNAME=${NOREPLY_EMAIL_USERNAME} - - MAIL_PASSWORD=${NOREPLY_EMAIL_PASSWORD} - - MAIL_ENCRYPTION=ssl - - APP_URL=https://money.millironx.com - - APP_LOG_LEVEL=debug - - STATIC_CRON_TOKEN=${FIREFLY_III_CRON_TOKEN} - - fireflyiii-importer: - image: fireflyiii/data-importer:version-1.5 - container_name: "fireflyiii-importer" - restart: always - networks: - - fireflyiii - - redis - - web - depends_on: - - fireflyiii - - redis - labels: - - "traefik.enable=true" - - "traefik.docker.network=traefik_proxy" - - "traefik.http.routers.fireflyiiiimport.rule=Host(`moneyimport.millironx.com`)" - - "traefik.http.routers.fireflyiiiimport.tls=true" - - "traefik.http.services.fireflyiiiimport.loadbalancer.server.port=8080" - environment: - FIREFLY_III_URL: http://fireflyiii:8080 - VANITY_URL: https://money.millironx.com - FIREFLY_III_ACCESS_TOKEN: ${FIREFLY_III_IMPORT_TOKEN} - AUTO_IMPORT_SECRET: ${FIREFLY_III_IMPORT_SECRET} - TRUSTED_PROXIES: "*" - TZ: America/New_York - MAIL_MAILER: smtp - MAIL_HOST: ${NOREPLY_EMAIL_HOST} - MAIL_PORT: ${NOREPLY_EMAIL_PORT} - MAIL_FROM: ${NOREPLY_EMAIL} - MAIL_USERNAME: ${NOREPLY_EMAIL_USERNAME} - MAIL_PASSWORD: ${NOREPLY_EMAIL_PASSWORD} - MAIL_ENCRYPTION: ssl - CACHE_DRIVER: redis - SESSION_DRIER: redis - REDIS_SCHEME: tcp - REDIS_HOST: redis - REDIS_PORT: 6379 - REDIS_USERNAME: "" - REDIS_PASSWORD: ${REDIS_PASSWORD} - REDIS_DB: "0" - REDIS_CACHE_DB: "1" - - fireflyiii-cron: - image: alpine:latest - container_name: "fireflyiii-cron" - restart: always - networks: - - fireflyiii - depends_on: - - fireflyiii - command: sh -c " - apk add tzdata - && ln -s /usr/share/zoneinfo/$${TZ} /etc/localtime - | echo \"0 3 * * * wget -qO- http://fireflyiii:8080/api/v1/cron/$${CRON_TOKEN};echo\" - | crontab - - && crond -f -L /dev/stdout" - environment: - TZ: America/New_York - CRON_TOKEN: ${FIREFLY_III_CRON_TOKEN} From 5b4c5ada790a9512ddb26231a5dc8c4c2f6a5ed9 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 24 Feb 2026 19:20:12 -0600 Subject: [PATCH 095/149] fix: Redis config --- secrets.nix | 2 ++ secrets/fireflyiii.toml.age | Bin 1230 -> 1298 bytes secrets/redis-password.age | 15 +++++++++++++++ services/fireflyiii.nix | 1 + systems/linux/mcentire.nix | 16 +++++++++++++++- 5 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 secrets/redis-password.age diff --git a/secrets.nix b/secrets.nix index 7f4bd23..d6effcc 100644 --- a/secrets.nix +++ b/secrets.nix @@ -46,4 +46,6 @@ in { ++ [ mcentire-host ]; "secrets/network-information.age".publicKeys = system-administrators ++ [ bosephus-host ]; + "secrets/redis-password.age".publicKeys = system-administrators + ++ [ mcentire-host ]; } diff --git a/secrets/fireflyiii.toml.age b/secrets/fireflyiii.toml.age index 5a2630c52e5bfa8900ba88dee01f9c431a7b167d..8d57f14040deb5047bdf6f926e63b694a2ed5d26 100644 GIT binary patch delta 1213 zcmZ9}S#uKw003ZGt`Y{BmO?2-nhsX5X(pRyHwP3Xn`E=u9NXN-P+&LrvE5`h?Iw{D zoKitKY-JD-ELaALEz&_44wVt)Xh8vsVD*6kltN`dEUjjSOW*ze!gqDbN4&P`ER%%I z8MVyeWg$RL5k}S@jd2c5ogtP;C5<0}^kb%sdKETH`98q@mH{0|QpT-Xw0c z2pR%@ou6c277c=RtjMYehLuX5a4DZsr-FnI0~oIiM&lBX*n}Ic5sm@{ zl$pbWji8%uA1QHq>_JrQZ^Bp=sge08xdIV~<7$%@Nze?C0^}MSM$#yR#A@t3M~0I+ zB9PP0x)>@A`baOPg$Yr{Ee%U3g^2-z{s?YDAiyc#x-zfCsb~^lltAmp)G7m`AoMgE zRo6jMr9LUJNI)WC3gIGg!pOo79S_Carldh;(^=^nsmYNv!ZgW2A_TT!I#%aWGxiLM z(y2rWvv0kUSCW;AK`V#H97crZKpgNX-9CpR!=loKzo0DJ&qIN>~ILSZ4`VTG{x z>}`Xqch1eH^;H9lrnkuY$Mtqkn^^Cqj!s;CE4SXZBRcEV%v)rhJ||f~zN{SKCtUZS zX$Karn7M_=rkeL_!P;xSCG|I^fBoP%CTTt6`$2aWQR#5dHWJTwU delta 1144 zcmZY63vUwz003YSR8~~XfNcWP4hRb#sdMAO{$6c?F>$|(&FoE9guGiU}dZjF;?^r*q(3ON;FF^fUwJZ4uV+^CkN5e`cRc_~2{9GWnU$!1Ig zg9zq}63%sxN@=RW=aNhjL|qq^ID*o9Sqm4-P#7kOzPL>2KvS4cXALmsLKH9o>s*lr zhV@{gDO)QH0R?VBXHVHLxr@a*V?7rqd1(Hae@L zff&t(>XV`l2RIH-+LMUgrLRxbP+Bd+3-bR406j#z0!llX4@TuQN6NWOAR=VM0vSUA z2jqcdLWfq-8kVKi84kBNva zRgEjEs;ZO(1qsebibewnV@XqCTyomgT+XX8yQ~JQ7|B{2Y`K_~h@)D?4uAQz%W8I@ zu=BSl=C>=tpo}6!qmK-$GXnW{NN_OY|^|F&!&5iJSdq# z2p5%b@`7~w>d!k*e|Dv_YEIh@q3!VGns3LNf#|6VR#SU;edW`N@4M%|zC}N+|C(v< zl>Wgz^!38xitL-J1FOs0X9ljk9Gp13`KSipR&l8-0WEf)y)g~^tlo3ed3URNcT@Sj3BYKobEtFK-A4YHzFE-BN5*xBR{k?A&M0^Hv~23stz^XjKA=4=y>@%!<0QKX_AGB6+TKy}=~s=@ z-X7X;4ljRHTp<~c8itOSoV2&N{Rc~ZtIiBgsXj7tbkmvbJ+|EoUO8V9X#$vQ!*l;# v+sdxKr{3AQkz3=)CsY3eIKj!e diff --git a/secrets/redis-password.age b/secrets/redis-password.age new file mode 100644 index 0000000..6731da7 --- /dev/null +++ b/secrets/redis-password.age @@ -0,0 +1,15 @@ +age-encryption.org/v1 +-> ssh-ed25519 il3lzQ 9+/0+lCYWH9ibqY7J0OWz4fyTJYNvjwVEQQgByg8eXo +DmqfjZYNCggmNwez+H0lNUmTuBUmlfOy9BMdo/mP1Ro +-> ssh-ed25519 1g/xww 3v7NGaDyYM/Na5DTgbpv7DtVg6mqsgqd0xU7NmcDlTk +7Z8yymlYYx3fO8CNMcosa6hLAZ7rlkDA6qPat2IWsS0 +-> ssh-ed25519 dbKeHw WlHTnJR3TyAuYm5NG+8WMXmeB3YUydDJ61SrWKMcByg +k5dwVAuUKNjFeCY7/L28Kx0ZHBiPUxndEQp1UyOPxIY +-> ssh-ed25519 3qPtug YU9PSuEkJElN4EOFQTrXBrRB/3g/MzSbLEU5mWIl6CA +HBFN2uTQo0tr8cnJ2okFibZXVouaCy6WCq0+YK2jSYI +-> ssh-ed25519 FRQvIA ufWjt9KuGr9Wx0kRbMK3WapeyOM9dnuy8nRpa9LcElY +WGB7xIuZOEGNlycHAlg3sE1W766/rMZGIb17VL54uYs +-> ssh-ed25519 +C0WRg 9jXj4AKdCK5RdQOOmDFu9/RapWvQQ6MieaHO7m/wKSc +vkdJWxmBtjmLQXq1tvM+sAXAOKbJmTdM7klyiW1xW2g +--- lEbO55yAuhIUejggLmlQ9UAZdw8DQVC+2EZ6Qs0Vn9Y +8/W"FJ[D<(O9;ljpM^ҷ/I|9*x@ɪEa:K*~ \ No newline at end of file diff --git a/services/fireflyiii.nix b/services/fireflyiii.nix index b8a859d..6cd0ea0 100644 --- a/services/fireflyiii.nix +++ b/services/fireflyiii.nix @@ -148,6 +148,7 @@ in { "MAIL_USERNAME" "MAIL_PASSWORD" "MAIL_ENCRYPTION" + "REDIS_PASSWORD" ]; volumes = [ "${stateDirectory}/upload:/var/html/storage/upload:U" ]; networks = [ networks."${user}".ref ]; diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 5861114..94c4bd6 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -58,6 +58,11 @@ environment.systemPackages = with pkgs; [ neovim inetutils mtr sysstat git ]; + age.secrets.redis-password = { + file = ./../../secrets/redis-password.age; + owner = config.services.redis.servers.redis.user; + }; + services = { openssh.enable = true; tailscale.enable = true; @@ -67,7 +72,16 @@ # so that borgmatic does not freak out about unset variables postgresql.package = pkgs.postgresql_17; - redis.servers.redis.enable = true; + redis.servers.redis = { + enable = true; + # Apparently, a port is actually required, see + # + # Evaluating this in the Nix repl confirms that the port is set + # incorrectly in the final config when left out + port = 6379; + bind = "0.0.0.0"; + requirePassFile = config.age.secrets.redis-password.path; + }; }; virtualisation.quadlet.enable = true; From 5c6324245310c1274e344531c1a8f60931b743d0 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 26 Feb 2026 12:34:05 -0600 Subject: [PATCH 096/149] fix: fireflyiii api access --- services/fireflyiii.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/fireflyiii.nix b/services/fireflyiii.nix index 6cd0ea0..cbeeca8 100644 --- a/services/fireflyiii.nix +++ b/services/fireflyiii.nix @@ -37,7 +37,8 @@ in { services.caddy.virtualHosts."money.millironx.com".extraConfig = '' reverse_proxy /outpost.goauthentik.io/* http://127.0.0.1:${authentikPort} - forward_auth http://127.0.0.1:${authentikPort} { + @proteched not path /oauth/* /api/* + forward_auth @protected http://127.0.0.1:${authentikPort} { uri /outpost.goauthentik.io/auth/caddy copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Entitlements X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version } From 24b19d280345a74eccfe51294a20ca25020690b2 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 26 Feb 2026 12:40:19 -0600 Subject: [PATCH 097/149] fix: fireflyiii api proxy typo --- services/fireflyiii.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/fireflyiii.nix b/services/fireflyiii.nix index cbeeca8..4d2f24d 100644 --- a/services/fireflyiii.nix +++ b/services/fireflyiii.nix @@ -37,7 +37,7 @@ in { services.caddy.virtualHosts."money.millironx.com".extraConfig = '' reverse_proxy /outpost.goauthentik.io/* http://127.0.0.1:${authentikPort} - @proteched not path /oauth/* /api/* + @protected not path /oauth/* /api/* forward_auth @protected http://127.0.0.1:${authentikPort} { uri /outpost.goauthentik.io/auth/caddy copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Entitlements X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version From df95ee500c358ab8eef27d1ce308b33aeb0d37f2 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 4 Mar 2026 08:59:57 -0600 Subject: [PATCH 098/149] chore: Upgrade Authentik to 2025.12 --- services/authentik.nix | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/services/authentik.nix b/services/authentik.nix index f507dac..b283bd0 100644 --- a/services/authentik.nix +++ b/services/authentik.nix @@ -24,6 +24,7 @@ in { systemd.tmpfiles.rules = [ "d ${state-directory} 1775 ${user} ${user} -" "d ${state-directory}/database 1775 ${user} ${user} -" + "d ${state-directory}/data 1775 ${user} ${user} -" "d ${state-directory}/media 1775 ${user} ${user} -" "d ${state-directory}/certs 1775 ${user} ${user} -" "d ${state-directory}/custom-templates 1775 ${user} ${user} -" @@ -35,6 +36,7 @@ in { services.borgmatic.configurations."${config.networking.hostName}" = { source_directories = [ + "${state-directory}/data" "${state-directory}/media" "${state-directory}/certs" "${state-directory}/custom-templates" @@ -131,7 +133,7 @@ in { authentik-worker = { autoStart = true; containerConfig = { - image = "ghcr.io/goauthentik/server:2025.10.2"; + image = "ghcr.io/goauthentik/server:2025.12"; environments = { AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; AUTHENTIK_POSTGRESQL__NAME = "${user}"; @@ -143,7 +145,10 @@ in { "AUTHENTIK_SECRET_KEY,type=env" ]; volumes = [ - "${state-directory}/media:/media:U" + # Remount media folder into new location based on + # + "${state-directory}/data:/data:U" + "${state-directory}/media:/data/media:U" "${state-directory}/custom-templates:/templates:U" "${state-directory}/certs:/certs:U" ]; @@ -159,7 +164,7 @@ in { authentik = { autoStart = true; containerConfig = { - image = "ghcr.io/goauthentik/server:2025.10.2"; + image = "ghcr.io/goauthentik/server:2025.12"; environments = { AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; AUTHENTIK_POSTGRESQL__NAME = "${user}"; From 02721bb173bb49981c641cc37c826b5c661ed98c Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 4 Mar 2026 09:06:24 -0600 Subject: [PATCH 099/149] fix: git ssh command --- programs/git.nix | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/programs/git.nix b/programs/git.nix index 244e916..89064e0 100644 --- a/programs/git.nix +++ b/programs/git.nix @@ -6,7 +6,11 @@ name = "Thomas A. Christensen II"; email = "25492070+MillironX@users.noreply.github.com"; }; - core = { editor = "nvim"; }; + core = { + editor = "nvim"; + # git push/pull via ssh over ipv6 is slow, so force ipv4 instead + sshCommand = "ssh -4"; + }; credential = { helper = "store"; }; color = { ui = "auto"; }; init = { defaultBranch = "master"; }; From 4348303e87e41c1f2d5b165970e2d17f675cf467 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 4 Mar 2026 09:15:05 -0600 Subject: [PATCH 100/149] refactor: Move Julia development packages to desktops only --- homes/common.nix | 6 +----- homes/desktop.nix | 2 ++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/homes/common.nix b/homes/common.nix index 78d70a0..e652bfb 100644 --- a/homes/common.nix +++ b/homes/common.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, pkgs-unstable, custom-pkgs, ... }: { +{ config, pkgs, ... }: { imports = [ ./../programs/shells.nix ./../programs/bat.nix @@ -28,14 +28,10 @@ lynx mamba-cpp most - nextflow p7zip pdfgrep pipx python3 - zulu17 - custom-pkgs.jlfmt - custom-pkgs.runic ]; sessionVariables = { PAGER = "most"; diff --git a/homes/desktop.nix b/homes/desktop.nix index 255db78..4ca1e6c 100644 --- a/homes/desktop.nix +++ b/homes/desktop.nix @@ -30,6 +30,8 @@ woodpecker-cli (texlive.combine { inherit (texlive) scheme-basic latex-bin latexmk; }) custom-pkgs.ark + custom-pkgs.jlfmt + custom-pkgs.runic ]; shellAliases = { code = "codium"; From 355601fe24f5057e30d2dc2ce43b3794f32e6045 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 4 Mar 2026 09:24:10 -0600 Subject: [PATCH 101/149] chore: Upgrade Authentik to 2026.2 --- services/authentik.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/authentik.nix b/services/authentik.nix index b283bd0..b6caf43 100644 --- a/services/authentik.nix +++ b/services/authentik.nix @@ -133,7 +133,7 @@ in { authentik-worker = { autoStart = true; containerConfig = { - image = "ghcr.io/goauthentik/server:2025.12"; + image = "ghcr.io/goauthentik/server:2026.2"; environments = { AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; AUTHENTIK_POSTGRESQL__NAME = "${user}"; @@ -164,7 +164,7 @@ in { authentik = { autoStart = true; containerConfig = { - image = "ghcr.io/goauthentik/server:2025.12"; + image = "ghcr.io/goauthentik/server:2026.2"; environments = { AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; AUTHENTIK_POSTGRESQL__NAME = "${user}"; From c0555b6b75468be7216f04dda41f5c940318ede6 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 6 Mar 2026 00:29:06 -0600 Subject: [PATCH 102/149] nix (corianne): only run gc every 90d --- systems/darwin/corianne.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index a029992..86a1c0a 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -32,7 +32,7 @@ in { automatic = true; interval = { Weekday = 1; }; options = '' - --delete-older-than 14d + --delete-older-than 90d ''; }; # Needed for rosetta-builder, see From b81a8f1e721f1f68846411afc95a57d935c2fd9f Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 8 Mar 2026 23:51:33 -0500 Subject: [PATCH 103/149] fix: Revert to prebuilt julia-bin in nixpkgs-darwin --- flake.lock | 50 +++++++++++++++++++++++++------------------------- flake.nix | 4 +++- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/flake.lock b/flake.lock index 5ffff1e..43c20a6 100644 --- a/flake.lock +++ b/flake.lock @@ -55,11 +55,11 @@ ] }, "locked": { - "lastModified": 1770260404, - "narHash": "sha256-3iVX1+7YUIt23hBx1WZsUllhbmP2EnXrV8tCRbLxHc8=", + "lastModified": 1772985280, + "narHash": "sha256-FdrNykOoY9VStevU4zjSUdvsL9SzJTcXt4omdEDZDLk=", "owner": "nix-community", "repo": "home-manager", - "rev": "0d782ee42c86b196acff08acfbf41bb7d13eed5b", + "rev": "8f736f007139d7f70752657dff6a401a585d6cbc", "type": "github" }, "original": { @@ -76,11 +76,11 @@ ] }, "locked": { - "lastModified": 1767634391, - "narHash": "sha256-owcSz2ICqTSvhBbhPP+1eWzi88e54rRZtfCNE5E/wwg=", + "lastModified": 1772129556, + "narHash": "sha256-Utk0zd8STPsUJPyjabhzPc5BpPodLTXrwkpXBHYnpeg=", "owner": "LnL7", "repo": "nix-darwin", - "rev": "08585aacc3d6d6c280a02da195fdbd4b9cf083c2", + "rev": "ebec37af18215214173c98cf6356d0aca24a2585", "type": "github" }, "original": { @@ -112,11 +112,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1771208521, - "narHash": "sha256-X01Q3DgSpjeBpapoGA4rzKOn25qdKxbPnxHeMLNoHTU=", + "lastModified": 1772822230, + "narHash": "sha256-yf3iYLGbGVlIthlQIk5/4/EQDZNNEmuqKZkQssMljuw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "fa56d7d6de78f5a7f997b0ea2bc6efd5868ad9e8", + "rev": "71caefce12ba78d84fe618cf61644dce01cf3a96", "type": "github" }, "original": { @@ -128,27 +128,27 @@ }, "nixpkgs-darwin": { "locked": { - "lastModified": 1771352457, - "narHash": "sha256-CCItBNMyLmtWqxTVaDAeeaIigbuaiZuN3WO8PZNkGBc=", + "lastModified": 1766129819, + "narHash": "sha256-crNRwvsbH2XSV8IwBjX6Tm+uWmYwhYyRuNVJ9/ZwlmA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "f8a68d8ce473ec59300d9fb510a1b545c1290939", + "rev": "eedcb27bf99430e51f83d896cd1149b828290d20", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixpkgs-25.11-darwin", "repo": "nixpkgs", + "rev": "eedcb27bf99430e51f83d896cd1149b828290d20", "type": "github" } }, "nixpkgs-unstable": { "locked": { - "lastModified": 1771177547, - "narHash": "sha256-trTtk3WTOHz7hSw89xIIvahkgoFJYQ0G43IlqprFoMA=", + "lastModified": 1772771118, + "narHash": "sha256-xWzaTvmmACR/SRWtABgI/Z97lcqwJAeoSd5QW1KdK1s=", "owner": "nixos", "repo": "nixpkgs", - "rev": "ac055f38c798b0d87695240c7b761b82fc7e5bc2", + "rev": "e38213b91d3786389a446dfce4ff5a8aaf6012f2", "type": "github" }, "original": { @@ -166,11 +166,11 @@ ] }, "locked": { - "lastModified": 1771425294, - "narHash": "sha256-owiQE9oINf1cgaulbrr2sMjelk2cmR8rkxLRPYYL6Kg=", + "lastModified": 1773029295, + "narHash": "sha256-xmHhVHbaA5hR3dCEoGwqAgL6HTTJ0KEMRUTLdJuVtGM=", "owner": "nix-community", "repo": "NUR", - "rev": "242d44cd6af365da2dfa77422263b29d0ac9f39f", + "rev": "bf45b24de2134f1488f7a6c135f4b0420ccec6fe", "type": "github" }, "original": { @@ -189,11 +189,11 @@ ] }, "locked": { - "lastModified": 1770766818, - "narHash": "sha256-12RCFLyAedyMOdenUi7cN3ioJPEGjA/ZG1BLjugfUVs=", + "lastModified": 1772361940, + "narHash": "sha256-B1Cz+ydL1iaOnGlwOFld/C8lBECPtzhiy/pP93/CuyY=", "owner": "nix-community", "repo": "plasma-manager", - "rev": "44b928068359b7d2310a34de39555c63c93a2c90", + "rev": "a4b33606111c9c5dcd10009042bb710307174f51", "type": "github" }, "original": { @@ -240,11 +240,11 @@ }, "locked": { "dir": "pkgs/firefox-addons", - "lastModified": 1771301023, - "narHash": "sha256-0XauSmXBLOqn8SYHRWOL7Z9O7m5qtF0Yw6rqXVHkEnw=", + "lastModified": 1773028978, + "narHash": "sha256-4BjOTYhHP8ljHShQyZ1gUIdwgSLjvaGN2ueKfqp6CQk=", "owner": "rycee", "repo": "nur-expressions", - "rev": "1cf8b4f42720573ef35dcd7d2ba0fd80e40954e9", + "rev": "a6ed037ffc0b50a9bd0c92e20e31f270a03ca1e3", "type": "gitlab" }, "original": { diff --git a/flake.nix b/flake.nix index 3b4f7b7..21bbcca 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,9 @@ inputs = { # Specify the source of Home Manager and Nixpkgs. nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11"; - nixpkgs-darwin.url = "github:nixos/nixpkgs/nixpkgs-25.11-darwin"; + # Revert to a cached version of Julia for aarch64-darwin + nixpkgs-darwin.url = + "github:nixos/nixpkgs/eedcb27bf99430e51f83d896cd1149b828290d20"; nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable"; # Inputs for both darwin and linux systems From e693e4c4c325d2203d658d6aeecfabd596cf9877 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 8 Mar 2026 23:52:08 -0500 Subject: [PATCH 104/149] nix (corianne): add cachix binary cache --- systems/darwin/corianne.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index 86a1c0a..ce15646 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -35,6 +35,14 @@ in { --delete-older-than 90d ''; }; + settings = { + substituters = + [ "https://nix-community.cachix.org" "https://cache.nixos.org/" ]; + trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + ]; + }; + # Needed for rosetta-builder, see # # From 847da998eecc34eb302b0da2fa52e7b265776a9d Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 8 Mar 2026 23:52:44 -0500 Subject: [PATCH 105/149] brew (corianne): Remove deprecated taps --- systems/darwin/corianne.nix | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index ce15646..786353c 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -192,15 +192,7 @@ in { no_quarantine = true; }; - taps = [ - "homebrew/services" - { - name = "millironx/millironx"; - clone_target = - "https://code.millironx.com/millironx/homebrew-millironx.git"; - } - "r-lib/rig" - ]; + taps = [ "r-lib/rig" ]; brews = [ "borgbackup/tap/borgbackup-fuse" "buildkit" From cf14f71bba0f40cde0826895fd191b136e8ec9c6 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 8 Mar 2026 23:53:02 -0500 Subject: [PATCH 106/149] brew (corianne): Add dash cask --- systems/darwin/corianne.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/systems/darwin/corianne.nix b/systems/darwin/corianne.nix index 786353c..40d240b 100644 --- a/systems/darwin/corianne.nix +++ b/systems/darwin/corianne.nix @@ -207,6 +207,7 @@ in { ]; casks = [ "alt-tab" + "dash" "db-browser-for-sqlite" "firefox" "inkscape" From 99f1ed322e1a3ff5531bd50a641334b464c2d17b Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 8 Mar 2026 23:54:44 -0500 Subject: [PATCH 107/149] config (zed): add nixd home-manager integration --- programs/zed.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/programs/zed.nix b/programs/zed.nix index 8b4fc69..1aceb66 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -59,6 +59,10 @@ }; lsp = { nil = { settings.nix.flake.autoArchive = true; }; + nixd = { + settings.options.home-manager.expr = + "(builtins.getFlake (builtins.toString ./.)).homeConfigurations..options"; + }; texlab = { settings = { build = { From 6a575d7cb5fb58f5fec28d0143ca6202200946ad Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 19 Mar 2026 09:12:05 -0500 Subject: [PATCH 108/149] fix (fireflyiii): Correct secrets service --- services/fireflyiii.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/fireflyiii.nix b/services/fireflyiii.nix index 4d2f24d..5174cc2 100644 --- a/services/fireflyiii.nix +++ b/services/fireflyiii.nix @@ -80,7 +80,7 @@ in { virtualisation.quadlet = let inherit (config.virtualisation.quadlet) containers; inherit (config.virtualisation.quadlet) networks; - secrets = osConfig.millironx.podman-secrets.freshrss; + secrets = osConfig.millironx.podman-secrets.fireflyiii; in { autoUpdate.enable = true; autoEscape = true; From 10652a8f4cc05e79365ec5d4cfccd485934dc734 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 19 Mar 2026 10:46:33 -0500 Subject: [PATCH 109/149] feat (mcentire): add Vaultwarden service --- secrets.nix | 2 + secrets/vaultwarden.toml.age | Bin 0 -> 1341 bytes services/vaultwarden.nix | 125 +++++++++++++++++++++++++++++++++++ systems/linux/mcentire.nix | 1 + 4 files changed, 128 insertions(+) create mode 100644 secrets/vaultwarden.toml.age create mode 100644 services/vaultwarden.nix diff --git a/secrets.nix b/secrets.nix index d6effcc..667dd30 100644 --- a/secrets.nix +++ b/secrets.nix @@ -48,4 +48,6 @@ in { ++ [ bosephus-host ]; "secrets/redis-password.age".publicKeys = system-administrators ++ [ mcentire-host ]; + "secrets/vaultwarden.toml.age".publicKeys = system-administrators + ++ [ mcentire-host ]; } diff --git a/secrets/vaultwarden.toml.age b/secrets/vaultwarden.toml.age new file mode 100644 index 0000000000000000000000000000000000000000..b60bcd255207f7df221fe8e394113d5ecc77114d GIT binary patch literal 1341 zcmZ9}SyK}S003ZHJ5!8Bt)o<`g-B75hzU726k(QRb8M2$Cgj?*sJV8-W|JkyZVp=Q z6mSX@t7vtgwQ4=aW2}Nsy+`o2+Hs~RB8XPy>Y=t?Ee>PbXMVx=@VN+Ip)cf#B&%ap zbZ7}3A^2<&r?8Y8jrt3HUZF%%Bj zN-S8y>BpQry9UD529ARf*@S9{k)w7SPa$VaAZ^7-eM)2I5jcaAF{6|WM#8KbFig~n z2!0|S=SDQuj(|u-8{H(t*bRxWn>L2UZdPV;(a{K24O?N4+@uM{RVI!ZVUv7Wz$zB; z*&va!VP+?-h#?h#ljjjrn9OJpg)Ms84jDZYHLqLe)5N(*FdW4|F{`0qXE;u|6{@H@ zk4GhUbm=0u; zkpLQ>sENX8j3Kz7M+o@5lJasK)_^FVBxpcM=)yD-6X+rpN`6!z7n3rzpEj8|)nL$P z7LpE0RLV~g5GGUOMOv%DuCc%%qw|WRVqsVsz(dulz(h@DHnCceE28}*--@Ih78#`! zfDR#SlXGNr*4^)MO5JzkD$JvP4X;3;apO(kyOcoCjDHmHoC;(Xy z3P@VLP8Lon1%inhPa&|I39dwrdW}IZYK*wCl-~i#5T7hj5w*k!7z;_YF1AWa>iyD) zOo?$cm;@2Z;#vV_vEiyXjL>4(06~<}WY#Bi2;YK6bwM0K0_6~=u&|JeMRXoFDKx7= zZ8b_sfDrER09qksHN*c;$SW{BtOj*4HS7~}8qXWQb#3n${j5N`QPB5Y`kZ3ntm_$y z9ealDJ45)s!j(wH&j2EOx$URKRlwU|8)TA!)L3G{?k*~C*ACl?HNT$RHdJ4ew>>xK z{FU9jDaw*5xxbegGI%<1F3;%qwb<*kjoYL;H^hNiVS;|Z|rk`u7vdbF}Czj^lyxi2@ z&FSbL$_{;b_G#tsS6|;SCYjs38p>KfUHKk*sC|CR=7EB>&5BJQm3W|DV`k;sU*Ej) zeOvuKQO#P(ythR2CzT4)Mrx0RJ4aK^$EP$bJ#qP7NB5gF@l2o_YAv=r%+Ajqy}797 zPTT0}vaDzGY#B)S#)E6*IG-IUjSoIl@5)nVw&s=$K0dHBZM^nQj9t9-llSlL{;g?7 z-HUkkX0UFov;4xl(}srTcJ_fpRZrR_sDEc8`nIJozy&i Date: Thu, 19 Mar 2026 11:20:55 -0500 Subject: [PATCH 110/149] feat (home): Add tmux --- homes/common.nix | 1 + programs/tmux.nix | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 programs/tmux.nix diff --git a/homes/common.nix b/homes/common.nix index e652bfb..32c75f9 100644 --- a/homes/common.nix +++ b/homes/common.nix @@ -7,6 +7,7 @@ ./../programs/lsd.nix ./../programs/neovim.nix ./../programs/starship.nix + ./../programs/tmux.nix ./../programs/yt-dlp.nix ]; home = { diff --git a/programs/tmux.nix b/programs/tmux.nix new file mode 100644 index 0000000..f1d45dd --- /dev/null +++ b/programs/tmux.nix @@ -0,0 +1,7 @@ +{ pkgs, ... }: { + programs.tmux = { + enable = true; + terminal = "tmux-256color"; + plugins = with pkgs.tmuxPlugins; [ tmux-powerline ]; + }; +} From f7ba80f9a6c921649742d32e4b0fae0cf82d8968 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 19 Mar 2026 11:31:41 -0500 Subject: [PATCH 111/149] fix (vaultwarden): Bring port back into range --- services/vaultwarden.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/vaultwarden.nix b/services/vaultwarden.nix index 42a87cd..5533f3e 100644 --- a/services/vaultwarden.nix +++ b/services/vaultwarden.nix @@ -1,7 +1,7 @@ { config, pkgs, home-manager-quadlet-nix, ... }: let user = "vaultwarden"; - port = "92858"; + port = "9285"; containerPort = port; authentikPort = "9000"; stateDirectory = "/var/lib/${user}"; From 0645add505ef20fda1956c3a21229567c00aa72f Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:57:24 -0500 Subject: [PATCH 112/149] feat (vaultwarden): Add push notification support --- secrets/vaultwarden.toml.age | Bin 1341 -> 1450 bytes services/vaultwarden.nix | 3 +++ 2 files changed, 3 insertions(+) diff --git a/secrets/vaultwarden.toml.age b/secrets/vaultwarden.toml.age index b60bcd255207f7df221fe8e394113d5ecc77114d..54c3986062db6b423537521c233045b5c1aa60cc 100644 GIT binary patch delta 1366 zcmZ9}X;Tvi002-KuQm)Q(n_nfMGGo~m~8F^WXQRJ++h>4c%(qcvDuK#xycUGU|aC2 z6ic-ZsG~@+AQi2MiUyIP6!B_n6;NBj15xaVBcl}$`n~Tjya=T^x;ib)@#A8Pjt~$c zgO`;rw;7~PuUyK9-0ZvpP$ek@F)gC!@FXRAD@BAW>;!;ISoBhe>&NpUu}ccDg?u__ z<nL$7V+-}%mFiLb* z61HH3VEfaAe2s@$uja)3=l$UOi>B>IAjh$7)UQPyHG0Wpet>3 zBex*OuC@qEgBqMv>REosrl49#K1HG6xtKy!>hK3N3?4?ZC1O{Qu!#v+Q3ALX3Q3+u*%pxw=!{Y~)6un68 zA|YeY=7aSb8>-W=l&k`!mMWDHA)`&5=jI@&Scglw`kem{P(_Sm5;22~I&0+H3}<+jd=TN$Gyy6uUS2#10n#&_>b3$$rz#Ii5%IO8wUP zsqo73<|OzJ`O~s{f1hRSTG+5?y6$4(;NpRl`Mqqs7NO*%EtOcqZ|_-xJxcf4RmB&bLp3fW{ffW%ZzE>31GCt`JbW|MOuMG#5?;MOomY<)1^5WyhYX(v(_u_M(omp^w zME`sICfTZ*@s3;W6|26uG>)!Gan@E_oRL{6+1)1xOCPS41ZEO@(Wj&{*o4>+h+f$OT=nv{W;g$sXLiD$jV~hj6}Dc z89u;`KerC~2TqcEhG&jpvrLNB_()R4lZ@BT9kuO!6^opA9>m7nZ6VonO#NGK^}Xdz zWq*}hKT%~nf^d4m{_AybU9*pUnBCJYsLkMIwv!e=3DjUk&KUO!K zzR$b_Yj5@J3B=VtS56`3y5Pv(jZ32ZTL*4a)w`7kq0Grok(z`#4yfgajZL$tREC07*7AD2GK9Rgug7cqdLOSFVz1ZodeP&(9&C0Q zU9z#8c#Q0$gsffL`oo#$z#hSXOQEvL!*aoq$QRDjt&9 zgX$2+PVu$2U?hxHBSyp_(8~NViI%2AsRWbnHFDTY%I{8^Fr76hilTbZ%5ZRe7+b(^(+oKP(ByE;8H#SVH1rV&kA41AxM1z7;Z#B?PSQ4y(>#^OF5lVTG}CRh~!V47U* ziBVylRVB7yE;)l#Xblc`SjaI#uopIKdz4$qHY8W@Z>hCibp6tyf9yk(PS7G1^6*J3p1E-Nen@Q97F}fKCxD( zj4M#4K@(BWK%xWxg=0iRKa{KqWNV|YjkDWX!u z#i2ExQ-5dM-Zhc>ypXq%HTZq{!V+Nq^$gLDJ!9sb0eoN48dU!?i1J@;yBfa&IvY$Q zWWt-Aj4$2Y>&xG@!?b$cuP3*S*4N~3&&xe`c{gLGxO8UTSVf?-ed|B3@L8v})hIUx zWBQ}nmj2!~z4fyh)5{hFxI_DI$meJl6bvl@v%b7b<*}Pm=Rf#DDf$EgSFax!|Hw3V z{v(yYZcWwEA2&r77M5v_bq{wvn%a|gM0onM*5fOl?vtH1v>7*DALe&IY#+;*by2b9 z#r|>={XA&?g={@HIiqoWQouSvZZBgDk*R0df73c3X^RL%uepb2SL#+Cs=fW@Nuc7E z;NV}+o1V-ow5JZxQ@wRF!21mdW_VTF+LpdI6L85o{euUu=R@;G8v1NMUF$DddPaix zZ(05I*{)ry2A6d(F4PU&TGyPOhc{6LuMg+g(=WDH=03Qx{=?y}+J5%3Kc8-$cB($N ztgk$M`TbRfa_x;dXPc_bg2uz~l?691HFfsUx`sw`0$-g;J*)Wr${QOdxr>_D!r5(e z#P4YibuMY$JY3k)EZX#OsRJHRXH~rO&CSa{bkyHt*R*gKzs+7Ut&Ej6UVALmGm&gQ zKC@xviA(po`rZn6lnsp8b5WDFY4NcyNuFVp8K}v5|+; zUHRgy_Po-O#|J8RrcKq}iBc=Je)|61-M=->t$P{E*$mZ9_6X0vJ9~6=QO_XcuIf+w z Date: Thu, 19 Mar 2026 13:28:17 -0500 Subject: [PATCH 113/149] security (mcentire): Add Caddy access logs to Crowdsec --- services/caddy.nix | 15 +++++++++++++++ systems/linux/mcentire.nix | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 services/caddy.nix diff --git a/services/caddy.nix b/services/caddy.nix new file mode 100644 index 0000000..2f80550 --- /dev/null +++ b/services/caddy.nix @@ -0,0 +1,15 @@ +{ config, ... }: { + services.caddy = { + enable = true; + logFormat = "level INFO"; + }; + + services.crowdsec = { + localConfig.acquisitions = [{ + filenames = [ "${config.services.caddy.logDir}/*.log" ]; + labels.type = "caddy"; + }]; + + hub.parsers = [ "crowdsecurity/caddy-logs" ]; + }; +} diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index cf01a65..95cb563 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -5,6 +5,7 @@ ./hardware-configuration/mcentire.nix ./../../modules/podman-secrets.nix ./../../services/borgmatic.nix + ./../../services/caddy.nix ./../../services/crowdsec.nix ./../../services/authentik.nix ./../../services/audiobookshelf.nix @@ -67,7 +68,6 @@ services = { openssh.enable = true; tailscale.enable = true; - caddy.enable = true; # Do not "enable" database services, but include the package configuration # so that borgmatic does not freak out about unset variables From fd50d5d088bd1d5953c5dc1c0891c8706ece9aba Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 19 Mar 2026 13:59:49 -0500 Subject: [PATCH 114/149] security (vaultwarden): Add hardened reverse proxy config --- services/vaultwarden.nix | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/services/vaultwarden.nix b/services/vaultwarden.nix index 51949ba..22562a0 100644 --- a/services/vaultwarden.nix +++ b/services/vaultwarden.nix @@ -36,7 +36,28 @@ in { }; services.caddy.virtualHosts."vault.millironx.com".extraConfig = '' - reverse_proxy http://127.0.0.1:${port} + # See + encode zstd gzip + header / { + Strict-Transport-Security "max-age=31536000;" + X-XSS-Protection "0" + X-Frame-Options "DENY" + X-Robots-Tag "noindex, nofollow" + X-Content-Type-Options "nosniff" + -Server + -X-Powered-By + -Last-Modified + } + + @admin { + path /admin* + not remote_ip private_ranges 100.64.0.0/10 + } + respond @admin "Access denied to remote clients. Use localhost or VPN." 403 + + reverse_proxy http://127.0.0.1:${port} { + header_up X-Real-IP {remote_host} + } ''; users.users."${user}" = { From 9b4aa045f4b09d7bacd5bc06477405fae83ea727 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 19 Mar 2026 14:25:03 -0500 Subject: [PATCH 115/149] feat (vaultwarden): Migrate Vaultwarden to use OIDC --- secrets/vaultwarden.toml.age | Bin 1450 -> 1660 bytes services/vaultwarden.nix | 7 +++++++ 2 files changed, 7 insertions(+) diff --git a/secrets/vaultwarden.toml.age b/secrets/vaultwarden.toml.age index 54c3986062db6b423537521c233045b5c1aa60cc..40b28038c80fa7953fc60168a9a64adbe7b51156 100644 GIT binary patch delta 1577 zcmV+^2G;qi3;Ya_EPpskR%upDQEV?+Hez)}GI>dFFKanbXlY|~V`y1YaCUezRV!3< zRya6PSqfrTO?p@{d09hHF)?9BXE-%xLrq0yGjA|3MQS!yWlVBLS2AWud3HH^Zwf6w zAaiqQEoEdfH8n9gATehzcz1UoWkgbDXKZ3mD|C5KXmD6)Y(_XzcS$j3HA6#hV`_AF za8xx>acyu}VPY{!3Uf3ybx(0^XF)MkZbNivP(f2eHDf_Ca799Ta%n?!HaTu@PBURh zT2yvtk?|N-P;PNoRcUoEZFg`~cv5Rvc20LiOi(gLG-E|nQDjzUSWGWdXL(djK}8B} zSy3@_GdVMAR8Uq$HDz^JZgDGNHAr(SZbwHkRzovsVNYT&Hce+Xb5WCD0T)+#Ge~bW zOE*$cL^y3?MpAJra#KS$ZBj&YHBB!|Yho`?H+nB~b7V$LXJ-mFacx;tbWeIWY&mXH zY&dyEQe{&zX-PFQNGoDlcxp{bW= zd2o7iYgm6*Rzg8TGfZhocWgL$aCmS>D@0>gc`;E{Gzvm&QF3cfI7ee>NJTYeGB-7E zG)QYTW^GhqCrW@R-`GD3K1bW2Ti zN>(dTXJlenXi79sGhr(*NoZ34_-!78iKq&yY8gq7GvpqL zFb7@%B4sD&`-M8wJHs|133lZaWsBmLoX8D+m}uibK!&BiG|1)Z(t}~==Jm_$P1Foc z=bV27D4YW@_nfwQ7w~bj?lYKNp4g-Gf2h8W4S&os(#F35y3W1`Fkhk_@PJ*++qjTj zZemgvKZrnsL>#?8nNndzAAjem%<_6IpU2Z_ZSKu+UQ=1+yD5`X?eKSTW<6nJ7)u30 z0;Eo7i#flpjVX~)IoM9q3)f-f>uU>0X%K%apZe7oel#X~Y&G5sImh{8&49wJGbo~3D#qSY;gdgLv%hL|Ek5%SF*oncIve+hVO?R4h&EO@ojUFGep}a@ zQTb-|NY4;}dtVcv=BL^SE{;9?8ee~`XT)th?u^fkvn8vJiznSvI}dveV`!TpN$@A+ zLMh1eZi!z6|<_mp@XPo~K0?!!LKvIAz)tA4z( zN=6_^!ZST8FMj^WDR}}47sY?H27&=D zIE^F^^(dBTs~?rKr8$q5`jiD5rtJUT9s8P6O?k$V7L_C7SgDIJ$Bl|zlmGkNM6t+h zvM9cm>@kQ_ltri*;#Z1(p&^(@2Q>R3N_34wHa_#&WLxSG;T|!8`Zqk}nTwK`5H3lm9P~Ke z1a5C{1!TOr%>!BD3;BJ{qGdu-83elvug5Y$up|Ut#7~?9h{u&;&ORYyhzlJvEhPcs bt(1CvfVt>9VR8%?JQ1f;E*(7=gl@(=D9e$A delta 1365 zcmZ9}`&Uy1003Y)zG?)5l$d6rfeK@8ckc_xanC#0d%GLE_#j}EP4^d_2W5^*ewOvLOva| zap^t@j-kc^f`NJ=H9?_eCir}In#IiIZ~!m?u+f7AkpS~JMldKV^s<9Meomo-CH3J< zhucKJB-O4ev?5%rkO9JgFGLC`Ad|-Z!fGYW`+#{)Z!CW+2Q z!d8qB?0B}&XeGJ+Kq%LMYauHD1G%UJ6QX)QQ_Roy$%rC?Zd4U1>_(4NOL4I!3Re(? zcz!=wtO1=2E7K69!gNW{OLbr{Psm`hOnemsgpjJdi1-{FG6x_Gr01L6D3x^5m3F#` zo15iOTZKhI4NfWzEI(vdP^~1NqEPVMOd%?D`U4sU49S63{DP->Xd4SM2M*DZo4QOu?kFnkHo=4oy9z60hjCL@q<6BeXtD6 zb!kaX0Uaxb3&kc2gF>Ux5;(;irXx>x%_rbwwPTkMX0b$%8=0^ zrARtR3n{O$w& z*2H-Oa|a_{ESx=|81Hztq5J0c-Pf9uyFSQ^-WPdtryBrhBWS`zU*4@b-pBHC!?u_d zcx7p0BK(K^S;_ss&oOo{s9Q8$b18pdaes154;!yWC|RjXCARRJyQlXipKyF!^771^ zFK9hUDdzdjwS(b?$yDyQkLM-LvpLS;l#@L}2cwT~slPZWj4Zn{bhI$`%Et9qPd|RY zFYmXQ#Mgbx_OERO$0#Y1&};B!v$V79&=&c88i z_&sj3Y*p1*+ilN^RbO5nL)Rv|sw=Io_F2hmx=sxgJz6IVoKL9en}~XF>^615;*QS0 zb_fpJNLEvNtbR+)#`uwPxlQB*0R3Ki>?XRnV0$MM^Ny{f_HVb zn@gUQr`@)U#}_bqpF z%~#pA;}!O!2&X&jzftqnJ^T2FYr4Ax)#<#9Rx-q(rbqIRwES6>nuWWIWP=$8Mr(%B z_M4YrtRX-R~CTmK!ZdXMrDlrixsQWZbP2{rw&sbN+pSaEoL z&o0E&0OR*~BZIMPo8RpCwRh#rN<&pKTx!HhlOh1&1LdxX_{+_oWnS3SmT7$+x6*fL zXdAe{tD(O!!%2;qZ<05g{O^>W8QXbj-M{DSM{A+1J3zGf(QxJKACIlBJ6fAIa$-ho O Date: Thu, 19 Mar 2026 14:27:02 -0500 Subject: [PATCH 116/149] fix (vaultwarden): Host gateway --- services/vaultwarden.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/services/vaultwarden.nix b/services/vaultwarden.nix index 4c08217..0156254 100644 --- a/services/vaultwarden.nix +++ b/services/vaultwarden.nix @@ -114,6 +114,7 @@ in { autoStart = true; containerConfig = { image = "ghcr.io/dani-garcia/vaultwarden:latest"; + addHosts = [ "auth.millironx.com:host-gateway" ]; environments = { DOMAIN = "https://vault.millironx.com"; ROCKET_PORT = port; From 23ce55d8806a08330802a64c5e18f70e432e6bb7 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:25:12 -0500 Subject: [PATCH 117/149] feat (crowdsec): Enable Crowdsec to read all journalctl logs --- services/crowdsec.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/crowdsec.nix b/services/crowdsec.nix index 5c3e279..9f3f6d8 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -44,6 +44,8 @@ }; }; + users.users."${config.services.crowdsec.user}".extraGroups = [ "adm" ]; + systemd.tmpfiles.rules = let cfg = config.services.crowdsec; in [ "d /var/lib/crowdsec 0755 ${cfg.user} ${cfg.group}" ]; } From 3b079d142f937b56cac158d397f596716b5b0846 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:26:02 -0500 Subject: [PATCH 118/149] fix (fireflyiii, vaultwarden): container dependency order --- services/fireflyiii.nix | 4 ++-- services/vaultwarden.nix | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/services/fireflyiii.nix b/services/fireflyiii.nix index 5174cc2..c029444 100644 --- a/services/fireflyiii.nix +++ b/services/fireflyiii.nix @@ -155,8 +155,8 @@ in { networks = [ networks."${user}".ref ]; publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; }; - unitConfig.Requires = [ secrets.ref containers."${user}".ref ]; - unitConfig.After = [ secrets.ref containers."${user}".ref ]; + unitConfig.Requires = [ secrets.ref containers."${user}-db".ref ]; + unitConfig.After = [ secrets.ref containers."${user}-db".ref ]; }; }; }; diff --git a/services/vaultwarden.nix b/services/vaultwarden.nix index 0156254..3b0ed47 100644 --- a/services/vaultwarden.nix +++ b/services/vaultwarden.nix @@ -146,8 +146,8 @@ in { networks = [ networks."${user}".ref ]; publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; }; - unitConfig.Requires = [ secrets.ref containers."${user}".ref ]; - unitConfig.After = [ secrets.ref containers."${user}".ref ]; + unitConfig.Requires = [ secrets.ref containers."${user}-db".ref ]; + unitConfig.After = [ secrets.ref containers."${user}-db".ref ]; }; }; }; From 67ca6433ccf3b8cf53ca439aabfdf258526dbf48 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:26:39 -0500 Subject: [PATCH 119/149] security (vaultwarden): Add vaultwarden logs to Crowdsec --- services/vaultwarden.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/vaultwarden.nix b/services/vaultwarden.nix index 3b0ed47..54ea31e 100644 --- a/services/vaultwarden.nix +++ b/services/vaultwarden.nix @@ -60,6 +60,15 @@ in { } ''; + services.crowdsec = { + localConfig.acquisitions = [{ + source = "journalctl"; + journalctl_filter = [ "_SYSTEMD_USER_UNIT=${user}.service" ]; + labels.type = "bitwarden"; + }]; + hub.collections = [ "MariuszKociubinski/bitwarden" ]; + }; + users.users."${user}" = { group = user; isNormalUser = true; From 98715d12e34471f68595e5300cd41eac8f2d2af4 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Thu, 19 Mar 2026 18:51:28 -0500 Subject: [PATCH 120/149] security (mcentire): Prevent ssh root and password login --- services/openssh.nix | 9 +++++++++ systems/linux/mcentire.nix | 1 + 2 files changed, 10 insertions(+) create mode 100644 services/openssh.nix diff --git a/services/openssh.nix b/services/openssh.nix new file mode 100644 index 0000000..a315eac --- /dev/null +++ b/services/openssh.nix @@ -0,0 +1,9 @@ +{ ... }: { + services.openssh = { + enable = true; + settings = { + PermitRootLogin = "no"; + PasswordAuthentication = false; + }; + }; +} diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 95cb563..bf03719 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -12,6 +12,7 @@ ./../../services/fireflyiii.nix ./../../services/freshrss.nix ./../../services/navidrome.nix + ./../../services/openssh.nix ./../../services/vaultwarden.nix ]; From bb9491e67358467bbe8ec94e6a2f323af70eaf63 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 20 Mar 2026 08:06:14 -0500 Subject: [PATCH 121/149] fix (vaultwarden): OIDC constant timeout errors --- services/vaultwarden.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/vaultwarden.nix b/services/vaultwarden.nix index 54ea31e..3d452bf 100644 --- a/services/vaultwarden.nix +++ b/services/vaultwarden.nix @@ -135,6 +135,9 @@ in { SSO_AUTHORITY = "https://auth.millironx.com/application/o/vaultwarden/"; SSO_SCOPES = "openid profile email offline_access"; + # Needed to keep token expiration errors from happening + # See + SSO_AUTH_ONLY_NOT_SESSION = "true"; }; secrets = map (s: "${s},type=env") [ "ADMIN_TOKEN" From 37a87f7a57aae591f6952daa4aad8cb31f1a1874 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 20 Mar 2026 08:11:07 -0500 Subject: [PATCH 122/149] security (authentik): Add Crowdsec monitoring to Authentik --- services/authentik.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/authentik.nix b/services/authentik.nix index b6caf43..b5f6dd8 100644 --- a/services/authentik.nix +++ b/services/authentik.nix @@ -75,6 +75,15 @@ in { }; users.groups."${user}" = { }; + services.crowdsec = { + localConfig.acquisitions = [{ + source = "journalctl"; + journalctl_filter = [ "_SYSTEMD_USER_UNIT=${user}.service" ]; + labels.type = "authentik"; + }]; + hub.collections = [ "firix/authentik" ]; + }; + home-manager.users."${user}" = { config, osConfig, ... }: { imports = [ home-manager-quadlet-nix ]; From 5b5aeea40b240489d10d2586675a6461a71e8f41 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 20 Mar 2026 10:22:18 -0500 Subject: [PATCH 123/149] feat (authentik): Add storage bucket support --- secrets/authentik.toml.age | Bin 1222 -> 1614 bytes services/authentik.nix | 14 ++++++++++++++ 2 files changed, 14 insertions(+) diff --git a/secrets/authentik.toml.age b/secrets/authentik.toml.age index d3c91cca5c23bc224a0f53a2dfff20c254edd975..e3b6a25099a2754a2f4547c9113968a76682d64d 100644 GIT binary patch delta 1531 zcmV-{GJ1Doa5Pd`ZE!F~ zaCk~WI0|oOO>;$aOEXzwRC7vEOfzIPF;;U)Ye95*S9VHkSvEIJN<(2yFLX#+Q3@?S zAaiqQEoEdfH8n9gATehzcz1Uob!D^EypFhntTYgI{hW=%CwcVSvYOm|sgGIV8d zS}{#Qk?|K-P)%Vq|PPcTO}ZAob}MM+3Wa!gr5SwvN2aXDm0ZEr$Yb81lv za&vE0M^;5?XL)2nHF#ESPd09Lb~$EHbSpMZdNoIGOIbBgQ&ChmG%{zCUjY|aayNA` zVnJ`uHa1aZRZC<~S9ozY zOhHdLG-fbvHD+^3VN_&BLRmF$bxSxfsGMpQF0dN+15bwqAOT47R2 zY<6g4aX4dYVOVoYXl^iLS7=U8c{5g4Hbr*|V=`BBZES5>I4?n2GjuU^D`{g(YIaX} zcQ{W?Oml8_Sx<0id15kocQVOPEJjKc~?bFHEKg-Lq}zLGgmQ7Zg5#)LUD6iLT?H%ZbURgbxdbOb75&QXhV2q zNojX^cTHDiQ*~=$H)?izO-@ZgdUa-1Zg&bTEiE8bLn}E^Q&@U3T5n@xc1JZbVR&<4 zRWfBlaWYq9L{fK6a5ZymVMAhSQZx!GSqa~ZZ=$DvKgsH((8xu@zYa^vrR011d&?29 z?ZIQ9qlrAJnhXDf(>6_Rwr{`oSclIl!~xE>$0{>VRI@WrC~0_`%*N*9hA=(i%M(um ziZ%p6?n4tGKWRmWksQWfQxR9EEK+3i4R_+-GzwUvTw=a0%S)LE&mb6{0W6D#;u0Dh zXm%HWhDE%dg$x_*R#x`%0nhF%!;Zd>EeO^wQfQHQ`v zCv94&#?xF%lHxLB5r#9F{Tuhkxk2K?3D>KZe4fz&e%w_f)nbJiDJ)X z?5wHiU(0%D^835w&hmD@DuTwgMLh1?T?#sXhFf073_;lrNq!M)W{7r3t>L*Z|v5f6TOPuwsq=EY2$|+(j#>{Kg>9kP+a2 zT6f?yySu!G5GT*4ZpZXCsSf+%a>+{}y9C*7j*Yzw#!FsD)y{I=AW~zzwYP|`PWxpV zZXn|1;UYLQG4XUXS#e|p+y*ZD5C77=S)Jxx0{t$h7;t=}MvT52*Bb787P`pgK#RK( z5eBWsXE$R*zp}q}Xrc)-D>h??UOnc23~k(>QK5E=zKk-?m(PKuCNi*!&L*0SZBUKu zb5fH-U&4$n1F8wXf?;|QJ!Z2?9;MvxR6YZ8ltZfjXcr=CP}z;3=u~k;FIL^ z^w|nGn_%}(1S6T6>aWfI~PfX;Gi5dDBPFW#M><$|bk( z`jjE@(cLE94V1o9Ym}2kRldgOt7`u}gtQ(}n?A57eY}7_V+|n;xaPZwRuON39C-d= zb?PsfdZ*sm^eEBXC=-%%h-n>~;d-LUwO|8XDv{aYBxp<=jUx#}2^A$+eMas4!v3=hH7VHlA-1!*7 h&oE8uGVd1w{LYdCX(}2&zgEw{gp@EL7+yJE8CVF6iwyt( delta 1136 zcmZ9}`)?Bk003Y>z^#)Z%nV`BRfIt3X79S*qd*q>xVE?Uu4{Y8wS+yoyFPAhulHDc zZHLqu69-u$W1xV+j2K41=kS5Xz`_D9uxxWg0wbU<8eS@c_zKVYyWhX?jX(EY>F%1M zU<-mAj1vMM*5?IRdoJj-M>{NOPXaQs7$&$344#hwQHjAcu|U8f=JEs=*kV_4BZ#>G zI0WV~XE4PxZFY+)QDRy^B}_?cYU_2160ePLMhF7UIxuF)sj4oH@-beKIcqAJHYIEs z#1V?7c{3(=FzxMGKbe7L*d9hZJP9kI0iqCxhCB&5VY3k|3XyJ~LS>@ixKmXrnZ{BI zW1;C}G#ABs?=NFe&Mbt}Y}T4=KwZ%w$hY}OH|zJN?XnxUMFrGnvEphz7x7s%=7c8< zxWEjPDcF6Oi6cpe385l!2Vth-fvg+zPz(_@)iv6EeJyjBF#-U%a_te-v(-^&_v$V2 zb}HBa`$20agwhP?4u}d3)!|7GX3BOfO0WfgX2sX zY;#fpTFje0BHkbyL{d=T0^pEgkCgOtF~R_2`7mbs|A5{GF#ebh4JNZG7S7>%)sz6J ze57a=6$9u5WJ00<(oCo%1gm*5;|FPt=tDvv9%2hfDiNuJJ0d70<&rW;W0puv-ohhr zM~G!eMF>dH?@yRl zK`*W=ej|CBD~@N$+2=dGBun`E%nlL!&=lyw=cky4tYd!&%*Q&7Q+n?;ltC zy;G}9qfePTm)2~Dt2%Ror2{QUz3wyoLFcqOpk4pMwYR&TE=DWH@!6iAc08Oa476P%Um_mJKwzf>{Qq9gJ&A1&zDzjzhXN*5+0rLm-6opJ$Yn0aG>(gt%uL# ztMS{~dn?~s+FjQ3&k{`;^wH4Wr59bhdT%}~+_kp1@*Vn9 zmbU)xcu9J!xTh=hDZSj(WsGdtyr}$xH%=~^eEsuV_bwicc8S-2>ik|X*Cy~ zt#Xo`$Hq&0UNIv3N3E`P&4WG4-~x1Wx4$U;c`iGD^7_Vkf_D#;R7|Tsc$y*WuaflIENGTypWH zeLFGtC(+9F)zcJf`}=B1vh(Zo^MjS#n|se6+Br3G;R+qUKQp{(*AFX(>c3xeq-ppa o>eND{e5T)W{Se!FZS9HHeP3N3xunfZ9Gveh%dF6zI5>RtKkD$hdH?_b diff --git a/services/authentik.nix b/services/authentik.nix index b5f6dd8..0349b87 100644 --- a/services/authentik.nix +++ b/services/authentik.nix @@ -147,11 +147,18 @@ in { AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; AUTHENTIK_POSTGRESQL__NAME = "${user}"; AUTHENTIK_POSTGRESQL__USER = "${user}"; + AUTHENTIK_STORAGE__BACKEND = "s3"; }; exec = "worker"; secrets = [ "AUTHENTIK_POSTGRESQL__PASSWORD,type=env" "AUTHENTIK_SECRET_KEY,type=env" + "AUTHENTIK_STORAGE__S3__ACCESS_KEY,type=env" + "AUTHENTIK_STORAGE__S3__SECRET_KEY,type=env" + "AUTHENTIK_STORAGE__S3__BUCKET_NAME,type=env" + "AUTHENTIK_STORAGE__S3__REGION,type=env" + "AUTHENTIK_STORAGE__S3__ENDPOINT,type=env" + "AUTHENTIK_STORAGE__S3__CUSTOM_DOMAIN,type=env" ]; volumes = [ # Remount media folder into new location based on @@ -178,6 +185,7 @@ in { AUTHENTIK_POSTGRESQL__HOST = "authentik-db"; AUTHENTIK_POSTGRESQL__NAME = "${user}"; AUTHENTIK_POSTGRESQL__USER = "${user}"; + AUTHENTIK_STORAGE__BACKEND = "s3"; }; exec = "server"; secrets = [ @@ -189,6 +197,12 @@ in { "AUTHENTIK_EMAIL__PASSWORD,type=env" "AUTHENTIK_EMAIL__USE_SSL,type=env" "AUTHENTIK_EMAIL__FROM,type=env" + "AUTHENTIK_STORAGE__S3__ACCESS_KEY,type=env" + "AUTHENTIK_STORAGE__S3__SECRET_KEY,type=env" + "AUTHENTIK_STORAGE__S3__BUCKET_NAME,type=env" + "AUTHENTIK_STORAGE__S3__REGION,type=env" + "AUTHENTIK_STORAGE__S3__ENDPOINT,type=env" + "AUTHENTIK_STORAGE__S3__CUSTOM_DOMAIN,type=env" ]; # Change from Traefik: publish ports to localhost only via 127.0.0.1 From 787ac3e718bf21f1d3555d5b182aa8b4d4bfbb2b Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 23 Mar 2026 08:36:45 -0500 Subject: [PATCH 124/149] feat (mcentire): Add SearXNG service --- services/searxng.nix | 48 ++++++++++++++++++++++++++++++++++++++ systems/linux/mcentire.nix | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 services/searxng.nix diff --git a/services/searxng.nix b/services/searxng.nix new file mode 100644 index 0000000..70eb146 --- /dev/null +++ b/services/searxng.nix @@ -0,0 +1,48 @@ +{ ... }: +let port = "7327"; +in { + services.searx = { + enable = true; + + configureUwsgi = true; + uwsgiConfig = { + disable-logging = true; + http = ":${port}"; + }; + + redisCreateLocally = true; + + settings = { + general = { + instance_name = "Milliron X Search"; + enable_metrics = false; + }; + search = { autocomplete = "duckduckgo"; }; + server = { + base_url = "https://search.millironx.com/"; + limiter = true; + public_instance = true; + image_proxy = true; + method = "GET"; + }; + ui = { query_in_title = false; }; + hostnames = { + replace = { "(www.)?reddit.com$" = "old.reddit.com"; }; + low_priority = [ + "(.*.)?facebooks.com$" + "(.*.)?youtube.com$" + "(.*.)?youtu.be$" + "(.*.)?reddit.com$" + "(.*.)?redd.it$" + "(www.)?twitter.com$" + "(www.)?x.com$" + ]; + high_priority = [ "(.*.)?wikipedia.org$" ]; + }; + }; + }; + + services.caddy.virtualHosts."search.millironx.com".extraConfig = '' + reverse_proxy http://127.0.0.1:${port} + ''; +} diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index bf03719..78ffeda 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -13,6 +13,7 @@ ./../../services/freshrss.nix ./../../services/navidrome.nix ./../../services/openssh.nix + ./../../services/searxng.nix ./../../services/vaultwarden.nix ]; @@ -67,7 +68,6 @@ }; services = { - openssh.enable = true; tailscale.enable = true; # Do not "enable" database services, but include the package configuration From 6364da77aa863517ddc75982a4bbb72232eb4f82 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 25 Mar 2026 08:28:55 -0500 Subject: [PATCH 125/149] fix (searx): Set secret key --- services/searxng.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/services/searxng.nix b/services/searxng.nix index 70eb146..d2c3587 100644 --- a/services/searxng.nix +++ b/services/searxng.nix @@ -24,6 +24,7 @@ in { public_instance = true; image_proxy = true; method = "GET"; + secret_key = "rC35eF8DRpJDqa"; }; ui = { query_in_title = false; }; hostnames = { From dcd15e47d606fcf2bfcd9a466e9f799000ab40ed Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 27 Mar 2026 23:41:44 -0500 Subject: [PATCH 126/149] feat (odyssey): Add AnythingLLM service --- flake.nix | 1 + homes/odyssey.nix | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/flake.nix b/flake.nix index 21bbcca..82a3ceb 100644 --- a/flake.nix +++ b/flake.nix @@ -84,6 +84,7 @@ ++ (if (desktop && os == "linux") then [ ./homes/linux-desktop.nix plasma-manager.homeModules.plasma-manager + quadlet-nix.homeManagerModules.quadlet ] else [ ]) ++ extraModules; extraSpecialArgs = { diff --git a/homes/odyssey.nix b/homes/odyssey.nix index 53b5368..1d50f04 100644 --- a/homes/odyssey.nix +++ b/homes/odyssey.nix @@ -14,6 +14,23 @@ services = { gpg-agent = { sshKeys = [ "F72C07DBA3DC0903C3ABB55E8B460803FEC22640" ]; }; }; + virtualisation.quadlet = { + containers = { + anythingllm = { + autoStart = true; + containerConfig = { + image = "docker.io/mintplexlabs/anythingllm:1.9"; + addHosts = [ "ollama.millironx.local:host-gateway" ]; + publishPorts = [ "3001:3001" ]; + volumes = + [ "${config.xdg.dataHome}/anythingllm:/app/server/storage:Z" ]; + environments = { STORAGE_DIR = "/app/server/storage"; }; + + }; + }; + }; + autoUpdate.enable = true; + }; xdg = { configFile = { "nextflow.config".text = '' From 8f45819c1ea1ba100217e61e321e82eb3037c351 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 27 Mar 2026 23:42:01 -0500 Subject: [PATCH 127/149] feat (shell): add conda alias --- homes/common.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/homes/common.nix b/homes/common.nix index 32c75f9..3836d34 100644 --- a/homes/common.nix +++ b/homes/common.nix @@ -65,6 +65,7 @@ # tsed - TailScale Exit node Disconnect tsed = "tailscale set --exit-node="; micromamba = "mamba"; + conda = "mamba"; }; sessionPath = [ "$HOME/.local/bin" ]; }; From 7f928ed2ae91c1869f6d2a5ebe912bf651bbc071 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 27 Mar 2026 23:42:44 -0500 Subject: [PATCH 128/149] config (plasma): Update number of CPUs in display widget --- programs/plasma.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/plasma.nix b/programs/plasma.nix index 2fdd769..6e9e9b5 100644 --- a/programs/plasma.nix +++ b/programs/plasma.nix @@ -66,7 +66,7 @@ Appearance.chartFace = "org.kde.ksysguard.barchart"; Sensors.highPrioritySensorIds = "[${ builtins.concatStringsSep "," (builtins.genList - (i: ''"cpu/cpu${builtins.toString i}/usage"'') 12) + (i: ''"cpu/cpu${builtins.toString i}/usage"'') 32) }]"; }; } From fa9cd84c823b7ab5efd9934e96afde2656aff683 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Fri, 27 Mar 2026 23:43:22 -0500 Subject: [PATCH 129/149] config (plasma): Make details default view for Dolphin --- programs/plasma.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/plasma.nix b/programs/plasma.nix index 6e9e9b5..c2db348 100644 --- a/programs/plasma.nix +++ b/programs/plasma.nix @@ -16,6 +16,7 @@ ShowFullPath = true; ShowStatusBar = "FullWidth"; ShowZoomSlider = true; + ViewMode = 1; }; "KFileDialog Settings" = { "Places Icons Auto-resize" = false; From b86ec60a5b36865f397578cef5d655826381f019 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sat, 28 Mar 2026 00:52:43 -0500 Subject: [PATCH 130/149] feat (mcentire): Add Immich --- secrets.nix | 6 + secrets/immich.toml.age | Bin 0 -> 983 bytes secrets/millironx-photos-s3.age | Bin 0 -> 824 bytes secrets/redis-immich-password.age | 16 +++ services/immich.nix | 194 ++++++++++++++++++++++++++++++ 5 files changed, 216 insertions(+) create mode 100644 secrets/immich.toml.age create mode 100644 secrets/millironx-photos-s3.age create mode 100644 secrets/redis-immich-password.age create mode 100644 services/immich.nix diff --git a/secrets.nix b/secrets.nix index 667dd30..562b3d5 100644 --- a/secrets.nix +++ b/secrets.nix @@ -38,14 +38,20 @@ in { ++ [ mcentire-host ]; "secrets/freshrss.toml.age".publicKeys = system-administrators ++ [ mcentire-host ]; + "secrets/immich.toml.age".publicKeys = system-administrators + ++ [ mcentire-host ]; "secrets/millironx-books-s3.age".publicKeys = system-administrators ++ [ mcentire-host ]; "secrets/millironx-music-s3.age".publicKeys = system-administrators ++ [ mcentire-host ]; + "secrets/millironx-photos-s3.age".publicKeys = system-administrators + ++ [ mcentire-host ]; "secrets/navidrome.toml.age".publicKeys = system-administrators ++ [ mcentire-host ]; "secrets/network-information.age".publicKeys = system-administrators ++ [ bosephus-host ]; + "secrets/redis-immich-password.age".publicKeys = system-administrators + ++ [ mcentire-host ]; "secrets/redis-password.age".publicKeys = system-administrators ++ [ mcentire-host ]; "secrets/vaultwarden.toml.age".publicKeys = system-administrators diff --git a/secrets/immich.toml.age b/secrets/immich.toml.age new file mode 100644 index 0000000000000000000000000000000000000000..dcdfc506fb0aca0c9f7e40b231ef4f8fe59def02 GIT binary patch literal 983 zcmZ9`>xb>vjr42#G{MMaHn2 zNYM4erzsbNY6DnbYFx#$!N{d90$o68=N?9hE94ioD!RXUjI-lk! zAuow)ofQzfw1Q_Sx~~>95HYK%GNn}}09tE=D2$Im1Sc7SBby9EO*DrAQ!7IPuNvV% zEcmePk$oiwTO%t{9KMEWVFn@Tp&e9vHi^fxrH&l2Ql+7aNYKxv?cuBjuP~#r4wNT$ z4-;Ldkj82*ReNazl?~Bw5m{D9wx2a{t6tW6 zq@;JdPExMmVQDnVDKb5)l{nTX@_6^ zx?EWl6DL2OKXH*mNbKxd^(yX-{25rlss|43UVCu+{MP0TuYI@o%C7G(o|_t36~P z`_j*6Zv6St(jWh zGIN_7cd*LoVEtC+#Ln$sUiU)z<$tYLzumL_*O~DH55M*17avYH53Ig;?Ukd4qujG3 zzl&P9W%0SM_H};Zk3V_W-c4lxZ_`u9)f3$UC{sT#jWX=Ep literal 0 HcmV?d00001 diff --git a/secrets/millironx-photos-s3.age b/secrets/millironx-photos-s3.age new file mode 100644 index 0000000000000000000000000000000000000000..2158f18646f2caff709be190c68206c75cd00a60 GIT binary patch literal 824 zcmZY6zsuBi0LSq<)FG5QN}VzYQo@;BF5l!1Y2k7|l3ebd{JdNeT=MI_m*g(F{CJYP z;6sN}0j`AfA}~sXa$Lv@3&=` zCKuBj;#C`IeU28zsulPo0PP+ct~={SLAUD=)b-T#Q_x+P#1bpJ;>w2my;BIuAj5T~ zt(9D~9P9)H8V63(pAwQGl#0#7C6!=vRhS)&2mMt%QT*;K8I~i3p1_k@8{)gVM#ZtW zbGcmdRgs&5!eaDrXp8*XE=AllptlF2(q71NGprF|NYzuEvfJz|ay84F+LcIaL9WHT zr8CxGH^wnW2`xz|PHMg@27Ha`+e4h*M(^kK*i!PhA+GMRfl4N_Rm64XHj5^2Opai8 zH3ESlFmhtjV`1+>ekg3#PL%;^!`NZoDaa&Ej3mHAt4dF5olGtdA?hvFUN;n@I+v}E zUUe~##p03PH)(2{uwtL)VvY{%!+Zr1gIGsf=m4irm2uCbZ2*XQ%tk;9h?S#Nt}JC! zcd;3!)JbiuDwWVjjhJFE-Rha5%mz?iWq?fkju*FGQ!-O_G%bn1u^nZrQAktvYylRV z5m`(U2}}yQYj^d03G6;u_|74e8x9s-Mm7HT8#W*oDnyh0ToW0PIuxxkM50+X9*rAO z=2ogZGa0e2{f@;LrZt}nFcF zJA32PuddxW`sviGFRng$@cns`{b2d+zwwLfZ!ewu=aFbFi`##E^83$ckY~?- n_%eR_ae4pc@o$%zf4+O=lQ)xZ9=&-z`t$si;P1bVKl|`Mq&gY* literal 0 HcmV?d00001 diff --git a/secrets/redis-immich-password.age b/secrets/redis-immich-password.age new file mode 100644 index 0000000..a92e560 --- /dev/null +++ b/secrets/redis-immich-password.age @@ -0,0 +1,16 @@ +age-encryption.org/v1 +-> ssh-ed25519 il3lzQ Lqt1JIJtjTwggbhuJj/vG65IbDyr4EK5pOOKtVqdN3s +OBvcpByhzHT+0fmvLpgOCQaTbudVEdNmNDCJCf+9Tzs +-> ssh-ed25519 1g/xww b1Gu6eFxAJwd+8P38D8HoEzApocQDwRpi7GF4tQH+zE +Js9XmUUcV4gGHvE37j6I3J1vYf7gkxOLbfPC2al0EsU +-> ssh-ed25519 dbKeHw nNL9fDDfudbcHOshRKuxtcaZzPNbTEY2z4jAQMNYQTE +Xrz8nKSxzaEnAYeZTust6eZNhILs4dOutAaIfZ4wcGM +-> ssh-ed25519 3qPtug JUTgaW4s68Gtr/kl+L4FLRldW97kk6vaALLSN3IgY24 +cyTIvPurE28TsE8Axl4x05OVcgEX7qA9X00B6u22/LI +-> ssh-ed25519 FRQvIA CYliqiKWpSXwHWteHCyPxDjaVgx3tYH3+OXYtH+HAEM +iSmpVhv01x+g/bN0TpbeN5210YsuAKTWdEJy34lulw4 +-> ssh-ed25519 +C0WRg 5O+LJgQPccaXNPvB/eRANbmq+4A5wNTGSwC6cCAecw4 +EkLahciiQbR8MmgJptjPVi2R/lMbXkZJYIFvOk4v5Vk +--- EcIUdYgRgZ1xHmTX+O1ULpDJKloyFquwZqFLHj1Lf4E +,y-]@5 +H>\= O=,%Z)q631Vl]8wVs \ No newline at end of file diff --git a/services/immich.nix b/services/immich.nix new file mode 100644 index 0000000..94149b9 --- /dev/null +++ b/services/immich.nix @@ -0,0 +1,194 @@ +{ config, pkgs, home-manager-quadlet-nix, ... }: +let + user = "immich"; + port = "46642"; + containerPort = "2283"; + redisPort = 64664; + stateDirectory = "/var/lib/${user}"; + servicePaths = [ ]; + databasePaths = [ "database" ]; + s3BucketName = "millironx-photos"; + s3MountDirectory = "/mount/s3/${s3BucketName}"; + immich-version = "v2"; +in { + age.secrets = { + millironx-photos-s3-token.file = ./../secrets/millironx-photos-s3.age; + redis-immich-password.file = ./../secrets/redis-immich-password.age; + "immich.toml" = { + file = ./../secrets/immich.toml.age; + owner = user; + }; + }; + + millironx.podman-secrets.immich = { + inherit user; + secrets-files = [ config.age.secrets."immich.toml".path ]; + }; + + systemd.tmpfiles.rules = + map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") + ([ "" ] ++ servicePaths ++ databasePaths); + + environment.systemPackages = [ pkgs.s3fs ]; + + fileSystems."${s3BucketName}" = { + device = s3BucketName; + mountPoint = s3MountDirectory; + fsType = "fuse./run/current-system/sw/bin/s3fs"; + noCheck = true; + options = [ + "_netdev" + "allow_other" + "use_path_request_style" + "url=https://us-east-1.linodeobjects.com/" + "passwd_file=${config.age.secrets.millironx-photos-s3-token.path}" + "uid=${user}" + "gid=${user}" + "umask=0022" + ]; + }; + + services = { + borgmatic.configurations."${config.networking.hostName}" = { + source_directories = map (d: "${stateDirectory}/${d}") servicePaths; + postgresql_databases = [{ + name = user; + psql_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db psql --username=${user}"; + pg_dump_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_dump --username=${user}"; + pg_restore_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_restore --username=${user}"; + }]; + }; + + caddy.virtualHosts."photos.millironx.com".extraConfig = '' + reverse_proxy http://127.0.0.1:${port} + ''; + + redis.servers."${user}" = { + enable = true; + port = redisPort; + bind = "0.0.0.0"; + requirePassFile = config.age.secrets.redis-immich-password.path; + }; + }; + + users.users."${user}" = { + group = user; + isNormalUser = true; + home = stateDirectory; + createHome = true; + linger = true; + autoSubUidGidRange = true; + }; + users.groups."${user}" = { }; + + home-manager.users."${user}" = { config, osConfig, ... }: { + imports = [ home-manager-quadlet-nix ]; + + home.stateVersion = "25.05"; + + virtualisation.quadlet = let + inherit (config.virtualisation.quadlet) containers; + inherit (config.virtualisation.quadlet) networks; + inherit (config.virtualisation.quadlet) volumes; + secrets = osConfig.millironx.podman-secrets.immich; + db-user = "postgres"; + in { + autoUpdate.enable = true; + autoEscape = true; + + networks."${user}" = { }; + + volumes.model-cache.volumeConfig = { }; + + containers = { + "${user}-db" = { + autoStart = true; + containerConfig = { + image = "docker.io/tensorchord/pgvecto-rs:pg16-v0.3.0-rootless"; + environments = { + POSTGRES_DB = user; + POSTGRES_USER = db-user; + POSTGRES_INITDB_ARGS = "--data-checksums"; + }; + secrets = [ + "POSTGRES_PASSWORD,type=env" + "POSTGRES_PASSWORD,type=env,target=PGPASSWORD" + ]; + healthCmd = '' + pg_isready --dbname="''${POSTGRES_DB}" --username="''${POSTGRES_USER}" || exit 1; + Chksum="$(psql --dbname="''${POSTGRES_DB}" --username="''${POSTGRES_USER}" --tuples-only --no-align + --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; + echo "checksum failure count is $Chksum"; + [ "$Chksum" = '0' ] || exit 1 + ''; + healthInterval = "30s"; + healthRetries = 5; + healthStartPeriod = "20s"; + exec = '' + postgres + -c shared_preload_libraries=vectors.so + -c 'search_path="$$user", public, vectors' + -c logging_collector=on + -c max_wal_size=2GB + -c shared_buffers=512MB + -c wal_compression=on + ''; + volumes = + [ "${stateDirectory}/database:/var/lib/postgresql/data:U" ]; + networks = [ networks."${user}".ref ]; + }; + unitConfig.Requires = [ secrets.ref ]; + unitConfig.After = [ secrets.ref ]; + }; + + # NOTE: These containers are commented out in order to allow the + # database to be setup without data in it first + # "${user}-ml" = { + # autoStart = true; + # containerConfig = { + # image = + # "ghcr.io/immich-app/immich-machine-learning:${immich-version}"; + # networks = [ networks."${user}".ref ]; + # volumes = [ "${volumes.model-cache.ref}:/cache" ]; + # }; + # }; + + # "${user}" = { + # autoStart = true; + # containerConfig = { + # image = "ghcr.io/immich-app/immich-server:${immich-version}"; + # environments = { + # DB_HOSTNAME = "${user}-db"; + # DB_USERNAME = db-user; + # DB_DATABASE_NAME = user; + # REDIS_HOST = "host.docker.internal"; + # REDIS_PORT = builtins.toString redisPort; + # }; + # secrets = + # map (s: "${s},type=env") [ "DB_PASSWORD" "REDIS_PASSWORD" ]; + # volumes = [ + # "${s3MountDirectory}:/usr/src/app/upload:U" + # "/etc/localtime:/etc/localtime:ro" + # ]; + # networks = [ networks."${user}".ref ]; + # publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; + # addHosts = [ "auth.millironx.com:host-gateway" ]; + # }; + # unitConfig.Requires = [ + # secrets.ref + # containers."${user}-db".ref + # containers."${user}-ml".ref + # ]; + # unitConfig.After = [ + # secrets.ref + # containers."${user}-db".ref + # containers."${user}-ml".ref + # ]; + # }; + }; + }; + }; +} From 0a465333062d27ebedcd31419b16139ca9f2d9c3 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sat, 28 Mar 2026 01:21:09 -0500 Subject: [PATCH 131/149] fix (immich): Actually wire Immich in --- services/immich.nix | 17 +---------------- systems/linux/mcentire.nix | 1 + 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/services/immich.nix b/services/immich.nix index 94149b9..89b1cc3 100644 --- a/services/immich.nix +++ b/services/immich.nix @@ -117,25 +117,10 @@ in { "POSTGRES_PASSWORD,type=env" "POSTGRES_PASSWORD,type=env,target=PGPASSWORD" ]; - healthCmd = '' - pg_isready --dbname="''${POSTGRES_DB}" --username="''${POSTGRES_USER}" || exit 1; - Chksum="$(psql --dbname="''${POSTGRES_DB}" --username="''${POSTGRES_USER}" --tuples-only --no-align - --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; - echo "checksum failure count is $Chksum"; - [ "$Chksum" = '0' ] || exit 1 - ''; + healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"; healthInterval = "30s"; healthRetries = 5; healthStartPeriod = "20s"; - exec = '' - postgres - -c shared_preload_libraries=vectors.so - -c 'search_path="$$user", public, vectors' - -c logging_collector=on - -c max_wal_size=2GB - -c shared_buffers=512MB - -c wal_compression=on - ''; volumes = [ "${stateDirectory}/database:/var/lib/postgresql/data:U" ]; networks = [ networks."${user}".ref ]; diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 78ffeda..0e78845 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -11,6 +11,7 @@ ./../../services/audiobookshelf.nix ./../../services/fireflyiii.nix ./../../services/freshrss.nix + ./../../services/immich.nix ./../../services/navidrome.nix ./../../services/openssh.nix ./../../services/searxng.nix From 200c0add864af51a13d9565cb61a09ddec2543d1 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sat, 28 Mar 2026 09:47:31 -0500 Subject: [PATCH 132/149] feat (immich): Turn Immich service on --- services/immich.nix | 84 ++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/services/immich.nix b/services/immich.nix index 89b1cc3..209c630 100644 --- a/services/immich.nix +++ b/services/immich.nix @@ -129,50 +129,48 @@ in { unitConfig.After = [ secrets.ref ]; }; - # NOTE: These containers are commented out in order to allow the - # database to be setup without data in it first - # "${user}-ml" = { - # autoStart = true; - # containerConfig = { - # image = - # "ghcr.io/immich-app/immich-machine-learning:${immich-version}"; - # networks = [ networks."${user}".ref ]; - # volumes = [ "${volumes.model-cache.ref}:/cache" ]; - # }; - # }; + "${user}-ml" = { + autoStart = true; + containerConfig = { + image = + "ghcr.io/immich-app/immich-machine-learning:${immich-version}"; + networks = [ networks."${user}".ref ]; + volumes = [ "${volumes.model-cache.ref}:/cache" ]; + }; + }; - # "${user}" = { - # autoStart = true; - # containerConfig = { - # image = "ghcr.io/immich-app/immich-server:${immich-version}"; - # environments = { - # DB_HOSTNAME = "${user}-db"; - # DB_USERNAME = db-user; - # DB_DATABASE_NAME = user; - # REDIS_HOST = "host.docker.internal"; - # REDIS_PORT = builtins.toString redisPort; - # }; - # secrets = - # map (s: "${s},type=env") [ "DB_PASSWORD" "REDIS_PASSWORD" ]; - # volumes = [ - # "${s3MountDirectory}:/usr/src/app/upload:U" - # "/etc/localtime:/etc/localtime:ro" - # ]; - # networks = [ networks."${user}".ref ]; - # publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; - # addHosts = [ "auth.millironx.com:host-gateway" ]; - # }; - # unitConfig.Requires = [ - # secrets.ref - # containers."${user}-db".ref - # containers."${user}-ml".ref - # ]; - # unitConfig.After = [ - # secrets.ref - # containers."${user}-db".ref - # containers."${user}-ml".ref - # ]; - # }; + "${user}" = { + autoStart = true; + containerConfig = { + image = "ghcr.io/immich-app/immich-server:${immich-version}"; + environments = { + DB_HOSTNAME = "${user}-db"; + DB_USERNAME = db-user; + DB_DATABASE_NAME = user; + REDIS_HOST = "host.docker.internal"; + REDIS_PORT = builtins.toString redisPort; + }; + secrets = + map (s: "${s},type=env") [ "DB_PASSWORD" "REDIS_PASSWORD" ]; + volumes = [ + "${s3MountDirectory}:/usr/src/app/upload:U" + "/etc/localtime:/etc/localtime:ro" + ]; + networks = [ networks."${user}".ref ]; + publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; + addHosts = [ "auth.millironx.com:host-gateway" ]; + }; + unitConfig.Requires = [ + secrets.ref + containers."${user}-db".ref + containers."${user}-ml".ref + ]; + unitConfig.After = [ + secrets.ref + containers."${user}-db".ref + containers."${user}-ml".ref + ]; + }; }; }; }; From f75bb699e98fbb1bcd4b6d75e6f2d8bfce2d3956 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sat, 28 Mar 2026 12:29:32 -0500 Subject: [PATCH 133/149] fix (immich): Various fixes found in prod --- services/immich.nix | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/services/immich.nix b/services/immich.nix index 209c630..c2d998f 100644 --- a/services/immich.nix +++ b/services/immich.nix @@ -107,7 +107,9 @@ in { "${user}-db" = { autoStart = true; containerConfig = { - image = "docker.io/tensorchord/pgvecto-rs:pg16-v0.3.0-rootless"; + # For some reason, the -rootless variant seems to hang, so go with + # the rootful one (even though this user has no root access) + image = "docker.io/tensorchord/pgvecto-rs:pg16-v0.3.0"; environments = { POSTGRES_DB = user; POSTGRES_USER = db-user; @@ -147,13 +149,16 @@ in { DB_HOSTNAME = "${user}-db"; DB_USERNAME = db-user; DB_DATABASE_NAME = user; - REDIS_HOST = "host.docker.internal"; + REDIS_HOSTNAME = "host.docker.internal"; REDIS_PORT = builtins.toString redisPort; }; secrets = map (s: "${s},type=env") [ "DB_PASSWORD" "REDIS_PASSWORD" ]; volumes = [ - "${s3MountDirectory}:/usr/src/app/upload:U" + # Generally, mounts need the :U directive, but in the case of + # mounting the root of a bucket, that hangs. Uploads are verified + # to work without that, so everything should be fine + "${s3MountDirectory}:/usr/src/app/upload" "/etc/localtime:/etc/localtime:ro" ]; networks = [ networks."${user}".ref ]; From 2b64410c2057bd35a0cef2a1d0b9132e7a48a610 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Sun, 29 Mar 2026 14:46:16 -0500 Subject: [PATCH 134/149] config (alttab): Change gesture to 4 fingers --- programs/alttab.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/alttab.nix b/programs/alttab.nix index 1901f4d..907b6d1 100644 --- a/programs/alttab.nix +++ b/programs/alttab.nix @@ -1,7 +1,7 @@ { ... }: { defaults."AltTab" = { appearanceStyle = 0; - nextWindowGesture = 1; + nextWindowGesture = 3; screenRecordingPermissionSkipped = true; showFullscreenWindows = 0; showHiddenWindows = 1; From abeb891d5d8cb779cbdfc08ce484fd7c365b120b Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 30 Mar 2026 09:45:30 -0500 Subject: [PATCH 135/149] feat (desktop): Add SyncThing config --- flake.nix | 1 + homes/desktop.nix | 1 + services/syncthing.nix | 49 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 services/syncthing.nix diff --git a/flake.nix b/flake.nix index 82a3ceb..65412b6 100644 --- a/flake.nix +++ b/flake.nix @@ -92,6 +92,7 @@ inherit firefox-addons; inherit buildFirefoxXpiAddon; inherit custom-pkgs; + inherit hostname; }; }; in { diff --git a/homes/desktop.nix b/homes/desktop.nix index 4ca1e6c..37cdec8 100644 --- a/homes/desktop.nix +++ b/homes/desktop.nix @@ -4,6 +4,7 @@ ./../programs/firefox.nix ./../programs/zed.nix ./../services/gpg-agent.nix + ./../services/syncthing.nix ]; home = { diff --git a/services/syncthing.nix b/services/syncthing.nix new file mode 100644 index 0000000..85ca1ed --- /dev/null +++ b/services/syncthing.nix @@ -0,0 +1,49 @@ +{ hostname, ... }: { + services.syncthing = let + devices = { + bracket.id = + "6I5AHYC-IWSO3SZ-TZY4SSR-Z7MGB2V-QMCMJXE-QW5JBQV-DBDU5YV-4LRLKQW"; + boozer.id = + "JKLIUHR-SBAVQCX-43ETUQR-M4ZZA75-JXK7EOF-F5RJBG7-PT363R6-MJ6WLQ4"; + } // (if hostname != "odyssey" then { + odyssey.id = + "YC6NDSU-2JRS4MY-BSM4B5V-FWPXKSJ-S573II2-HDOSWSN-DVIDORQ-UUHTKQB"; + } else + { }) // (if hostname != "corianne" then { + corianne.id = + "EN5KDDZ-F6DYDSR-KK35M2M-BVGBU4W-MVC4ENT-5EPWA6M-BBJPIBU-EQTPRQX"; + } else + { }); + in { + enable = true; + settings = { + inherit devices; + folders = let deviceNames = builtins.attrNames devices; + in { + Logseq = { + label = "Logseq"; + id = "kkqs5-4upcf"; + path = "~/Logseq"; + type = "sendreceive"; + versioning = { + type = "trashcan"; + params.cleanoutDays = 14; + }; + devices = deviceNames; + }; + SyncBucket = { + label = "SyncBucket"; + id = "9l6gb-rkyou"; + path = "~/SyncBucket"; + type = "sendreceive"; + versioning = { + type = "trashcan"; + params.cleanoutDays = 14; + }; + devices = deviceNames; + }; + }; + options = { urAccepted = -1; }; + }; + }; +} From 325bc887efcffa230af0052f79ebacf8a5104d0c Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 8 Apr 2026 22:36:49 -0500 Subject: [PATCH 136/149] fix (zed): nixd home-manager autocomplete --- programs/zed.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/zed.nix b/programs/zed.nix index 1aceb66..0fa72a1 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -1,4 +1,4 @@ -{ pkgs, ... }: { +{ pkgs, hostname, ... }: { programs.zed-editor = { enable = true; package = null; @@ -60,8 +60,8 @@ lsp = { nil = { settings.nix.flake.autoArchive = true; }; nixd = { - settings.options.home-manager.expr = - "(builtins.getFlake (builtins.toString ./.)).homeConfigurations..options"; + settings.options.home-manager.expr = '' + (builtins.getFlake (builtins.toString ~/.config/home-manager)).homeConfigurations."millironx@${hostname}".options''; }; texlab = { settings = { From 20efe752c20cfe863491a148ce7a87d27cc96926 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 8 Apr 2026 22:37:16 -0500 Subject: [PATCH 137/149] chore (odyssey): Update AnythingLLM container --- homes/odyssey.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homes/odyssey.nix b/homes/odyssey.nix index 1d50f04..fd1c201 100644 --- a/homes/odyssey.nix +++ b/homes/odyssey.nix @@ -19,7 +19,7 @@ anythingllm = { autoStart = true; containerConfig = { - image = "docker.io/mintplexlabs/anythingllm:1.9"; + image = "docker.io/mintplexlabs/anythingllm:latest"; addHosts = [ "ollama.millironx.local:host-gateway" ]; publishPorts = [ "3001:3001" ]; volumes = From 804132ae4f435a2d54bc38d201c1f60d952e926c Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Wed, 8 Apr 2026 22:39:31 -0500 Subject: [PATCH 138/149] feat (common): Add ssh support This removes GPG agent support for SSH. The GPG agent will still be in charge of signing git commits. Default user keys will still be used for encryption (i.e. agenix) purposes. --- homes/common.nix | 1 + programs/ssh.nix | 72 ++++++++++++++++++++++++++++++++++++++++++ services/gpg-agent.nix | 2 +- 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 programs/ssh.nix diff --git a/homes/common.nix b/homes/common.nix index 3836d34..389c618 100644 --- a/homes/common.nix +++ b/homes/common.nix @@ -6,6 +6,7 @@ ./../programs/git.nix ./../programs/lsd.nix ./../programs/neovim.nix + ./../programs/ssh.nix ./../programs/starship.nix ./../programs/tmux.nix ./../programs/yt-dlp.nix diff --git a/programs/ssh.nix b/programs/ssh.nix new file mode 100644 index 0000000..a768c6b --- /dev/null +++ b/programs/ssh.nix @@ -0,0 +1,72 @@ +{ pkgs, lib, config, hostname, ... }: +let + sshIdPath = host: "~/.ssh/id_ed25519__${host}"; + tailnetConfig = host: { identityFile = sshIdPath host; }; + gitConfig = host: tailnetConfig host // { user = "git"; }; + tailnetHosts = [ "anderson" "mcentire" "bosephus" ]; + gitHosts = [ "github.com" "gitlab.com" "codeberg.org" "code.millironx.com" ]; + tailnetMatchBlocks = + lib.genAttrs (lib.lists.remove hostname tailnetHosts) tailnetConfig; + gitMatchBlocks = lib.genAttrs gitHosts gitConfig // { + "code.millironx.com" = (gitConfig "code.millironx.com") // { + proxyCommand = "ssh anderson -W localhost:2222"; + }; + }; +in { + programs.ssh = { + enable = true; + enableDefaultConfig = false; + matchBlocks = { + "*" = { identitiesOnly = true; }; + "aahz" = { + hostname = "nistac-108-37.dhcp.ksu.edu"; + user = "tchristensen"; + identityFile = sshIdPath "aahz"; + }; + "skeeve" = { + hostname = "129.130.108.157"; + user = "tchristensen"; + identityFile = sshIdPath "skeeve"; + }; + "ceres" = { + hostname = "ceres.scinet.usda.gov"; + user = "thomas.christensen"; + identitiesOnly = false; + serverAliveInterval = 20; + serverAliveCountMax = 30; + extraOptions = { TCPKeepAlive = "yes"; }; + }; + "atlas" = { + hostname = "Atlas-login-1.hpc.msstate.edu"; + user = "thomas.christensen"; + identitiesOnly = false; + serverAliveInterval = 20; + serverAliveCountMax = 30; + extraOptions = { TCPKeepAlive = "yes"; }; + }; + "atlas-dtn" = { + hostname = "Atlas-dtn.hpc.msstate.edu"; + user = "thomas.christensen"; + identitiesOnly = false; + }; + "code.millironx.com" = { + proxyCommand = "ssh anderson -W localhost:2222"; + }; + } // tailnetMatchBlocks // gitMatchBlocks; + }; + + home.packages = let + # Answer no to overwrite questions + keygen = host: '' + yes "n" | \ + ssh-keygen \ + -t ed25519 \ + -f ~/.ssh/id_ed25519__${host} \ + -C "millironx@${hostname}" \ + -N "" + ''; + in [ + (pkgs.writeShellScriptBin "ssh-bootstrap-keys" + (builtins.concatStringsSep "\n" (map keygen (tailnetHosts ++ gitHosts)))) + ]; +} diff --git a/services/gpg-agent.nix b/services/gpg-agent.nix index e34906a..e4a7939 100644 --- a/services/gpg-agent.nix +++ b/services/gpg-agent.nix @@ -2,7 +2,7 @@ services.gpg-agent = { enable = true; enableBashIntegration = true; - enableSshSupport = true; + enableSshSupport = false; enableZshIntegration = true; defaultCacheTtl = 604800; maxCacheTtl = 604800; From 16ebf17d5120eeb82b751c8914375c513550f2a6 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Mon, 13 Apr 2026 11:36:21 -0500 Subject: [PATCH 139/149] fix (ssh): incorrect hostname for code.millironx.com --- programs/ssh.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/ssh.nix b/programs/ssh.nix index a768c6b..a094d44 100644 --- a/programs/ssh.nix +++ b/programs/ssh.nix @@ -10,6 +10,7 @@ let gitMatchBlocks = lib.genAttrs gitHosts gitConfig // { "code.millironx.com" = (gitConfig "code.millironx.com") // { proxyCommand = "ssh anderson -W localhost:2222"; + hostname = "code.millironx.com"; }; }; in { From 27611901d687781709fe6075b5281e887388557e Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 21 Apr 2026 11:54:44 -0500 Subject: [PATCH 140/149] fix (zed): Texlab settings nesting --- programs/zed.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/zed.nix b/programs/zed.nix index 0fa72a1..d698e9d 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -64,9 +64,9 @@ (builtins.getFlake (builtins.toString ~/.config/home-manager)).homeConfigurations."millironx@${hostname}".options''; }; texlab = { - settings = { + settings.texlab = { build = { - onSave = false; + onSave = true; forwardSearchAfter = true; }; forwardSearch = if pkgs.stdenv.hostPlatform.isDarwin then { From d503f858aaade555b5667df1dcc5b28dd6f924bb Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 21 Apr 2026 11:55:14 -0500 Subject: [PATCH 141/149] perf (zed): Make latexindent available vix Nix store path --- programs/zed.nix | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/programs/zed.nix b/programs/zed.nix index d698e9d..28d6147 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -48,8 +48,12 @@ LaTeX = { formatter = { external = { - command = "tex-fmt"; - arguments = [ "--stdin" ]; + command = let + latexindent = (pkgs.texlive.combine { + inherit (pkgs.texlive) scheme-minimal latexindent; + }); + in "${latexindent}/bin/latexindent"; + arguments = [ "-m" "-tt" "-l" "-" ]; }; }; }; From ff37fb108ec7335d2f2205750e6dff04921b4981 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 21 Apr 2026 11:56:11 -0500 Subject: [PATCH 142/149] feat (zed): Add Caddyfile extension --- programs/zed.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/programs/zed.nix b/programs/zed.nix index 28d6147..639bd20 100644 --- a/programs/zed.nix +++ b/programs/zed.nix @@ -5,6 +5,7 @@ extensions = [ "basher" "clean-vscode-icons" + "caddyfile" "clojure" "dockerfile" "earthfile" @@ -44,6 +45,13 @@ } ]; languages = { + Caddyfile = { + tab_size = 2; + formatter.external = { + command = "${pkgs.caddy}/bin/caddy"; + arguments = [ "fmt" "-c" "-" ]; + }; + }; Julia = { formatter = { external = { command = "jlfmt"; }; }; }; LaTeX = { formatter = { From 0563fb8a7e4f9a5658451c418014bf143da8f47c Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:06:28 -0500 Subject: [PATCH 143/149] fix (vaultwarden): SMTP security model --- services/vaultwarden.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/services/vaultwarden.nix b/services/vaultwarden.nix index 3d452bf..d58a40e 100644 --- a/services/vaultwarden.nix +++ b/services/vaultwarden.nix @@ -130,6 +130,7 @@ in { PUSH_ENABLED = "true"; SIGNUPS_ALLOWED = "false"; SMTP_FROM_NAME = "Milliron X Vault"; + SMTP_SECURITY = "force_tls"; SSO_ENABLED = "true"; SSO_ONLY = "true"; SSO_AUTHORITY = From d5e599c7c08f2fc60e19a8e0c1cf78acbb39251c Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:07:07 -0500 Subject: [PATCH 144/149] feat (mcentire): Enable Tailscale exit node --- services/tailscale.nix | 6 ++++++ systems/linux/mcentire.nix | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 services/tailscale.nix diff --git a/services/tailscale.nix b/services/tailscale.nix new file mode 100644 index 0000000..327afc6 --- /dev/null +++ b/services/tailscale.nix @@ -0,0 +1,6 @@ +{ ... }: { + services.tailscale = { + enable = true; + useRoutingFeatures = "server"; + }; +} diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 0e78845..998b024 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -15,6 +15,7 @@ ./../../services/navidrome.nix ./../../services/openssh.nix ./../../services/searxng.nix + ./../../services/tailscale.nix ./../../services/vaultwarden.nix ]; @@ -69,8 +70,6 @@ }; services = { - tailscale.enable = true; - # Do not "enable" database services, but include the package configuration # so that borgmatic does not freak out about unset variables postgresql.package = pkgs.postgresql_17; From 5a70bf0f8de93eaca9c268710d978870dabcf504 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:46:46 -0500 Subject: [PATCH 145/149] feat (mcentire): Add PeerTube service --- conf/peertube.caddyfile | 157 +++++++++++++++++++++ secrets.nix | 4 + secrets/peertube.toml.age | Bin 0 -> 1767 bytes secrets/redis-peertube-password.age | 15 ++ services/peertube.nix | 211 ++++++++++++++++++++++++++++ systems/linux/mcentire.nix | 1 + 6 files changed, 388 insertions(+) create mode 100644 conf/peertube.caddyfile create mode 100644 secrets/peertube.toml.age create mode 100644 secrets/redis-peertube-password.age create mode 100644 services/peertube.nix diff --git a/conf/peertube.caddyfile b/conf/peertube.caddyfile new file mode 100644 index 0000000..204cd75 --- /dev/null +++ b/conf/peertube.caddyfile @@ -0,0 +1,157 @@ +# Translated from +@api_resumable <0rm!o=mkagpfTUMUjN;A!J`cAqm;@UgFF0lFR^=id8Dg z90j4prGtzNh`6A#sUV<$3StEnJ22rZb z0LUgf=>`x+@Kg+8Hir)AMJeh85migkQoUNT2}LJ3Xpl#3BC|oSNg}6W)~GT0I&O)g}S-2$G3149~=n5QvpqdK^$eu|lh04;d2z|FIY0W48S zQrbK!A%t=pNKAz{Kv4i`Y{)|q_YUwFcRgIV^Xmc8%7~eILUGwPQGDB#dS8nGyl0QyK2AwzAD z*+?8NhWoxo*d}s&Oh~s_4_c^l9FCf1X1IttFG(nn(zPNKR|y74bRNzpLYZhBlvYAS zh@=u6k741`X<{48$K(;ont)JGv`AGHF=X`1O)fqQtCIO7{6A?diP+1fA+u>Jx60tb zq*CQ#ztyZFfEp`7hEGxO15CM4htfK*VnP~)%#sliOoP#7W$FR13HG>{9tj&Ilh~zF zJyoZ6yYTc>K7nMR5(Lx)tp5EQDg~>Qn2_60Y^x=eET^&PDUef>B6RuP961p~cR)sg z#4RLY6Z{rbf|IE;w3_Sd_ReXC;m|pYtnx8f{zkUEPtk|+_ZBZRH6m=&^ zRBYcf`Xpx`c=O`nm@6Zs&;-_4i|9e?p2YY&h*Fo+7ctb)xu6?v8C3j=4qTlIe$WzM ze=Zz9Q(xg>3@wI5S5z7hMpka>L*{o9!$Zf%inJP81gWJE-{{C5vRFKi+Y_wR1ZsXqRIY>oMrk;y6GQ6PjvqHq^TzE6FYL0L96;l$ffH3 zuc45(zs7%M`8oIEfU?uCcq7`_)cl>7fmR#a+lzxW1LZFZU3gL3Yz6=DvlHPn>;uDh z8#Z>Fnc%wZ{p0(N?J4@Qtukw}zBg}IUa`u!7GDySRD8JrKAtWRG_Cq-v>hL7G>4nT zzeRSP9C__~6Iv^KH)g%|pNM|A*L7iGKe8pZbGI}zXG;uj?!pdJZ?`40o^Vv=2;Ld= zL+%H4ks5t0TuPq8H?J05j|h+c7;MSqAKdzwxB22{xWOP!cTRZ^^NR(6Wb=(hbrs&8 z+Q4inx-=w!s~>#v&8Pd(IY-K%Z@*L`W4!P7dc!UkMdyw^;h$ptVSn8h=7?;4t6thU z`9-*Z2;COEIrQ--y2BM^I^IlHQ(I-?P@eJf=uG6Ab%%ECUFb<$l9==MgT=qU+VasP zZv*Qa3&Fbbk?J*W!_ATBJr`p5{3}%Afx)1H>T_cmE3P)bIz_xwa(%4nktcR2?!lT{ z{of@=nI{#8y$W^ri5)xE{~~xij~`kT0`Ysd-!FZ}8ZEgJBu`s+Z+!S9mr((vRL##F zIoL34S5owvYWX|PH7){kQ?laRk+Qrcac9aJX!4#{^SrWNPsgL01pCpU#HcA!u1$bD8?nZF_Q z!zI7tvT(P;?pd>5H1KIoc2zlP{LtQA$1fbeWrN#;!d^a|v9*G^KXv?TX>k%T_wN4* CZ}-;# literal 0 HcmV?d00001 diff --git a/secrets/redis-peertube-password.age b/secrets/redis-peertube-password.age new file mode 100644 index 0000000..1ee6754 --- /dev/null +++ b/secrets/redis-peertube-password.age @@ -0,0 +1,15 @@ +age-encryption.org/v1 +-> ssh-ed25519 il3lzQ BiSY+7dxt1jVDqysxYAqAGAXQ0SurqZXGgGqvwaQEXM +gzdbiaAo0nzVOIFEjAoKXSHfs+JQAbJWDJyrO4tt6gA +-> ssh-ed25519 1g/xww 3MK5439qn8MkP5HrLLkY6a+IRGrjVIIe/OhaZ20THU0 +dKe0EkynB0G1zAZZ+VA/Of1x4Q6j+R4al7ohb6V6YWM +-> ssh-ed25519 dbKeHw GfX7az0oBf1Nh6YQFqZuDrCZyK1Mm6w+SGAhQSGeJww +kgLWmzfZjBnds1fjAVme6M7fKD4NrJZ3X6vJU7055ac +-> ssh-ed25519 3qPtug zUXACZya4MCbMyPLR59VN4GRQSOokgORvDhL/ByWbHM +dSfQVAGj8u+7L7GX53dWbs5rHo9H5TaVRwEFZUq3lJ8 +-> ssh-ed25519 FRQvIA z2qGPHCG5wGlmmngy2d4L8kHz7pO/F4YPAWwsNjWQEI +HIVGXAxOfD7O8yP2piOfMLTM9EzWkHslCRFIf+XrXXY +-> ssh-ed25519 +C0WRg BhTldebU1YLAxlQ5dYG/RuExT9czS//LUXwKg+Q7tT8 +mEiv5g1PWgdwZHrlqrv5wEVWvubsppUpryEwtdSNDXM +--- 2+fbTKQ8yZPOKxLvYhFO2laMF/gq2cWs7byzYOcuohM +h D V/0; Os7wrVzeӔWg˝vl} \ No newline at end of file diff --git a/services/peertube.nix b/services/peertube.nix new file mode 100644 index 0000000..2e91337 --- /dev/null +++ b/services/peertube.nix @@ -0,0 +1,211 @@ +{ config, pkgs, home-manager-quadlet-nix, ... }: +let + domain = "video.millironx.com"; + user = "peertube"; + port = "33788"; + containerPort = "9000"; + rtmpHostPort = "41936"; + rtmpContainerPort = "1935"; + redisPort = 63378; + stateDirectory = "/var/lib/${user}"; + servicePaths = [ "data" "config" "assets" ]; + databasePaths = [ "database" ]; + peertubeVersion = "v8.1.4"; +in { + age.secrets = { + "redis-${user}-password".file = ./../secrets/redis-${user}-password.age; + "${user}.toml" = { + file = ./../secrets/${user}.toml.age; + owner = user; + }; + }; + + millironx.podman-secrets.${user} = { + inherit user; + secrets-files = [ config.age.secrets."${user}.toml".path ]; + }; + + systemd.tmpfiles.rules = + map (d: "d ${stateDirectory}/${d} 1775 ${user} ${user} -") + ([ "" ] ++ servicePaths ++ databasePaths); + + services = { + borgmatic.configurations."${config.networking.hostName}" = { + source_directories = map (d: "${stateDirectory}/${d}") servicePaths; + postgresql_databases = [{ + name = user; + psql_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db psql --username=${user}"; + pg_dump_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_dump --username=${user}"; + pg_restore_command = + "/run/wrappers/bin/sudo -iu ${user} ${pkgs.podman}/bin/podman exec ${user}-db pg_restore --username=${user}"; + }]; + }; + + caddy.virtualHosts.${domain}.extraConfig = + builtins.readFile ./../conf/peertube.caddyfile; + + redis.servers.${user} = { + enable = true; + port = redisPort; + bind = "0.0.0.0"; + requirePassFile = config.age.secrets."redis-${user}-password".path; + }; + }; + + # This is a hack - I'm deliberately hijacking the systemd service that is + # set up by `services.caddy` in order to sync the `let` variables with the + # external Caddyfile via environment variables + # This is safe for NixOS 25.11 - see + # + systemd.services.caddy.environment = { + MILLIRONX_PEERTUBE_PORT = port; + MILLIRONX_PEERTUBE_ASSETS_DIR = "${stateDirectory}/assets"; + MILLIRONX_PEERTUBE_DATA_DIR = "${stateDirectory}/data"; + }; + # Another hack - allows the Caddy user to be able to read files that + # PeerTube writes into its dist/ folders + users.users.${config.services.caddy.user}.extraGroups = [ user ]; + + # Forward RTMP (privileged) port to container-accessible (non-privileged) port + systemd = { + sockets."peertube-rtmp" = { + description = "PeerTube RTMP Socket"; + wantedBy = [ "sockets.target" ]; + socketConfig = { + ListenStream = "0.0.0.0:${rtmpContainerPort}"; + Accept = false; + Service = "peertube-rtmp-forward.service"; + }; + }; + + services."peertube-rtmp-forward" = { + description = "PeerTube RTMP Port Forwarder"; + requires = [ "peertube-rtmp.socket" ]; + after = [ "network.target" ]; + serviceConfig = { + Type = "notify"; + ExecStart = + "${pkgs.systemd}/lib/systemd/systemd-socket-proxyd 127.0.0.1:${rtmpHostPort}"; + PrivateTmp = true; + }; + }; + }; + networking.firewall.allowedTCPPorts = [ 1935 ]; + + users.users.${user} = { + group = user; + isNormalUser = true; + home = stateDirectory; + createHome = true; + linger = true; + autoSubUidGidRange = true; + }; + users.groups.${user} = { }; + + home-manager.users.${user} = { config, osConfig, ... }: { + imports = [ home-manager-quadlet-nix ]; + + home.stateVersion = "25.05"; + + virtualisation.quadlet = let + inherit (config.virtualisation.quadlet) containers; + inherit (config.virtualisation.quadlet) networks; + secrets = osConfig.millironx.podman-secrets.${user}; + in { + autoUpdate.enable = true; + autoEscape = true; + + networks.${user} = { }; + + containers = { + "${user}-db" = { + autoStart = true; + containerConfig = { + image = "docker.io/library/postgres:16"; + environments = { + POSTGRES_DB = user; + POSTGRES_USER = user; + }; + secrets = [ + "POSTGRES_PASSWORD,type=env" + "POSTGRES_PASSWORD,type=env,target=PGPASSWORD" + ]; + healthCmd = "pg_isready -d $\${POSTGRES_DB} -U $\${POSTGRES_USER}"; + healthInterval = "30s"; + healthRetries = 5; + healthStartPeriod = "20s"; + volumes = + [ "${stateDirectory}/database:/var/lib/postgresql/data:U" ]; + networks = [ networks."${user}".ref ]; + }; + unitConfig.Requires = [ secrets.ref ]; + unitConfig.After = [ secrets.ref ]; + }; + + "${user}" = { + # TODO: Once data is migrated from anderson, turn this server to + # autostart true + autoStart = false; + containerConfig = { + image = "docker.io/choobozz/peertube:${peertubeVersion}"; + environments = { + PEERTUBE_DB_USERNAME = user; + PEERTUBE_DB_SSL = "false"; + PEERTUBE_DB_HOSTNAME = "${user}-db"; + PEERTUBE_WEBSERVER_HOSTNAME = domain; + PEERTUBE_TRUST_PROXY = + ''["127.0.0.1","loopback","172.18.0.0/16"]''; + PEERTUBE_REDIS_HOSTNAME = "host.docker.internal"; + PEERTUBE_REDIS_PORT = builtins.toString redisPort; + PEERTUBE_USER_VIDEO_QUOTA = "0"; + PEERTUBE_SIGNUP_ENABLED = "false"; + PEERTUBE_CONTACT_FORM_ENABLED = "false"; + PEERTUBE_TRANSCODING_ENABLED = "true"; + PEERTUBE_TRANSCODING_THREADS = "2"; + PEERTUBE_TRANSCODING_144P = "true"; + PEERTUBE_TRANSCODING_360P = "true"; + PEERTUBE_TRANSCODING_480P = "true"; + PEERTUBE_TRANSCODING_720P = "true"; + PEERTUBE_TRANSCODING_1080P = "true"; + PEERTUBE_TRANSCODING_HLS_ENABLED = "true"; + PEERTUBE_OBJECT_STORAGE_ENABLED = "true"; + PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_PREFIX = "videos"; + PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL_PUBLIC = "public-read"; + PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_PREFIX = "playlists"; + }; + secrets = map (s: "${s},type=env") [ + "PEERTUBE_DB_PASSWORD" + "PEERTUBE_SECRETS_PEERTUBE" + "PEERTUBE_SMTP_USERNAME" + "PEERTUBE_SMTP_PASSWORD" + "PEERTUBE_SMTP_HOSTNAME" + "PEERTUBE_SMTP_PORT" + "PEERTUBE_SMTP_FROM_ADDRESS" + "PEERTUBE_ADMIN_EMAIL" + "PEERTUBE_REDIS_AUTH" + "PEERTUBE_OBJECT_STORAGE_ENDPOINT" + "PEERTUBE_OBJECT_STORAGE_REGION" + "PEERTUBE_OBJECT_STORAGE_CREDENTIALS_ACCESS_KEY_ID" + "PEERTUBE_OBJECT_STORAGE_CREDENTIALS_SECRET_ACCESS_KEY" + "PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_BUCKET_NAME" + "PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_BUCKET_NAME" + ]; + networks = [ networks."${user}".ref ]; + publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; + addHosts = [ "auth.millironx.com:host-gateway" ]; + volumes = [ + "${stateDirectory}/data:/data" + "${stateDirectory}/config:/config" + "${stateDirectory}/assets:/app/client/dist" + ]; + }; + + unitConfig.Requires = [ secrets.ref containers."${user}-db".ref ]; + unitConfig.After = [ secrets.ref containers."${user}-db".ref ]; + }; + }; + }; + }; +} diff --git a/systems/linux/mcentire.nix b/systems/linux/mcentire.nix index 998b024..c5645d1 100644 --- a/systems/linux/mcentire.nix +++ b/systems/linux/mcentire.nix @@ -14,6 +14,7 @@ ./../../services/immich.nix ./../../services/navidrome.nix ./../../services/openssh.nix + ./../../services/peertube.nix ./../../services/searxng.nix ./../../services/tailscale.nix ./../../services/vaultwarden.nix From 9527d6bacda274c9cad053cc7a26a8d494e56b04 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:37:31 -0500 Subject: [PATCH 146/149] fix (peertube): Docker image name --- services/peertube.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/peertube.nix b/services/peertube.nix index 2e91337..6aef1be 100644 --- a/services/peertube.nix +++ b/services/peertube.nix @@ -149,7 +149,7 @@ in { # autostart true autoStart = false; containerConfig = { - image = "docker.io/choobozz/peertube:${peertubeVersion}"; + image = "docker.io/chocobozzz/peertube:${peertubeVersion}"; environments = { PEERTUBE_DB_USERNAME = user; PEERTUBE_DB_SSL = "false"; From 6968bfbf6cca9b6566937c4fb92b96f2f07d8072 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:56:10 -0500 Subject: [PATCH 147/149] fix (peertube): PeerTube secret nomenclature --- secrets/peertube.toml.age | Bin 1767 -> 1757 bytes services/peertube.nix | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secrets/peertube.toml.age b/secrets/peertube.toml.age index f406a05f7646096de9433eab5ad761ff1df7c248..212d7bcadf86dba4d482f16f93fa2927305e3c5c 100644 GIT binary patch delta 1676 zcmV;726Or64c!fpEPr-aW^7|NLqRlVS#DEqQ%pBwWJ6JHP)lM}VpMfuI4^NAPiJRH zR#Q1=Zwf~zubWTT5YEDl^Q3@?S zAaiqQEoEdfH8n9gATehzcz1UoD>Qjna8hYGS4U=4LOF45WJYjUYGNx-MrvnMT47B= zIC*GKHDWe2S9fZ63P>+uFh(#zcuR0%GEGx8Pi8k*c1v+tcy23LVmVAnIA?BRXLDzH zbv8_Ak?|K-aW6teOj%H6N>O1rXm~JfH%v5BR5>{^XG?8#Q%gB8b2M{FFja3_QBgPw zZ%#sUaA{LkGIMT1a8+b%Gj>N}Luf~6S$A4dL2pNDXe&%YT6k?!QBXLOUjY|aMpZab zZBs!qG%sOSMpbq%LO60|cR_e|NijD=bZu=!R%AJ8Q)zHva%@EkOL%fQXK-*)axyq^ zXEZBWYH&t*LQHOHRWxQZNii@fsGOEYFkH8Cr4GG}W`M|na* zMlw$?Rx&nvaYjOHHf%6-M>ke6Q86+yMMq-_FUl zO*cqcRcU!kb9i%2NKj&9FhW5JEj}P~b7(DPWHL21F*zVBLoioTXCOB>GGW zF?mXGRzpvJF-$8^OiF4iVPVp>;1V>3-rFl;bQSTqVuH&$76Ofqg%Fj;3eNpCMj zD@$l^Pi1j$VpDKdMmTtI zb~R&BdU|hRY;kT^WK=jaFiCfHM{f!;gLDnuQ& z1B|)*s3Ubh!TwSjz*jqofDsyg%s`}IKmAsV8}UPg=nYFkm@Fk#tg&;#;q$jSPwiEp zP5 z<*Be^a=fVT@yVK@HPe?4ok(ixgk1P0*TGDIc)ZS{ObwIoVI-+*)m8#UL#70Xf2CJ{ zSNv@v$F5Jpzx8uT0lY909uQ-MdZVxDGifA&BN*KFK)ToA6Q(qbjWj=+KZ0Mz>Y)v$ zfqNxq6qEcpcdMhku3gBXB8r`9sHO3_pmqD_72A+XSefJLS-KA0`Vh`;1^JH5 zhqv>Lm4`@4d#nvL8hW}UlK;Vb1_>gx3)E|BVq!-G%GARHx&7Lb*l()8*MZ(?@L#+L z`2hI1Tw=h1ACgo#g=wId%0G&YBfkN$qD*ERRsP*-)8}`vC-rJ#N>#O%a9c!w#kUS( z!;cCHlT`IVJvsRYrgSFXXD-_gIVj=P^gWE6?*F|0@4h|rXHb-@YGiFQHt#RnbR|DW zw;l~*XEo}gcTf^7KJT`YR0Yt9qsVhL$kJ?~VN#w9_;Q)YPyqq2AMbztD_(UR2>HFRM@PBF~ z1a&GcOzt72fMJV7nC2#w>m9%v3c=)wsRQI|kJuI{+55D1RW<&P(Xm}qe#R@`968Um zl8O0o&_!PygSaonn+e79ozjLtk3YWGDTSTUH{FOz(R5x_QPQPie#+B-H{o_p5jHJT zVIb954XYlsg^2X^Q-e73xRq#ssv%moY_Qb6c;3KDq(fv`;EPwR4dEp+GdYdGCdoW@ zq4))x_#;&r^WQ`g+0MwvIf^c*wqRWUI?RDTv@pqGg^L5cK()3F+NC~WV*SN?EZ;bw W{=jN_*@Ea3b(zaP{1vXbIbklM0k2?L`PCrK}JWI7a#|}< zN?K)cId4f!c{gY@3T|mKQB8D8YEf-4G*2~GYjs#paw~LYHAPl-dN)>WPDgTeH%)nX zLv2Y-k?|K-D{xgWOfWZVFIG)fa5hzIF;GTnb3#FOYI-tJI7?J|P(*1(Zgh87czRfsGWIrDOgU9id1`1_ zGj3XHGgLA|R!e$CRZn6oVQ(-|Gfp=)MpQHkMP+7lYDHshc4v2Wb47JhM=MlPY*SNX zIbvCKb236qOEWcTIWtW;I51-hEj}P~b7(DPWHL21F*zVBLoioTXCQGaM`~$IHdR4J zLPK(JT0>8Nb9r<~RWvU`Z*pc$Qglx>FgST>D>!IDM|TQmPhv(`V=!q*5CL3d1JSZ!);L_|nAT6#%lQgcFicQgtuEiE82a5QOcHA_iwQ+X?ILSnNJR=nqrs@r>(1l-k#{Jj1f>Npx(_>5rt0jU~W; zqhRl^%72J|kXU9WGL->7kiUg@r&~=;xg9#@!7?glXbWgj>kh@P-t~C+2dh;6=W55P z49|DUbGQGKAiFBWiBn&FT^2F@$T4O4AmNxP-x+74_ z3=0z!Zo7U?ehb31a7IyxQb_lv6z@t0Xe`det_6{T`orsSA$xZ`1efX*y-A?Nkp7&L#6uppO>`SY*#m9TBue2NXJPEFU?XH zwV#-O11z$bv_VzYT&oko0+dRB^og0sK%Br4ehXi?bGth#BgrrtkxzeWkG4p4Qa7`( ziTK2BtCV>3Zte+ky3jC!vUDyy&dl5T1wUBd2;bSAg9r#c2?4^j5a|0e+`#u003>Z!NKee(IK^f++_H1N$*xG0+IuYGCfPOF?i)rI|J9 gosNj7x2Mo+cfkP&@aXmpYrJlL)5D?-kUnks{*5r>^Z)<= diff --git a/services/peertube.nix b/services/peertube.nix index 6aef1be..2e89e43 100644 --- a/services/peertube.nix +++ b/services/peertube.nix @@ -177,7 +177,7 @@ in { }; secrets = map (s: "${s},type=env") [ "PEERTUBE_DB_PASSWORD" - "PEERTUBE_SECRETS_PEERTUBE" + "PEERTUBE_SECRET" "PEERTUBE_SMTP_USERNAME" "PEERTUBE_SMTP_PASSWORD" "PEERTUBE_SMTP_HOSTNAME" @@ -196,8 +196,8 @@ in { publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; addHosts = [ "auth.millironx.com:host-gateway" ]; volumes = [ - "${stateDirectory}/data:/data" - "${stateDirectory}/config:/config" + "${stateDirectory}/data:/data:U" + "${stateDirectory}/config:/config:U" "${stateDirectory}/assets:/app/client/dist" ]; }; From 662f17b94add6a37e00d7069261c78aeceba5bce Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 21 Apr 2026 16:00:28 -0500 Subject: [PATCH 148/149] fix (peertube): Assets dir --- services/peertube.nix | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/peertube.nix b/services/peertube.nix index 2e89e43..1d785fa 100644 --- a/services/peertube.nix +++ b/services/peertube.nix @@ -11,6 +11,7 @@ let servicePaths = [ "data" "config" "assets" ]; databasePaths = [ "database" ]; peertubeVersion = "v8.1.4"; + peertubeAssetsDir = "${pkgs.peertube}/client/dist"; in { age.secrets = { "redis-${user}-password".file = ./../secrets/redis-${user}-password.age; @@ -61,7 +62,7 @@ in { # systemd.services.caddy.environment = { MILLIRONX_PEERTUBE_PORT = port; - MILLIRONX_PEERTUBE_ASSETS_DIR = "${stateDirectory}/assets"; + MILLIRONX_PEERTUBE_ASSETS_DIR = peertubeAssetsDir; MILLIRONX_PEERTUBE_DATA_DIR = "${stateDirectory}/data"; }; # Another hack - allows the Caddy user to be able to read files that @@ -196,9 +197,9 @@ in { publishPorts = [ "127.0.0.1:${port}:${containerPort}" ]; addHosts = [ "auth.millironx.com:host-gateway" ]; volumes = [ - "${stateDirectory}/data:/data:U" - "${stateDirectory}/config:/config:U" - "${stateDirectory}/assets:/app/client/dist" + "${stateDirectory}/data:/data" + "${stateDirectory}/config:/config" + "${peertubeAssetsDir}:/app/client/dist:ro" ]; }; From 860f1f6fd0fdf336b4a122f7411f131e9bde5c58 Mon Sep 17 00:00:00 2001 From: "Thomas A. Christensen II" <25492070+MillironX@users.noreply.github.com> Date: Tue, 21 Apr 2026 20:03:21 -0500 Subject: [PATCH 149/149] fix (peertube): Email settings --- secrets/peertube.toml.age | Bin 1757 -> 1749 bytes services/peertube.nix | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/secrets/peertube.toml.age b/secrets/peertube.toml.age index 212d7bcadf86dba4d482f16f93fa2927305e3c5c..3441ff030df0c1a2c7e5fba9834ac919e540e0ea 100644 GIT binary patch delta 1667 zcmV-}27LM54b=^hEPrn+b9s4FRWnmedO2B4b5~VPIaG3UIA&{AHgi)mOh#uhL{xP% zb7Vn6Sqf20ZZ>vqYiC$+XhBRxS6Vn_VJk~&d0AOaVRkl7D_L$~Q8{Z#R9QwdYYHts zAaiqQEoEdfH8n9gATehzcz1UoFhONFoFFjOyPQh9k*3OQ6rY-x0OGBtE^Wj0ZCc}GP>SV?Vda!7AEZ*y@~H+DH^dSy~L zIcZZ>k?|K-Z*NC7dNX-hFgH1OOL%lNMr=oQGi56^WM^tbRyl4{aArtVFmYx~F)&#Q zcXDBOL}+MIYicwwG-z#fa(G2eRdIG|Z$fH9b60M6M>s+>Q+a1nSW{J#UjY|aN_8+X zYHd_kFJeh=V{AoPVJ~B5ZbDcwYBfn^YBWShLTP0*RZ=)Oc1Lpxc6d}TOE7g)I5TQ1 zN=aujSvD|5IZ#V4H#b#8YgbKncz9w;FhV&rVsbQ-%>fsGWlS+cX)-ZzRc1tWZdO!7 zczJ1UPfs~QNJdL{ZE#6QK|(TBT3328HCJZ}SZ6p`dTK>xH(D@hHA7@pOHwj)c|~nf zZDnFvYe#K3HB@V1YB@<-Ol4yVEj}P~b7(DPWHL21F*zVBLoioTXCPu_QF3xdc{5}< zSW8eWAW>j}pVr+6@OJ*-IcQH<7LRAViGI=m!WNI={PiZ+gNJchB zGf-D;W@=hVFjZ}OFf(&9dRReLZ(((AD^&_DEiE8(G(}H&M{7uHYjSy7cV>1_VMbGE zHA`VwZ!}{;O;$)ZD>hh7W^`;+V{Z!H2y!vB#?h*O^Wh7tlbCw-h95#@wwnwY)fpKJ zUUqsNQqee-9?l13pmQu)fHqMq^_0|1_Kj?5_GoqcpC3!hjA z!iRW&3cf9&z7Y3*A_cHP^wncE)!6^5{JisaaKd*5En@|02h?(?ejJ9Ea4)w%u)>6#R#*c_n6crKL5^yI&9?b_U zSo(ZQ5q2-dYg#Q2u%{&>wzf>^-2nP^U0y;^O3zU-`^aco zK(CiZ4N++Y*0dQOM=L^Tfz5~8_{;L~3vg5WDz734-BPf&IC;TgN{Y#%iA4CU#?TA=lwRb2ZdzRaVYkJ+L5 zWmen-VuD#A>tS|&S1#ZV?|V_idbqJfyyca2oBl_YIUe&cN-bZiZ$xSqc^mwHtmgL; zcyLXbvq$d`0hZGpPc-HiA`HKO0|XS2`CqB#He4!E>8>VgkExSakgc2*xI?RsLVE2J z*w{~<7@sR*5qkVjXhV%GS9u19+g!*f;oc9V-yx@-aRO;u`1l}7d3*D_g_d(bOjS_t zukC2W)rOqyistF^38^{{nI<{QM2uvLi+6u^4f0Elc|t;7r=l_d%m2=L%+IL-|Bo#n zrM2sK*yAV(c1;ScGY)N8Utz`%b2vHpEBH}@r_`}jQ2)YB&8A)jgQL%VWVJkphvJH5 zYqc2>q}!);>4oLtmQWK9HincyW_IIfun9zcQ?9~zubWTT5YEDl^Q3@?S zAaiqQEoEdfH8n9gATehzcz1UoD>Qjna8hYGS4U=4LOF45WJYjUYGNx-MrvnMT47B= zIC*GKHDWe2S9fZ63P>+uFh(#zcuR0%GEGx8Pi8k*c1v+tcy23LVmVAnIA?BRXLDzH zbv8_Ak?|K-aW6teOj%H6N>O1rXm~JfH%v5BR5>{^XG?8#Q%gB8b2M{FFja3_QBgPw zZ%#sUaA{LkGIMT1a8+b%Gj>N}Luf~6S$A4dL2pNDXe&%YT6k?!QBXLOUjY|aMpZab zZBs!qG%sOSMpbq%LO60|cR_e|NijD=bZu=!R%AJ8Q)zHva%@EkOL%fQXK-*)axyq^ zXEZBWYH&t*LQHOHRWxQZNii@fsGOEYFkH8Cr4GG}W`M|na* zMlw$?Rx&nvaYjOHHf%6-M>ke6Q86+yMMq-_FUl zO*cqcRcU!kb9i%2NKj&9FhW5JEj}P~b7(DPWHL21F*zVBLoioTXCOB>GGW zF?mXGRzpvJF-$8^OiF4iVPVp>;1V>3-rFl;bQSTqVuH&$76Ofqg%Fj;3eNpCMj zD@$l^Pi1j$VpDKdMmTtI zb~R&BdU|hRY;kT^WK=jaFiCfHM{f!;gLDnuQ& z1B|)*s3Ubh!TwSjz*jqofDsyg%s`}IKmAsV8}UPg=nYFkm@Fk#tg&;#;q$jSPwiEp zP5 z<*Be^a=fVT@yVK@HPe?4ok(ixgk1P0*TGDIc)ZS{ObwIoVI-+*)m8#UL#70Xf2CJ{ zSNv@v$F5Jpzx8uT0lY909uQ-MdZVxDGifA&BN*KFK)ToA6Q(qbjWj=+KZ0Mz>Y)v$ zfqNxq6qEcpcdMhku3gBXB8r`9sHO3_pmqD_72A+XSefJLS-KA0`Vh`;1^JH5 zhqv>Lm4`@4d#nvL8hW}UlK;Vb1_>gx3)E|BVq!-G%GARHx&7Lb*l()8*MZ(?@L#+L z`2hI1Tw=h1ACgo#g=wId%0G&YBfkN$qD*ERRsP*-)8}`vC-rJ#N>#O%a9c!w#kUS( z!;cCHlT`IVJvsRYrgSFXXD-_gIVj=P^gWE6?*F|0@4h|rXHb-@YGiFQHt#RnbR|DW zw;l~*XEo}gcTf^7KJT`YR0Yt9qsVhL$kJ?~VN#w9_;Q)YPyqq2AMbztD_(UR2>HFRM@PBF~ z1a&GcOzt72fMJV7nC2#w>m9%v3c=)wsRQI|kJuI{+55D1RW<&P(Xm}qe#R@`968Um zl8O0o&_!PygSaonn+e79ozjLtk3YWGDTSTUH{FOz(R5x_QPQPie#+B-H{o_p5jHJT zVIb954XYlsg^2X^Q-e73xRq#ssv%moY_Qb6c;3KDq(fv`;EPwR4dEp+GdYdGCdoW@ zq4))x_#;&r^WQ`g+0MwvIf^c*wqRWUI?RDTv@pqGg^L5cK()3F+NC~WV*SN?EZ;bw W{=jN_*@Ea3b(zaP{1v