🏡 my personal home lab
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

we got things runnin

+109 -82
+9 -5
flake.nix
··· 33 33 34 34 hosts = { 35 35 cm4-node-1 = { 36 - ip = "10.0.0.11"; 36 + ipv4 = "10.0.0.11"; 37 + ipv6 = "2a02:168:7353::68f"; 37 38 hardware = nixos-hardware.nixosModules.raspberry-pi-4; 38 39 }; 39 40 cm4-node-2 = { 40 - ip = "10.0.0.12"; 41 + ipv4 = "10.0.0.12"; 42 + ipv6 = "2a02:168:7353::6f8"; 41 43 hardware = nixos-hardware.nixosModules.raspberry-pi-4; 42 44 }; 43 45 rk1-node-1 = { 44 - ip = "10.0.0.13"; 46 + ipv4 = "10.0.0.13"; 47 + ipv6 = "2a02:168:7353::7bf"; 45 48 hardware = turing-rk1.nixosModules.turing-rk1; 46 49 }; 47 50 rk1-node-2 = { 48 - ip = "10.0.0.14"; 51 + ipv4 = "10.0.0.14"; 52 + ipv6 = "2a02:168:7353::708"; 49 53 hardware = turing-rk1.nixosModules.turing-rk1; 50 54 }; 51 55 }; ··· 65 69 }; 66 70 67 71 mkDeploy = name: host: { 68 - hostname = host.ip; 72 + hostname = host.ipv4; 69 73 profiles.system = { 70 74 sshUser = "root"; 71 75 user = "root";
+1 -1
hosts/cm4-node-1.nix
··· 5 5 ../modules/common.nix 6 6 ../modules/tailscale.nix 7 7 ../modules/caddy.nix 8 - ../modules/ddclient.nix 8 + ../modules/dyndns.nix 9 9 ]; 10 10 11 11 system.stateVersion = "23.11";
+8 -21
modules/caddy.nix
··· 1 1 { 2 2 config, 3 - hosts, 4 3 ... 5 4 }: 6 5 { ··· 11 10 grace_period 1m 12 11 ''; 13 12 virtualHosts = { 14 - "(acme_tls)".extraConfig = '' 13 + "(goo_garden_cert)".extraConfig = '' 15 14 tls ${config.security.acme.certs."goo.garden".directory}/fullchain.pem ${ 16 15 config.security.acme.certs."goo.garden".directory 17 16 }/key.pem 18 17 ''; 19 18 "goo.garden".extraConfig = '' 20 - import acme_tls 19 + import goo_garden_cert 21 20 22 21 handle /.well-known/matrix/server { 23 22 header Content-Type application/json ··· 34 33 } 35 34 ''; 36 35 "*.goo.garden".extraConfig = '' 37 - import acme_tls 36 + import goo_garden_cert 38 37 abort 39 38 ''; 40 39 "matrix.goo.garden".extraConfig = '' 41 - reverse_proxy ${hosts.cm4-node-2.ip}:6167 42 - ''; 43 - "mumble.goo.garden:64738".extraConfig = '' 44 - reverse_proxy ${hosts.cm4-node-2.ip}:64738 40 + reverse_proxy cm4-node-2:6167 45 41 ''; 46 42 }; 47 43 }; ··· 52 48 reloadServices = [ "caddy" ]; 53 49 }; 54 50 55 - networking.firewall = { 56 - allowedTCPPorts = [ 57 - 80 58 - 443 59 - 60 - # mumble 61 - 64738 62 - ]; 63 - allowedUDPPorts = [ 64 - # mumble 65 - 64738 66 - ]; 67 - }; 51 + networking.firewall.allowedTCPPorts = [ 52 + 80 53 + 443 54 + ]; 68 55 }
+21 -10
modules/common.nix
··· 1 1 { 2 2 config, 3 3 name, 4 + lib, 5 + hosts, 4 6 pkgs, 5 7 ... 6 8 }: 7 9 8 10 { 9 - # set name from flake host list 10 - networking.hostName = name; 11 - 12 11 nixpkgs.config.allowUnfree = true; 13 - 14 12 nix.settings.experimental-features = [ 15 13 "nix-command" 16 14 "flakes" ··· 29 27 vim 30 28 btop 31 29 ]; 32 - 33 - networking.networkmanager.enable = true; 34 30 35 31 # Enable the OpenSSH daemon. 36 32 services.openssh = { ··· 39 35 settings.PermitRootLogin = "prohibit-password"; 40 36 }; 41 37 42 - networking.nftables.enable = true; 43 - networking.firewall = { 44 - enable = true; 45 - allowedTCPPorts = [ 22 ]; 38 + networking = { 39 + networkmanager.enable = true; 40 + 41 + # set name from flake host list 42 + hostName = name; 43 + 44 + # generate /etc/hosts entries for all nodes 45 + hosts = lib.mkMerge ( 46 + lib.mapAttrsToList (hostname: host: { 47 + ${host.ipv4} = [ hostname ]; 48 + ${host.ipv6} = [ hostname ]; 49 + }) hosts 50 + ); 51 + 52 + nftables.enable = true; 53 + firewall = { 54 + enable = true; 55 + allowedTCPPorts = [ 22 ]; 56 + }; 46 57 }; 47 58 48 59 security.acme = {
-25
modules/ddclient.nix
··· 1 - { 2 - config, 3 - ... 4 - }: 5 - let 6 - tld = "goo.garden"; 7 - in 8 - { 9 - services.ddclient = { 10 - enable = true; 11 - ssl = true; 12 - interval = "10min"; 13 - protocol = "dyndns2"; 14 - server = "update.dedyn.io"; 15 - 16 - usev4 = "webv4, webv4=https://checkipv4.dedyn.io/"; 17 - usev6 = "webv6, webv6=https://checkipv6.dedyn.io/"; 18 - 19 - username = tld; 20 - passwordFile = config.sops.secrets.desec-dyndns-token.path; 21 - domains = [ tld ]; 22 - }; 23 - 24 - sops.secrets.desec-dyndns-token = { }; 25 - }
+64
modules/dyndns.nix
··· 1 + { 2 + config, 3 + pkgs, 4 + lib, 5 + ... 6 + }: 7 + let 8 + tld = "goo.garden"; 9 + dyndnsDomains = [ 10 + tld 11 + "mumble.${tld}" 12 + ]; 13 + in 14 + { 15 + systemd.services.dyndns-update = { 16 + description = "Update deSEC DynDNS"; 17 + after = [ "network-online.target" ]; 18 + wants = [ "network-online.target" ]; 19 + serviceConfig = { 20 + Type = "oneshot"; 21 + DynamicUser = true; 22 + StateDirectory = "dyndns-update"; 23 + LoadCredential = "token:${config.sops.secrets.desec-dyndns-token.path}"; 24 + }; 25 + script = '' 26 + CACHE_FILE="$STATE_DIRECTORY/last-ip" 27 + TOKEN=$(cat "$CREDENTIALS_DIRECTORY/token") 28 + 29 + CURRENT_IP=$(${pkgs.curl}/bin/curl -4 -sf https://checkipv4.dedyn.io/) 30 + 31 + if [ -z "$CURRENT_IP" ]; then 32 + echo "Failed to get current IP" 33 + exit 1 34 + fi 35 + 36 + LAST_IP="" 37 + if [ -f "$CACHE_FILE" ]; then 38 + LAST_IP=$(cat "$CACHE_FILE") 39 + fi 40 + 41 + if [ "$CURRENT_IP" = "$LAST_IP" ]; then 42 + echo "IP unchanged ($CURRENT_IP), skipping update" 43 + exit 0 44 + fi 45 + 46 + echo "IP changed: $LAST_IP -> $CURRENT_IP, updating..." 47 + ${pkgs.curl}/bin/curl -4 -sf --ssl-reqd \ 48 + "https://update.dedyn.io/update?hostname=${lib.concatStringsSep "," dyndnsDomains}&myipv4=$CURRENT_IP&myipv6=preserve" \ 49 + -H "Authorization: Token $TOKEN" 50 + 51 + echo "$CURRENT_IP" > "$CACHE_FILE" 52 + ''; 53 + }; 54 + 55 + systemd.timers.dyndns-update = { 56 + wantedBy = [ "timers.target" ]; 57 + timerConfig = { 58 + OnBootSec = "1min"; 59 + OnUnitActiveSec = "10min"; 60 + }; 61 + }; 62 + 63 + sops.secrets.desec-dyndns-token = { }; 64 + }
+1 -1
modules/matrix.nix
··· 1 - { config, pkgs, ... }: 1 + { ... }: 2 2 { 3 3 services.matrix-continuwuity = { 4 4 enable = true;
+2 -1
modules/mumble.nix
··· 3 3 services.murmur = { 4 4 enable = true; 5 5 openFirewall = true; 6 + hostName = ""; # binds all 6 7 port = 64738; 7 8 environmentFile = config.sops.secrets.mumble-env.path; 8 9 9 - hostName = "mumble.goo.garden"; 10 + registerHostname = "mumble.goo.garden"; 10 11 registerName = "📞 mumble.goo.garden"; 11 12 welcometext = "more like John Goo"; 12 13
-15
secrets/caddy.env
··· 1 - DESEC_ACME_TOKEN=ENC[AES256_GCM,data:2T3zS1LIM/ML1lD8UULhgVG0U0zyd+HYyEA12A==,iv:jCQHSzWRrAyV2OOONiPsY/y/TPt6/0XR3XVl5dQuq2w=,tag:u9tmmN6wJt+NSknt4WqqOQ==,type:str] 2 - sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWNjREcm5NcmRnd1c3V2dW\ndjkxK2FZdndyUzFrblJsVm83Snc3NUhiTWdVClpCK0dKTXJMUU9VQUtJUTBUc3Fw\ncEZJSXVTbitOaS9NQ0pVb1pNdG9TSFEKLS0tIEZGeEpSek53LzQweml0bExwVkI3\nWGM3OEJvcXlvcGNrbEpyOUN1YThrdEEKI6dcjKVr/fKNKF+vwFevY71cSl3bJz0Y\npxdoZwf1SMv05m26ounrE159WIAPaNWaWYamdmxarMbsaAZtHP7wMA==\n-----END AGE ENCRYPTED FILE-----\n 3 - sops_age__list_0__map_recipient=age1ukx4wxssue9d5y72tt7wk0nqg86wjhcnsy80ky0kkwf5m8p72a7su87kf3 4 - sops_age__list_1__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpaEhUL2Y4TTZaZVU5ZDRL\nNFMxSnhDelZ2Mk1vYU1PL1hpUkl6Wnp4aUVRCm0wUS90T1o2cWg0bnI5TjVaNlNu\nMHRnb20rbTVtaW5QVXU5NjlLMXE1dncKLS0tIHVzYnJ3ajhuNXI2ZCtoRGxaYXFv\nOWVXWnNPK1ZKcXp3ai8zUmwvaENGMlkKU1Yolq9r/ZbmmKqupdsK0iqMmco0LKRK\npcSUeN01bUQx6CdH3MpvLtlRwgvI+CjHMg5VvAZhRm1mep9Bu7STdg==\n-----END AGE ENCRYPTED FILE-----\n 5 - sops_age__list_1__map_recipient=age1hnzrlvwx7ej6yyg8uvuwmx0vln37n554ksp6ryarne2qhqm2ggxqta3sra 6 - sops_age__list_2__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkNDdvemgzeUJpN3BWMXVu\nSFZvb0hhNzlINEZNOEhNTklTNDA1TVZxbUJZCnUva1hhVjdBbndZTWxmcUJoeUN6\neEl1MnJ2TGFhWUdOOFRjeXczOHFJemsKLS0tIDc5czlDQjZQenhPczNZMHdqaSs2\nREF3aTNvTTB5NHgrQi9PeTlNcGo5VGcKNfK3sivq9AtXUYkSsuiDMWsjaDXsYJ9B\n7emGcphgU0654xllbUyDYmNPXlCUmiuYGdeq+4IwDfiA2AjIOrAPpg==\n-----END AGE ENCRYPTED FILE-----\n 7 - sops_age__list_2__map_recipient=age1yk9d90hd37thd3w56urke49jdat6yehfj6dsh3m77y3edpy0pppsp5s7wj 8 - sops_age__list_3__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4c2xIM1dsUkh3ZndKaFMr\nYzJORzhadzNydGNjT0JDTytMUDc1KzdHc1ZrCkg3NWF0bExUVEh5RDRnVUVXSHpq\nY1gwS3poeGpLVEd4elZNdkFJN3pKcVUKLS0tIFhMKzlQQUFOckx3WjI4eUk3L0V3\nbjJJREhPa1hLL1RhYzB2NWxRc1BsaEkKZKH1Wvkmrz8gNMBz8sqHoWrBGi4zjFCt\nTUVIEjy1eJ30sHN9yrM/UlUc0wUKnZqgWpWYSGC3RSmDpyjwf8oGqw==\n-----END AGE ENCRYPTED FILE-----\n 9 - sops_age__list_3__map_recipient=age1h2due5w4mfp9es3p34znk8yujn73n856jrypnwkaszaf66tpma4qv7wajq 10 - sops_age__list_4__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2aTVTT3dsMHJJY1ZWOGs0\nMld1dWNFdVJrY0dCWVlNNE82WHlYODgvRWpRClJxa0pJVmZ0YVVsMFQ3YVByODRz\nbmJTMVAzcGlCRzhYakNzOWpNY1NRUkkKLS0tIE5MaDNsM2RmTEpLOHlJbXY1U21v\nSzhuMUVzNHNJTEFsTkplTXk2YWJITm8KzeNpqbStY6blpjPq3L17e8vJ9/W7Qe4i\nv5n/NnRx8fqJPSNMpjg2QxMnKcYgSe5UZ3MM+bGlcF2oZFPUCvLHww==\n-----END AGE ENCRYPTED FILE-----\n 11 - sops_age__list_4__map_recipient=age1m8hxem565mprflphn5e3yrwxdsz3q06x4nzc6xpju0y6knudfuwsz2g8w2 12 - sops_lastmodified=2026-02-11T16:13:37Z 13 - sops_mac=ENC[AES256_GCM,data:hLZ0Z6psu0HG2DRxLG0UnCIF16UQsqyeef9H03cUjuD37sraE5RRptXn+DgDNorSk54hGZudaIYIly270FJxgKjFQ1GpqvHgdgXouvq2zzHK1B9QEDilDhNu4NrNkeANbb5FW9QDfYlBAMx0q2A4aa7QldKkP0zzZyG1t5+8QSE=,iv:VJmFr6dURPbbONhxBQdmTFFhn/lt+/s4Ebmre+94F6A=,tag:cKa9fEIFJKkJzgrfMJnLeA==,type:str] 14 - sops_unencrypted_suffix=_unencrypted 15 - sops_version=3.11.0
+3 -3
secrets/secrets.yaml
··· 1 - desec-dyndns-token: ENC[AES256_GCM,data:8LFSK6fGrIaznn+s9ldxNdYXE/34NwyeMhZ9vw==,iv:Ro5BWqXPKBCSNt/oUMJbSaEoOsDMt0e4JSADU0S8w4A=,tag:GQXZA+Yj4zT4NqGezgZh5g==,type:str] 2 1 desec-acme-token: ENC[AES256_GCM,data:ou543u/k1uWC5Xg54K/7Q/mZnVdN7GIEea0/iA==,iv:TEPB708bn7uijs+r2Ekn3lQPw7rEdnMiJ53p3CFTwhw=,tag:10qQXFS3aVOKcx6Erxde3A==,type:str] 2 + desec-dyndns-token: ENC[AES256_GCM,data:RBh4TQNGURLTVCWN4EfarbL92AYTLVf94mStzw==,iv:KtbrVBKjw3J5mNBaLnDx9P4I/V7jXvMPLVKwz9ifFiM=,tag:eufB9+NiZWPzUdYsOOg3MQ==,type:str] 3 3 sops: 4 4 age: 5 5 - recipient: age1ukx4wxssue9d5y72tt7wk0nqg86wjhcnsy80ky0kkwf5m8p72a7su87kf3 ··· 47 47 cXdka1dhbXUzbDRsTlhUbGRsVXlzNjgK1iD6hVbUpwRonRzgo/eeLECI9SB4mduW 48 48 1RejiCfpGsA55eeiohD9s7fK/5bAb67xDQZRGZqa/H4brNz/v7+yRA== 49 49 -----END AGE ENCRYPTED FILE----- 50 - lastmodified: "2026-02-11T16:13:56Z" 51 - mac: ENC[AES256_GCM,data:mxvAZ6VnZD51RRPyGEHPD5i9CiZEUuCQ7mgWljtKUZdO6rCvexJeJX4S+6rJsMn4f0Vaw0ah7+iAA3+BMo77UYVeIOZ3sqziy/m0KxQIRdrr9b/MOgnyvhg/EP4KeXcEr2zAXVSzmwKj/aORtWq4KEU4ffVXppy5N70yA2UVU2M=,iv:L4vNOMbswjHNalSDaly61j1x0RllSnq2+q6LnHQ5yfg=,tag:Q6J0+dUYUaElsDWtRJ+N3A==,type:str] 50 + lastmodified: "2026-02-12T09:12:05Z" 51 + mac: ENC[AES256_GCM,data:x/6PADypayHyBhgpbxzlOc/dUFy7wYdtOWyOhNzM9UJy+9e/Nr2flj2nPk3OpEN6IhYZRcaoMGLZj1KW94YyfPrPRu0KQOlmcYqEnReLppEmvNIY3pFQv5dzJO7biNjVl3mw61e7/x5aZi1HKEEMxUztih8XIk7CbNEaChpSG+o=,iv:xujlQYK7ghcHPXtbVZtTyWEFFekaGoKTWQphvFP99aA=,tag:x/WffPkrh2EsQk7wo881Iw==,type:str] 52 52 unencrypted_suffix: _unencrypted 53 53 version: 3.11.0