summaryrefslogtreecommitdiff
path: root/hosts
diff options
context:
space:
mode:
authorvin <vin@vineetk.net>2025-09-20 22:11:24 -0400
committervin <vin@vineetk.net>2025-09-20 22:11:24 -0400
commite34fc237e405e79dff3fa27f6124a4ec4a2e25ea (patch)
tree8f5120162f373e270e40604b93216ccac3636da0 /hosts
parentbd18f4a8f3d5d3d360216bbb01ae83514c28d00c (diff)
a
Diffstat (limited to 'hosts')
-rw-r--r--hosts/demiurge/default.nix325
-rw-r--r--hosts/demiurge/hardware.nix8
2 files changed, 193 insertions, 140 deletions
diff --git a/hosts/demiurge/default.nix b/hosts/demiurge/default.nix
index c53c3eb..f3259df 100644
--- a/hosts/demiurge/default.nix
+++ b/hosts/demiurge/default.nix
@@ -21,6 +21,7 @@
21 allowUnfreePredicate = 21 allowUnfreePredicate =
22 pkg: 22 pkg:
23 builtins.elem (lib.getName pkg) [ 23 builtins.elem (lib.getName pkg) [
24 "open-webui"
24 "steam" 25 "steam"
25 "steam-unwrapped" 26 "steam-unwrapped"
26 ]; 27 ];
@@ -42,16 +43,14 @@
42 super.usbutils 43 super.usbutils
43 ]; 44 ];
44 nativeBuildInputs = old.nativeBuildInputs ++ [ super.makeWrapper ]; 45 nativeBuildInputs = old.nativeBuildInputs ++ [ super.makeWrapper ];
45 postInstall = 46 postInstall = (old.postInstall or "") + ''
46 (old.postInstall or "") 47 wrapProgram $out/bin/alvr_dashboard --prefix PATH : "${
47 + '' 48 super.lib.makeBinPath [
48 wrapProgram $out/bin/alvr_dashboard --prefix PATH : "${ 49 super.android-tools
49 super.lib.makeBinPath [ 50 super.usbutils
50 super.android-tools 51 ]
51 super.usbutils 52 }"
52 ] 53 '';
53 }"
54 '';
55 }); 54 });
56 }) 55 })
57 ]; 56 ];
@@ -60,7 +59,7 @@
60 # decrypt agenix secrets 59 # decrypt agenix secrets
61 age.secrets = { 60 age.secrets = {
62 wg0_demiurge.file = ../../secrets/wg0_demiurge.age; 61 wg0_demiurge.file = ../../secrets/wg0_demiurge.age;
63 wg1_demiurge.file = ../../secrets/wg0_demiurge.age; 62 wg1_demiurge.file = ../../secrets/wg1_demiurge.age;
64 }; 63 };
65 64
66 # boot options 65 # boot options
@@ -70,17 +69,23 @@
70 "net.ipv6.conf.all.forwarding" = true; 69 "net.ipv6.conf.all.forwarding" = true;
71 }; 70 };
72 71
73 kernelPackages = pkgs.linuxPackages_6_13; 72 kernelPackages = pkgs.linuxPackages_6_12;
74 73
75 loader = { 74 loader = {
76 systemd-boot.enable = true; 75 systemd-boot.enable = true;
77 efi.canTouchEfiVariables = true; 76 efi.canTouchEfiVariables = true;
78 }; 77 };
79 78
80 zfs.extraPools = [ 79 supportedFilesystems = [ "zfs" ];
81 "data_wd" 80
82 "data" 81 zfs = {
83 ]; 82 devNodes = "/dev/disk/by-partuuid";
83 extraPools = [
84 "data_nvme"
85 "data_wd"
86 ];
87 forceImportRoot = false;
88 };
84 }; 89 };
85 90
86 # disable wifi and open some ports 91 # disable wifi and open some ports
@@ -88,6 +93,9 @@
88 hostName = "demiurge"; 93 hostName = "demiurge";
89 hostId = "cafebabe"; 94 hostId = "cafebabe";
90 95
96 # I like my ethX/wlanX names
97 usePredictableInterfaceNames = false;
98
91 wireless.enable = false; 99 wireless.enable = false;
92 100
93 firewall = { 101 firewall = {
@@ -99,59 +107,80 @@
99 allowedUDPPorts = [ 51413 ]; 107 allowedUDPPorts = [ 51413 ];
100 }; 108 };
101 109
102 wg-quick.interfaces = { 110 interfaces.eth0 = {
111 ipv4.addresses = [
112 {
113 address = "192.168.1.2";
114 prefixLength = 24;
115 }
116 ];
117 };
118 defaultGateway = {
119 address = "192.168.1.1";
120 interface = "eth0";
121 };
122
123 wireguard.interfaces = {
103 # mullvad 124 # mullvad
104 wg0 = { 125 wg0 = {
105 address = [ 126 ips = [
106 "10.68.117.111/32" 127 "10.68.117.111/32"
107 "fc00:bbbb:bbbb:bb01::5:756e/128" 128 "fc00:bbbb:bbbb:bb01::5:756e/128"
108 ]; 129 ];
109 privateKeyFile = config.age.secrets.wg0_demiurge.path; 130 privateKeyFile = config.age.secrets.wg0_demiurge.path;
110 131
111 postUp = "ip route add 45.134.142.206 dev eth0"; 132 postSetup = ''
112 postDown = "ip route del 45.134.142.206 dev eth0"; 133 ip route add 45.134.142.206 via 192.168.1.1
134 ip route add default via 45.134.142.206
135 '';
136 postShutdown = ''
137 ip route del default via 45.134.142.206
138 ip route del 45.134.142.206 via 192.168.1.1
139 '';
113 140
114 peers = [{ 141 peers = [
142 {
115 allowedIPs = [ 143 allowedIPs = [
116 "0.0.0.0/0" 144 "0.0.0.0/0"
117 "::0/0" 145 "::0/0"
118 ]; 146 ];
119 endpoint = "45.134.142.206:51820"; 147 endpoint = "45.134.142.206:51820";
120 publicKey = "H5t7PsMDnUAHrR8D2Jt3Mh6N6w43WmCzrOHShlEU+zw="; 148 publicKey = "H5t7PsMDnUAHrR8D2Jt3Mh6N6w43WmCzrOHShlEU+zw=";
121 }]; 149 }
150 ];
122 }; 151 };
123 152
124 # epistemia 153 # epistemia
125 wg1 = { 154 wg1 = {
126 address = [ 155 ips = [
127 "10.0.13.2/24" 156 "10.0.13.2/24"
128 "fd00:b0ba:cafe:babe::2/64" 157 "fd00:b0ba:cafe:babe::2/64"
129 ]; 158 ];
130 privateKeyFile = config.age.secrets.wg1_demiurge.path; 159 privateKeyFile = config.age.secrets.wg1_demiurge.path;
131 listenPort = 51820; 160 listenPort = 51820;
132 fwMark = 51821; 161 fwMark = "51821";
133 MTU = 1420; 162 mtu = 1420;
134 163
135 table = false; 164 #table = "Off";
136 postUp = '' 165 postSetup = ''
137PostUp = ip rule add from 10.0.13.0/24 lookup main pref 31000 166 ip rule add from 10.0.13.0/24 lookup main pref 31000
138PostUp = ip rule add from all fwmark 51821 lookup 51821 pref 32000 167 ip rule add from all fwmark 51821 lookup 51821 pref 32000
139PostUp = ip route add default via 192.168.1.1 dev eth0 table 51821 168 ip route replace default via 192.168.1.1 dev eth0 table 51821
140 169
141# NAT iphonebob and allow traffic between peers (when routing through demiurge) 170 # NAT iphonebob and allow traffic between peers (when routing through demiurge)
142PostUp = iptables -F FORWARD 171 ${pkgs.iptables}/bin/iptables -F FORWARD
143PostUp = iptables -t nat -I POSTROUTING 1 -s 10.0.13.4/32 -o wg0 -j MASQUERADE 172 ${pkgs.iptables}/bin/iptables -t nat -I POSTROUTING 1 -s 10.0.13.4/32 -o wg0 -j MASQUERADE
144PostUp = iptables -A FORWARD -i wg1 -o wg1 -j ACCEPT 173 ${pkgs.iptables}/bin/iptables -A FORWARD -i wg1 -o wg1 -j ACCEPT
145PostUp = iptables -A FORWARD -i wg1 -o wg0 -j ACCEPT 174 ${pkgs.iptables}/bin/iptables -A FORWARD -i wg1 -o wg0 -j ACCEPT
146PostUp = iptables -A FORWARD -i wg0 -o wg1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT 175 ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -o wg1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
147 ''; 176 '';
148 preDown = '' 177 preShutdown = ''
149PreDown = ip rule del from all fwmark 51821 lookup 51821 pref 32000 178 ip rule del from all fwmark 51821 lookup 51821 pref 32000
150PreDown = ip rule del from 10.0.13.0/24 lookup main pref 31000 179 ip rule del from 10.0.13.0/24 lookup main pref 31000
151PreDown = ip route flush table 51821 180 ip route flush table 51821
152 181
153PreDown = iptables -t nat -D POSTROUTING -s 10.0.13.4/32 -o wg0 -j MASQUERADE 182 ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.0.13.4/32 -o wg0 -j MASQUERADE
154PreDown = iptables -F FORWARD 183 ${pkgs.iptables}/bin/iptables -F FORWARD
155 ''; 184 '';
156 185
157 peers = [ 186 peers = [
@@ -191,7 +220,7 @@ PreDown = iptables -F FORWARD
191 ]; 220 ];
192 persistentKeepalive = 25; 221 persistentKeepalive = 25;
193 publicKey = "iMDEwvXjPAlQH8ZCmP63FM5ICYIFIX5XIyGxjnXoNVE="; 222 publicKey = "iMDEwvXjPAlQH8ZCmP63FM5ICYIFIX5XIyGxjnXoNVE=";
194 } 223 }
195 ]; 224 ];
196 }; 225 };
197 }; 226 };
@@ -231,7 +260,7 @@ PreDown = iptables -F FORWARD
231 packages = with pkgs; [ 260 packages = with pkgs; [
232 alvr 261 alvr
233 bs-manager 262 bs-manager
234 (llama-cpp.packages.x86_64-linux.rocm.override { useVulkan = true; }) 263 #(llama-cpp.packages.x86_64-linux.rocm.override { useVulkan = true; })
235 #(vllm.override { cudaSupport = false; rocmSupport = true; gpuTargets = [ "gfx906" "gfx1100" ]; }) 264 #(vllm.override { cudaSupport = false; rocmSupport = true; gpuTargets = [ "gfx906" "gfx1100" ]; })
236 ]; 265 ];
237 }; 266 };
@@ -300,37 +329,26 @@ PreDown = iptables -F FORWARD
300 services = { 329 services = {
301 # dns 330 # dns
302 unbound = { 331 unbound = {
303 enable = true; 332 enable = false;
304 settings = { 333 settings = {
305 server = { 334 server = {
306 interface = [ "127.0.0.1" "10.0.13.2" "fd00:b0ba:cafe:babe::2" "::1" ]; 335 interface = [
307 access-control = [ "0.0.0.0/0 allow" "::0/0 allow" ]; 336 "127.0.0.1"
308 337 "10.0.13.2"
309 hide-identity = yes; 338 "fd00:b0ba:cafe:babe::2"
310 hide-version = yes; 339 "::1"
311 340 ];
312 # Synthesize NXDOMAINs from DNSSEC NSEC chains. 341 access-control = [
313 # https://tools.ietf.org/html/rfc8198 342 "0.0.0.0/0 allow"
314 aggressive-nsec = no; 343 "::0/0 allow"
315 344 ];
316 local-zone = "saklas.epistemia." redirect; 345
317 local-data = "saklas.epistemia. 86400 IN A 10.0.13.1"; 346 hide-identity = true;
318 local-data = "saklas.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::1"; 347 hide-version = true;
319 local-zone = "demiurge.epistemia." redirect; 348
320 local-data = "demiurge.epistemia. 86400 IN A 10.0.13.2"; 349 # Synthesize NXDOMAINs from DNSSEC NSEC chains.
321 local-data = "demiurge.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::2"; 350 # https://tools.ietf.org/html/rfc8198
322 local-zone = "hastur.epistemia." redirect; 351 aggressive-nsec = false;
323 local-data = "hastur.epistemia. 86400 IN A 10.0.13.3";
324 local-data = "hastur.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::3";
325 local-zone = "iphonebob.epistemia." redirect;
326 local-data = "iphonebob.epistemia. 86400 IN A 10.0.13.4";
327 local-data = "iphonebob.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::4";
328 local-zone = "lab.epistemia." redirect;
329 local-data = "lab.epistemia. 86400 IN A 10.0.13.5";
330 local-data = "lab.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::5";
331 local-zone = "paraclete.epistemia." redirect;
332 local-data = "paraclete.epistemia. 86400 IN A 10.0.13.6";
333 local-data = "paraclete.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::6";
334 }; 352 };
335 353
336 # hagezi for dns-based adblocking (in addition to others) 354 # hagezi for dns-based adblocking (in addition to others)
@@ -341,13 +359,40 @@ PreDown = iptables -F FORWARD
341 }; 359 };
342 360
343 # go through mullvad for regular dns queries 361 # go through mullvad for regular dns queries
344 forward-zone = { 362 forward-zone = {
345 name = "."; 363 name = ".";
346 forward-addr = [ "100.64.0.3" ]; 364 forward-addr = [ "100.64.0.3" ];
347 }; 365 };
366
367 local-data = [
368 "demiurge.epistemia. 86400 IN A 10.0.13.2"
369 "demiurge.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::2"
370 "hastur.epistemia. 86400 IN A 10.0.13.3"
371 "hastur.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::3"
372 "iphonebob.epistemia. 86400 IN A 10.0.13.4"
373 "iphonebob.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::4"
374 "lab.epistemia. 86400 IN A 10.0.13.5"
375 "lab.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::5"
376 "paraclete.epistemia. 86400 IN A 10.0.13.6"
377 "paraclete.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::6"
378 "saklas.epistemia. 86400 IN A 10.0.13.1"
379 "saklas.epistemia. 86400 IN AAAA fd00:b0ba:cafe:babe::1"
380 ];
381
382 local-zone = [
383 "\"demiurge.epistemia.\" redirect"
384 "\"hastur.epistemia.\" redirect"
385 "\"iphonebob.epistemia.\" redirect"
386 "\"lab.epistemia.\" redirect"
387 "\"paraclete.epistemia.\" redirect"
388 "\"saklas.epistemia.\" redirect"
389 ];
348 }; 390 };
349 }; 391 };
350 392
393 # automatically scrub zfs pools (every week by default)
394 zfs.autoScrub.enable = true;
395
351 # media server 396 # media server
352 jellyfin = { 397 jellyfin = {
353 enable = true; 398 enable = true;
@@ -415,7 +460,10 @@ PreDown = iptables -F FORWARD
415 nginx = { 460 nginx = {
416 enable = true; 461 enable = true;
417 462
418 defaultListenAddresses = [ "10.0.13.2" "fd00:b0ba:cafe:babe::2" ]; 463 defaultListenAddresses = [
464 "10.0.13.2"
465 "fd00:b0ba:cafe:babe::2"
466 ];
419 467
420 recommendedGzipSettings = true; 468 recommendedGzipSettings = true;
421 recommendedOptimisation = true; 469 recommendedOptimisation = true;
@@ -525,7 +573,7 @@ PreDown = iptables -F FORWARD
525 } 573 }
526 ]; 574 ];
527 }; 575 };
528 }; 576 }
529 ]; 577 ];
530 }; 578 };
531 579
@@ -555,66 +603,65 @@ PreDown = iptables -F FORWARD
555 }; 603 };
556 }; 604 };
557 605
558 # TODO run nixfmt to fix indenting of below (can't right now because on gentoo without nixfmt)
559 wireplumber = { 606 wireplumber = {
560 enable = true; 607 enable = true;
561 extraConfig."50-smartfilters-airpods.conf".text = '' 608 extraConfig."50-smartfilters-airpods.conf".text = ''
562 { 609 {
563 "monitor.bluez.rules" : [ 610 "monitor.bluez.rules" : [
564 # When a BlueZ device is detected we set an identifying property that the smart filter will match. 611 # When a BlueZ device is detected we set an identifying property that the smart filter will match.
565 # (This fragment adds nothing by default; we're using a policy to match target.node later.) 612 # (This fragment adds nothing by default; we're using a policy to match target.node later.)
566 ], 613 ],
567 614
568 "policy.rules" : [ 615 "policy.rules" : [
569 # The core smart filter matching is done by matching the target.node properties 616 # The core smart filter matching is done by matching the target.node properties
570 # WirePlumber's smart filters will look for filter.smart.target (set below). 617 # WirePlumber's smart filters will look for filter.smart.target (set below).
571 ], 618 ],
572 619
573 "policy" : { 620 "policy" : {
574 "smart_filters" : { 621 "smart_filters" : {
575 "rules" : [ 622 "rules" : [
623 {
624 "matches" : [
625 { "device.props" : { "bluez5.device.name" : "AirPods Pro 2" } }
626 ],
627 "actions" : {
628 # If target device matches, set the 'target.node' metadata for smart filters to use
629 "update-metadata" : {
630 "target.node" : { "name" : "bluez_output.*AirPods.*" }
631 }
632 }
633 }
634 ]
635 }
636 },
637
638 "endpoint.rules" : [
576 { 639 {
577 "matches" : [ 640 "matches" : [
578 { "device.props" : { "bluez5.device.name" : "AirPods Pro 2" } } 641 { "node.name" : "peq-airpods-pro-2-sink" }
579 ], 642 ],
580 "actions" : { 643 "actions" : {
581 # If target device matches, set the 'target.node' metadata for smart filters to use 644 "update-props" : {
582 "update-metadata" : { 645 # Mark this WF sink as intended for a specific target device.
583 "target.node" : { "name" : "bluez_output.*AirPods.*" } 646 # WirePlumber will use filter.smart.target to identify which device to chain to.
647 "filter.smart.target" : { "bluez5.device.name" : "AirPods Pro 2" }
648 }
649 }
650 },
651 {
652 "matches" : [
653 { "node.name" : "peq-he5xx-sink" }
654 ],
655 "actions" : {
656 "update-props" : {
657 # He5xx is a generic filter (no specific bluez target) — it could be matched by other rules.
658 "filter.smart.target" : {}
584 } 659 }
585 } 660 }
586 } 661 }
587 ] 662 ]
588 } 663 }
589 }, 664 '';
590
591 "endpoint.rules" : [
592 {
593 "matches" : [
594 { "node.name" : "peq-airpods-pro-2-sink" }
595 ],
596 "actions" : {
597 "update-props" : {
598 # Mark this WF sink as intended for a specific target device.
599 # WirePlumber will use filter.smart.target to identify which device to chain to.
600 "filter.smart.target" : { "bluez5.device.name" : "AirPods Pro 2" }
601 }
602 }
603 },
604 {
605 "matches" : [
606 { "node.name" : "peq-he5xx-sink" }
607 ],
608 "actions" : {
609 "update-props" : {
610 # He5xx is a generic filter (no specific bluez target) — it could be matched by other rules.
611 "filter.smart.target" : {}
612 }
613 }
614 }
615 ]
616 }
617 '';
618 }; 665 };
619 }; 666 };
620 667
@@ -1106,10 +1153,22 @@ PreDown = iptables -F FORWARD
1106 }; 1153 };
1107 1154
1108 # extra systemd stuff 1155 # extra systemd stuff
1109 systemd.services.nginx = { 1156 systemd.services = {
1110 after = [ "wg-quick@wg1.service" ]; 1157 nginx = {
1111 requires = [ "wg-quick@wg1.service" ]; 1158 after = [ "wireguard-wg1.service" ];
1112 serviceConfig.Type = lib.mkForce "idle"; 1159 requires = [ "wireguard-wg1.service" ];
1160 serviceConfig.Type = lib.mkForce "idle";
1161 };
1162
1163 wireguard-wg0 = {
1164 after = [ "network-addresses-eth0.service" ];
1165 requires = [ "network-addresses-eth0.service" ];
1166 };
1167
1168 wireguard-wg1 = {
1169 after = [ "wireguard-wg0.service" ];
1170 requires = [ "wireguard-wg0.service" ];
1171 };
1113 }; 1172 };
1114 1173
1115 # create caches and use mandoc 1174 # create caches and use mandoc
diff --git a/hosts/demiurge/hardware.nix b/hosts/demiurge/hardware.nix
index 21d7ab3..5fa707c 100644
--- a/hosts/demiurge/hardware.nix
+++ b/hosts/demiurge/hardware.nix
@@ -51,14 +51,8 @@
51 options = [ "zfsutil" ]; 51 options = [ "zfsutil" ];
52 }; 52 };
53 53
54 fileSystems."/data" = {
55 device = "nvme_warm";
56 fsType = "zfs";
57 options = [ "zfsutil" ];
58 };
59
60 fileSystems."/boot" = { 54 fileSystems."/boot" = {
61 device = "/dev/disk/by-uuid/1C01-EE5C"; 55 device = "/dev/disk/by-uuid/B259-F128";
62 fsType = "vfat"; 56 fsType = "vfat";
63 options = [ 57 options = [
64 "fmask=0022" 58 "fmask=0022"