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/.gitconfig b/.gitconfig new file mode 100644 index 0000000..78d2a4a --- /dev/null +++ b/.gitconfig @@ -0,0 +1,2 @@ +[core] + hooksPath = .hooks 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 new file mode 100755 index 0000000..56c439d --- /dev/null +++ b/.hooks/post-commit @@ -0,0 +1,6 @@ +#!/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 new file mode 100755 index 0000000..f98c64f --- /dev/null +++ b/.hooks/pre-commit @@ -0,0 +1,22 @@ +#!/usr/bin/env nix-shell +#! nix-shell -i bash ../shell.nix + +echo "stashing all uncommitted changes" +git stash -q --keep-index + +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 0ac5664..b8b0adf 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -1,7 +1,15 @@ keys: - &leyla age15ga3jmn2mqtlgwwtdcdh6l5vdx6um9aftrkexxfyue6xvcqapqusle75jh creation_rules: - - path_regex: secrets/secrets.yaml$ + - path_regex: secrets/user-passwords.yaml$ + key_groups: + - age: + - *leyla + - path_regex: secrets/defiant-services.yaml$ + key_groups: + - age: + - *leyla + - path_regex: secrets/vpn-keys.yaml$ key_groups: - age: - *leyla 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 b8bed40..bc31eca 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,62 +11,60 @@ | :---------: | :------------------------: | :--------------: | :-------: | | `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 | - -### Rebuild current machine to match target host: -`sudo nixos-rebuild switch --flake .#hostname` - -### Rebuild current machine maintaining current target +# Tooling +## Rebuilding `./rebuild.sh` -# New machine setup -keys for decrypting password secrets for each users located at `/var/lib/sops-nix/key.txt` - -updating passwords: `sops secrets/secrets.yaml` +## Updating +`nix flake update` +## New host setup `./install.sh --target 192.168.1.130 --flake hostname` -> how the current config was set up https://www.youtube.com/watch?v=G5f6GC7SnhU +## Updating Secrets +`sops secrets/secrets_file_here.yaml` -> something about ssh keys for remotes +## Inspecting a configuration +`nix-inspect -p .` # Notes: -- Look into this for fixing nixos-anywhere `https://github.com/lucidph3nx/nixos-config/tree/main` -- 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/ -# Updating -`nix flake update` +## Research topics +- Look into this for auto rotating sops keys `https://technotim.live/posts/rotate-sops-encryption-keys/` +- Look into this for flake templates https://nix.dev/manual/nix/2.22/command-ref/new-cli/nix3-flake-init +- https://nixos-and-flakes.thiscute.world/ # Tasks: ## Tech Debt -- allowUnfree should be enabled user side not host side (this isn't enabled at all right now for some reason???) -- Move configs for pipe mouse, open rgb, and via keyboard to hardware config and install users side from those configs -- have nfs binds and exports defined by same code -- move services from defiant into own flake -- made base domain in nas services configurable -- vscode extensions should be in own flake (make sure to add the nixpkgs.overlays in it too) +- 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/) +- syncthing folder passwords +- nfs export should be backed by the same values for server and client ## New Features -- GNOME default monitors per hardware configuration? - 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) -- Flake templates -- Docker parity with existing NAS on defiant -- NFS on defiant -- firefox declarative??? +- samba mounts - figure out steam vr things? - Open GL? -- util functions -- openssh known hosts -- limit boot configurations to 2 on defiant - rotate sops encryption keys periodically (and somehow sync between devices?) -- zfs email after scrubbing -- headscale server -- mastodon server -- tail scale clients -- wake on LAN \ No newline at end of file +- zfs email after scrubbing # TODO: test this +- wake on LAN for updates +- ISO target that contains authorized keys for nixos-anywhere https://github.com/diegofariasm/yggdrasil/blob/4acc43ebc7bcbf2e41376d14268e382007e94d78/hosts/bootstrap/default.nix +- zfs encryption FIDO2 2fa (look into shavee) +- Secure Boot - https://github.com/nix-community/lanzaboote +- SMART test with email results +- Create Tor guard/relay server +- remote distributed builds - https://nix.dev/tutorials/nixos/distributed-builds-setup.html +- migrate away from flakes and move to npins +- fix nfs +- fix home assistant +- create adguard server \ 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..0ab0c59 --- /dev/null +++ b/configurations/home-manager/eve/default.nix @@ -0,0 +1,55 @@ +{osConfig, ...}: let + userConfig = osConfig.host.users.eve; +in { + nixpkgs.config = { + allowUnfree = true; + }; + + 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/packages.nix b/configurations/home-manager/eve/packages.nix new file mode 100644 index 0000000..6cc4630 --- /dev/null +++ b/configurations/home-manager/eve/packages.nix @@ -0,0 +1,52 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: let + userConfig = osConfig.host.users.eve; +in { + config = { + # 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; [ + firefox + bitwarden + discord + makemkv + signal-desktop-bin + ungoogled-chromium + ] + ); + + # Packages that need to be installed with some extra configuration + # See https://home-manager-options.extranix.com/ for all options + programs = { + # Let Home Manager install and manage itself. + home-manager.enable = true; + + git = { + enable = true; + userName = "Eve"; + userEmail = "evesnrobins@gmail.com"; + extraConfig.init.defaultBranch = "main"; + }; + + vscode = { + enable = true; + package = pkgs.vscodium; + }; + + openssh = { + hostKeys = [ + { + type = "ed25519"; + path = "${config.home.username}_${osConfig.networking.hostName}_ed25519"; + } + ]; + }; + }; + }; +} 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..5818641 --- /dev/null +++ b/configurations/home-manager/leyla/dconf.nix @@ -0,0 +1,104 @@ +{pkgs, ...}: { + config = { + dconf = { + enable = true; + settings = { + "org/gnome/desktop/interface".color-scheme = "prefer-dark"; + + "org/gnome/desktop/wm/preferences".button-layout = ":minimize,maximize,close"; + + "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"; + }; + + "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..90251a3 --- /dev/null +++ b/configurations/home-manager/leyla/default.nix @@ -0,0 +1,108 @@ +{osConfig, ...}: { + imports = [ + ./i18n.nix + ./packages.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/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"; + }; + }; + + user = { + continue = { + enable = true; + docs = { + "Continue Docs" = { + startUrl = "https://docs.continue.dev"; + }; + "Nixpkgs" = { + startUrl = "https://ryantm.github.io/nixpkgs/#preface"; + }; + "Nix Manual" = { + startUrl = "https://nixos.org/manual/nixos/stable/"; + }; + "Home manager Manual" = { + startUrl = "https://nix-community.github.io/home-manager/"; + }; + "Nix Docs" = { + startUrl = "https://nix.dev/index.html"; + }; + "Linux Man Page" = { + startUrl = "https://linux.die.net/man/"; + }; + }; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/firefox.nix b/configurations/home-manager/leyla/firefox.nix new file mode 100644 index 0000000..0adea28 --- /dev/null +++ b/configurations/home-manager/leyla/firefox.nix @@ -0,0 +1,347 @@ +{ + lib, + pkgs, + inputs, + osConfig, + ... +}: let + is-desktop-user = osConfig.host.users.leyla.isDesktopUser; +in { + config = lib.mkIf is-desktop-user { + programs.firefox = { + enable = true; + 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/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..29936b5 --- /dev/null +++ b/configurations/home-manager/leyla/impermanence.nix @@ -0,0 +1,24 @@ +{ + lib, + osConfig, + ... +}: { + config = lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist/home/leyla" = { + directories = [ + "desktop" + "downloads" + "documents" + { + directory = ".local/share/Steam"; + method = "symlink"; + } + ]; + files = [ + ".bash_history" # keep shell history around + ".local/share/recently-used.xbel" # gnome recently viewed files + ]; + allowOther = true; + }; + }; +} diff --git a/configurations/home-manager/leyla/packages.nix b/configurations/home-manager/leyla/packages.nix new file mode 100644 index 0000000..020060d --- /dev/null +++ b/configurations/home-manager/leyla/packages.nix @@ -0,0 +1,136 @@ +{ + lib, + config, + osConfig, + pkgs, + ... +}: let + userConfig = osConfig.host.users.leyla; + hardware = osConfig.host.hardware; +in { + imports = [ + ./vscode/default.nix + ./firefox.nix + ]; + + config = lib.mkMerge [ + (lib.mkIf userConfig.isTerminalUser { + home.packages = with pkgs; [ + # command line tools + sox + yt-dlp + ffmpeg + imagemagick + ]; + }) + (lib.mkIf userConfig.isDesktopUser { + nixpkgs.config = { + allowUnfree = true; + }; + + home.packages = ( + lib.lists.optionals userConfig.isDesktopUser ( + (with pkgs; [ + # helvetica font + aileron + + gnomeExtensions.dash-to-dock + + # development tools + dbeaver-bin + bruno + proxmark3 + ]) + ++ ( + lib.lists.optionals hardware.directAccess.enable (with pkgs; [ + #foss platforms + signal-desktop-bin + bitwarden + ungoogled-chromium + libreoffice + inkscape + gimp + krita + freecad + # cura + # kicad-small + makemkv + onionshare + # rhythmbox + (lib.mkIf hardware.graphicsAcceleration.enable obs-studio) + # wireshark + # rpi-imager + # fritzing + mfoc + tor-browser + anki + pdfarranger + calibre + qbittorrent + picard + + # proprietary platforms + discord + obsidian + prostudiomasters + (lib.mkIf hardware.graphicsAcceleration.enable davinci-resolve) + + # development tools + # androidStudioPackages.canary + jetbrains.idea-community + qFlipper + + # system tools + protonvpn-gui + openvpn + noisetorch + + # hardware management tools + (lib.mkIf hardware.piperMouse.enable piper) + (lib.mkIf hardware.openRGB.enable openrgb) + (lib.mkIf hardware.viaKeyboard.enable via) + ]) + ) + ) + ); + programs = lib.mkIf userConfig.isDesktopUser { + # Let Home Manager install and manage itself. + home-manager.enable = true; + + # set up git defaults + git = { + enable = true; + userName = "Leyla Becker"; + userEmail = "git@jan-leila.com"; + extraConfig.init.defaultBranch = "main"; + }; + + # add direnv to auto load flakes for development + direnv = { + enable = true; + enableBashIntegration = true; + nix-direnv.enable = true; + config = { + global.hide_env_diff = true; + whitelist.exact = ["/home/leyla/documents/code/nix-config"]; + }; + }; + bash.enable = true; + + 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/vscode/default.nix b/configurations/home-manager/leyla/vscode/default.nix new file mode 100644 index 0000000..c2ee066 --- /dev/null +++ b/configurations/home-manager/leyla/vscode/default.nix @@ -0,0 +1,121 @@ +{ + lib, + pkgs, + inputs, + config, + osConfig, + ... +}: let + nix-development-enabled = osConfig.host.nix-development.enable; + ai-tooling-enabled = config.user.continue.enable && osConfig.host.ai.enable; + is-desktop-user = osConfig.host.users.leyla.isDesktopUser; +in { + config = lib.mkIf is-desktop-user { + nixpkgs = { + overlays = [ + inputs.nix-vscode-extensions.overlays.default + ]; + }; + + programs = { + bash.shellAliases = { + code = "codium"; + }; + + vscode = let + extensions = inputs.nix-vscode-extensions.extensions.${pkgs.system}; + open-vsx = extensions.open-vsx; + vscode-marketplace = extensions.vscode-marketplace; + in { + enable = true; + + 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 { + "continue.telemetryEnabled" = false; + }) + ]; + + extensions = ( + 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 + + # 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 + + # 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 vscode-marketplace; + [ + # js extensions + karyfoundation.nearley + ] + ++ (lib.lists.optionals ai-tooling-enabled [ + continue.continue + ]) + ) + ); + }; + }; + }; + }; +} diff --git a/configurations/home-manager/leyla/vscode/user-words.nix b/configurations/home-manager/leyla/vscode/user-words.nix new file mode 100644 index 0000000..b581118 --- /dev/null +++ b/configurations/home-manager/leyla/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..0b9d1b7 --- /dev/null +++ b/configurations/nixos/defiant/configuration.nix @@ -0,0 +1,310 @@ +# 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"; + }; + }; + + 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; + }; + }; + }; + # home-assistant = { + # enable = false; + # subdomain = "home"; + # }; + adguardhome = { + enable = false; + }; + }; + + 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; + # }; + }; + }; + + 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; + + 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"; + }; + + virt-home-assistant = { + enable = false; + networkBridge = "bond0"; + hostDevice = "0x10c4:0xea60"; + }; + + 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/configurations/nixos/defiant/hardware-configuration.nix b/configurations/nixos/defiant/hardware-configuration.nix new file mode 100644 index 0000000..d4a638b --- /dev/null +++ b/configurations/nixos/defiant/hardware-configuration.nix @@ -0,0 +1,63 @@ +# 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" "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 = ["rpool"]; + }; + + networking = { + hostName = "defiant"; # Define your hostname. + hostId = "c51763d6"; + useNetworkd = true; + }; + + systemd.network = { + enable = true; + + networks = { + "30-eno1" = { + matchConfig.Name = "eno1"; + networkConfig.Bond = "bond0"; + }; + "30-eno2" = { + matchConfig.Name = "eno2"; + networkConfig.Bond = "bond0"; + }; + }; + }; + + networking.networkmanager.enable = true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware = { + # TODO: hardware graphics + cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + }; +} diff --git a/configurations/nixos/emergent/configuration.nix b/configurations/nixos/emergent/configuration.nix new file mode 100644 index 0000000..aacc820 --- /dev/null +++ b/configurations/nixos/emergent/configuration.nix @@ -0,0 +1,157 @@ +# 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 the GNOME Desktop Environment. + services.displayManager.gdm.enable = true; + services.desktopManager.gnome.enable = true; + + host = { + users = { + eve = { + isDesktopUser = true; + isTerminalUser = true; + isPrincipleUser = 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.steam = { + 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 + localNetworkGameTransfers.openFirewall = true; # Open ports in the firewall for Steam Local Network Game Transfers + }; + + # 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..fd569b3 --- /dev/null +++ b/configurations/nixos/emergent/nvidia-drivers.nix @@ -0,0 +1,44 @@ +{ + config, + lib, + pkgs, + ... +}: { + # Enable OpenGL + hardware.graphics = { + enable = true; + }; + + # Load nvidia driver for Xorg and Wayland + services.xserver.videoDrivers = ["nvidia"]; + + 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..5817e2b --- /dev/null +++ b/configurations/nixos/horizon/configuration.nix @@ -0,0 +1,130 @@ +{ + 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 = "lamma3.1:8b"; + roles = ["chat" "edit" "apply"]; + apiBase = "http://twilight:11434"; + }; + + "qwen2.5-coder:1.5b-base" = { + model = "qwen2.5-coder:1.5b-base"; + roles = ["autocomplete"]; + apiBase = "http://twilight:11434"; + }; + + "nomic-embed-text:latest" = { + model = "nomic-embed-text:latest"; + roles = ["embed"]; + apiBase = "http://twilight:11434"; + }; + }; + }; + }; + + environment.systemPackages = with pkgs; [ + cachefilesd + webtoon-dl + ]; + services.cachefilesd.enable = true; + + programs = { + adb.enable = true; + steam = { + 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 + }; + }; + + 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..6cef2fb --- /dev/null +++ b/configurations/nixos/twilight/configuration.nix @@ -0,0 +1,215 @@ +{ + 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 + ]; + programs.steam = { + 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 + }; + 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/configurations/nixos/twilight/monitors.nix b/configurations/nixos/twilight/monitors.nix new file mode 100644 index 0000000..1308f50 --- /dev/null +++ b/configurations/nixos/twilight/monitors.nix @@ -0,0 +1,199 @@ +{pkgs, ...}: { + systemd.tmpfiles.rules = [ + "L+ /run/gdm/.config/monitors.xml - - - - ${pkgs.writeText "gdm-monitors.xml" '' + + + + 0 + 156 + 1 + + + DP-4 + DEL + DELL U2719D + 8RGXNS2 + + + 2560 + 1440 + 59.951 + + + + + 2560 + 324 + 1 + yes + + + DP-2 + GSM + LG ULTRAGEAR + 0x00068c96 + + + 1920 + 1080 + 240.001 + + + + + 4480 + 0 + 1 + + left + no + + + + HDMI-0 + HWP + HP w2207 + CND7332S88 + + + 1600 + 1000 + 59.999 + + + + + + + 0 + 0 + 1 + yes + + + DP-1 + DEL + DELL U2719D + 8RGXNS2 + + + 2560 + 1440 + 59.951 + + + + + 4480 + 226 + 1 + + left + no + + + + HDMI-1 + HWP + HP w2207 + CND7332S88 + + + 1680 + 1050 + 59.954 + + + + + 2560 + 226 + 1 + + + DP-2 + GSM + LG ULTRAGEAR + 0x00068c96 + + + 1920 + 1080 + 240.001 + + + + + + + 2560 + 228 + 1 + yes + + + DP-2 + GSM + LG ULTRAGEAR + 0x00068c96 + + + 1920 + 1080 + 240.001 + + + + + 4480 + 69 + 1 + + left + no + + + + HDMI-1 + HWP + HP w2207 + CND7332S88 + + + 1680 + 1050 + 59.954 + + + + + 0 + 0 + 1 + + + DP-3 + DEL + DELL U2719D + 8RGXNS2 + + + 2560 + 1440 + 59.951 + + + + + + None-1 + unknown + unknown + unknown + + + + + ''}" + ]; +} 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 555305f..0000000 --- a/enviroments/client/default.nix +++ /dev/null @@ -1,60 +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 - ]; -} \ No newline at end of file diff --git a/enviroments/common/default.nix b/enviroments/common/default.nix deleted file mode 100644 index 99f3e5a..0000000 --- a/enviroments/common/default.nix +++ /dev/null @@ -1,71 +0,0 @@ -{ pkgs, ... }: -{ - imports = [ - ../../users - ]; - - nix.settings.experimental-features = [ "nix-command" "flakes" ]; - nix.settings.trusted-users = [ "leyla" ]; - - # 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.groups.users = {}; - - services = { - openssh = { - enable = true; - ports = [ 22 ]; - settings = { - PasswordAuthentication = false; - AllowUsers = [ "leyla" ]; # Allows all users by default. Can be [ "user1" "user2" ] - UseDns = true; - X11Forwarding = false; - }; - }; - }; - - sops = { - defaultSopsFile = ../../secrets/secrets.yaml; - defaultSopsFormat = "yaml"; - gnupg.sshKeyPaths = []; - - age ={ - keyFile = "/var/lib/sops-nix/key.txt"; - sshKeyPaths = []; - # generateKey = true; - }; - }; - environment.sessionVariables = { - AGE_KEY_FILE_LOCATION = "/var/lib/sops-nix/"; - }; - - # List packages installed in system profile. - environment.systemPackages = with pkgs; [ - wget - - # version control - git - - # system debuging tools - iputils - dnsutils - ]; -} \ No newline at end of file diff --git a/enviroments/server/default.nix b/enviroments/server/default.nix deleted file mode 100644 index d3e9d63..0000000 --- a/enviroments/server/default.nix +++ /dev/null @@ -1,63 +0,0 @@ -{ config, ... }: -{ - imports = [ - ../common - ]; - - services = let - headscaleDomain = "headscale.jan-leila.com"; - in { - 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) - ''; - }; - - headscale = { - enable = true; - address = "0.0.0.0"; - port = 8080; - settings = { - server_url = "https://${headscaleDomain}"; - dns_config.base_domain = "jan-leila.com"; - logtail.enabled = false; - }; - }; - - nginx = { - enable = false; # TODO: enable this when you want to test all the configs - virtualHosts = { - ${headscaleDomain} = { - forceSSL = true; - enableACME = true; - locations."/" = { - proxyPass = - "http://localhost:${toString config.services.headscale.port}"; - proxyWebsockets = true; - }; - }; - }; - }; - }; - - security.acme = { - acceptTerms = true; - defaults.email = "jan-leila@protonmail.com"; - }; - - # disable computer sleeping - systemd.targets = { - sleep.enable = false; - suspend.enable = false; - hibernate.enable = false; - hybrid-sleep.enable = false; - }; - - networking.firewall.allowedTCPPorts = [ 2049 ]; - - environment.systemPackages = [ config.services.headscale.package ]; -} \ No newline at end of file diff --git a/flake.lock b/flake.lock index 3f277b2..bbaffa4 100644 --- a/flake.lock +++ b/flake.lock @@ -7,11 +7,11 @@ ] }, "locked": { - "lastModified": 1725377834, - "narHash": "sha256-tqoAO8oT6zEUDXte98cvA1saU9+1dLJQe3pMKLXv8ps=", + "lastModified": 1748225455, + "narHash": "sha256-AzlJCKaM4wbEyEpV3I/PUq5mHnib2ryEy32c+qfj6xk=", "owner": "nix-community", "repo": "disko", - "rev": "e55f9a8678adc02024a4877c2a403e3f6daf24fe", + "rev": "a894f2811e1ee8d10c50560551e50d6ab3c392ba", "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": 1748730131, + "narHash": "sha256-QHKZlwzw80hoJkNGXQePIg4u109lqcodALkont2WJAc=", + "owner": "rycee", + "repo": "nur-expressions", + "rev": "aa7bfc2ec4763b57386fcd50242c390a596b9bb0", + "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": 1725948275, - "narHash": "sha256-4QOPemDQ9VRLQaAdWuvdDBhh+lEUOAnSMHhdr4nS1mk=", + "lastModified": 1748811839, + "narHash": "sha256-MDl6vpEK18ZfPHfoeOa9dGRdwVWNfmCCGazt72nHw+U=", "owner": "nix-community", "repo": "home-manager", - "rev": "e5fa72bad0c6f533e8d558182529ee2acc9454fe", + "rev": "6abf27943bbb09a0f9d443df45ec70b07a6cbe20", "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": 1726623336, - "narHash": "sha256-mslZtr0SPdHDLUM5VRV0ipQQ4G0Piv2Kk15490w4JXM=", + "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": 1748352827, + "narHash": "sha256-sNUUP6qxGkK9hXgJ+p362dtWLgnIWwOCmiq72LAWtYo=", + "owner": "LnL7", + "repo": "nix-darwin", + "rev": "44a7d0e687a87b73facfe94fba78d323a6686a90", + "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": 1748744745, + "narHash": "sha256-kcj58eYic+yLX/KjtHEOmn6lVnCRwL1IfRGnb8aHprE=", "owner": "nix-community", "repo": "nix-vscode-extensions", - "rev": "b23683fef09032c85bb8b20f8ec72fb2f70075ff", + "rev": "c008ed9dd78efdeda5e9d5bb835c785e600791f6", "type": "github" }, "original": { @@ -98,11 +242,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1725885300, - "narHash": "sha256-5RLEnou1/GJQl+Wd+Bxaj7QY7FFQ9wjnFq1VNEaxTmc=", + "lastModified": 1748634340, + "narHash": "sha256-pZH4bqbOd8S+si6UcfjHovWDiWKiIGRNRMpmRWaDIms=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "166dee4f88a7e3ba1b7a243edb1aca822f00680e", + "rev": "daa628a725ab4948e0e2b795e8fb6f4c3e289a7a", "type": "github" }, "original": { @@ -114,11 +258,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1725634671, - "narHash": "sha256-v3rIhsJBOMLR8e/RNWxr828tB+WywYIoajrZKFM+0Gg=", + "lastModified": 1748693115, + "narHash": "sha256-StSrWhklmDuXT93yc3GrTlb0cKSS0agTAxMGjLKAsY8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "574d1eac1c200690e27b8eb4e24887f8df7ac27c", + "rev": "910796cabe436259a29a72e8d3f5e180fc6dfacc", "type": "github" }, "original": { @@ -128,59 +272,51 @@ "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", + "secrets": "secrets", "sops-nix": "sops-nix" } }, + "secrets": { + "flake": false, + "locked": { + "lastModified": 1743538790, + "narHash": "sha256-QXmvyxfAhpifxAWcYTvuGfzv9I+9gHw0bq4WYtGEB9A=", + "ref": "refs/heads/main", + "rev": "3d63dff77f8eda1667e3586169642cf256c4aa34", + "revCount": 17, + "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": 1725922448, - "narHash": "sha256-ruvh8tlEflRPifs5tlpa0gkttzq4UtgXkJQS7FusgFE=", + "lastModified": 1747603214, + "narHash": "sha256-lAblXm0VwifYCJ/ILPXJwlz0qNY07DDYdLD+9H+Wc8o=", "owner": "Mic92", "repo": "sops-nix", - "rev": "cede1a08039178ac12957733e97ab1006c6b6892", + "rev": "8d215e1c981be3aa37e47aeabd4e61bb069548fd", "type": "github" }, "original": { @@ -203,6 +339,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 033e2c2..7896d60 100644 --- a/flake.nix +++ b/flake.nix @@ -5,71 +5,169 @@ # 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 + # 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"; + }; }; - outputs = { self, nixpkgs, disko, nixos-hardware, ... }@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; }); + outputs = { + self, + nixpkgs, + sops-nix, + nix-syncthing, + home-manager, + impermanence, + ... + } @ inputs: let + 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 + ]; + + 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 d2b1348..0000000 --- a/hosts/defiant/configuration.nix +++ /dev/null @@ -1,57 +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; - }; - - nixpkgs.config.allowUnfree = true; - - 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? -} \ No newline at end of file diff --git a/hosts/defiant/disko-config.nix b/hosts/defiant/disko-config.nix deleted file mode 100644 index 653f29f..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/defiant/hardware-configuration.nix b/hosts/defiant/hardware-configuration.nix deleted file mode 100644 index 3ba63d0..0000000 --- a/hosts/defiant/hardware-configuration.nix +++ /dev/null @@ -1,45 +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") - ]; - - boot = { - initrd = { - availableKernelModules = [ "xhci_pci" "aacraid" "ahci" "usbhid" "usb_storage" "sd_mod" ]; - kernelModules = [ ]; - }; - kernelModules = [ "kvm-amd" ]; - extraModulePackages = [ ]; - - supportedFilesystems = [ "zfs" ]; - - zfs.extraPools = [ "zroot" ]; - }; - - # fileSystems."/" = - # { device = "/dev/disk/by-uuid/dc6a9664-80f2-4988-afd7-fee5bd3ee2ca"; - # fsType = "ext4"; - # }; - - 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; - # networking.interfaces.eno1.useDHCP = lib.mkDefault true; - # networking.interfaces.eno2.useDHCP = lib.mkDefault true; - hostId = "c51763d6"; - hostName = "defiant"; # Define your hostname. - }; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} \ No newline at end of file diff --git a/hosts/horizon/configuration.nix b/hosts/horizon/configuration.nix deleted file mode 100644 index f1c3bee..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; - - # Allow unfree packages - nixpkgs.config.allowUnfree = 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 59a900d..0000000 --- a/hosts/horizon/hardware-configuration.nix +++ /dev/null @@ -1,104 +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") - ]; - - 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; - }; - }; - - - hardware.graphics.enable = 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.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} diff --git a/hosts/twilight/configuration.nix b/hosts/twilight/configuration.nix deleted file mode 100644 index 1352c8b..0000000 --- a/hosts/twilight/configuration.nix +++ /dev/null @@ -1,42 +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; - hasPiperMouse = true; - hasOpenRGBHardware = true; - hasViaKeyboard = true; - hasGPU = true; - }; - ester.isFullUser = true; - eve.isFullUser = true; - }; - - # enabled virtualisation for docker - # virtualisation.docker.enable = true; - - # Enable touchpad support (enabled default in most desktopManager). - # services.xserver.libinput.enable = true; - - # Allow unfree packages - nixpkgs.config.allowUnfree = 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/hosts/twilight/hardware-configuration.nix b/hosts/twilight/hardware-configuration.nix deleted file mode 100644 index ab24b97..0000000 --- a/hosts/twilight/hardware-configuration.nix +++ /dev/null @@ -1,119 +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") - ]; - - 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; - }; - - 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 = 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; - }; - }; - - 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.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} - diff --git a/install.sh b/install.sh index 0718998..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() { @@ -47,8 +48,8 @@ cleanup() { trap cleanup EXIT # copy key file to temp folder to copy over to target -mkdir -p $temp$AGE_KEY_FILE_LOCATION -cp -r $AGE_KEY_FILE_LOCATION/* $temp$AGE_KEY_FILE_LOCATION +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/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..08085f5 --- /dev/null +++ b/modules/common-modules/overlays/default.nix @@ -0,0 +1,3 @@ +# this folder is for derivation overlays +{...}: { +} diff --git a/modules/common-modules/pkgs/default.nix b/modules/common-modules/pkgs/default.nix new file mode 100644 index 0000000..208ee24 --- /dev/null +++ b/modules/common-modules/pkgs/default.nix @@ -0,0 +1,17 @@ +{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 + {}; + }) + ]; +} 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/continue.nix b/modules/home-manager-modules/continue.nix new file mode 100644 index 0000000..327ee44 --- /dev/null +++ b/modules/home-manager-modules/continue.nix @@ -0,0 +1,75 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: let + ai-tooling-enabled = config.user.continue.enable && osConfig.host.ai.enable; +in { + options = { + user.continue = { + enable = lib.mkEnableOption "should continue be enabled on this machine"; + docs = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + name = lib.mkOption { + type = lib.types.str; + default = name; + }; + startUrl = lib.mkOption { + type = lib.types.str; + }; + }; + })); + }; + context = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule ({name, ...}: { + options = { + provider = lib.mkOption { + type = lib.types.str; + default = name; + }; + }; + })); + default = { + "code" = {}; + "docs" = {}; + "diff" = {}; + "terminal" = {}; + "problems" = {}; + "folder" = {}; + "codebase" = {}; + }; + }; + }; + }; + + config = + lib.mkIf ai-tooling-enabled + (lib.mkMerge [ + { + home = { + file = { + ".continue/config.yaml".source = (pkgs.formats.yaml {}).generate "continue-config" { + name = "Assistant"; + version = "1.0.0"; + schema = "v1"; + models = lib.attrsets.attrValues osConfig.host.ai.models; + context = lib.attrsets.attrValues config.user.continue.context; + docs = lib.attrsets.attrValues config.user.continue.docs; + }; + }; + }; + } + (lib.mkIf osConfig.host.impermanence.enable { + home.persistence."/persist${config.home.homeDirectory}" = { + directories = [ + ".continue/index" + ".continue/sessions" + ]; + allowOther = true; + }; + }) + ]); +} diff --git a/modules/home-manager-modules/default.nix b/modules/home-manager-modules/default.nix new file mode 100644 index 0000000..ee47fb5 --- /dev/null +++ b/modules/home-manager-modules/default.nix @@ -0,0 +1,9 @@ +# this folder container modules that are for home manager only +{...}: { + imports = [ + ./flipperzero.nix + ./i18n.nix + ./openssh.nix + ./continue.nix + ]; +} 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/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..7b646b8 --- /dev/null +++ b/modules/home-manager-modules/openssh.nix @@ -0,0 +1,99 @@ +{ + pkgs, + config, + osConfig, + lib, + ... +}: { + options.programs.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.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/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..8cdeae9 --- /dev/null +++ b/modules/nixos-modules/default.nix @@ -0,0 +1,23 @@ +# 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 + ./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..323b7cc --- /dev/null +++ b/modules/nixos-modules/desktop.nix @@ -0,0 +1,75 @@ +{ + 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 { + 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; + excludePackages = with pkgs; [ + xterm + atomix # puzzle game + cheese # webcam tool + epiphany # web browser + geary # email reader + gedit # text editor + gnome-characters + gnome-music + gnome-photos + gnome-tour + gnome-logs + gnome-maps + hitori # sudoku game + iagno # go game + tali # poker game + yelp # help viewer + ]; + }; + + # 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; + # disable welcome tour + environment.gnome.excludePackages = [pkgs.gnome-tour]; + }) + ]; +} 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..cab004b --- /dev/null +++ b/modules/nixos-modules/home-manager/default.nix @@ -0,0 +1,8 @@ +# modules in this folder are to adapt home-manager modules configs to nixos-module configs +{...}: { + imports = [ + ./flipperzero.nix + ./i18n.nix + ./openssh.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/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..2f38cd3 --- /dev/null +++ b/modules/nixos-modules/impermanence.nix @@ -0,0 +1,88 @@ +{ + 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."; + } + ]; + + 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..8f194cf --- /dev/null +++ b/modules/nixos-modules/ollama.nix @@ -0,0 +1,52 @@ +{ + 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 = config.services.ollama.models; + user = config.services.ollama.user; + group = config.services.ollama.group; + } + { + directory = "/var/lib/private/ollama"; + user = config.services.ollama.user; + group = config.services.ollama.group; + mode = "0700"; + defaultPerms.mode = "0700"; + } + ]; + }; + }) + ] + ); +} diff --git a/modules/nixos-modules/server/adguardhome.nix b/modules/nixos-modules/server/adguardhome.nix new file mode 100644 index 0000000..866ad8a --- /dev/null +++ b/modules/nixos-modules/server/adguardhome.nix @@ -0,0 +1,72 @@ +{ + lib, + config, + ... +}: let + dnsPort = 53; +in { + options.host.adguardhome = { + enable = lib.mkEnableOption "should home-assistant be enabled on this computer"; + directory = lib.mkOption { + type = lib.types.str; + default = "/var/lib/AdGuardHome/"; + }; + }; + config = lib.mkIf config.host.adguardhome.enable (lib.mkMerge [ + { + services.adguardhome = { + enable = true; + mutableSettings = false; + settings = { + dns = { + bootstrap_dns = [ + "1.1.1.1" + "9.9.9.9" + ]; + upstream_dns = [ + "dns.quad9.net" + ]; + }; + filtering = { + protection_enabled = true; + filtering_enabled = true; + + parental_enabled = false; # Parental control-based DNS requests filtering. + safe_search = { + enabled = false; # Enforcing "Safe search" option for search engines, when possible. + }; + }; + # The following notation uses map + # to not have to manually create {enabled = true; url = "";} for every filter + # This is, however, fully optional + filters = + map (url: { + enabled = true; + url = url; + }) [ + "https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt" + "https://adguardteam.github.io/HostlistsRegistry/assets/filter_9.txt" # The Big List of Hacked Malware Web Sites + "https://adguardteam.github.io/HostlistsRegistry/assets/filter_11.txt" # malicious url blocklist + ]; + }; + }; + + networking.firewall.allowedTCPPorts = [ + dnsPort + ]; + } + (lib.mkIf config.host.impermanence.enable { + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = config.host.adguardhome.directory; + user = "adguardhome"; + group = "adguardhome"; + } + ]; + }; + }) + ]); +} diff --git a/modules/nixos-modules/server/default.nix b/modules/nixos-modules/server/default.nix new file mode 100644 index 0000000..7beee8b --- /dev/null +++ b/modules/nixos-modules/server/default.nix @@ -0,0 +1,16 @@ +{...}: { + imports = [ + ./fail2ban.nix + ./network_storage + ./reverse_proxy.nix + ./postgres.nix + ./podman.nix + ./jellyfin.nix + ./forgejo.nix + ./searx.nix + ./virt-home-assistant.nix + ./adguardhome.nix + ./immich.nix + ./qbittorent.nix + ]; +} diff --git a/modules/nixos-modules/server/fail2ban.nix b/modules/nixos-modules/server/fail2ban.nix new file mode 100644 index 0000000..be83e6f --- /dev/null +++ b/modules/nixos-modules/server/fail2ban.nix @@ -0,0 +1,98 @@ +{ + 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: " + '') + ); + # "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 = { + 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; + }; + # 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; + # }; + # 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..40a5303 --- /dev/null +++ b/modules/nixos-modules/server/forgejo.nix @@ -0,0 +1,112 @@ +{ + 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; + }; + }; + }; + }; + + 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..a90bd6d --- /dev/null +++ b/modules/nixos-modules/server/home-assistant.nix @@ -0,0 +1,130 @@ +{ + lib, + config, + inputs, + ... +}: let + configDir = "/var/lib/hass"; +in { + options.host.home-assistant = { + enable = lib.mkEnableOption "should home-assistant be enabled on this computer"; + subdomain = lib.mkOption { + type = lib.types.str; + description = "subdomain of base domain that home-assistant will be hosted at"; + default = "home-assistant"; + }; + }; + + config = lib.mkIf config.host.home-assistant.enable (lib.mkMerge [ + { + virtualisation.libvirt = { + swtpm.enable = true; + connections."qemu:///session" = { + networks = [ + { + definition = inputs.nix-virt.lib.network.writeXML (inputs.nix-virt.lib.network.templates.bridge + { + uuid = "d57e37e2-311f-4e5c-a484-97c2210c2770"; + subnet_byte = 71; + }); + active = true; + } + ]; + domains = [ + { + definition = inputs.nix-virt.lib.domain.writeXML (inputs.nix-virt.lib.domain.templates.linux + { + name = "Home Assistant"; + uuid = "c5cc0efc-6101-4c1d-be31-acbba203ccde"; + memory = { + count = 4; + unit = "GiB"; + }; + # storage_vol = { + # pool = "MyPool"; + # volume = "Penguin.qcow2"; + # }; + }); + } + ]; + }; + }; + + # systemd.tmpfiles.rules = [ + # "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass" + # ]; + # services.home-assistant = { + # enable = true; + # configDir = configDir; + # extraComponents = [ + # "met" + # "radio_browser" + # "isal" + # "zha" + # "jellyfin" + # "webostv" + # "tailscale" + # "syncthing" + # "sonos" + # "analytics_insights" + # "unifi" + # "openweathermap" + # ]; + # config = { + # http = { + # server_port = 8082; + # use_x_forwarded_for = true; + # trusted_proxies = ["127.0.0.1" "::1"]; + # ip_ban_enabled = true; + # login_attempts_threshold = 10; + # }; + # # recorder.db_url = "postgresql://@/${db_user}"; + # "automation manual" = []; + # "automation ui" = "!include automations.yaml"; + # }; + # extraPackages = python3Packages: + # with python3Packages; [ + # hassil + # numpy + # gtts + # ]; + # }; + # host = { + # reverse_proxy.subdomains.${config.host.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; + # ''; + # }; + # }; + } + (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..a8bbe71 --- /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 = lib.mkIf config.services.jellyfin.enable ( + pkgs.lib.mkDefault (pkgs.lib.mkAfter '' + [Definition] + failregex = "^.*Authentication request for .* has been denied \\\(IP: \"\"\\\)\\\." + '') + ); + }; + + services.fail2ban = { + jails = { + jellyfin-iptables.settings = lib.mkIf config.services.jellyfin.enable { + 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/podman.nix b/modules/nixos-modules/server/podman.nix new file mode 100644 index 0000000..e806e65 --- /dev/null +++ b/modules/nixos-modules/server/podman.nix @@ -0,0 +1,73 @@ +{ + lib, + config, + ... +}: { + options.host.podman = { + enable = lib.mkEnableOption "should home-assistant 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/virt-home-assistant.nix b/modules/nixos-modules/server/virt-home-assistant.nix new file mode 100644 index 0000000..4212668 --- /dev/null +++ b/modules/nixos-modules/server/virt-home-assistant.nix @@ -0,0 +1,155 @@ +{ + config, + lib, + pkgs, + ... +}: { + options.services.virt-home-assistant = { + enable = lib.mkEnableOption "Wether to enable home assistant virtual machine"; + networkBridge = lib.mkOption { + type = lib.types.str; + description = "what network bridge should we attach to the image"; + }; + hostDevice = lib.mkOption { + type = lib.types.str; + description = "what host devices should be attached to the image"; + }; + initialVersion = lib.mkOption { + type = lib.types.str; + description = "what home assistant image version should we pull for initial instal"; + default = "15.0"; + }; + imageName = lib.mkOption { + type = lib.types.str; + description = "where should the image be installed to"; + default = "home-assistant.qcow2"; + }; + installLocation = lib.mkOption { + type = lib.types.str; + description = "where should the image be installed to"; + default = "/etc/hass"; + }; + virtualMachineName = lib.mkOption { + type = lib.types.str; + description = "what name should we give the virtual machine"; + default = "home-assistant"; + }; + subdomain = lib.mkOption { + type = lib.types.str; + description = "subdomain of base domain that home-assistant will be hosted at"; + default = "home-assistant"; + }; + }; + config = lib.mkIf config.services.virt-home-assistant.enable (lib.mkMerge [ + { + # environment.systemPackages = with pkgs; [ + # virt-manager + # ]; + + # TODO: move this to external module and just have an assertion here that its enabled + # enable virtualization on the system + virtualisation = { + libvirtd = { + enable = true; + qemu.ovmf.enable = true; + }; + }; + + # TODO: deactivation script? + # create service to install and start the container + systemd.services.virt-install-home-assistant = let + # TODO: all of these need to be escaped to be used in commands reliably + bridgedNetwork = config.services.virt-home-assistant.networkBridge; + hostDevice = config.services.virt-home-assistant.hostDevice; + virtualMachineName = config.services.virt-home-assistant.virtualMachineName; + imageName = config.services.virt-home-assistant.imageName; + installLocation = config.services.virt-home-assistant.installLocation; + installImage = "${installLocation}/${imageName}"; + initialVersion = config.services.virt-home-assistant.initialVersion; + + home-assistant-qcow2 = pkgs.fetchurl { + name = "home-assistant.qcow2"; + url = "https://github.com/home-assistant/operating-system/releases/download/${initialVersion}/haos_ova-${initialVersion}.qcow2.xz"; + hash = "sha256-V1BEjvvLNbMMKJVyMCmipjQ/3owoJteeVxoF9LDHo1U="; + postFetch = '' + cp $out src.xz + rm -r $out + ${pkgs.xz}/bin/unxz src.xz --stdout > $out/${imageName} + ''; + }; + + # Write a script to install the Home Assistant OS qcow2 image + virtInstallScript = pkgs.writeShellScriptBin "virt-install-hass" '' + # Copy the initial image out of the package store to the install location if we don't have one yet + if [ ! -f ${installImage} ]; then + cp ${home-assistant-qcow2} ${installLocation} + fi + + # Check if VM already exists, and other pre-conditions + if ! ${pkgs.libvirt}/bin/virsh list --all | grep -q ${virtualMachineName}; then + ${pkgs.virt-manager}/bin/virt-install --name ${virtualMachineName} \ + --description "Home Assistant OS" \ + --os-variant=generic \ + --boot uefi \ + --ram=2048 \ + --vcpus=2 \ + --import \ + --disk ${installImage},bus=sata \ + --network bridge=${bridgedNetwork} \ + --host-device ${hostDevice} \ + --graphics none + ${pkgs.libvirt}/bin/virsh autostart ${virtualMachineName} + fi + ''; + in { + description = "Install and start Home Assistant"; + wantedBy = ["multi-user.target"]; + after = ["local-fs.target"]; + requires = ["libvirtd.service"]; + serviceConfig.Type = "oneshot"; + serviceConfig = { + ExecStart = "${virtInstallScript}/bin/virt-install-hass"; + }; + }; + + # TODO: figure out what we need to proxy to the virtual image + # host = { + # reverse_proxy.subdomains.${config.services.virt-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; + # ''; + # }; + # }; + } + (lib.mkIf config.services.fail2ban.enable { + # TODO: figure out how to write a config for this, prob based on nginx proxy logs? + }) + (lib.mkIf config.host.impermanence.enable { + # assertions = [ + # { + # assertion = config.services.virt-home-assistant.installLocation == configDir; + # message = "home assistant install location does not match persistence"; + # } + # ]; + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = config.services.virt-home-assistant.installLocation; + } + ]; + }; + }) + ]); +} 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/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..68bd78b --- /dev/null +++ b/modules/nixos-modules/users.nix @@ -0,0 +1,354 @@ +{ + 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; + }; + + 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; + }; + + 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; + }; + }; + + 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 + ]; + }; + }; + }; + } + (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..3d63dff --- /dev/null +++ b/nix-config-secrets @@ -0,0 +1 @@ +Subproject commit 3d63dff77f8eda1667e3586169642cf256c4aa34 diff --git a/overlays/intellij.nix b/overlays/intellij.nix deleted file mode 100644 index d83bd15..0000000 --- a/overlays/intellij.nix +++ /dev/null @@ -1,19 +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"; - # }; - # }); - # }; - # }) - # ]; -} \ No newline at end of file diff --git a/overlays/vscodium.nix b/overlays/vscodium.nix deleted file mode 100644 index 618af19..0000000 --- a/overlays/vscodium.nix +++ /dev/null @@ -1,15 +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"; - # }; - # }); - # }) - # ]; -} \ No newline at end of file diff --git a/pkgs/default.nix b/pkgs/default.nix deleted file mode 100644 index 9a81f3b..0000000 --- a/pkgs/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -pkgs: { - -} \ No newline at end of file diff --git a/rebuild.sh b/rebuild.sh index b37be13..45dae64 100755 --- a/rebuild.sh +++ b/rebuild.sh @@ -1,12 +1,21 @@ #!/usr/bin/env bash +if [ -d "result" ]; +then + preserve_result=true +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#*=}" ;; @@ -18,12 +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 ;; *) @@ -39,9 +65,30 @@ flake=${flake:-$target} mode=${mode:-switch} user=${user:-$USER} -if [[ "$target" == "$(hostname)" ]] +command="nixos-rebuild $mode --use-remote-sudo --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" ]]; + then + rm -r result + fi +fi \ No newline at end of file diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml deleted file mode 100644 index 1c7579e..0000000 --- a/secrets/secrets.yaml +++ /dev/null @@ -1,24 +0,0 @@ -passwords: - leyla: ENC[AES256_GCM,data:c69e5uF40ACxVI0zXizydaqMVk6MXVJ13HwptHKeYIJ9H6bCgZRK0HCoTYw366mIpe7zt2V/OVdNr6hdzGfLa90/iOAMaCGqgw==,iv:esVvjfJm3RvO8RdXPvrnT/+At7VFl9Vt6077I5Ks89Q=,tag:fHfIFBRVH3y/V16rHYsT2g==,type:str] - ester: ENC[AES256_GCM,data:Cz3oXNOVz35Uino3HLUNcao4YbG1QwmZn6ulWafGpa6Z3U+X+92f+PpHNx6L+q9ToIDabx0vNGs0Pfsrs4y9k/nmhWB1i66PzA==,iv:pY3aVbxmILYXHG06+XJWM6nHA8FbmsNBssh5LXplCOM=,tag:D09d2Bv4SAO7v4JeHVM+tw==,type:str] - eve: ENC[AES256_GCM,data:XvJjFNIujwk9ttYLTbAE+PEMUpWzLXrJeJJ0aEqWBwx+gjOwX4XVg0J/B75ByJxflh9RSwB0oAGfC+6coAHoMTXPyym52zAYBw==,iv:lVbZ8uC6IKn3Bew0LHmwl47nFfBuNqslltNBiv6cx7I=,tag:lgE0N6JKDcOPqynwtXJKzQ==,type:str] -sops: - kms: [] - gcp_kms: [] - azure_kv: [] - hc_vault: [] - age: - - recipient: age15ga3jmn2mqtlgwwtdcdh6l5vdx6um9aftrkexxfyue6xvcqapqusle75jh - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXd3BCR2RmMms4ZkNlbTdy - SzRKQ1NqZmFmOHJIS0oxZ3BMSnUyWXAyUUVrCk9tNjNNb0xEcnkvamJpSFF5UlhU - ejF4ZHFlZzJoemxpWXd0clN3cFZvMlkKLS0tIDdoK1oxc2doQTh3QlVyc3dhUE1W - VFBiZm5ZK2kwZjJPd3dCai9QUlpLaFEKFuwGgcdleN69voM5mpsa4J/ulmzZo7q+ - Q7KHOOidDH9C4xKjztYMuJSyviOYiIgILhljMXbNlmZnRs867gmmbw== - -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-09-03T02:19:43Z" - mac: ENC[AES256_GCM,data:Wc8nCiXVj6/+FANq82T+KsObOgwKUJTfkEnrK5MRU5gbLF3Skn0BY/alskV4aI9Kgi1cwh5ZBhHNzvyeIujuRB55QYyoocY0Pq7vLH5dgnA58DKEzrb09SAayiiH9hzRSTkdhtxj8FgCAdA6dWVkHEAO351ee67QNkG0nSwDdK0=,iv:vwUO50SKvzAPwACV1xhh7r+Am/OdlkNEN1pMimEVfC8=,tag:yF2CK41sLHLQqIISlQGAGg==,type:str] - pgp: [] - unencrypted_suffix: _unencrypted - version: 3.9.0 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 f9d63b0..0000000 --- a/templates/default.nix +++ /dev/null @@ -1,2 +0,0 @@ -_: -{} \ No newline at end of file diff --git a/users/default.nix b/users/default.nix deleted file mode 100644 index 57effe3..0000000 --- a/users/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ inputs, ... }: -{ - imports = [ ./leyla ./ester ./eve ]; - - users.mutableUsers = false; - - home-manager.extraSpecialArgs = { inherit inputs; }; -} \ No newline at end of file diff --git a/users/ester/default.nix b/users/ester/default.nix deleted file mode 100644 index 156716f..0000000 --- a/users/ester/default.nix +++ /dev/null @@ -1,45 +0,0 @@ -{ lib, config, pkgs, ... }: -let - cfg = config.users.ester; -in -{ - options.users.ester = { - isFullUser = lib.mkEnableOption "ester"; - }; - - config = { - sops.secrets = lib.mkIf cfg.isFullUser { - "passwords/ester" = { - neededForUsers = true; - # sopsFile = ../secrets.yaml; - }; - }; - - users.groups.ester = {}; - - users.users.ester = lib.mkMerge [ - { - uid = 1001; - description = "Ester"; - group = "ester"; - } - - ( - if cfg.isFullUser then { - isNormalUser = true; - extraGroups = [ "networkmanager" "users" ]; - - hashedPasswordFile = config.sops.secrets."passwords/ester".path; - - packages = with pkgs; [ - firefox - bitwarden - discord - ]; - } else { - isSystemUser = true; - } - ) - ]; - }; -} \ No newline at end of file diff --git a/users/eve/default.nix b/users/eve/default.nix deleted file mode 100644 index 4ed06a8..0000000 --- a/users/eve/default.nix +++ /dev/null @@ -1,47 +0,0 @@ -{ lib, config, pkgs, ... }: -let - cfg = config.users.eve; -in -{ - options.users.eve = { - isFullUser = lib.mkEnableOption "eve"; - }; - - config = { - sops.secrets = lib.mkIf cfg.isFullUser { - "passwords/eve" = { - neededForUsers = true; - # sopsFile = ../secrets.yaml; - }; - }; - - users.groups.eve = {}; - - users.users.eve = lib.mkMerge [ - { - uid = 1002; - description = "Eve"; - group = "eve"; - } - - ( - if cfg.isFullUser then { - isNormalUser = true; - extraGroups = [ "networkmanager" "users" ]; - - hashedPasswordFile = config.sops.secrets."passwords/eve".path; - - packages = with pkgs; [ - firefox - bitwarden - discord - makemkv - signal-desktop - ]; - } else { - isSystemUser = true; - } - ) - ]; - }; -} \ No newline at end of file diff --git a/users/leyla/default.nix b/users/leyla/default.nix deleted file mode 100644 index 7a8dc54..0000000 --- a/users/leyla/default.nix +++ /dev/null @@ -1,72 +0,0 @@ -{ lib, config, pkgs, ... }: -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"; - hasPiperMouse = lib.mkEnableOption "install programs for managing piper supported mouses"; - hasOpenRGBHardware = lib.mkEnableOption "install programs for managing openRGB supported hardware"; - hasViaKeyboard = lib.mkEnableOption "install programs for managing via supported keyboards"; - hasGPU = lib.mkEnableOption "installs gpu intensive programs"; - }; - - config = { - sops.secrets = lib.mkIf (cfg.isFullUser || cfg.isThinUser) { - "passwords/leyla" = { - neededForUsers = true; - # sopsFile = ../secrets.yaml; - }; - }; - - users.groups.leyla = {}; - - users.users.leyla = lib.mkMerge [ - { - uid = 1000; - description = "Leyla"; - group = "leyla"; - } - - ( - if (cfg.isFullUser || cfg.isThinUser) then { - isNormalUser = true; - extraGroups = lib.mkMerge [ - ["networkmanager" "wheel" "users"] - ( - 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); - }; -} \ No newline at end of file diff --git a/users/leyla/home.nix b/users/leyla/home.nix deleted file mode 100644 index 40a6926..0000000 --- a/users/leyla/home.nix +++ /dev/null @@ -1,125 +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" = true; - "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 223f568..0000000 --- a/users/leyla/packages.nix +++ /dev/null @@ -1,129 +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 cfg.hasPiperMouse piper) - (lib.mkIf cfg.hasOpenRGBHardware openrgb) - (lib.mkIf cfg.hasViaKeyboard via) - ] - ) - ) - ] - ); -} \ No newline at end of file diff --git a/util/default.nix b/util/default.nix index a4fab1e..fb2f83d 100644 --- a/util/default.nix +++ b/util/default.nix @@ -1,8 +1,128 @@ -_: -{ - # mkUnless = condition: then: (mkIf (!condition) then); - # mkIfElse = condition: then: else: lib.mkMerge [ - # (mkIf condition then) - # (mkUnless condition else) - # ]; -} \ No newline at end of file +{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) + ]; + }; +}