forked from jan-leila/nix-config
		
	Compare commits
	
		
			63 commits
		
	
	
		
			8b3e0e296e
			...
			28a962d712
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 28a962d712 | |||
| 76d3c488db | |||
| 44922dfcd5 | |||
| 884d11d0a3 | |||
| 0730cc6594 | |||
| 2935d43bcb | |||
| bc705098d6 | |||
| 7483c2c01c | |||
| 2c918478ab | |||
| 03149db7ea | |||
| c9bb9380b5 | |||
| 21edda5fe6 | |||
| d4615fc435 | |||
| c10c610034 | |||
| 6dfe3ac326 | |||
| 0cb4c25467 | |||
| 178b414a0a | |||
| c8d994814f | |||
| 1d940fd8d8 | |||
| 24def1e3d3 | |||
| a8dfcb02c8 | |||
| d2be5c7e24 | |||
| a8139f4265 | |||
| f9fe74cc8a | |||
| 4d52c58f79 | |||
| ee80636b2b | |||
| d35e2c93c1 | |||
| ca6de5c0cd | |||
| 2cdc39f3dc | |||
| 333c68a8cd | |||
| 7e6fa744af | |||
| 3bee0c7402 | |||
| 1b1a3f7219 | |||
| e2e07c9a70 | |||
| 9b02e30080 | |||
| dfdd6bcc82 | |||
| cdeb4e108b | |||
| b2e5ae1f98 | |||
| 01325c3068 | |||
| dbd5d36913 | |||
| 0f87d78271 | |||
| c0579f55dc | |||
| 1d0f51c70a | |||
| 376cb934c3 | |||
| 84b204f8b1 | |||
| 52801b4bb7 | |||
| 663bdcc012 | |||
| 88dcba346f | |||
| 22b9c5b3f9 | |||
| 3bf3391eb9 | |||
| ffcba0d714 | |||
| 0f8faadd80 | |||
| cf330b1cbb | |||
| ca9f54d795 | |||
| 2745af9443 | |||
| 487dc21550 | |||
| 58fec3f132 | |||
| 09d2588406 | |||
| 68b791f7c1 | |||
| 1831fea96a | |||
| 2aad75a334 | |||
| c31eb38229 | |||
| fab03391fc | 
					 118 changed files with 6316 additions and 971 deletions
				
			
		
							
								
								
									
										41
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										41
									
								
								README.md
									
										
									
									
									
								
							|  | @ -7,19 +7,19 @@ nix multi user, multi system, configuration with `sops` secret management, `home | ||||||
| # Hosts | # Hosts | ||||||
| 
 | 
 | ||||||
| ## Host Map | ## Host Map | ||||||
| |   Hostname  |      Device Description    |   Primary User   |    Role   | | |   Hostname  |      Device Description    |   Primary User   |    Role   | Provisioned | Using Nix | | ||||||
| | :---------: | :------------------------: | :--------------: | :-------: | | | :---------: | :------------------------: | :--------------: | :-------: | :---------: | :-------: | | ||||||
| |  `twilight` |      Desktop Computer      |      Leyla       |  Desktop  | | |  `twilight` |      Desktop Computer      |      Leyla       |  Desktop  |     ✅      |    ✅     | | ||||||
| |  `horizon`  |  13 inch Framework Laptop  |      Leyla       |  Laptop   | | |  `horizon`  |  13 inch Framework Laptop  |      Leyla       |  Laptop   |     ✅      |    ✅     | | ||||||
| |  `defiant`  |         NAS Server         |      Leyla       |   Server  | | |  `defiant`  |         NAS Server         |      Leyla       |   Server  |     ✅      |    ✅     | | ||||||
| | `hesperium` |             Mac            |      ?????       |    ???    | | | `hesperium` |             Mac            |      ?????       |    Mac    |     ❌      |    ❌     | | ||||||
| |  `emergent` |      Desktop Computer      |       Eve        |  Desktop  | | |  `emergent` |      Desktop Computer      |       Eve        |  Desktop  |     ✅      |    ✅     | | ||||||
| | `threshold` |           Laptop           |       Eve        |  Laptop   | | | `threshold` |           Laptop           |       Eve        |  Laptop   |     ❌      |    ❌     | | ||||||
| |  `wolfram`  |         Steam Deck         |      House       |  Handheld | | |  `wolfram`  |          Steam Deck        |      House       |  Handheld |     ✅      |    ❌     | | ||||||
| |   `ceder`   | A5 Tablet (not using nix)  |      Leyla       |   Tablet  | | |   `ceder`   |          A5 Tablet         |      Leyla       |   Tablet  |     ✅      |    ❌     | | ||||||
| |   `skate`   | A6 Tablet (not using nix)  |      Leyla       |   Tablet  | | |   `skate`   |          A6 Tablet         |      Leyla       |   Tablet  |     ❌      |    ❌     | | ||||||
| |   `shale`   | A6 Tablet (not using nix)  |       Eve        |   Tablet  | | |   `shale`   |          A6 Tablet         |       Eve        |   Tablet  |     ✅      |    ❌     | | ||||||
| |   `coven`   |  Pixel 8 (not using nix)   |      Leyla       |  Android  | | |   `coven`   |           Pixel 8          |      Leyla       |  Android  |     ✅      |    ❌     | | ||||||
| 
 | 
 | ||||||
| # Tooling | # Tooling | ||||||
| ## Rebuilding | ## Rebuilding | ||||||
|  | @ -43,7 +43,6 @@ nix multi user, multi system, configuration with `sops` secret management, `home | ||||||
| - Look into this for auto rotating sops keys `https://technotim.live/posts/rotate-sops-encryption-keys/` | - Look into this for auto rotating sops keys `https://technotim.live/posts/rotate-sops-encryption-keys/` | ||||||
| - Look into this for npins https://jade.fyi/blog/pinning-nixos-with-npins/ | - Look into this for npins https://jade.fyi/blog/pinning-nixos-with-npins/ | ||||||
| - https://nixos-and-flakes.thiscute.world/ | - https://nixos-and-flakes.thiscute.world/ | ||||||
| - nix config mcp https://github.com/utensils/mcp-nixos |  | ||||||
| 
 | 
 | ||||||
| # Tasks: | # Tasks: | ||||||
| 
 | 
 | ||||||
|  | @ -67,4 +66,16 @@ nix multi user, multi system, configuration with `sops` secret management, `home | ||||||
| - rotate sops encryption keys periodically (and somehow sync between devices?) | - rotate sops encryption keys periodically (and somehow sync between devices?) | ||||||
| - wake on LAN for updates | - wake on LAN for updates | ||||||
| - remote distributed builds - https://nix.dev/tutorials/nixos/distributed-builds-setup.html | - remote distributed builds - https://nix.dev/tutorials/nixos/distributed-builds-setup.html | ||||||
| - ISO target that contains authorized keys for nixos-anywhere https://github.com/diegofariasm/yggdrasil/blob/4acc43ebc7bcbf2e41376d14268e382007e94d78/hosts/bootstrap/default.nix | - ISO target that contains authorized keys for nixos-anywhere https://github.com/diegofariasm/yggdrasil/blob/4acc43ebc7bcbf2e41376d14268e382007e94d78/hosts/bootstrap/default.nix | ||||||
|  | - panoramax instance | ||||||
|  | - mastodon instance | ||||||
|  | - rework the reverse_proxy.nix file so that it is a normally named service. Then also change it so that we can hook into it with both a base domain and a subdomain to make migrating to vpn accessible services easier | ||||||
|  | - move searx, home-assistant, actual, jellyfin, paperless, and immich to only be accessible via vpn | ||||||
|  | - make radarr, sonarr, and bazarr accessible over vpn | ||||||
|  | - create some sort of service that allows uploading files to jellyfin | ||||||
|  | 	- auto sort files into where they should go with some combination of filebot cli and picard cli | ||||||
|  | - graphana accessible though tailscale | ||||||
|  | - fix panoramax package | ||||||
|  | - actual instance | ||||||
|  | - intergrade radarr, sonarr, and bazarr | ||||||
|  | - claude code MCP servers should bundle node with them so they work in all environments | ||||||
|  |  | ||||||
|  | @ -8,5 +8,6 @@ | ||||||
| in { | in { | ||||||
|   leyla = lib.mkIf users.leyla.isNormalUser (import ./leyla); |   leyla = lib.mkIf users.leyla.isNormalUser (import ./leyla); | ||||||
|   eve = lib.mkIf users.eve.isNormalUser (import ./eve); |   eve = lib.mkIf users.eve.isNormalUser (import ./eve); | ||||||
|  |   ivy = lib.mkIf users.ivy.isNormalUser (import ./ivy); | ||||||
|   git = lib.mkIf (osConfig.services.forgejo.enable or false) (import ./git); |   git = lib.mkIf (osConfig.services.forgejo.enable or false) (import ./git); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -17,7 +17,6 @@ in { | ||||||
|     # See https://search.nixos.org/packages for all options |     # See https://search.nixos.org/packages for all options | ||||||
|     home.packages = lib.lists.optionals userConfig.isDesktopUser ( |     home.packages = lib.lists.optionals userConfig.isDesktopUser ( | ||||||
|       with pkgs; [ |       with pkgs; [ | ||||||
|         ungoogled-chromium |  | ||||||
|         gnomeExtensions.dash-to-panel |         gnomeExtensions.dash-to-panel | ||||||
|       ] |       ] | ||||||
|     ); |     ); | ||||||
|  | @ -61,6 +60,7 @@ in { | ||||||
|         steam.enable = true; |         steam.enable = true; | ||||||
|         piper.enable = hardware.piperMouse.enable; |         piper.enable = hardware.piperMouse.enable; | ||||||
|         krita.enable = true; |         krita.enable = true; | ||||||
|  |         ungoogled-chromium.enable = true; | ||||||
|       }) |       }) | ||||||
|     ]; |     ]; | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
							
								
								
									
										55
									
								
								configurations/home-manager/ivy/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								configurations/home-manager/ivy/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | ||||||
|  | {osConfig, ...}: let | ||||||
|  |   userConfig = osConfig.host.users.ivy; | ||||||
|  | in { | ||||||
|  |   imports = [ | ||||||
|  |     ./packages.nix | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   home = { | ||||||
|  |     username = userConfig.name; | ||||||
|  |     homeDirectory = osConfig.users.users.ivy.home; | ||||||
|  | 
 | ||||||
|  |     # This value determines the Home Manager release that your configuration is | ||||||
|  |     # compatible with. This helps avoid breakage when a new Home Manager release | ||||||
|  |     # introduces backwards incompatible changes. | ||||||
|  |     # | ||||||
|  |     # You should not change this value, even if you update Home Manager. If you do | ||||||
|  |     # want to update the value, then make sure to first check the Home Manager | ||||||
|  |     # release notes. | ||||||
|  |     stateVersion = "23.11"; # Please read the comment before changing. | ||||||
|  | 
 | ||||||
|  |     # Home Manager is pretty good at managing dotfiles. The primary way to manage | ||||||
|  |     # plain files is through 'home.file'. | ||||||
|  |     file = { | ||||||
|  |       # # Building this configuration will create a copy of 'dotfiles/screenrc' in | ||||||
|  |       # # the Nix store. Activating the configuration will then make '~/.screenrc' a | ||||||
|  |       # # symlink to the Nix store copy. | ||||||
|  |       # ".screenrc".source = dotfiles/screenrc; | ||||||
|  | 
 | ||||||
|  |       # # You can also set the file content immediately. | ||||||
|  |       # ".gradle/gradle.properties".text = '' | ||||||
|  |       #   org.gradle.console=verbose | ||||||
|  |       #   org.gradle.daemon.idletimeout=3600000 | ||||||
|  |       # ''; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     # Home Manager can also manage your environment variables through | ||||||
|  |     # 'home.sessionVariables'. If you don't want to manage your shell through Home | ||||||
|  |     # Manager then you have to manually source 'hm-session-vars.sh' located at | ||||||
|  |     # either | ||||||
|  |     # | ||||||
|  |     #  ~/.nix-profile/etc/profile.d/hm-session-vars.sh | ||||||
|  |     # | ||||||
|  |     # or | ||||||
|  |     # | ||||||
|  |     #  ~/.local/state/nix/profiles/profile/etc/profile.d/hm-session-vars.sh | ||||||
|  |     # | ||||||
|  |     # or | ||||||
|  |     # | ||||||
|  |     #  /etc/profiles/per-user/ivy/etc/profile.d/hm-session-vars.sh | ||||||
|  |     # | ||||||
|  |     sessionVariables = { | ||||||
|  |       # EDITOR = "emacs"; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										73
									
								
								configurations/home-manager/ivy/packages.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								configurations/home-manager/ivy/packages.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   config = { | ||||||
|  |     nixpkgs.config = { | ||||||
|  |       allowUnfree = true; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     # Programs that need to be installed with some extra configuration | ||||||
|  |     programs = lib.mkMerge [ | ||||||
|  |       { | ||||||
|  |         # Let Home Manager install and manage itself. | ||||||
|  |         home-manager.enable = true; | ||||||
|  |       } | ||||||
|  |       (lib.mkIf (config.user.isDesktopUser || config.user.isTerminalUser) { | ||||||
|  |         # git = { | ||||||
|  |         #   enable = true; | ||||||
|  |         #   userName = "Ivy"; | ||||||
|  |         #   userEmail = "ivy@example.com"; # Update this with actual email | ||||||
|  |         #   extraConfig.init.defaultBranch = "main"; | ||||||
|  |         # }; | ||||||
|  | 
 | ||||||
|  |         openssh = { | ||||||
|  |           enable = true; | ||||||
|  |           hostKeys = [ | ||||||
|  |             { | ||||||
|  |               type = "ed25519"; | ||||||
|  |               path = "${config.home.username}_${osConfig.networking.hostName}_ed25519"; | ||||||
|  |             } | ||||||
|  |           ]; | ||||||
|  |         }; | ||||||
|  |       }) | ||||||
|  |       (lib.mkIf config.user.isDesktopUser { | ||||||
|  |         vscode = { | ||||||
|  |           enable = true; | ||||||
|  |           package = pkgs.vscodium; | ||||||
|  |           mutableExtensionsDir = false; | ||||||
|  | 
 | ||||||
|  |           profiles.default = { | ||||||
|  |             enableUpdateCheck = false; | ||||||
|  |             enableExtensionUpdateCheck = false; | ||||||
|  | 
 | ||||||
|  |             extraExtensions = { | ||||||
|  |               # Cline extension (Claude AI assistant) | ||||||
|  |               claudeDev.enable = true; | ||||||
|  |               # Auto Rename Tag | ||||||
|  |               autoRenameTag.enable = true; | ||||||
|  |               # Live Server | ||||||
|  |               liveServer.enable = true; | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             extensions = let | ||||||
|  |               extension-pkgs = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version; | ||||||
|  |             in ( | ||||||
|  |               with extension-pkgs.open-vsx; [ | ||||||
|  |                 streetsidesoftware.code-spell-checker | ||||||
|  |               ] | ||||||
|  |             ); | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         firefox.enable = true; | ||||||
|  |         discord.enable = true; | ||||||
|  |         signal-desktop-bin.enable = true; | ||||||
|  |         claude-code.enable = true; | ||||||
|  |       }) | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | @ -37,6 +37,12 @@ in { | ||||||
|           dbeaver-bin.enable = true; |           dbeaver-bin.enable = true; | ||||||
|           bruno.enable = true; |           bruno.enable = true; | ||||||
|           piper.enable = hardware.piperMouse.enable; |           piper.enable = hardware.piperMouse.enable; | ||||||
|  |           proxmark3.enable = true; | ||||||
|  |           openrgb.enable = hardware.openRGB.enable; | ||||||
|  |           via.enable = hardware.viaKeyboard.enable; | ||||||
|  |           claude-code.enable = osConfig.host.ai.enable; | ||||||
|  |           davinci-resolve.enable = hardware.graphicsAcceleration.enable; | ||||||
|  |           mfoc.enable = true; | ||||||
|         }) |         }) | ||||||
|         (lib.mkIf (hardware.directAccess.enable && config.user.isDesktopUser) { |         (lib.mkIf (hardware.directAccess.enable && config.user.isDesktopUser) { | ||||||
|           anki.enable = true; |           anki.enable = true; | ||||||
|  | @ -50,6 +56,22 @@ in { | ||||||
|           firefox.enable = true; |           firefox.enable = true; | ||||||
|           steam.enable = true; |           steam.enable = true; | ||||||
|           krita.enable = true; |           krita.enable = true; | ||||||
|  |           ungoogled-chromium.enable = true; | ||||||
|  |           libreoffice.enable = true; | ||||||
|  |           mapillary-uploader.enable = true; | ||||||
|  |           inkscape.enable = true; | ||||||
|  |           gimp.enable = true; | ||||||
|  |           freecad.enable = true; | ||||||
|  |           onionshare.enable = true; | ||||||
|  |           pdfarranger.enable = true; | ||||||
|  |           picard.enable = true; | ||||||
|  |           qflipper.enable = true; | ||||||
|  |           openvpn.enable = true; | ||||||
|  |           noisetorch.enable = true; | ||||||
|  |           tor-browser.enable = true; | ||||||
|  |           gdx-liftoff.enable = true; | ||||||
|  |           # polycule package is now working with Flutter 3.29 | ||||||
|  |           polycule.enable = true; | ||||||
|         }) |         }) | ||||||
|       ]; |       ]; | ||||||
|     } |     } | ||||||
|  | @ -66,53 +88,6 @@ in { | ||||||
|       nixpkgs.config = { |       nixpkgs.config = { | ||||||
|         allowUnfree = true; |         allowUnfree = true; | ||||||
|       }; |       }; | ||||||
| 
 |  | ||||||
|       home.packages = ( |  | ||||||
|         (with pkgs; [ |  | ||||||
|           proxmark3 |  | ||||||
|         ]) |  | ||||||
|         ++ ( |  | ||||||
|           lib.lists.optionals hardware.directAccess.enable (with pkgs; [ |  | ||||||
|             #foss platforms |  | ||||||
|             ungoogled-chromium |  | ||||||
|             libreoffice |  | ||||||
|             inkscape |  | ||||||
|             gimp |  | ||||||
|             freecad |  | ||||||
|             # cura |  | ||||||
|             # kicad-small |  | ||||||
|             onionshare |  | ||||||
|             # rhythmbox |  | ||||||
| 
 |  | ||||||
|             # wireshark |  | ||||||
|             # rpi-imager |  | ||||||
|             # fritzing |  | ||||||
|             mfoc |  | ||||||
|             tor-browser |  | ||||||
|             pdfarranger |  | ||||||
|             picard |  | ||||||
| 
 |  | ||||||
|             gdx-liftoff |  | ||||||
| 
 |  | ||||||
|             # proprietary platforms |  | ||||||
|             (lib.mkIf hardware.graphicsAcceleration.enable davinci-resolve) |  | ||||||
| 
 |  | ||||||
|             # development tools |  | ||||||
|             # androidStudioPackages.canary |  | ||||||
|             qFlipper |  | ||||||
| 
 |  | ||||||
|             # system tools |  | ||||||
|             openvpn |  | ||||||
|             noisetorch |  | ||||||
| 
 |  | ||||||
|             # hardware management tools |  | ||||||
|             (lib.mkIf hardware.openRGB.enable openrgb) |  | ||||||
|             (lib.mkIf hardware.viaKeyboard.enable via) |  | ||||||
| 
 |  | ||||||
|             (lib.mkIf osConfig.host.ai.enable claude-code) |  | ||||||
|           ]) |  | ||||||
|         ) |  | ||||||
|       ); |  | ||||||
|     }) |     }) | ||||||
|   ]; |   ]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -71,13 +71,47 @@ in { | ||||||
|             claudeDev = lib.mkIf ai-tooling-enabled { |             claudeDev = lib.mkIf ai-tooling-enabled { | ||||||
|               enable = true; |               enable = true; | ||||||
|               mcp = { |               mcp = { | ||||||
|                 nixos.enable = true; |                 nixos = { | ||||||
|                 eslint.enable = true; |                   enable = true; | ||||||
|  |                   autoApprove = { | ||||||
|  |                     nixos_search = true; | ||||||
|  |                     nixos_info = true; | ||||||
|  |                     home_manager_search = true; | ||||||
|  |                     home_manager_info = true; | ||||||
|  |                     darwin_search = true; | ||||||
|  |                     darwin_info = true; | ||||||
|  |                     nixos_flakes_search = true; | ||||||
|  |                   }; | ||||||
|  |                 }; | ||||||
|  |                 eslint = { | ||||||
|  |                   enable = true; | ||||||
|  |                   autoApprove = { | ||||||
|  |                     lint-files = true; | ||||||
|  |                   }; | ||||||
|  |                 }; | ||||||
|  |                 vitest = { | ||||||
|  |                   enable = true; | ||||||
|  |                   autoApprove = { | ||||||
|  |                     list_tests = true; | ||||||
|  |                     run_tests = true; | ||||||
|  |                     analyze_coverage = true; | ||||||
|  |                     set_project_root = true; | ||||||
|  |                   }; | ||||||
|  |                 }; | ||||||
|  |                 sleep = { | ||||||
|  |                   enable = true; | ||||||
|  |                   timeout = 18000; # 5 hours to match claude codes timeout | ||||||
|  |                   autoApprove = { | ||||||
|  |                     sleep = true; | ||||||
|  |                   }; | ||||||
|  |                 }; | ||||||
|               }; |               }; | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             # misc extensions |             # misc extensions | ||||||
|             evenBetterToml.enable = true; |             evenBetterToml.enable = true; | ||||||
|  |             direnv.enable = config.programs.direnv.enable; | ||||||
|  |             conventionalCommits.enable = true; | ||||||
|           }; |           }; | ||||||
| 
 | 
 | ||||||
|           extensions = let |           extensions = let | ||||||
|  |  | ||||||
|  | @ -132,23 +132,24 @@ | ||||||
|         }; |         }; | ||||||
|       }; |       }; | ||||||
| 
 | 
 | ||||||
|       # "20-wg0" = { |       "20-wg0" = { | ||||||
|       #   netdevConfig = { |         netdevConfig = { | ||||||
|       #     Kind = "wireguard"; |           Kind = "wireguard"; | ||||||
|       #     Name = "wg0"; |           Name = "wg0"; | ||||||
|       #   }; |         }; | ||||||
|       #   wireguardConfig = { |         wireguardConfig = { | ||||||
|       #     PrivateKeyFile = config.sops.secrets."vpn-keys/proton-wireguard/defiant-p2p".path; |           PrivateKeyFile = config.sops.secrets."vpn-keys/proton-wireguard/defiant-p2p".path; | ||||||
|       #     ListenPort = 51820; |           ListenPort = 51820; | ||||||
|       #   }; |         }; | ||||||
|       #   wireguardPeers = [ |         wireguardPeers = [ | ||||||
|       #     { |           { | ||||||
|       #       PublicKey = "rRO6yJim++Ezz6scCLMaizI+taDjU1pzR2nfW6qKbW0="; |             PublicKey = "rRO6yJim++Ezz6scCLMaizI+taDjU1pzR2nfW6qKbW0="; | ||||||
|       #       Endpoint = "185.230.126.146:51820"; |             Endpoint = "185.230.126.146:51820"; | ||||||
|       #       AllowedIPs = ["0.0.0.0/0"]; |             # Allow all traffic but use policy routing to prevent system-wide VPN | ||||||
|       #     } |             AllowedIPs = ["0.0.0.0/0"]; | ||||||
|       #   ]; |           } | ||||||
|       # }; |         ]; | ||||||
|  |       }; | ||||||
|     }; |     }; | ||||||
|     networks = { |     networks = { | ||||||
|       "40-bond0" = { |       "40-bond0" = { | ||||||
|  | @ -163,36 +164,67 @@ | ||||||
|           "192.168.1.10/32" |           "192.168.1.10/32" | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         gateway = ["192.168.1.1"]; |         # Set lower priority for default gateway to allow WireGuard interface binding | ||||||
|  |         routes = [ | ||||||
|  |           { | ||||||
|  |             Destination = "0.0.0.0/0"; | ||||||
|  |             Gateway = "192.168.1.1"; | ||||||
|  |             Metric = 100; | ||||||
|  |           } | ||||||
|  |         ]; | ||||||
|         dns = ["192.168.1.1"]; |         dns = ["192.168.1.1"]; | ||||||
|       }; |       }; | ||||||
| 
 | 
 | ||||||
|       # For some reason this isn't working. It looks like traffic goes out and comes back but doesn't get correctly routed back to the wg interface on the return trip |       "50-wg0" = { | ||||||
|       # debugging steps: |         matchConfig.Name = "wg0"; | ||||||
|       # try sending data on the interface `ping -I wg0 8.8.8.8` |         networkConfig = { | ||||||
|       # view all traffic on the interface `sudo tshark -i wg0` |           DHCP = "no"; | ||||||
|       # see what applications are listening to port 14666 (thats what we currently have qbittorent set up to use) `ss -tuln | grep 14666` |         }; | ||||||
|       # "50-wg0" = { |         address = [ | ||||||
|       #   matchConfig.Name = "wg0"; |           "10.2.0.2/32" | ||||||
|       #   networkConfig = { |         ]; | ||||||
|       #     DHCP = "no"; |         # Configure routing for application binding | ||||||
|       #   }; |         routingPolicyRules = [ | ||||||
|       #   address = [ |           { | ||||||
|       #     "10.2.0.2/32" |             # Route traffic from VPN interface through VPN table | ||||||
|       #   ]; |             From = "10.2.0.2/32"; | ||||||
|       #   # routes = [ |             Table = 200; | ||||||
|       #   #   { |             Priority = 100; | ||||||
|       #   #     Destination = "10.2.0.2/32"; |           } | ||||||
|       #   #     Gateway = "10.2.0.1"; |         ]; | ||||||
|       #   #   } |         routes = [ | ||||||
|       #   # ]; |           { | ||||||
|       # }; |             # Direct route to VPN gateway | ||||||
|  |             Destination = "10.2.0.1/32"; | ||||||
|  |             Scope = "link"; | ||||||
|  |           } | ||||||
|  |           { | ||||||
|  |             # Route VPN subnet through VPN gateway in custom table | ||||||
|  |             Destination = "10.2.0.0/16"; | ||||||
|  |             Gateway = "10.2.0.1"; | ||||||
|  |             Table = 200; | ||||||
|  |           } | ||||||
|  |           { | ||||||
|  |             # Route all traffic through VPN gateway in custom table | ||||||
|  |             Destination = "0.0.0.0/0"; | ||||||
|  |             Gateway = "10.2.0.1"; | ||||||
|  |             Table = 200; | ||||||
|  |           } | ||||||
|  |         ]; | ||||||
|  |       }; | ||||||
|     }; |     }; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   # limit arc usage to 50gb because ollama doesn't play nice with zfs using up all of the memory |   # limit arc usage to 50gb because ollama doesn't play nice with zfs using up all of the memory | ||||||
|   boot.kernelParams = ["zfs.zfs_arc_max=53687091200"]; |   boot.kernelParams = ["zfs.zfs_arc_max=53687091200"]; | ||||||
| 
 | 
 | ||||||
|  |   # Enable policy routing and source routing for application-specific VPN binding | ||||||
|  |   boot.kernel.sysctl = { | ||||||
|  |     "net.ipv4.conf.all.rp_filter" = 2; | ||||||
|  |     "net.ipv4.conf.default.rp_filter" = 2; | ||||||
|  |     "net.ipv4.conf.wg0.rp_filter" = 2; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|   services = { |   services = { | ||||||
|     # temp enable desktop environment for setup |     # temp enable desktop environment for setup | ||||||
|     # Enable the X11 windowing system. |     # Enable the X11 windowing system. | ||||||
|  | @ -306,12 +338,35 @@ | ||||||
|       passwordFile = config.sops.secrets."services/paperless_password".path; |       passwordFile = config.sops.secrets."services/paperless_password".path; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     panoramax = { | ||||||
|  |       enable = false; | ||||||
|  |       openFirewall = true; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     qbittorrent = { |     qbittorrent = { | ||||||
|       enable = true; |       enable = true; | ||||||
|       mediaDir = "/srv/qbittorent"; |       mediaDir = "/srv/qbittorent"; | ||||||
|       openFirewall = true; |       openFirewall = true; | ||||||
|       webuiPort = 8084; |       webuiPort = 8084; | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|  |     filebot-cleanup = { | ||||||
|  |       enable = true; | ||||||
|  |       licenseFile = "/srv/jellyfin/filebot_license.psm"; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     sonarr = { | ||||||
|  |       enable = false; | ||||||
|  |       openFirewall = true; | ||||||
|  |     }; | ||||||
|  |     radarr = { | ||||||
|  |       enable = false; | ||||||
|  |       openFirewall = true; | ||||||
|  |     }; | ||||||
|  |     bazarr = { | ||||||
|  |       enable = false; | ||||||
|  |       openFirewall = true; | ||||||
|  |     }; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   # disable computer sleeping |   # disable computer sleeping | ||||||
|  |  | ||||||
|  | @ -3,5 +3,7 @@ | ||||||
|   imports = [ |   imports = [ | ||||||
|     ./hardware-configuration.nix |     ./hardware-configuration.nix | ||||||
|     ./configuration.nix |     ./configuration.nix | ||||||
|  |     ./packages.nix | ||||||
|  |     ./filebot.nix | ||||||
|   ]; |   ]; | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										82
									
								
								configurations/nixos/defiant/filebot.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								configurations/nixos/defiant/filebot.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,82 @@ | ||||||
|  | { | ||||||
|  |   config, | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   ... | ||||||
|  | }: | ||||||
|  | with lib; let | ||||||
|  |   cfg = config.services.filebot-cleanup; | ||||||
|  | in { | ||||||
|  |   options.services.filebot-cleanup = { | ||||||
|  |     enable = mkEnableOption "Filebot cleanup service"; | ||||||
|  | 
 | ||||||
|  |     licenseFile = mkOption { | ||||||
|  |       type = types.nullOr types.path; | ||||||
|  |       default = null; | ||||||
|  |       description = "Path to the Filebot license file"; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     cleanupDirectory = mkOption { | ||||||
|  |       type = types.str; | ||||||
|  |       default = "/srv/jellyfin/filebot_cleanup"; | ||||||
|  |       description = "Directory where cleaned up media files are stored"; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = mkIf cfg.enable { | ||||||
|  |     users.groups.filebot_cleanup = {}; | ||||||
|  |     users.users.filebot_cleanup = { | ||||||
|  |       isSystemUser = true; | ||||||
|  |       group = "filebot_cleanup"; | ||||||
|  |       extraGroups = ["jellyfin_media"]; | ||||||
|  |       home = cfg.cleanupDirectory; | ||||||
|  |       createHome = true; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     nixpkgs.config.allowUnfreePredicate = pkg: | ||||||
|  |       builtins.elem (lib.getName pkg) [ | ||||||
|  |         "filebot" | ||||||
|  |       ]; | ||||||
|  | 
 | ||||||
|  |     environment.systemPackages = with pkgs; [ | ||||||
|  |       filebot | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     systemd.services.filebot-cleanup = { | ||||||
|  |       description = "Filebot media cleanup service"; | ||||||
|  |       serviceConfig = { | ||||||
|  |         Type = "simple"; | ||||||
|  |         User = "filebot_cleanup"; | ||||||
|  |         Group = "filebot_cleanup"; | ||||||
|  |         ExecStart = pkgs.writeShellScript "filebot-cleanup" '' | ||||||
|  |           ${optionalString (cfg.licenseFile != null) '' | ||||||
|  |             ${pkgs.filebot}/bin/filebot --license "${cfg.licenseFile}" | ||||||
|  |           ''} | ||||||
|  |           ${pkgs.filebot}/bin/filebot -rename -r "/srv/jellyfin/media/Movies/" --output "${cfg.cleanupDirectory}/" --format "{jellyfin}" -non-strict --action duplicate | ||||||
|  |           ${pkgs.filebot}/bin/filebot -rename -r "/srv/jellyfin/media/Shows/" --output "${cfg.cleanupDirectory}/" --format "{jellyfin}" -non-strict --action duplicate | ||||||
|  |         ''; | ||||||
|  |         StandardOutput = "journal"; | ||||||
|  |         StandardError = "journal"; | ||||||
|  |       }; | ||||||
|  |       wantedBy = ["multi-user.target"]; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     environment.persistence = lib.mkIf config.host.impermanence.enable { | ||||||
|  |       "/persist/system/jellyfin" = { | ||||||
|  |         enable = true; | ||||||
|  |         hideMounts = true; | ||||||
|  |         files = [ | ||||||
|  |           cfg.licenseFile | ||||||
|  |         ]; | ||||||
|  |         directories = [ | ||||||
|  |           { | ||||||
|  |             directory = cfg.cleanupDirectory; | ||||||
|  |             user = "filebot_cleanup"; | ||||||
|  |             group = "filebot_cleanup"; | ||||||
|  |             mode = "1770"; | ||||||
|  |           } | ||||||
|  |         ]; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								configurations/nixos/defiant/packages.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								configurations/nixos/defiant/packages.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | {pkgs, ...}: { | ||||||
|  |   environment.systemPackages = with pkgs; [ | ||||||
|  |     ffsubsync | ||||||
|  |     sox | ||||||
|  |     yt-dlp | ||||||
|  |     ffmpeg | ||||||
|  |     imagemagick | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  | @ -32,6 +32,7 @@ | ||||||
|         isPrincipleUser = true; |         isPrincipleUser = true; | ||||||
|       }; |       }; | ||||||
|       eve.isDesktopUser = true; |       eve.isDesktopUser = true; | ||||||
|  |       ivy.isDesktopUser = true; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     hardware = { |     hardware = { | ||||||
|  |  | ||||||
							
								
								
									
										177
									
								
								flake.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										177
									
								
								flake.lock
									
										
									
										generated
									
									
									
								
							|  | @ -25,11 +25,11 @@ | ||||||
|         ] |         ] | ||||||
|       }, |       }, | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1756733629, |         "lastModified": 1758287904, | ||||||
|         "narHash": "sha256-dwWGlDhcO5SMIvMSTB4mjQ5Pvo2vtxvpIknhVnSz2I8=", |         "narHash": "sha256-IGmaEf3Do8o5Cwp1kXBN1wQmZwQN3NLfq5t4nHtVtcU=", | ||||||
|         "owner": "nix-community", |         "owner": "nix-community", | ||||||
|         "repo": "disko", |         "repo": "disko", | ||||||
|         "rev": "a5c4f2ab72e3d1ab43e3e65aa421c6f2bd2e12a1", |         "rev": "67ff9807dd148e704baadbd4fd783b54282ca627", | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       }, |       }, | ||||||
|       "original": { |       "original": { | ||||||
|  | @ -46,11 +46,11 @@ | ||||||
|       }, |       }, | ||||||
|       "locked": { |       "locked": { | ||||||
|         "dir": "pkgs/firefox-addons", |         "dir": "pkgs/firefox-addons", | ||||||
|         "lastModified": 1756699417, |         "lastModified": 1759403080, | ||||||
|         "narHash": "sha256-rpRy5ae5ijEGaK+Cr66NqCQJ6ZeUE5Zi8gUWgKhesto=", |         "narHash": "sha256-EteyL8KyG9R5xzqyOBzyag4n2cSemu61VFrl3opJSqE=", | ||||||
|         "owner": "rycee", |         "owner": "rycee", | ||||||
|         "repo": "nur-expressions", |         "repo": "nur-expressions", | ||||||
|         "rev": "007b803d1eff595d25e7886e83054dbd038bf029", |         "rev": "8af6dfcbcbf1115a4f5aeed77ff0db5d3c02caf0", | ||||||
|         "type": "gitlab" |         "type": "gitlab" | ||||||
|       }, |       }, | ||||||
|       "original": { |       "original": { | ||||||
|  | @ -111,6 +111,39 @@ | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "flake-utils_3": { | ||||||
|  |       "inputs": { | ||||||
|  |         "systems": "systems_3" | ||||||
|  |       }, | ||||||
|  |       "locked": { | ||||||
|  |         "lastModified": 1731533236, | ||||||
|  |         "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", | ||||||
|  |         "owner": "numtide", | ||||||
|  |         "repo": "flake-utils", | ||||||
|  |         "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", | ||||||
|  |         "type": "github" | ||||||
|  |       }, | ||||||
|  |       "original": { | ||||||
|  |         "owner": "numtide", | ||||||
|  |         "repo": "flake-utils", | ||||||
|  |         "type": "github" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "flakey-profile": { | ||||||
|  |       "locked": { | ||||||
|  |         "lastModified": 1712898590, | ||||||
|  |         "narHash": "sha256-FhGIEU93VHAChKEXx905TSiPZKga69bWl1VB37FK//I=", | ||||||
|  |         "owner": "lf-", | ||||||
|  |         "repo": "flakey-profile", | ||||||
|  |         "rev": "243c903fd8eadc0f63d205665a92d4df91d42d9d", | ||||||
|  |         "type": "github" | ||||||
|  |       }, | ||||||
|  |       "original": { | ||||||
|  |         "owner": "lf-", | ||||||
|  |         "repo": "flakey-profile", | ||||||
|  |         "type": "github" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "home-manager": { |     "home-manager": { | ||||||
|       "inputs": { |       "inputs": { | ||||||
|         "nixpkgs": [ |         "nixpkgs": [ | ||||||
|  | @ -118,11 +151,11 @@ | ||||||
|         ] |         ] | ||||||
|       }, |       }, | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1756734952, |         "lastModified": 1759337100, | ||||||
|         "narHash": "sha256-H6jmduj4QIncLPAPODPSG/8ry9lpr1kRq6fYytU52qU=", |         "narHash": "sha256-CcT3QvZ74NGfM+lSOILcCEeU+SnqXRvl1XCRHenZ0Us=", | ||||||
|         "owner": "nix-community", |         "owner": "nix-community", | ||||||
|         "repo": "home-manager", |         "repo": "home-manager", | ||||||
|         "rev": "29ab63bbb3d9eee4a491f7ce701b189becd34068", |         "rev": "004753ae6b04c4b18aa07192c1106800aaacf6c3", | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       }, |       }, | ||||||
|       "original": { |       "original": { | ||||||
|  | @ -146,20 +179,57 @@ | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "mcp-nixos": { |     "lix": { | ||||||
|  |       "flake": false, | ||||||
|  |       "locked": { | ||||||
|  |         "lastModified": 1759624822, | ||||||
|  |         "narHash": "sha256-cf40qfsfpxJU/BnQ9PEj027LdPINNSsJqm+C6Ug93BA=", | ||||||
|  |         "rev": "57333a0e600c5e096a609410a2f1059b97194b1e", | ||||||
|  |         "type": "tarball", | ||||||
|  |         "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/57333a0e600c5e096a609410a2f1059b97194b1e.tar.gz" | ||||||
|  |       }, | ||||||
|  |       "original": { | ||||||
|  |         "type": "tarball", | ||||||
|  |         "url": "https://git.lix.systems/lix-project/lix/archive/main.tar.gz" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "lix-module": { | ||||||
|       "inputs": { |       "inputs": { | ||||||
|         "devshell": "devshell", |  | ||||||
|         "flake-utils": "flake-utils", |         "flake-utils": "flake-utils", | ||||||
|  |         "flakey-profile": "flakey-profile", | ||||||
|  |         "lix": "lix", | ||||||
|         "nixpkgs": [ |         "nixpkgs": [ | ||||||
|           "nixpkgs" |           "nixpkgs" | ||||||
|         ] |         ] | ||||||
|       }, |       }, | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1755372538, |         "lastModified": 1756511062, | ||||||
|         "narHash": "sha256-iWhsf1Myk6RyQ7IuNf4bWI3Sqq9pgmhKvEisCXtkxyw=", |         "narHash": "sha256-IgD1JR7scSEwlK/YAbmrcTWpAYT30LPldCUHdzXkaMs=", | ||||||
|  |         "ref": "refs/heads/main", | ||||||
|  |         "rev": "3f09a5eb772e02d98bb8878ab687d5b721f00d16", | ||||||
|  |         "revCount": 162, | ||||||
|  |         "type": "git", | ||||||
|  |         "url": "https://git.lix.systems/lix-project/nixos-module.git" | ||||||
|  |       }, | ||||||
|  |       "original": { | ||||||
|  |         "type": "git", | ||||||
|  |         "url": "https://git.lix.systems/lix-project/nixos-module.git" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "mcp-nixos": { | ||||||
|  |       "inputs": { | ||||||
|  |         "devshell": "devshell", | ||||||
|  |         "flake-utils": "flake-utils_2", | ||||||
|  |         "nixpkgs": [ | ||||||
|  |           "nixpkgs" | ||||||
|  |         ] | ||||||
|  |       }, | ||||||
|  |       "locked": { | ||||||
|  |         "lastModified": 1759342933, | ||||||
|  |         "narHash": "sha256-mdlUFcrOfvT0Pm+Hko/6aR3xf1ao5JA2iem4KsEVjP4=", | ||||||
|         "owner": "utensils", |         "owner": "utensils", | ||||||
|         "repo": "mcp-nixos", |         "repo": "mcp-nixos", | ||||||
|         "rev": "46b4d4d3d6421bfbadc415532ef74433871e1cda", |         "rev": "50b02bcba32b941d2ec48fedef68641702ca5b0f", | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       }, |       }, | ||||||
|       "original": { |       "original": { | ||||||
|  | @ -175,11 +245,11 @@ | ||||||
|         ] |         ] | ||||||
|       }, |       }, | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1755825449, |         "lastModified": 1758805352, | ||||||
|         "narHash": "sha256-XkiN4NM9Xdy59h69Pc+Vg4PxkSm9EWl6u7k6D5FZ5cM=", |         "narHash": "sha256-BHdc43Lkayd+72W/NXRKHzX5AZ+28F3xaUs3a88/Uew=", | ||||||
|         "owner": "LnL7", |         "owner": "LnL7", | ||||||
|         "repo": "nix-darwin", |         "repo": "nix-darwin", | ||||||
|         "rev": "8df64f819698c1fee0c2969696f54a843b2231e8", |         "rev": "c48e963a5558eb1c3827d59d21c5193622a1477c", | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       }, |       }, | ||||||
|       "original": { |       "original": { | ||||||
|  | @ -211,17 +281,17 @@ | ||||||
|     }, |     }, | ||||||
|     "nix-vscode-extensions": { |     "nix-vscode-extensions": { | ||||||
|       "inputs": { |       "inputs": { | ||||||
|         "flake-utils": "flake-utils_2", |         "flake-utils": "flake-utils_3", | ||||||
|         "nixpkgs": [ |         "nixpkgs": [ | ||||||
|           "nixpkgs" |           "nixpkgs" | ||||||
|         ] |         ] | ||||||
|       }, |       }, | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1756692643, |         "lastModified": 1759369908, | ||||||
|         "narHash": "sha256-SVos3AYuLvF6bD8Y0b6EiLABoEaiAOa4M/fTCBe0FV8=", |         "narHash": "sha256-IIhaE6jAge64z+fIyi/8Vtu0JdTtapbp4CvwiuIkZ1E=", | ||||||
|         "owner": "nix-community", |         "owner": "nix-community", | ||||||
|         "repo": "nix-vscode-extensions", |         "repo": "nix-vscode-extensions", | ||||||
|         "rev": "2f1d16db96f1ce8ee3c893ea9dc49c0035846988", |         "rev": "a66ad2141b1440a838ead278c6edfe8a4ce75e6c", | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       }, |       }, | ||||||
|       "original": { |       "original": { | ||||||
|  | @ -232,11 +302,11 @@ | ||||||
|     }, |     }, | ||||||
|     "nixos-hardware": { |     "nixos-hardware": { | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1756245047, |         "lastModified": 1759261527, | ||||||
|         "narHash": "sha256-9bHzrVbjAudbO8q4vYFBWlEkDam31fsz0J7GB8k4AsI=", |         "narHash": "sha256-wPd5oGvBBpUEzMF0kWnXge0WITNsITx/aGI9qLHgJ4g=", | ||||||
|         "owner": "NixOS", |         "owner": "NixOS", | ||||||
|         "repo": "nixos-hardware", |         "repo": "nixos-hardware", | ||||||
|         "rev": "a65b650d6981e23edd1afa1f01eb942f19cdcbb7", |         "rev": "e087756cf4abbe1a34f3544c480fc1034d68742f", | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       }, |       }, | ||||||
|       "original": { |       "original": { | ||||||
|  | @ -264,11 +334,11 @@ | ||||||
|     }, |     }, | ||||||
|     "nixpkgs_2": { |     "nixpkgs_2": { | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1756542300, |         "lastModified": 1759381078, | ||||||
|         "narHash": "sha256-tlOn88coG5fzdyqz6R93SQL5Gpq+m/DsWpekNFhqPQk=", |         "narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=", | ||||||
|         "owner": "nixos", |         "owner": "nixos", | ||||||
|         "repo": "nixpkgs", |         "repo": "nixpkgs", | ||||||
|         "rev": "d7600c775f877cd87b4f5a831c28aa94137377aa", |         "rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee", | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       }, |       }, | ||||||
|       "original": { |       "original": { | ||||||
|  | @ -285,6 +355,7 @@ | ||||||
|         "flake-compat": "flake-compat", |         "flake-compat": "flake-compat", | ||||||
|         "home-manager": "home-manager", |         "home-manager": "home-manager", | ||||||
|         "impermanence": "impermanence", |         "impermanence": "impermanence", | ||||||
|  |         "lix-module": "lix-module", | ||||||
|         "mcp-nixos": "mcp-nixos", |         "mcp-nixos": "mcp-nixos", | ||||||
|         "nix-darwin": "nix-darwin", |         "nix-darwin": "nix-darwin", | ||||||
|         "nix-syncthing": "nix-syncthing", |         "nix-syncthing": "nix-syncthing", | ||||||
|  | @ -292,18 +363,17 @@ | ||||||
|         "nixos-hardware": "nixos-hardware", |         "nixos-hardware": "nixos-hardware", | ||||||
|         "nixpkgs": "nixpkgs_2", |         "nixpkgs": "nixpkgs_2", | ||||||
|         "secrets": "secrets", |         "secrets": "secrets", | ||||||
|         "sops-nix": "sops-nix", |         "sops-nix": "sops-nix" | ||||||
|         "steam-fetcher": "steam-fetcher" |  | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "secrets": { |     "secrets": { | ||||||
|       "flake": false, |       "flake": false, | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1752531440, |         "lastModified": 1759945215, | ||||||
|         "narHash": "sha256-04tQ3EUrtmZ7g6fVUkZC4AbAG+Z7lng79qU3jsiqWJY=", |         "narHash": "sha256-xmUzOuhJl6FtTjR5++OQvSoAnXe7/VA5QFCZDyFwBXo=", | ||||||
|         "ref": "refs/heads/main", |         "ref": "refs/heads/main", | ||||||
|         "rev": "f016767c13aa36dde91503f7a9f01bdd02468045", |         "rev": "444229a105445339fb028d15a8d866063c5f8141", | ||||||
|         "revCount": 20, |         "revCount": 21, | ||||||
|         "type": "git", |         "type": "git", | ||||||
|         "url": "ssh://git@git.jan-leila.com/jan-leila/nix-config-secrets.git" |         "url": "ssh://git@git.jan-leila.com/jan-leila/nix-config-secrets.git" | ||||||
|       }, |       }, | ||||||
|  | @ -319,11 +389,11 @@ | ||||||
|         ] |         ] | ||||||
|       }, |       }, | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1754988908, |         "lastModified": 1759188042, | ||||||
|         "narHash": "sha256-t+voe2961vCgrzPFtZxha0/kmFSHFobzF00sT8p9h0U=", |         "narHash": "sha256-f9QC2KKiNReZDG2yyKAtDZh0rSK2Xp1wkPzKbHeQVRU=", | ||||||
|         "owner": "Mic92", |         "owner": "Mic92", | ||||||
|         "repo": "sops-nix", |         "repo": "sops-nix", | ||||||
|         "rev": "3223c7a92724b5d804e9988c6b447a0d09017d48", |         "rev": "9fcfabe085281dd793589bdc770a2e577a3caa5d", | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       }, |       }, | ||||||
|       "original": { |       "original": { | ||||||
|  | @ -332,26 +402,6 @@ | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "steam-fetcher": { |  | ||||||
|       "inputs": { |  | ||||||
|         "nixpkgs": [ |  | ||||||
|           "nixpkgs" |  | ||||||
|         ] |  | ||||||
|       }, |  | ||||||
|       "locked": { |  | ||||||
|         "lastModified": 1714795926, |  | ||||||
|         "narHash": "sha256-PkgC9jqoN6cJ8XYzTA2PlrWs7aPJkM3BGiTxNqax0cA=", |  | ||||||
|         "owner": "nix-community", |  | ||||||
|         "repo": "steam-fetcher", |  | ||||||
|         "rev": "12f66eafb7862d91b3e30c14035f96a21941bd9c", |  | ||||||
|         "type": "github" |  | ||||||
|       }, |  | ||||||
|       "original": { |  | ||||||
|         "owner": "nix-community", |  | ||||||
|         "repo": "steam-fetcher", |  | ||||||
|         "type": "github" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "systems": { |     "systems": { | ||||||
|       "locked": { |       "locked": { | ||||||
|         "lastModified": 1681028828, |         "lastModified": 1681028828, | ||||||
|  | @ -381,6 +431,21 @@ | ||||||
|         "repo": "default", |         "repo": "default", | ||||||
|         "type": "github" |         "type": "github" | ||||||
|       } |       } | ||||||
|  |     }, | ||||||
|  |     "systems_3": { | ||||||
|  |       "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", |   "root": "root", | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								flake.nix
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								flake.nix
									
										
									
									
									
								
							|  | @ -5,10 +5,10 @@ | ||||||
|     # base packages |     # base packages | ||||||
|     nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; |     nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; | ||||||
| 
 | 
 | ||||||
|     # lix-module = { |     lix-module = { | ||||||
|     #   url = "https://git.lix.systems/lix-project/nixos-module/archive/2.93.3-1.tar.gz"; |       url = "git+https://git.lix.systems/lix-project/nixos-module.git"; | ||||||
|     #   inputs.nixpkgs.follows = "nixpkgs"; |       inputs.nixpkgs.follows = "nixpkgs"; | ||||||
|     # }; |     }; | ||||||
| 
 | 
 | ||||||
|     # secret encryption |     # secret encryption | ||||||
|     sops-nix = { |     sops-nix = { | ||||||
|  | @ -72,11 +72,6 @@ | ||||||
|       url = "github:edolstra/flake-compat"; |       url = "github:edolstra/flake-compat"; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     steam-fetcher = { |  | ||||||
|       url = "github:nix-community/steam-fetcher"; |  | ||||||
|       inputs.nixpkgs.follows = "nixpkgs"; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     # MCP NixOS server for Claude Dev |     # MCP NixOS server for Claude Dev | ||||||
|     mcp-nixos = { |     mcp-nixos = { | ||||||
|       url = "github:utensils/mcp-nixos"; |       url = "github:utensils/mcp-nixos"; | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| # this folder is for derivation overlays | # this folder is for derivation overlays | ||||||
| {inputs, ...}: { | {inputs, ...}: { | ||||||
|   nixpkgs.overlays = [ |   nixpkgs.overlays = [ | ||||||
|     inputs.steam-fetcher.overlays.default |  | ||||||
|     inputs.nix-vscode-extensions.overlays.default |     inputs.nix-vscode-extensions.overlays.default | ||||||
|   ]; |   ]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,4 +1,8 @@ | ||||||
| {pkgs, ...}: { | {pkgs, ...}: { | ||||||
|  |   imports = [ | ||||||
|  |     ./python | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|   nixpkgs.overlays = [ |   nixpkgs.overlays = [ | ||||||
|     (final: prev: { |     (final: prev: { | ||||||
|       webtoon-dl = |       webtoon-dl = | ||||||
|  | @ -6,7 +10,6 @@ | ||||||
|         ./webtoon-dl.nix |         ./webtoon-dl.nix | ||||||
|         {}; |         {}; | ||||||
|     }) |     }) | ||||||
|     # TODO: this package always needs to be called with the --in-process-gpu flag for some reason, can we automate that? |  | ||||||
|     (final: prev: { |     (final: prev: { | ||||||
|       prostudiomasters = |       prostudiomasters = | ||||||
|         pkgs.callPackage |         pkgs.callPackage | ||||||
|  | @ -22,5 +25,21 @@ | ||||||
|     (final: prev: { |     (final: prev: { | ||||||
|       codium-extensions = pkgs.callPackage ./codium-extensions {}; |       codium-extensions = pkgs.callPackage ./codium-extensions {}; | ||||||
|     }) |     }) | ||||||
|  |     (final: prev: { | ||||||
|  |       mapillary-uploader = pkgs.callPackage ./mapillary-uploader.nix {}; | ||||||
|  |     }) | ||||||
|  |     (final: prev: { | ||||||
|  |       panoramax = pkgs.python3.pkgs.callPackage ./panoramax.nix {}; | ||||||
|  |     }) | ||||||
|  |     (final: prev: { | ||||||
|  |       sgblur = pkgs.python3.pkgs.callPackage ./sgblur.nix {}; | ||||||
|  |     }) | ||||||
|  |     (final: prev: { | ||||||
|  |       # Override h3 C library to version 4.3.0 | ||||||
|  |       h3 = pkgs.callPackage ./h3-c-lib.nix {}; | ||||||
|  |     }) | ||||||
|  |     (final: prev: { | ||||||
|  |       polycule = pkgs.callPackage ./polycule {}; | ||||||
|  |     }) | ||||||
|   ]; |   ]; | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										36
									
								
								modules/common-modules/pkgs/h3-c-lib.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								modules/common-modules/pkgs/h3-c-lib.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   stdenv, | ||||||
|  |   fetchFromGitHub, | ||||||
|  |   cmake, | ||||||
|  |   doxygen, | ||||||
|  | }: | ||||||
|  | stdenv.mkDerivation rec { | ||||||
|  |   pname = "h3"; | ||||||
|  |   version = "4.3.0"; | ||||||
|  | 
 | ||||||
|  |   src = fetchFromGitHub { | ||||||
|  |     owner = "uber"; | ||||||
|  |     repo = "h3"; | ||||||
|  |     rev = "v${version}"; | ||||||
|  |     hash = "sha256-DUILKZ1QvML6qg+WdOxir6zRsgTvk+En6yjeFf6MQBg="; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   nativeBuildInputs = [ | ||||||
|  |     cmake | ||||||
|  |     doxygen | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   cmakeFlags = [ | ||||||
|  |     "-DBUILD_SHARED_LIBS=ON" | ||||||
|  |     "-DBUILD_TESTING=OFF" | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   meta = with lib; { | ||||||
|  |     homepage = "https://github.com/uber/h3"; | ||||||
|  |     description = "Hexagonal hierarchical geospatial indexing system"; | ||||||
|  |     license = licenses.asl20; | ||||||
|  |     maintainers = []; | ||||||
|  |     platforms = platforms.all; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								modules/common-modules/pkgs/mapillary-uploader.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								modules/common-modules/pkgs/mapillary-uploader.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   fetchurl, | ||||||
|  |   appimageTools, | ||||||
|  | }: let | ||||||
|  |   pname = "mapillary-uploader"; | ||||||
|  |   version = "4.7.2"; | ||||||
|  | 
 | ||||||
|  |   src = fetchurl { | ||||||
|  |     url = "http://tools.mapillary.com/uploader/download/linux/${version}"; | ||||||
|  |     name = "mapillary-uploader.AppImage"; | ||||||
|  |     sha256 = "sha256-Oyx7AIdA/2mwBaq7UzXOoyq/z2SU2sViMN40sY2RCQw="; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   appimageContents = appimageTools.extractType2 { | ||||||
|  |     inherit pname version src; | ||||||
|  |   }; | ||||||
|  | in | ||||||
|  |   appimageTools.wrapType2 { | ||||||
|  |     inherit pname version src; | ||||||
|  | 
 | ||||||
|  |     extraInstallCommands = '' | ||||||
|  |       # Install desktop file | ||||||
|  |       install -Dm644 ${appimageContents}/mapillary-desktop-uploader.desktop $out/share/applications/mapillary-uploader.desktop | ||||||
|  | 
 | ||||||
|  |       # Install icon | ||||||
|  |       install -Dm644 ${appimageContents}/usr/share/icons/hicolor/0x0/apps/mapillary-desktop-uploader.png $out/share/pixmaps/mapillary-uploader.png | ||||||
|  | 
 | ||||||
|  |       # Fix desktop file paths | ||||||
|  |       substituteInPlace $out/share/applications/mapillary-uploader.desktop \ | ||||||
|  |         --replace 'Exec=AppRun' 'Exec=${pname}' | ||||||
|  |     ''; | ||||||
|  | 
 | ||||||
|  |     meta = with lib; { | ||||||
|  |       description = "Mapillary Desktop Uploader - Upload street-level imagery to Mapillary"; | ||||||
|  |       homepage = "https://www.mapillary.com/"; | ||||||
|  |       license = licenses.unfree; # Mapillary's license terms | ||||||
|  |       maintainers = []; | ||||||
|  |       platforms = ["x86_64-linux"]; | ||||||
|  |       sourceProvenance = with sourceTypes; [binaryNativeCode]; | ||||||
|  |     }; | ||||||
|  |   } | ||||||
							
								
								
									
										105
									
								
								modules/common-modules/pkgs/panoramax.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								modules/common-modules/pkgs/panoramax.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,105 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   fetchFromGitLab, | ||||||
|  |   buildPythonPackage, | ||||||
|  |   flit-core, | ||||||
|  |   flask, | ||||||
|  |   pillow, | ||||||
|  |   requests, | ||||||
|  |   python-dotenv, | ||||||
|  |   authlib, | ||||||
|  |   sentry-sdk, | ||||||
|  |   python-dateutil, | ||||||
|  |   dateparser, | ||||||
|  |   croniter, | ||||||
|  |   pydantic, | ||||||
|  |   flask-cors, | ||||||
|  |   flask-compress, | ||||||
|  |   flask-babel, | ||||||
|  |   flasgger, | ||||||
|  |   yoyo-migrations, | ||||||
|  |   psycopg, | ||||||
|  |   psycopg-pool, | ||||||
|  |   tzdata, | ||||||
|  |   email-validator, | ||||||
|  |   pydantic-extra-types, | ||||||
|  |   python-multipart, | ||||||
|  |   fs, | ||||||
|  |   fs-s3fs, | ||||||
|  |   geopic-tag-reader, | ||||||
|  |   pygeofilter, | ||||||
|  |   pygeoif, | ||||||
|  |   rfeed, | ||||||
|  |   geojson-pydantic, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   pname = "geovisio"; | ||||||
|  |   version = "2.10.0"; | ||||||
|  |   repo = fetchFromGitLab { | ||||||
|  |     owner = "panoramax"; | ||||||
|  |     repo = "server/api"; | ||||||
|  |     rev = version; | ||||||
|  |     hash = "sha256-kCLcrOe7jJdIfmWWOmxQ5dOj8ZG2B7s0qFpHXs02B/E="; | ||||||
|  |   }; | ||||||
|  | in | ||||||
|  |   buildPythonPackage { | ||||||
|  |     inherit pname version; | ||||||
|  | 
 | ||||||
|  |     pyproject = true; | ||||||
|  | 
 | ||||||
|  |     src = repo; | ||||||
|  | 
 | ||||||
|  |     build-system = [ | ||||||
|  |       flit-core | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |       flask | ||||||
|  |       pillow | ||||||
|  |       requests | ||||||
|  |       python-dotenv | ||||||
|  |       authlib | ||||||
|  |       sentry-sdk | ||||||
|  |       python-dateutil | ||||||
|  |       dateparser | ||||||
|  |       croniter | ||||||
|  |       pydantic | ||||||
|  |       flask-cors | ||||||
|  |       flask-compress | ||||||
|  |       flask-babel | ||||||
|  |       flasgger | ||||||
|  |       yoyo-migrations | ||||||
|  |       psycopg | ||||||
|  |       psycopg-pool | ||||||
|  |       tzdata | ||||||
|  |       email-validator | ||||||
|  |       pydantic-extra-types | ||||||
|  |       python-multipart | ||||||
|  |       fs | ||||||
|  |       fs-s3fs | ||||||
|  |       geopic-tag-reader | ||||||
|  |       pygeofilter | ||||||
|  |       pygeoif | ||||||
|  |       rfeed | ||||||
|  |       geojson-pydantic | ||||||
|  |       # Missing from nixpkgs - may need custom packages: | ||||||
|  |       # flask-executor | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     # Skip tests as they may require network access or specific setup | ||||||
|  |     doCheck = false; | ||||||
|  | 
 | ||||||
|  |     # Disable runtime dependencies check as many dependencies are not available in nixpkgs | ||||||
|  |     dontCheckRuntimeDeps = true; | ||||||
|  | 
 | ||||||
|  |     # Disable imports check as many dependencies are not available in nixpkgs | ||||||
|  |     pythonImportsCheck = []; | ||||||
|  | 
 | ||||||
|  |     meta = with lib; { | ||||||
|  |       description = "Panoramax API client and tools for street-level imagery platform"; | ||||||
|  |       homepage = "https://gitlab.com/panoramax/server/api"; | ||||||
|  |       license = licenses.mit; | ||||||
|  |       maintainers = []; | ||||||
|  |       platforms = platforms.all; | ||||||
|  |     }; | ||||||
|  |   } | ||||||
							
								
								
									
										149
									
								
								modules/common-modules/pkgs/polycule/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								modules/common-modules/pkgs/polycule/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,149 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   flutter332, | ||||||
|  |   fetchFromGitLab, | ||||||
|  |   pkg-config, | ||||||
|  |   wrapGAppsHook, | ||||||
|  |   gtk3, | ||||||
|  |   glib, | ||||||
|  |   glib-networking, | ||||||
|  |   webkitgtk_4_1, | ||||||
|  |   libsecret, | ||||||
|  |   libnotify, | ||||||
|  |   dbus, | ||||||
|  |   sqlcipher, | ||||||
|  |   openssl, | ||||||
|  |   mpv, | ||||||
|  |   alsa-lib, | ||||||
|  |   libass, | ||||||
|  |   ffmpeg-full, | ||||||
|  |   libplacebo, | ||||||
|  |   libunwind, | ||||||
|  |   shaderc, | ||||||
|  |   vulkan-headers, | ||||||
|  |   vulkan-loader, | ||||||
|  |   lcms2, | ||||||
|  |   libdovi, | ||||||
|  |   libdvdnav, | ||||||
|  |   libdvdread, | ||||||
|  |   mujs, | ||||||
|  |   libbluray, | ||||||
|  |   lua, | ||||||
|  |   rubberband, | ||||||
|  |   libuchardet, | ||||||
|  |   zimg, | ||||||
|  |   openal, | ||||||
|  |   pipewire, | ||||||
|  |   libpulseaudio, | ||||||
|  |   libcaca, | ||||||
|  |   libdrm, | ||||||
|  |   libdisplay-info, | ||||||
|  |   libgbm, | ||||||
|  |   xorg, | ||||||
|  |   nv-codec-headers-11, | ||||||
|  |   libva, | ||||||
|  |   libvdpau, | ||||||
|  | }: | ||||||
|  | flutter332.buildFlutterApplication rec { | ||||||
|  |   pname = "polycule"; | ||||||
|  |   version = "0.3.4"; | ||||||
|  | 
 | ||||||
|  |   src = fetchFromGitLab { | ||||||
|  |     owner = "polycule_client"; | ||||||
|  |     repo = "polycule"; | ||||||
|  |     rev = "v${version}"; | ||||||
|  |     hash = "sha256-RUu8DKuX2NUU5Ce5WLHtDaORkn7CSrgTj3KhM/z+yHc="; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   pubspecLock = lib.importJSON ./polycule-pubspec.lock.json; | ||||||
|  | 
 | ||||||
|  |   gitHashes = { | ||||||
|  |     matrix = "sha256-w/QB5nYJ9Lh77TcYKEN/DnNQjWfp+9NX0dwQ9GOzWE8="; | ||||||
|  |     media_kit = "sha256-1sVX+aHFLFJBtrNZrR6tWkb80vFELW2N9EejyQKlBPg="; | ||||||
|  |     media_kit_libs_android_video = "sha256-N6QoktM8u9NYF8MAXLsxM9RlV8nICM4NbnmABHTRkZg="; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   nativeBuildInputs = [ | ||||||
|  |     pkg-config | ||||||
|  |     wrapGAppsHook | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   buildInputs = [ | ||||||
|  |     gtk3 | ||||||
|  |     glib | ||||||
|  |     glib-networking | ||||||
|  |     webkitgtk_4_1 | ||||||
|  |     libsecret | ||||||
|  |     libnotify | ||||||
|  |     dbus | ||||||
|  |     sqlcipher | ||||||
|  |     openssl | ||||||
|  |     mpv | ||||||
|  |     alsa-lib | ||||||
|  |     libass | ||||||
|  |     ffmpeg-full | ||||||
|  |     libplacebo | ||||||
|  |     libunwind | ||||||
|  |     shaderc | ||||||
|  |     vulkan-headers | ||||||
|  |     vulkan-loader | ||||||
|  |     lcms2 | ||||||
|  |     libdovi | ||||||
|  |     libdvdnav | ||||||
|  |     libdvdread | ||||||
|  |     mujs | ||||||
|  |     libbluray | ||||||
|  |     lua | ||||||
|  |     rubberband | ||||||
|  |     libuchardet | ||||||
|  |     zimg | ||||||
|  |     openal | ||||||
|  |     pipewire | ||||||
|  |     libpulseaudio | ||||||
|  |     libcaca | ||||||
|  |     libdrm | ||||||
|  |     libdisplay-info | ||||||
|  |     libgbm | ||||||
|  |     xorg.libXScrnSaver | ||||||
|  |     xorg.libXpresent | ||||||
|  |     nv-codec-headers-11 | ||||||
|  |     libva | ||||||
|  |     libvdpau | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   flutterBuildFlags = [ | ||||||
|  |     "--release" | ||||||
|  |     "--target" | ||||||
|  |     "lib/main.dart" | ||||||
|  |     "--dart-define=POLYCULE_VERSION=v${version}" | ||||||
|  |     "--dart-define=POLYCULE_IS_STABLE=true" | ||||||
|  |     "--no-tree-shake-icons" | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   postInstall = '' | ||||||
|  |     # Install desktop files and icons from the source | ||||||
|  |     install -Dm644 linux/business.braid.polycule.desktop $out/share/applications/polycule.desktop | ||||||
|  |     install -Dm644 assets/logo/logo-circle.png $out/share/pixmaps/polycule.png | ||||||
|  | 
 | ||||||
|  |     # Update desktop file to use correct executable name | ||||||
|  |     substituteInPlace $out/share/applications/polycule.desktop \ | ||||||
|  |       --replace 'Exec=business.braid.polycule' 'Exec=polycule' | ||||||
|  | 
 | ||||||
|  |     # Create a symlink with the expected name | ||||||
|  |     ln -sf $out/bin/polycule $out/bin/business.braid.polycule | ||||||
|  |   ''; | ||||||
|  | 
 | ||||||
|  |   meta = with lib; { | ||||||
|  |     description = "A geeky and efficient [matrix] client for power users"; | ||||||
|  |     longDescription = '' | ||||||
|  |       Polycule is a modern Matrix client built with Flutter, designed for power users | ||||||
|  |       who want a fast, efficient, and feature-rich Matrix experience. | ||||||
|  |     ''; | ||||||
|  |     homepage = "https://polycule.im/"; | ||||||
|  |     license = licenses.eupl12; | ||||||
|  |     maintainers = []; | ||||||
|  |     platforms = ["x86_64-linux" "aarch64-linux"]; | ||||||
|  |     sourceProvenance = with sourceTypes; [fromSource]; | ||||||
|  |     mainProgram = "polycule"; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										2459
									
								
								modules/common-modules/pkgs/polycule/polycule-pubspec.lock.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2459
									
								
								modules/common-modules/pkgs/polycule/polycule-pubspec.lock.json
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,6 +1,7 @@ | ||||||
| { | { | ||||||
|   fetchurl, |   fetchurl, | ||||||
|   appimageTools, |   appimageTools, | ||||||
|  |   writeShellScript, | ||||||
| }: let | }: let | ||||||
|   pname = "prostudiomasters"; |   pname = "prostudiomasters"; | ||||||
|   version = "2.5.6"; |   version = "2.5.6"; | ||||||
|  | @ -8,7 +9,25 @@ | ||||||
|     url = "https://download.prostudiomasters.com/linux/ProStudioMasters-${version}.AppImage"; |     url = "https://download.prostudiomasters.com/linux/ProStudioMasters-${version}.AppImage"; | ||||||
|     hash = "sha256-7owOwdcucFfl+JsVj+Seau2KOz0J4P/ep7WrBSNSmbs="; |     hash = "sha256-7owOwdcucFfl+JsVj+Seau2KOz0J4P/ep7WrBSNSmbs="; | ||||||
|   }; |   }; | ||||||
| in | 
 | ||||||
|   appimageTools.wrapType2 { |   # Create the base AppImage wrapper | ||||||
|  |   baseApp = appimageTools.wrapType2 { | ||||||
|     inherit pname version src; |     inherit pname version src; | ||||||
|   } |   }; | ||||||
|  | 
 | ||||||
|  |   # Create a wrapper script that automatically adds the --in-process-gpu flag | ||||||
|  |   wrapper = writeShellScript "prostudiomasters-wrapper" '' | ||||||
|  |     exec ${baseApp}/bin/prostudiomasters --in-process-gpu "$@" | ||||||
|  |   ''; | ||||||
|  | in | ||||||
|  |   # Override the base app to use our wrapper script | ||||||
|  |   baseApp.overrideAttrs (oldAttrs: { | ||||||
|  |     buildCommand = | ||||||
|  |       oldAttrs.buildCommand | ||||||
|  |       + '' | ||||||
|  |         # Replace the original binary with our wrapper | ||||||
|  |         rm $out/bin/prostudiomasters | ||||||
|  |         cp ${wrapper} $out/bin/prostudiomasters | ||||||
|  |         chmod +x $out/bin/prostudiomasters | ||||||
|  |       ''; | ||||||
|  |   }) | ||||||
|  |  | ||||||
							
								
								
									
										18
									
								
								modules/common-modules/pkgs/python/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								modules/common-modules/pkgs/python/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | {...}: { | ||||||
|  |   nixpkgs.overlays = [ | ||||||
|  |     (final: prev: { | ||||||
|  |       python3 = prev.python3.override { | ||||||
|  |         packageOverrides = pythonPrev: pythonFinal: { | ||||||
|  |           h3 = pythonPrev.callPackage ./h3.nix {h3 = final.h3;}; | ||||||
|  |           pygeofilter = pythonPrev.callPackage ./pygeofilter.nix {}; | ||||||
|  |           pygeoif = pythonPrev.callPackage ./pygeoif.nix {}; | ||||||
|  |           rfeed = pythonPrev.callPackage ./rfeed.nix {}; | ||||||
|  |           pyexiv2 = pythonPrev.callPackage ./pyexiv2.nix {}; | ||||||
|  |           geojson-pydantic = pythonPrev.callPackage ./geojson-pydantic.nix {}; | ||||||
|  |           geopic-tag-reader = pythonPrev.callPackage ./geopic-tag-reader.nix {}; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |       python3Packages = final.python3.pkgs; | ||||||
|  |     }) | ||||||
|  |   ]; | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								modules/common-modules/pkgs/python/geojson-pydantic.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								modules/common-modules/pkgs/python/geojson-pydantic.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   fetchPypi, | ||||||
|  |   buildPythonPackage, | ||||||
|  |   flit-core, | ||||||
|  |   pydantic, | ||||||
|  |   geojson, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   pname = "geojson_pydantic"; | ||||||
|  |   version = "2.0.0"; | ||||||
|  | in | ||||||
|  |   buildPythonPackage { | ||||||
|  |     inherit pname version; | ||||||
|  | 
 | ||||||
|  |     pyproject = true; | ||||||
|  | 
 | ||||||
|  |     src = fetchPypi { | ||||||
|  |       inherit pname version; | ||||||
|  |       hash = "sha256-ti6LRFAt0a1Ri19zkDWoGSSnb5gMvbOk6JFu+RO+JC4="; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     build-system = [ | ||||||
|  |       flit-core | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |       pydantic | ||||||
|  |       geojson | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     # Skip tests as they may require specific setup | ||||||
|  |     doCheck = false; | ||||||
|  | 
 | ||||||
|  |     # Disable runtime dependencies check | ||||||
|  |     dontCheckRuntimeDeps = true; | ||||||
|  | 
 | ||||||
|  |     # Basic imports check | ||||||
|  |     pythonImportsCheck = ["geojson_pydantic"]; | ||||||
|  | 
 | ||||||
|  |     meta = with lib; { | ||||||
|  |       description = "Pydantic models for GeoJSON objects"; | ||||||
|  |       homepage = "https://github.com/developmentseed/geojson-pydantic"; | ||||||
|  |       license = licenses.mit; | ||||||
|  |       maintainers = []; | ||||||
|  |       platforms = platforms.all; | ||||||
|  |     }; | ||||||
|  |   } | ||||||
							
								
								
									
										70
									
								
								modules/common-modules/pkgs/python/geopic-tag-reader.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								modules/common-modules/pkgs/python/geopic-tag-reader.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   fetchFromGitLab, | ||||||
|  |   buildPythonPackage, | ||||||
|  |   flit-core, | ||||||
|  |   typer, | ||||||
|  |   xmltodict, | ||||||
|  |   timezonefinder, | ||||||
|  |   pytz, | ||||||
|  |   types-pytz, | ||||||
|  |   types-python-dateutil, | ||||||
|  |   rtree, | ||||||
|  |   python-dateutil, | ||||||
|  |   pyexiv2, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   pname = "geopic-tag-reader"; | ||||||
|  |   version = "1.8.0"; | ||||||
|  | in | ||||||
|  |   buildPythonPackage { | ||||||
|  |     inherit pname version; | ||||||
|  | 
 | ||||||
|  |     pyproject = true; | ||||||
|  | 
 | ||||||
|  |     src = fetchFromGitLab { | ||||||
|  |       owner = "panoramax"; | ||||||
|  |       repo = "server/geo-picture-tag-reader"; | ||||||
|  |       rev = version; | ||||||
|  |       sha256 = "0lzf5xxxcdqmq28bpvgpkxf5jxmh2nawwa4rl4yg04bdsi16rf1j"; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     build-system = [ | ||||||
|  |       flit-core | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |       typer | ||||||
|  |       xmltodict | ||||||
|  |       pyexiv2 | ||||||
|  |       timezonefinder | ||||||
|  |       pytz | ||||||
|  |       types-pytz | ||||||
|  |       types-python-dateutil | ||||||
|  |       rtree | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     optional-dependencies = { | ||||||
|  |       write-exif = [ | ||||||
|  |         python-dateutil | ||||||
|  |         types-python-dateutil | ||||||
|  |       ]; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     # Skip tests as they may require network access or specific setup | ||||||
|  |     doCheck = false; | ||||||
|  | 
 | ||||||
|  |     # Disable runtime dependencies check as some dependencies might have issues | ||||||
|  |     dontCheckRuntimeDeps = true; | ||||||
|  | 
 | ||||||
|  |     # Disable imports check initially to avoid dependency issues | ||||||
|  |     pythonImportsCheck = []; | ||||||
|  | 
 | ||||||
|  |     meta = with lib; { | ||||||
|  |       description = "GeoPic Tag Reader - Python library to read and write standardized metadata from geolocated pictures EXIF metadata"; | ||||||
|  |       homepage = "https://gitlab.com/panoramax/server/geo-picture-tag-reader"; | ||||||
|  |       license = licenses.mit; | ||||||
|  |       maintainers = []; | ||||||
|  |       platforms = platforms.all; | ||||||
|  |     }; | ||||||
|  |   } | ||||||
							
								
								
									
										81
									
								
								modules/common-modules/pkgs/python/h3.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								modules/common-modules/pkgs/python/h3.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,81 @@ | ||||||
|  | { | ||||||
|  |   autoPatchelfHook, | ||||||
|  |   buildPythonPackage, | ||||||
|  |   cmake, | ||||||
|  |   cython, | ||||||
|  |   fetchFromGitHub, | ||||||
|  |   h3, | ||||||
|  |   lib, | ||||||
|  |   ninja, | ||||||
|  |   numpy, | ||||||
|  |   pytestCheckHook, | ||||||
|  |   pytest-cov-stub, | ||||||
|  |   scikit-build-core, | ||||||
|  |   stdenv, | ||||||
|  | }: | ||||||
|  | buildPythonPackage rec { | ||||||
|  |   pname = "h3"; | ||||||
|  |   version = "4.3.1"; | ||||||
|  |   pyproject = true; | ||||||
|  | 
 | ||||||
|  |   # pypi version does not include tests | ||||||
|  |   src = fetchFromGitHub { | ||||||
|  |     owner = "uber"; | ||||||
|  |     repo = "h3-py"; | ||||||
|  |     tag = "v${version}"; | ||||||
|  |     hash = "sha256-zt7zbBgSp2P9q7mObZeQZpW9Szip62dAYdPZ2cGTmi4="; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   dontConfigure = true; | ||||||
|  | 
 | ||||||
|  |   nativeCheckInputs = [ | ||||||
|  |     pytestCheckHook | ||||||
|  |     pytest-cov-stub | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   build-system = | ||||||
|  |     [ | ||||||
|  |       scikit-build-core | ||||||
|  |       cmake | ||||||
|  |       cython | ||||||
|  |       ninja | ||||||
|  |     ] | ||||||
|  |     ++ lib.optionals stdenv.hostPlatform.isLinux [ | ||||||
|  |       # On Linux the .so files ends up referring to libh3.so instead of the full | ||||||
|  |       # Nix store path. I'm not sure why this is happening! On Darwin it works | ||||||
|  |       # fine. | ||||||
|  |       autoPatchelfHook | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |   # This is not needed per-se, it's only added for autoPatchelfHook to work | ||||||
|  |   # correctly. See the note above ^^ | ||||||
|  |   buildInputs = lib.optionals stdenv.hostPlatform.isLinux [h3]; | ||||||
|  | 
 | ||||||
|  |   dependencies = [numpy]; | ||||||
|  | 
 | ||||||
|  |   # The following prePatch replaces the h3lib compilation with using the h3 packaged in nixpkgs. | ||||||
|  |   # | ||||||
|  |   # - Remove the h3lib submodule. | ||||||
|  |   # - Patch CMakeLists to avoid building h3lib, and use h3 instead. | ||||||
|  |   prePatch = let | ||||||
|  |     cmakeCommands = '' | ||||||
|  |       include_directories(${lib.getDev h3}/include/h3) | ||||||
|  |       link_directories(${h3}/lib) | ||||||
|  |     ''; | ||||||
|  |   in '' | ||||||
|  |     rm -r src/h3lib | ||||||
|  |     substituteInPlace CMakeLists.txt \ | ||||||
|  |       --replace-fail "add_subdirectory(src/h3lib)" "${cmakeCommands}" \ | ||||||
|  |       --replace-fail "\''${CMAKE_CURRENT_BINARY_DIR}/src/h3lib/src/h3lib/include/h3api.h" "${lib.getDev h3}/include/h3/h3api.h" | ||||||
|  |   ''; | ||||||
|  | 
 | ||||||
|  |   # Extra check to make sure we can import it from Python | ||||||
|  |   pythonImportsCheck = ["h3"]; | ||||||
|  | 
 | ||||||
|  |   meta = { | ||||||
|  |     homepage = "https://github.com/uber/h3-py"; | ||||||
|  |     description = "Hierarchical hexagonal geospatial indexing system"; | ||||||
|  |     license = lib.licenses.asl20; | ||||||
|  |     maintainers = [lib.maintainers.kalbasit]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								modules/common-modules/pkgs/python/pyexiv2.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								modules/common-modules/pkgs/python/pyexiv2.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   fetchFromGitHub, | ||||||
|  |   buildPythonPackage, | ||||||
|  |   exiv2, | ||||||
|  |   boost, | ||||||
|  |   pybind11, | ||||||
|  |   setuptools, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   pname = "pyexiv2"; | ||||||
|  |   version = "2.15.3"; | ||||||
|  | in | ||||||
|  |   buildPythonPackage { | ||||||
|  |     inherit pname version; | ||||||
|  | 
 | ||||||
|  |     pyproject = true; | ||||||
|  |     build-system = [setuptools]; | ||||||
|  | 
 | ||||||
|  |     src = fetchFromGitHub { | ||||||
|  |       owner = "LeoHsiao1"; | ||||||
|  |       repo = "pyexiv2"; | ||||||
|  |       rev = "v${version}"; | ||||||
|  |       sha256 = "sha256-83bFMaoXncvhRJNcCgkkC7B29wR5pjuLO/EdkQdqxxo="; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     buildInputs = [ | ||||||
|  |       exiv2 | ||||||
|  |       boost | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     nativeBuildInputs = [ | ||||||
|  |       pybind11 | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     # Skip tests as they may require specific test images | ||||||
|  |     doCheck = false; | ||||||
|  | 
 | ||||||
|  |     # Disable runtime dependencies check initially | ||||||
|  |     dontCheckRuntimeDeps = true; | ||||||
|  | 
 | ||||||
|  |     meta = with lib; { | ||||||
|  |       description = "Python binding to the library exiv2"; | ||||||
|  |       homepage = "https://github.com/LeoHsiao1/pyexiv2"; | ||||||
|  |       license = licenses.gpl3Plus; | ||||||
|  |       maintainers = []; | ||||||
|  |       platforms = platforms.linux; | ||||||
|  |     }; | ||||||
|  |   } | ||||||
							
								
								
									
										52
									
								
								modules/common-modules/pkgs/python/pygeofilter.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								modules/common-modules/pkgs/python/pygeofilter.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   fetchPypi, | ||||||
|  |   buildPythonPackage, | ||||||
|  |   setuptools, | ||||||
|  |   wheel, | ||||||
|  |   lark, | ||||||
|  |   python-dateutil, | ||||||
|  |   shapely, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   pname = "pygeofilter"; | ||||||
|  |   version = "0.3.1"; | ||||||
|  | in | ||||||
|  |   buildPythonPackage { | ||||||
|  |     inherit pname version; | ||||||
|  | 
 | ||||||
|  |     pyproject = true; | ||||||
|  | 
 | ||||||
|  |     src = fetchPypi { | ||||||
|  |       inherit pname version; | ||||||
|  |       hash = "sha256-+SvAYiCZ+H/os23nq92GBZ1hWontYIInNwgiI6V44VA="; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     build-system = [ | ||||||
|  |       setuptools | ||||||
|  |       wheel | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |       lark | ||||||
|  |       python-dateutil | ||||||
|  |       shapely | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     # Skip tests as they may require specific setup | ||||||
|  |     doCheck = false; | ||||||
|  | 
 | ||||||
|  |     # Disable runtime dependencies check | ||||||
|  |     dontCheckRuntimeDeps = true; | ||||||
|  | 
 | ||||||
|  |     # Basic imports check | ||||||
|  |     pythonImportsCheck = ["pygeofilter"]; | ||||||
|  | 
 | ||||||
|  |     meta = with lib; { | ||||||
|  |       description = "A pure Python parser implementation of OGC filtering standards"; | ||||||
|  |       homepage = "https://github.com/geopython/pygeofilter"; | ||||||
|  |       license = licenses.mit; | ||||||
|  |       maintainers = []; | ||||||
|  |       platforms = platforms.all; | ||||||
|  |     }; | ||||||
|  |   } | ||||||
							
								
								
									
										48
									
								
								modules/common-modules/pkgs/python/pygeoif.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								modules/common-modules/pkgs/python/pygeoif.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   fetchPypi, | ||||||
|  |   buildPythonPackage, | ||||||
|  |   setuptools, | ||||||
|  |   wheel, | ||||||
|  |   typing-extensions, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   pname = "pygeoif"; | ||||||
|  |   version = "1.5.1"; | ||||||
|  | in | ||||||
|  |   buildPythonPackage { | ||||||
|  |     inherit pname version; | ||||||
|  | 
 | ||||||
|  |     pyproject = true; | ||||||
|  | 
 | ||||||
|  |     src = fetchPypi { | ||||||
|  |       inherit pname version; | ||||||
|  |       hash = "sha256-8nprah7Lh66swrUbzFnKeb5w7RKgEE3oYBR4shPdXYE="; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     build-system = [ | ||||||
|  |       setuptools | ||||||
|  |       wheel | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |       typing-extensions | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     # Skip tests as they may require specific setup | ||||||
|  |     doCheck = false; | ||||||
|  | 
 | ||||||
|  |     # Disable runtime dependencies check | ||||||
|  |     dontCheckRuntimeDeps = true; | ||||||
|  | 
 | ||||||
|  |     # Basic imports check | ||||||
|  |     pythonImportsCheck = ["pygeoif"]; | ||||||
|  | 
 | ||||||
|  |     meta = with lib; { | ||||||
|  |       description = "A basic implementation of the __geo_interface__"; | ||||||
|  |       homepage = "https://github.com/cleder/pygeoif"; | ||||||
|  |       license = licenses.lgpl21Plus; | ||||||
|  |       maintainers = []; | ||||||
|  |       platforms = platforms.all; | ||||||
|  |     }; | ||||||
|  |   } | ||||||
							
								
								
									
										40
									
								
								modules/common-modules/pkgs/python/rfeed.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								modules/common-modules/pkgs/python/rfeed.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   fetchPypi, | ||||||
|  |   buildPythonPackage, | ||||||
|  |   setuptools, | ||||||
|  |   python-dateutil, | ||||||
|  | }: | ||||||
|  | buildPythonPackage rec { | ||||||
|  |   pname = "rfeed"; | ||||||
|  |   version = "1.1.1"; | ||||||
|  |   pyproject = true; | ||||||
|  | 
 | ||||||
|  |   src = fetchPypi { | ||||||
|  |     inherit pname version; | ||||||
|  |     hash = "sha256-qpUG8oZrdPWjItOUoUpjwZpoJcLZR1X/GdRt0eJDSBk="; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   build-system = [ | ||||||
|  |     setuptools | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   dependencies = [ | ||||||
|  |     python-dateutil | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   # No tests available in the package | ||||||
|  |   doCheck = false; | ||||||
|  | 
 | ||||||
|  |   pythonImportsCheck = [ | ||||||
|  |     "rfeed" | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   meta = with lib; { | ||||||
|  |     description = "RSS feed generation library for Python"; | ||||||
|  |     homepage = "https://pypi.org/project/rfeed/"; | ||||||
|  |     license = licenses.mit; | ||||||
|  |     maintainers = []; | ||||||
|  |     platforms = platforms.all; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										65
									
								
								modules/common-modules/pkgs/sgblur.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								modules/common-modules/pkgs/sgblur.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   python3Packages, | ||||||
|  |   fetchFromGitHub, | ||||||
|  |   pkg-config, | ||||||
|  |   libjpeg_turbo, | ||||||
|  |   exiftran ? libjpeg_turbo, | ||||||
|  | }: | ||||||
|  | python3Packages.buildPythonPackage { | ||||||
|  |   pname = "sgblur"; | ||||||
|  |   version = "1.0.0"; | ||||||
|  | 
 | ||||||
|  |   pyproject = true; | ||||||
|  | 
 | ||||||
|  |   src = fetchFromGitHub { | ||||||
|  |     owner = "cquest"; | ||||||
|  |     repo = "sgblur"; | ||||||
|  |     rev = "master"; | ||||||
|  |     hash = "sha256-17wpif2sa021kaa1pbkry4l1967la1qd7knhngvxblrvd7jqqz4y="; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   nativeBuildInputs = [ | ||||||
|  |     pkg-config | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   buildInputs = [ | ||||||
|  |     libjpeg_turbo | ||||||
|  |     exiftran | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   build-system = with python3Packages; [ | ||||||
|  |     setuptools | ||||||
|  |     wheel | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   dependencies = with python3Packages; [ | ||||||
|  |     # Core dependencies from pyproject.toml | ||||||
|  |     ultralytics | ||||||
|  |     # pyturbojpeg  # May need special handling | ||||||
|  |     pillow | ||||||
|  |     # uuid  # Built into Python | ||||||
|  |     # exifread | ||||||
|  |     python-multipart | ||||||
|  |     fastapi | ||||||
|  |     uvicorn | ||||||
|  |     requests | ||||||
|  |     # piexif | ||||||
|  |     pydantic-settings | ||||||
|  |     pydantic | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   # Skip tests as they may require GPU or specific setup | ||||||
|  |   doCheck = false; | ||||||
|  | 
 | ||||||
|  |   # The package may have import issues due to system dependencies | ||||||
|  |   pythonImportsCheck = []; | ||||||
|  | 
 | ||||||
|  |   meta = with lib; { | ||||||
|  |     description = "Panoramax Speedy Gonzales Blurring Algorithm - AI-powered face and license plate blurring API"; | ||||||
|  |     homepage = "https://github.com/cquest/sgblur"; | ||||||
|  |     license = licenses.mit; | ||||||
|  |     maintainers = []; | ||||||
|  |     platforms = platforms.unix; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								modules/home-manager-modules/programs/davinci-resolve.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								modules/home-manager-modules/programs/davinci-resolve.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.davinci-resolve = { | ||||||
|  |     enable = lib.mkEnableOption "enable davinci-resolve"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.davinci-resolve.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       home.packages = with pkgs; [ | ||||||
|  |         davinci-resolve | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |     ( | ||||||
|  |       lib.mkIf osConfig.host.impermanence.enable { | ||||||
|  |         home.persistence."/persist${config.home.homeDirectory}" = { | ||||||
|  |           directories = [ | ||||||
|  |             "${config.xdg.dataHome}/DaVinciResolve" | ||||||
|  |             "${config.xdg.configHome}/blackmagic" | ||||||
|  |           ]; | ||||||
|  |           allowOther = true; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
|  | @ -19,5 +19,25 @@ | ||||||
|     ./dbeaver.nix |     ./dbeaver.nix | ||||||
|     ./steam.nix |     ./steam.nix | ||||||
|     ./vscode |     ./vscode | ||||||
|  |     ./ungoogled-chromium.nix | ||||||
|  |     ./libreoffice.nix | ||||||
|  |     ./mapillary-uploader.nix | ||||||
|  |     ./inkscape.nix | ||||||
|  |     ./gimp.nix | ||||||
|  |     ./proxmark3.nix | ||||||
|  |     ./freecad.nix | ||||||
|  |     ./onionshare.nix | ||||||
|  |     ./mfoc.nix | ||||||
|  |     ./pdfarranger.nix | ||||||
|  |     ./picard.nix | ||||||
|  |     ./qflipper.nix | ||||||
|  |     ./openvpn.nix | ||||||
|  |     ./noisetorch.nix | ||||||
|  |     ./openrgb.nix | ||||||
|  |     ./via.nix | ||||||
|  |     ./davinci-resolve.nix | ||||||
|  |     ./gdx-liftoff.nix | ||||||
|  |     ./tor-browser.nix | ||||||
|  |     ./polycule.nix | ||||||
|   ]; |   ]; | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										29
									
								
								modules/home-manager-modules/programs/freecad.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/home-manager-modules/programs/freecad.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.freecad = { | ||||||
|  |     enable = lib.mkEnableOption "enable freecad"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.freecad.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       home.packages = with pkgs; [ | ||||||
|  |         freecad | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |     ( | ||||||
|  |       lib.mkIf osConfig.host.impermanence.enable { | ||||||
|  |         home.persistence."/persist${config.home.homeDirectory}" = { | ||||||
|  |           directories = [ | ||||||
|  |             "${config.xdg.configHome}/FreeCAD" | ||||||
|  |           ]; | ||||||
|  |           allowOther = true; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								modules/home-manager-modules/programs/gdx-liftoff.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/home-manager-modules/programs/gdx-liftoff.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.gdx-liftoff = { | ||||||
|  |     enable = lib.mkEnableOption "enable gdx-liftoff"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.gdx-liftoff.enable { | ||||||
|  |     home.packages = with pkgs; [ | ||||||
|  |       gdx-liftoff | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								modules/home-manager-modules/programs/gimp.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/home-manager-modules/programs/gimp.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.gimp = { | ||||||
|  |     enable = lib.mkEnableOption "enable gimp"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.gimp.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       home.packages = with pkgs; [ | ||||||
|  |         gimp | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |     ( | ||||||
|  |       lib.mkIf osConfig.host.impermanence.enable { | ||||||
|  |         home.persistence."/persist${config.home.homeDirectory}" = { | ||||||
|  |           directories = [ | ||||||
|  |             "${config.xdg.configHome}/GIMP" | ||||||
|  |           ]; | ||||||
|  |           allowOther = true; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								modules/home-manager-modules/programs/inkscape.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/home-manager-modules/programs/inkscape.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.inkscape = { | ||||||
|  |     enable = lib.mkEnableOption "enable inkscape"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.inkscape.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       home.packages = with pkgs; [ | ||||||
|  |         inkscape | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |     ( | ||||||
|  |       lib.mkIf osConfig.host.impermanence.enable { | ||||||
|  |         home.persistence."/persist${config.home.homeDirectory}" = { | ||||||
|  |           directories = [ | ||||||
|  |             "${config.xdg.configHome}/inkscape" | ||||||
|  |           ]; | ||||||
|  |           allowOther = true; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								modules/home-manager-modules/programs/libreoffice.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/home-manager-modules/programs/libreoffice.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.libreoffice = { | ||||||
|  |     enable = lib.mkEnableOption "enable libreoffice"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.libreoffice.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       home.packages = with pkgs; [ | ||||||
|  |         libreoffice | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |     ( | ||||||
|  |       lib.mkIf osConfig.host.impermanence.enable { | ||||||
|  |         home.persistence."/persist${config.home.homeDirectory}" = { | ||||||
|  |           directories = [ | ||||||
|  |             "${config.xdg.configHome}/libreoffice" | ||||||
|  |           ]; | ||||||
|  |           allowOther = true; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								modules/home-manager-modules/programs/mapillary-uploader.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/home-manager-modules/programs/mapillary-uploader.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | { | ||||||
|  |   config, | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   ... | ||||||
|  | }: | ||||||
|  | with lib; let | ||||||
|  |   cfg = config.programs.mapillary-uploader; | ||||||
|  | in { | ||||||
|  |   options.programs.mapillary-uploader = { | ||||||
|  |     enable = mkEnableOption "Mapillary Desktop Uploader"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = mkIf cfg.enable { | ||||||
|  |     home.packages = [pkgs.mapillary-uploader]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								modules/home-manager-modules/programs/mfoc.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/home-manager-modules/programs/mfoc.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.mfoc = { | ||||||
|  |     enable = lib.mkEnableOption "enable mfoc"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.mfoc.enable { | ||||||
|  |     home.packages = with pkgs; [ | ||||||
|  |       mfoc | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								modules/home-manager-modules/programs/noisetorch.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/home-manager-modules/programs/noisetorch.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.noisetorch = { | ||||||
|  |     enable = lib.mkEnableOption "enable noisetorch"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.noisetorch.enable { | ||||||
|  |     home.packages = with pkgs; [ | ||||||
|  |       noisetorch | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								modules/home-manager-modules/programs/onionshare.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/home-manager-modules/programs/onionshare.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.onionshare = { | ||||||
|  |     enable = lib.mkEnableOption "enable onionshare"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.onionshare.enable { | ||||||
|  |     home.packages = with pkgs; [ | ||||||
|  |       onionshare | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								modules/home-manager-modules/programs/openrgb.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/home-manager-modules/programs/openrgb.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.openrgb = { | ||||||
|  |     enable = lib.mkEnableOption "enable openrgb"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.openrgb.enable { | ||||||
|  |     home.packages = with pkgs; [ | ||||||
|  |       openrgb | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								modules/home-manager-modules/programs/openvpn.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/home-manager-modules/programs/openvpn.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.openvpn = { | ||||||
|  |     enable = lib.mkEnableOption "enable openvpn"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.openvpn.enable { | ||||||
|  |     home.packages = with pkgs; [ | ||||||
|  |       openvpn | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								modules/home-manager-modules/programs/pdfarranger.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/home-manager-modules/programs/pdfarranger.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.pdfarranger = { | ||||||
|  |     enable = lib.mkEnableOption "enable pdfarranger"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.pdfarranger.enable { | ||||||
|  |     home.packages = with pkgs; [ | ||||||
|  |       pdfarranger | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								modules/home-manager-modules/programs/picard.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/home-manager-modules/programs/picard.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.picard = { | ||||||
|  |     enable = lib.mkEnableOption "enable picard"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.picard.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       home.packages = with pkgs; [ | ||||||
|  |         picard | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |     ( | ||||||
|  |       lib.mkIf osConfig.host.impermanence.enable { | ||||||
|  |         home.persistence."/persist${config.home.homeDirectory}" = { | ||||||
|  |           directories = [ | ||||||
|  |             "${config.xdg.configHome}/MusicBrainz" | ||||||
|  |           ]; | ||||||
|  |           allowOther = true; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								modules/home-manager-modules/programs/polycule.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								modules/home-manager-modules/programs/polycule.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.polycule = { | ||||||
|  |     enable = lib.mkEnableOption "enable polycule matrix client"; | ||||||
|  |     package = lib.mkPackageOption pkgs "polycule" {}; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.polycule.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       home.packages = [ | ||||||
|  |         config.programs.polycule.package | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |     ( | ||||||
|  |       lib.mkIf osConfig.host.impermanence.enable { | ||||||
|  |         home.persistence."/persist${config.home.homeDirectory}" = { | ||||||
|  |           # TODO: check that these are actually the correct folders | ||||||
|  |           # directories = [ | ||||||
|  |           #   "${config.xdg.configHome}/polycule" | ||||||
|  |           #   "${config.xdg.dataHome}/polycule" | ||||||
|  |           #   "${config.xdg.cacheHome}/polycule" | ||||||
|  |           # ]; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								modules/home-manager-modules/programs/proxmark3.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/home-manager-modules/programs/proxmark3.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.proxmark3 = { | ||||||
|  |     enable = lib.mkEnableOption "enable proxmark3"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.proxmark3.enable { | ||||||
|  |     home.packages = with pkgs; [ | ||||||
|  |       proxmark3 | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								modules/home-manager-modules/programs/qflipper.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/home-manager-modules/programs/qflipper.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.qflipper = { | ||||||
|  |     enable = lib.mkEnableOption "enable qflipper"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.qflipper.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       home.packages = with pkgs; [ | ||||||
|  |         qFlipper | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |     ( | ||||||
|  |       lib.mkIf osConfig.host.impermanence.enable { | ||||||
|  |         home.persistence."/persist${config.home.homeDirectory}" = { | ||||||
|  |           directories = [ | ||||||
|  |             "${config.xdg.configHome}/qFlipper" | ||||||
|  |           ]; | ||||||
|  |           allowOther = true; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								modules/home-manager-modules/programs/tor-browser.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/home-manager-modules/programs/tor-browser.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.tor-browser = { | ||||||
|  |     enable = lib.mkEnableOption "enable tor-browser"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.tor-browser.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       home.packages = with pkgs; [ | ||||||
|  |         tor-browser | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |     ( | ||||||
|  |       lib.mkIf osConfig.host.impermanence.enable { | ||||||
|  |         home.persistence."/persist${config.home.homeDirectory}" = { | ||||||
|  |           directories = [ | ||||||
|  |             "${config.xdg.dataHome}/torbrowser" | ||||||
|  |           ]; | ||||||
|  |           allowOther = true; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								modules/home-manager-modules/programs/ungoogled-chromium.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/home-manager-modules/programs/ungoogled-chromium.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.ungoogled-chromium = { | ||||||
|  |     enable = lib.mkEnableOption "enable ungoogled-chromium"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.ungoogled-chromium.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       home.packages = with pkgs; [ | ||||||
|  |         ungoogled-chromium | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |     ( | ||||||
|  |       lib.mkIf osConfig.host.impermanence.enable { | ||||||
|  |         home.persistence."/persist${config.home.homeDirectory}" = { | ||||||
|  |           directories = [ | ||||||
|  |             "${config.xdg.configHome}/chromium" | ||||||
|  |           ]; | ||||||
|  |           allowOther = true; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								modules/home-manager-modules/programs/via.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/home-manager-modules/programs/via.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.programs.via = { | ||||||
|  |     enable = lib.mkEnableOption "enable via"; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.programs.via.enable { | ||||||
|  |     home.packages = with pkgs; [ | ||||||
|  |       via | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | @ -10,10 +10,6 @@ | ||||||
| 
 | 
 | ||||||
|   mcp-nixos = inputs.mcp-nixos.packages.${pkgs.stdenv.hostPlatform.system}.default; |   mcp-nixos = inputs.mcp-nixos.packages.${pkgs.stdenv.hostPlatform.system}.default; | ||||||
| 
 | 
 | ||||||
|   mcp-eslint = pkgs.writeShellScriptBin "mcp-eslint" '' |  | ||||||
|     ${pkgs.nodejs}/bin/npx --yes @modelcontextprotocol/server-eslint "$@" |  | ||||||
|   ''; |  | ||||||
| 
 |  | ||||||
|   anyProfileHasMcpNixos = lib.any ( |   anyProfileHasMcpNixos = lib.any ( | ||||||
|     profile: |     profile: | ||||||
|       profile.extraExtensions.claudeDev.enable |       profile.extraExtensions.claudeDev.enable | ||||||
|  | @ -25,6 +21,44 @@ | ||||||
|       profile.extraExtensions.claudeDev.enable |       profile.extraExtensions.claudeDev.enable | ||||||
|       && profile.extraExtensions.claudeDev.mcp.eslint.enable |       && profile.extraExtensions.claudeDev.mcp.eslint.enable | ||||||
|   ) (lib.attrValues config.programs.vscode.profiles); |   ) (lib.attrValues config.programs.vscode.profiles); | ||||||
|  | 
 | ||||||
|  |   anyProfileHasMcpVitest = lib.any ( | ||||||
|  |     profile: | ||||||
|  |       profile.extraExtensions.claudeDev.enable | ||||||
|  |       && profile.extraExtensions.claudeDev.mcp.vitest.enable | ||||||
|  |   ) (lib.attrValues config.programs.vscode.profiles); | ||||||
|  | 
 | ||||||
|  |   anyProfileHasMcpSleep = lib.any ( | ||||||
|  |     profile: | ||||||
|  |       profile.extraExtensions.claudeDev.enable | ||||||
|  |       && profile.extraExtensions.claudeDev.mcp.sleep.enable | ||||||
|  |   ) (lib.attrValues config.programs.vscode.profiles); | ||||||
|  | 
 | ||||||
|  |   anyProfileHasMcp = anyProfileHasMcpNixos || anyProfileHasMcpEslint || anyProfileHasMcpVitest || anyProfileHasMcpSleep; | ||||||
|  | 
 | ||||||
|  |   getMcpTimeout = serverName: | ||||||
|  |     lib.findFirst (timeout: timeout != null) null (map ( | ||||||
|  |       profile: | ||||||
|  |         if profile.extraExtensions.claudeDev.enable && profile.extraExtensions.claudeDev.mcp.${serverName}.enable | ||||||
|  |         then profile.extraExtensions.claudeDev.mcp.${serverName}.timeout | ||||||
|  |         else null | ||||||
|  |     ) (lib.attrValues config.programs.vscode.profiles)); | ||||||
|  | 
 | ||||||
|  |   getMcpAutoApprove = serverName: | ||||||
|  |     lib.foldl' ( | ||||||
|  |       acc: profile: | ||||||
|  |         if profile.extraExtensions.claudeDev.enable && profile.extraExtensions.claudeDev.mcp.${serverName}.enable | ||||||
|  |         then acc // profile.extraExtensions.claudeDev.mcp.${serverName}.autoApprove | ||||||
|  |         else acc | ||||||
|  |     ) {} (lib.attrValues config.programs.vscode.profiles); | ||||||
|  | 
 | ||||||
|  |   getMcpPackage = serverName: | ||||||
|  |     lib.findFirst (package: package != null) null (map ( | ||||||
|  |       profile: | ||||||
|  |         if profile.extraExtensions.claudeDev.enable && profile.extraExtensions.claudeDev.mcp.${serverName}.enable | ||||||
|  |         then profile.extraExtensions.claudeDev.mcp.${serverName}.package | ||||||
|  |         else null | ||||||
|  |     ) (lib.attrValues config.programs.vscode.profiles)); | ||||||
| in { | in { | ||||||
|   options.programs.vscode.profiles = lib.mkOption { |   options.programs.vscode.profiles = lib.mkOption { | ||||||
|     type = lib.types.attrsOf (lib.types.submodule ({config, ...}: { |     type = lib.types.attrsOf (lib.types.submodule ({config, ...}: { | ||||||
|  | @ -38,9 +72,66 @@ in { | ||||||
|           mcp = { |           mcp = { | ||||||
|             nixos = { |             nixos = { | ||||||
|               enable = lib.mkEnableOption "enable NixOS MCP server for Claude Dev"; |               enable = lib.mkEnableOption "enable NixOS MCP server for Claude Dev"; | ||||||
|  |               autoApprove = { | ||||||
|  |                 nixos_search = lib.mkEnableOption "should the nixos_search tool be auto approved for the nixos MCP server"; | ||||||
|  |                 nixos_info = lib.mkEnableOption "should the nixos_info tool be auto approved for the nixos MCP server"; | ||||||
|  |                 home_manager_search = lib.mkEnableOption "should the home_manager_search tool be auto approved for the nixos MCP server"; | ||||||
|  |                 home_manager_info = lib.mkEnableOption "should the home_manager_info tool be auto approved for the nixos MCP server"; | ||||||
|  |                 darwin_search = lib.mkEnableOption "should the darwin_search tool be auto approved for the nixos MCP server"; | ||||||
|  |                 darwin_info = lib.mkEnableOption "should the darwin_info tool be auto approved for the nixos MCP server"; | ||||||
|  |                 nixos_flakes_search = lib.mkEnableOption "should the nixos_flakes_search tool be auto approved for the nixos MCP server"; | ||||||
|  |               }; | ||||||
|             }; |             }; | ||||||
|             eslint = { |             eslint = { | ||||||
|               enable = lib.mkEnableOption "enable ESLint MCP server for Claude Dev"; |               enable = lib.mkEnableOption "enable ESLint MCP server for Claude Dev"; | ||||||
|  |               package = lib.mkOption { | ||||||
|  |                 type = lib.types.str; | ||||||
|  |                 default = "@eslint/mcp@latest"; | ||||||
|  |                 description = "NPM package to use for ESLint MCP server"; | ||||||
|  |               }; | ||||||
|  |               timeout = lib.mkOption { | ||||||
|  |                 type = lib.types.nullOr lib.types.int; | ||||||
|  |                 default = null; | ||||||
|  |                 description = "Timeout in seconds for ESLint MCP server operations"; | ||||||
|  |               }; | ||||||
|  |               autoApprove = { | ||||||
|  |                 lint-files = lib.mkEnableOption "Should the lint-files tool be auto approved for ESLint MCP server"; | ||||||
|  |               }; | ||||||
|  |             }; | ||||||
|  |             vitest = { | ||||||
|  |               enable = lib.mkEnableOption "enable Vitest MCP server for Claude Dev"; | ||||||
|  |               package = lib.mkOption { | ||||||
|  |                 type = lib.types.str; | ||||||
|  |                 default = "@djankies/vitest-mcp"; | ||||||
|  |                 description = "NPM package to use for Vitest MCP server"; | ||||||
|  |               }; | ||||||
|  |               timeout = lib.mkOption { | ||||||
|  |                 type = lib.types.nullOr lib.types.int; | ||||||
|  |                 default = null; | ||||||
|  |                 description = "Timeout in seconds for Vitest MCP server operations"; | ||||||
|  |               }; | ||||||
|  |               autoApprove = { | ||||||
|  |                 list_tests = lib.mkEnableOption "Should the list_tests tool be auto approved for Vitest MCP server"; | ||||||
|  |                 run_tests = lib.mkEnableOption "Should the run_tests tool be auto approved for Vitest MCP server"; | ||||||
|  |                 analyze_coverage = lib.mkEnableOption "Should the analyze_coverage tool be auto approved for Vitest MCP server"; | ||||||
|  |                 set_project_root = lib.mkEnableOption "Should the set_project_root tool be auto approved for Vitest MCP server"; | ||||||
|  |               }; | ||||||
|  |             }; | ||||||
|  |             sleep = { | ||||||
|  |               enable = lib.mkEnableOption "enable Sleep MCP server for Claude Dev"; | ||||||
|  |               package = lib.mkOption { | ||||||
|  |                 type = lib.types.str; | ||||||
|  |                 default = "sleep-mcp"; | ||||||
|  |                 description = "NPM package to use for Sleep MCP server"; | ||||||
|  |               }; | ||||||
|  |               timeout = lib.mkOption { | ||||||
|  |                 type = lib.types.nullOr lib.types.int; | ||||||
|  |                 default = null; | ||||||
|  |                 description = "Timeout in seconds for Sleep MCP server operations"; | ||||||
|  |               }; | ||||||
|  |               autoApprove = { | ||||||
|  |                 sleep = lib.mkEnableOption "Should the sleep tool be auto approved for Sleep MCP server"; | ||||||
|  |               }; | ||||||
|             }; |             }; | ||||||
|           }; |           }; | ||||||
|         }; |         }; | ||||||
|  | @ -60,14 +151,7 @@ in { | ||||||
|       ]; |       ]; | ||||||
|     }) |     }) | ||||||
| 
 | 
 | ||||||
|     (lib.mkIf anyProfileHasMcpEslint { |     (lib.mkIf anyProfileHasMcp { | ||||||
|       home.packages = [ |  | ||||||
|         mcp-eslint |  | ||||||
|         pkgs.eslint |  | ||||||
|       ]; |  | ||||||
|     }) |  | ||||||
| 
 |  | ||||||
|     (lib.mkIf (anyProfileHasMcpNixos || anyProfileHasMcpEslint) { |  | ||||||
|       home.file."${config.xdg.configHome}/VSCodium/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json" = { |       home.file."${config.xdg.configHome}/VSCodium/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json" = { | ||||||
|         text = builtins.toJSON { |         text = builtins.toJSON { | ||||||
|           mcpServers = |           mcpServers = | ||||||
|  | @ -77,9 +161,43 @@ in { | ||||||
|               }; |               }; | ||||||
|             }) |             }) | ||||||
|             // (lib.optionalAttrs anyProfileHasMcpEslint { |             // (lib.optionalAttrs anyProfileHasMcpEslint { | ||||||
|               eslint = { |               eslint = | ||||||
|                 command = "${mcp-eslint}/bin/mcp-eslint"; |                 { | ||||||
|               }; |                   command = "${pkgs.nodejs}/bin/npx"; | ||||||
|  |                   args = ["-y" (getMcpPackage "eslint")]; | ||||||
|  |                 } | ||||||
|  |                 // (lib.optionalAttrs ((getMcpTimeout "eslint") != null) { | ||||||
|  |                   timeout = getMcpTimeout "eslint"; | ||||||
|  |                 }) | ||||||
|  |                 // (lib.optionalAttrs ((getMcpAutoApprove "eslint") != {}) { | ||||||
|  |                   autoApprove = builtins.attrNames (lib.filterAttrs (_: v: v) (getMcpAutoApprove "eslint")); | ||||||
|  |                 }); | ||||||
|  |             }) | ||||||
|  |             // (lib.optionalAttrs anyProfileHasMcpVitest { | ||||||
|  |               vitest = | ||||||
|  |                 { | ||||||
|  |                   command = "${pkgs.nodejs}/bin/npx"; | ||||||
|  |                   args = ["-y" (getMcpPackage "vitest")]; | ||||||
|  |                 } | ||||||
|  |                 // (lib.optionalAttrs ((getMcpTimeout "vitest") != null) { | ||||||
|  |                   timeout = getMcpTimeout "vitest"; | ||||||
|  |                 }) | ||||||
|  |                 // (lib.optionalAttrs ((getMcpAutoApprove "vitest") != {}) { | ||||||
|  |                   autoApprove = builtins.attrNames (lib.filterAttrs (_: v: v) (getMcpAutoApprove "vitest")); | ||||||
|  |                 }); | ||||||
|  |             }) | ||||||
|  |             // (lib.optionalAttrs anyProfileHasMcpSleep { | ||||||
|  |               sleep-mcp = | ||||||
|  |                 { | ||||||
|  |                   command = "${pkgs.nodejs}/bin/npx"; | ||||||
|  |                   args = ["-y" (getMcpPackage "sleep")]; | ||||||
|  |                 } | ||||||
|  |                 // (lib.optionalAttrs ((getMcpTimeout "sleep") != null) { | ||||||
|  |                   timeout = getMcpTimeout "sleep"; | ||||||
|  |                 }) | ||||||
|  |                 // (lib.optionalAttrs ((getMcpAutoApprove "sleep") != {}) { | ||||||
|  |                   autoApprove = builtins.attrNames (lib.filterAttrs (_: v: v) (getMcpAutoApprove "sleep")); | ||||||
|  |                 }); | ||||||
|             }); |             }); | ||||||
|         }; |         }; | ||||||
|         force = true; |         force = true; | ||||||
|  |  | ||||||
|  | @ -0,0 +1,34 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   pkgsRepositories = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version; | ||||||
|  |   pkgsRepository = pkgsRepositories.vscode-marketplace; | ||||||
|  | in { | ||||||
|  |   options.programs.vscode.profiles = lib.mkOption { | ||||||
|  |     type = lib.types.attrsOf (lib.types.submodule ({config, ...}: { | ||||||
|  |       options = { | ||||||
|  |         extraExtensions.conventionalCommits = { | ||||||
|  |           enable = lib.mkEnableOption "Enable VSCode Conventional Commits extension"; | ||||||
|  |           extension = lib.mkPackageOption pkgsRepository "conventional-commits" { | ||||||
|  |             default = ["vivaxy" "vscode-conventional-commits"]; | ||||||
|  |           }; | ||||||
|  | 
 | ||||||
|  |           gitmoji = lib.mkEnableOption "should emoji be prompted for as a part of the commit message./"; | ||||||
|  | 
 | ||||||
|  |           promptScopes = lib.mkEnableOption "prompting for scopes in conventional commits"; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |       config = lib.mkIf config.extraExtensions.conventionalCommits.enable { | ||||||
|  |         extensions = [config.extraExtensions.conventionalCommits.extension]; | ||||||
|  | 
 | ||||||
|  |         userSettings = { | ||||||
|  |           "conventionalCommits.gitmoji" = config.extraExtensions.conventionalCommits.gitmoji; | ||||||
|  |           "conventionalCommits.promptScopes" = config.extraExtensions.conventionalCommits.promptScopes; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     })); | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | @ -21,5 +21,7 @@ | ||||||
|     ./claudeDev.nix |     ./claudeDev.nix | ||||||
|     ./nearley.nix |     ./nearley.nix | ||||||
|     ./vitest.nix |     ./vitest.nix | ||||||
|  |     ./direnv.nix | ||||||
|  |     ./conventionalCommits.nix | ||||||
|   ]; |   ]; | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										25
									
								
								modules/home-manager-modules/programs/vscode/direnv.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								modules/home-manager-modules/programs/vscode/direnv.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   pkgsRepositories = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version; | ||||||
|  |   pkgsRepository = pkgsRepositories.vscode-marketplace; | ||||||
|  | in { | ||||||
|  |   options.programs.vscode.profiles = lib.mkOption { | ||||||
|  |     type = lib.types.attrsOf (lib.types.submodule ({config, ...}: { | ||||||
|  |       options = { | ||||||
|  |         extraExtensions.direnv = { | ||||||
|  |           enable = lib.mkEnableOption "Enable direnv extension"; | ||||||
|  |           extension = lib.mkPackageOption pkgsRepository "direnv" { | ||||||
|  |             default = ["mkhl" "direnv"]; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |       config = lib.mkIf config.extraExtensions.direnv.enable { | ||||||
|  |         extensions = [config.extraExtensions.direnv.extension]; | ||||||
|  |       }; | ||||||
|  |     })); | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | @ -1,54 +0,0 @@ | ||||||
| { |  | ||||||
|   lib, |  | ||||||
|   config, |  | ||||||
|   ... |  | ||||||
| }: let |  | ||||||
|   dataDirectory = "/var/lib/actual/"; |  | ||||||
| in { |  | ||||||
|   options.services.actual = { |  | ||||||
|     subdomain = lib.mkOption { |  | ||||||
|       type = lib.types.str; |  | ||||||
|       default = "actual"; |  | ||||||
|       description = "subdomain of base domain that actual will be hosted at"; |  | ||||||
|     }; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   config = lib.mkIf config.services.actual.enable (lib.mkMerge [ |  | ||||||
|     { |  | ||||||
|       systemd.tmpfiles.rules = [ |  | ||||||
|         "d ${dataDirectory} 2770 actual actual" |  | ||||||
|       ]; |  | ||||||
|       host = { |  | ||||||
|         reverse_proxy.subdomains.${config.services.actual.subdomain} = { |  | ||||||
|           target = "http://localhost:${toString config.services.actual.settings.port}"; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       services.actual = { |  | ||||||
|         settings = { |  | ||||||
|           ACTUAL_DATA_DIR = dataDirectory; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
|     } |  | ||||||
|     (lib.mkIf config.services.fail2ban.enable { |  | ||||||
|       # TODO: configuration for fail2ban for actual |  | ||||||
|     }) |  | ||||||
|     (lib.mkIf config.host.impermanence.enable { |  | ||||||
|       assertions = [ |  | ||||||
|         { |  | ||||||
|           assertion = config.services.actual.settings.ACTUAL_DATA_DIR == dataDirectory; |  | ||||||
|           message = "actual data location does not match persistence"; |  | ||||||
|         } |  | ||||||
|       ]; |  | ||||||
|       environment.persistence."/persist/system/root" = { |  | ||||||
|         directories = [ |  | ||||||
|           { |  | ||||||
|             directory = dataDirectory; |  | ||||||
|             user = "actual"; |  | ||||||
|             group = "actual"; |  | ||||||
|           } |  | ||||||
|         ]; |  | ||||||
|       }; |  | ||||||
|     }) |  | ||||||
|   ]); |  | ||||||
| } |  | ||||||
							
								
								
									
										3
									
								
								modules/nixos-modules/server/actual/const.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								modules/nixos-modules/server/actual/const.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | ||||||
|  | { | ||||||
|  |   dataDirectory = "/var/lib/actual/"; | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								modules/nixos-modules/server/actual/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								modules/nixos-modules/server/actual/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   const = import ./const.nix; | ||||||
|  |   dataDirectory = const.dataDirectory; | ||||||
|  | in { | ||||||
|  |   imports = [ | ||||||
|  |     ./proxy.nix | ||||||
|  |     ./fail2ban.nix | ||||||
|  |     ./impermanence.nix | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.services.actual.enable { | ||||||
|  |     systemd.tmpfiles.rules = [ | ||||||
|  |       "d ${dataDirectory} 2770 actual actual" | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     services.actual = { | ||||||
|  |       settings = { | ||||||
|  |         ACTUAL_DATA_DIR = dataDirectory; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								modules/nixos-modules/server/actual/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								modules/nixos-modules/server/actual/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   config = lib.mkIf (config.services.actual.enable && config.services.fail2ban.enable) { | ||||||
|  |     # TODO: configuration for fail2ban for actual | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								modules/nixos-modules/server/actual/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								modules/nixos-modules/server/actual/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   const = import ./const.nix; | ||||||
|  |   dataDirectory = const.dataDirectory; | ||||||
|  | in { | ||||||
|  |   config = lib.mkIf (config.services.actual.enable && config.host.impermanence.enable) { | ||||||
|  |     assertions = [ | ||||||
|  |       { | ||||||
|  |         assertion = config.services.actual.settings.ACTUAL_DATA_DIR == dataDirectory; | ||||||
|  |         message = "actual data location does not match persistence"; | ||||||
|  |       } | ||||||
|  |     ]; | ||||||
|  |     environment.persistence."/persist/system/root" = { | ||||||
|  |       directories = [ | ||||||
|  |         { | ||||||
|  |           directory = dataDirectory; | ||||||
|  |           user = "actual"; | ||||||
|  |           group = "actual"; | ||||||
|  |         } | ||||||
|  |       ]; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								modules/nixos-modules/server/actual/proxy.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								modules/nixos-modules/server/actual/proxy.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.services.actual = { | ||||||
|  |     subdomain = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       default = "actual"; | ||||||
|  |       description = "subdomain of base domain that actual will be hosted at"; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf (config.services.actual.enable && config.host.reverse_proxy.enable) { | ||||||
|  |     host = { | ||||||
|  |       reverse_proxy.subdomains.${config.services.actual.subdomain} = { | ||||||
|  |         target = "http://localhost:${toString config.services.actual.settings.port}"; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								modules/nixos-modules/server/bazarr/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								modules/nixos-modules/server/bazarr/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | ||||||
|  | {...}: { | ||||||
|  |   imports = [ | ||||||
|  |     ./proxy.nix | ||||||
|  |     ./impermanence.nix | ||||||
|  |   ]; | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								modules/nixos-modules/server/bazarr/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								modules/nixos-modules/server/bazarr/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   bazarr_data_directory = "/var/lib/bazarr"; | ||||||
|  | in { | ||||||
|  |   config = lib.mkIf (config.services.bazarr.enable && config.host.impermanence.enable) { | ||||||
|  |     assertions = [ | ||||||
|  |       { | ||||||
|  |         assertion = config.services.bazarr.dataDir == bazarr_data_directory; | ||||||
|  |         message = "bazarr data directory does not match persistence"; | ||||||
|  |       } | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     environment.persistence."/persist/system/root" = { | ||||||
|  |       directories = [ | ||||||
|  |         { | ||||||
|  |           directory = bazarr_data_directory; | ||||||
|  |           user = "bazarr"; | ||||||
|  |           group = "bazarr"; | ||||||
|  |         } | ||||||
|  |       ]; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								modules/nixos-modules/server/bazarr/proxy.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								modules/nixos-modules/server/bazarr/proxy.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.services.bazarr = { | ||||||
|  |     subdomain = lib.mkOption { | ||||||
|  |       type = lib.types.nullOr lib.types.str; | ||||||
|  |       default = null; | ||||||
|  |       description = "Subdomain for reverse proxy. If null, service will be local only."; | ||||||
|  |     }; | ||||||
|  |     extraSubdomains = lib.mkOption { | ||||||
|  |       type = lib.types.listOf lib.types.str; | ||||||
|  |       default = []; | ||||||
|  |       description = "Extra subdomains for reverse proxy."; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf (config.services.bazarr.enable && config.services.bazarr.subdomain != null) { | ||||||
|  |     host.reverse_proxy.subdomains.bazarr = { | ||||||
|  |       subdomain = config.services.bazarr.subdomain; | ||||||
|  |       extraSubdomains = config.services.bazarr.extraSubdomains; | ||||||
|  |       target = "http://127.0.0.1:6767"; | ||||||
|  |       websockets.enable = true; | ||||||
|  |       forwardHeaders.enable = true; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | @ -1,18 +1,23 @@ | ||||||
| {...}: { | {...}: { | ||||||
|   imports = [ |   imports = [ | ||||||
|     ./fail2ban.nix |  | ||||||
|     ./network_storage |  | ||||||
|     ./reverse_proxy.nix |     ./reverse_proxy.nix | ||||||
|  |     ./fail2ban.nix | ||||||
|     ./postgres.nix |     ./postgres.nix | ||||||
|  |     ./network_storage | ||||||
|     ./podman.nix |     ./podman.nix | ||||||
|     ./jellyfin.nix | 
 | ||||||
|     ./forgejo.nix |     ./actual | ||||||
|     ./searx.nix |     ./bazarr | ||||||
|     ./home-assistant.nix |     ./forgejo | ||||||
|     ./wyoming.nix |     ./home-assistant | ||||||
|     ./immich.nix |     ./immich | ||||||
|  |     ./jellyfin | ||||||
|  |     ./panoramax | ||||||
|  |     ./paperless | ||||||
|     ./qbittorent.nix |     ./qbittorent.nix | ||||||
|     ./paperless.nix |     ./radarr | ||||||
|     ./actual.nix |     ./searx | ||||||
|  |     ./sonarr | ||||||
|  |     ./wyoming.nix | ||||||
|   ]; |   ]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,124 +0,0 @@ | ||||||
| { |  | ||||||
|   lib, |  | ||||||
|   config, |  | ||||||
|   pkgs, |  | ||||||
|   ... |  | ||||||
| }: let |  | ||||||
|   forgejoPort = 8081; |  | ||||||
|   stateDir = "/var/lib/forgejo"; |  | ||||||
|   db_user = "forgejo"; |  | ||||||
|   sshPort = 22222; |  | ||||||
| in { |  | ||||||
|   options.services.forgejo = { |  | ||||||
|     subdomain = lib.mkOption { |  | ||||||
|       type = lib.types.str; |  | ||||||
|       description = "subdomain of base domain that forgejo will be hosted at"; |  | ||||||
|       default = "forgejo"; |  | ||||||
|     }; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   config = lib.mkIf config.services.forgejo.enable (lib.mkMerge [ |  | ||||||
|     { |  | ||||||
|       assertions = [ |  | ||||||
|         { |  | ||||||
|           assertion = config.services.forgejo.settings.server.BUILTIN_SSH_SERVER_USER == config.users.users.git.name; |  | ||||||
|           message = "Forgejo BUILTIN_SSH_SERVER_USER hardcoded value does not match expected git user name"; |  | ||||||
|         } |  | ||||||
|       ]; |  | ||||||
|       host = { |  | ||||||
|         reverse_proxy.subdomains.${config.services.forgejo.subdomain} = { |  | ||||||
|           target = "http://localhost:${toString forgejoPort}"; |  | ||||||
|         }; |  | ||||||
|         postgres = { |  | ||||||
|           enable = true; |  | ||||||
|           extraUsers = { |  | ||||||
|             ${db_user} = { |  | ||||||
|               isClient = true; |  | ||||||
|               createUser = true; |  | ||||||
|             }; |  | ||||||
|           }; |  | ||||||
|           extraDatabases = { |  | ||||||
|             ${db_user} = { |  | ||||||
|               name = db_user; |  | ||||||
|             }; |  | ||||||
|           }; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       services.forgejo = { |  | ||||||
|         database = { |  | ||||||
|           type = "postgres"; |  | ||||||
|           socket = "/run/postgresql"; |  | ||||||
|         }; |  | ||||||
|         lfs.enable = true; |  | ||||||
|         settings = { |  | ||||||
|           server = { |  | ||||||
|             DOMAIN = "${config.services.forgejo.subdomain}.${config.host.reverse_proxy.hostname}"; |  | ||||||
|             HTTP_PORT = forgejoPort; |  | ||||||
|             START_SSH_SERVER = true; |  | ||||||
|             SSH_LISTEN_PORT = sshPort; |  | ||||||
|             SSH_PORT = 22; |  | ||||||
|             BUILTIN_SSH_SERVER_USER = "git"; |  | ||||||
|             ROOT_URL = "https://git.jan-leila.com"; |  | ||||||
|           }; |  | ||||||
|           service = { |  | ||||||
|             DISABLE_REGISTRATION = true; |  | ||||||
|           }; |  | ||||||
|           database = { |  | ||||||
|             DB_TYPE = "postgres"; |  | ||||||
|             NAME = db_user; |  | ||||||
|             USER = db_user; |  | ||||||
|           }; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       networking.firewall.allowedTCPPorts = [ |  | ||||||
|         config.services.forgejo.settings.server.SSH_LISTEN_PORT |  | ||||||
|       ]; |  | ||||||
|     } |  | ||||||
|     (lib.mkIf config.services.fail2ban.enable { |  | ||||||
|       environment.etc = { |  | ||||||
|         "fail2ban/filter.d/forgejo.local".text = lib.mkIf config.services.forgejo.enable ( |  | ||||||
|           pkgs.lib.mkDefault (pkgs.lib.mkAfter '' |  | ||||||
|             [Definition] |  | ||||||
|             failregex = ".*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>" |  | ||||||
|           '') |  | ||||||
|         ); |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       services.fail2ban = { |  | ||||||
|         jails = { |  | ||||||
|           forgejo-iptables.settings = lib.mkIf config.services.forgejo.enable { |  | ||||||
|             enabled = true; |  | ||||||
|             filter = "forgejo"; |  | ||||||
|             action = ''iptables-multiport[name=HTTP, port="http,https"]''; |  | ||||||
|             logpath = "${config.services.forgejo.settings.log.ROOT_PATH}/*.log"; |  | ||||||
|             backend = "auto"; |  | ||||||
|             findtime = 600; |  | ||||||
|             bantime = 600; |  | ||||||
|             maxretry = 5; |  | ||||||
|           }; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
|     }) |  | ||||||
|     (lib.mkIf config.host.impermanence.enable { |  | ||||||
|       assertions = [ |  | ||||||
|         { |  | ||||||
|           assertion = config.services.forgejo.stateDir == stateDir; |  | ||||||
|           message = "forgejo state directory does not match persistence"; |  | ||||||
|         } |  | ||||||
|       ]; |  | ||||||
|       environment.persistence."/persist/system/root" = { |  | ||||||
|         enable = true; |  | ||||||
|         hideMounts = true; |  | ||||||
|         directories = [ |  | ||||||
|           { |  | ||||||
|             directory = stateDir; |  | ||||||
|             user = "forgejo"; |  | ||||||
|             group = "forgejo"; |  | ||||||
|           } |  | ||||||
|         ]; |  | ||||||
|       }; |  | ||||||
|     }) |  | ||||||
|   ]); |  | ||||||
| } |  | ||||||
							
								
								
									
										4
									
								
								modules/nixos-modules/server/forgejo/const.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								modules/nixos-modules/server/forgejo/const.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | ||||||
|  | { | ||||||
|  |   httpPort = 8081; | ||||||
|  |   sshPort = 22222; | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								modules/nixos-modules/server/forgejo/database.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								modules/nixos-modules/server/forgejo/database.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   config = lib.mkIf config.services.forgejo.enable ( | ||||||
|  |     lib.mkMerge [ | ||||||
|  |       { | ||||||
|  |         host = { | ||||||
|  |           postgres = { | ||||||
|  |             enable = true; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         assertions = [ | ||||||
|  |           { | ||||||
|  |             assertion = config.services.forgejo.settings.database.DB_TYPE == "postgres"; | ||||||
|  |             message = "Forgejo database type must be postgres"; | ||||||
|  |           } | ||||||
|  |         ]; | ||||||
|  |       } | ||||||
|  |       (lib.mkIf config.host.postgres.enable { | ||||||
|  |         host = { | ||||||
|  |           postgres = { | ||||||
|  |             extraUsers = { | ||||||
|  |               forgejo = { | ||||||
|  |                 isClient = true; | ||||||
|  |                 createUser = true; | ||||||
|  |               }; | ||||||
|  |             }; | ||||||
|  |             extraDatabases = { | ||||||
|  |               forgejo = { | ||||||
|  |                 name = "forgejo"; | ||||||
|  |               }; | ||||||
|  |             }; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  |       }) | ||||||
|  |     ] | ||||||
|  |   ); | ||||||
|  | } | ||||||
							
								
								
									
										53
									
								
								modules/nixos-modules/server/forgejo/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								modules/nixos-modules/server/forgejo/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   const = import ./const.nix; | ||||||
|  |   httpPort = const.httpPort; | ||||||
|  |   sshPort = const.sshPort; | ||||||
|  |   db_user = "forgejo"; | ||||||
|  | in { | ||||||
|  |   imports = [ | ||||||
|  |     ./proxy.nix | ||||||
|  |     ./database.nix | ||||||
|  |     ./fail2ban.nix | ||||||
|  |     ./impermanence.nix | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.services.forgejo.enable { | ||||||
|  |     assertions = [ | ||||||
|  |       { | ||||||
|  |         assertion = config.services.forgejo.settings.server.BUILTIN_SSH_SERVER_USER == config.users.users.git.name; | ||||||
|  |         message = "Forgejo BUILTIN_SSH_SERVER_USER hardcoded value does not match expected git user name"; | ||||||
|  |       } | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     services.forgejo = { | ||||||
|  |       database = { | ||||||
|  |         type = "postgres"; | ||||||
|  |         socket = "/run/postgresql"; | ||||||
|  |       }; | ||||||
|  |       lfs.enable = true; | ||||||
|  |       settings = { | ||||||
|  |         server = { | ||||||
|  |           DOMAIN = "${config.services.forgejo.subdomain}.${config.host.reverse_proxy.hostname}"; | ||||||
|  |           HTTP_PORT = httpPort; | ||||||
|  |           START_SSH_SERVER = true; | ||||||
|  |           SSH_LISTEN_PORT = sshPort; | ||||||
|  |           SSH_PORT = 22; | ||||||
|  |           BUILTIN_SSH_SERVER_USER = "git"; | ||||||
|  |           ROOT_URL = "https://git.jan-leila.com"; | ||||||
|  |         }; | ||||||
|  |         service = { | ||||||
|  |           DISABLE_REGISTRATION = true; | ||||||
|  |         }; | ||||||
|  |         database = { | ||||||
|  |           DB_TYPE = "postgres"; | ||||||
|  |           NAME = db_user; | ||||||
|  |           USER = db_user; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								modules/nixos-modules/server/forgejo/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								modules/nixos-modules/server/forgejo/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   pkgs, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   config = lib.mkIf (config.services.forgejo.enable && config.services.fail2ban.enable) { | ||||||
|  |     environment.etc = { | ||||||
|  |       "fail2ban/filter.d/forgejo.local".text = lib.mkIf config.services.forgejo.enable ( | ||||||
|  |         pkgs.lib.mkDefault (pkgs.lib.mkAfter '' | ||||||
|  |           [Definition] | ||||||
|  |           failregex = ".*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>" | ||||||
|  |         '') | ||||||
|  |       ); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     services.fail2ban = { | ||||||
|  |       jails = { | ||||||
|  |         forgejo-iptables.settings = lib.mkIf config.services.forgejo.enable { | ||||||
|  |           enabled = true; | ||||||
|  |           filter = "forgejo"; | ||||||
|  |           action = ''iptables-multiport[name=HTTP, port="http,https"]''; | ||||||
|  |           logpath = "${config.services.forgejo.settings.log.ROOT_PATH}/*.log"; | ||||||
|  |           backend = "auto"; | ||||||
|  |           findtime = 600; | ||||||
|  |           bantime = 600; | ||||||
|  |           maxretry = 5; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								modules/nixos-modules/server/forgejo/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								modules/nixos-modules/server/forgejo/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   stateDir = "/var/lib/forgejo"; | ||||||
|  | in { | ||||||
|  |   config = lib.mkIf (config.services.forgejo.enable && config.host.impermanence.enable) { | ||||||
|  |     assertions = [ | ||||||
|  |       { | ||||||
|  |         assertion = config.services.forgejo.stateDir == stateDir; | ||||||
|  |         message = "forgejo state directory does not match persistence"; | ||||||
|  |       } | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     environment.persistence."/persist/system/root" = { | ||||||
|  |       enable = true; | ||||||
|  |       hideMounts = true; | ||||||
|  |       directories = [ | ||||||
|  |         { | ||||||
|  |           directory = stateDir; | ||||||
|  |           user = "forgejo"; | ||||||
|  |           group = "forgejo"; | ||||||
|  |         } | ||||||
|  |       ]; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								modules/nixos-modules/server/forgejo/proxy.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								modules/nixos-modules/server/forgejo/proxy.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   const = import ./const.nix; | ||||||
|  |   httpPort = const.httpPort; | ||||||
|  | in { | ||||||
|  |   options.services.forgejo = { | ||||||
|  |     subdomain = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "subdomain of base domain that forgejo will be hosted at"; | ||||||
|  |       default = "forgejo"; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf (config.services.forgejo.enable && config.host.reverse_proxy.enable) { | ||||||
|  |     host.reverse_proxy.subdomains.${config.services.forgejo.subdomain} = { | ||||||
|  |       target = "http://localhost:${toString httpPort}"; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     networking.firewall.allowedTCPPorts = [ | ||||||
|  |       config.services.forgejo.settings.server.SSH_LISTEN_PORT | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | @ -1,229 +0,0 @@ | ||||||
| { |  | ||||||
|   lib, |  | ||||||
|   pkgs, |  | ||||||
|   config, |  | ||||||
|   ... |  | ||||||
| }: let |  | ||||||
|   configDir = "/var/lib/hass"; |  | ||||||
|   dbUser = "hass"; |  | ||||||
| in { |  | ||||||
|   options.services.home-assistant = { |  | ||||||
|     subdomain = lib.mkOption { |  | ||||||
|       type = lib.types.str; |  | ||||||
|       description = "subdomain of base domain that home-assistant will be hosted at"; |  | ||||||
|       default = "home-assistant"; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     database = lib.mkOption { |  | ||||||
|       type = lib.types.enum [ |  | ||||||
|         "builtin" |  | ||||||
|         "postgres" |  | ||||||
|       ]; |  | ||||||
|       description = "what database do we want to use"; |  | ||||||
|       default = "builtin"; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     extensions = { |  | ||||||
|       sonos = { |  | ||||||
|         enable = lib.mkEnableOption "enable the sonos plugin"; |  | ||||||
|         port = lib.mkOption { |  | ||||||
|           type = lib.types.int; |  | ||||||
|           default = 1400; |  | ||||||
|           description = "what port to use for sonos discovery"; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
|       jellyfin = { |  | ||||||
|         enable = lib.mkEnableOption "enable the jellyfin plugin"; |  | ||||||
|       }; |  | ||||||
|       wyoming = { |  | ||||||
|         enable = lib.mkEnableOption "enable wyoming"; |  | ||||||
|       }; |  | ||||||
|     }; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   config = lib.mkIf config.services.home-assistant.enable (lib.mkMerge [ |  | ||||||
|     { |  | ||||||
|       host = { |  | ||||||
|         reverse_proxy.subdomains.${config.services.home-assistant.subdomain} = { |  | ||||||
|           target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}"; |  | ||||||
| 
 |  | ||||||
|           websockets.enable = true; |  | ||||||
|           forwardHeaders.enable = true; |  | ||||||
| 
 |  | ||||||
|           extraConfig = '' |  | ||||||
|             add_header Upgrade $http_upgrade; |  | ||||||
|             add_header Connection \"upgrade\"; |  | ||||||
| 
 |  | ||||||
|             proxy_buffering off; |  | ||||||
| 
 |  | ||||||
|             proxy_read_timeout 90; |  | ||||||
|           ''; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       services.home-assistant = { |  | ||||||
|         configDir = configDir; |  | ||||||
|         extraComponents = [ |  | ||||||
|           "default_config" |  | ||||||
|           "esphome" |  | ||||||
|           "met" |  | ||||||
|           "radio_browser" |  | ||||||
|           "isal" |  | ||||||
|           "zha" |  | ||||||
|           "webostv" |  | ||||||
|           "tailscale" |  | ||||||
|           "syncthing" |  | ||||||
|           "analytics_insights" |  | ||||||
|           "unifi" |  | ||||||
|           "openweathermap" |  | ||||||
|           "ollama" |  | ||||||
|           "mobile_app" |  | ||||||
|           "logbook" |  | ||||||
|           "ssdp" |  | ||||||
|           "usb" |  | ||||||
|           "webhook" |  | ||||||
|           "bluetooth" |  | ||||||
|           "dhcp" |  | ||||||
|           "energy" |  | ||||||
|           "history" |  | ||||||
|           "backup" |  | ||||||
|           "assist_pipeline" |  | ||||||
|           "conversation" |  | ||||||
|           "sun" |  | ||||||
|           "zeroconf" |  | ||||||
|           "cpuspeed" |  | ||||||
|         ]; |  | ||||||
|         config = { |  | ||||||
|           http = { |  | ||||||
|             server_port = 8123; |  | ||||||
|             use_x_forwarded_for = true; |  | ||||||
|             trusted_proxies = ["127.0.0.1" "::1"]; |  | ||||||
|             ip_ban_enabled = true; |  | ||||||
|             login_attempts_threshold = 10; |  | ||||||
|           }; |  | ||||||
|           homeassistant = { |  | ||||||
|             external_url = "https://${config.services.home-assistant.subdomain}.${config.host.reverse_proxy.hostname}"; |  | ||||||
|             # internal_url = "http://192.168.1.2:8123"; |  | ||||||
|           }; |  | ||||||
|           recorder.db_url = "postgresql://@/${dbUser}"; |  | ||||||
|           "automation manual" = []; |  | ||||||
|           "automation ui" = "!include automations.yaml"; |  | ||||||
|           mobile_app = {}; |  | ||||||
|         }; |  | ||||||
|         extraPackages = python3Packages: |  | ||||||
|           with python3Packages; [ |  | ||||||
|             hassil |  | ||||||
|             numpy |  | ||||||
|             gtts |  | ||||||
|           ]; |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       # TODO: configure /var/lib/hass/secrets.yaml via sops |  | ||||||
| 
 |  | ||||||
|       networking.firewall.allowedUDPPorts = [ |  | ||||||
|         1900 |  | ||||||
|       ]; |  | ||||||
| 
 |  | ||||||
|       systemd.tmpfiles.rules = [ |  | ||||||
|         "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass" |  | ||||||
|       ]; |  | ||||||
|     } |  | ||||||
|     (lib.mkIf (config.services.home-assistant.extensions.sonos.enable) { |  | ||||||
|       services.home-assistant.extraComponents = ["sonos"]; |  | ||||||
|       networking.firewall.allowedTCPPorts = [ |  | ||||||
|         config.services.home-assistant.extensions.sonos.port |  | ||||||
|       ]; |  | ||||||
|     }) |  | ||||||
|     (lib.mkIf (config.services.home-assistant.extensions.jellyfin.enable) { |  | ||||||
|       services.home-assistant.extraComponents = ["jellyfin"]; |  | ||||||
|       # TODO: configure port, address, and login information here |  | ||||||
|     }) |  | ||||||
|     (lib.mkIf (config.services.home-assistant.extensions.wyoming.enable) { |  | ||||||
|       services.home-assistant.extraComponents = ["wyoming"]; |  | ||||||
|       services.wyoming.enable = true; |  | ||||||
|     }) |  | ||||||
|     (lib.mkIf (config.services.home-assistant.database == "postgres") { |  | ||||||
|       host = { |  | ||||||
|         postgres = { |  | ||||||
|           enable = true; |  | ||||||
|           extraUsers = { |  | ||||||
|             ${dbUser} = { |  | ||||||
|               isClient = true; |  | ||||||
|               createUser = true; |  | ||||||
|             }; |  | ||||||
|           }; |  | ||||||
|           extraDatabases = { |  | ||||||
|             ${dbUser} = { |  | ||||||
|               name = dbUser; |  | ||||||
|             }; |  | ||||||
|           }; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       services.home-assistant = { |  | ||||||
|         extraPackages = python3Packages: |  | ||||||
|           with python3Packages; [ |  | ||||||
|             psycopg2 |  | ||||||
|           ]; |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       systemd.services.home-assistant = { |  | ||||||
|         requires = [ |  | ||||||
|           config.systemd.services.postgresql.name |  | ||||||
|         ]; |  | ||||||
|       }; |  | ||||||
|     }) |  | ||||||
|     (lib.mkIf config.services.fail2ban.enable { |  | ||||||
|       environment.etc = { |  | ||||||
|         "fail2ban/filter.d/hass.local".text = lib.mkIf config.services.home-assistant.enable ( |  | ||||||
|           pkgs.lib.mkDefault (pkgs.lib.mkAfter '' |  | ||||||
|             [INCLUDES] |  | ||||||
|             before = common.conf |  | ||||||
| 
 |  | ||||||
|             [Definition] |  | ||||||
|             failregex = ^%(__prefix_line)s.*Login attempt or request with invalid authentication from <HOST>.*$ |  | ||||||
| 
 |  | ||||||
|             ignoreregex = |  | ||||||
| 
 |  | ||||||
|             [Init] |  | ||||||
|             datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S |  | ||||||
|           '') |  | ||||||
|         ); |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       services.fail2ban = { |  | ||||||
|         jails = { |  | ||||||
|           home-assistant-iptables.settings = lib.mkIf config.services.home-assistant.enable { |  | ||||||
|             enabled = true; |  | ||||||
|             filter = "hass"; |  | ||||||
|             action = ''iptables-multiport[name=HTTP, port="http,https"]''; |  | ||||||
|             logpath = "${config.services.home-assistant.configDir}/*.log"; |  | ||||||
|             backend = "auto"; |  | ||||||
|             findtime = 600; |  | ||||||
|             bantime = 600; |  | ||||||
|             maxretry = 5; |  | ||||||
|           }; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
|     }) |  | ||||||
|     (lib.mkIf config.host.impermanence.enable { |  | ||||||
|       assertions = [ |  | ||||||
|         { |  | ||||||
|           assertion = config.services.home-assistant.configDir == configDir; |  | ||||||
|           message = "home assistant config directory does not match persistence"; |  | ||||||
|         } |  | ||||||
|       ]; |  | ||||||
|       environment.persistence."/persist/system/root" = { |  | ||||||
|         enable = true; |  | ||||||
|         hideMounts = true; |  | ||||||
|         directories = [ |  | ||||||
|           { |  | ||||||
|             directory = configDir; |  | ||||||
|             user = "hass"; |  | ||||||
|             group = "hass"; |  | ||||||
|           } |  | ||||||
|         ]; |  | ||||||
|       }; |  | ||||||
|     }) |  | ||||||
|   ]); |  | ||||||
| } |  | ||||||
							
								
								
									
										56
									
								
								modules/nixos-modules/server/home-assistant/database.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								modules/nixos-modules/server/home-assistant/database.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   dbUser = "hass"; | ||||||
|  | in { | ||||||
|  |   config = lib.mkIf config.services.home-assistant.enable ( | ||||||
|  |     lib.mkMerge [ | ||||||
|  |       { | ||||||
|  |         host = { | ||||||
|  |           postgres = { | ||||||
|  |             enable = true; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         assertions = [ | ||||||
|  |           { | ||||||
|  |             assertion = config.services.home-assistant.database == "postgres"; | ||||||
|  |             message = "Home Assistant database type must be postgres"; | ||||||
|  |           } | ||||||
|  |         ]; | ||||||
|  |       } | ||||||
|  |       (lib.mkIf config.host.postgres.enable { | ||||||
|  |         host = { | ||||||
|  |           postgres = { | ||||||
|  |             extraUsers = { | ||||||
|  |               ${dbUser} = { | ||||||
|  |                 isClient = true; | ||||||
|  |                 createUser = true; | ||||||
|  |               }; | ||||||
|  |             }; | ||||||
|  |             extraDatabases = { | ||||||
|  |               ${dbUser} = { | ||||||
|  |                 name = dbUser; | ||||||
|  |               }; | ||||||
|  |             }; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         services.home-assistant = { | ||||||
|  |           extraPackages = python3Packages: | ||||||
|  |             with python3Packages; [ | ||||||
|  |               psycopg2 | ||||||
|  |             ]; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         systemd.services.home-assistant = { | ||||||
|  |           requires = [ | ||||||
|  |             config.systemd.services.postgresql.name | ||||||
|  |           ]; | ||||||
|  |         }; | ||||||
|  |       }) | ||||||
|  |     ] | ||||||
|  |   ); | ||||||
|  | } | ||||||
							
								
								
									
										112
									
								
								modules/nixos-modules/server/home-assistant/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								modules/nixos-modules/server/home-assistant/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,112 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   imports = [ | ||||||
|  |     ./proxy.nix | ||||||
|  |     ./database.nix | ||||||
|  |     ./fail2ban.nix | ||||||
|  |     ./impermanence.nix | ||||||
|  |     ./extensions | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   options.services.home-assistant = { | ||||||
|  |     database = lib.mkOption { | ||||||
|  |       type = lib.types.enum [ | ||||||
|  |         "builtin" | ||||||
|  |         "postgres" | ||||||
|  |       ]; | ||||||
|  |       description = "what database do we want to use"; | ||||||
|  |       default = "builtin"; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     extensions = { | ||||||
|  |       sonos = { | ||||||
|  |         enable = lib.mkEnableOption "enable the sonos plugin"; | ||||||
|  |         port = lib.mkOption { | ||||||
|  |           type = lib.types.int; | ||||||
|  |           default = 1400; | ||||||
|  |           description = "what port to use for sonos discovery"; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |       jellyfin = { | ||||||
|  |         enable = lib.mkEnableOption "enable the jellyfin plugin"; | ||||||
|  |       }; | ||||||
|  |       wyoming = { | ||||||
|  |         enable = lib.mkEnableOption "enable wyoming"; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.services.home-assistant.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       services.home-assistant = { | ||||||
|  |         configDir = "/var/lib/hass"; | ||||||
|  |         extraComponents = [ | ||||||
|  |           "default_config" | ||||||
|  |           "esphome" | ||||||
|  |           "met" | ||||||
|  |           "radio_browser" | ||||||
|  |           "isal" | ||||||
|  |           "zha" | ||||||
|  |           "webostv" | ||||||
|  |           "tailscale" | ||||||
|  |           "syncthing" | ||||||
|  |           "analytics_insights" | ||||||
|  |           "unifi" | ||||||
|  |           "openweathermap" | ||||||
|  |           "ollama" | ||||||
|  |           "mobile_app" | ||||||
|  |           "logbook" | ||||||
|  |           "ssdp" | ||||||
|  |           "usb" | ||||||
|  |           "webhook" | ||||||
|  |           "bluetooth" | ||||||
|  |           "dhcp" | ||||||
|  |           "energy" | ||||||
|  |           "history" | ||||||
|  |           "backup" | ||||||
|  |           "assist_pipeline" | ||||||
|  |           "conversation" | ||||||
|  |           "sun" | ||||||
|  |           "zeroconf" | ||||||
|  |           "cpuspeed" | ||||||
|  |         ]; | ||||||
|  |         config = { | ||||||
|  |           http = { | ||||||
|  |             server_port = 8123; | ||||||
|  |             use_x_forwarded_for = true; | ||||||
|  |             trusted_proxies = ["127.0.0.1" "::1"]; | ||||||
|  |             ip_ban_enabled = true; | ||||||
|  |             login_attempts_threshold = 10; | ||||||
|  |           }; | ||||||
|  |           homeassistant = { | ||||||
|  |             external_url = "https://${config.services.home-assistant.subdomain}.${config.host.reverse_proxy.hostname}"; | ||||||
|  |             # internal_url = "http://192.168.1.2:8123"; | ||||||
|  |           }; | ||||||
|  |           recorder.db_url = "postgresql://@/${config.services.home-assistant.configDir}"; | ||||||
|  |           "automation manual" = []; | ||||||
|  |           "automation ui" = "!include automations.yaml"; | ||||||
|  |           mobile_app = {}; | ||||||
|  |         }; | ||||||
|  |         extraPackages = python3Packages: | ||||||
|  |           with python3Packages; [ | ||||||
|  |             hassil | ||||||
|  |             numpy | ||||||
|  |             gtts | ||||||
|  |           ]; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       # TODO: configure /var/lib/hass/secrets.yaml via sops | ||||||
|  | 
 | ||||||
|  |       networking.firewall.allowedUDPPorts = [ | ||||||
|  |         1900 | ||||||
|  |       ]; | ||||||
|  | 
 | ||||||
|  |       systemd.tmpfiles.rules = [ | ||||||
|  |         "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass" | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |   ]); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | { | ||||||
|  |   config, | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   imports = [ | ||||||
|  |     ./sonos.nix | ||||||
|  |     ./jellyfin.nix | ||||||
|  |     ./wyoming.nix | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,9 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: | ||||||
|  | lib.mkIf (config.services.home-assistant.extensions.jellyfin.enable) { | ||||||
|  |   services.home-assistant.extraComponents = ["jellyfin"]; | ||||||
|  |   # TODO: configure port, address, and login information here | ||||||
|  | } | ||||||
|  | @ -0,0 +1,11 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: | ||||||
|  | lib.mkIf (config.services.home-assistant.extensions.sonos.enable) { | ||||||
|  |   services.home-assistant.extraComponents = ["sonos"]; | ||||||
|  |   networking.firewall.allowedTCPPorts = [ | ||||||
|  |     config.services.home-assistant.extensions.sonos.port | ||||||
|  |   ]; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,9 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: | ||||||
|  | lib.mkIf (config.services.home-assistant.extensions.wyoming.enable) { | ||||||
|  |   services.home-assistant.extraComponents = ["wyoming"]; | ||||||
|  |   services.wyoming.enable = true; | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								modules/nixos-modules/server/home-assistant/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								modules/nixos-modules/server/home-assistant/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: | ||||||
|  | lib.mkIf (config.services.fail2ban.enable && config.services.home-assistant.enable) { | ||||||
|  |   environment.etc = { | ||||||
|  |     "fail2ban/filter.d/hass.local".text = ( | ||||||
|  |       pkgs.lib.mkDefault (pkgs.lib.mkAfter '' | ||||||
|  |         [INCLUDES] | ||||||
|  |         before = common.conf | ||||||
|  | 
 | ||||||
|  |         [Definition] | ||||||
|  |         failregex = ^%(__prefix_line)s.*Login attempt or request with invalid authentication from <HOST>.*$ | ||||||
|  | 
 | ||||||
|  |         ignoreregex = | ||||||
|  | 
 | ||||||
|  |         [Init] | ||||||
|  |         datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S | ||||||
|  |       '') | ||||||
|  |     ); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   services.fail2ban = { | ||||||
|  |     jails = { | ||||||
|  |       home-assistant-iptables.settings = { | ||||||
|  |         enabled = true; | ||||||
|  |         filter = "hass"; | ||||||
|  |         action = ''iptables-multiport[name=HTTP, port="http,https"]''; | ||||||
|  |         logpath = "${config.services.home-assistant.configDir}/*.log"; | ||||||
|  |         backend = "auto"; | ||||||
|  |         findtime = 600; | ||||||
|  |         bantime = 600; | ||||||
|  |         maxretry = 5; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								modules/nixos-modules/server/home-assistant/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								modules/nixos-modules/server/home-assistant/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   configDir = "/var/lib/hass"; | ||||||
|  | in | ||||||
|  |   lib.mkIf (config.host.impermanence.enable && config.services.home-assistant.enable) { | ||||||
|  |     assertions = [ | ||||||
|  |       { | ||||||
|  |         assertion = config.services.home-assistant.configDir == configDir; | ||||||
|  |         message = "home assistant config directory does not match persistence"; | ||||||
|  |       } | ||||||
|  |     ]; | ||||||
|  |     environment.persistence."/persist/system/root" = { | ||||||
|  |       enable = true; | ||||||
|  |       hideMounts = true; | ||||||
|  |       directories = [ | ||||||
|  |         { | ||||||
|  |           directory = configDir; | ||||||
|  |           user = "hass"; | ||||||
|  |           group = "hass"; | ||||||
|  |         } | ||||||
|  |       ]; | ||||||
|  |     }; | ||||||
|  |   } | ||||||
							
								
								
									
										33
									
								
								modules/nixos-modules/server/home-assistant/proxy.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								modules/nixos-modules/server/home-assistant/proxy.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.services.home-assistant = { | ||||||
|  |     subdomain = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "subdomain of base domain that home-assistant will be hosted at"; | ||||||
|  |       default = "home-assistant"; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf (config.host.reverse_proxy.enable && config.services.home-assistant.enable) { | ||||||
|  |     host = { | ||||||
|  |       reverse_proxy.subdomains.${config.services.home-assistant.subdomain} = { | ||||||
|  |         target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}"; | ||||||
|  | 
 | ||||||
|  |         websockets.enable = true; | ||||||
|  |         forwardHeaders.enable = true; | ||||||
|  | 
 | ||||||
|  |         extraConfig = '' | ||||||
|  |           add_header Upgrade $http_upgrade; | ||||||
|  |           add_header Connection \"upgrade\"; | ||||||
|  | 
 | ||||||
|  |           proxy_buffering off; | ||||||
|  | 
 | ||||||
|  |           proxy_read_timeout 90; | ||||||
|  |         ''; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | @ -1,95 +0,0 @@ | ||||||
| { |  | ||||||
|   lib, |  | ||||||
|   config, |  | ||||||
|   pkgs, |  | ||||||
|   ... |  | ||||||
| }: let |  | ||||||
|   mediaLocation = "/var/lib/immich"; |  | ||||||
| in { |  | ||||||
|   options.services.immich = { |  | ||||||
|     subdomain = lib.mkOption { |  | ||||||
|       type = lib.types.str; |  | ||||||
|       description = "subdomain of base domain that immich will be hosted at"; |  | ||||||
|       default = "immich"; |  | ||||||
|     }; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   config = lib.mkIf config.services.immich.enable (lib.mkMerge [ |  | ||||||
|     { |  | ||||||
|       host = { |  | ||||||
|         reverse_proxy.subdomains.${config.services.immich.subdomain} = { |  | ||||||
|           target = "http://localhost:${toString config.services.immich.port}"; |  | ||||||
| 
 |  | ||||||
|           websockets.enable = true; |  | ||||||
|           forwardHeaders.enable = true; |  | ||||||
| 
 |  | ||||||
|           extraConfig = '' |  | ||||||
|             # allow large file uploads |  | ||||||
|             client_max_body_size 50000M; |  | ||||||
| 
 |  | ||||||
|             # set timeout |  | ||||||
|             proxy_read_timeout 600s; |  | ||||||
|             proxy_send_timeout 600s; |  | ||||||
|             send_timeout       600s; |  | ||||||
|             proxy_redirect     off; |  | ||||||
|           ''; |  | ||||||
|         }; |  | ||||||
|         postgres = { |  | ||||||
|           enable = true; |  | ||||||
|           extraUsers = { |  | ||||||
|             ${config.services.immich.database.user} = { |  | ||||||
|               isClient = true; |  | ||||||
|             }; |  | ||||||
|           }; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       networking.firewall.interfaces.${config.services.tailscale.interfaceName} = { |  | ||||||
|         allowedUDPPorts = [ |  | ||||||
|           config.services.immich.port |  | ||||||
|         ]; |  | ||||||
|         allowedTCPPorts = [ |  | ||||||
|           config.services.immich.port |  | ||||||
|         ]; |  | ||||||
|       }; |  | ||||||
|     } |  | ||||||
|     (lib.mkIf config.services.fail2ban.enable { |  | ||||||
|       environment.etc = { |  | ||||||
|         "fail2ban/filter.d/immich.local".text = lib.mkIf config.services.immich.enable ( |  | ||||||
|           pkgs.lib.mkDefault (pkgs.lib.mkAfter '' |  | ||||||
|             [Definition] |  | ||||||
|             failregex = immich-server.*Failed login attempt for user.+from ip address\s?<ADDR> |  | ||||||
|             journalmatch = CONTAINER_TAG=immich-server |  | ||||||
|           '') |  | ||||||
|         ); |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       services.fail2ban = { |  | ||||||
|         jails = { |  | ||||||
|           immich-iptables.settings = lib.mkIf config.services.immich.enable { |  | ||||||
|             enabled = true; |  | ||||||
|             filter = "immich"; |  | ||||||
|             backend = "systemd"; |  | ||||||
|           }; |  | ||||||
|         }; |  | ||||||
|       }; |  | ||||||
|     }) |  | ||||||
|     (lib.mkIf config.host.impermanence.enable { |  | ||||||
|       assertions = [ |  | ||||||
|         { |  | ||||||
|           assertion = config.services.immich.mediaLocation == mediaLocation; |  | ||||||
|           message = "immich media location does not match persistence"; |  | ||||||
|         } |  | ||||||
|       ]; |  | ||||||
|       environment.persistence."/persist/system/root" = { |  | ||||||
|         directories = [ |  | ||||||
|           { |  | ||||||
|             directory = mediaLocation; |  | ||||||
|             user = "immich"; |  | ||||||
|             group = "immich"; |  | ||||||
|           } |  | ||||||
|         ]; |  | ||||||
|       }; |  | ||||||
|     }) |  | ||||||
|   ]); |  | ||||||
| } |  | ||||||
							
								
								
									
										26
									
								
								modules/nixos-modules/server/immich/database.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								modules/nixos-modules/server/immich/database.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   config = lib.mkIf config.services.immich.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       host = { | ||||||
|  |         postgres = { | ||||||
|  |           enable = true; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     } | ||||||
|  |     (lib.mkIf config.host.postgres.enable { | ||||||
|  |       host = { | ||||||
|  |         postgres = { | ||||||
|  |           extraUsers = { | ||||||
|  |             ${config.services.immich.database.user} = { | ||||||
|  |               isClient = true; | ||||||
|  |             }; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     }) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								modules/nixos-modules/server/immich/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								modules/nixos-modules/server/immich/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | ||||||
|  | {...}: { | ||||||
|  |   imports = [ | ||||||
|  |     ./proxy.nix | ||||||
|  |     ./database.nix | ||||||
|  |     ./fail2ban.nix | ||||||
|  |     ./impermanence.nix | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   # NOTE: This shouldn't be needed now that we are out of testing | ||||||
|  |   # config = lib.mkIf config.services.immich.enable { | ||||||
|  |   #   networking.firewall.interfaces.${config.services.tailscale.interfaceName} = { | ||||||
|  |   #     allowedUDPPorts = [ | ||||||
|  |   #       config.services.immich.port | ||||||
|  |   #     ]; | ||||||
|  |   #     allowedTCPPorts = [ | ||||||
|  |   #       config.services.immich.port | ||||||
|  |   #     ]; | ||||||
|  |   #   }; | ||||||
|  |   # }; | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								modules/nixos-modules/server/immich/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								modules/nixos-modules/server/immich/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   pkgs, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   config = lib.mkIf (config.services.fail2ban.enable && config.services.immich.enable) { | ||||||
|  |     environment.etc = { | ||||||
|  |       "fail2ban/filter.d/immich.local".text = pkgs.lib.mkDefault (pkgs.lib.mkAfter '' | ||||||
|  |         [Definition] | ||||||
|  |         failregex = immich-server.*Failed login attempt for user.+from ip address\s?<ADDR> | ||||||
|  |         journalmatch = CONTAINER_TAG=immich-server | ||||||
|  |       ''); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     services.fail2ban = { | ||||||
|  |       jails = { | ||||||
|  |         immich-iptables.settings = { | ||||||
|  |           enabled = true; | ||||||
|  |           filter = "immich"; | ||||||
|  |           backend = "systemd"; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								modules/nixos-modules/server/immich/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								modules/nixos-modules/server/immich/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   mediaLocation = "/var/lib/immich"; | ||||||
|  | in { | ||||||
|  |   config = lib.mkIf (config.services.immich.enable && config.host.impermanence.enable) { | ||||||
|  |     assertions = [ | ||||||
|  |       { | ||||||
|  |         assertion = config.services.immich.mediaLocation == mediaLocation; | ||||||
|  |         message = "immich media location does not match persistence"; | ||||||
|  |       } | ||||||
|  |     ]; | ||||||
|  |     environment.persistence."/persist/system/root" = { | ||||||
|  |       directories = [ | ||||||
|  |         { | ||||||
|  |           directory = mediaLocation; | ||||||
|  |           user = "immich"; | ||||||
|  |           group = "immich"; | ||||||
|  |         } | ||||||
|  |       ]; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								modules/nixos-modules/server/immich/proxy.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								modules/nixos-modules/server/immich/proxy.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.services.immich = { | ||||||
|  |     subdomain = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "subdomain of base domain that immich will be hosted at"; | ||||||
|  |       default = "immich"; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf (config.services.immich.enable && config.host.reverse_proxy.enable) { | ||||||
|  |     host = { | ||||||
|  |       reverse_proxy.subdomains.${config.services.immich.subdomain} = { | ||||||
|  |         target = "http://localhost:${toString config.services.immich.port}"; | ||||||
|  | 
 | ||||||
|  |         websockets.enable = true; | ||||||
|  |         forwardHeaders.enable = true; | ||||||
|  | 
 | ||||||
|  |         extraConfig = '' | ||||||
|  |           # allow large file uploads | ||||||
|  |           client_max_body_size 50000M; | ||||||
|  | 
 | ||||||
|  |           # set timeout | ||||||
|  |           proxy_read_timeout 600s; | ||||||
|  |           proxy_send_timeout 600s; | ||||||
|  |           send_timeout       600s; | ||||||
|  |           proxy_redirect     off; | ||||||
|  |         ''; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | @ -1,145 +0,0 @@ | ||||||
| { |  | ||||||
|   lib, |  | ||||||
|   pkgs, |  | ||||||
|   config, |  | ||||||
|   ... |  | ||||||
| }: let |  | ||||||
|   jellyfinPort = 8096; |  | ||||||
|   dlanPort = 1900; |  | ||||||
|   jellyfin_data_directory = "/var/lib/jellyfin"; |  | ||||||
|   jellyfin_cache_directory = "/var/cache/jellyfin"; |  | ||||||
| in { |  | ||||||
|   options.services.jellyfin = { |  | ||||||
|     subdomain = lib.mkOption { |  | ||||||
|       type = lib.types.str; |  | ||||||
|       description = "subdomain of base domain that jellyfin will be hosted at"; |  | ||||||
|       default = "jellyfin"; |  | ||||||
|     }; |  | ||||||
|     extraSubdomains = lib.mkOption { |  | ||||||
|       type = lib.types.listOf lib.types.str; |  | ||||||
|       description = "ex subdomain of base domain that jellyfin will be hosted at"; |  | ||||||
|       default = []; |  | ||||||
|     }; |  | ||||||
|     media_directory = lib.mkOption { |  | ||||||
|       type = lib.types.str; |  | ||||||
|       description = "directory jellyfin media will be hosted at"; |  | ||||||
|       default = "/srv/jellyfin/media"; |  | ||||||
|     }; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   config = lib.mkIf config.services.jellyfin.enable ( |  | ||||||
|     lib.mkMerge [ |  | ||||||
|       { |  | ||||||
|         host.reverse_proxy.subdomains.jellyfin = { |  | ||||||
|           target = "http://localhost:${toString jellyfinPort}"; |  | ||||||
| 
 |  | ||||||
|           subdomain = config.services.jellyfin.subdomain; |  | ||||||
|           extraSubdomains = config.services.jellyfin.extraSubdomains; |  | ||||||
| 
 |  | ||||||
|           forwardHeaders.enable = true; |  | ||||||
| 
 |  | ||||||
|           extraConfig = '' |  | ||||||
|             client_max_body_size 20M; |  | ||||||
|             add_header X-Content-Type-Options "nosniff"; |  | ||||||
| 
 |  | ||||||
|             proxy_buffering off; |  | ||||||
|           ''; |  | ||||||
|         }; |  | ||||||
|         environment.systemPackages = [ |  | ||||||
|           pkgs.jellyfin |  | ||||||
|           pkgs.jellyfin-web |  | ||||||
|           pkgs.jellyfin-ffmpeg |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         networking.firewall.allowedTCPPorts = [jellyfinPort dlanPort]; |  | ||||||
| 
 |  | ||||||
|         systemd.tmpfiles.rules = [ |  | ||||||
|           "d ${config.services.jellyfin.media_directory} 2770 jellyfin jellyfin_media" |  | ||||||
|           "A ${config.services.jellyfin.media_directory} -    -        -               - u:jellyfin:rwX,g:jellyfin_media:rwX,o::-" |  | ||||||
|         ]; |  | ||||||
|       } |  | ||||||
|       (lib.mkIf config.services.fail2ban.enable { |  | ||||||
|         environment.etc = { |  | ||||||
|           "fail2ban/filter.d/jellyfin.local".text = ( |  | ||||||
|             pkgs.lib.mkDefault (pkgs.lib.mkAfter '' |  | ||||||
|               [Definition] |  | ||||||
|               failregex = "^.*Authentication request for .* has been denied \\\(IP: \"<ADDR>\"\\\)\\\." |  | ||||||
|             '') |  | ||||||
|           ); |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         services.fail2ban = { |  | ||||||
|           jails = { |  | ||||||
|             jellyfin-iptables.settings = { |  | ||||||
|               enabled = true; |  | ||||||
|               filter = "jellyfin"; |  | ||||||
|               action = ''iptables-multiport[name=HTTP, port="http,https"]''; |  | ||||||
|               logpath = "${config.services.jellyfin.dataDir}/log/*.log"; |  | ||||||
|               backend = "auto"; |  | ||||||
|               findtime = 600; |  | ||||||
|               bantime = 600; |  | ||||||
|               maxretry = 5; |  | ||||||
|             }; |  | ||||||
|           }; |  | ||||||
|         }; |  | ||||||
|       }) |  | ||||||
|       (lib.mkIf config.host.impermanence.enable { |  | ||||||
|         fileSystems."/persist/system/jellyfin".neededForBoot = true; |  | ||||||
| 
 |  | ||||||
|         host.storage.pool.extraDatasets = { |  | ||||||
|           # sops age key needs to be available to pre persist for user generation |  | ||||||
|           "persist/system/jellyfin" = { |  | ||||||
|             type = "zfs_fs"; |  | ||||||
|             mountpoint = "/persist/system/jellyfin"; |  | ||||||
|             options = { |  | ||||||
|               atime = "off"; |  | ||||||
|               relatime = "off"; |  | ||||||
|               canmount = "on"; |  | ||||||
|             }; |  | ||||||
|           }; |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         assertions = [ |  | ||||||
|           { |  | ||||||
|             assertion = config.services.jellyfin.dataDir == jellyfin_data_directory; |  | ||||||
|             message = "jellyfin data directory does not match persistence"; |  | ||||||
|           } |  | ||||||
|           { |  | ||||||
|             assertion = config.services.jellyfin.cacheDir == jellyfin_cache_directory; |  | ||||||
|             message = "jellyfin cache directory does not match persistence"; |  | ||||||
|           } |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         environment.persistence = { |  | ||||||
|           "/persist/system/root" = { |  | ||||||
|             directories = [ |  | ||||||
|               { |  | ||||||
|                 directory = jellyfin_data_directory; |  | ||||||
|                 user = "jellyfin"; |  | ||||||
|                 group = "jellyfin"; |  | ||||||
|               } |  | ||||||
|               { |  | ||||||
|                 directory = jellyfin_cache_directory; |  | ||||||
|                 user = "jellyfin"; |  | ||||||
|                 group = "jellyfin"; |  | ||||||
|               } |  | ||||||
|             ]; |  | ||||||
|           }; |  | ||||||
| 
 |  | ||||||
|           "/persist/system/jellyfin" = { |  | ||||||
|             enable = true; |  | ||||||
|             hideMounts = true; |  | ||||||
|             directories = [ |  | ||||||
|               { |  | ||||||
|                 directory = config.services.jellyfin.media_directory; |  | ||||||
|                 user = "jellyfin"; |  | ||||||
|                 group = "jellyfin_media"; |  | ||||||
|                 mode = "1770"; |  | ||||||
|               } |  | ||||||
|             ]; |  | ||||||
|           }; |  | ||||||
|         }; |  | ||||||
|       }) |  | ||||||
|     ] |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
							
								
								
									
										38
									
								
								modules/nixos-modules/server/jellyfin/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								modules/nixos-modules/server/jellyfin/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   jellyfinPort = 8096; | ||||||
|  |   dlanPort = 1900; | ||||||
|  | in { | ||||||
|  |   imports = [ | ||||||
|  |     ./proxy.nix | ||||||
|  |     ./fail2ban.nix | ||||||
|  |     ./impermanence.nix | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   options.services.jellyfin = { | ||||||
|  |     media_directory = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "directory jellyfin media will be hosted at"; | ||||||
|  |       default = "/srv/jellyfin/media"; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.services.jellyfin.enable { | ||||||
|  |     environment.systemPackages = [ | ||||||
|  |       pkgs.jellyfin | ||||||
|  |       pkgs.jellyfin-web | ||||||
|  |       pkgs.jellyfin-ffmpeg | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     networking.firewall.allowedTCPPorts = [jellyfinPort dlanPort]; | ||||||
|  | 
 | ||||||
|  |     systemd.tmpfiles.rules = [ | ||||||
|  |       "d ${config.services.jellyfin.media_directory} 2770 jellyfin jellyfin_media" | ||||||
|  |       "A ${config.services.jellyfin.media_directory} -    -        -               - u:jellyfin:rwX,g:jellyfin_media:rwX,o::-" | ||||||
|  |     ]; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										32
									
								
								modules/nixos-modules/server/jellyfin/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								modules/nixos-modules/server/jellyfin/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   config = lib.mkIf (config.services.jellyfin.enable && config.services.fail2ban.enable) { | ||||||
|  |     environment.etc = { | ||||||
|  |       "fail2ban/filter.d/jellyfin.local".text = ( | ||||||
|  |         pkgs.lib.mkDefault (pkgs.lib.mkAfter '' | ||||||
|  |           [Definition] | ||||||
|  |           failregex = "^.*Authentication request for .* has been denied \\\\\\(IP: \\\"<ADDR>\\\"\\\\\\)\\\\\\." | ||||||
|  |         '') | ||||||
|  |       ); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     services.fail2ban = { | ||||||
|  |       jails = { | ||||||
|  |         jellyfin-iptables.settings = { | ||||||
|  |           enabled = true; | ||||||
|  |           filter = "jellyfin"; | ||||||
|  |           action = ''iptables-multiport[name=HTTP, port="http,https"]''; | ||||||
|  |           logpath = "${config.services.jellyfin.dataDir}/log/*.log"; | ||||||
|  |           backend = "auto"; | ||||||
|  |           findtime = 600; | ||||||
|  |           bantime = 600; | ||||||
|  |           maxretry = 5; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										66
									
								
								modules/nixos-modules/server/jellyfin/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								modules/nixos-modules/server/jellyfin/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   jellyfin_data_directory = "/var/lib/jellyfin"; | ||||||
|  |   jellyfin_cache_directory = "/var/cache/jellyfin"; | ||||||
|  | in { | ||||||
|  |   config = lib.mkIf (config.services.jellyfin.enable && config.host.impermanence.enable) { | ||||||
|  |     fileSystems."/persist/system/jellyfin".neededForBoot = true; | ||||||
|  | 
 | ||||||
|  |     host.storage.pool.extraDatasets = { | ||||||
|  |       # sops age key needs to be available to pre persist for user generation | ||||||
|  |       "persist/system/jellyfin" = { | ||||||
|  |         type = "zfs_fs"; | ||||||
|  |         mountpoint = "/persist/system/jellyfin"; | ||||||
|  |         options = { | ||||||
|  |           atime = "off"; | ||||||
|  |           relatime = "off"; | ||||||
|  |           canmount = "on"; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     assertions = [ | ||||||
|  |       { | ||||||
|  |         assertion = config.services.jellyfin.dataDir == jellyfin_data_directory; | ||||||
|  |         message = "jellyfin data directory does not match persistence"; | ||||||
|  |       } | ||||||
|  |       { | ||||||
|  |         assertion = config.services.jellyfin.cacheDir == jellyfin_cache_directory; | ||||||
|  |         message = "jellyfin cache directory does not match persistence"; | ||||||
|  |       } | ||||||
|  |     ]; | ||||||
|  | 
 | ||||||
|  |     environment.persistence = { | ||||||
|  |       "/persist/system/root" = { | ||||||
|  |         directories = [ | ||||||
|  |           { | ||||||
|  |             directory = jellyfin_data_directory; | ||||||
|  |             user = "jellyfin"; | ||||||
|  |             group = "jellyfin"; | ||||||
|  |           } | ||||||
|  |           { | ||||||
|  |             directory = jellyfin_cache_directory; | ||||||
|  |             user = "jellyfin"; | ||||||
|  |             group = "jellyfin"; | ||||||
|  |           } | ||||||
|  |         ]; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       "/persist/system/jellyfin" = { | ||||||
|  |         enable = true; | ||||||
|  |         hideMounts = true; | ||||||
|  |         directories = [ | ||||||
|  |           { | ||||||
|  |             directory = config.services.jellyfin.media_directory; | ||||||
|  |             user = "jellyfin"; | ||||||
|  |             group = "jellyfin_media"; | ||||||
|  |             mode = "1770"; | ||||||
|  |           } | ||||||
|  |         ]; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										38
									
								
								modules/nixos-modules/server/jellyfin/proxy.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								modules/nixos-modules/server/jellyfin/proxy.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: let | ||||||
|  |   jellyfinPort = 8096; | ||||||
|  | in { | ||||||
|  |   options.services.jellyfin = { | ||||||
|  |     subdomain = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "subdomain of base domain that jellyfin will be hosted at"; | ||||||
|  |       default = "jellyfin"; | ||||||
|  |     }; | ||||||
|  |     extraSubdomains = lib.mkOption { | ||||||
|  |       type = lib.types.listOf lib.types.str; | ||||||
|  |       description = "ex subdomain of base domain that jellyfin will be hosted at"; | ||||||
|  |       default = []; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf (config.services.jellyfin.enable && config.host.reverse_proxy.enable) { | ||||||
|  |     host.reverse_proxy.subdomains.jellyfin = { | ||||||
|  |       target = "http://localhost:${toString jellyfinPort}"; | ||||||
|  | 
 | ||||||
|  |       subdomain = config.services.jellyfin.subdomain; | ||||||
|  |       extraSubdomains = config.services.jellyfin.extraSubdomains; | ||||||
|  | 
 | ||||||
|  |       forwardHeaders.enable = true; | ||||||
|  | 
 | ||||||
|  |       extraConfig = '' | ||||||
|  |         client_max_body_size 20M; | ||||||
|  |         add_header X-Content-Type-Options "nosniff"; | ||||||
|  | 
 | ||||||
|  |         proxy_buffering off; | ||||||
|  |       ''; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								modules/nixos-modules/server/panoramax/database.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								modules/nixos-modules/server/panoramax/database.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   config = lib.mkIf config.services.panoramax.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       host = { | ||||||
|  |         postgres = { | ||||||
|  |           enable = true; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     } | ||||||
|  |     ( | ||||||
|  |       lib.mkIf config.host.postgres.enable { | ||||||
|  |         host = { | ||||||
|  |           postgres = { | ||||||
|  |             extraUsers = { | ||||||
|  |               ${config.services.panoramax.database.user} = { | ||||||
|  |                 isClient = true; | ||||||
|  |                 createUser = true; | ||||||
|  |               }; | ||||||
|  |             }; | ||||||
|  |             extraDatabases = { | ||||||
|  |               ${config.services.panoramax.database.name} = { | ||||||
|  |                 name = config.services.panoramax.database.user; | ||||||
|  |               }; | ||||||
|  |             }; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								modules/nixos-modules/server/panoramax/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								modules/nixos-modules/server/panoramax/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | {...}: { | ||||||
|  |   imports = [ | ||||||
|  |     ./proxy.nix | ||||||
|  |     ./fail2ban.nix | ||||||
|  |     ./impermanence.nix | ||||||
|  |     ./panoramax.nix | ||||||
|  |     ./database.nix | ||||||
|  |   ]; | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								modules/nixos-modules/server/panoramax/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								modules/nixos-modules/server/panoramax/fail2ban.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   config = lib.mkIf (config.services.panoramax.enable && config.services.fail2ban.enable) { | ||||||
|  |     # TODO: configure options for fail2ban | ||||||
|  |     # This is a placeholder - panoramax fail2ban configuration would need to be defined | ||||||
|  |     # based on the specific log patterns and security requirements | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								modules/nixos-modules/server/panoramax/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								modules/nixos-modules/server/panoramax/impermanence.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   osConfig, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   config = lib.mkIf (config.services.panoramax.enable && osConfig.host.impermanence.enable) { | ||||||
|  |     # TODO: configure impermanence for panoramax data | ||||||
|  |     # This would typically include directories like: | ||||||
|  |     # - /var/lib/panoramax | ||||||
|  |     # - panoramax storage directories | ||||||
|  |     # - any cache or temporary directories that need to persist | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										359
									
								
								modules/nixos-modules/server/panoramax/panoramax.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								modules/nixos-modules/server/panoramax/panoramax.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,359 @@ | ||||||
|  | { | ||||||
|  |   config, | ||||||
|  |   lib, | ||||||
|  |   pkgs, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.services = { | ||||||
|  |     panoramax = { | ||||||
|  |       enable = lib.mkEnableOption "panoramax"; | ||||||
|  | 
 | ||||||
|  |       package = lib.mkOption { | ||||||
|  |         type = lib.types.package; | ||||||
|  |         default = pkgs.panoramax; | ||||||
|  |         description = "The panoramax package to use"; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       user = lib.mkOption { | ||||||
|  |         type = lib.types.str; | ||||||
|  |         default = "panoramax"; | ||||||
|  |         description = "The user panoramax should run as."; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       group = lib.mkOption { | ||||||
|  |         type = lib.types.str; | ||||||
|  |         default = "panoramax"; | ||||||
|  |         description = "The group panoramax should run as."; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       host = lib.mkOption { | ||||||
|  |         type = lib.types.str; | ||||||
|  |         default = "127.0.0.1"; | ||||||
|  |         description = "Host to bind the panoramax service to"; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       port = lib.mkOption { | ||||||
|  |         type = lib.types.nullOr lib.types.port; | ||||||
|  |         default = 5000; | ||||||
|  |         description = "Port for the panoramax service"; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       openFirewall = lib.mkOption { | ||||||
|  |         type = lib.types.bool; | ||||||
|  |         default = false; | ||||||
|  |         description = "Whether to open the panoramax port in the firewall"; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       settings = { | ||||||
|  |         urlScheme = lib.mkOption { | ||||||
|  |           type = lib.types.enum ["http" "https"]; | ||||||
|  |           default = "https"; | ||||||
|  |           description = "URL scheme for the application"; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         storage = { | ||||||
|  |           fsUrl = lib.mkOption { | ||||||
|  |             type = lib.types.nullOr lib.types.str; | ||||||
|  |             default = "/var/lib/panoramax/storage"; | ||||||
|  |             description = "File system URL for storage"; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         infrastructure = { | ||||||
|  |           nbProxies = lib.mkOption { | ||||||
|  |             type = lib.types.nullOr lib.types.int; | ||||||
|  |             default = 1; | ||||||
|  |             description = "Number of proxies in front of the application"; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         flask = { | ||||||
|  |           secretKey = lib.mkOption { | ||||||
|  |             type = lib.types.nullOr lib.types.str; | ||||||
|  |             default = null; | ||||||
|  |             description = "Flask secret key for session security"; | ||||||
|  |           }; | ||||||
|  | 
 | ||||||
|  |           sessionCookieDomain = lib.mkOption { | ||||||
|  |             type = lib.types.nullOr lib.types.str; | ||||||
|  |             default = null; | ||||||
|  |             description = "Flask session cookie domain"; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         api = { | ||||||
|  |           pictures = { | ||||||
|  |             licenseSpdxId = lib.mkOption { | ||||||
|  |               type = lib.types.nullOr lib.types.str; | ||||||
|  |               default = null; | ||||||
|  |               description = "SPDX license identifier for API pictures"; | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             licenseUrl = lib.mkOption { | ||||||
|  |               type = lib.types.nullOr lib.types.str; | ||||||
|  |               default = null; | ||||||
|  |               description = "License URL for API pictures"; | ||||||
|  |             }; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         extraEnvironment = lib.mkOption { | ||||||
|  |           type = lib.types.attrsOf lib.types.str; | ||||||
|  |           default = {}; | ||||||
|  |           description = "Additional environment variables"; | ||||||
|  |           example = { | ||||||
|  |             CUSTOM_SETTING = "value"; | ||||||
|  |             DEBUG = "true"; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       database = { | ||||||
|  |         createDB = lib.mkOption { | ||||||
|  |           type = lib.types.bool; | ||||||
|  |           default = true; | ||||||
|  |           description = "Whether to automatically create the database and user"; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         name = lib.mkOption { | ||||||
|  |           type = lib.types.str; | ||||||
|  |           default = "panoramax"; | ||||||
|  |           description = "The name of the panoramax database"; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         host = lib.mkOption { | ||||||
|  |           type = lib.types.nullOr lib.types.str; | ||||||
|  |           default = "/run/postgresql"; | ||||||
|  |           description = "Hostname or address of the postgresql server. If an absolute path is given here, it will be interpreted as a unix socket path."; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         port = lib.mkOption { | ||||||
|  |           type = lib.types.nullOr lib.types.port; | ||||||
|  |           default = 5432; | ||||||
|  |           description = "Port of the postgresql server."; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         user = lib.mkOption { | ||||||
|  |           type = lib.types.nullOr lib.types.str; | ||||||
|  |           default = "panoramax"; | ||||||
|  |           description = "The database user for panoramax."; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         # TODO: password file for external database | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       sgblur = { | ||||||
|  |         # TODO: configs to bind to sgblur | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |     sgblur = { | ||||||
|  |       enable = lib.mkOption { | ||||||
|  |         type = lib.types.bool; | ||||||
|  |         default = false; | ||||||
|  |         description = "Whether to enable sgblur integration for face and license plate blurring"; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       package = lib.mkOption { | ||||||
|  |         type = lib.types.package; | ||||||
|  |         default = pkgs.sgblur; | ||||||
|  |         description = "The sgblur package to use"; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       port = lib.mkOption { | ||||||
|  |         type = lib.types.port; | ||||||
|  |         default = 8080; | ||||||
|  |         description = "Port for the sgblur service"; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       host = lib.mkOption { | ||||||
|  |         type = lib.types.str; | ||||||
|  |         default = "127.0.0.1"; | ||||||
|  |         description = "Host to bind the sgblur service to"; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       url = lib.mkOption { | ||||||
|  |         type = lib.types.str; | ||||||
|  |         default = "http://127.0.0.1:8080"; | ||||||
|  |         description = "URL where sgblur service is accessible"; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf config.services.panoramax.enable (lib.mkMerge [ | ||||||
|  |     { | ||||||
|  |       # Create panoramax user and group | ||||||
|  |       users.users.${config.services.panoramax.user} = { | ||||||
|  |         isSystemUser = true; | ||||||
|  |         group = config.services.panoramax.group; | ||||||
|  |         home = "/var/lib/panoramax"; | ||||||
|  |         createHome = true; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       users.groups.${config.services.panoramax.group} = {}; | ||||||
|  | 
 | ||||||
|  |       # Ensure storage directory exists with correct permissions | ||||||
|  |       systemd.tmpfiles.rules = [ | ||||||
|  |         "d '${config.services.panoramax.settings.storage.fsUrl}' 0755 ${config.services.panoramax.user} ${config.services.panoramax.group} - -" | ||||||
|  |       ]; | ||||||
|  | 
 | ||||||
|  |       systemd.services.panoramax-api = { | ||||||
|  |         description = "Panoramax API server (self hosted map street view)"; | ||||||
|  |         after = ["network.target" "postgresql.service"]; | ||||||
|  |         wantedBy = ["multi-user.target"]; | ||||||
|  | 
 | ||||||
|  |         environment = | ||||||
|  |           { | ||||||
|  |             # Core Flask configuration | ||||||
|  |             FLASK_APP = "geovisio"; | ||||||
|  | 
 | ||||||
|  |             # Storage configuration | ||||||
|  |             FS_URL = config.services.panoramax.settings.storage.fsUrl; | ||||||
|  | 
 | ||||||
|  |             # Infrastructure configuration | ||||||
|  |             INFRA_NB_PROXIES = toString config.services.panoramax.settings.infrastructure.nbProxies; | ||||||
|  | 
 | ||||||
|  |             # Application configuration | ||||||
|  |             PORT = toString config.services.panoramax.port; | ||||||
|  | 
 | ||||||
|  |             # Python path to include the panoramax package | ||||||
|  |             PYTHONPATH = "${config.services.panoramax.package}/${pkgs.python3.sitePackages}"; | ||||||
|  |           } | ||||||
|  |           // ( | ||||||
|  |             if config.services.panoramax.database.host == "/run/postgresql" | ||||||
|  |             then { | ||||||
|  |               DB_URL = "postgresql://${config.services.panoramax.database.user}@/${config.services.panoramax.database.name}?host=/run/postgresql"; | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |               DB_HOST = config.services.panoramax.database.host; | ||||||
|  |               DB_PORT = toString config.services.panoramax.database.port; | ||||||
|  |               DB_USERNAME = config.services.panoramax.database.user; | ||||||
|  |               DB_NAME = config.services.panoramax.database.name; | ||||||
|  |             } | ||||||
|  |           ) | ||||||
|  |           // (lib.optionalAttrs (config.services.panoramax.settings.flask.secretKey != null) { | ||||||
|  |             FLASK_SECRET_KEY = config.services.panoramax.settings.flask.secretKey; | ||||||
|  |           }) | ||||||
|  |           // (lib.optionalAttrs (config.services.panoramax.settings.flask.sessionCookieDomain != null) { | ||||||
|  |             FLASK_SESSION_COOKIE_DOMAIN = config.services.panoramax.settings.flask.sessionCookieDomain; | ||||||
|  |           }) | ||||||
|  |           // (lib.optionalAttrs (config.services.panoramax.settings.api.pictures.licenseSpdxId != null) { | ||||||
|  |             API_PICTURES_LICENSE_SPDX_ID = config.services.panoramax.settings.api.pictures.licenseSpdxId; | ||||||
|  |           }) | ||||||
|  |           // (lib.optionalAttrs (config.services.panoramax.settings.api.pictures.licenseUrl != null) { | ||||||
|  |             API_PICTURES_LICENSE_URL = config.services.panoramax.settings.api.pictures.licenseUrl; | ||||||
|  |           }) | ||||||
|  |           // (lib.optionalAttrs config.services.sgblur.enable { | ||||||
|  |             SGBLUR_API_URL = config.services.sgblur.url; | ||||||
|  |           }) | ||||||
|  |           // config.services.panoramax.settings.extraEnvironment; | ||||||
|  | 
 | ||||||
|  |         path = with pkgs; [ | ||||||
|  |           (python3.withPackages (ps: with ps; [config.services.panoramax.package waitress])) | ||||||
|  |         ]; | ||||||
|  | 
 | ||||||
|  |         serviceConfig = { | ||||||
|  |           ExecStart = "${pkgs.python3.withPackages (ps: with ps; [config.services.panoramax.package waitress])}/bin/waitress-serve --port ${toString config.services.panoramax.port} --call geovisio:create_app"; | ||||||
|  |           User = config.services.panoramax.user; | ||||||
|  |           Group = config.services.panoramax.group; | ||||||
|  |           WorkingDirectory = "/var/lib/panoramax"; | ||||||
|  |           Restart = "always"; | ||||||
|  |           RestartSec = 5; | ||||||
|  | 
 | ||||||
|  |           # Security hardening | ||||||
|  |           PrivateTmp = true; | ||||||
|  |           ProtectSystem = "strict"; | ||||||
|  |           ProtectHome = true; | ||||||
|  |           ReadWritePaths = [ | ||||||
|  |             "/var/lib/panoramax" | ||||||
|  |             config.services.panoramax.settings.storage.fsUrl | ||||||
|  |           ]; | ||||||
|  |           NoNewPrivileges = true; | ||||||
|  |           PrivateDevices = true; | ||||||
|  |           ProtectKernelTunables = true; | ||||||
|  |           ProtectKernelModules = true; | ||||||
|  |           ProtectControlGroups = true; | ||||||
|  |           RestrictSUIDSGID = true; | ||||||
|  |           RestrictRealtime = true; | ||||||
|  |           RestrictNamespaces = true; | ||||||
|  |           LockPersonality = true; | ||||||
|  |           MemoryDenyWriteExecute = true; | ||||||
|  |           SystemCallArchitectures = "native"; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       # Open firewall if requested | ||||||
|  |       networking.firewall.allowedTCPPorts = lib.mkIf config.services.panoramax.openFirewall [ | ||||||
|  |         config.services.panoramax.port | ||||||
|  |       ]; | ||||||
|  |     } | ||||||
|  |     (lib.mkIf config.services.sgblur.enable { | ||||||
|  |       # SGBlur service configuration | ||||||
|  |       systemd.services.sgblur = { | ||||||
|  |         description = "SGBlur face and license plate blurring service"; | ||||||
|  |         after = ["network.target"]; | ||||||
|  |         wantedBy = ["multi-user.target"]; | ||||||
|  | 
 | ||||||
|  |         path = with pkgs; [ | ||||||
|  |           config.services.sgblur.package | ||||||
|  |           python3 | ||||||
|  |           python3Packages.waitress | ||||||
|  |         ]; | ||||||
|  | 
 | ||||||
|  |         serviceConfig = { | ||||||
|  |           ExecStart = "${pkgs.python3Packages.waitress}/bin/waitress-serve --host ${config.services.sgblur.host} --port ${toString config.services.sgblur.port} src.detect.detect_api:app"; | ||||||
|  |           WorkingDirectory = "${config.services.sgblur.package}"; | ||||||
|  |           Restart = "always"; | ||||||
|  |           RestartSec = 5; | ||||||
|  | 
 | ||||||
|  |           # Basic security hardening | ||||||
|  |           PrivateTmp = true; | ||||||
|  |           ProtectSystem = "strict"; | ||||||
|  |           ProtectHome = true; | ||||||
|  |           NoNewPrivileges = true; | ||||||
|  |           PrivateDevices = true; | ||||||
|  |           ProtectKernelTunables = true; | ||||||
|  |           ProtectKernelModules = true; | ||||||
|  |           ProtectControlGroups = true; | ||||||
|  |           RestrictSUIDSGID = true; | ||||||
|  |           RestrictRealtime = true; | ||||||
|  |           RestrictNamespaces = true; | ||||||
|  |           LockPersonality = true; | ||||||
|  |           MemoryDenyWriteExecute = true; | ||||||
|  |           SystemCallArchitectures = "native"; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       networking.firewall.allowedTCPPorts = lib.mkIf config.services.panoramax.openFirewall [ | ||||||
|  |         config.services.sgblur.port | ||||||
|  |       ]; | ||||||
|  |     }) | ||||||
|  |     (lib.mkIf config.services.panoramax.database.createDB { | ||||||
|  |       services.postgresql = { | ||||||
|  |         enable = true; | ||||||
|  |         ensureDatabases = lib.mkIf config.services.panoramax.database.createDB [config.services.panoramax.database.name]; | ||||||
|  |         ensureUsers = lib.mkIf config.services.panoramax.database.createDB [ | ||||||
|  |           { | ||||||
|  |             name = config.services.panoramax.database.user; | ||||||
|  |             ensureDBOwnership = true; | ||||||
|  |             ensureClauses.login = true; | ||||||
|  |           } | ||||||
|  |         ]; | ||||||
|  |         extensions = ps: with ps; [postgis]; | ||||||
|  |       }; | ||||||
|  |       systemd.services.postgresql.serviceConfig.ExecStartPost = let | ||||||
|  |         sqlFile = pkgs.writeText "panoramax-postgis-setup.sql" '' | ||||||
|  |           CREATE EXTENSION IF NOT EXISTS postgis; | ||||||
|  | 
 | ||||||
|  |           -- TODO: how can we ensure that this runs after the databases have been created | ||||||
|  |           -- ALTER DATABASE ${config.services.panoramax.database.name} SET TIMEZONE TO 'UTC'; | ||||||
|  | 
 | ||||||
|  |           GRANT SET ON PARAMETER session_replication_role TO ${config.services.panoramax.database.user}; | ||||||
|  |         ''; | ||||||
|  |       in [ | ||||||
|  |         '' | ||||||
|  |           ${lib.getExe' config.services.postgresql.package "psql"} -d "${config.services.panoramax.database.user}" -f "${sqlFile}" | ||||||
|  |         '' | ||||||
|  |       ]; | ||||||
|  |     }) | ||||||
|  |   ]); | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								modules/nixos-modules/server/panoramax/proxy.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								modules/nixos-modules/server/panoramax/proxy.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | ||||||
|  | { | ||||||
|  |   lib, | ||||||
|  |   config, | ||||||
|  |   ... | ||||||
|  | }: { | ||||||
|  |   options.services.panoramax = { | ||||||
|  |     subdomain = lib.mkOption { | ||||||
|  |       type = lib.types.str; | ||||||
|  |       description = "subdomain of base domain that panoramax will be hosted at"; | ||||||
|  |       default = "panoramax"; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   config = lib.mkIf (config.services.panoramax.enable && config.host.reverse_proxy.enable) { | ||||||
|  |     host = { | ||||||
|  |       reverse_proxy.subdomains.${config.services.panoramax.subdomain} = { | ||||||
|  |         target = "http://localhost:${toString config.services.panoramax.port}"; | ||||||
|  | 
 | ||||||
|  |         websockets.enable = true; | ||||||
|  |         forwardHeaders.enable = true; | ||||||
|  | 
 | ||||||
|  |         extraConfig = '' | ||||||
|  |           # allow large file uploads for panoramic images | ||||||
|  |           client_max_body_size 100M; | ||||||
|  | 
 | ||||||
|  |           # set timeout for image processing | ||||||
|  |           proxy_read_timeout 300s; | ||||||
|  |           proxy_send_timeout 300s; | ||||||
|  |           send_timeout       300s; | ||||||
|  |           proxy_redirect     off; | ||||||
|  |         ''; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  |   }; | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue