diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..8392d15 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake \ No newline at end of file diff --git a/.gitignore b/.gitignore index e2f5dd2..ce2538f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -result \ No newline at end of file +result +.direnv +.vscode/* +!.vscode/settings.json \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..dcfaddd --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "secrets"] + path = secrets + url = git@git.jan-leila.com:jan-leila/nix-config-secrets.git diff --git a/.hooks/post-commit b/.hooks/post-commit index 7803850..56c439d 100755 --- a/.hooks/post-commit +++ b/.hooks/post-commit @@ -1,3 +1,6 @@ -#!/usr/bin/env bash +#!/usr/bin/env nix-shell +#! nix-shell -i bash ../shell.nix + +echo "restoring stashed changes" git stash pop -q diff --git a/.hooks/pre-commit b/.hooks/pre-commit index 5721472..f98c64f 100755 --- a/.hooks/pre-commit +++ b/.hooks/pre-commit @@ -1,11 +1,22 @@ -#!/usr/bin/env bash +#!/usr/bin/env nix-shell +#! nix-shell -i bash ../shell.nix +echo "stashing all uncommitted changes" git stash -q --keep-index -./lint.sh +echo "checking flakes all compile" +nix flake check + +if [ ! $? -eq 0 ]; then + exit 1 +fi + +echo "running linter" +alejandra -q . RESULT=$? +echo "adding lint changes to commit" git add -u exit $RESULT \ No newline at end of file diff --git a/.sops.yaml b/.sops.yaml index e9ddb56..a6e6f4f 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -9,3 +9,11 @@ creation_rules: key_groups: - age: - *leyla + - path_regex: secrets/vpn-keys.yaml$ + key_groups: + - age: + - *leyla + - path_regex: secrets/application-keys.yaml$ + key_groups: + - age: + - *leyla \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..8d6717e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,21 @@ +{ + "cSpell.words": [ + "attrsets", + "bitwarden", + "forgejo", + "gids", + "headscale", + "hesperium", + "jellyfin", + "macvlan", + "nextcloud", + "nixos", + "nixpkgs", + "pihole", + "pkgs", + "rpool", + "searx", + "ublock", + "uids" + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 60e9169..141c2fd 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +# nix-config + +https://git.jan-leila.com/jan-leila/nix-config + +nix multi user, multi system, configuration with `sops` secret management, `home-manager`, and `nixos-anywhere` setup via `disko` with `zfs` + `impermanence` + # Hosts ## Host Map @@ -5,14 +11,17 @@ | :---------: | :------------------------: | :--------------: | :-------: | | `twilight` | Desktop Computer | Leyla | Desktop | | `horizon` | 13 inch Framework Laptop | Leyla | Laptop | -| `defiant` | NAS Server | Leyla | Service | -| `emergent` | Desktop Computer | Eve | Laptop | -| `threshold` | Laptop | Eve | Desktop | +| `defiant` | NAS Server | Leyla | Server | +| `hesperium` | Mac | ????? | ??? | +| `emergent` | Desktop Computer | Eve | Desktop | +| `threshold` | Laptop | Eve | Laptop | +| `wolfram` | Steam Deck | House | Handheld | +| `ceder` | A5 Tablet (not using nix) | Leyla | Tablet | +| `skate` | A6 Tablet (not using nix) | Leyla | Tablet | +| `shale` | A6 Tablet (not using nix) | Eve | Tablet | +| `coven` | Pixel 8 (not using nix) | Leyla | Android | # Tooling -## Lint -`./lint.sh` - ## Rebuilding `./rebuild.sh` @@ -22,45 +31,43 @@ ## New host setup `./install.sh --target 192.168.1.130 --flake hostname` +## Updating Secrets +`sops secrets/secrets_file_here.yaml` + +## Inspecting a configuration +`nix-inspect -p .` + # Notes: ## Research topics -- Look into this for rotating sops keys `https://technotim.live/posts/rotate-sops-encryption-keys/` -- Look into this for openssh known configurations https://search.nixos.org/options?channel=unstable&from=0&size=15&sort=alpha_asc&type=packages&query=services.openssh -- Look into this for flake templates https://nix.dev/manual/nix/2.22/command-ref/new-cli/nix3-flake-init -- Look into this for headscale https://carlosvaz.com/posts/setting-up-headscale-on-nixos/ -- Look into this for home assistant configuration https://nixos.wiki/wiki/Home_Assistant https://myme.no/posts/2021-11-25-nixos-home-assistant.html - -## Configuration -set up git configuration for local development: `git config --local include.path .gitconfig` - -to update passwords run: `nix shell nixpkgs#sops -c sops secrets/user-passwords.yaml` (NOTE: this depends on the SOPS_AGE_KEY_DIRECTORY environment variable being set) +- 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/ +- https://nixos-and-flakes.thiscute.world/ +- nix config mcp https://github.com/utensils/mcp-nixos # Tasks: ## Tech Debt -- vscode extensions should be in own flake (make sure to add the nixpkgs.overlays in it too) -- join config for systemd.tmpfiles.rules and service directory bindings -- monitor configuration in `~/.config/monitors.xml` should be sym linked to `/run/gdm/.config/monitors.xml` -- move applications in server environment into their own flakes -- pihole config files +- monitor configuration in `~/.config/monitors.xml` should be sym linked to `/run/gdm/.config/monitors.xml` (https://www.reddit.com/r/NixOS/comments/u09cz9/home_manager_create_my_own_symlinks_automatically/) +- nfs export should be backed by the same values for server and client ## New Features -- offline access for nfs mounts (overlay with rsync might be a good option here? https://www.spinics.net/lists/linux-unionfs/msg07105.html note about nfs4 and overlay fs) -- fix pre commit hook -- Flake templates -- home assistant virtual machine -- searxng docker -- nextcloud ??? -- samba mounts -- firefox declarative??? +- crab-hole +- figure out why syncthing and jellyfins permissions don't propagate downwards - figure out steam vr things? -- Open GL? -- util functions -- openssh known hosts +- auto turn off on power loss - nut +- zfs email after scrubbing # TODO: test this +- SMART test with email results +- fix nfs +- samba mounts +- offline access for nfs mounts (overlay with rsync might be a good option here? https://www.spinics.net/lists/linux-unionfs/msg07105.html note about nfs4 and overlay fs) +- Create Tor guard/relay server +- migrate away from flakes and move to npins +- whisper +- figure out ai vs code plugin +- nix mcp +- zfs encryption FIDO2 2fa (look into shavee) +- Secure Boot - https://github.com/nix-community/lanzaboote - rotate sops encryption keys periodically (and somehow sync between devices?) -- zfs email after scrubbing -- headscale server (just needs to be tested) -- mastodon server -- tail scale clients -- wake on LAN -- ISO target that contains authorized keys for nixos-anywhere \ No newline at end of file +- wake on LAN for updates +- 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 \ No newline at end of file diff --git a/build-installer.sh b/build-installer.sh new file mode 100644 index 0000000..e124091 --- /dev/null +++ b/build-installer.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +while [ $# -gt 0 ]; do + case "$1" in + --flake*|-f*) + if [[ "$1" != *=* ]]; then shift; fi + flake="${1#*=}" + ;; + # --user*|-u*) + # if [[ "$1" != *=* ]]; then shift; fi + # user="${1#*=}" + # ;; + --help|-h) + echo "--help -h: print this message" + echo "--flake -f: set the flake to build an installer for" + # echo "--user -u: set the user to install flake as on the target system" + exit 0 + ;; + *) + echo "Error: Invalid argument $1" + exit 1 + ;; + esac + shift +done + +flake=${flake:-"basic"} +user=${user:-$USER} + +nix build .#installerConfigurations.$flake.config.system.build.isoImage \ No newline at end of file diff --git a/configurations/darwin/hesperium/configuration.nix b/configurations/darwin/hesperium/configuration.nix new file mode 100644 index 0000000..f8af5c8 --- /dev/null +++ b/configurations/darwin/hesperium/configuration.nix @@ -0,0 +1,16 @@ +{...}: { + host = { + users = { + leyla = { + isDesktopUser = true; + isTerminalUser = true; + isPrincipleUser = true; + }; + eve.isNormalUser = false; + }; + }; + + system.stateVersion = 5; + + nixpkgs.hostPlatform = "aarch64-darwin"; +} diff --git a/configurations/darwin/hesperium/default.nix b/configurations/darwin/hesperium/default.nix new file mode 100644 index 0000000..220a6fb --- /dev/null +++ b/configurations/darwin/hesperium/default.nix @@ -0,0 +1,5 @@ +{...}: { + imports = [ + ./configuration.nix + ]; +} diff --git a/configurations/home-manager/default.nix b/configurations/home-manager/default.nix new file mode 100644 index 0000000..a7fa478 --- /dev/null +++ b/configurations/home-manager/default.nix @@ -0,0 +1,12 @@ +{ + lib, + config, + osConfig, + ... +}: let + users = config.host.users; +in { + leyla = lib.mkIf users.leyla.isNormalUser (import ./leyla); + eve = lib.mkIf users.eve.isNormalUser (import ./eve); + git = lib.mkIf (osConfig.services.forgejo.enable or false) (import ./git); +} diff --git a/configurations/home-manager/eve/default.nix b/configurations/home-manager/eve/default.nix new file mode 100644 index 0000000..192c980 --- /dev/null +++ b/configurations/home-manager/eve/default.nix @@ -0,0 +1,56 @@ +{osConfig, ...}: let + userConfig = osConfig.host.users.eve; +in { + imports = [ + ./packages.nix + ./gnomeconf.nix + ]; + + home = { + username = userConfig.name; + homeDirectory = osConfig.users.users.eve.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/leyla/etc/profile.d/hm-session-vars.sh + # + sessionVariables = { + # EDITOR = "emacs"; + }; + }; +} diff --git a/configurations/home-manager/eve/gnomeconf.nix b/configurations/home-manager/eve/gnomeconf.nix new file mode 100644 index 0000000..fbad391 --- /dev/null +++ b/configurations/home-manager/eve/gnomeconf.nix @@ -0,0 +1,12 @@ +{pkgs, ...}: { + config = { + dconf = { + enable = true; + settings = { + "org/gnome/shell".enabled-extensions = [ + pkgs.gnomeExtensions.dash-to-panel.extensionUuid + ]; + }; + }; + }; +} diff --git a/configurations/home-manager/eve/packages.nix b/configurations/home-manager/eve/packages.nix new file mode 100644 index 0000000..295597a --- /dev/null +++ b/configurations/home-manager/eve/packages.nix @@ -0,0 +1,67 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: let + userConfig = osConfig.host.users.eve; + hardware = osConfig.host.hardware; +in { + config = { + nixpkgs.config = { + allowUnfree = true; + }; + + # Packages that can be installed without any extra configuration + # See https://search.nixos.org/packages for all options + home.packages = lib.lists.optionals userConfig.isDesktopUser ( + with pkgs; [ + ungoogled-chromium + krita + gnomeExtensions.dash-to-panel + (lib.mkIf hardware.piperMouse.enable piper) + ] + ); + + # Packages that need to be installed with some extra configuration + # See https://home-manager-options.extranix.com/ for all options + 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 = "Eve"; + userEmail = "evesnrobins@gmail.com"; + 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; + }; + + firefox.enable = true; + bitwarden.enable = true; + discord.enable = true; + makemkv.enable = true; + signal-desktop-bin.enable = true; + steam.enable = true; + }) + ]; + }; +} diff --git a/configurations/home-manager/git/default.nix b/configurations/home-manager/git/default.nix new file mode 100644 index 0000000..2276e7a --- /dev/null +++ b/configurations/home-manager/git/default.nix @@ -0,0 +1,20 @@ +{osConfig, ...}: { + home = { + username = osConfig.users.users.git.name; + homeDirectory = osConfig.users.users.git.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. + }; + + programs.ssh.extraConfig = '' + AuthorizedKeysFile + /var/lib/forgejo/.ssh/authorized_keys + ''; +} diff --git a/configurations/home-manager/leyla/dconf.nix b/configurations/home-manager/leyla/dconf.nix new file mode 100644 index 0000000..ef75db6 --- /dev/null +++ b/configurations/home-manager/leyla/dconf.nix @@ -0,0 +1,89 @@ +{pkgs, ...}: { + config = { + gnome = { + extraWindowControls = true; + colorScheme = "prefer-dark"; + clockFormat = "24h"; + extensions = [ + pkgs.gnomeExtensions.dash-to-dock + ]; + hotkeys = { + "Open Terminal" = { + binding = "t"; + command = "kgx"; + }; + }; + }; + + dconf = { + enable = true; + settings = { + "org/gnome/shell/extensions/dash-to-dock" = { + "dock-position" = "LEFT"; + "intellihide-mode" = "ALL_WINDOWS"; + "show-trash" = false; + "require-pressure-to-show" = false; + "show-mounts" = false; + }; + + "org/gnome/shell" = { + favorite-apps = ["org.gnome.Nautilus.desktop" "firefox.desktop" "codium.desktop" "steam.desktop" "org.gnome.Console.desktop"]; + # app-picker-layout = + # builtins.map ( + # applications: + # lib.hm.gvariant (builtins.listToAttrs (lib.lists.imap0 (i: v: lib.attrsets.nameValuePair v (lib.hm.gvariant.mkVariant "{'position': <${i}>}")) applications)) + # ) [ + # [ + # "org.gnome.Nautilus.desktop" + # "bitwarden.desktop" + # "firefox.desktop" + # "torbrowser.desktop" + # "chromium-browser.desktop" + # "codium.desktop" + # "idea-community.desktop" + # "org.gnome.TextEditor.desktop" + # "dbeaver.desktop" + # "bruno.desktop" + # "anki.desktop" + # "obsidian.desktop" + # "signal-desktop.desktop" + # "discord.desktop" + # "gimp.desktop" + # "org.inkscape.Inkscape.desktop" + # "org.kde.krita.desktop" + # "davinci-resolve.desktop" + # "com.obsproject.Studio.desktop" + # "org.freecad.FreeCAD.desktop" + # "makemkv.desktop" + # "easytag.desktop" + # "transmission-gtk.desktop" + # ] + # [ + # "SteamVR.desktop" + # "Beat Saber.desktop" + # "Noun Town.desktop" + # "WEBFISHING.desktop" + # "Factorio.desktop" + # ] + # [ + # "org.gnome.Settings.desktop" + # "org.gnome.SystemMonitor.desktop" + # "org.gnome.Snapshot.desktop" + # "org.gnome.Usage.desktop" + # "org.gnome.DiskUtility.desktop" + # "org.gnome.Evince.desktop" + # "org.gnome.fonts.desktop" + # "noisetorch.desktop" + # "nvidia-settings.desktop" + # "OpnRGB.desktop" + # "org.freedesktop.Piper.desktop" + # "via-nativia.desktop" + # "protonvpn-app.desktop" + # "simple-scan.desktop" + # ] + # ]; + }; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/default.nix b/configurations/home-manager/leyla/default.nix new file mode 100644 index 0000000..538eab8 --- /dev/null +++ b/configurations/home-manager/leyla/default.nix @@ -0,0 +1,86 @@ +{ + config, + osConfig, + ... +}: { + imports = [ + ./packages + ./i18n.nix + ./impermanence.nix + ./dconf.nix + ]; + + config = { + # Home Manager needs a bit of information about you and the paths it should + # manage. + home = { + username = osConfig.host.users.leyla.name; + homeDirectory = osConfig.users.users.leyla.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 + # ''; + "${config.xdg.configHome}/user-dirs.dirs" = { + force = true; + text = '' + # This file is written by xdg-user-dirs-update + # If you want to change or add directories, just edit the line you're + # interested in. All local changes will be retained on the next run. + # Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped + # homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an + # absolute path. No other format is supported. + # + XDG_DESKTOP_DIR="$HOME/desktop" + XDG_DOWNLOAD_DIR="$HOME/downloads" + XDG_DOCUMENTS_DIR="$HOME/documents" + XDG_TEMPLATES_DIR="$HOME/documents/templates" + XDG_MUSIC_DIR="$HOME/documents/music" + XDG_PICTURES_DIR="$HOME/documents/photos" + XDG_VIDEOS_DIR="$HOME/documents/videos" + XDG_PUBLICSHARE_DIR="$HOME/documents/public" + ''; + }; + }; + + keyboard.layout = "us,it,de"; + + # 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/leyla/etc/profile.d/hm-session-vars.sh + # + sessionVariables = { + # EDITOR = "emacs"; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/i18n.nix b/configurations/home-manager/leyla/i18n.nix new file mode 100644 index 0000000..f12cd95 --- /dev/null +++ b/configurations/home-manager/leyla/i18n.nix @@ -0,0 +1,12 @@ +{...}: { + i18n = { + defaultLocale = "en_IE.UTF-8"; + + extraLocaleSettings = { + # LC_ADDRESS = "en_IE.UTF-8"; # lets just get used to this one now + # LC_TELEPHONE = "en_IE.UTF-8"; # lets just get used to this one now + LC_MONETARY = "en_US.UTF-8"; # to be changed once I move + LC_PAPER = "en_US.UTF-8"; # convenient for american printers until I move + }; + }; +} diff --git a/configurations/home-manager/leyla/impermanence.nix b/configurations/home-manager/leyla/impermanence.nix new file mode 100644 index 0000000..041bff8 --- /dev/null +++ b/configurations/home-manager/leyla/impermanence.nix @@ -0,0 +1,21 @@ +{ + lib, + config, + osConfig, + ... +}: { + config = lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist/home/leyla" = { + directories = [ + "desktop" + "downloads" + "documents" + ]; + files = [ + ".bash_history" # keep shell history around + "${config.xdg.dataHome}/recently-used.xbel" # gnome recently viewed files + ]; + allowOther = true; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages/default.nix b/configurations/home-manager/leyla/packages/default.nix new file mode 100644 index 0000000..63f9661 --- /dev/null +++ b/configurations/home-manager/leyla/packages/default.nix @@ -0,0 +1,118 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: let + hardware = osConfig.host.hardware; +in { + imports = [ + ./vscode + ./firefox.nix + ./direnv.nix + ./openssh.nix + ./git.nix + ./makemkv.nix + ]; + + config = lib.mkMerge [ + { + programs = lib.mkMerge [ + { + # Let Home Manager install and manage itself. + home-manager.enable = true; + } + (lib.mkIf (config.user.isTerminalUser || config.user.isDesktopUser) { + bash.enable = true; + git.enable = true; + openssh.enable = true; + }) + (lib.mkIf config.user.isDesktopUser { + bitwarden.enable = true; + obs-studio.enable = hardware.graphicsAcceleration.enable; + qbittorrent.enable = true; + prostudiomasters.enable = true; + protonvpn-gui.enable = true; + dbeaver-bin.enable = true; + bruno.enable = true; + }) + (lib.mkIf (hardware.directAccess.enable && config.user.isDesktopUser) { + anki.enable = true; + makemkv.enable = true; + discord.enable = true; + signal-desktop-bin.enable = true; + calibre.enable = true; + obsidian.enable = true; + jetbrains.idea-community.enable = true; + vscode.enable = true; + firefox.enable = true; + steam.enable = true; + }) + ]; + } + (lib.mkIf config.user.isTerminalUser { + home.packages = with pkgs; [ + # command line tools + sox + yt-dlp + ffmpeg + imagemagick + ]; + }) + (lib.mkIf config.user.isDesktopUser { + nixpkgs.config = { + allowUnfree = true; + }; + + home.packages = ( + (with pkgs; [ + aileron + + proxmark3 + ]) + ++ ( + lib.lists.optionals hardware.directAccess.enable (with pkgs; [ + #foss platforms + ungoogled-chromium + libreoffice + inkscape + gimp + krita + 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.piperMouse.enable piper) + (lib.mkIf hardware.openRGB.enable openrgb) + (lib.mkIf hardware.viaKeyboard.enable via) + ]) + ) + ); + }) + ]; +} diff --git a/configurations/home-manager/leyla/packages/direnv.nix b/configurations/home-manager/leyla/packages/direnv.nix new file mode 100644 index 0000000..038c149 --- /dev/null +++ b/configurations/home-manager/leyla/packages/direnv.nix @@ -0,0 +1,22 @@ +{ + lib, + config, + osConfig, + ... +}: let + userConfig = osConfig.host.users.leyla; +in { + config = lib.mkIf userConfig.isDesktopUser { + programs = { + direnv = { + enable = true; + enableBashIntegration = true; + nix-direnv.enable = true; + config = { + global.hide_env_diff = true; + whitelist.exact = ["${config.home.homeDirectory}/documents/code/nix-config"]; + }; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages/firefox.nix b/configurations/home-manager/leyla/packages/firefox.nix new file mode 100644 index 0000000..1613cb3 --- /dev/null +++ b/configurations/home-manager/leyla/packages/firefox.nix @@ -0,0 +1,343 @@ +{ + lib, + pkgs, + inputs, + ... +}: { + config = { + programs.firefox = { + profiles.leyla = { + settings = { + "browser.search.defaultenginename" = "Searx"; + "browser.search.order.1" = "Searx"; + }; + + search = { + force = true; + default = "Searx"; + engines = { + "Nix Packages" = { + urls = [ + { + template = "https://search.nixos.org/packages"; + params = [ + { + name = "type"; + value = "packages"; + } + { + name = "query"; + value = "{searchTerms}"; + } + ]; + } + ]; + icon = "''${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = ["@np"]; + }; + "NixOS Wiki" = { + urls = [{template = "https://nixos.wiki/index.php?search={searchTerms}";}]; + icon = "https://nixos.wiki/favicon.png"; + updateInterval = 24 * 60 * 60 * 1000; # every day + definedAliases = ["@nw"]; + }; + "Searx" = { + urls = [{template = "https://search.jan-leila.com/?q={searchTerms}";}]; + icon = "https://nixos.wiki/favicon.png"; + updateInterval = 24 * 60 * 60 * 1000; # every day + definedAliases = ["@searx"]; + }; + }; + }; + + extensions.packages = with inputs.firefox-addons.packages.${pkgs.system}; [ + bitwarden + terms-of-service-didnt-read + multi-account-containers + shinigami-eyes + + ublock-origin + sponsorblock + dearrow + df-youtube + return-youtube-dislikes + + privacy-badger + decentraleyes + clearurls + localcdn + + snowflake + + deutsch-de-language-pack + dictionary-german + + # ( + # buildFirefoxXpiAddon rec { + # pname = "italiano-it-language-pack"; + # version = "132.0.20241110.231641"; + # addonId = "langpack-it@firefox.mozilla.org"; + # url = "https://addons.mozilla.org/firefox/downloads/file/4392453/italiano_it_language_pack-${version}.xpi"; + # sha256 = ""; + # meta = with lib; + # { + # description = "Firefox Language Pack for Italiano (it) – Italian"; + # license = licenses.mpl20; + # mozPermissions = []; + # platforms = platforms.all; + # }; + # } + # ) + # ( + # buildFirefoxXpiAddon rec { + # pname = "dizionario-italiano"; + # version = "5.1"; + # addonId = "it-IT@dictionaries.addons.mozilla.org"; + # url = "https://addons.mozilla.org/firefox/downloads/file/1163874/dizionario_italiano-${version}.xpi"; + # sha256 = ""; + # meta = with lib; + # { + # description = "Add support for Italian to spellchecking"; + # license = licenses.gpl3; + # mozPermissions = []; + # platforms = platforms.all; + # }; + # } + # ) + ]; + + settings = { + # Disable irritating first-run stuff + "browser.disableResetPrompt" = true; + "browser.download.panel.shown" = true; + "browser.feeds.showFirstRunUI" = false; + "browser.messaging-system.whatsNewPanel.enabled" = false; + "browser.rights.3.shown" = true; + "browser.shell.checkDefaultBrowser" = false; + "browser.shell.defaultBrowserCheckCount" = 1; + "browser.startup.homepage_override.mstone" = "ignore"; + "browser.uitour.enabled" = false; + "startup.homepage_override_url" = ""; + "trailhead.firstrun.didSeeAboutWelcome" = true; + "browser.bookmarks.restore_default_bookmarks" = false; + "browser.bookmarks.addedImportButton" = true; + "browser.newtabpage.activity-stream.feeds.section.topstories" = false; + + # Usage Experience + "browser.startup.homepage" = "about:home"; + "browser.download.useDownloadDir" = false; + "browser.uiCustomization.state" = builtins.toJSON { + "currentVersion" = 20; + "newElementCount" = 6; + "dirtyAreaCache" = [ + "nav-bar" + "PersonalToolbar" + "toolbar-menubar" + "TabsToolbar" + "unified-extensions-area" + "vertical-tabs" + ]; + "placements" = { + "widget-overflow-fixed-list" = []; + "unified-extensions-area" = [ + "privacy_privacy_com-browser-action" + # bitwarden + "_446900e4-71c2-419f-a6a7-df9c091e268b_-browser-action" + "ublock0_raymondhill_net-browser-action" + "sponsorblocker_ajay_app-browser-action" + "dearrow_ajay_app-browser-action" + "jid1-mnnxcxisbpnsxq_jetpack-browser-action" + "_testpilot-containers-browser-action" + "addon_simplelogin-browser-action" + "_74145f27-f039-47ce-a470-a662b129930a_-browser-action" + "jid1-bofifl9vbdl2zq_jetpack-browser-action" + "dfyoutube_example_com-browser-action" + "_b86e4813-687a-43e6-ab65-0bde4ab75758_-browser-action" + "_762f9885-5a13-4abd-9c77-433dcd38b8fd_-browser-action" + "_b11bea1f-a888-4332-8d8a-cec2be7d24b9_-browse-action" + "jid0-3guet1r69sqnsrca5p8kx9ezc3u_jetpack-browser-action" + ]; + "nav-bar" = [ + "back-button" + "forward-button" + "stop-reload-button" + "urlbar-container" + "downloads-button" + "unified-extensions-button" + "reset-pbm-toolbar-button" + ]; + "toolbar-menubar" = [ + "menubar-items" + ]; + "TabsToolbar" = [ + "firefox-view-button" + "tabbrowser-tabs" + "new-tab-button" + "alltabs-button" + ]; + "vertical-tabs" = []; + "PersonalToolbar" = [ + "import-button" + "personal-bookmarks" + ]; + }; + "seen" = [ + "save-to-pocket-button" + "developer-button" + "privacy_privacy_com-browser-action" + "sponsorblocker_ajay_app-browser-action" + "ublock0_raymondhill_net-browser-action" + "addon_simplelogin-browser-action" + "dearrow_ajay_app-browser-action" + "_446900e4-71c2-419f-a6a7-df9c091e268b_-browser-action" + "_74145f27-f039-47ce-a470-a662b129930a_-browser-action" + "jid1-bofifl9vbdl2zq_jetpack-browser-action" + "dfyoutube_example_com-browser-action" + "_testpilot-containers-browser-action" + "_b86e4813-687a-43e6-ab65-0bde4ab75758_-browser-action" + "jid1-mnnxcxisbpnsxq_jetpack-browser-action" + "_762f9885-5a13-4abd-9c77-433dcd38b8fd_-browser-action" + "_b11bea1f-a888-4332-8d8a-cec2be7d24b9_-browser-action" + "jid0-3guet1r69sqnsrca5p8kx9ezc3u_jetpack-browser-action" + ]; + }; + "browser.newtabpage.activity-stream.feeds.topsites" = false; + "browser.newtabpage.activity-stream.showSponsoredTopSites" = false; + "browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts" = false; + "browser.newtabpage.blocked" = lib.genAttrs [ + # Facebook + "4gPpjkxgZzXPVtuEoAL9Ig==" + # Reddit + "gLv0ja2RYVgxKdp0I5qwvA==" + # Amazon + "K00ILysCaEq8+bEqV/3nuw==" + # Twitter + "T9nJot5PurhJSy8n038xGA==" + ] (_: 1); + "identity.fxaccounts.enabled" = false; + + # Security + "privacy.trackingprotection.enabled" = true; + "dom.security.https_only_mode" = true; + + "extensions.formautofill.addresses.enabled" = false; + "extensions.formautofill.creditCards.enabled" = false; + "signon.rememberSignons" = false; + "privacy.sanitize.sanitizeOnShutdown" = true; + "privacy.clearOnShutdown_v2.cache" = true; + "privacy.clearOnShutdown_v2.cookiesAndStorage" = true; + "privacy.clearOnShutdown_v2.historyFormDataAndDownloads" = true; + "urlclassifier.trackingSkipURLs" = ""; + "urlclassifier.features.socialtracking.skipURLs" = ""; + "dom.security.https_only_mode_pbm" = true; + "dom.security.https_only_mode_error_page_user_suggestions" = true; + + # Disable telemetry + "app.shield.optoutstudies.enabled" = false; + "browser.discovery.enabled" = false; + "browser.newtabpage.activity-stream.feeds.telemetry" = false; + "browser.newtabpage.activity-stream.telemetry" = false; + "browser.ping-centre.telemetry" = false; + "datareporting.healthreport.service.enabled" = false; + "datareporting.healthreport.uploadEnabled" = false; + "datareporting.policy.dataSubmissionEnabled" = false; + "datareporting.sessions.current.clean" = true; + "devtools.onboarding.telemetry.logged" = false; + "toolkit.telemetry.archive.enabled" = false; + "toolkit.telemetry.bhrPing.enabled" = false; + "toolkit.telemetry.enabled" = false; + "toolkit.telemetry.firstShutdownPing.enabled" = false; + "toolkit.telemetry.hybridContent.enabled" = false; + "toolkit.telemetry.newProfilePing.enabled" = false; + "toolkit.telemetry.prompted" = 2; + "toolkit.telemetry.rejected" = true; + "toolkit.telemetry.reportingpolicy.firstRun" = false; + "toolkit.telemetry.server" = ""; + "toolkit.telemetry.shutdownPingSender.enabled" = false; + "toolkit.telemetry.unified" = false; + "toolkit.telemetry.unifiedIsOptIn" = false; + "toolkit.telemetry.updatePing.enabled" = false; + }; + + bookmarks = { + force = true; + settings = [ + { + name = "Media"; + url = "https://media.jan-leila.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Photos"; + url = "https://photos.jan-leila.com"; + keyword = ""; + tags = [""]; + } + { + name = "Git"; + url = "https://git.jan-leila.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Home Automation"; + url = "https://home.jan-leila.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Mail"; + url = "https://mail.protonmail.com"; + keyword = ""; + tags = [""]; + } + { + name = "Open Street Map"; + url = "https://www.openstreetmap.org/"; + keyword = ""; + tags = [""]; + } + { + name = "Password Manager"; + url = "https://vault.bitwarden.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Mastodon"; + url = "https://mspsocial.net"; + keyword = ""; + tags = [""]; + } + { + name = "Linked In"; + url = "https://www.linkedin.com/"; + keyword = ""; + tags = [""]; + } + { + name = "Job Search"; + url = "https://www.jobsinnetwork.com/?state=cleaned_history&language%5B%5D=en&query=react&locations.countryCode%5B%5D=IT&locations.countryCode%5B%5D=DE&locations.countryCode%5B%5D=NL&experience%5B%5D=medior&experience%5B%5D=junior&page=1"; + keyword = ""; + tags = [""]; + } + { + name = "React Docs"; + url = "https://react.dev/"; + keyword = ""; + tags = [""]; + } + # Template + # { + # name = ""; + # url = ""; + # keyword = ""; + # tags = [""]; + # } + ]; + }; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages/git.nix b/configurations/home-manager/leyla/packages/git.nix new file mode 100644 index 0000000..568cd7a --- /dev/null +++ b/configurations/home-manager/leyla/packages/git.nix @@ -0,0 +1,11 @@ +{...}: { + config = { + programs = { + git = { + userName = "Leyla Becker"; + userEmail = "git@jan-leila.com"; + extraConfig.init.defaultBranch = "main"; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages/makemkv.nix b/configurations/home-manager/leyla/packages/makemkv.nix new file mode 100644 index 0000000..ee71955 --- /dev/null +++ b/configurations/home-manager/leyla/packages/makemkv.nix @@ -0,0 +1,17 @@ +{ + config, + inputs, + ... +}: { + config = { + sops.secrets = { + "application-keys/makemkv" = { + sopsFile = "${inputs.secrets}/application-keys.yaml"; + }; + }; + programs.makemkv = { + appKeyFile = config.sops.placeholder."application-keys/makemkv"; + destinationDir = "/home/leyla/downloads/makemkv"; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages/openssh.nix b/configurations/home-manager/leyla/packages/openssh.nix new file mode 100644 index 0000000..91aec11 --- /dev/null +++ b/configurations/home-manager/leyla/packages/openssh.nix @@ -0,0 +1,23 @@ +{ + config, + osConfig, + ... +}: { + config = { + programs = { + openssh = { + authorizedKeys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJHeItmt8TRW43uNcOC+eIurYC7Eunc0V3LGocQqLaYj leyla@horizon" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIILimFIW2exEH/Xo7LtXkqgE04qusvnPNpPWSCeNrFkP leyla@defiant" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKBiZkg1c2aaNHiieBX4cEziqvJVj9pcDfzUrKU/mO0I leyla@twilight" + ]; + hostKeys = [ + { + type = "ed25519"; + path = "${config.home.username}_${osConfig.networking.hostName}_ed25519"; + } + ]; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages/vscode/default.nix b/configurations/home-manager/leyla/packages/vscode/default.nix new file mode 100644 index 0000000..89ee876 --- /dev/null +++ b/configurations/home-manager/leyla/packages/vscode/default.nix @@ -0,0 +1,107 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: let + nix-development-enabled = osConfig.host.nix-development.enable; + ai-tooling-enabled = osConfig.host.ai.enable; +in { + config = lib.mkIf config.user.isDesktopUser { + programs = { + bash.shellAliases = { + code = "codium"; + }; + + vscode = { + package = pkgs.vscodium; + + mutableExtensionsDir = false; + + profiles.default = { + enableUpdateCheck = false; + enableExtensionUpdateCheck = false; + + userSettings = lib.mkMerge [ + { + "workbench.colorTheme" = "Atom One Dark"; + "cSpell.userWords" = import ./user-words.nix; + "javascript.updateImportsOnFileMove.enabled" = "always"; + "editor.tabSize" = 2; + "editor.insertSpaces" = false; + } + (lib.mkIf nix-development-enabled { + "nix.enableLanguageServer" = true; + "nix.serverPath" = "nil"; + "[nix]" = { + "editor.defaultFormatter" = "kamadorueda.alejandra"; + "editor.formatOnPaste" = true; + "editor.formatOnSave" = true; + "editor.formatOnType" = true; + }; + "alejandra.program" = "alejandra"; + "nixpkgs" = { + "expr" = "import {}"; + }; + }) + (lib.mkIf ai-tooling-enabled { + }) + ]; + + extensions = let + extension-pkgs = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version; + in ( + with extension-pkgs.open-vsx; + [ + # vs code feel extensions + ms-vscode.atom-keybindings + akamud.vscode-theme-onedark + streetsidesoftware.code-spell-checker + streetsidesoftware.code-spell-checker-german + streetsidesoftware.code-spell-checker-italian + jeanp413.open-remote-ssh + + # html extensions + formulahendry.auto-rename-tag + ms-vscode.live-server + + # js extensions + dsznajder.es7-react-js-snippets + dbaeumer.vscode-eslint + standard.vscode-standard + orta.vscode-jest + stylelint.vscode-stylelint + tauri-apps.tauri-vscode + + # go extensions + golang.go + + # astro blog extensions + astro-build.astro-vscode + unifiedjs.vscode-mdx + + # misc extensions + tamasfe.even-better-toml + ] + ++ (lib.lists.optionals nix-development-enabled [ + # nix extensions + pinage404.nix-extension-pack + jnoortheen.nix-ide + kamadorueda.alejandra + ]) + ++ ( + with extension-pkgs.vscode-marketplace; + [ + # js extensions + karyfoundation.nearley + ] + ++ (lib.lists.optionals ai-tooling-enabled [ + ]) + ) + ); + }; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages/vscode/user-words.nix b/configurations/home-manager/leyla/packages/vscode/user-words.nix new file mode 100644 index 0000000..b581118 --- /dev/null +++ b/configurations/home-manager/leyla/packages/vscode/user-words.nix @@ -0,0 +1,6 @@ +[ + "leyla" + "webdav" + "ollama" + "optimise" +] diff --git a/configurations/installer/basic/configuration.nix b/configurations/installer/basic/configuration.nix new file mode 100644 index 0000000..4e63727 --- /dev/null +++ b/configurations/installer/basic/configuration.nix @@ -0,0 +1,19 @@ +{ + lib, + pkgs, + modulesPath, + ... +}: { + imports = [(modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix")]; + + systemd.services.sshd.wantedBy = pkgs.lib.mkForce ["multi-user.target"]; + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AaAeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee username@host" + ]; + + isoImage.squashfsCompression = "gzip -Xcompression-level 1"; + + networking.hostName = "installer"; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/configurations/installer/basic/default.nix b/configurations/installer/basic/default.nix new file mode 100644 index 0000000..220a6fb --- /dev/null +++ b/configurations/installer/basic/default.nix @@ -0,0 +1,5 @@ +{...}: { + imports = [ + ./configuration.nix + ]; +} diff --git a/configurations/nixos/defiant/configuration.nix b/configurations/nixos/defiant/configuration.nix new file mode 100644 index 0000000..960e90b --- /dev/null +++ b/configurations/nixos/defiant/configuration.nix @@ -0,0 +1,327 @@ +# server nas +{ + inputs, + config, + ... +}: { + sops.secrets = { + "vpn-keys/tailscale-authkey/defiant" = { + sopsFile = "${inputs.secrets}/vpn-keys.yaml"; + }; + "vpn-keys/proton-wireguard/defiant-p2p" = { + sopsFile = "${inputs.secrets}/vpn-keys.yaml"; + mode = "0640"; + owner = "root"; + group = "systemd-network"; + }; + "services/zfs_smtp_token" = { + sopsFile = "${inputs.secrets}/defiant-services.yaml"; + }; + "services/paperless_password" = { + sopsFile = "${inputs.secrets}/defiant-services.yaml"; + mode = "0700"; + owner = "paperless"; + group = "paperless"; + }; + }; + + host = { + users = { + leyla = { + isDesktopUser = true; + isTerminalUser = true; + isPrincipleUser = true; + }; + }; + impermanence.enable = true; + storage = { + enable = true; + encryption = true; + notifications = { + enable = true; + host = "smtp.protonmail.ch"; + port = 587; + to = "leyla@jan-leila.com"; + user = "leyla@jan-leila.com"; + tokenFile = config.sops.secrets."services/zfs_smtp_token".path; + }; + pool = { + # We are having to boot off of the nvm cache drive because I cant figure out how to boot via the HBA + bootDrives = ["nvme-Samsung_SSD_990_PRO_4TB_S7KGNU0X907881F"]; + vdevs = [ + [ + "ata-ST18000NE000-3G6101_ZVTCXVEB" + "ata-ST18000NE000-3G6101_ZVTCXWSC" + "ata-ST18000NE000-3G6101_ZVTD10EH" + "ata-ST18000NT001-3NF101_ZVTE0S3Q" + "ata-ST18000NT001-3NF101_ZVTEF27J" + "ata-ST18000NE000-3G6101_ZVTJ7359" + ] + # TODO: this needs to be configured manually + [ + "ata-ST4000NE001-2MA101_WS2275P3" + "ata-ST4000NE001-2MA101_WS227B9F" + "ata-ST4000NE001-2MA101_WS227CEW" + "ata-ST4000NE001-2MA101_WS227CYN" + "ata-ST4000NE001-2MA101_WS23TBWV" + "ata-ST4000NE001-2MA101_WS23TC5F" + ] + ]; + cache = [ + "nvme-Samsung_SSD_990_PRO_4TB_S7KGNU0X907881F" + ]; + }; + }; + network_storage = { + enable = true; + directories = [ + { + folder = "leyla_documents"; + user = "leyla"; + group = "leyla"; + bind = "/home/leyla/documents"; + } + { + folder = "eve_documents"; + user = "eve"; + group = "eve"; + } + { + folder = "users_documents"; + user = "root"; + group = "users"; + } + { + folder = "media"; + user = "jellyfin"; + group = "jellyfin_media"; + bind = config.services.jellyfin.media_directory; + } + ]; + nfs = { + enable = true; + directories = ["leyla_documents" "eve_documents" "users_documents" "media"]; + }; + }; + reverse_proxy = { + enable = true; + enableACME = true; + hostname = "jan-leila.com"; + }; + postgres = { + extraUsers = { + leyla = { + isAdmin = true; + }; + }; + }; + }; + + systemd.network = { + enable = true; + + # config = { + # routeTables = { + # p2p = 1; + # }; + # }; + + netdevs = { + "10-bond0" = { + netdevConfig = { + Kind = "bond"; + Name = "bond0"; + }; + bondConfig = { + Mode = "802.3ad"; + TransmitHashPolicy = "layer3+4"; + }; + }; + + # "15-p2p0" = { + # netdevConfig = { + # Kind = "wireguard"; + # Name = "p2p0"; + # MTUBytes = "1280"; + # }; + # wireguardConfig = { + # PrivateKeyFile = config.sops.secrets."vpn-keys/proton-wireguard/defiant-p2p".path; + # ListenPort = 51820; + # # RouteTable = "p2p"; + # }; + # wireguardPeers = [ + # { + # PublicKey = "rRO6yJim++Ezz6scCLMaizI+taDjU1pzR2nfW6qKbW0="; + # Endpoint = "185.230.126.146:51820"; + # AllowedIPs = ["0.0.0.0/0"]; + # RouteTable = "off"; + # } + # ]; + # }; + }; + networks = { + "40-bond0" = { + matchConfig.Name = "bond0"; + linkConfig = { + RequiredForOnline = "degraded-carrier"; + RequiredFamilyForOnline = "any"; + }; + networkConfig.DHCP = "yes"; + + address = [ + "192.168.1.10/32" + ]; + + gateway = ["192.168.1.1"]; + dns = ["192.168.1.1"]; + }; + + # "45-p2p0" = { + # matchConfig.Name = "p2p0"; + # address = [ + # "10.2.0.2/32" + # ]; + # routes = [ + # { + # Destination = "0.0.0.0/0"; + # } + # ]; + # linkConfig.RequiredForOnline = false; + # }; + }; + }; + + # 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"]; + + services = { + # TODO: move zfs scrubbing into module + zfs = { + autoScrub.enable = true; + autoSnapshot.enable = true; + }; + + # temp enable desktop enviroment for setup + # Enable the X11 windowing system. + xserver.enable = true; + + # Enable the GNOME Desktop Environment. + displayManager = { + gdm.enable = true; + }; + desktopManager = { + gnome.enable = true; + }; + + ollama = { + enable = true; + exposePort = true; + + acceleration = false; + + loadModels = [ + # conversation models + "llama3.1:8b" + "deepseek-r1:8b" + "deepseek-r1:32b" + "deepseek-r1:70b" + + # auto complete models + "qwen2.5-coder:1.5b-base" + "qwen2.5-coder:7b" + "deepseek-coder:6.7b" + "deepseek-coder:33b" + + # agent models + "qwen3:8b" + "qwen3:32b" + + # embedding models + "nomic-embed-text:latest" + ]; + }; + tailscale = { + enable = true; + authKeyFile = config.sops.secrets."vpn-keys/tailscale-authkey/defiant".path; + useRoutingFeatures = "server"; + extraUpFlags = [ + "--advertise-exit-node" + "--advertise-routes=192.168.0.0/24" + "--accept-dns=false" + ]; + extraSetFlags = [ + "--advertise-exit-node" + "--advertise-routes=192.168.0.0/24" + "--accept-dns=false" + ]; + }; + + syncthing.enable = true; + + fail2ban.enable = true; + + jellyfin = { + enable = true; + subdomain = "media"; + extraSubdomains = ["jellyfin"]; + }; + + immich = { + enable = true; + subdomain = "photos"; + }; + + forgejo = { + enable = true; + subdomain = "git"; + }; + + searx = { + enable = true; + subdomain = "search"; + }; + + home-assistant = { + enable = true; + subdomain = "home"; + openFirewall = true; + database = "postgres"; + + extensions = { + sonos.enable = true; + jellyfin.enable = true; + wyoming.enable = true; + }; + }; + + paperless = { + enable = true; + subdomain = "documents"; + passwordFile = config.sops.secrets."services/paperless_password".path; + }; + + qbittorrent = { + enable = true; + mediaDir = "/srv/qbittorent"; + openFirewall = true; + webPort = 8084; + }; + }; + + # disable computer sleeping + systemd.targets = { + sleep.enable = false; + suspend.enable = false; + hibernate.enable = false; + hybrid-sleep.enable = false; + }; + services.displayManager.gdm.autoSuspend = false; + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It's perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + # Before changing this value read the documentation for this option + # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). + system.stateVersion = "23.05"; # Did you read the comment? +} diff --git a/configurations/nixos/defiant/default.nix b/configurations/nixos/defiant/default.nix new file mode 100644 index 0000000..fe850af --- /dev/null +++ b/configurations/nixos/defiant/default.nix @@ -0,0 +1,7 @@ +# server nas +{...}: { + imports = [ + ./hardware-configuration.nix + ./configuration.nix + ]; +} diff --git a/hosts/defiant/hardware-configuration.nix b/configurations/nixos/defiant/hardware-configuration.nix similarity index 54% rename from hosts/defiant/hardware-configuration.nix rename to configurations/nixos/defiant/hardware-configuration.nix index edfaeee..d4a638b 100644 --- a/hosts/defiant/hardware-configuration.nix +++ b/configurations/nixos/defiant/hardware-configuration.nix @@ -4,79 +4,57 @@ { config, lib, - pkgs, modulesPath, ... }: { imports = [ (modulesPath + "/installer/scan/not-detected.nix") - ../hardware-common.nix ]; boot = { initrd = { - availableKernelModules = ["xhci_pci" "aacraid" "ahci" "usbhid" "usb_storage" "sd_mod"]; + availableKernelModules = ["xhci_pci" "aacraid" "ahci" "usbhid" "nvme" "usb_storage" "sd_mod"]; kernelModules = []; }; kernelModules = ["kvm-amd"]; extraModulePackages = []; + # Bootloader. + loader = { + systemd-boot.enable = true; + efi = { + canTouchEfiVariables = true; + efiSysMountPoint = "/boot"; + }; + }; supportedFilesystems = ["zfs"]; - zfs.extraPools = ["zroot"]; + zfs.extraPools = ["rpool"]; }; - swapDevices = []; - networking = { - hostId = "c51763d6"; hostName = "defiant"; # Define your hostname. + hostId = "c51763d6"; useNetworkd = true; }; systemd.network = { enable = true; - netdevs = { - "10-bond0" = { - netdevConfig = { - Kind = "bond"; - Name = "bond0"; - }; - bondConfig = { - Mode = "802.3ad"; - TransmitHashPolicy = "layer3+4"; - }; - }; - }; - networks = { - "30-enp4s0" = { - matchConfig.Name = "enp4s0"; + "30-eno1" = { + matchConfig.Name = "eno1"; networkConfig.Bond = "bond0"; - DHCP = "no"; }; - "30-enp5s0" = { - matchConfig.Name = "enp5s0"; + "30-eno2" = { + matchConfig.Name = "eno2"; networkConfig.Bond = "bond0"; - DHCP = "no"; - }; - - "40-bond0" = { - matchConfig.Name = "bond0"; - linkConfig.RequiredForOnline = "carrier"; - networkConfig.LinkLocalAddressing = "no"; - DHCP = "ipv4"; - - address = [ - # configure addresses including subnet mask - "192.168.1.10/24" - # TODO: ipv6 address configuration - ]; }; }; }; + networking.networkmanager.enable = true; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; hardware = { # TODO: hardware graphics diff --git a/configurations/nixos/emergent/configuration.nix b/configurations/nixos/emergent/configuration.nix new file mode 100644 index 0000000..90aecab --- /dev/null +++ b/configurations/nixos/emergent/configuration.nix @@ -0,0 +1,160 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page, on +# https://search.nixos.org/options and in the NixOS manual (`nixos-help`). +{ + lib, + pkgs, + ... +}: { + imports = [ + ./nvidia-drivers.nix + ]; + + # Use the systemd-boot EFI boot loader. + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + # networking.hostName = "nixos"; # Define your hostname. + # Pick only one of the below networking options. + # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. + # networking.networkmanager.enable = true; # Easiest to use and most distros use this by default. + + # Set your time zone. + # time.timeZone = "Europe/Amsterdam"; + + # Configure network proxy if necessary + # networking.proxy.default = "http://user:password@proxy:port/"; + # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; + + # Select internationalisation properties. + # i18n.defaultLocale = "en_US.UTF-8"; + # console = { + # font = "Lat2-Terminus16"; + # keyMap = "us"; + # useXkbConfig = true; # use xkb.options in tty. + # }; + + # Enable the X11 windowing system. + services.xserver.enable = true; + # Enable wacom touchscreen device + services.xserver.wacom.enable = true; + + # installed opentabletdriver + hardware.opentabletdriver.enable = true; + + # Enable the GNOME Desktop Environment. + services.displayManager.gdm.enable = true; + services.desktopManager.gnome.enable = true; + + host = { + users = { + eve = { + isDesktopUser = true; + isTerminalUser = true; + isPrincipleUser = true; + }; + }; + hardware = { + piperMouse.enable = true; + }; + + storage = { + enable = true; + pool = { + mode = ""; + drives = ["wwn-0x5000039fd0cf05eb"]; + }; + }; + }; + + # Configure keymap in X11 + # services.xserver.xkb.layout = "us"; + # services.xserver.xkb.options = "eurosign:e,caps:escape"; + + # Enable CUPS to print documents. + # services.printing.enable = true; + + # Enable sound. + # services.pulseaudio.enable = true; + # OR + # services.pipewire = { + # enable = true; + # pulse.enable = true; + # }; + + # Enable touchpad support (enabled default in most desktopManager). + # services.libinput.enable = true; + + # Define a user account. Don't forget to set a password with ‘passwd’. + # users.users.alice = { + # isNormalUser = true; + # extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. + # packages = with pkgs; [ + # tree + # ]; + # }; + + # programs.firefox.enable = true; + + nixpkgs.config.allowUnfree = true; + + # Packages that can be installed without any extra configuration + # See https://search.nixos.org/packages for all options + environment.systemPackages = with pkgs; [ + wget + ]; + + # Packages that need to be installed with some extra configuration + # See https://search.nixos.org/options for all options + programs = {}; + + # Some programs need SUID wrappers, can be configured further or are + # started in user sessions. + # programs.mtr.enable = true; + # programs.gnupg.agent = { + # enable = true; + # enableSSHSupport = true; + # }; + + # List services that you want to enable: + + # Enable the OpenSSH daemon. + # services.openssh.enable = true; + + # Open ports in the firewall. + # networking.firewall.allowedTCPPorts = [ ... ]; + # networking.firewall.allowedUDPPorts = [ ... ]; + # Or disable the firewall altogether. + # networking.firewall.enable = false; + + networking = { + networkmanager.enable = true; + useDHCP = lib.mkDefault true; + hostId = "7e35eb97"; # arbitrary id number generated via this command: `head -c4 /dev/urandom | od -A none -t x4` + hostName = "emergent"; # Define your hostname. + }; + + # Copy the NixOS configuration file and link it from the resulting system + # (/run/current-system/configuration.nix). This is useful in case you + # accidentally delete configuration.nix. + # system.copySystemConfiguration = true; + + # This option defines the first version of NixOS you have installed on this particular machine, + # and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions. + # + # Most users should NEVER change this value after the initial install, for any reason, + # even if you've upgraded your system to a new NixOS release. + # + # This value does NOT affect the Nixpkgs version your packages and OS are pulled from, + # so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how + # to actually do that. + # + # This value being lower than the current NixOS release does NOT mean your system is + # out of date, out of support, or vulnerable. + # + # Do NOT change this value unless you have manually inspected all the changes it would make to your configuration, + # and migrated your data accordingly. + # + # For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion . + system.stateVersion = "25.05"; # Did you read the comment? +} diff --git a/configurations/nixos/emergent/default.nix b/configurations/nixos/emergent/default.nix new file mode 100644 index 0000000..452334a --- /dev/null +++ b/configurations/nixos/emergent/default.nix @@ -0,0 +1,7 @@ +# evs desktop +{...}: { + imports = [ + ./configuration.nix + ./hardware-configuration.nix + ]; +} diff --git a/configurations/nixos/emergent/hardware-configuration.nix b/configurations/nixos/emergent/hardware-configuration.nix new file mode 100644 index 0000000..4e13149 --- /dev/null +++ b/configurations/nixos/emergent/hardware-configuration.nix @@ -0,0 +1,32 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: { + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod"]; + boot.initrd.kernelModules = []; + boot.kernelModules = []; + boot.extraModulePackages = []; + + swapDevices = []; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp42s0.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp4s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/configurations/nixos/emergent/nvidia-drivers.nix b/configurations/nixos/emergent/nvidia-drivers.nix new file mode 100644 index 0000000..fb66cf6 --- /dev/null +++ b/configurations/nixos/emergent/nvidia-drivers.nix @@ -0,0 +1,51 @@ +{ + config, + lib, + pkgs, + ... +}: { + # Enable OpenGL + hardware.graphics = { + enable = true; + }; + + # Load nvidia driver for Xorg and Wayland + services = { + xserver = { + # Load nvidia driver for Xorg and Wayland + videoDrivers = ["nvidia"]; + }; + # Use X instead of wayland + displayManager.gdm.wayland = false; + }; + + hardware.nvidia = { + # Modesetting is required. + modesetting.enable = true; + + # Nvidia power management. Experimental, and can cause sleep/suspend to fail. + # Enable this if you have graphical corruption issues or application crashes after waking + # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead + # of just the bare essentials. + powerManagement.enable = false; + + # Fine-grained power management. Turns off GPU when not in use. + # Experimental and only works on modern Nvidia GPUs (Turing or newer). + powerManagement.finegrained = false; + + # Use the NVidia open source kernel module (not to be confused with the + # independent third-party "nouveau" open source driver). + # Support is limited to the Turing and later architectures. Full list of + # supported GPUs is at: + # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus + # Only available from driver 515.43.04+ + open = true; + + # Enable the Nvidia settings menu, + # accessible via `nvidia-settings`. + nvidiaSettings = true; + + # Optionally, you may need to select the appropriate driver version for your specific GPU. + package = config.boot.kernelPackages.nvidiaPackages.stable; + }; +} diff --git a/configurations/nixos/horizon/configuration.nix b/configurations/nixos/horizon/configuration.nix new file mode 100644 index 0000000..42dcbb9 --- /dev/null +++ b/configurations/nixos/horizon/configuration.nix @@ -0,0 +1,147 @@ +{ + lib, + pkgs, + config, + inputs, + ... +}: { + imports = [ + inputs.nixos-hardware.nixosModules.framework-11th-gen-intel + ]; + + nixpkgs.config.allowUnfree = true; + + boot = { + initrd = { + availableKernelModules = ["usb_storage" "sd_mod"]; + }; + kernelModules = ["sg"]; + + # Bootloader. + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + }; + + host = { + users = { + leyla = { + isDesktopUser = true; + isTerminalUser = true; + isPrincipleUser = true; + }; + eve.isDesktopUser = true; + }; + + hardware = { + directAccess.enable = true; + }; + + ai = { + enable = true; + models = { + "Llama 3.1 8B" = { + model = "llama3.1:8b"; + roles = ["chat" "edit" "apply"]; + apiBase = "http://defiant:11434"; + }; + "Deepseek Coder:6.7B" = { + model = "deepseek-coder:6.7b"; + roles = ["chat" "edit" "apply"]; + apiBase = "http://defiant:11434"; + }; + "Deepseek Coder:33B" = { + model = "deepseek-coder:33b"; + roles = ["chat" "edit" "apply"]; + apiBase = "http://defiant:11434"; + }; + + "Deepseek r1:8B" = { + model = "deepseek-r1:8b"; + roles = ["chat"]; + apiBase = "http://defiant:11434"; + }; + + "Deepseek r1:32B" = { + model = "deepseek-r1:32b"; + roles = ["chat"]; + apiBase = "http://defiant:11434"; + }; + + "qwen2.5-coder:1.5b-base" = { + model = "qwen2.5-coder:1.5b-base"; + roles = ["autocomplete"]; + apiBase = "http://defiant:11434"; + }; + + "nomic-embed-text:latest" = { + model = "nomic-embed-text:latest"; + roles = ["embed"]; + apiBase = "http://defiant:11434"; + }; + }; + }; + }; + + environment.systemPackages = with pkgs; [ + cachefilesd + webtoon-dl + ]; + services.cachefilesd.enable = true; + + programs = { + adb.enable = true; + }; + + networking = { + networkmanager.enable = true; + hostName = "horizon"; # Define your hostname. + }; + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; + + hardware = { + graphics.enable = true; + }; + + sops.secrets = { + "vpn-keys/tailscale-authkey/horizon" = { + sopsFile = "${inputs.secrets}/vpn-keys.yaml"; + }; + }; + + services = { + # sudo fprintd-enroll + fprintd = { + enable = true; + }; + # firmware update tool + fwupd = { + enable = true; + }; + tailscale = { + enable = true; + authKeyFile = config.sops.secrets."vpn-keys/tailscale-authkey/horizon".path; + useRoutingFeatures = "client"; + }; + + syncthing.enable = true; + }; + + # Enable touchpad support (enabled default in most desktopManager). + # services.xserver.libinput.enable = true; + + # Open ports in the firewall. + # networking.firewall.allowedTCPPorts = [ ... ]; + # networking.firewall.allowedUDPPorts = [ ... ]; + # Or disable the firewall altogether. + # networking.firewall.enable = false; + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It's perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + # Before changing this value read the documentation for this option + # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). + system.stateVersion = "23.05"; # Did you read the comment? +} diff --git a/configurations/nixos/horizon/default.nix b/configurations/nixos/horizon/default.nix new file mode 100644 index 0000000..1263215 --- /dev/null +++ b/configurations/nixos/horizon/default.nix @@ -0,0 +1,7 @@ +# leyla laptop +{...}: { + imports = [ + ./configuration.nix + ./hardware-configuration.nix + ]; +} diff --git a/configurations/nixos/horizon/hardware-configuration.nix b/configurations/nixos/horizon/hardware-configuration.nix new file mode 100644 index 0000000..cec4914 --- /dev/null +++ b/configurations/nixos/horizon/hardware-configuration.nix @@ -0,0 +1,45 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + modulesPath, + ... +}: { + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = ["xhci_pci" "thunderbolt" "nvme"]; + boot.initrd.kernelModules = []; + boot.kernelModules = ["kvm-intel"]; + boot.extraModulePackages = []; + + fileSystems = { + "/" = { + device = "/dev/disk/by-uuid/866d422b-f816-4ad9-9846-791839cb9337"; + fsType = "ext4"; + }; + + "/boot" = { + device = "/dev/disk/by-uuid/E138-65B5"; + fsType = "vfat"; + }; + }; + + swapDevices = [ + {device = "/dev/disk/by-uuid/be98e952-a072-4c3a-8c12-69500b5a2fff";} + ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.tailscale0.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp170s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/configurations/nixos/twilight/configuration.nix b/configurations/nixos/twilight/configuration.nix new file mode 100644 index 0000000..111c002 --- /dev/null +++ b/configurations/nixos/twilight/configuration.nix @@ -0,0 +1,210 @@ +{ + inputs, + config, + pkgs, + ... +}: { + imports = [ + ./monitors.nix + ]; + + nixpkgs.config.allowUnfree = true; + + boot.initrd.availableKernelModules = ["usb_storage"]; + boot.kernelModules = ["sg"]; + + boot.loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + + sops.secrets = { + "vpn-keys/tailscale-authkey/twilight" = { + sopsFile = "${inputs.secrets}/vpn-keys.yaml"; + }; + }; + host = { + users = { + leyla = { + isDesktopUser = true; + isTerminalUser = true; + isPrincipleUser = true; + }; + eve.isDesktopUser = true; + }; + hardware = { + piperMouse.enable = true; + viaKeyboard.enable = true; + openRGB.enable = true; + graphicsAcceleration.enable = true; + directAccess.enable = true; + }; + ai = { + enable = true; + # TODO: benchmark twilight against defiant and prune this list of models that are faster on defiant + models = { + # conversation models + "Llama 3.1 8B" = { + model = "lamma3.1:8b"; + roles = ["chat" "edit" "apply"]; + }; + "deepseek-r1:8b" = { + model = "deepseek-r1:8b"; + roles = ["chat" "edit" "apply"]; + }; + "deepseek-r1:32b" = { + model = "deepseek-r1:32b"; + roles = ["chat" "edit" "apply"]; + }; + + # auto complete models + "qwen2.5-coder:1.5b-base" = { + model = "qwen2.5-coder:1.5b-base"; + roles = ["autocomplete"]; + }; + "qwen2.5-coder:7b" = { + model = "qwen2.5-coder:7b"; + roles = ["autocomplete"]; + }; + "deepseek-coder:6.7b" = { + model = "deepseek-coder:6.7b"; + roles = ["autocomplete"]; + }; + "deepseek-coder:33b" = { + model = "deepseek-coder:33b"; + roles = ["autocomplete"]; + }; + + # agent models + "qwen3:32b" = { + model = "qwen3:32b"; + roles = ["chat" "edit" "apply"]; + }; + + # embedding models + "nomic-embed-text:latest" = { + model = "nomic-embed-text:latest"; + roles = ["embed"]; + }; + }; + }; + }; + services = { + ollama = { + enable = true; + exposePort = true; + + loadModels = [ + # conversation models + "llama3.1:8b" + "deepseek-r1:8b" + "deepseek-r1:32b" + + # auto complete models + "qwen2.5-coder:1.5b-base" + "qwen2.5-coder:7b" + "deepseek-coder:6.7b" + "deepseek-coder:33b" + + # agent models + "qwen3:32b" + + # embedding models + "nomic-embed-text:latest" + ]; + }; + + tailscale = { + enable = true; + authKeyFile = config.sops.secrets."vpn-keys/tailscale-authkey/twilight".path; + useRoutingFeatures = "both"; + extraUpFlags = [ + "--advertise-exit-node" + "--advertise-routes=192.168.0.0/24" + ]; + extraSetFlags = [ + "--advertise-exit-node" + "--advertise-routes=192.168.0.0/24" + ]; + }; + + syncthing.enable = true; + }; + + boot.supportedFilesystems = ["nfs"]; + + fileSystems = { + "/mnt/leyla_documents" = { + device = "defiant:/exports/leyla_documents"; + fsType = "nfs"; + options = [ + "x-systemd.automount" + "noauto" + "user" + "noatime" + "nofail" + "soft" + "x-systemd.idle-timeout=600" + "fsc" + ]; + }; + + "/mnt/users_documents" = { + device = "defiant:/exports/users_documents"; + fsType = "nfs"; + options = [ + "x-systemd.automount" + "noauto" + "user" + "nofail" + "soft" + "x-systemd.idle-timeout=600" + "fsc" + ]; + }; + + "/mnt/media" = { + device = "defiant:/exports/media"; + fsType = "nfs"; + options = [ + "x-systemd.automount" + "noauto" + "user" + "noatime" + "nofail" + "soft" + "x-systemd.idle-timeout=600" + "noatime" + "nodiratime" + "relatime" + "rsize=32768" + "wsize=32768" + "fsc" + ]; + }; + }; + + environment.systemPackages = with pkgs; [ + cachefilesd + ]; + hardware.steam-hardware.enable = true; # Provides udev rules for controller, HTC vive, and Valve Index + + networking = { + networkmanager.enable = true; + hostName = "twilight"; # Define your hostname. + }; + + # enabled virtualisation for docker + # virtualisation.docker.enable = true; + + # Enable touchpad support (enabled default in most desktopManager). + # services.xserver.libinput.enable = true; + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It's perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + # Before changing this value read the documentation for this option + # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). + system.stateVersion = "23.05"; # Did you read the comment? +} diff --git a/configurations/nixos/twilight/default.nix b/configurations/nixos/twilight/default.nix new file mode 100644 index 0000000..43a9164 --- /dev/null +++ b/configurations/nixos/twilight/default.nix @@ -0,0 +1,8 @@ +# leyla desktop +{...}: { + imports = [ + ./configuration.nix + ./hardware-configuration.nix + ./nvidia-drivers.nix + ]; +} diff --git a/configurations/nixos/twilight/hardware-configuration.nix b/configurations/nixos/twilight/hardware-configuration.nix new file mode 100644 index 0000000..1389caf --- /dev/null +++ b/configurations/nixos/twilight/hardware-configuration.nix @@ -0,0 +1,42 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + modulesPath, + ... +}: { + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = ["nvme" "xhci_pci" "ahci" "usbhid" "sd_mod"]; + boot.initrd.kernelModules = []; + boot.kernelModules = ["kvm-amd"]; + boot.extraModulePackages = []; + + fileSystems = { + "/" = { + device = "/dev/disk/by-uuid/8be49c65-2b57-48f1-b74d-244d26061adb"; + fsType = "ext4"; + }; + + "/boot" = { + device = "/dev/disk/by-uuid/3006-3867"; + fsType = "vfat"; + options = ["fmask=0022" "dmask=0022"]; + }; + }; + + swapDevices = []; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/twilight/configuration.nix b/configurations/nixos/twilight/monitors.nix similarity index 85% rename from hosts/twilight/configuration.nix rename to configurations/nixos/twilight/monitors.nix index 6441e2a..1308f50 100644 --- a/hosts/twilight/configuration.nix +++ b/configurations/nixos/twilight/monitors.nix @@ -1,28 +1,4 @@ -# leyla laptop -{ - config, - pkgs, - inputs, - ... -}: { - imports = [ - inputs.home-manager.nixosModules.default - inputs.sops-nix.nixosModules.sops - - ./hardware-configuration.nix - - ../../enviroments/client - ]; - - users = { - leyla = { - isFullUser = true; - hasGPU = true; - }; - ester.isFullUser = true; - eve.isFullUser = true; - }; - +{pkgs, ...}: { systemd.tmpfiles.rules = [ "L+ /run/gdm/.config/monitors.xml - - - - ${pkgs.writeText "gdm-monitors.xml" '' @@ -220,18 +196,4 @@ ''}" ]; - - # enabled virtualisation for docker - # virtualisation.docker.enable = true; - - # Enable touchpad support (enabled default in most desktopManager). - # services.xserver.libinput.enable = true; - - # This value determines the NixOS release from which the default - # settings for stateful data, like file locations and database versions - # on your system were taken. It‘s perfectly fine and recommended to leave - # this value at the release version of the first install of this system. - # Before changing this value read the documentation for this option - # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). - system.stateVersion = "23.05"; # Did you read the comment? } diff --git a/configurations/nixos/twilight/nvidia-drivers.nix b/configurations/nixos/twilight/nvidia-drivers.nix new file mode 100644 index 0000000..47763f8 --- /dev/null +++ b/configurations/nixos/twilight/nvidia-drivers.nix @@ -0,0 +1,47 @@ +{config, ...}: { + services = { + xserver = { + # Load nvidia driver for Xorg and Wayland + videoDrivers = ["nvidia"]; + }; + # Use X instead of wayland for gaming reasons + displayManager.gdm.wayland = false; + }; + + hardware = { + # Enable OpenGL + graphics.enable = true; + + # install graphics drivers + nvidia = { + # Modesetting is required. + modesetting.enable = true; + + # Nvidia power management. Experimental, and can cause sleep/suspend to fail. + # Enable this if you have graphical corruption issues or application crashes after waking + # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead + # of just the bare essentials. + powerManagement.enable = false; + + # Fine-grained power management. Turns off GPU when not in use. + # Experimental and only works on modern Nvidia GPUs (Turing or newer). + powerManagement.finegrained = false; + + # Use the NVidia open source kernel module (not to be confused with the + # independent third-party "nouveau" open source driver). + # Support is limited to the Turing and later architectures. Full list of + # supported GPUs is at: + # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus + # Only available from driver 515.43.04+ + # Currently alpha-quality/buggy, so false is currently the recommended setting. + open = true; + + # Enable the Nvidia settings menu, + # accessible via `nvidia-settings`. + nvidiaSettings = true; + + # Optionally, you may need to select the appropriate driver version for your specific GPU. + package = config.boot.kernelPackages.nvidiaPackages.production; + }; + }; +} diff --git a/configurations/syncthing/default.nix b/configurations/syncthing/default.nix new file mode 100644 index 0000000..397f678 --- /dev/null +++ b/configurations/syncthing/default.nix @@ -0,0 +1,119 @@ +{config, ...}: { + folders = { + leyla_documents = { + id = "hvrj0-9bm1p"; + }; + leyla_calendar = { + id = "8oatl-1rv6w"; + }; + leyla_supernote_notes = { + id = "dwbuv-zffnf"; + }; + eve_records = { + id = "by6at-d4h9n"; + }; + share = { + id = "73ot0-cxmkx"; + }; + }; + devices = { + defiant = { + id = "3R6E6Y4-2F7MF2I-IGB4WE6-A3SQSMV-LIBYSAM-2OXHHU2-KJ6CGIV-QNMCPAR"; + folders = { + leyla_documents = { + folder = config.folders.leyla_documents; + path = "/mnt/sync/leyla/documents"; + }; + leyla_calendar = { + folder = config.folders.leyla_calendar; + path = "/mnt/sync/leyla/calendar"; + }; + leyla_supernote_notes = { + folder = config.folders.leyla_supernote_notes; + path = "/mnt/sync/leyla/notes"; + }; + eve_records = { + folder = config.folders.eve_records; + path = "/mnt/sync/eve/records"; + }; + share = { + folder = config.folders.share; + path = "/mnt/sync/default/share"; + }; + }; + }; + twilight = { + id = "UDIYL7V-OAZ2BI3-EJRAWFB-GZYVDWR-JNUYW3F-FFQ35MU-XBTGWEF-QD6K6QN"; + folders = { + leyla_documents = { + folder = config.folders.leyla_documents; + path = "/mnt/sync/leyla/documents"; + }; + share = { + folder = config.folders.share; + path = "/mnt/sync/default/share"; + }; + }; + }; + horizon = { + id = "OGPAEU6-5UR56VL-SP7YC4Y-IMVCRTO-XFD4CYN-Z6T5TZO-PFZNAT6-4MKWPQS"; + folders = { + leyla_documents = { + folder = config.folders.leyla_documents; + path = "/mnt/sync/leyla/documents"; + }; + share = { + folder = config.folders.share; + path = "/mnt/sync/default/share"; + }; + }; + }; + coven = { + id = "QGU7NN6-OMXTWVA-YCZ73S5-2O7ECTS-MUCTN4M-YH6WLEL-U4U577I-7PBNCA5"; + folders = { + leyla_documents = { + folder = config.folders.leyla_documents; + }; + share = { + folder = config.folders.share; + }; + }; + }; + ceder = { + id = "MGXUJBS-7AENXHB-7YQRNWG-QILKEJD-5462U2E-WAQW4R4-I2TVK5H-SMK6LAA"; + folders = { + share = { + folder = config.folders.share; + }; + leyla_documents = { + folder = config.folders.leyla_documents; + }; + leyla_calendar = { + folder = config.folders.leyla_calendar; + }; + leyla_notes = { + folder = config.folders.leyla_supernote_notes; + }; + }; + }; + emergent = { + id = "6MIDMKJ-7IFHXVX-FIR3YTB-KVE75LN-PA6IOTN-I257LWR-MMC4K6C-5H4SHQN"; + folders = { + eve_records = { + folder = config.folders.eve_records; + }; + share = { + folder = config.folders.share; + }; + }; + }; + shale = { + id = "AOAXEVD-QJ2IVRA-6G44Q7Q-TGUPXU2-FWWKOBH-DPKWC5N-LBAEHWJ-7EQF4AM"; + folders = { + share = { + folder = config.folders.share; + }; + }; + }; + }; +} diff --git a/const/sops_age_key_directory.nix b/const/sops_age_key_directory.nix new file mode 100644 index 0000000..cf948df --- /dev/null +++ b/const/sops_age_key_directory.nix @@ -0,0 +1 @@ +"/var/lib/sops-nix" diff --git a/enviroments/client/default.nix b/enviroments/client/default.nix deleted file mode 100644 index 86ff67b..0000000 --- a/enviroments/client/default.nix +++ /dev/null @@ -1,57 +0,0 @@ -{pkgs, ...}: { - imports = [ - ../common - ]; - - services = { - # Enable CUPS to print documents. - printing.enable = true; - - xserver = { - # Enable the X11 windowing system. - enable = true; - - # Enable the GNOME Desktop Environment. - displayManager.gdm.enable = true; - desktopManager = { - gnome.enable = true; - xterm.enable = false; - }; - - # Get rid of xTerm - excludePackages = [pkgs.xterm]; - - # Configure keymap in X11 - xkb = { - layout = "us,it,de"; - variant = ""; - }; - }; - - pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - # If you want to use JACK applications, uncomment this - #jack.enable = true; - - # use the example session manager (no others are packaged yet so this is enabled by default, - # no need to redefine it in your config for now) - #media-session.enable = true; - }; - }; - - # Enable sound with pipewire. - hardware.pulseaudio.enable = false; - security.rtkit.enable = true; - - environment.systemPackages = with pkgs; [ - # helvetica font - aileron - - cachefilesd - - gnomeExtensions.dash-to-dock - ]; -} diff --git a/enviroments/common/default.nix b/enviroments/common/default.nix deleted file mode 100644 index 0194ec1..0000000 --- a/enviroments/common/default.nix +++ /dev/null @@ -1,155 +0,0 @@ -{pkgs, ...}: { - imports = [ - ../../users - ]; - - nix = { - settings = { - experimental-features = ["nix-command" "flakes"]; - trusted-users = ["leyla"]; - }; - gc.automatic = true; - }; - - # Enable networking - networking.networkmanager.enable = true; - - # Set your time zone. - time.timeZone = "America/Chicago"; - - i18n.defaultLocale = "en_US.UTF-8"; - - i18n.extraLocaleSettings = { - LC_ADDRESS = "en_US.UTF-8"; - LC_IDENTIFICATION = "en_US.UTF-8"; - LC_MEASUREMENT = "en_US.UTF-8"; - LC_MONETARY = "en_US.UTF-8"; - LC_NAME = "en_US.UTF-8"; - LC_NUMERIC = "en_US.UTF-8"; - LC_PAPER = "en_US.UTF-8"; - LC_TELEPHONE = "en_US.UTF-8"; - LC_TIME = "en_US.UTF-8"; - }; - - users = { - users = { - leyla = { - uid = 1000; - description = "Leyla"; - group = "leyla"; - }; - - ester = { - uid = 1001; - description = "Ester"; - group = "ester"; - }; - - eve = { - uid = 1002; - description = "Eve"; - group = "eve"; - }; - - jellyfin = { - uid = 2000; - group = "jellyfin"; - isSystemUser = true; - }; - - forgejo = { - uid = 2002; - group = "forgejo"; - isSystemUser = true; - }; - - pihole = { - uid = 2003; - group = "pihole"; - isSystemUser = true; - }; - }; - - groups = { - leyla = { - gid = 1000; - members = ["lelya"]; - }; - - ester = { - gid = 1001; - members = ["ester"]; - }; - - eve = { - gid = 1002; - members = ["eve"]; - }; - - users = { - gid = 100; - members = ["leyla" "ester" "eve"]; - }; - - jellyfin = { - gid = 2000; - members = ["jellyfin" "leyla"]; - }; - - jellyfin_media = { - gid = 2001; - members = ["jellyfin" "leyla" "ester" "eve"]; - }; - - forgejo = { - gid = 2002; - members = ["forgejo" "leyla"]; - }; - - pihole = { - gid = 2003; - members = ["pihole" "leyla"]; - }; - }; - }; - - services = { - openssh = { - enable = true; - ports = [22]; - settings = { - PasswordAuthentication = false; - AllowUsers = ["leyla"]; # Allows all users by default. Can be [ "user1" "user2" ] - UseDns = true; - X11Forwarding = false; - }; - }; - }; - - environment.sessionVariables = rec { - SOPS_AGE_KEY_DIRECTORY = "/var/lib/sops-nix"; - SOPS_AGE_KEY_FILE = "${SOPS_AGE_KEY_DIRECTORY}/key.txt"; - }; - - sops = { - defaultSopsFormat = "yaml"; - gnupg.sshKeyPaths = []; - - age = { - keyFile = "/var/lib/sops-nix/key.txt"; - sshKeyPaths = []; - # generateKey = true; - }; - }; - # List packages installed in system profile. - environment.systemPackages = with pkgs; [ - wget - - # version control - git - - # system debuging tools - iputils - dnsutils - ]; -} diff --git a/enviroments/server/default.nix b/enviroments/server/default.nix deleted file mode 100644 index 6c18f29..0000000 --- a/enviroments/server/default.nix +++ /dev/null @@ -1,258 +0,0 @@ -{ - lib, - config, - pkgs, - ... -}: { - imports = [ - ../common - ]; - - options = { - domains = { - base_domain = lib.mkOption { - type = lib.types.str; - }; - headscale = { - subdomain = lib.mkOption { - type = lib.types.str; - description = "subdomain of base domain that headscale will be hosted at"; - default = "headscale"; - }; - }; - jellyfin = { - subdomain = lib.mkOption { - type = lib.types.str; - description = "subdomain of base domain that jellyfin will be hosted at"; - default = "jellyfin"; - }; - hostname = lib.mkOption { - type = lib.types.str; - description = "hosname that jellyfin will be hosted at"; - default = "${config.domains.jellyfin.subdomain}.${config.domains.base_domain}"; - }; - }; - forgejo = { - subdomain = lib.mkOption { - type = lib.types.str; - description = "subdomain of base domain that foregjo will be hosted at"; - default = "forgejo"; - }; - hostname = lib.mkOption { - type = lib.types.str; - description = "hosname that forgejo will be hosted at"; - default = "${config.domains.forgejo.subdomain}.${config.domains.base_domain}"; - }; - }; - }; - }; - - config = { - sops.secrets = { - "services/pi-hole" = { - sopsFile = ../../secrets/defiant-services.yaml; - }; - }; - - # Runtime - virtualisation.podman = { - enable = true; - autoPrune.enable = true; - dockerCompat = true; - defaultNetwork.settings = { - # Required for container networking to be able to use names. - dns_enabled = true; - }; - }; - virtualisation.oci-containers.backend = "podman"; - - virtualisation.oci-containers.containers.pihole = { - image = "pihole/pihole:2024.07.0"; - hostname = "pihole"; - volumes = [ - "/home/pihole:/etc/pihole:rw" # TODO; set this based on configs - "${config.sops.secrets."services/pi-hole".path}:/var/lib/pihole/webpassword.txt" - ]; - environment = { - TZ = config.time.timeZone; - WEBPASSWORD_FILE = "/var/lib/pihole/webpassword.txt"; - PIHOLE_UID = toString config.users.users.pihole.uid; - PIHOLE_GID = toString config.users.groups.pihole.gid; - }; - log-driver = "journald"; - extraOptions = [ - "--ip=192.168.1.201" # TODO: set this to some ip address from configs - "--network=macvlan" - ]; - }; - - systemd = { - tmpfiles.rules = [ - "d /home/jellyfin 755 jellyfin jellyfin -" - "d /home/jellyfin/media 775 jellyfin jellyfin_media -" - "d /home/jellyfin/config 750 jellyfin jellyfin -" - "d /home/jellyfin/cache 755 jellyfin jellyfin_media -" - "d /home/forgejo 750 forgejo forgejo -" - "d /home/forgejo/data 750 forgejo forgejo -" - "d /home/pihole 750 pihole pihole -" - ]; - - services = { - "podman-pihole" = { - serviceConfig = { - Restart = lib.mkOverride 500 "always"; - }; - after = [ - "podman-network-macvlan.service" - ]; - requires = [ - "podman-network-macvlan.service" - ]; - partOf = [ - "podman-compose-root.target" - ]; - wantedBy = [ - "podman-compose-root.target" - ]; - }; - - "podman-network-macvlan" = { - path = [ pkgs.podman ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStop = "podman network rm -f macvlan"; - }; - # TODO: check subnet against pi-hole ip address - # TODO: make lan configurable - # TODO: make parent interface configurable - script = '' - podman network inspect macvlan || podman network create --driver macvlan --subnet 192.168.1.0/24 --gateway 192.168.1.1 --opt parent=bond0 macvlan - ''; - partOf = [ "podman-compose-root.target" ]; - wantedBy = [ "podman-compose-root.target" ]; - }; - }; - - # disable computer sleeping - targets = { - sleep.enable = false; - suspend.enable = false; - hibernate.enable = false; - hybrid-sleep.enable = false; - - # Root service - # When started, this will automatically create all resources and start - # the containers. When stopped, this will teardown all resources. - "podman-compose-root" = { - unitConfig = { - Description = "Root target for podman targets."; - }; - wantedBy = [ "multi-user.target" ]; - }; - }; - }; - - services = { - # DNS stub needs to be disabled so pi hole can bind - # resolved.extraConfig = "DNSStubListener=no"; - - nfs.server = { - enable = true; - exports = '' - /home/leyla 192.168.1.0/22(rw,sync,no_subtree_check,crossmnt) - /home/eve 192.168.1.0/22(rw,sync,no_subtree_check,crossmnt) - /home/ester 192.168.1.0/22(rw,sync,no_subtree_check,crossmnt) - /home/users 192.168.1.0/22(rw,sync,no_subtree_check,crossmnt) - ''; - }; - - postgresql = { - enable = true; - ensureDatabases = ["forgejo"]; - identMap = '' - # ArbitraryMapName systemUser DBUser - superuser_map root postgres - superuser_map postgres postgres - superuser_map forgejo forgejo - ''; - # configuration here lets users access the db that matches their name and lets user postgres access everything - authentication = pkgs.lib.mkOverride 10 '' - # type database DBuser auth-method optional_ident_map - local sameuser all peer map=superuser_map - ''; - }; - - headscale = { - enable = true; - address = "0.0.0.0"; - port = 8080; - settings = { - server_url = "http://${config.domains.headscale.subdomain}.${config.domains.base_domain}"; - dns_config.base_domain = config.domains.base_domain; - logtail.enabled = false; - }; - }; - - jellyfin = { - enable = true; - user = "jellyfin"; - group = "jellyfin"; - dataDir = "/home/jellyfin/config"; # location on existing server: /home/docker/jellyfin/config - cacheDir = "/home/jellyfin/cache"; # location on existing server: /home/docker/jellyfin/cache - }; - - forgejo = { - enable = true; - database.type = "postgres"; - lfs.enable = true; - settings = { - server = { - DOMAIN = config.domains.forgejo.hostname; - HTTP_PORT = 8081; - }; - service.DISABLE_REGISTRATION = true; - }; - stateDir = "/home/forgejo/data"; - }; - - nginx = { - enable = false; # TODO: enable this when you want to test all the configs - virtualHosts = { - ${config.domains.headscale.hostname} = { - forceSSL = true; - enableACME = true; - locations."/" = { - proxyPass = "http://localhost:${toString config.services.headscale.port}"; - proxyWebsockets = true; - }; - }; - ${config.domains.jellyfin.hostname} = { - forceSSL = true; - enableACME = true; - locations."/".proxyPass = "http://localhost:8096"; - }; - ${config.domains.forgejo.hostname} = { - forceSSL = true; - enableACME = true; - locations."/".proxyPass = "http://localhost:${toString config.services.forgejo.settings.server.HTTP_PORT}"; - }; - }; - }; - }; - - security.acme = { - acceptTerms = true; - defaults.email = "jan-leila@protonmail.com"; - }; - - networking.firewall.allowedTCPPorts = [53 2049 3000 8081]; - - environment.systemPackages = [ - config.services.headscale.package - pkgs.jellyfin - pkgs.jellyfin-web - pkgs.jellyfin-ffmpeg - ]; - }; -} diff --git a/flake.lock b/flake.lock index a424800..a32ae84 100644 --- a/flake.lock +++ b/flake.lock @@ -7,11 +7,11 @@ ] }, "locked": { - "lastModified": 1726842196, - "narHash": "sha256-u9h03JQUuQJ607xmti9F9Eh6E96kKUAGP+aXWgwm70o=", + "lastModified": 1752113600, + "narHash": "sha256-7LYDxKxZgBQ8LZUuolAQ8UkIB+jb4A2UmiR+kzY9CLI=", "owner": "nix-community", "repo": "disko", - "rev": "51994df8ba24d5db5459ccf17b6494643301ad28", + "rev": "79264292b7e3482e5702932949de9cbb69fedf6d", "type": "github" }, "original": { @@ -20,14 +20,35 @@ "type": "github" } }, - "flake-compat": { - "flake": false, + "firefox-addons": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "dir": "pkgs/firefox-addons", + "lastModified": 1752379414, + "narHash": "sha256-0R3slhrjrnzyxR/fAYy5UliZvSgaVS38YCESBdH5RJw=", + "owner": "rycee", + "repo": "nur-expressions", + "rev": "51e77bb95540b7dd6c60f8fd65a0c472a2c9c3b7", + "type": "gitlab" + }, + "original": { + "dir": "pkgs/firefox-addons", + "owner": "rycee", + "repo": "nur-expressions", + "type": "gitlab" + } + }, + "flake-compat": { + "locked": { + "lastModified": 1747046372, + "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", "owner": "edolstra", "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", "type": "github" }, "original": { @@ -41,11 +62,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -54,6 +75,39 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "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": { "inputs": { "nixpkgs": [ @@ -61,11 +115,11 @@ ] }, "locked": { - "lastModified": 1726863345, - "narHash": "sha256-fjbKe1/UJpLT6tQLAKJ/djJFdnmAh2kkdsgmylyFrQA=", + "lastModified": 1752467539, + "narHash": "sha256-4kaR+xmng9YPASckfvIgl5flF/1nAZOplM+Wp9I5SMI=", "owner": "nix-community", "repo": "home-manager", - "rev": "dfe4d334b172071e7189d971ddecd3a7f811b48d", + "rev": "1e54837569e0b80797c47be4720fab19e0db1616", "type": "github" }, "original": { @@ -74,20 +128,110 @@ "type": "github" } }, - "nix-vscode-extensions": { + "impermanence": { + "locked": { + "lastModified": 1737831083, + "narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=", + "owner": "nix-community", + "repo": "impermanence", + "rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "impermanence", + "type": "github" + } + }, + "lix": { + "flake": false, + "locked": { + "lastModified": 1746827285, + "narHash": "sha256-hsFe4Tsqqg4l+FfQWphDtjC79WzNCZbEFhHI8j2KJzw=", + "rev": "47aad376c87e2e65967f17099277428e4b3f8e5a", + "type": "tarball", + "url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/47aad376c87e2e65967f17099277428e4b3f8e5a.tar.gz?rev=47aad376c87e2e65967f17099277428e4b3f8e5a" + }, + "original": { + "type": "tarball", + "url": "https://git.lix.systems/lix-project/lix/archive/2.93.0.tar.gz" + } + }, + "lix-module": { "inputs": { - "flake-compat": "flake-compat", "flake-utils": "flake-utils", + "flakey-profile": "flakey-profile", + "lix": "lix", "nixpkgs": [ "nixpkgs" ] }, "locked": { - "lastModified": 1726796602, - "narHash": "sha256-rYMcODISSljSETcqUUTMo++ZEa1CC6Xx6d3xuydishM=", + "lastModified": 1746838955, + "narHash": "sha256-11R4K3iAx4tLXjUs+hQ5K90JwDABD/XHhsM9nkeS5N8=", + "rev": "cd2a9c028df820a83ca2807dc6c6e7abc3dfa7fc", + "type": "tarball", + "url": "https://git.lix.systems/api/v1/repos/lix-project/nixos-module/archive/cd2a9c028df820a83ca2807dc6c6e7abc3dfa7fc.tar.gz?rev=cd2a9c028df820a83ca2807dc6c6e7abc3dfa7fc" + }, + "original": { + "type": "tarball", + "url": "https://git.lix.systems/lix-project/nixos-module/archive/2.93.0.tar.gz" + } + }, + "nix-darwin": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1751313918, + "narHash": "sha256-HsJM3XLa43WpG+665aGEh8iS8AfEwOIQWk3Mke3e7nk=", + "owner": "LnL7", + "repo": "nix-darwin", + "rev": "e04a388232d9a6ba56967ce5b53a8a6f713cdfcf", + "type": "github" + }, + "original": { + "owner": "LnL7", + "repo": "nix-darwin", + "type": "github" + } + }, + "nix-syncthing": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1741849924, + "narHash": "sha256-5vyb1H6HtW24QVqfI56P4QVQP6vHh1jS9ULwnunCO94=", + "ref": "main", + "rev": "86bcb200c83b6a5d13b3583126b9d8dc6770613a", + "revCount": 6, + "type": "git", + "url": "https://git.jan-leila.com/jan-leila/nix-syncthing" + }, + "original": { + "ref": "main", + "type": "git", + "url": "https://git.jan-leila.com/jan-leila/nix-syncthing" + } + }, + "nix-vscode-extensions": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1752459325, + "narHash": "sha256-46TgjdxT02a4nFd9HCXCf8kK5ZSH7r9gYROLtc8zVOg=", "owner": "nix-community", "repo": "nix-vscode-extensions", - "rev": "91dea80194080f017c6edf84fd94e33f6c12aec3", + "rev": "61c2e99ebd586f463a6c0ebe3d931e74883b163d", "type": "github" }, "original": { @@ -98,11 +242,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1726724509, - "narHash": "sha256-sVeAM1tgVi52S1e29fFBTPUAFSzgQwgLon3CrztXGm8=", + "lastModified": 1752048960, + "narHash": "sha256-gATnkOe37eeVwKKYCsL+OnS2gU4MmLuZFzzWCtaKLI8=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "10d5e0ecc32984c1bf1a9a46586be3451c42fd94", + "rev": "7ced9122cff2163c6a0212b8d1ec8c33a1660806", "type": "github" }, "original": { @@ -114,11 +258,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1726755586, - "narHash": "sha256-PmUr/2GQGvFTIJ6/Tvsins7Q43KTMvMFhvG6oaYK+Wk=", + "lastModified": 1751984180, + "narHash": "sha256-LwWRsENAZJKUdD3SpLluwDmdXY9F45ZEgCb0X+xgOL0=", "owner": "nixos", "repo": "nixpkgs", - "rev": "c04d5652cfa9742b1d519688f65d1bbccea9eb7e", + "rev": "9807714d6944a957c2e036f84b0ff8caf9930bc0", "type": "github" }, "original": { @@ -128,59 +272,52 @@ "type": "github" } }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1725762081, - "narHash": "sha256-vNv+aJUW5/YurRy1ocfvs4q/48yVESwlC/yHzjkZSP8=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "dc454045f5b5d814e5862a6d057e7bb5c29edc05", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "release-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1725534445, - "narHash": "sha256-Yd0FK9SkWy+ZPuNqUgmVPXokxDgMJoGuNpMEtkfcf84=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "9bb1e7571aadf31ddb4af77fc64b2d59580f9a39", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, "root": { "inputs": { "disko": "disko", + "firefox-addons": "firefox-addons", + "flake-compat": "flake-compat", "home-manager": "home-manager", + "impermanence": "impermanence", + "lix-module": "lix-module", + "nix-darwin": "nix-darwin", + "nix-syncthing": "nix-syncthing", "nix-vscode-extensions": "nix-vscode-extensions", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs", - "sops-nix": "sops-nix" + "secrets": "secrets", + "sops-nix": "sops-nix", + "steam-fetcher": "steam-fetcher" + } + }, + "secrets": { + "flake": false, + "locked": { + "lastModified": 1752531440, + "narHash": "sha256-04tQ3EUrtmZ7g6fVUkZC4AbAG+Z7lng79qU3jsiqWJY=", + "ref": "refs/heads/main", + "rev": "f016767c13aa36dde91503f7a9f01bdd02468045", + "revCount": 20, + "type": "git", + "url": "ssh://git@git.jan-leila.com/jan-leila/nix-config-secrets.git" + }, + "original": { + "type": "git", + "url": "ssh://git@git.jan-leila.com/jan-leila/nix-config-secrets.git" } }, "sops-nix": { "inputs": { - "nixpkgs": "nixpkgs_2", - "nixpkgs-stable": "nixpkgs-stable" + "nixpkgs": [ + "nixpkgs" + ] }, "locked": { - "lastModified": 1726524647, - "narHash": "sha256-qis6BtOOBBEAfUl7FMHqqTwRLB61OL5OFzIsOmRz2J4=", + "lastModified": 1751606940, + "narHash": "sha256-KrDPXobG7DFKTOteqdSVeL1bMVitDcy7otpVZWDE6MA=", "owner": "Mic92", "repo": "sops-nix", - "rev": "e2d404a7ea599a013189aa42947f66cede0645c8", + "rev": "3633fc4acf03f43b260244d94c71e9e14a2f6e0d", "type": "github" }, "original": { @@ -189,6 +326,26 @@ "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": { "locked": { "lastModified": 1681028828, @@ -203,6 +360,21 @@ "repo": "default", "type": "github" } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 70992b0..651a210 100644 --- a/flake.nix +++ b/flake.nix @@ -5,75 +5,176 @@ # base packages nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - # encrypt files that contain secreats that I would like to not encrypt - sops-nix.url = "github:Mic92/sops-nix"; + lix-module = { + url = "https://git.lix.systems/lix-project/nixos-module/archive/2.93.0.tar.gz"; + inputs.nixpkgs.follows = "nixpkgs"; + }; - # declairtive disk configuration + # secret encryption + sops-nix = { + url = "github:Mic92/sops-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # self hosted repo of secrets file to further protect files in case of future encryption vulnerabilities + secrets = { + url = "git+ssh://git@git.jan-leila.com/jan-leila/nix-config-secrets.git"; + flake = false; + }; + + # common config for syncthing + nix-syncthing = { + url = "git+https://git.jan-leila.com/jan-leila/nix-syncthing?ref=main"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # disk configurations disko = { url = "github:nix-community/disko"; inputs.nixpkgs.follows = "nixpkgs"; }; - # managment per user + # delete your darlings + impermanence = { + url = "github:nix-community/impermanence"; + }; + + nix-darwin = { + url = "github:LnL7/nix-darwin"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # users home directories home-manager = { url = "github:nix-community/home-manager"; inputs.nixpkgs.follows = "nixpkgs"; }; - # repo of hardware configs for prebuilt systems - nixos-hardware.url = "github:NixOS/nixos-hardware/master"; + # firefox extensions + firefox-addons = { + url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons"; + inputs.nixpkgs.follows = "nixpkgs"; + }; # vscode extensions nix-vscode-extensions = { url = "github:nix-community/nix-vscode-extensions"; inputs.nixpkgs.follows = "nixpkgs"; }; + + # pregenerated hardware configurations + nixos-hardware = { + url = "github:NixOS/nixos-hardware/master"; + }; + + # this is just here so that we have a lock on it for our dev shells + flake-compat = { + url = "github:edolstra/flake-compat"; + }; + + steam-fetcher = { + url = "github:nix-community/steam-fetcher"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = { self, nixpkgs, - disko, - nixos-hardware, + sops-nix, + nix-syncthing, + home-manager, + impermanence, ... } @ inputs: let - forEachSystem = nixpkgs.lib.genAttrs [ - "aarch64-darwin" - "aarch64-linux" - "x86_64-darwin" - "x86_64-linux" - ]; - forEachPkgs = lambda: forEachSystem (system: lambda nixpkgs.legacyPackages.${system}); - in { - packages = forEachPkgs (pkgs: import ./pkgs {inherit pkgs;}); + util = import ./util {inherit inputs;}; + forEachPkgs = util.forEachPkgs; - nixosConfigurations = { - # Leyla Laptop - horizon = nixpkgs.lib.nixosSystem { - specialArgs = {inherit inputs;}; - modules = [ - ./hosts/horizon/configuration.nix - inputs.home-manager.nixosModules.default - nixos-hardware.nixosModules.framework-11th-gen-intel - ]; - }; - # Leyla Desktop - twilight = nixpkgs.lib.nixosSystem { - specialArgs = {inherit inputs;}; - modules = [ - ./hosts/twilight/configuration.nix - inputs.home-manager.nixosModules.default - ]; - }; - # NAS Service - defiant = nixpkgs.lib.nixosSystem { - specialArgs = {inherit inputs;}; - modules = [ - disko.nixosModules.disko - ./hosts/defiant/disko-config.nix - ./hosts/defiant/configuration.nix - ]; - }; + mkNixosInstaller = util.mkNixosInstaller; + mkNixosSystem = util.mkNixosSystem; + mkDarwinSystem = util.mkDarwinSystem; + mkHome = util.mkHome; + syncthingConfiguration = util.syncthingConfiguration; + + installerSystems = { + basic = mkNixosInstaller "basic" []; }; + + nixosSystems = { + horizon = mkNixosSystem "horizon"; + twilight = mkNixosSystem "twilight"; + defiant = mkNixosSystem "defiant"; + emergent = mkNixosSystem "emergent"; + }; + + darwinSystems = { + hesperium = mkDarwinSystem "hesperium"; + }; + + homeSystems = { + # stand alone home manager configurations here: + # name = mkHome "name" + }; + + systemsHomes = nixpkgs.lib.attrsets.mergeAttrsList ( + nixpkgs.lib.attrsets.mapAttrsToList (hostname: system: ( + nixpkgs.lib.attrsets.mapAttrs' (user: _: { + name = "${user}@${hostname}"; + value = mkHome { + user = user; + host = hostname; + system = system.pkgs.hostPlatform.system; + osConfig = system.config; + }; + }) + system.config.home-manager.users + )) + (nixosSystems // darwinSystems) + ); + + homeConfigurations = + systemsHomes + // homeSystems; + in { + formatter = forEachPkgs (system: pkgs: pkgs.alejandra); + + # templates = import ./templates; + + devShells = forEachPkgs (system: pkgs: { + default = pkgs.mkShell { + packages = with pkgs; [ + # for version controlling this repo + git + # for formatting code in this repo + alejandra + # for editing secrets in the secrets repo + sops + # for viewing configuration options defined in this repo + nix-inspect + # for installing flakes from this repo onto other systems + nixos-anywhere + # for updating disko configurations + disko + # for viewing dconf entries + dconf-editor + ]; + + SOPS_AGE_KEY_DIRECTORY = import ./const/sops_age_key_directory.nix; + + shellHook = '' + git config core.hooksPath .hooks + ''; + }; + }); + + installerConfigurations = installerSystems; + + nixosConfigurations = nixosSystems; + + darwinConfigurations = darwinSystems; + + homeConfigurations = homeConfigurations; + + syncthingConfiguration = syncthingConfiguration; }; } diff --git a/hosts/defiant/configuration.nix b/hosts/defiant/configuration.nix deleted file mode 100644 index ec5cf1d..0000000 --- a/hosts/defiant/configuration.nix +++ /dev/null @@ -1,65 +0,0 @@ -# server nas -{ - config, - pkgs, - inputs, - ... -}: { - imports = [ - inputs.home-manager.nixosModules.default - inputs.sops-nix.nixosModules.sops - - ./hardware-configuration.nix - - ../../enviroments/server - ]; - - users.leyla.isThinUser = true; - - boot.loader.grub = { - enable = true; - zfsSupport = true; - efiSupport = true; - efiInstallAsRemovable = true; - }; - - domains = { - base_domain = "jan-leila.com"; - headscale.subdomain = "vpn"; - jellyfin.subdomain = "media"; - forgejo.subdomain = "git"; - }; - - services = { - zfs = { - autoScrub.enable = true; - autoSnapshot.enable = true; - }; - - # temp enable desktop enviroment for setup - # Enable the X11 windowing system. - xserver = { - enable = true; - - # Enable the GNOME Desktop Environment. - displayManager = { - gdm.enable = true; - }; - desktopManager = { - gnome.enable = true; - xterm.enable = false; - }; - - # Get rid of xTerm - excludePackages = [pkgs.xterm]; - }; - }; - - # This value determines the NixOS release from which the default - # settings for stateful data, like file locations and database versions - # on your system were taken. It‘s perfectly fine and recommended to leave - # this value at the release version of the first install of this system. - # Before changing this value read the documentation for this option - # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). - system.stateVersion = "23.05"; # Did you read the comment? -} diff --git a/hosts/defiant/disko-config.nix b/hosts/defiant/disko-config.nix deleted file mode 100644 index a913aeb..0000000 --- a/hosts/defiant/disko-config.nix +++ /dev/null @@ -1,136 +0,0 @@ -{lib, ...}: let - bootDisk = devicePath: { - type = "disk"; - device = devicePath; - content = { - type = "gpt"; - - partitions = { - boot = { - size = "1M"; - type = "EF02"; # for grub MBR - }; - ESP = { - size = "1G"; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - }; - }; - }; - }; - }; - zfsDisk = devicePath: { - type = "disk"; - device = devicePath; - content = { - type = "gpt"; - partitions = { - zfs = { - size = "100%"; - content = { - type = "zfs"; - pool = "zroot"; - }; - }; - }; - }; - }; - cacheDisk = devicePath: swapSize: { - type = "disk"; - device = devicePath; - content = { - type = "gpt"; - partitions = { - encryptedSwap = { - size = swapSize; - content = { - type = "swap"; - randomEncryption = true; - discardPolicy = "both"; - resumeDevice = true; - }; - }; - zfs = { - size = "100%"; - content = { - type = "zfs"; - pool = "zroot"; - }; - }; - }; - }; - }; -in { - disko.devices = { - disk = { - boot = bootDisk "/dev/disk/by-path/pci-0000:23:00.3-usb-0:1:1.0-scsi-0:0:0:0"; - - hd_13_tb_a = zfsDisk "/dev/disk/by-id/ata-ST18000NE000-3G6101_ZVTCXVEB"; - hd_13_tb_b = zfsDisk "/dev/disk/by-id/ata-ST18000NE000-3G6101_ZVTCXWSC"; - hd_13_tb_c = zfsDisk "/dev/disk/by-id/ata-ST18000NE000-3G6101_ZVTD10EH"; - - # ssd_2_tb_a = cacheDisk "64G" "/dev/disk/by-id/XXX"; - }; - zpool = { - zroot = { - type = "zpool"; - mode = { - topology = { - type = "topology"; - vdev = [ - { - # should this only mirror for this inital config with 3 drives we will used raidz2 for future configs??? - mode = "mirror"; - members = [ - "hd_13_tb_a" - "hd_13_tb_b" - "hd_13_tb_c" - ]; - } - ]; - cache = []; - # cache = [ "ssd_2_tb_a" ]; - }; - }; - - options = { - ashift = "12"; - }; - - rootFsOptions = { - encryption = "on"; - keyformat = "hex"; - keylocation = "prompt"; - compression = "lz4"; - xattr = "sa"; - acltype = "posixacl"; - "com.sun:auto-snapshot" = "false"; - }; - - mountpoint = "/"; - postCreateHook = "zfs list -t snapshot -H -o name | grep -E '^zroot@blank$' || zfs snapshot zroot@blank"; - - datasets = { - "nix" = { - type = "zfs_fs"; - mountpoint = "/nix"; - }; - "home" = { - type = "zfs_fs"; - mountpoint = "/mnt/home"; - options = { - "com.sun:auto-snapshot" = "true"; - }; - }; - "var" = { - type = "zfs_fs"; - mountpoint = "/var"; - }; - }; - }; - }; - }; -} diff --git a/hosts/hardware-common.nix b/hosts/hardware-common.nix deleted file mode 100644 index 920d609..0000000 --- a/hosts/hardware-common.nix +++ /dev/null @@ -1,15 +0,0 @@ -{lib, ...}: { - options = { - hardware = { - piperMouse = { - enable = lib.mkEnableOption "host has a piper mouse"; - }; - viaKeyboard = { - enable = lib.mkEnableOption "host has a via keyboard"; - }; - openRGB = { - enable = lib.mkEnableOption "host has open rgb hardware"; - }; - }; - }; -} diff --git a/hosts/horizon/configuration.nix b/hosts/horizon/configuration.nix deleted file mode 100644 index c83fcc6..0000000 --- a/hosts/horizon/configuration.nix +++ /dev/null @@ -1,49 +0,0 @@ -# leyla laptop -{ - config, - pkgs, - inputs, - ... -}: { - imports = [ - inputs.home-manager.nixosModules.default - inputs.sops-nix.nixosModules.sops - - ./hardware-configuration.nix - - ../../enviroments/client - ]; - - users = { - leyla.isFullUser = true; - ester.isFullUser = true; - eve.isFullUser = true; - }; - - # enabled virtualisation for docker - virtualisation.docker = { - enable = true; - rootless = { - enable = true; - setSocketVariable = true; - }; - }; - users.extraGroups.docker.members = ["leyla"]; - - # Enable touchpad support (enabled default in most desktopManager). - # services.xserver.libinput.enable = true; - - # Open ports in the firewall. - # networking.firewall.allowedTCPPorts = [ ... ]; - # networking.firewall.allowedUDPPorts = [ ... ]; - # Or disable the firewall altogether. - # networking.firewall.enable = false; - - # This value determines the NixOS release from which the default - # settings for stateful data, like file locations and database versions - # on your system were taken. It‘s perfectly fine and recommended to leave - # this value at the release version of the first install of this system. - # Before changing this value read the documentation for this option - # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). - system.stateVersion = "23.05"; # Did you read the comment? -} diff --git a/hosts/horizon/hardware-configuration.nix b/hosts/horizon/hardware-configuration.nix deleted file mode 100644 index 1e203f3..0000000 --- a/hosts/horizon/hardware-configuration.nix +++ /dev/null @@ -1,106 +0,0 @@ -# Do not modify this file! It was generated by ‘nixos-generate-config’ -# and may be overwritten by future invocations. Please make changes -# to /etc/nixos/configuration.nix instead. -{ - config, - lib, - pkgs, - modulesPath, - ... -}: { - imports = [ - (modulesPath + "/installer/scan/not-detected.nix") - ../hardware-common.nix - ]; - - boot = { - initrd = { - availableKernelModules = ["xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod"]; - kernelModules = []; - }; - kernelModules = ["kvm-intel" "sg"]; - extraModulePackages = []; - - # Bootloader. - loader = { - systemd-boot.enable = true; - efi.canTouchEfiVariables = true; - }; - }; - - fileSystems = { - "/" = { - device = "/dev/disk/by-uuid/866d422b-f816-4ad9-9846-791839cb9337"; - fsType = "ext4"; - }; - - "/boot" = { - device = "/dev/disk/by-uuid/E138-65B5"; - fsType = "vfat"; - }; - - "/mnt/leyla_home" = { - device = "defiant:/home/leyla"; - fsType = "nfs"; - options = ["x-systemd.automount" "user" "noatime" "nofail" "soft" "x-systemd.idle-timeout=600" "fsc"]; - }; - - "/mnt/eve_home" = { - device = "defiant:/home/eve"; - fsType = "nfs"; - options = ["x-systemd.automount" "user" "nofail" "soft" "x-systemd.idle-timeout=600" "fsc"]; - }; - - "/mnt/ester_home" = { - device = "defiant:/home/ester"; - fsType = "nfs"; - options = ["x-systemd.automount" "user" "nofail" "soft" "x-systemd.idle-timeout=600" "fsc"]; - }; - - "/mnt/users_home" = { - device = "defiant:/home/users"; - fsType = "nfs"; - options = ["x-systemd.automount" "user" "nofail" "soft" "x-systemd.idle-timeout=600" "fsc"]; - }; - - # "/mnt/legacy_leyla_home" = - # { - # device = "server.arpa:/home/leyla"; - # fsType = "nfs"; - # options = [ "x-systemd.automount" "user" "nofail" "soft" "x-systemd.idle-timeout=600" "fsc" ]; - # }; - - # "/mnt/legacy_share_home" = - # { - # device = "server.arpa:/home/share"; - # fsType = "nfs"; - # options = [ "x-systemd.automount" "user" "nofail" "soft" "x-systemd.idle-timeout=600" "fsc" ]; - # }; - - # "/mnt/legacy_docker_home" = - # { - # device = "server.arpa:/home/docker"; - # fsType = "nfs"; - # options = [ "x-systemd.automount" "noauto" "x-systemd.idle-timeout=600" ]; - # }; - }; - - services.cachefilesd.enable = true; - - swapDevices = [ - {device = "/dev/disk/by-uuid/be98e952-a072-4c3a-8c12-69500b5a2fff";} - ]; - - networking = { - useDHCP = lib.mkDefault true; - hostName = "horizon"; # Define your hostname. - }; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; - - hardware = { - graphics.enable = true; - cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; - }; -} diff --git a/hosts/twilight/hardware-configuration.nix b/hosts/twilight/hardware-configuration.nix deleted file mode 100644 index b2f11ee..0000000 --- a/hosts/twilight/hardware-configuration.nix +++ /dev/null @@ -1,125 +0,0 @@ -# Do not modify this file! It was generated by ‘nixos-generate-config’ -# and may be overwritten by future invocations. Please make changes -# to /etc/nixos/configuration.nix instead. -{ - config, - lib, - pkgs, - modulesPath, - ... -}: { - imports = [ - (modulesPath + "/installer/scan/not-detected.nix") - ../hardware-common.nix - ]; - - boot = { - initrd = { - availableKernelModules = ["nvme" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod"]; - kernelModules = []; - }; - kernelModules = ["kvm-amd" "sg"]; - extraModulePackages = []; - - # Bootloader. - loader = { - systemd-boot.enable = true; - efi.canTouchEfiVariables = true; - }; - }; - - services.xserver = { - # Load nvidia driver for Xorg and Wayland - videoDrivers = ["nvidia"]; - - # Use X instead of wayland for gaming reasons - displayManager.gdm.wayland = false; - }; - - fileSystems = { - "/" = { - device = "/dev/disk/by-uuid/8be49c65-2b57-48f1-b74d-244d26061adb"; - fsType = "ext4"; - }; - - "/boot" = { - device = "/dev/disk/by-uuid/3006-3867"; - fsType = "vfat"; - options = ["fmask=0022" "dmask=0022"]; - }; - - "/mnt/leyla_home" = { - device = "server.arpa:/home/leyla"; - fsType = "nfs"; - options = ["x-systemd.automount" "user" "nofail" "soft" "x-systemd.idle-timeout=600" "fsc"]; - }; - - "/mnt/share_home" = { - device = "server.arpa:/home/share"; - fsType = "nfs"; - options = ["x-systemd.automount" "user" "nofail" "soft" "x-systemd.idle-timeout=600" "fsc"]; - }; - - "/mnt/docker_home" = { - device = "server.arpa:/home/docker"; - fsType = "nfs"; - options = ["x-systemd.automount" "noauto" "x-systemd.idle-timeout=600"]; - }; - }; - - swapDevices = []; - - networking = { - # Enables DHCP on each ethernet and wireless interface. In case of scripted networking - # (the default) this is the recommended approach. When using systemd-networkd it's - # still possible to use this option, but it's recommended to use it in conjunction - # with explicit per-interface declarations with `networking.interfaces..useDHCP`. - useDHCP = lib.mkDefault true; - hostName = "twilight"; # Define your hostname. - }; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - - hardware = { - piperMouse.enable = true; - viaKeyboard.enable = true; - openRGB.enable = true; - - # Enable OpenGL - graphics.enable = true; - - # install graphics drivers - nvidia = { - # Modesetting is required. - modesetting.enable = true; - - # Nvidia power management. Experimental, and can cause sleep/suspend to fail. - # Enable this if you have graphical corruption issues or application crashes after waking - # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead - # of just the bare essentials. - powerManagement.enable = false; - - # Fine-grained power management. Turns off GPU when not in use. - # Experimental and only works on modern Nvidia GPUs (Turing or newer). - powerManagement.finegrained = false; - - # Use the NVidia open source kernel module (not to be confused with the - # independent third-party "nouveau" open source driver). - # Support is limited to the Turing and later architectures. Full list of - # supported GPUs is at: - # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus - # Only available from driver 515.43.04+ - # Currently alpha-quality/buggy, so false is currently the recommended setting. - open = false; - - # Enable the Nvidia settings menu, - # accessible via `nvidia-settings`. - nvidiaSettings = true; - - # Optionally, you may need to select the appropriate driver version for your specific GPU. - package = config.boot.kernelPackages.nvidiaPackages.production; - }; - - cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; - }; -} diff --git a/install.sh b/install.sh index 882a935..c77d748 100755 --- a/install.sh +++ b/install.sh @@ -39,6 +39,7 @@ if [ -z ${flake} ]; then exit 1; fi +# TODO: we might not need to copy the key over here anymore? temp=$(mktemp -d) # Function to cleanup temporary directory on exit cleanup() { @@ -51,4 +52,4 @@ mkdir -p $temp$SOPS_AGE_KEY_DIRECTORY cp -r $SOPS_AGE_KEY_DIRECTORY/* $temp$SOPS_AGE_KEY_DIRECTORY # commit number in this is because the main branch of nixos-anywhere is broken right now -nix run github:nix-community/nixos-anywhere/b3b6bfebba35d55fba485ceda588984dec74c54f -- --extra-files $temp --flake ".#$flake" ${user:-nixos}@$target +nixos-anywhere --extra-files $temp --flake ".#$flake" ${user:-nixos}@$target diff --git a/lint.sh b/lint.sh deleted file mode 100755 index 3fc29e9..0000000 --- a/lint.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -nix run git+https://github.com/kamadorueda/alejandra -- -q . diff --git a/modules/common-modules/default.nix b/modules/common-modules/default.nix new file mode 100644 index 0000000..3dd1923 --- /dev/null +++ b/modules/common-modules/default.nix @@ -0,0 +1,7 @@ +# this folder is for modules that are common between nixos, home-manager, and darwin +{...}: { + imports = [ + ./overlays + ./pkgs + ]; +} diff --git a/modules/common-modules/overlays/default.nix b/modules/common-modules/overlays/default.nix new file mode 100644 index 0000000..465e83f --- /dev/null +++ b/modules/common-modules/overlays/default.nix @@ -0,0 +1,7 @@ +# this folder is for derivation overlays +{inputs, ...}: { + nixpkgs.overlays = [ + inputs.steam-fetcher.overlays.default + inputs.nix-vscode-extensions.overlays.default + ]; +} diff --git a/modules/common-modules/pkgs/default.nix b/modules/common-modules/pkgs/default.nix new file mode 100644 index 0000000..e955354 --- /dev/null +++ b/modules/common-modules/pkgs/default.nix @@ -0,0 +1,23 @@ +{pkgs, ...}: { + nixpkgs.overlays = [ + (final: prev: { + webtoon-dl = + pkgs.callPackage + ./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: { + prostudiomasters = + pkgs.callPackage + ./prostudiomasters.nix + {}; + }) + (final: prev: { + noita_entangled_worlds = pkgs.callPackage ./noita-entangled-worlds.nix {}; + }) + (final: prev: { + gdx-liftoff = pkgs.callPackage ./gdx-liftoff.nix {}; + }) + ]; +} diff --git a/modules/common-modules/pkgs/gdx-liftoff.nix b/modules/common-modules/pkgs/gdx-liftoff.nix new file mode 100644 index 0000000..d2e9424 --- /dev/null +++ b/modules/common-modules/pkgs/gdx-liftoff.nix @@ -0,0 +1,44 @@ +{ + stdenv, + fetchurl, + makeWrapper, + jdk, + lib, + xorg, + libGL, + ... +}: +stdenv.mkDerivation rec { + pname = "gdx-liftoff"; + version = "1.13.5.1"; + + src = fetchurl { + url = "https://github.com/libgdx/gdx-liftoff/releases/download/v${version}/gdx-liftoff-${version}.jar"; + hash = "sha256-9vCXGNGwI/P4VmcdIzTv2GPAX8bZb7nkfopaRAf6yMA="; + }; + + dontUnpack = true; + + nativeBuildInputs = [makeWrapper]; + + runtimeDependencies = lib.makeLibraryPath [ + # glfw + libGL + xorg.libX11 + xorg.libXcursor + xorg.libXext + xorg.libXrandr + xorg.libXxf86vm + ]; + + installPhase = '' + runHook preInstall + + install -Dm644 $src $out/lib/gdx-liftoff-${version}.jar + + makeWrapper ${lib.getExe jdk} $out/bin/gdx-liftoff-${version} \ + --append-flags "-jar $out/lib/gdx-liftoff-${version}.jar"\ + ${lib.optionalString stdenv.hostPlatform.isLinux "--prefix LD_LIBRARY_PATH : ${runtimeDependencies}"} + runHook postInstall + ''; +} diff --git a/modules/common-modules/pkgs/noita-entangled-worlds.nix b/modules/common-modules/pkgs/noita-entangled-worlds.nix new file mode 100644 index 0000000..322ce41 --- /dev/null +++ b/modules/common-modules/pkgs/noita-entangled-worlds.nix @@ -0,0 +1,46 @@ +# not working yet +{ + pkgs, + rustPlatform, + fetchFromGitHub, + ... +}: let + version = "1.5.3"; + repo = fetchFromGitHub { + owner = "IntQuant"; + repo = "noita_entangled_worlds"; + rev = "v${version}"; + hash = "sha256-frrpD0aWTeDbZYtp15R+quUUAZf7OvHlbSLtGJJtAqk="; + }; +in + rustPlatform.buildRustPackage { + name = "noita-proxy-${version}"; + src = repo + "/noita-proxy"; + prePatch = '' + substituteInPlace Cargo.toml \ + --replace "path = \"../shared\"" "path = \"${repo + "/shared"}\"" + ''; + nativeBuildInputs = with pkgs; [ + pkg-config + python3 + cmake + ]; + buildInputs = with pkgs; [ + openssl + openssl.dev + libpulseaudio + libjack2 + alsa-lib + xorg.libxcb + xorg.libxcb.dev + libopus + ]; + propagatedBuildInputs = with pkgs; [ + steamworks-sdk-redist + ]; + runtimeDependencies = with pkgs; [ + steamworks-sdk-redist + ]; + doCheck = false; + cargoHash = "sha256-TzUS6d6PopgGf2i1yVaXaXdzNrvfSz+Gv67BAtxYmb4="; + } diff --git a/modules/common-modules/pkgs/prostudiomasters.nix b/modules/common-modules/pkgs/prostudiomasters.nix new file mode 100644 index 0000000..c1c03fe --- /dev/null +++ b/modules/common-modules/pkgs/prostudiomasters.nix @@ -0,0 +1,14 @@ +{ + fetchurl, + appimageTools, +}: let + pname = "prostudiomasters"; + version = "2.5.6"; + src = fetchurl { + url = "https://download.prostudiomasters.com/linux/ProStudioMasters-${version}.AppImage"; + hash = "sha256-7owOwdcucFfl+JsVj+Seau2KOz0J4P/ep7WrBSNSmbs="; + }; +in + appimageTools.wrapType2 { + inherit pname version src; + } diff --git a/modules/common-modules/pkgs/webtoon-dl.nix b/modules/common-modules/pkgs/webtoon-dl.nix new file mode 100644 index 0000000..4341098 --- /dev/null +++ b/modules/common-modules/pkgs/webtoon-dl.nix @@ -0,0 +1,18 @@ +{ + buildGoModule, + fetchFromGitHub, + ... +}: +buildGoModule rec { + pname = "webtoon-dl"; + version = "0.0.10"; + + src = fetchFromGitHub { + owner = "robinovitch61"; + repo = "webtoon-dl"; + rev = "v${version}"; + hash = "sha256-geVb3LFPZxPQYARZnaqOr5sgaN6mqkEX5ZiLvg8mF5k="; + }; + + vendorHash = "sha256-NTqUygJ6b6kTnLUnJqxCo/URzaRouPLACEPi2Ob1s9w="; +} diff --git a/modules/darwin-modules/default.nix b/modules/darwin-modules/default.nix new file mode 100644 index 0000000..5f4447b --- /dev/null +++ b/modules/darwin-modules/default.nix @@ -0,0 +1,8 @@ +# this folder container modules that are for darwin only +{...}: { + imports = [ + ./home-manager + ./users.nix + ./system.nix + ]; +} diff --git a/modules/darwin-modules/home-manager/default.nix b/modules/darwin-modules/home-manager/default.nix new file mode 100644 index 0000000..1ebec5f --- /dev/null +++ b/modules/darwin-modules/home-manager/default.nix @@ -0,0 +1,2 @@ +# modules in this folder are to adapt home-manager modules configs to darwin-module configs +{...}: {} diff --git a/modules/darwin-modules/system.nix b/modules/darwin-modules/system.nix new file mode 100644 index 0000000..ee56162 --- /dev/null +++ b/modules/darwin-modules/system.nix @@ -0,0 +1,27 @@ +{self, ...}: { + system.configurationRevision = self.rev or self.dirtyRev or null; + + nix = { + gc = { + automatic = true; + interval = [ + { + Hour = 4; + Minute = 15; + Weekday = 7; + } + ]; + options = "--delete-older-than 7d"; + }; + optimise = { + automatic = true; + interval = [ + { + Hour = 4; + Minute = 15; + Weekday = 7; + } + ]; + }; + }; +} diff --git a/modules/darwin-modules/users.nix b/modules/darwin-modules/users.nix new file mode 100644 index 0000000..72fd1b1 --- /dev/null +++ b/modules/darwin-modules/users.nix @@ -0,0 +1,16 @@ +{ + lib, + config, + ... +}: let + host = config.host; +in { + users = { + users = { + leyla = { + name = lib.mkForce host.users.leyla.name; + home = lib.mkForce "/home/${host.users.leyla.name}"; + }; + }; + }; +} diff --git a/modules/home-manager-modules/default.nix b/modules/home-manager-modules/default.nix new file mode 100644 index 0000000..4c085a5 --- /dev/null +++ b/modules/home-manager-modules/default.nix @@ -0,0 +1,12 @@ +# this folder container modules that are for home manager only +{...}: { + imports = [ + ./sops.nix + ./user.nix + ./flipperzero.nix + ./i18n.nix + ./openssh.nix + ./gnome.nix + ./programs + ]; +} diff --git a/modules/home-manager-modules/flipperzero.nix b/modules/home-manager-modules/flipperzero.nix new file mode 100644 index 0000000..6354bc0 --- /dev/null +++ b/modules/home-manager-modules/flipperzero.nix @@ -0,0 +1,3 @@ +{lib, ...}: { + options.hardware.flipperzero.enable = lib.mkEnableOption "enable flipperzero hardware"; +} diff --git a/modules/home-manager-modules/gnome.nix b/modules/home-manager-modules/gnome.nix new file mode 100644 index 0000000..8c70cf6 --- /dev/null +++ b/modules/home-manager-modules/gnome.nix @@ -0,0 +1,106 @@ +{ + lib, + config, + ... +}: { + options.gnome = { + extraWindowControls = lib.mkEnableOption "Should we add back in the minimize and maximize window controls?"; + clockFormat = lib.mkOption { + type = lib.types.enum [ + "12h" + "24h" + ]; + default = "24h"; + }; + colorScheme = lib.mkOption { + type = lib.types.enum [ + "default" + "prefer-dark" + "prefer-light" + ]; + default = "default"; + }; + accentColor = lib.mkOption { + type = lib.types.enum [ + "blue" + "teal" + "green" + "yellow" + "orange" + "red" + "pink" + "purple" + "slate" + ]; + default = "blue"; + }; + extensions = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = []; + description = "The set of extensions to install and enable in the user environment."; + }; + hotkeys = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + key = lib.mkOption { + type = lib.types.strMatching "[a-zA-Z0-9-]+"; + default = builtins.replaceStrings [" " "/" "_"] ["-" "-" "-"] name; + }; + name = lib.mkOption { + type = lib.types.str; + default = name; + }; + binding = lib.mkOption { + type = lib.types.str; + }; + command = lib.mkOption { + type = lib.types.str; + }; + }; + })); + default = {}; + }; + }; + + config = { + home.packages = config.gnome.extensions; + dconf = { + settings = lib.mkMerge [ + { + "org/gnome/shell" = { + disable-user-extensions = false; # enables user extensions + enabled-extensions = builtins.map (extension: extension.extensionUuid) config.gnome.extensions; + }; + + "org/gnome/desktop/wm/preferences".button-layout = lib.mkIf config.gnome.extraWindowControls ":minimize,maximize,close"; + + "org/gnome/desktop/interface".color-scheme = config.gnome.colorScheme; + "org/gnome/desktop/interface".accent-color = config.gnome.accentColor; + "org/gnome/desktop/interface".clock-format = config.gnome.clockFormat; + } + ( + lib.mkMerge ( + builtins.map (value: let + entry = "org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/${value.key}"; + in { + ${entry} = { + binding = value.binding; + command = value.command; + name = value.name; + }; + + "org/gnome/settings-daemon/plugins/media-keys" = { + custom-keybindings = [ + "/${entry}/" + ]; + }; + }) + ( + lib.attrsets.mapAttrsToList (_: value: value) config.gnome.hotkeys + ) + ) + ) + ]; + }; + }; +} diff --git a/modules/home-manager-modules/i18n.nix b/modules/home-manager-modules/i18n.nix new file mode 100644 index 0000000..2c93e59 --- /dev/null +++ b/modules/home-manager-modules/i18n.nix @@ -0,0 +1,42 @@ +{ + lib, + config, + ... +}: { + options = { + i18n = { + defaultLocale = lib.mkOption { + type = lib.types.str; + default = "en_US.UTF-8"; + example = "nl_NL.UTF-8"; + description = '' + The default locale. It determines the language for program + messages, the format for dates and times, sort order, and so on. + It also determines the character set, such as UTF-8. + ''; + }; + + extraLocaleSettings = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = {}; + example = { + LC_MESSAGES = "en_US.UTF-8"; + LC_TIME = "de_DE.UTF-8"; + }; + description = '' + A set of additional system-wide locale settings other than + `LANG` which can be configured with + {option}`i18n.defaultLocale`. + ''; + }; + }; + }; + + config = { + home.sessionVariables = + { + LANG = config.i18n.defaultLocale; + } + // config.i18n.extraLocaleSettings; + }; +} diff --git a/modules/home-manager-modules/openssh.nix b/modules/home-manager-modules/openssh.nix new file mode 100644 index 0000000..c8ba22d --- /dev/null +++ b/modules/home-manager-modules/openssh.nix @@ -0,0 +1,102 @@ +{ + pkgs, + config, + osConfig, + lib, + ... +}: { + options.programs.openssh = { + enable = lib.mkEnableOption "should we enable openssh"; + authorizedKeys = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; + }; + hostKeys = lib.mkOption { + type = lib.types.listOf lib.types.attrs; + default = []; + example = [ + { + type = "rsa"; + bits = 4096; + path = "${config.home.username}_${osConfig.networking.hostName}_rsa"; + rounds = 100; + openSSHFormat = true; + } + { + type = "ed25519"; + path = "${config.home.username}_${osConfig.networking.hostName}_ed25519"; + rounds = 100; + comment = "key comment"; + } + ]; + description = '' + NixOS can automatically generate SSH host keys. This option + specifies the path, type and size of each key. See + {manpage}`ssh-keygen(1)` for supported types + and sizes. Paths are relative to home directory + ''; + }; + }; + + config = lib.mkIf config.programs.openssh.enable ( + lib.mkMerge [ + ( + lib.mkIf ((builtins.length config.programs.openssh.hostKeys) != 0) { + services.ssh-agent.enable = true; + programs.ssh = { + enable = true; + compression = true; + addKeysToAgent = "confirm"; + extraConfig = lib.strings.concatLines ( + builtins.map (hostKey: "IdentityFile ~/.ssh/${hostKey.path}") config.programs.openssh.hostKeys + ); + }; + + systemd.user.services = builtins.listToAttrs ( + builtins.map (hostKey: + lib.attrsets.nameValuePair "ssh-gen-keys-${hostKey.path}" { + Install = { + WantedBy = ["default.target"]; + }; + Service = let + path = "${config.home.homeDirectory}/.ssh/${hostKey.path}"; + in { + Restart = "always"; + Type = "simple"; + ExecStart = "${ + pkgs.writeShellScript "ssh-gen-keys" '' + if ! [ -s "${path}" ]; then + if ! [ -h "${path}" ]; then + rm -f "${path}" + fi + mkdir -p "$(dirname '${path}')" + chmod 0755 "$(dirname '${path}')" + ${pkgs.openssh}/bin/ssh-keygen \ + -t "${hostKey.type}" \ + ${lib.optionalString (hostKey ? bits) "-b ${toString hostKey.bits}"} \ + ${lib.optionalString (hostKey ? rounds) "-a ${toString hostKey.rounds}"} \ + ${lib.optionalString (hostKey ? comment) "-C '${hostKey.comment}'"} \ + ${lib.optionalString (hostKey ? openSSHFormat && hostKey.openSSHFormat) "-o"} \ + -f "${path}" \ + -N "" + chown ${config.home.username} ${path}* + chgrp ${config.home.username} ${path}* + fi + '' + }"; + }; + }) + config.programs.openssh.hostKeys + ); + } + ) + (lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + files = lib.lists.flatten ( + builtins.map (hostKey: [".ssh/${hostKey.path}" ".ssh/${hostKey.path}.pub"]) config.programs.openssh.hostKeys + ); + }; + }) + ] + ); +} diff --git a/modules/home-manager-modules/programs/anki.nix b/modules/home-manager-modules/programs/anki.nix new file mode 100644 index 0000000..c2f93ea --- /dev/null +++ b/modules/home-manager-modules/programs/anki.nix @@ -0,0 +1,15 @@ +{ + lib, + config, + osConfig, + ... +}: { + config = lib.mkIf (config.programs.anki.enable && osConfig.host.impermanence.enable) { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + "${config.xdg.dataHome}/Anki2/" + ]; + allowOther = true; + }; + }; +} diff --git a/modules/home-manager-modules/programs/bitwarden.nix b/modules/home-manager-modules/programs/bitwarden.nix new file mode 100644 index 0000000..b9b91c4 --- /dev/null +++ b/modules/home-manager-modules/programs/bitwarden.nix @@ -0,0 +1,29 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.bitwarden = { + enable = lib.mkEnableOption "enable bitwarden"; + }; + + config = lib.mkIf config.programs.bitwarden.enable (lib.mkMerge [ + { + home.packages = with pkgs; [ + bitwarden + ]; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + "${config.xdg.configHome}/Bitwarden" + ]; + allowOther = true; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/bruno.nix b/modules/home-manager-modules/programs/bruno.nix new file mode 100644 index 0000000..00b248f --- /dev/null +++ b/modules/home-manager-modules/programs/bruno.nix @@ -0,0 +1,29 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.bruno = { + enable = lib.mkEnableOption "enable bruno"; + }; + + config = lib.mkIf config.programs.bruno.enable (lib.mkMerge [ + { + home.packages = with pkgs; [ + bruno + ]; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + "${config.xdg.configHome}/bruno/" + ]; + allowOther = true; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/calibre.nix b/modules/home-manager-modules/programs/calibre.nix new file mode 100644 index 0000000..9e5f34e --- /dev/null +++ b/modules/home-manager-modules/programs/calibre.nix @@ -0,0 +1,29 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.calibre = { + enable = lib.mkEnableOption "enable calibre"; + }; + + config = lib.mkIf config.programs.calibre.enable (lib.mkMerge [ + { + home.packages = with pkgs; [ + calibre + ]; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + "${config.xdg.configHome}/calibre" + ]; + allowOther = true; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/dbeaver.nix b/modules/home-manager-modules/programs/dbeaver.nix new file mode 100644 index 0000000..a962459 --- /dev/null +++ b/modules/home-manager-modules/programs/dbeaver.nix @@ -0,0 +1,29 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.dbeaver-bin = { + enable = lib.mkEnableOption "enable dbeaver"; + }; + + config = lib.mkIf config.programs.dbeaver-bin.enable (lib.mkMerge [ + { + home.packages = with pkgs; [ + dbeaver-bin + ]; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + "${config.xdg.dataHome}/DBeaverData/" + ]; + allowOther = true; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/default.nix b/modules/home-manager-modules/programs/default.nix new file mode 100644 index 0000000..ee52da2 --- /dev/null +++ b/modules/home-manager-modules/programs/default.nix @@ -0,0 +1,20 @@ +{...}: { + imports = [ + ./firefox.nix + ./signal.nix + ./bitwarden.nix + ./makemkv.nix + ./obs.nix + ./anki.nix + ./qbittorrent.nix + ./discord.nix + ./obsidian.nix + ./prostudiomasters.nix + ./idea.nix + ./protonvpn.nix + ./calibre.nix + ./bruno.nix + ./dbeaver.nix + ./steam.nix + ]; +} diff --git a/modules/home-manager-modules/programs/discord.nix b/modules/home-manager-modules/programs/discord.nix new file mode 100644 index 0000000..e8605a5 --- /dev/null +++ b/modules/home-manager-modules/programs/discord.nix @@ -0,0 +1,29 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.discord = { + enable = lib.mkEnableOption "enable discord"; + }; + + config = lib.mkIf config.programs.discord.enable (lib.mkMerge [ + { + home.packages = with pkgs; [ + discord + ]; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + "${config.xdg.configHome}/discord/" + ]; + allowOther = true; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/firefox.nix b/modules/home-manager-modules/programs/firefox.nix new file mode 100644 index 0000000..907b619 --- /dev/null +++ b/modules/home-manager-modules/programs/firefox.nix @@ -0,0 +1,43 @@ +{ + lib, + config, + osConfig, + ... +}: let + buildProfilePersistence = profile: { + directories = [ + ".mozilla/firefox/${profile}/extensions" + ]; + files = [ + ".mozilla/firefox/${profile}/cookies.sqlite" + ".mozilla/firefox/${profile}/favicons.sqlite" + # Permissions and ${profileName} levels for each site + ".mozilla/firefox/${profile}/permissions.sqlite" + ".mozilla/firefox/${profile}/content-prefs.sqlite" + # Browser history and bookmarks + ".mozilla/firefox/${profile}/places.sqlite" + # I guess this is useful? + # https://bugzilla.mozilla.org/show_bug.cgi?id=1511384 + # https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria + ".mozilla/firefox/${profile}/storage.sqlite" + # Extension configuration + ".mozilla/firefox/${profile}/extension-settings.json" + ]; + allowOther = true; + }; +in { + config = lib.mkIf (config.programs.firefox.enable && osConfig.host.impermanence.enable) { + home.persistence."/persist${config.home.homeDirectory}" = lib.mkMerge ( + ( + lib.attrsets.mapAttrsToList + (profile: _: buildProfilePersistence profile) + config.programs.firefox.profiles + ) + ++ ( + lib.lists.optional + ((builtins.length (lib.attrsets.mapAttrsToList (key: value: value) config.programs.firefox.profiles)) == 0) + (buildProfilePersistence "default") + ) + ); + }; +} diff --git a/modules/home-manager-modules/programs/idea.nix b/modules/home-manager-modules/programs/idea.nix new file mode 100644 index 0000000..f0a928c --- /dev/null +++ b/modules/home-manager-modules/programs/idea.nix @@ -0,0 +1,33 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.jetbrains.idea-community = { + enable = lib.mkEnableOption "enable idea-community"; + }; + + config = lib.mkIf config.programs.jetbrains.idea-community.enable (lib.mkMerge [ + { + home.packages = with pkgs; [ + jetbrains.idea-community + ]; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + # configuration + "${config.xdg.configHome}/JetBrains/" + # plugins + "${config.xdg.dataHome}/JetBrains/" + # System and Logs + "${config.xdg.cacheHome}/JetBrains/" + ]; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/makemkv.nix b/modules/home-manager-modules/programs/makemkv.nix new file mode 100644 index 0000000..eca059d --- /dev/null +++ b/modules/home-manager-modules/programs/makemkv.nix @@ -0,0 +1,42 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.makemkv = { + enable = lib.mkEnableOption "enable makemkv"; + appKeyFile = lib.mkOption { + type = lib.types.str; + }; + destinationDir = lib.mkOption { + type = lib.types.str; + }; + }; + + config = lib.mkIf config.programs.makemkv.enable (lib.mkMerge [ + { + home.packages = with pkgs; [ + makemkv + ]; + + sops.templates."MakeMKV.settings.conf".content = '' + app_DestinationDir = "${config.programs.makemkv.destinationDir}" + app_DestinationType = "2" + app_Key = "${config.programs.makemkv.appKeyFile}" + ''; + + home.file.".MakeMKV/settings.conf".source = config.lib.file.mkOutOfStoreSymlink config.sops.templates."MakeMKV.settings.conf".path; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + ".MakeMKV" + ]; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/obs.nix b/modules/home-manager-modules/programs/obs.nix new file mode 100644 index 0000000..98c4fea --- /dev/null +++ b/modules/home-manager-modules/programs/obs.nix @@ -0,0 +1,14 @@ +{ + lib, + config, + osConfig, + ... +}: { + config = lib.mkIf config.programs.obs-studio.enable (lib.mkMerge [ + ( + lib.mkIf osConfig.host.impermanence.enable { + # TODO: map impermanence for obs + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/obsidian.nix b/modules/home-manager-modules/programs/obsidian.nix new file mode 100644 index 0000000..4d28b3e --- /dev/null +++ b/modules/home-manager-modules/programs/obsidian.nix @@ -0,0 +1,18 @@ +{ + lib, + config, + osConfig, + ... +}: { + config = lib.mkIf config.programs.obsidian.enable (lib.mkMerge [ + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + "${config.xdg.configHome}/obsidian" + ]; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/prostudiomasters.nix b/modules/home-manager-modules/programs/prostudiomasters.nix new file mode 100644 index 0000000..9e6088f --- /dev/null +++ b/modules/home-manager-modules/programs/prostudiomasters.nix @@ -0,0 +1,28 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.prostudiomasters = { + enable = lib.mkEnableOption "enable prostudiomasters"; + }; + + config = lib.mkIf config.programs.prostudiomasters.enable (lib.mkMerge [ + { + home.packages = with pkgs; [ + prostudiomasters + ]; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + "${config.xdg.configHome}/ProStudioMasters" + ]; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/protonvpn.nix b/modules/home-manager-modules/programs/protonvpn.nix new file mode 100644 index 0000000..dd11aae --- /dev/null +++ b/modules/home-manager-modules/programs/protonvpn.nix @@ -0,0 +1,29 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.protonvpn-gui = { + enable = lib.mkEnableOption "enable protonvpn"; + }; + + config = lib.mkIf config.programs.protonvpn-gui.enable (lib.mkMerge [ + { + home.packages = with pkgs; [ + protonvpn-gui + ]; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + "${config.xdg.configHome}/protonvpn" + "${config.xdg.configHome}/Proton" + ]; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/qbittorrent.nix b/modules/home-manager-modules/programs/qbittorrent.nix new file mode 100644 index 0000000..02e23df --- /dev/null +++ b/modules/home-manager-modules/programs/qbittorrent.nix @@ -0,0 +1,28 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.qbittorrent = { + enable = lib.mkEnableOption "enable qbittorrent"; + }; + + config = lib.mkIf config.programs.qbittorrent.enable (lib.mkMerge [ + { + home.packages = with pkgs; [ + qbittorrent + ]; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + "${config.xdg.configHome}/qBittorrent" + ]; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/signal.nix b/modules/home-manager-modules/programs/signal.nix new file mode 100644 index 0000000..fdf0af9 --- /dev/null +++ b/modules/home-manager-modules/programs/signal.nix @@ -0,0 +1,28 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.signal-desktop-bin = { + enable = lib.mkEnableOption "enable signal"; + }; + + config = lib.mkIf config.programs.signal-desktop-bin.enable (lib.mkMerge [ + { + home.packages = with pkgs; [ + signal-desktop-bin + ]; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + "${config.xdg.configHome}/Signal" + ]; + }; + } + ) + ]); +} diff --git a/modules/home-manager-modules/programs/steam.nix b/modules/home-manager-modules/programs/steam.nix new file mode 100644 index 0000000..4661151 --- /dev/null +++ b/modules/home-manager-modules/programs/steam.nix @@ -0,0 +1,37 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + options.programs.steam = { + enable = lib.mkEnableOption "enable steam"; + }; + + config = lib.mkIf config.programs.steam.enable ( + lib.mkMerge [ + { + home.packages = with pkgs; [ + steam + steam.run + ]; + } + ( + lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + { + directory = "${config.xdg.dataHome}/Steam"; + method = "symlink"; + } + ]; + allowOther = true; + }; + } + ) + ] + ); + + # TODO: bind impermanence config +} diff --git a/modules/home-manager-modules/sops.nix b/modules/home-manager-modules/sops.nix new file mode 100644 index 0000000..910fbb6 --- /dev/null +++ b/modules/home-manager-modules/sops.nix @@ -0,0 +1,7 @@ +{...}: { + config = { + sops = { + age.keyFile = "/var/lib/sops-nix/key.txt"; + }; + }; +} diff --git a/modules/home-manager-modules/user.nix b/modules/home-manager-modules/user.nix new file mode 100644 index 0000000..efce22d --- /dev/null +++ b/modules/home-manager-modules/user.nix @@ -0,0 +1,17 @@ +{ + lib, + config, + osConfig, + ... +}: { + options.user = { + isDesktopUser = lib.mkOption { + type = lib.types.bool; + default = osConfig.host.users.${config.home.username}.isDesktopUser; + }; + isTerminalUser = lib.mkOption { + type = lib.types.bool; + default = osConfig.host.users.${config.home.username}.isTerminalUser; + }; + }; +} diff --git a/modules/nixos-modules/ai.nix b/modules/nixos-modules/ai.nix new file mode 100644 index 0000000..d8cd63d --- /dev/null +++ b/modules/nixos-modules/ai.nix @@ -0,0 +1,46 @@ +{lib, ...}: { + options.host = { + ai = { + enable = lib.mkEnableOption "should we use AI on this machine"; + models = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + name = lib.mkOption { + type = lib.types.str; + default = name; + }; + model = lib.mkOption { + type = lib.types.str; + }; + provider = lib.mkOption { + type = lib.types.str; + default = "ollama"; + }; + apiBase = lib.mkOption { + type = lib.types.str; + default = "http://localhost:11434"; + }; + roles = lib.mkOption { + type = lib.types.listOf (lib.types.enum [ + "chat" + "autocomplete" + "embed" + "rerank" + "edit" + "apply" + "summarize" + ]); + default = []; + }; + }; + })); + }; + default = {}; + }; + }; + + config = { + # TODO: configure ollama to download any modules listed in options.host.ai.models.{name}.model if options.host.ai.models.{name}.apiBase is localhost + # TODO: if we have any models that have a non localhost options.host.ai.models.{name}.apiBase then set services.ollama.enable to a lib.mkAfter true + }; +} diff --git a/modules/nixos-modules/default.nix b/modules/nixos-modules/default.nix new file mode 100644 index 0000000..2ba1a58 --- /dev/null +++ b/modules/nixos-modules/default.nix @@ -0,0 +1,24 @@ +# this folder container modules that are for nixos only +{...}: { + imports = [ + ./home-manager + ./system.nix + ./hardware.nix + ./users.nix + ./desktop.nix + ./ssh.nix + ./i18n.nix + ./sync.nix + ./impermanence.nix + ./disko.nix + ./ollama.nix + ./ai.nix + ./tailscale.nix + ./steam.nix + ./server + ]; + + nixpkgs.config.permittedInsecurePackages = [ + "dotnet-sdk-6.0.428" + ]; +} diff --git a/modules/nixos-modules/desktop.nix b/modules/nixos-modules/desktop.nix new file mode 100644 index 0000000..900aacf --- /dev/null +++ b/modules/nixos-modules/desktop.nix @@ -0,0 +1,74 @@ +{ + lib, + pkgs, + config, + ... +}: { + options.host.desktop.enable = lib.mkEnableOption "should desktop configuration be enabled"; + + config = lib.mkMerge [ + { + host.desktop.enable = lib.mkDefault true; + } + (lib.mkIf config.host.desktop.enable { + environment.gnome.excludePackages = with pkgs; [ + xterm # default terminal + atomix # puzzle game + cheese # webcam tool + epiphany # web browser + geary # email reader + gedit # text editor + decibels # audio player + gnome-characters # character set viewer + gnome-music # music player + gnome-photos # photo viewer + gnome-logs # log viwer + gnome-maps # map viewer + gnome-tour # welcome tour + hitori # sudoku game + iagno # go game + tali # poker game + yelp # help viewer + ]; + services = { + # Enable CUPS to print documents. + printing.enable = true; + + xserver = { + # Enable the X11 windowing system. + enable = true; + + # Get rid of xTerm + desktopManager.xterm.enable = false; + }; + + # Enable the GNOME Desktop Environment. + displayManager.gdm.enable = true; + desktopManager.gnome.enable = true; + + pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + + # If you want to use JACK applications, uncomment this + #jack.enable = true; + + # use the example session manager (no others are packaged yet so this is enabled by default, + # no need to redefine it in your config for now) + #media-session.enable = true; + }; + automatic-timezoned = { + enable = true; + }; + + # Enable sound with pipewire. + pulseaudio.enable = false; + }; + + # enable RealtimeKit for pulse audio + security.rtkit.enable = true; + }) + ]; +} diff --git a/modules/nixos-modules/disko.nix b/modules/nixos-modules/disko.nix new file mode 100644 index 0000000..3d15498 --- /dev/null +++ b/modules/nixos-modules/disko.nix @@ -0,0 +1,266 @@ +{ + lib, + pkgs, + config, + inputs, + ... +}: let + # there currently is a bug with disko that causes long disk names to be generated improperly this hash function should alleviate it when used for disk names instead of what we are defaulting to + # max gpt length is 36 and disk adds formats it like disk-xxxx-zfs which means we need to be 9 characters under that + hashDisk = drive: (builtins.substring 0 27 (builtins.hashString "sha256" drive)); + + vdevs = + builtins.map ( + disks: + builtins.map (disk: lib.attrsets.nameValuePair (hashDisk disk) disk) disks + ) + config.host.storage.pool.vdevs; + cache = + builtins.map ( + disk: lib.attrsets.nameValuePair (hashDisk disk) disk + ) + config.host.storage.pool.cache; + + datasets = config.host.storage.pool.datasets // config.host.storage.pool.extraDatasets; +in { + options.host.storage = { + enable = lib.mkEnableOption "are we going create zfs disks with disko on this device"; + encryption = lib.mkEnableOption "is the vdev going to be encrypted"; + notifications = { + enable = lib.mkEnableOption "are notifications enabled"; + host = lib.mkOption { + type = lib.types.str; + description = "what is the host that we are going to send the email to"; + }; + port = lib.mkOption { + type = lib.types.port; + description = "what port is the host using to receive mail on"; + }; + to = lib.mkOption { + type = lib.types.str; + description = "what account is the email going to be sent to"; + }; + user = lib.mkOption { + type = lib.types.str; + description = "what user is the email going to be set from"; + }; + tokenFile = lib.mkOption { + type = lib.types.str; + description = "file containing the password to be used by msmtp for notifications"; + }; + }; + pool = { + mode = lib.mkOption { + type = lib.types.str; + default = "raidz2"; + description = "what level of redundancy should this pool have"; + }; + # list of drives in pool that will have a boot partition put onto them + bootDrives = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "list of disks that are going to have a boot partition installed on them"; + default = lib.lists.flatten config.host.storage.pool.vdevs; + }; + # shorthand for vdevs if you only have 1 vdev + drives = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "list of drives that are going to be in the vdev"; + default = []; + }; + # list of all drives in each vdev + vdevs = lib.mkOption { + type = lib.types.listOf (lib.types.listOf lib.types.str); + description = "list of disks that are going to be in"; + default = [config.host.storage.pool.drives]; + }; + # list of cache drives for pool + cache = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "list of drives that are going to be used as cache"; + default = []; + }; + # Default datasets that are needed to make a functioning system + datasets = lib.mkOption { + type = lib.types.attrsOf (inputs.disko.lib.subType { + types = {inherit (inputs.disko.lib.types) zfs_fs zfs_volume;}; + }); + default = { + "local" = { + type = "zfs_fs"; + options.canmount = "off"; + }; + # nix directory needs to be available pre persist and doesn't need to be snapshotted or backed up + "local/system/nix" = { + type = "zfs_fs"; + mountpoint = "/nix"; + options = { + atime = "off"; + relatime = "off"; + canmount = "on"; + }; + }; + # dataset for root that gets rolled back on every boot + "local/system/root" = { + type = "zfs_fs"; + mountpoint = "/"; + options = { + canmount = "on"; + }; + postCreateHook = '' + zfs snapshot rpool/local/system/root@blank + ''; + }; + }; + }; + extraDatasets = lib.mkOption { + type = lib.types.attrsOf (inputs.disko.lib.subType { + types = {inherit (inputs.disko.lib.types) zfs_fs zfs_volume;}; + }); + description = "List of datasets to define"; + default = {}; + }; + }; + }; + + config = lib.mkIf config.host.storage.enable { + programs.msmtp = lib.mkIf config.host.storage.notifications.enable { + enable = true; + setSendmail = true; + defaults = { + aliases = "/etc/aliases"; + port = config.host.storage.notifications.port; + tls_trust_file = "/etc/ssl/certs/ca-certificates.crt"; + tls = "on"; + auth = "login"; + tls_starttls = "off"; + }; + accounts = { + zfs_notifications = { + host = config.host.storage.notifications.host; + passwordeval = "cat ${config.host.storage.notifications.tokenFile}"; + user = config.host.storage.notifications.user; + from = config.host.storage.notifications.user; + }; + }; + }; + + services.zfs = { + autoScrub.enable = true; + autoSnapshot.enable = true; + + zed = lib.mkIf config.host.storage.notifications.enable { + # this option is broken we are just going to disable it + enableMail = false; + + settings = { + ZED_DEBUG_LOG = "/tmp/zed.debug.log"; + ZED_EMAIL_ADDR = [config.host.storage.notifications.to]; + ZED_EMAIL_PROG = "${pkgs.msmtp}/bin/msmtp"; + ZED_EMAIL_OPTS = "@ADDRESS@"; + + ZED_NOTIFY_INTERVAL_SECS = 3600; + ZED_NOTIFY_VERBOSE = true; + + ZED_USE_ENCLOSURE_LEDS = true; + ZED_SCRUB_AFTER_RESILVER = true; + }; + }; + }; + + disko.devices = { + disk = ( + builtins.listToAttrs ( + builtins.map + (drive: + lib.attrsets.nameValuePair (drive.name) { + type = "disk"; + device = "/dev/disk/by-id/${drive.value}"; + content = { + type = "gpt"; + partitions = { + ESP = lib.mkIf (builtins.elem drive.value config.host.storage.pool.bootDrives) { + # The 2GB here for the boot partition might be a bit overkill we probably only need like 1/4th of that but storage is cheap + size = "2G"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = ["umask=0077"]; + }; + }; + zfs = { + size = "100%"; + content = { + type = "zfs"; + pool = "rpool"; + }; + }; + }; + }; + }) + ( + (lib.lists.flatten vdevs) ++ cache + ) + ) + ); + zpool = { + rpool = { + type = "zpool"; + mode = { + topology = { + type = "topology"; + vdev = ( + builtins.map (disks: { + mode = config.host.storage.pool.mode; + members = + builtins.map (disk: disk.name) disks; + }) + vdevs + ); + cache = builtins.map (disk: disk.name) cache; + }; + }; + + options = { + ashift = "12"; + autotrim = "on"; + }; + + rootFsOptions = + { + canmount = "off"; + mountpoint = "none"; + + xattr = "sa"; + acltype = "posixacl"; + relatime = "on"; + + compression = "lz4"; + + "com.sun:auto-snapshot" = "false"; + } + // ( + lib.attrsets.optionalAttrs config.host.storage.encryption { + encryption = "on"; + keyformat = "hex"; + keylocation = "prompt"; + } + ); + + datasets = lib.mkMerge [ + ( + lib.attrsets.mapAttrs (name: value: { + type = value.type; + options = value.options; + mountpoint = value.mountpoint; + postCreateHook = value.postCreateHook; + }) + datasets + ) + ]; + }; + }; + }; + }; +} diff --git a/modules/nixos-modules/hardware.nix b/modules/nixos-modules/hardware.nix new file mode 100644 index 0000000..07e6fa8 --- /dev/null +++ b/modules/nixos-modules/hardware.nix @@ -0,0 +1,34 @@ +{ + lib, + config, + pkgs, + ... +}: { + options.host.hardware = { + piperMouse = { + enable = lib.mkEnableOption "host has a piper mouse"; + }; + viaKeyboard = { + enable = lib.mkEnableOption "host has a via keyboard"; + }; + openRGB = { + enable = lib.mkEnableOption "host has open rgb hardware"; + }; + graphicsAcceleration = { + enable = lib.mkEnableOption "host has a gpu for graphical acceleration"; + }; + directAccess = { + enable = lib.mkEnableOption "can a host be used on its own"; + }; + }; + config = lib.mkMerge [ + (lib.mkIf config.host.hardware.piperMouse.enable { + services.ratbagd.enable = true; + }) + (lib.mkIf config.host.hardware.viaKeyboard.enable { + hardware.keyboard.qmk.enable = true; + + services.udev.packages = [pkgs.via]; + }) + ]; +} diff --git a/modules/nixos-modules/home-manager/default.nix b/modules/nixos-modules/home-manager/default.nix new file mode 100644 index 0000000..10f86c7 --- /dev/null +++ b/modules/nixos-modules/home-manager/default.nix @@ -0,0 +1,9 @@ +# modules in this folder are to adapt home-manager modules configs to nixos-module configs +{...}: { + imports = [ + ./flipperzero.nix + ./i18n.nix + ./openssh.nix + ./steam.nix + ]; +} diff --git a/modules/nixos-modules/home-manager/flipperzero.nix b/modules/nixos-modules/home-manager/flipperzero.nix new file mode 100644 index 0000000..6c94773 --- /dev/null +++ b/modules/nixos-modules/home-manager/flipperzero.nix @@ -0,0 +1,9 @@ +{ + lib, + config, + ... +}: let + home-users = lib.attrsets.mapAttrsToList (_: user: user) config.home-manager.users; +in { + hardware.flipperzero.enable = lib.lists.any (home-user: home-user.hardware.flipperzero.enable) home-users; +} diff --git a/modules/nixos-modules/home-manager/i18n.nix b/modules/nixos-modules/home-manager/i18n.nix new file mode 100644 index 0000000..78b86fa --- /dev/null +++ b/modules/nixos-modules/home-manager/i18n.nix @@ -0,0 +1,26 @@ +{ + lib, + config, + ... +}: let + home-users = lib.attrsets.mapAttrsToList (_: user: user) config.home-manager.users; +in { + config = { + i18n.supportedLocales = + lib.unique + (builtins.map (l: (lib.replaceStrings ["utf8" "utf-8" "UTF8"] ["UTF-8" "UTF-8" "UTF-8"] l) + "/UTF-8") ( + [ + "C.UTF-8" + "en_US.UTF-8" + config.i18n.defaultLocale + ] + ++ (lib.attrValues (lib.filterAttrs (n: v: n != "LANGUAGE") config.i18n.extraLocaleSettings)) + ++ ( + map (user-config: user-config.i18n.defaultLocale) home-users + ) + ++ (lib.lists.flatten ( + map (user-config: lib.attrValues (lib.filterAttrs (n: v: n != "LANGUAGE") user-config.i18n.extraLocaleSettings)) home-users + )) + )); + }; +} diff --git a/modules/nixos-modules/home-manager/openssh.nix b/modules/nixos-modules/home-manager/openssh.nix new file mode 100644 index 0000000..31a785f --- /dev/null +++ b/modules/nixos-modules/home-manager/openssh.nix @@ -0,0 +1,11 @@ +{ + config, + lib, + ... +}: { + users.users = + lib.attrsets.mapAttrs (name: value: { + openssh.authorizedKeys.keys = value.programs.openssh.authorizedKeys; + }) + config.home-manager.users; +} diff --git a/modules/nixos-modules/home-manager/steam.nix b/modules/nixos-modules/home-manager/steam.nix new file mode 100644 index 0000000..d151bca --- /dev/null +++ b/modules/nixos-modules/home-manager/steam.nix @@ -0,0 +1,18 @@ +{ + lib, + config, + ... +}: let + setupSteam = + lib.lists.any + (value: value) + (lib.attrsets.mapAttrsToList (name: value: value.programs.steam.enable) config.home-manager.users); +in { + config = lib.mkIf setupSteam { + programs.steam = { + enable = true; + # TODO: figure out how to not install steam here + # package = lib.mkDefault pkgs.emptyFile; + }; + }; +} diff --git a/modules/nixos-modules/i18n.nix b/modules/nixos-modules/i18n.nix new file mode 100644 index 0000000..eada12c --- /dev/null +++ b/modules/nixos-modules/i18n.nix @@ -0,0 +1,3 @@ +{...}: { + i18n.defaultLocale = "en_IE.UTF-8"; +} diff --git a/modules/nixos-modules/impermanence.nix b/modules/nixos-modules/impermanence.nix new file mode 100644 index 0000000..7735e97 --- /dev/null +++ b/modules/nixos-modules/impermanence.nix @@ -0,0 +1,100 @@ +{ + config, + lib, + ... +}: { + options.host.impermanence.enable = lib.mkEnableOption "are we going to use impermanence on this device"; + + config = lib.mkMerge [ + { + assertions = [ + { + assertion = !(config.host.impermanence.enable && !config.host.storage.enable); + message = '' + Disko storage must be enabled to use impermanence. + ''; + } + ]; + } + ( + lib.mkIf config.host.impermanence.enable { + assertions = [ + { + assertion = config.host.impermanence.enable && config.host.storage.enable; + message = "Impermanence can not be used without managed host storage."; + } + ]; + + # fixes issues with /var/lib/private not having the correct permissions https://github.com/nix-community/impermanence/issues/254 + system.activationScripts."createPersistentStorageDirs".deps = ["var-lib-private-permissions" "users" "groups"]; + system.activationScripts = { + "var-lib-private-permissions" = { + deps = ["specialfs"]; + text = '' + mkdir -p /persist/system/root/var/lib/private + chmod 0700 /persist/system/root/var/lib/private + ''; + }; + }; + + programs.fuse.userAllowOther = true; + + boot.initrd.postResumeCommands = lib.mkAfter '' + zfs rollback -r rpool/local/system/root@blank + ''; + + fileSystems = { + "/".neededForBoot = true; + "/persist/system/root".neededForBoot = true; + "/persist/system/var/log".neededForBoot = true; + }; + + host.storage.pool.extraDatasets = { + # persist datasets are datasets that contain information that we would like to keep around + "persist" = { + type = "zfs_fs"; + options.canmount = "off"; + options = { + "com.sun:auto-snapshot" = "true"; + }; + }; + # this is where root data actually lives + "persist/system/root" = { + type = "zfs_fs"; + mountpoint = "/persist/system/root"; + }; + "persist/system/var/log" = { + type = "zfs_fs"; + mountpoint = "/persist/system/var/log"; + # logs should be append only so we shouldn't need to snapshot them + options = { + "com.sun:auto-snapshot" = "false"; + }; + }; + }; + + environment.persistence."/persist/system/var/log" = { + enable = true; + hideMounts = true; + directories = [ + "/var/log" + ]; + }; + + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + "/var/lib/nixos" + "/var/lib/systemd/coredump" + ]; + files = [ + "/etc/machine-id" + ]; + }; + + security.sudo.extraConfig = "Defaults lecture=never"; + } + ) + ]; +} diff --git a/modules/nixos-modules/ollama.nix b/modules/nixos-modules/ollama.nix new file mode 100644 index 0000000..99819bf --- /dev/null +++ b/modules/nixos-modules/ollama.nix @@ -0,0 +1,46 @@ +{ + config, + lib, + ... +}: { + options = { + services.ollama.exposePort = lib.mkEnableOption "should we expose ollama on tailscale"; + }; + + config = lib.mkIf config.services.ollama.enable ( + lib.mkMerge [ + { + services.ollama = { + # TODO: these should match whats set in the users file + group = "ollama"; + user = "ollama"; + }; + } + (lib.mkIf config.services.ollama.exposePort (let + ports = [ + config.services.ollama.port + ]; + in { + services.ollama.host = "0.0.0.0"; + networking.firewall.interfaces.${config.services.tailscale.interfaceName} = { + allowedTCPPorts = ports; + allowedUDPPorts = ports; + }; + })) + (lib.mkIf config.host.impermanence.enable { + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = "/var/lib/private/ollama"; + user = config.services.ollama.user; + group = config.services.ollama.group; + mode = "0700"; + } + ]; + }; + }) + ] + ); +} diff --git a/modules/nixos-modules/server/default.nix b/modules/nixos-modules/server/default.nix new file mode 100644 index 0000000..95c7096 --- /dev/null +++ b/modules/nixos-modules/server/default.nix @@ -0,0 +1,17 @@ +{...}: { + imports = [ + ./fail2ban.nix + ./network_storage + ./reverse_proxy.nix + ./postgres.nix + ./podman.nix + ./jellyfin.nix + ./forgejo.nix + ./searx.nix + ./home-assistant.nix + ./wyoming.nix + ./immich.nix + ./qbittorent.nix + ./paperless.nix + ]; +} diff --git a/modules/nixos-modules/server/fail2ban.nix b/modules/nixos-modules/server/fail2ban.nix new file mode 100644 index 0000000..d19aeeb --- /dev/null +++ b/modules/nixos-modules/server/fail2ban.nix @@ -0,0 +1,74 @@ +{ + lib, + pkgs, + config, + ... +}: let + dataFolder = "/var/lib/fail2ban"; + dataFile = "fail2ban.sqlite3"; +in { + config = lib.mkIf config.services.fail2ban.enable (lib.mkMerge [ + { + environment.etc = { + "fail2ban/filter.d/nginx.local".text = lib.mkIf config.services.nginx.enable ( + pkgs.lib.mkDefault (pkgs.lib.mkAfter '' + [Definition] + failregex = "limiting requests, excess:.* by zone.*client: " + '') + ); + }; + + services.fail2ban = { + maxretry = 5; + ignoreIP = [ + # Whitelist local networks + "10.0.0.0/8" + "172.16.0.0/12" + "192.168.0.0/16" + + # tail scale tailnet + "100.64.0.0/10" + "fd7a:115c:a1e0::/48" + ]; + bantime = "24h"; # Ban IPs for one day on the first ban + bantime-increment = { + enable = true; # Enable increment of bantime after each violation + formula = "ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)"; + maxtime = "168h"; # Do not ban for more than 1 week + overalljails = true; # Calculate the ban time based on all the violations + }; + jails = { + nginx-iptables.settings = lib.mkIf config.services.nginx.enable { + enabled = true; + filter = "nginx"; + action = ''iptables-multiport[name=HTTP, port="http,https"]''; + backend = "auto"; + findtime = 600; + bantime = 600; + maxretry = 5; + }; + # TODO; figure out if there is any fail2ban things we can do on searx + # searx-iptables.settings = lib.mkIf config.services.searx.enable {}; + }; + }; + } + (lib.mkIf config.host.impermanence.enable { + assertions = [ + { + assertion = config.services.fail2ban.daemonSettings.Definition.dbfile == "${dataFolder}/${dataFile}"; + message = "fail2ban data file does not match persistence"; + } + ]; + + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = dataFolder; + user = "fail2ban"; + group = "fail2ban"; + } + ]; + }; + }) + ]); +} diff --git a/modules/nixos-modules/server/forgejo.nix b/modules/nixos-modules/server/forgejo.nix new file mode 100644 index 0000000..7898daa --- /dev/null +++ b/modules/nixos-modules/server/forgejo.nix @@ -0,0 +1,118 @@ +{ + 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 [ + { + 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 = config.users.users.git.name; + 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 " + '') + ); + }; + + 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"; + } + ]; + }; + }) + ]); +} diff --git a/modules/nixos-modules/server/home-assistant.nix b/modules/nixos-modules/server/home-assistant.nix new file mode 100644 index 0000000..57bedc1 --- /dev/null +++ b/modules/nixos-modules/server/home-assistant.nix @@ -0,0 +1,229 @@ +{ + 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 .*$ + + 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"; + } + ]; + }; + }) + ]); +} diff --git a/modules/nixos-modules/server/immich.nix b/modules/nixos-modules/server/immich.nix new file mode 100644 index 0000000..e7088a9 --- /dev/null +++ b/modules/nixos-modules/server/immich.nix @@ -0,0 +1,95 @@ +{ + 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? + 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"; + } + ]; + }; + }) + ]); +} diff --git a/modules/nixos-modules/server/jellyfin.nix b/modules/nixos-modules/server/jellyfin.nix new file mode 100644 index 0000000..bad04c9 --- /dev/null +++ b/modules/nixos-modules/server/jellyfin.nix @@ -0,0 +1,140 @@ +{ + 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]; + } + (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: \"\"\\\)\\\." + '') + ); + }; + + 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"; + } + ]; + }; + }; + }) + ] + ); +} diff --git a/modules/nixos-modules/server/network_storage/default.nix b/modules/nixos-modules/server/network_storage/default.nix new file mode 100644 index 0000000..00ea7ac --- /dev/null +++ b/modules/nixos-modules/server/network_storage/default.nix @@ -0,0 +1,90 @@ +{ + config, + lib, + ... +}: let + export_directory = config.host.network_storage.export_directory; +in { + imports = [ + ./nfs.nix + ]; + + options = { + host.network_storage = { + enable = lib.mkEnableOption "is this machine going to export network storage"; + export_directory = lib.mkOption { + type = lib.types.path; + description = "what are exports going to be stored in"; + default = "/export"; + }; + directories = lib.mkOption { + type = lib.types.listOf (lib.types.submodule ({config, ...}: { + options = { + folder = lib.mkOption { + type = lib.types.str; + description = "what is the name of this export directory"; + }; + bind = lib.mkOption { + type = lib.types.nullOr lib.types.path; + description = "is this directory bound to anywhere"; + default = null; + }; + user = lib.mkOption { + type = lib.types.str; + description = "what user owns this directory"; + default = "nouser"; + }; + group = lib.mkOption { + type = lib.types.str; + description = "what group owns this directory"; + default = "nogroup"; + }; + _directory = lib.mkOption { + internal = true; + readOnly = true; + type = lib.types.path; + default = "${export_directory}/${config.folder}"; + }; + }; + })); + description = "list of directory names to export"; + }; + }; + }; + + config = lib.mkIf config.host.network_storage.enable (lib.mkMerge [ + { + # create any folders that we need to have for our exports + systemd.tmpfiles.rules = + [ + "d ${config.host.network_storage.export_directory} 2775 nobody nogroup -" + ] + ++ ( + builtins.map ( + directory: "d ${directory._directory} 2770 ${directory.user} ${directory.group}" + ) + config.host.network_storage.directories + ); + + # set up any bind mounts that we need for our exports + fileSystems = builtins.listToAttrs ( + builtins.map (directory: + lib.attrsets.nameValuePair directory._directory { + device = directory.bind; + options = ["bind"]; + }) ( + builtins.filter (directory: directory.bind != null) config.host.network_storage.directories + ) + ); + } + # (lib.mkIf config.host.impermanence.enable { + # environment.persistence."/persist/system/root" = { + # enable = true; + # hideMounts = true; + # directories = [ + # config.host.network_storage.export_directory + # ]; + # }; + # }) + ]); +} diff --git a/modules/nixos-modules/server/network_storage/nfs.nix b/modules/nixos-modules/server/network_storage/nfs.nix new file mode 100644 index 0000000..bad0452 --- /dev/null +++ b/modules/nixos-modules/server/network_storage/nfs.nix @@ -0,0 +1,103 @@ +{ + config, + lib, + ... +}: { + options = { + host.network_storage.nfs = { + enable = lib.mkEnableOption "is this server going to export network storage as nfs shares"; + port = lib.mkOption { + type = lib.types.int; + default = 2049; + description = "port that nfs will run on"; + }; + directories = lib.mkOption { + type = lib.types.listOf ( + lib.types.enum ( + builtins.map ( + directory: directory.folder + ) + config.host.network_storage.directories + ) + ); + description = "list of exported directories to be exported via nfs"; + }; + }; + }; + config = lib.mkMerge [ + { + assertions = [ + { + assertion = !(config.host.network_storage.nfs.enable && !config.host.network_storage.enable); + message = "nfs cant be enabled with network storage disabled"; + } + ]; + } + ( + lib.mkIf (config.host.network_storage.nfs.enable && config.host.network_storage.enable) { + services.nfs = { + settings = { + nfsd = { + threads = 32; + port = config.host.network_storage.nfs.port; + }; + }; + server = { + enable = true; + + lockdPort = 4001; + mountdPort = 4002; + statdPort = 4000; + + exports = lib.strings.concatLines ( + [ + "${config.host.network_storage.export_directory} 100.64.0.0/10(rw,fsid=0,no_subtree_check)" + ] + ++ ( + lib.lists.imap0 ( + i: directory: let + createOptions = fsid: "(rw,fsid=${toString fsid},nohide,insecure,no_subtree_check)"; + addresses = [ + # loopback + "127.0.0.1" + "::1" + # local network + # "192.168.0.0/24" + # tailscale + "100.64.0.0/10" + "fd7a:115c:a1e0::/48" + ]; + options = lib.strings.concatStrings ( + lib.strings.intersperse " " ( + lib.lists.imap0 (index: address: "${address}${createOptions (1 + (i * (builtins.length addresses)) + index)}") addresses + ) + ); + in "${directory._directory} ${options}" + ) + ( + builtins.filter ( + directory: lib.lists.any (target: target == directory.folder) config.host.network_storage.nfs.directories + ) + config.host.network_storage.directories + ) + ) + ); + }; + }; + networking.firewall.interfaces.${config.services.tailscale.interfaceName} = let + ports = [ + 111 + config.host.network_storage.nfs.port + config.services.nfs.server.lockdPort + config.services.nfs.server.mountdPort + config.services.nfs.server.statdPort + 20048 + ]; + in { + allowedTCPPorts = ports; + allowedUDPPorts = ports; + }; + } + ) + ]; +} diff --git a/modules/nixos-modules/server/paperless.nix b/modules/nixos-modules/server/paperless.nix new file mode 100644 index 0000000..0243d53 --- /dev/null +++ b/modules/nixos-modules/server/paperless.nix @@ -0,0 +1,110 @@ +{ + config, + lib, + pkgs, + ... +}: let + dataDir = "/var/lib/paperless"; +in { + options.services.paperless = { + subdomain = lib.mkOption { + type = lib.types.str; + description = "subdomain of base domain that paperless will be hosted at"; + default = "paperless"; + }; + database = { + user = lib.mkOption { + type = lib.types.str; + description = "what is the user and database that we are going to use for paperless"; + default = "paperless"; + }; + }; + }; + + config = lib.mkIf config.services.paperless.enable (lib.mkMerge [ + { + host = { + reverse_proxy.subdomains.${config.services.paperless.subdomain} = { + target = "http://${config.services.paperless.address}:${toString config.services.paperless.port}"; + + websockets.enable = true; + forwardHeaders.enable = true; + + extraConfig = '' + # allow large file uploads + client_max_body_size 50000M; + ''; + }; + postgres = { + enable = true; + extraUsers = { + ${config.services.paperless.database.user} = { + isClient = true; + createUser = true; + }; + }; + extraDatabases = { + ${config.services.paperless.database.user} = { + name = config.services.paperless.database.user; + }; + }; + }; + }; + services.paperless = { + configureTika = true; + settings = { + PAPERLESS_URL = "https://${config.services.paperless.subdomain}.${config.host.reverse_proxy.hostname}"; + + PAPERLESS_DBENGINE = "postgresql"; + PAPERLESS_DBHOST = "/run/postgresql"; + PAPERLESS_DBNAME = config.services.paperless.database.user; + PAPERLESS_DBUSER = config.services.paperless.database.user; + }; + }; + } + (lib.mkIf config.services.fail2ban.enable { + environment.etc = { + "fail2ban/filter.d/paperless.local".text = ( + pkgs.lib.mkDefault (pkgs.lib.mkAfter '' + [Definition] + failregex = Login failed for user `.*` from (?:IP|private IP) ``\.$ + ignoreregex = + + '') + ); + }; + + services.fail2ban = { + jails = { + paperless.settings = { + enabled = true; + filter = "paperless"; + action = ''iptables-multiport[name=HTTP, port="http,https"]''; + logpath = "${config.services.paperless.dataDir}/log/*.log"; + backend = "auto"; + findtime = 600; + bantime = 600; + maxretry = 5; + }; + }; + }; + }) + (lib.mkIf config.host.impermanence.enable { + assertions = [ + { + assertion = config.services.paperless.dataDir == dataDir; + message = "paperless data location does not match persistence"; + } + ]; + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = dataDir; + user = "paperless"; + group = "paperless"; + } + ]; + }; + }) + ]); +} diff --git a/modules/nixos-modules/server/podman.nix b/modules/nixos-modules/server/podman.nix new file mode 100644 index 0000000..9301140 --- /dev/null +++ b/modules/nixos-modules/server/podman.nix @@ -0,0 +1,73 @@ +{ + lib, + config, + ... +}: { + options.host.podman = { + enable = lib.mkEnableOption "should podman be enabled on this computer"; + macvlan = { + subnet = lib.mkOption { + type = lib.types.str; + description = "Subnet for macvlan address range"; + }; + gateway = lib.mkOption { + type = lib.types.str; + description = "Gateway for macvlan"; + # TODO: see if we can default this to systemd network gateway + }; + networkInterface = lib.mkOption { + type = lib.types.str; + description = "Parent network interface for macvlan"; + # TODO: see if we can default this some interface? + }; + }; + }; + config = lib.mkIf config.host.podman.enable { + systemd = { + services = { + # "podman-network-macvlan" = { + # path = [pkgs.podman]; + # serviceConfig = { + # Type = "oneshot"; + # RemainAfterExit = true; + # ExecStop = "podman network rm -f macvlan"; + # }; + # script = '' + # podman network inspect macvlan || podman network create --driver macvlan --subnet ${config.host.podman.macvlan.subnet} --gateway ${config.host.podman.macvlan.gateway} --opt parent=${config.host.podman.macvlan.networkInterface} macvlan + # ''; + # partOf = ["podman-compose-root.target"]; + # wantedBy = ["podman-compose-root.target"]; + # }; + }; + # disable computer sleeping + targets = { + # Root service + # When started, this will automatically create all resources and start + # the containers. When stopped, this will teardown all resources. + "podman-compose-root" = { + unitConfig = { + Description = "Root target for podman targets."; + }; + wantedBy = ["multi-user.target"]; + }; + }; + }; + + virtualisation = { + # Runtime + podman = { + enable = true; + autoPrune.enable = true; + dockerCompat = true; + # defaultNetwork.settings = { + # # Required for container networking to be able to use names. + # dns_enabled = true; + # }; + }; + + oci-containers = { + backend = "podman"; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/postgres.nix b/modules/nixos-modules/server/postgres.nix new file mode 100644 index 0000000..71ce44c --- /dev/null +++ b/modules/nixos-modules/server/postgres.nix @@ -0,0 +1,121 @@ +{ + config, + lib, + pkgs, + ... +}: let + dataDir = "/var/lib/postgresql/16"; + adminUsers = lib.lists.filter (user: user.isAdmin) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); + clientUsers = lib.lists.filter (user: user.isClient) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); + createUsers = lib.lists.filter (user: user.createUser) (lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraUsers); + createDatabases = lib.attrsets.mapAttrsToList (_: user: user) config.host.postgres.extraDatabases; +in { + options = { + host.postgres = { + enable = lib.mkEnableOption "enable postgres"; + extraUsers = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + name = lib.mkOption { + type = lib.types.str; + default = name; + }; + isAdmin = lib.mkOption { + type = lib.types.bool; + default = false; + }; + isClient = lib.mkOption { + type = lib.types.bool; + default = false; + }; + createUser = lib.mkOption { + type = lib.types.bool; + default = false; + }; + }; + })); + default = {}; + }; + extraDatabases = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + name = lib.mkOption { + type = lib.types.str; + default = name; + }; + }; + })); + default = {}; + }; + }; + }; + + config = lib.mkIf config.host.postgres.enable (lib.mkMerge [ + { + services = { + postgresql = { + enable = true; + package = pkgs.postgresql_16; + ensureUsers = + [ + { + name = "postgres"; + } + ] + ++ ( + builtins.map (user: { + name = user.name; + ensureDBOwnership = true; + }) + createUsers + ); + ensureDatabases = builtins.map (database: database.name) createDatabases; + identMap = + '' + # ArbitraryMapName systemUser DBUser + + # Administration Users + superuser_map root postgres + superuser_map postgres postgres + '' + + ( + lib.strings.concatLines (builtins.map (user: "superuser_map ${user.name} postgres") adminUsers) + ) + + '' + + # Client Users + '' + + ( + lib.strings.concatLines (builtins.map (user: "user_map ${user.name} ${user.name}") clientUsers) + ); + # configuration here lets users access the db that matches their name and lets user postgres access everything + authentication = pkgs.lib.mkOverride 10 '' + # type database DBuser origin-address auth-method optional_ident_map + local all postgres peer map=superuser_map + local sameuser all peer map=user_map + ''; + }; + }; + } + + (lib.mkIf config.host.impermanence.enable { + assertions = [ + { + assertion = config.services.postgresql.dataDir == dataDir; + message = "postgres data directory does not match persistence"; + } + ]; + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = dataDir; + user = "postgres"; + group = "postgres"; + } + ]; + }; + }) + ]); +} diff --git a/modules/nixos-modules/server/qbittorent.nix b/modules/nixos-modules/server/qbittorent.nix new file mode 100644 index 0000000..9b7b7e8 --- /dev/null +++ b/modules/nixos-modules/server/qbittorent.nix @@ -0,0 +1,160 @@ +{ + lib, + pkgs, + config, + ... +}: let + qbittorent_data_directory = "/var/lib/qbittorrent"; +in { + options.services.qbittorrent = { + enable = lib.mkEnableOption "should the headless qbittorrent service be enabled"; + + dataDir = lib.mkOption { + type = lib.types.path; + default = "/var/lib/qbittorrent"; + description = lib.mdDoc '' + The directory where qBittorrent stores its data files. + ''; + }; + + mediaDir = lib.mkOption { + type = lib.types.path; + description = lib.mdDoc '' + The directory to create to store qbittorrent media. + ''; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "qbittorrent"; + description = lib.mdDoc '' + User account under which qBittorrent runs. + ''; + }; + + group = lib.mkOption { + type = lib.types.str; + default = "qbittorrent"; + description = lib.mdDoc '' + Group under which qBittorrent runs. + ''; + }; + + webPort = lib.mkOption { + type = lib.types.port; + default = 8080; + description = lib.mdDoc '' + qBittorrent web UI port. + ''; + }; + + openFirewall = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Open services.qBittorrent.webPort to the outside network."; + }; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.qbittorrent-nox; + defaultText = lib.literalExpression "pkgs.qbittorrent-nox"; + description = "The qbittorrent package to use."; + }; + }; + + config = lib.mkIf config.services.qbittorrent.enable (lib.mkMerge [ + { + networking.firewall = lib.mkIf config.services.qbittorrent.openFirewall { + allowedTCPPorts = [config.services.qbittorrent.webPort]; + }; + + systemd.services.qbittorrent = { + # based on the plex.nix service module and + # https://github.com/qbittorrent/qBittorrent/blob/master/dist/unix/systemd/qbittorrent-nox%40.service.in + description = "qBittorrent-nox service"; + documentation = ["man:qbittorrent-nox(1)"]; + after = ["network.target"]; + wantedBy = ["multi-user.target"]; + + serviceConfig = { + Type = "simple"; + User = config.services.qbittorrent.user; + Group = config.services.qbittorrent.group; + + # Run the pre-start script with full permissions (the "!" prefix) so it + # can create the data directory if necessary. + ExecStartPre = let + preStartScript = pkgs.writeScript "qbittorrent-run-prestart" '' + #!${pkgs.bash}/bin/bash + + # Create data directory if it doesn't exist + if ! test -d "$QBT_PROFILE"; then + echo "Creating initial qBittorrent data directory in: $QBT_PROFILE" + install -d -m 0755 -o "${config.services.qbittorrent.user}" -g "${config.services.qbittorrent.group}" "$QBT_PROFILE" + fi + ''; + in "!${preStartScript}"; + + #ExecStart = "${pkgs.qbittorrent-nox}/bin/qbittorrent-nox"; + ExecStart = "${config.services.qbittorrent.package}/bin/qbittorrent-nox"; + # To prevent "Quit & shutdown daemon" from working; we want systemd to + # manage it! + #Restart = "on-success"; + #UMask = "0002"; + #LimitNOFILE = cfg.openFilesLimit; + }; + + environment = { + QBT_PROFILE = config.services.qbittorrent.dataDir; + QBT_WEBUI_PORT = toString config.services.qbittorrent.webPort; + }; + }; + } + (lib.mkIf config.host.impermanence.enable { + fileSystems."/persist/system/qbittorrent".neededForBoot = true; + + host.storage.pool.extraDatasets = { + # sops age key needs to be available to pre persist for user generation + "persist/system/qbittorrent" = { + type = "zfs_fs"; + mountpoint = "/persist/system/qbittorrent"; + options = { + canmount = "on"; + }; + }; + }; + + assertions = [ + { + assertion = config.services.qbittorrent.dataDir == qbittorent_data_directory; + message = "qbittorrent data directory does not match persistence"; + } + ]; + + environment.persistence = { + "/persist/system/root" = { + directories = [ + { + directory = qbittorent_data_directory; + user = "qbittorrent"; + group = "qbittorrent"; + } + ]; + }; + + "/persist/system/qbittorrent" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = config.services.qbittorrent.mediaDir; + user = "qbittorrent"; + group = "qbittorrent"; + mode = "1775"; + } + ]; + }; + }; + }) + ]); +} diff --git a/modules/nixos-modules/server/reverse_proxy.nix b/modules/nixos-modules/server/reverse_proxy.nix new file mode 100644 index 0000000..26b4374 --- /dev/null +++ b/modules/nixos-modules/server/reverse_proxy.nix @@ -0,0 +1,128 @@ +{ + lib, + config, + ... +}: let + dataDir = "/var/lib/acme"; + httpPort = 80; + httpsPort = 443; +in { + options.host.reverse_proxy = { + enable = lib.mkEnableOption "turn on the reverse proxy"; + hostname = lib.mkOption { + type = lib.types.str; + description = "what host name are we going to be proxying from"; + }; + forceSSL = lib.mkOption { + type = lib.types.bool; + description = "force connections to use https"; + default = config.host.reverse_proxy.enableACME; + }; + enableACME = lib.mkOption { + type = lib.types.bool; + description = "auto renew certificates"; + default = true; + }; + subdomains = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + subdomain = lib.mkOption { + type = lib.types.str; + description = "what is the default subdomain to be used for this application to be used for"; + default = name; + }; + extraSubdomains = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "extra domains that should be configured for this domain"; + default = []; + }; + + target = lib.mkOption { + type = lib.types.str; + description = "what url will all traffic to this application be forwarded to"; + }; + + websockets.enable = lib.mkEnableOption "should the default config proxy websockets"; + + forwardHeaders.enable = lib.mkEnableOption "should the default config contain forward headers"; + + extraConfig = lib.mkOption { + type = lib.types.lines; + default = ""; + description = '' + These lines go to the end of the upstream verbatim. + ''; + }; + }; + })); + }; + }; + + config = lib.mkIf config.host.reverse_proxy.enable (lib.mkMerge [ + { + security.acme = lib.mkIf config.host.reverse_proxy.enableACME { + acceptTerms = true; + defaults.email = "jan-leila@protonmail.com"; + }; + + services.nginx = { + enable = true; + virtualHosts = lib.mkMerge ( + lib.lists.flatten ( + lib.attrsets.mapAttrsToList ( + name: value: let + hostConfig = { + forceSSL = config.host.reverse_proxy.forceSSL; + enableACME = config.host.reverse_proxy.enableACME; + locations = { + "/" = { + proxyPass = value.target; + proxyWebsockets = value.websockets.enable; + recommendedProxySettings = value.forwardHeaders.enable; + extraConfig = + value.extraConfig; + }; + }; + }; + in ( + [ + { + ${"${value.subdomain}.${config.host.reverse_proxy.hostname}"} = hostConfig; + } + ] + ++ builtins.map (subdomain: {${"${subdomain}.${config.host.reverse_proxy.hostname}"} = hostConfig;}) + value.extraSubdomains + ) + ) + config.host.reverse_proxy.subdomains + ) + ); + }; + + networking.firewall.allowedTCPPorts = [ + httpPort + httpsPort + ]; + } + (lib.mkIf config.host.impermanence.enable { + # TODO: figure out how to write an assertion for this + # assertions = [ + # { + # assertion = security.acme.certs..directory == dataDir; + # message = "postgres data directory does not match persistence"; + # } + # ]; + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = dataDir; + user = "acme"; + group = "acme"; + } + ]; + }; + }) + ]); +} diff --git a/modules/nixos-modules/server/searx.nix b/modules/nixos-modules/server/searx.nix new file mode 100644 index 0000000..d357308 --- /dev/null +++ b/modules/nixos-modules/server/searx.nix @@ -0,0 +1,72 @@ +{ + config, + lib, + inputs, + ... +}: { + options.services.searx = { + subdomain = lib.mkOption { + type = lib.types.str; + description = "subdomain of base domain that searx will be hosted at"; + default = "searx"; + }; + }; + + config = lib.mkIf config.services.searx.enable { + sops.secrets = { + "services/searx" = { + sopsFile = "${inputs.secrets}/defiant-services.yaml"; + }; + }; + host = { + reverse_proxy.subdomains.searx = { + subdomain = config.services.searx.subdomain; + target = "http://localhost:${toString config.services.searx.settings.server.port}"; + }; + }; + services.searx = { + environmentFile = config.sops.secrets."services/searx".path; + + # Rate limiting + limiterSettings = { + real_ip = { + x_for = 1; + ipv4_prefix = 32; + ipv6_prefix = 56; + }; + + botdetection = { + ip_limit = { + filter_link_local = true; + link_token = true; + }; + }; + }; + + settings = { + server = { + port = 8083; + secret_key = "@SEARXNG_SECRET@"; + }; + + # Search engine settings + search = { + safe_search = 2; + autocomplete_min = 2; + autocomplete = "duckduckgo"; + }; + + # Enabled plugins + enabled_plugins = [ + "Basic Calculator" + "Hash plugin" + "Tor check plugin" + "Open Access DOI rewrite" + "Hostnames plugin" + "Unit converter plugin" + "Tracker URL remover" + ]; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/wyoming.nix b/modules/nixos-modules/server/wyoming.nix new file mode 100644 index 0000000..4894dd4 --- /dev/null +++ b/modules/nixos-modules/server/wyoming.nix @@ -0,0 +1,63 @@ +{ + lib, + config, + ... +}: { + options.services.wyoming.enable = lib.mkEnableOption "should wyoming be enabled on this device"; + config = lib.mkIf config.services.wyoming.enable (lib.mkMerge [ + { + services.wyoming = { + # Text to speech + piper = { + servers = { + "en" = { + enable = true; + # see https://github.com/rhasspy/rhasspy3/blob/master/programs/tts/piper/script/download.py + voice = "en-us-amy-low"; + uri = "tcp://0.0.0.0:10200"; + speaker = 0; + }; + }; + }; + + # Speech to text + faster-whisper = { + servers = { + "en" = { + enable = true; + # see https://github.com/rhasspy/rhasspy3/blob/master/programs/asr/faster-whisper/script/download.py + model = "tiny-int8"; + language = "en"; + uri = "tcp://0.0.0.0:10300"; + device = "cpu"; + }; + }; + }; + + openwakeword = { + enable = true; + uri = "tcp://0.0.0.0:10400"; + preloadModels = [ + "ok_nabu" + ]; + # TODO: custom models + }; + }; + + # needs access to /proc/cpuinfo + systemd.services."wyoming-faster-whisper-en".serviceConfig.ProcSubset = lib.mkForce "all"; + } + (lib.mkIf config.host.impermanence.enable { + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = "/var/lib/private/wyoming"; + mode = "0700"; + } + ]; + }; + }) + ]); +} diff --git a/modules/nixos-modules/ssh.nix b/modules/nixos-modules/ssh.nix new file mode 100644 index 0000000..6f5fac1 --- /dev/null +++ b/modules/nixos-modules/ssh.nix @@ -0,0 +1,28 @@ +{ + lib, + config, + ... +}: { + config = lib.mkMerge [ + { + services = { + openssh = { + enable = true; + ports = [22]; + settings = { + PasswordAuthentication = false; + UseDns = true; + X11Forwarding = false; + }; + }; + }; + } + (lib.mkIf config.host.impermanence.enable { + environment.persistence."/persist/system/root" = { + files = lib.lists.flatten ( + builtins.map (hostKey: [hostKey.path "${hostKey.path}.pub"]) config.services.openssh.hostKeys + ); + }; + }) + ]; +} diff --git a/modules/nixos-modules/steam.nix b/modules/nixos-modules/steam.nix new file mode 100644 index 0000000..20c0978 --- /dev/null +++ b/modules/nixos-modules/steam.nix @@ -0,0 +1,9 @@ +{...}: { + programs = { + steam = { + remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play + dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server + localNetworkGameTransfers.openFirewall = true; # Open ports in the firewall for Steam Local Network Game Transfers + }; + }; +} diff --git a/modules/nixos-modules/sync.nix b/modules/nixos-modules/sync.nix new file mode 100644 index 0000000..8915dc8 --- /dev/null +++ b/modules/nixos-modules/sync.nix @@ -0,0 +1,68 @@ +{ + config, + lib, + outputs, + ... +}: let + mountDir = "/mnt/sync"; + configDir = "/etc/syncthing"; +in { + config = lib.mkMerge [ + { + systemd = lib.mkIf config.services.syncthing.enable { + tmpfiles.rules = [ + "d ${mountDir} 2755 syncthing syncthing -" + "d ${config.services.syncthing.dataDir} 775 syncthing syncthing -" + "d ${config.services.syncthing.configDir} 755 syncthing syncthing -" + ]; + }; + } + (lib.mkIf config.services.syncthing.enable (lib.mkMerge [ + { + services.syncthing = { + user = "syncthing"; + group = "syncthing"; + dataDir = "${mountDir}/default"; + configDir = configDir; + overrideDevices = true; + overrideFolders = true; + configuration = outputs.syncthingConfiguration; + deviceName = config.networking.hostName; + }; + } + + (lib.mkIf config.host.impermanence.enable { + assertions = + [ + { + assertion = config.services.syncthing.configDir == configDir; + message = "syncthing config dir does not match persistence"; + } + ] + ++ lib.attrsets.mapAttrsToList (_: folder: { + assertion = lib.strings.hasPrefix mountDir folder.path; + message = "syncthing folder ${folder.label} is stored at ${folder.path} which not under the persisted path of ${mountDir}"; + }) + config.services.syncthing.settings.folders; + environment.persistence = { + "/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = mountDir; + user = "syncthing"; + group = "syncthing"; + } + { + directory = configDir; + user = "syncthing"; + group = "syncthing"; + } + ]; + }; + }; + }) + ])) + ]; +} diff --git a/modules/nixos-modules/system.nix b/modules/nixos-modules/system.nix new file mode 100644 index 0000000..b839067 --- /dev/null +++ b/modules/nixos-modules/system.nix @@ -0,0 +1,13 @@ +{...}: { + nix = { + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 7d"; + }; + optimise = { + automatic = true; + dates = ["weekly"]; + }; + }; +} diff --git a/modules/nixos-modules/tailscale.nix b/modules/nixos-modules/tailscale.nix new file mode 100644 index 0000000..db664e8 --- /dev/null +++ b/modules/nixos-modules/tailscale.nix @@ -0,0 +1,34 @@ +{ + config, + lib, + ... +}: let + tailscale_data_directory = "/var/lib/tailscale"; +in { + options.host.tailscale = { + enable = lib.mkEnableOption "should tailscale be enabled on this computer"; + }; + + config = lib.mkIf config.services.tailscale.enable ( + lib.mkMerge [ + { + # any configs we want shared between all machines + } + (lib.mkIf config.host.impermanence.enable { + environment.persistence = { + "/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = tailscale_data_directory; + user = "root"; + group = "root"; + } + ]; + }; + }; + }) + ] + ); +} diff --git a/modules/nixos-modules/users.nix b/modules/nixos-modules/users.nix new file mode 100644 index 0000000..a774e44 --- /dev/null +++ b/modules/nixos-modules/users.nix @@ -0,0 +1,369 @@ +{ + lib, + config, + inputs, + ... +}: let + SOPS_AGE_KEY_DIRECTORY = import ../../const/sops_age_key_directory.nix; + + host = config.host; + + principleUsers = host.principleUsers; + terminalUsers = host.terminalUsers; + normalUsers = host.normalUsers; + + uids = { + leyla = 1000; + eve = 1002; + jellyfin = 2000; + forgejo = 2002; + adguardhome = 2003; + hass = 2004; + syncthing = 2007; + ollama = 2008; + git = 2009; + immich = 2010; + qbittorrent = 2011; + paperless = 2012; + }; + + gids = { + leyla = 1000; + eve = 1002; + users = 100; + jellyfin_media = 2001; + jellyfin = 2000; + forgejo = 2002; + adguardhome = 2003; + hass = 2004; + syncthing = 2007; + ollama = 2008; + git = 2009; + immich = 2010; + qbittorrent = 2011; + paperless = 2012; + }; + + users = config.users.users; + leyla = users.leyla.name; + eve = users.eve.name; +in { + config = lib.mkMerge [ + { + # principle users are by definition trusted + nix.settings.trusted-users = builtins.map (user: user.name) principleUsers; + + # we should only be able to ssh into principle users of a computer who are also set up for terminal access + services.openssh.settings.AllowUsers = builtins.map (user: user.name) (lib.lists.intersectLists terminalUsers principleUsers); + + # we need to set up env variables to nix can find keys to decrypt passwords on rebuild + environment = { + sessionVariables = { + SOPS_AGE_KEY_DIRECTORY = SOPS_AGE_KEY_DIRECTORY; + SOPS_AGE_KEY_FILE = "${SOPS_AGE_KEY_DIRECTORY}/key.txt"; + }; + }; + + # set up user passwords + sops = { + defaultSopsFormat = "yaml"; + gnupg.sshKeyPaths = []; + + age = { + keyFile = "/var/lib/sops-nix/key.txt"; + sshKeyPaths = []; + # generateKey = true; + }; + + secrets = { + "passwords/leyla" = { + neededForUsers = true; + sopsFile = "${inputs.secrets}/user-passwords.yaml"; + }; + "passwords/eve" = { + neededForUsers = true; + sopsFile = "${inputs.secrets}/user-passwords.yaml"; + }; + }; + }; + + users = { + mutableUsers = false; + users = { + leyla = { + uid = lib.mkForce uids.leyla; + name = lib.mkForce host.users.leyla.name; + description = "Leyla"; + extraGroups = + (lib.lists.optionals host.users.leyla.isNormalUser ["networkmanager"]) + ++ (lib.lists.optionals host.users.leyla.isPrincipleUser ["wheel" "dialout"]) + ++ (lib.lists.optionals host.users.leyla.isDesktopUser ["adbusers"]); + hashedPasswordFile = config.sops.secrets."passwords/leyla".path; + isNormalUser = host.users.leyla.isNormalUser; + isSystemUser = !host.users.leyla.isNormalUser; + group = config.users.users.leyla.name; + }; + + eve = { + uid = lib.mkForce uids.eve; + name = lib.mkForce host.users.eve.name; + description = "Eve"; + extraGroups = + lib.optionals host.users.eve.isNormalUser ["networkmanager"] + ++ (lib.lists.optionals host.users.eve.isPrincipleUser ["wheel"]); + hashedPasswordFile = config.sops.secrets."passwords/eve".path; + isNormalUser = host.users.eve.isNormalUser; + isSystemUser = !host.users.eve.isNormalUser; + group = config.users.users.eve.name; + }; + + jellyfin = { + uid = lib.mkForce uids.jellyfin; + isSystemUser = true; + group = config.users.users.jellyfin.name; + }; + + forgejo = { + uid = lib.mkForce uids.forgejo; + isSystemUser = true; + group = config.users.users.forgejo.name; + }; + + adguardhome = { + uid = lib.mkForce uids.adguardhome; + isSystemUser = true; + group = config.users.users.adguardhome.name; + }; + + hass = { + uid = lib.mkForce uids.hass; + isSystemUser = true; + group = config.users.users.hass.name; + }; + + syncthing = { + uid = lib.mkForce uids.syncthing; + isSystemUser = true; + group = config.users.users.syncthing.name; + }; + + ollama = { + uid = lib.mkForce uids.ollama; + isSystemUser = true; + group = config.users.users.ollama.name; + }; + + git = { + uid = lib.mkForce uids.git; + isSystemUser = !config.services.forgejo.enable; + isNormalUser = config.services.forgejo.enable; + group = config.users.users.git.name; + }; + + immich = { + uid = lib.mkForce uids.immich; + isSystemUser = true; + group = config.users.users.immich.name; + }; + + qbittorrent = { + uid = lib.mkForce uids.qbittorrent; + isNormalUser = true; + group = config.users.users.qbittorrent.name; + }; + + paperless = { + uid = lib.mkForce uids.paperless; + isSystemUser = true; + group = config.users.users.paperless.name; + }; + }; + + groups = { + leyla = { + gid = lib.mkForce gids.leyla; + members = [ + leyla + ]; + }; + + eve = { + gid = lib.mkForce gids.eve; + members = [ + eve + ]; + }; + + users = { + gid = lib.mkForce gids.users; + members = [ + leyla + eve + ]; + }; + + jellyfin_media = { + gid = lib.mkForce gids.jellyfin_media; + members = [ + users.jellyfin.name + leyla + eve + ]; + }; + + jellyfin = { + gid = lib.mkForce gids.jellyfin; + members = [ + users.jellyfin.name + # leyla + ]; + }; + + forgejo = { + gid = lib.mkForce gids.forgejo; + members = [ + users.forgejo.name + # leyla + ]; + }; + + adguardhome = { + gid = lib.mkForce gids.adguardhome; + members = [ + users.adguardhome.name + # leyla + ]; + }; + + hass = { + gid = lib.mkForce gids.hass; + members = [ + users.hass.name + # leyla + ]; + }; + + syncthing = { + gid = lib.mkForce gids.syncthing; + members = [ + users.syncthing.name + leyla + eve + ]; + }; + + ollama = { + gid = lib.mkForce gids.ollama; + members = [ + users.ollama.name + ]; + }; + + git = { + gid = lib.mkForce gids.git; + members = [ + users.git.name + ]; + }; + + immich = { + gid = lib.mkForce gids.immich; + members = [ + users.immich.name + # leyla + ]; + }; + + qbittorrent = { + gid = lib.mkForce gids.qbittorrent; + members = [ + users.qbittorrent.name + leyla + ]; + }; + + paperless = { + gid = lib.mkForce gids.paperless; + members = [ + users.paperless.name + ]; + }; + }; + }; + } + (lib.mkIf config.host.impermanence.enable { + boot.initrd.postResumeCommands = lib.mkAfter ( + lib.strings.concatLines (builtins.map (user: "zfs rollback -r rpool/local/home/${user.name}@blank") + normalUsers) + ); + + systemd = { + tmpfiles.rules = + builtins.map ( + user: "d /persist/home/${user.name} 700 ${user.name} ${user.name} -" + ) + normalUsers; + }; + + fileSystems = lib.mkMerge [ + { + ${SOPS_AGE_KEY_DIRECTORY}.neededForBoot = true; + } + ( + builtins.listToAttrs ( + builtins.map (user: + lib.attrsets.nameValuePair "/persist/home/${user.name}" { + neededForBoot = true; + }) + normalUsers + ) + ) + ( + builtins.listToAttrs ( + builtins.map (user: + lib.attrsets.nameValuePair "/home/${user.name}" { + neededForBoot = true; + }) + normalUsers + ) + ) + ]; + + host.storage.pool.extraDatasets = lib.mkMerge ( + [ + { + # sops age key needs to be available to pre persist for user generation + "local/system/sops" = { + type = "zfs_fs"; + mountpoint = SOPS_AGE_KEY_DIRECTORY; + options = { + atime = "off"; + relatime = "off"; + canmount = "on"; + }; + }; + } + ] + ++ ( + builtins.map (user: { + "local/home/${user.name}" = { + type = "zfs_fs"; + mountpoint = "/home/${user.name}"; + options = { + canmount = "on"; + }; + postCreateHook = '' + zfs snapshot rpool/local/home/${user.name}@blank + ''; + }; + "persist/home/${user.name}" = { + type = "zfs_fs"; + mountpoint = "/persist/home/${user.name}"; + }; + }) + normalUsers + ) + ); + }) + ]; +} diff --git a/modules/system-modules/default.nix b/modules/system-modules/default.nix new file mode 100644 index 0000000..637b6b5 --- /dev/null +++ b/modules/system-modules/default.nix @@ -0,0 +1,9 @@ +# this folder container modules that are for nixos and darwin +{...}: { + imports = [ + ./home-manager + ./system.nix + ./nix-development.nix + ./users.nix + ]; +} diff --git a/modules/system-modules/home-manager/default.nix b/modules/system-modules/home-manager/default.nix new file mode 100644 index 0000000..3745b8f --- /dev/null +++ b/modules/system-modules/home-manager/default.nix @@ -0,0 +1,2 @@ +# modules in this folder are to adapt home-manager modules configs to system-module configs +{...}: {} diff --git a/modules/system-modules/nix-development.nix b/modules/system-modules/nix-development.nix new file mode 100644 index 0000000..6eeddc4 --- /dev/null +++ b/modules/system-modules/nix-development.nix @@ -0,0 +1,26 @@ +{ + lib, + pkgs, + config, + inputs, + ... +}: { + options.host.nix-development.enable = lib.mkEnableOption "should desktop configuration be enabled"; + + config = lib.mkMerge [ + { + host.nix-development.enable = lib.mkDefault true; + } + (lib.mkIf config.host.nix-development.enable { + nix = { + nixPath = ["nixpkgs=${inputs.nixpkgs}"]; + }; + environment.systemPackages = with pkgs; [ + # nix language server + nil + # nix formatter + alejandra + ]; + }) + ]; +} diff --git a/modules/system-modules/system.nix b/modules/system-modules/system.nix new file mode 100644 index 0000000..f464835 --- /dev/null +++ b/modules/system-modules/system.nix @@ -0,0 +1,7 @@ +{...}: { + nix = { + settings = { + experimental-features = ["nix-command" "flakes"]; + }; + }; +} diff --git a/modules/system-modules/users.nix b/modules/system-modules/users.nix new file mode 100644 index 0000000..cd9c900 --- /dev/null +++ b/modules/system-modules/users.nix @@ -0,0 +1,113 @@ +{ + lib, + config, + ... +}: let + host = config.host; + + hostUsers = host.hostUsers; + principleUsers = host.principleUsers; +in { + options.host = { + users = lib.mkOption { + default = {}; + type = lib.types.attrsOf (lib.types.submodule ({ + config, + name, + ... + }: { + options = { + name = lib.mkOption { + type = lib.types.str; + default = name; + description = '' + What should this users name on the system be + ''; + defaultText = lib.literalExpression "config.host.users.\${name}.name"; + }; + isPrincipleUser = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + User should be configured as root and have ssh access + ''; + defaultText = lib.literalExpression "config.host.users.\${name}.isPrincipleUser"; + }; + isDesktopUser = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + User should install their desktop applications + ''; + defaultText = lib.literalExpression "config.host.users.\${name}.isDesktopUser"; + }; + isTerminalUser = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + User should install their terminal applications + ''; + defaultText = lib.literalExpression "config.host.users.\${name}.isTerminalUser"; + }; + isNormalUser = lib.mkOption { + type = lib.types.bool; + default = config.isDesktopUser || config.isTerminalUser; + description = '' + User should install their applications and can log in + ''; + defaultText = lib.literalExpression "config.host.users.\${name}.isNormalUser"; + }; + }; + })); + }; + hostUsers = lib.mkOption { + default = lib.attrsets.mapAttrsToList (_: user: user) host.users; + }; + principleUsers = lib.mkOption { + default = lib.lists.filter (user: user.isPrincipleUser) hostUsers; + }; + normalUsers = lib.mkOption { + default = lib.lists.filter (user: user.isNormalUser) hostUsers; + }; + desktopUsers = lib.mkOption { + default = lib.lists.filter (user: user.isDesktopUser) hostUsers; + }; + terminalUsers = lib.mkOption { + default = lib.lists.filter (user: user.isTerminalUser) hostUsers; + }; + }; + + config = { + host.users = { + leyla = { + isPrincipleUser = lib.mkDefault false; + isDesktopUser = lib.mkDefault false; + isTerminalUser = lib.mkDefault false; + }; + eve = { + isPrincipleUser = lib.mkDefault false; + isDesktopUser = lib.mkDefault false; + isTerminalUser = lib.mkDefault false; + }; + }; + + assertions = + ( + builtins.map (user: { + assertion = !(user.isPrincipleUser && !user.isNormalUser); + message = '' + Non normal user ${user.name} can not be a principle user. + ''; + }) + hostUsers + ) + ++ [ + { + assertion = (builtins.length principleUsers) > 0; + message = '' + At least one user must be a principle user. + ''; + } + ]; + }; +} diff --git a/nix-config-secrets b/nix-config-secrets new file mode 160000 index 0000000..f016767 --- /dev/null +++ b/nix-config-secrets @@ -0,0 +1 @@ +Subproject commit f016767c13aa36dde91503f7a9f01bdd02468045 diff --git a/overlays/intellij.nix b/overlays/intellij.nix deleted file mode 100644 index c907588..0000000 --- a/overlays/intellij.nix +++ /dev/null @@ -1,18 +0,0 @@ -_: { - # nixpkgs.overlays = [ - # (self: super: { - # # idea is too out of date for android gradle things - # jetbrains = { - # jdk = super.jdk17; - # idea-community = super.jetbrains.idea-community.overrideAttrs (oldAttrs: rec { - # version = "2023.3.3"; - # name = "idea-community-${version}"; - # src = super.fetchurl { - # sha256 = "sha256-3BI97Tx+3onnzT1NXkb62pa4dj9kjNDNvFt9biYgP9I="; - # url = "https://download.jetbrains.com/idea/ideaIC-${version}.tar.gz"; - # }; - # }); - # }; - # }) - # ]; -} diff --git a/overlays/vscodium.nix b/overlays/vscodium.nix deleted file mode 100644 index 7c5f863..0000000 --- a/overlays/vscodium.nix +++ /dev/null @@ -1,14 +0,0 @@ -_: { - # nixpkgs.overlays = [ - # (self: super: { - # # ui is broken on 1.84 - # vscodium = super.vscodium.overrideAttrs (oldAttrs: rec { - # version = "1.85.2.24019"; - # src = super.fetchurl { - # sha256 = "sha256-OBGFXOSN+Oq9uj/5O6tF0Kp7rxTY1AzNbhLK8G+EqVk="; - # url = "https://github.com/VSCodium/vscodium/releases/download/${version}/VSCodium-linux-x64-${version}.tar.gz"; - # }; - # }); - # }) - # ]; -} diff --git a/pkgs/default.nix b/pkgs/default.nix deleted file mode 100644 index 87a13d7..0000000 --- a/pkgs/default.nix +++ /dev/null @@ -1,2 +0,0 @@ -_: { -} diff --git a/rebuild.sh b/rebuild.sh index 9988b7b..36a1201 100755 --- a/rebuild.sh +++ b/rebuild.sh @@ -7,13 +7,15 @@ else preserve_result=false fi +show_trace=false + while [ $# -gt 0 ]; do case "$1" in --target*|-t*) if [[ "$1" != *=* ]]; then shift; fi # Value is next arg if no `=` target="${1#*=}" ;; - --flake*|-h*) + --flake*|-f*) if [[ "$1" != *=* ]]; then shift; fi flake="${1#*=}" ;; @@ -25,20 +27,29 @@ while [ $# -gt 0 ]; do if [[ "$1" != *=* ]]; then shift; fi user="${1#*=}" ;; + --host*) + if [[ "$1" != *=* ]]; then shift; fi + host="${1#*=}" + ;; --preserve-result) preserve_result=true ;; --no-preserve-result) preserve_result=false ;; + --show-trace) + show_trace=true + ;; --help|-h) echo "--help -h: print this message" echo "--target -t: set the target system to rebuild on" echo "--flake -f: set the flake to rebuild on the target system" echo "--mode -m: set the mode to rebuild flake as on the target system" echo "--user -u: set the user to rebuild flake as on the target system" + echo "--host: set the host that the flake will be rebuilt on (unset for current machine)" echo "--preserve-result: do not remove the generated result folder after building" echo "--no-preserve-result: remove any result folder after building" + echo "--show-trace: show trace on builds" exit 0 ;; *) @@ -54,13 +65,26 @@ flake=${flake:-$target} mode=${mode:-switch} user=${user:-$USER} -if [[ "$target" == "$(hostname)" ]]; +command="nixos-rebuild $mode --sudo --ask-sudo-password --flake .#$flake" + +if [[ $host ]]; then - nixos-rebuild $mode --use-remote-sudo --flake .#$flake -else - nixos-rebuild $mode --use-remote-sudo --target-host $user@$target --flake .#$flake + command="$command --build-host $host" fi +if [[ "$target" != "$(hostname)" ]]; +then + command="$command --target-host $user@$target" +fi + +if [[ "$show_trace" = true ]]; +then + command="$command --show-trace" +fi + +echo $command +$command + if [ -d "result" ]; then if [[ "$preserve_result" == "false" ]]; diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..d7c46b9 --- /dev/null +++ b/shell.nix @@ -0,0 +1,14 @@ +( + import + ( + let + lock = builtins.fromJSON (builtins.readFile ./flake.lock); + in + fetchTarball { + url = lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flake-compat.locked.narHash; + } + ) + {src = ./.;} +) +.shellNix diff --git a/templates/default.nix b/templates/default.nix deleted file mode 100644 index eed7124..0000000 --- a/templates/default.nix +++ /dev/null @@ -1 +0,0 @@ -_: {} diff --git a/users/default.nix b/users/default.nix deleted file mode 100644 index 4c0b5d7..0000000 --- a/users/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{inputs, ...}: { - imports = [./leyla ./ester ./eve]; - - users.mutableUsers = false; - - home-manager.extraSpecialArgs = {inherit inputs;}; -} diff --git a/users/ester/default.nix b/users/ester/default.nix deleted file mode 100644 index 3597d2d..0000000 --- a/users/ester/default.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ - lib, - config, - pkgs, - ... -}: let - cfg = config.users.ester; -in { - options.users.ester = { - isFullUser = lib.mkEnableOption "ester"; - }; - - config = { - nixpkgs.config.allowUnfree = true; - - sops.secrets = lib.mkIf cfg.isFullUser { - "passwords/ester" = { - neededForUsers = true; - sopsFile = ../../secrets/user-passwords.yaml; - }; - }; - - users.users.ester = ( - if cfg.isFullUser - then { - isNormalUser = true; - extraGroups = ["networkmanager"]; - - hashedPasswordFile = config.sops.secrets."passwords/ester".path; - - packages = with pkgs; [ - firefox - bitwarden - discord - ]; - } - else { - isSystemUser = true; - } - ); - }; -} diff --git a/users/eve/default.nix b/users/eve/default.nix deleted file mode 100644 index 16787f8..0000000 --- a/users/eve/default.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ - lib, - config, - pkgs, - ... -}: let - cfg = config.users.eve; -in { - options.users.eve = { - isFullUser = lib.mkEnableOption "eve"; - }; - - config = { - nixpkgs.config.allowUnfree = true; - - sops.secrets = lib.mkIf cfg.isFullUser { - "passwords/eve" = { - neededForUsers = true; - sopsFile = ../../secrets/user-passwords.yaml; - }; - }; - - users.users.eve = ( - if cfg.isFullUser - then { - isNormalUser = true; - extraGroups = ["networkmanager"]; - - hashedPasswordFile = config.sops.secrets."passwords/eve".path; - - packages = with pkgs; [ - firefox - bitwarden - discord - makemkv - signal-desktop - ]; - } - else { - isSystemUser = true; - } - ); - }; -} diff --git a/users/leyla/default.nix b/users/leyla/default.nix deleted file mode 100644 index 20f99ab..0000000 --- a/users/leyla/default.nix +++ /dev/null @@ -1,65 +0,0 @@ -{ - lib, - config, - ... -}: let - cfg = config.users.leyla; -in { - imports = [ - ./packages.nix - ]; - - options.users.leyla = { - isFullUser = lib.mkEnableOption "create usable leyla user"; - isThinUser = lib.mkEnableOption "create usable user but witohut user applications"; - hasGPU = lib.mkEnableOption "installs gpu intensive programs"; - }; - - config = { - nixpkgs.config.allowUnfree = true; - - sops.secrets = lib.mkIf (cfg.isFullUser || cfg.isThinUser) { - "passwords/leyla" = { - neededForUsers = true; - sopsFile = ../../secrets/user-passwords.yaml; - }; - }; - - users.users.leyla = ( - if (cfg.isFullUser || cfg.isThinUser) - then { - isNormalUser = true; - extraGroups = lib.mkMerge [ - ["networkmanager" "wheel"] - ( - lib.mkIf (!cfg.isThinUser) ["adbusers"] - ) - ]; - - hashedPasswordFile = config.sops.secrets."passwords/leyla".path; - - openssh = { - authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJHeItmt8TRW43uNcOC+eIurYC7Eunc0V3LGocQqLaYj leyla@horizon" - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKBiZkg1c2aaNHiieBX4cEziqvJVj9pcDfzUrKU/mO0I leyla@twilight" - ]; - }; - } - else { - isSystemUser = true; - } - ); - - # TODO: this should reference the home directory from the user config - services.openssh.hostKeys = [ - { - comment = "leyla@" + config.networking.hostName; - path = "/home/leyla/.ssh/leyla_" + config.networking.hostName + "_ed25519"; - rounds = 100; - type = "ed25519"; - } - ]; - - home-manager.users.leyla = lib.mkIf (cfg.isFullUser || cfg.isThinUser) (import ./home.nix); - }; -} diff --git a/users/leyla/home.nix b/users/leyla/home.nix deleted file mode 100644 index 118d0cc..0000000 --- a/users/leyla/home.nix +++ /dev/null @@ -1,127 +0,0 @@ -{ - config, - pkgs, - ... -}: { - # Home Manager needs a bit of information about you and the paths it should - # manage. - home = { - username = "leyla"; - homeDirectory = "/home/leyla"; - - # 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. - - # The home.packages option allows you to install Nix packages into your - # environment. - packages = [ - # # Adds the 'hello' command to your environment. It prints a friendly - # # "Hello, world!" when run. - # pkgs.hello - - # # It is sometimes useful to fine-tune packages, for example, by applying - # # overrides. You can do that directly here, just don't forget the - # # parentheses. Maybe you want to install Nerd Fonts with a limited number of - # # fonts? - # (pkgs.nerdfonts.override { fonts = [ "FantasqueSansMono" ]; }) - - # # You can also create simple shell scripts directly inside your - # # configuration. For example, this adds a command 'my-hello' to your - # # environment: - # (pkgs.writeShellScriptBin "my-hello" '' - # echo "Hello, ${config.home.username}!" - # '') - ]; - - # 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/leyla/etc/profile.d/hm-session-vars.sh - # - sessionVariables = { - # EDITOR = "emacs"; - }; - }; - - programs = { - # Let Home Manager install and manage itself. - home-manager.enable = true; - git = { - enable = true; - userName = "Leyla Becker"; - userEmail = "git@jan-leila.com"; - extraConfig.init.defaultBranch = "main"; - }; - }; - - dconf = { - enable = true; - settings = { - "org/gnome/desktop/interface".color-scheme = "prefer-dark"; - - "org/gnome/shell" = { - disable-user-extensions = false; # enables user extensions - enabled-extensions = [ - # Put UUIDs of extensions that you want to enable here. - # If the extension you want to enable is packaged in nixpkgs, - # you can easily get its UUID by accessing its extensionUuid - # field (look at the following example). - pkgs.gnomeExtensions.dash-to-dock.extensionUuid - - # Alternatively, you can manually pass UUID as a string. - # "dash-to-dock@micxgx.gmail.com" - ]; - }; - - "org/gnome/shell/extensions/dash-to-dock" = { - "dock-position" = "LEFT"; - "intellihide-mode" = "ALL_WINDOWS"; - "show-trash" = false; - "require-pressure-to-show" = false; - "show-mounts" = false; - }; - - "org/gnome/settings-daemon/plugins/media-keys" = { - custom-keybindings = [ - "/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/" - ]; - }; - "org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0" = { - binding = "t"; - command = "kgx"; - name = "Open Terminal"; - }; - }; - }; -} diff --git a/users/leyla/packages.nix b/users/leyla/packages.nix deleted file mode 100644 index e206d22..0000000 --- a/users/leyla/packages.nix +++ /dev/null @@ -1,135 +0,0 @@ -{ - lib, - config, - pkgs, - inputs, - ... -}: let - cfg = config.users.leyla; -in { - imports = [ - ../../overlays/intellij.nix - ../../overlays/vscodium.nix - ]; - - nixpkgs = { - overlays = [ - inputs.nix-vscode-extensions.overlays.default - ]; - }; - - programs = { - bash.shellAliases = lib.mkIf cfg.isFullUser { - code = "codium"; - }; - - steam = lib.mkIf cfg.isFullUser { - enable = true; - remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play - dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server - }; - - noisetorch.enable = cfg.isFullUser; - - adb.enable = cfg.isFullUser; - }; - - users.users.leyla.packages = lib.mkIf (cfg.isFullUser || cfg.isThinUser) ( - lib.mkMerge [ - ( - with pkgs; [ - # comand line tools - yt-dlp - ffmpeg - imagemagick - ] - ) - ( - lib.mkIf (!cfg.isThinUser) ( - with pkgs; [ - #foss platforms - signal-desktop - bitwarden - firefox - ungoogled-chromium - libreoffice - inkscape - gimp - krita - freecad - # cura - kicad-small - makemkv - transmission_4-gtk - onionshare - easytag - # rhythmbox - (lib.mkIf cfg.hasGPU obs-studio) - # wireshark - # rpi-imager - # fritzing - - # proprietary platforms - discord - obsidian - steam - (lib.mkIf cfg.hasGPU davinci-resolve) - - # development tools - (vscode-with-extensions.override { - vscode = vscodium; - vscodeExtensions = with open-vsx; - [ - # vs code feel extensions - ms-vscode.atom-keybindings - akamud.vscode-theme-onedark - streetsidesoftware.code-spell-checker - streetsidesoftware.code-spell-checker-german - streetsidesoftware.code-spell-checker-italian - jeanp413.open-remote-ssh - - # nix extensions - pinage404.nix-extension-pack - jnoortheen.nix-ide - - # html extensions - formulahendry.auto-rename-tag - ms-vscode.live-server - - # js extensions - dsznajder.es7-react-js-snippets - dbaeumer.vscode-eslint - standard.vscode-standard - firsttris.vscode-jest-runner - stylelint.vscode-stylelint - tauri-apps.tauri-vscode - - # misc extensions - bungcip.better-toml - ] - ++ (with vscode-marketplace; [ - # js extensions - karyfoundation.nearley - ]); - }) - androidStudioPackages.canary - jetbrains.idea-community - dbeaver-bin - bruno - - # system tools - protonvpn-gui - openvpn - nextcloud-client - noisetorch - - # hardware managment tools - (lib.mkIf config.hardware.piperMouse.enable piper) - (lib.mkIf config.hardware.openRGB.enable openrgb) - (lib.mkIf config.hardware.viaKeyboard.enable via) - ] - ) - ) - ] - ); -} diff --git a/util/default.nix b/util/default.nix index acd1997..fb2f83d 100644 --- a/util/default.nix +++ b/util/default.nix @@ -1,7 +1,128 @@ -_: { - # mkUnless = condition: then: (mkIf (!condition) then); - # mkIfElse = condition: then: else: lib.mkMerge [ - # (mkIf condition then) - # (mkUnless condition else) - # ]; +{inputs}: let + util = (import ./default.nix) {inherit inputs;}; + outputs = inputs.self.outputs; + + lib = inputs.lib; + nixpkgs = inputs.nixpkgs; + home-manager = inputs.home-manager; + nix-darwin = inputs.nix-darwin; + sops-nix = inputs.sops-nix; + nix-syncthing = inputs.nix-syncthing; + disko = inputs.disko; + impermanence = inputs.impermanence; + lix-module = inputs.lix-module; + + systems = [ + "aarch64-darwin" + "aarch64-linux" + "x86_64-darwin" + "x86_64-linux" + ]; + forEachSystem = nixpkgs.lib.genAttrs systems; + pkgsFor = system: nixpkgs.legacyPackages.${system}; + + common-modules = [ + ../modules/common-modules + ]; + + home-manager-modules = + common-modules + ++ [ + sops-nix.homeManagerModules.sops + impermanence.homeManagerModules.impermanence + ../modules/home-manager-modules + ]; + + home-manager-config = nixpkgs: { + home-manager.useUserPackages = true; + home-manager.backupFileExtension = "backup"; + home-manager.extraSpecialArgs = { + inherit inputs outputs util; + }; + home-manager.users = import ../configurations/home-manager (nixpkgs + // { + osConfig = nixpkgs.config; + }); + home-manager.sharedModules = home-manager-modules; + }; + + system-modules = + common-modules + ++ [ + home-manager-config + ../modules/system-modules + ]; +in { + forEachPkgs = lambda: forEachSystem (system: lambda system (pkgsFor system)); + + mkUnless = condition: yes: (lib.mkIf (!condition) yes); + mkIfElse = condition: yes: no: + lib.mkMerge [ + (lib.mkIf condition yes) + (lib.mkUnless condition no) + ]; + + mkNixosInstaller = host: userKeys: + nixpkgs.lib.nixosSystem { + modules = [ + { + # TODO: authorized keys for all users and hosts + } + ../configurations/nixos/${host} + ]; + }; + + mkNixosSystem = host: + nixpkgs.lib.nixosSystem { + specialArgs = {inherit inputs outputs util;}; + modules = + system-modules + ++ [ + sops-nix.nixosModules.sops + nix-syncthing.nixosModules.syncthing + impermanence.nixosModules.impermanence + home-manager.nixosModules.home-manager + disko.nixosModules.disko + lix-module.nixosModules.default + ../modules/nixos-modules + ../configurations/nixos/${host} + ]; + }; + + mkDarwinSystem = host: + nix-darwin.lib.darwinSystem { + specialArgs = {inherit inputs outputs util;}; + modules = + system-modules + ++ [ + sops-nix.darwinModules.sops + home-manager.darwinModules.home-manager + ../modules/darwin-modules + ../configurations/darwin/${host} + ]; + }; + + mkHome = { + user, + host, + system, + osConfig, + }: + home-manager.lib.homeManagerConfiguration { + pkgs = pkgsFor system; + extraSpecialArgs = { + inherit inputs util outputs osConfig; + }; + modules = + home-manager-modules + ++ [ + ../configurations/home-manager/${user} + ]; + }; + + syncthingConfiguration = nix-syncthing.lib.syncthingConfiguration { + modules = [ + (import ../configurations/syncthing) + ]; + }; }