diff --git a/README.md b/README.md new file mode 100644 index 0000000..1cfefab --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# nixos-config + +> Declarative, reproducible configuration for all my NixOS systems +> Covers workstation/gaming, laptop, and homelab/server use cases. + +## Overview + +This repository maanges **multiple NixOS systems** using a shared modular configuration. +It's designed to be **secure, composable, and automated** using modern Nix tooling. + +- **Laptop ("neon")**: Portable KVM/Swiss-Army Knife +- **Homelab Server ("lithium")**: Identity, Backups, Forgejo, Jellyfin +- **Workstation / Gaming ("titanium")**: Dev and Gaming /w Steam/Proton +- Secrets managed via `sops-nix` +- Deployable with `nixos-rebuild` (and soon `deploy-rs` or `nixos-anywhere`) + + +## How to use this? (Deployment) + +With [home-manager](https://github.com/nix-community/home-manager) included as +an input to the flake, and pulled into the hosts along with their users, this +will automatically apply updates to both the system and user environments. + + +```bash +# This will show what the flake has to offer. +nix flake show + +# Build a VM to test config +nixos-rebuild build-vm --flake .#hostname + +# Preview and apply changes on a nixOS system +nixos-rebuild dry-run --flake .#hostname +sudo nixos-rebuild switch --flake .#hostname + +# Preview and apply changes on a macOS system +darwin-rebuild dry-run --flake .#hostname +darwin-rebuild switch --flake .#hostname + +# Generate an Install ISO +nix build .#nixosConfigurations.installIso.config.system.build.images.iso + +# Verify the ISO contents +sudo mount -o loop result/iso/nixos-*.iso mnt +ls mnt +umount mnt +``` + +## Design Goals + +- **Reproducibility**: All systems can be rebuilt from this repo +- **Modularity**: Every services is a reusable module +- **Security**: Minimal trust, secrets managed explicitly +- **Composability**: Roles + services enable rapid provisioning + +## Directory Layout / Organization + +``` +├── flake.nix # sets inputs, imports lib functions, wires hosts and users +├── lib # functions to build flake outputs +├── hosts +│   ├── +│   │   ├── configuration.nix # imports from ../../modules/nixos +│   │   ├── hardware.nix # host specific hardware configuration +│   │   └── default.nix # entrypoint for host configuration +├── users +│   ├── +│   │   ├── default.nix # entrypoint for user configuration +│   │   └── home.nix # imports from ../../modules/home/ +├── modules # Reusable NixOS and Home-Manager Modules +│   ├── nixos # host configuration modules +│   └── home # home-manager modules +├── overlays # Custom Nixpkgs overlays that modify existing pacakges. +└── pkgs # Custom Nix packages (not in nixpkgs) + +``` + +## References + +- [@shazow](https://github.com/shazow/) and https://github.com/shazow/nixfiles/ +- [@ryan4yin] and the contributors and co-authors of [nixos-and-flakes-book](https://nixos-and-flakes.thiscute.world/) +- [@Mic92] for https://github.com/Mic92/sops-nix and https://blog.thalheim.io/ +- Various GitHub Projects found with searches [similar to this](https://github.com/search?q=language%3ANix+sops-nix.nixosModules.sops&type=code) +- https://nix.dev/ and https://search.nixos.org/ +- https://edolstra.github.io/pubs/phd-thesis.pdf diff --git a/flake.lock b/flake.lock index b014985..8daf022 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,79 @@ { "nodes": { + "crane": { + "locked": { + "lastModified": 1731098351, + "narHash": "sha256-HQkYvKvaLQqNa10KEFGgWHfMAbWBfFp+4cAgkut+NNE=", + "owner": "ipetkov", + "repo": "crane", + "rev": "ef80ead953c1b28316cc3f8613904edc2eb90c28", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1730504689, + "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "506278e768c2a08bec68eb62932193e341f55c90", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "pre-commit-hooks-nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -7,11 +81,11 @@ ] }, "locked": { - "lastModified": 1748979197, - "narHash": "sha256-mKYwYcO9RmA2AcAFIXGDBOw5iv/fbjw6adWvMbnfIuk=", + "lastModified": 1749499854, + "narHash": "sha256-V1BgwiX8NjbRreU6LC2EzmuqFSQAHhoSeNlYJyZ40NE=", "owner": "nix-community", "repo": "home-manager", - "rev": "34a13086148cbb3ae65a79f753eb451ce5cac3d3", + "rev": "1df816c407d3a5090c8496c9b00170af7891f021", "type": "github" }, "original": { @@ -20,13 +94,39 @@ "type": "github" } }, + "lanzaboote": { + "inputs": { + "crane": "crane", + "flake-compat": "flake-compat", + "flake-parts": "flake-parts", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit-hooks-nix": "pre-commit-hooks-nix", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1737639419, + "narHash": "sha256-AEEDktApTEZ5PZXNDkry2YV2k6t0dTgLPEmAZbnigXU=", + "owner": "nix-community", + "repo": "lanzaboote", + "rev": "a65905a09e2c43ff63be8c0e86a93712361f871e", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "v0.4.2", + "repo": "lanzaboote", + "type": "github" + } + }, "nixos-hardware": { "locked": { - "lastModified": 1748942041, - "narHash": "sha256-HEu2gTct7nY0tAPRgBtqYepallryBKR1U8B4v2zEEqA=", + "lastModified": 1749195551, + "narHash": "sha256-W5GKQHgunda/OP9sbKENBZhMBDNu2QahoIPwnsF6CeM=", "owner": "nixos", "repo": "nixos-hardware", - "rev": "fc7c4714125cfaa19b048e8aaf86b9c53e04d853", + "rev": "4602f7e1d3f197b3cb540d5accf5669121629628", "type": "github" }, "original": { @@ -37,11 +137,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1748929857, - "narHash": "sha256-lcZQ8RhsmhsK8u7LIFsJhsLh/pzR9yZ8yqpTzyGdj+Q=", + "lastModified": 1749285348, + "narHash": "sha256-frdhQvPbmDYaScPFiCnfdh3B/Vh81Uuoo0w5TkWmmjU=", "owner": "nixos", "repo": "nixpkgs", - "rev": "c2a03962b8e24e669fb37b7df10e7c79531ff1a4", + "rev": "3e3afe5174c561dee0df6f2c2b2236990146329f", "type": "github" }, "original": { @@ -51,14 +151,79 @@ "type": "github" } }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1730741070, + "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks-nix": { + "inputs": { + "flake-compat": [ + "lanzaboote", + "flake-compat" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1731363552, + "narHash": "sha256-vFta1uHnD29VUY4HJOO/D6p6rxyObnf+InnSMT4jlMU=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "cd1af27aa85026ac759d5d3fccf650abe7e1bbf0", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, "root": { "inputs": { "home-manager": "home-manager", + "lanzaboote": "lanzaboote", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs", "sops-nix": "sops-nix" } }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1731897198, + "narHash": "sha256-Ou7vLETSKwmE/HRQz4cImXXJBr/k9gp4J4z/PF8LzTE=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "0be641045af6d8666c11c2c40e45ffc9667839b5", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, "sops-nix": { "inputs": { "nixpkgs": [ diff --git a/flake.nix b/flake.nix index 517bc72..707151c 100644 --- a/flake.nix +++ b/flake.nix @@ -5,29 +5,66 @@ nixos-hardware.url = "github:nixos/nixos-hardware"; home-manager.url = "github:nix-community/home-manager"; home-manager.inputs.nixpkgs.follows = "nixpkgs"; + lanzaboote.url = "github:nix-community/lanzaboote/v0.4.2"; + lanzaboote.inputs.nixpkgs.follows = "nixpkgs"; sops-nix.url = "github:Mic92/sops-nix"; sops-nix.inputs.nixpkgs.follows = "nixpkgs"; }; - outputs = inputs@{self, nixpkgs, nixos-hardware, sops-nix, ...}: + # https://nix.dev/tutorials/nix-language.html#named-attribute-set-argument + outputs = inputs@{self, nixpkgs, nixos-hardware, home-manager, sops-nix, lanzaboote, ...}: + let + mkSystem = (import ./lib { + inherit nixpkgs home-manager inputs; + }).mkSystem; + in { + # NOTE: Run `nix flake show` to see what this flake has to offer. + # TODO: Enable automated formatting with something like numtide/treefmt-nix nixosConfigurations = { - neon = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - modules = [ - # https://github.com/NixOS/nixos-hardware/blob/master/README.md#using-nix-flakes-support - nixos-hardware.nixosModules.gpd-pocket-3 - ./hosts/neon - # override from nixos-hardware - ({config, lib, ...}: { services.xserver.videoDrivers = lib.mkForce [ "modesetting" ]; }) + neon = mkSystem { + hostname = "neon"; + users = [ "jml" ]; + }; + lithium = mkSystem { + hostname = "lithium"; + # extraModules = [ inputs.sops-nix.nixosModules.sops ]; + users = [ + "jml" + "breakglass" ]; }; - lithium = nixpkgs.lib.nixosSystem { + titanium = mkSystem { + hostname = "titanium"; + users = [ + "jml" + ]; + extraModules = [ + { nixpkgs.config.allowUnfree = true; } + lanzaboote.nixosModules.lanzaboote + ({ pkgs, lib, ... }: { + environment.systemPackages = [ pkgs.sbctl ]; + boot.loader.systemd-boot.enable = lib.mkForce false; + boot.lanzaboote.enable = true; + boot.lanzaboote.pkiBundle = "/var/lib/sbctl"; + }) + ]; + }; + # `nix build .#nixosConfigurations.installIso.config.system.build.isoImage` + # https://github.com/nix-community/nixos-generators + installIso = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ - ./hosts/lithium - sops-nix.nixosModules.sops + "${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix" ]; + specialArgs = {inherit inputs;}; }; }; + homeConfigurations = { + "jml" = home-manager.lib.homeManagerConfiguration { + modules = [ + ./users/jml/home.nix + ]; + }; + }; }; } diff --git a/hosts/lithium/README.md b/hosts/lithium/README.md index 7c19beb..1cdad59 100644 --- a/hosts/lithium/README.md +++ b/hosts/lithium/README.md @@ -2,10 +2,22 @@ This is my primary homelab host/NAS, previously powered by TrueNAS Scale/k3s. +## Manual Actions + +Even with fully declarative Nix/Nixpkgs/NixOS at the end of the day there are +still some actions that need to be taken manually. + +- secrets configuration (both for SOPS and git-agecrypt semi-secrets) +- kanidm user management +- tailscale auth key +- jellyfin configuration via web-ui + ## Semi-Secrets -`semi-secret-vars.nix` is following a pattern I discovered here: - https://github.com/nyawox/arcanum/blob/4629dfba1bc6d4dd2f4cf45724df81289230b61a/var/README.md +`semi-secret-vars.nix` is using [git-agecrypt](https://github.com/vlaci/git-agecrypt) +and following a pattern I discovered here: + - https://github.com/nyawox/arcanum/blob/4629dfba1bc6d4dd2f4cf45724df81289230b61a/var/README.md + - https://github.com/vlaci/git-agecrypt Essentially there are some details I won't want exposed in the repository, but I do want them available to all my nix modules. The main one being the domain. diff --git a/hosts/lithium/configuration.nix b/hosts/lithium/configuration.nix index 91ee105..5023ef1 100644 --- a/hosts/lithium/configuration.nix +++ b/hosts/lithium/configuration.nix @@ -1,130 +1,13 @@ -# 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`). { config, pkgs, ... }: { - # Setup sops default secrets. sops.defaultSopsFile = ./secrets/common.yaml; - - # Use the systemd-boot EFI boot loader. - boot.loader.systemd-boot.enable = true; - boot.loader.efi.canTouchEfiVariables = true; - - # TODO: Request 192.168.50.3 over DHCP - # Currently this is enforced at the router layer on a single interface. - # I'd dramatically prefer it to be a bond0 interface but w/e it is what it is. - networking.hostName = "lithium"; # Define your hostname. + networking.hostName = "lithium"; networking.domain = config.vars.domain; - # 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 = "America/Chicago"; - - # 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.xserver.displayManager.gdm.enable = true; - #services.xserver.desktopManager.gnome.enable = true; - - - # 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.jay = { - isNormalUser = true; - extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. - packages = with pkgs; [ - tree - ]; - }; - nixpkgs.config.allowUnfree = true; - nix.settings = { - experimental-features = [ "nix-command" "flakes" ]; - }; - - # List packages installed in system profile. - # You can use https://search.nixos.org/ to find more packages (and options). environment.systemPackages = with pkgs; [ - vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default. - git zfs - # wget ]; - - # 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; - - # 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? - + programs.mosh.enable = true; + system.stateVersion = "25.05"; } diff --git a/hosts/lithium/default.nix b/hosts/lithium/default.nix index 7a2d30d..4a02b76 100644 --- a/hosts/lithium/default.nix +++ b/hosts/lithium/default.nix @@ -1,12 +1,16 @@ -{ ... }: +{ inputs, ... }: { imports = [ + ../../modules/nixos/base.nix + inputs.sops-nix.nixosModules.sops ./hardware.nix ./configuration.nix ./semi-secret-vars.nix ./services/caddy.nix + ./services/tailscale.nix ./services/kanidm.nix ./services/jellyfin.nix ./services/uptime-kuma.nix + ./services/file-shares.nix ]; } diff --git a/hosts/lithium/services/file-shares.nix b/hosts/lithium/services/file-shares.nix new file mode 100644 index 0000000..7bf60b2 --- /dev/null +++ b/hosts/lithium/services/file-shares.nix @@ -0,0 +1,78 @@ +{ ... }: +{ + # NOTE: We do need to guarantee this group exists. + # and manually provision users with `sudo smbpasswd -a $username` + users.groups.samba = {}; + services.samba = { + enable = true; + openFirewall = true; + + nmbd.enable = false; # NOTE: Disable NetBIOS responses. + # usershares.enable = true; # NOTE: Members of group "samba" can create usershares. + + # NOTE: Refer to https://www.samba.org/samba/docs/current/man-html/smb.conf.5.html + # to configure this service. + settings = { + global = { + workgroup = "WORKGROUP"; + "hosts allow" = "192.168.50."; + "hosts deny" = "ALL"; + "guest account" = "nobody"; + "map to guest" = "bad user"; + + "log file" = "/var/log/samba/%m.log"; + "max log size" = 1000; + + "create mask" = "0660"; + "directory mask" = "2770"; + }; + + # NOTE: usershares enables users to create their own shares. This creates + # a share per-user. + homes = { + browseable = "no"; + writable = "yes"; + "read only" = "no"; + "guest ok" = "no"; + "valid users" = "%S"; + path = "/tank/shares/personal/%S"; + }; + + staging = { + comment = "Temp Upload Area"; + path = "/tank/shares/staging"; + browseable = "yes"; + writable = "yes"; + "guest ok" = "yes"; + "force user" = "nobody"; + "force group" = "nogroup"; + "create mask" = "0666"; + "directory mask" = "0777"; + }; + + backups = { + comment = "Device Backups"; + path = "/tank/shares/backups"; + browseable = "no"; + writable = "yes"; + "valid users" = "@samba"; + "guest ok" = "no"; + }; + + ## TODO: Time Machine Configuration + # http://wiki.nixos.org/wiki/Samba#Apple_Time_Machine + }; + }; + + # NOTE: This is used to advertise shares to Windows hosts. + services.samba-wsdd = { + enable = true; + openFirewall = true; + }; + #services.avahi = { + #enable = true; + #openFirewall = true; + #publish.enable = true; + #publish.userServices = true; + #}; +} diff --git a/hosts/lithium/services/tailscale.nix b/hosts/lithium/services/tailscale.nix new file mode 100644 index 0000000..4fee47f --- /dev/null +++ b/hosts/lithium/services/tailscale.nix @@ -0,0 +1,22 @@ +{ config, pkgs, ... }: +#let + #hostName = config.networking.hostName; + #tailnetName = "tail79151.ts.net"; + #svcDomain = "${hostName}.${tailnetName}"; +#in +{ + # NOTE: This does require a manual step of creating a tailscale account if + # you don't already have one, and generating an Auth Key: + # https://login.tailscale.com/admin/machines/new-linux + # After enabling this and generating an install script copy the authkey and + # run: `sudo tailscale up --auth-key=KEY` + + # NOTE: Use Caddy to create and manage SSL Certs for Tailscale + #services.caddy.virtualHosts."${svcDomain}".extraConfig = '' + #reverse_proxy : + #''; + services.tailscale = { + enable = true; + #permitCertUid = "caddy"; # Allow caddy to edit certs + }; +} diff --git a/hosts/neon/configuration.nix b/hosts/neon/configuration.nix index 82b0a8e..8dbe56d 100644 --- a/hosts/neon/configuration.nix +++ b/hosts/neon/configuration.nix @@ -1,147 +1,7 @@ -# Edit this configuration file to define what should be installed on -# your system. Help is available in the configuration.nix(5) man page -# and in the NixOS manual (accessible by running ‘nixos-help’). - -{ config, pkgs, ... }: - +{ ... }: { - # Bootloader. - boot.loader.systemd-boot.enable = true; - boot.loader.efi.canTouchEfiVariables = true; - - networking.hostName = "neon"; # Define your hostname. - # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. - - # Enable networking + networking.hostName = "neon"; networking.networkmanager.enable = true; - - # Set your time zone. - time.timeZone = "America/Chicago"; - - # Select internationalisation properties. - 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"; - }; - - # Enable the X11 windowing system. - services.xserver.enable = true; - - # Enable the GNOME Desktop Environment. - services.xserver.displayManager.gdm.enable = true; - services.xserver.desktopManager.gnome.enable = true; - - # Configure keymap in X11 - services.xserver.xkb.layout = "us"; - - # Enable CUPS to print documents. - # services.printing.enable = true; - - # Enable sound with pipewire. - # sound.enable = true; - hardware.pulseaudio.enable = false; - security.rtkit.enable = true; - services.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 touchpad support (enabled default in most desktopManager). - # services.xserver.libinput.enable = true; - - # Define a user account. Don't forget to set a password with ‘passwd’. - users.users.jml = { - isNormalUser = true; - description = "Jay Looney"; - extraGroups = [ "networkmanager" "wheel" ]; - packages = with pkgs; [ - firefox - ]; - }; - - # Enable automatic login for the user. - services.displayManager.autoLogin.enable = true; - services.displayManager.autoLogin.user = "jml"; - - # Workaround for GNOME autologin: https://github.com/NixOS/nixpkgs/issues/103746#issuecomment-945091229 - systemd.services."getty@tty1".enable = false; - systemd.services."autovt@tty1".enable = false; - - # Allow unfree packages - nixpkgs.config.allowUnfree = true; - - nix.settings = { - experimental-features = [ "nix-command" "flakes" ]; - # substituters = ["https://hyprland.cachix.org"]; - # trusted-public-keys = ["hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc="]; - }; - - # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default. - environment.systemPackages = with pkgs; [ - home-manager - neovim - git - yubikey-personalization - kitty # hyprland default term - swww # wallpaper - xdg-desktop-portal-gtk - xdg-desktop-portal-hyprland - xwayland - ]; - - programs.neovim.enable = true; - programs.neovim.defaultEditor = true; - environment.variables = { - EDITOR = "nvim"; - VISUAL = "nvim"; - }; - - # Some programs need SUID wrappers, can be configured further or are - # started in user sessions. - programs.hyprland = { - enable = true; - # following along with stackademic installing nixos with hyprland - xwayland.enable = true; - #xwayland.hidpi = true; - }; - # Hint electron apps to use wayland - environment.sessionVariables = { - NIXOS_OZONE_WL = "1"; - }; - # screen sharing /w hyp - services.dbus.enable = true; - - # 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; - - # 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? + system.stateVersion = "23.05"; } diff --git a/hosts/neon/default.nix b/hosts/neon/default.nix index 045c642..6d3d3e0 100644 --- a/hosts/neon/default.nix +++ b/hosts/neon/default.nix @@ -1,6 +1,13 @@ -{ ... }: +{ inputs, ... }: { imports = [ + ../../modules/nixos/base.nix + ../../modules/nixos/audio.nix + ../../modules/nixos/desktop.nix + # https://github.com/NixOS/nixos-hardware/blob/master/README.md#using-nix-flakes-support + inputs.nixos-hardware.nixosModules.gpd-pocket-3 + # override from nixos-hardware + ({config, lib, ...}: { services.xserver.videoDrivers = lib.mkForce [ "modesetting" ]; }) ./hardware-configuration.nix ./configuration.nix ]; diff --git a/hosts/titanium/configuration.nix b/hosts/titanium/configuration.nix new file mode 100644 index 0000000..f2566c0 --- /dev/null +++ b/hosts/titanium/configuration.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, ... }: +{ + networking.hostName = "titanium"; + networking.networkmanager.enable = true; + environment.systemPackages = with pkgs; [ + sbctl # Secure-Boot + helix nil # nice for editing '.nix' + discord + signal-desktop + obs-studio + ]; + # Hardware Specific programs... + #programs.ryzen-monitor-ng.enable = true; + #programs.rog-control-center.enable = true; + services.openssh.enable = true; + services.tailscale.enable = true; + networking.firewall.trustedInterfaces = [ "tailscale0" ]; + system.stateVersion = "25.05"; +} diff --git a/hosts/titanium/default.nix b/hosts/titanium/default.nix new file mode 100644 index 0000000..77305be --- /dev/null +++ b/hosts/titanium/default.nix @@ -0,0 +1,12 @@ +{ inputs, ... }: +{ + imports = [ + ../../modules/nixos/base.nix + ../../modules/nixos/audio.nix + ../../modules/nixos/desktop.nix + ../../modules/nixos/gaming.nix + inputs.nixos-hardware.nixosModules.asus-rog-strix-x570e + ./hardware.nix + ./configuration.nix + ]; +} diff --git a/hosts/titanium/disko.nix b/hosts/titanium/disko.nix new file mode 100644 index 0000000..97a2b39 --- /dev/null +++ b/hosts/titanium/disko.nix @@ -0,0 +1,76 @@ +{ ... }: +{ + # Based on: + # https://github.com/nix-community/disko/blob/master/example/luks-btrfs-subvolumes.nix + # + # Run with: + # `sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount /tmp/disk-config.nix` + disko.devices = { + disk = { + main-disk = { + type = "disk"; + device = "/dev/disk/by-path/pci-0000:08:00.0-ata-2"; + content = { + type = "gpt"; + partitions = { + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + luks = { + size = "100%"; # Full Disk Encryption + content = { + type = "luks"; + name = "crypted"; + # disable settings.keyFile if you want to use interactive password entry + # passwordFile = "/tmp/secret.key"; # Interactive + settings = { + allowDiscards = true; + #keyFile = "/tmp/secret.key"; + }; + #additionalKeyFiles = [ "/tmp/additionalSecret.key" ]; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; # What? + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/home" = { + mountpoint = "/home"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/swap" = { + mountpoint = "/.swapvol"; + swap.swapfile.size = "16G"; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/hosts/titanium/hardware.nix b/hosts/titanium/hardware.nix new file mode 100644 index 0000000..da5e356 --- /dev/null +++ b/hosts/titanium/hardware.nix @@ -0,0 +1,72 @@ +# 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" "usbhid" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-amd" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/0b3de117-c34f-4cc6-81db-5b84ea46cd51"; + fsType = "btrfs"; + options = [ "subvol=root" ]; + }; + + boot.initrd.luks.devices."crypted".device = "/dev/disk/by-uuid/0ccc4028-c27e-4259-ade9-a2b2081722cb"; + + fileSystems."/.swapvol" = + { device = "/dev/disk/by-uuid/0b3de117-c34f-4cc6-81db-5b84ea46cd51"; + fsType = "btrfs"; + options = [ "subvol=swap" ]; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/219D-4579"; + fsType = "vfat"; + options = [ "fmask=0077" "dmask=0077" ]; + }; + + fileSystems."/home" = + { device = "/dev/disk/by-uuid/0b3de117-c34f-4cc6-81db-5b84ea46cd51"; + fsType = "btrfs"; + options = [ "subvol=home" ]; + }; + + fileSystems."/nix" = + { device = "/dev/disk/by-uuid/0b3de117-c34f-4cc6-81db-5b84ea46cd51"; + fsType = "btrfs"; + options = [ "subvol=nix" ]; + }; + + 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.enp4s0.useDHCP = lib.mkDefault true; + # networking.interfaces.enp5s0.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp3s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + + # GPU Things + hardware.graphics.enable = true; + hardware.nvidia = { + # package = config.boot.kernelPackages.nvidiaPackages.stable; + modesetting.enable = true; + open = true; + nvidiaSettings = true; + powerManagement.enable = false; + powerManagement.finegrained = false; + }; +} diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..3926ed9 --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,47 @@ +{ nixpkgs, home-manager, inputs, ... }: +{ + # It's not really that I care about whether a system is a desktop system or + # a server system, but moreso that I care about whether a system is headless or not. + # I also care about things like if it's darwin, or wsl. + mkSystem = { + hostname, + system ? "x86_64-linux", + users ? [], + extraModules ? [] + }: + let + hostModule = import ../hosts/${hostname} { inherit inputs; }; + userModules = map (name: + import ../users/${name} { + pkgs = nixpkgs.legacyPackages.${system}; + lib = nixpkgs.lib; + } + ) users; + + homeUserNames = builtins.filter (name: + builtins.pathExists ../users/${name}/home.nix + ) users; + + homeUsers = nixpkgs.lib.listToAttrs (map (name: { + name = name; + value = import ../users/${name}/home.nix { + username = name; + pkgs = nixpkgs.legacyPackages.${system}; + lib = nixpkgs.lib; + }; + }) homeUserNames); + in + nixpkgs.lib.nixosSystem { + inherit system; + modules = [ hostModule ] + ++ userModules + ++ extraModules + ++ (if homeUserNames != [] then [ + home-manager.nixosModules.home-manager + { + home-manager.backupFileExtension = "hm-bak"; + home-manager.users = homeUsers; + } + ] else []); + }; +} diff --git a/modules/nixos/audio.nix b/modules/nixos/audio.nix new file mode 100644 index 0000000..a897bb4 --- /dev/null +++ b/modules/nixos/audio.nix @@ -0,0 +1,15 @@ +{ pkgs, ... }: +{ + # For real-time audio/production consider: https://github.com/musnix/musnix + security.rtkit.enable = true; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + }; + + environment.systemPackages = with pkgs; [ + pavucontrol + ]; +} diff --git a/modules/nixos/base.nix b/modules/nixos/base.nix new file mode 100644 index 0000000..036a5c9 --- /dev/null +++ b/modules/nixos/base.nix @@ -0,0 +1,110 @@ +{ config, pkgs, lib, ... }: +{ + nixpkgs.config.allowUnfree = true; + nix.settings = { + experimental-features = [ "nix-command" "flakes" ]; + }; + + # Default to systemd-boot + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + # https://datatracker.ietf.org/doc/html/rfc8375 + networking.domain = "home.arpa"; + + 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"; + }; + + console.font = null; # Kernel will automatically choose a font. + console.keyMap = "us"; + # 4-bit ANSI -> Catpuccin Mocha Colors: https://catppuccin.com/palette/ + console.colors = [ + "11111b" # black -> crust + "f38ba8" # red -> red + "a6e3a1" # green -> green + "fab387" # yellow -> peach + "89b4fa" # blue -> blue + "cba6f7" # magenta -> mauve + "74c7ec" # cyan -> sapphire + "6c7086" # white -> overlay 0 + "313244" # bright black (gray) -> surface 0 + "eba0ac" # bright red -> maroon + "94e2d5" # bright green -> teal + "f9e2af" # bright yellow -> yellow + "b4befe" # bright blue -> lavender + "f5c2e7" # bright magenta -> pink + "89dceb" # bright cyan -> sky + "cdd6f4" # bright white -> text + ]; + + networking.firewall.enable = true; + + # Installed on every NixOS Host. + environment.systemPackages = with pkgs; [ + wget curl + ripgrep + ]; + programs = { + less = { + enable = true; + # https://ascending.wordpress.com/2011/02/11/unix-tip-make-less-more-friendly/ + # https://www.topbug.net/blog/2016/09/27/make-gnu-less-more-powerful/ + envVariables = { + LESS = lib.concatStrings [ + "--quit-if-one-screen " + "--ignore-case " + "--long-prompt " + "--raw-control-chars " # raw ANSI colors + "--hilite-unread " # first unread line after forward screen + "--tabs=4 " + "--no-init " # Don't use termcap init/deinit strings. + ]; + # Render colors + # TODO: Figure out how to represent those termcap sequences properly. + #LESS_TERMCAP_mb=$'\E[1;31m' # begin bold + #LESS_TERMCAP_md=$'\E[1;36m' # begin blink + #LESS_TERMCAP_me=$'\E[0m' # reset bold/blink + #LESS_TERMCAP_so=$'\E[01;44;33m' # begin reverse video + #LESS_TERMCAP_se=$'\E[0m' # reset reverse video + #LESS_TERMCAP_us=$'\E[1;32m' # begin underline + #LESS_TERMCAP_ue=$'\E[0m' # reset underline + }; + }; + + git.enable = true; + htop.enable = true; + command-not-found.enable = false; + bat.enable = true; + bandwhich.enable = true; + + nano.enable = false; + neovim = { + enable = true; + defaultEditor = true; + + viAlias = true; + vimAlias = true; + + withRuby = true; + withPython3 = true; + withNodeJs = true; + + #configure = {}; + }; + }; + + # Services running on all machines + services.avahi.enable = true; # zeroconf/mDNS(.local) +} diff --git a/modules/nixos/desktop.nix b/modules/nixos/desktop.nix new file mode 100644 index 0000000..7251a84 --- /dev/null +++ b/modules/nixos/desktop.nix @@ -0,0 +1,40 @@ +{ pkgs, ... }: +{ + environment.systemPackages = with pkgs; [ + yubikey-personalization + xdg-desktop-portal-gtk + xdg-desktop-portal-hyprland + xwayland + rofi-wayland + waybar + hyprpaper + kitty # hyprland default term + swww # wallpaper + ]; + services.xserver.enable = true; + services.xserver.xkb.layout = "us"; + + services.displayManager.gdm.enable = true; + services.desktopManager.gnome.enable = true; + + services.printing.enable = true; + + programs.hyprland = { + enable = true; + withUWSM = true; + xwayland.enable = true; + }; + programs.hyprlock.enable = true; + # Hint electron apps to use wayland + environment.sessionVariables = { + NIXOS_OZONE_WL = "1"; + }; + # screen sharing /w hyp + services.dbus.enable = true; + + fonts.packages = with pkgs; [ + nerd-fonts.fira-code + nerd-fonts.iosevka + atkinson-hyperlegible + ]; +} diff --git a/modules/nixos/gaming.nix b/modules/nixos/gaming.nix new file mode 100644 index 0000000..68b2946 --- /dev/null +++ b/modules/nixos/gaming.nix @@ -0,0 +1,17 @@ +{ config, lib, pkgs, ... }: +{ + environment.systemPackages = with pkgs; [ + mangohud + protonup-qt + lutris + bottles + heroic + ]; + programs.steam = { + enable = true; + remotePlay.openFirewall = true; + localNetworkGameTransfers.openFirewall = true; + protontricks.enable = true; + gamescopeSession.enable = true; + }; +} diff --git a/users/breakglass/default.nix b/users/breakglass/default.nix new file mode 100644 index 0000000..9318130 --- /dev/null +++ b/users/breakglass/default.nix @@ -0,0 +1,17 @@ +{ pkgs, lib, ... }: +{ + users.users.breakglass = { + home = + if pkgs.stdenv.isLinux then + lib.mkDefault "/home/breakglass" + else if pkgs.stdenv.isDarwin then + lib.mkDefault "/Users/breakglass" + else + abort "Unsupported OS"; + } // lib.optionalAttrs pkgs.stdenv.isLinux { + isNormalUser = true; + extraGroups = [ "wheel" ]; + # NOTE: Generated with `mkpasswd` + hashedPassword = "$y$j9T$U7phasQYqMhxY8WXoiHL51$IHHDTreR4uZrvAC1Xusjy2M0yXkU.vLy3z6zBjZCFX."; + }; +} diff --git a/users/jml/default.nix b/users/jml/default.nix new file mode 100644 index 0000000..592e6ba --- /dev/null +++ b/users/jml/default.nix @@ -0,0 +1,18 @@ +{ pkgs, lib, ... }: +{ + programs.fish.enable = true; + users.users.jml = { + shell = pkgs.fish; + home = + if pkgs.stdenv.isLinux then + lib.mkDefault "/home/jml" + else if pkgs.stdenv.isDarwin then + lib.mkDefault "/Users/jml" + else + abort "Unsupported OS"; + } // lib.optionalAttrs pkgs.stdenv.isLinux { + isNormalUser = true; + extraGroups = [ "networkmanager" "wheel" "samba" ]; + initialHashedPassword = "$y$j9T$R9y36VAOEudqmyVVgyYLD1$xQktVMaRP9qiARiJ6KATvyH6VAL1IKSJoPAo7k4YNZ."; + }; +} diff --git a/users/jml/home.nix b/users/jml/home.nix new file mode 100644 index 0000000..e6170c6 --- /dev/null +++ b/users/jml/home.nix @@ -0,0 +1,166 @@ +{ username, pkgs, lib, ... }: +{ + nixpkgs.config.allowUnfree = true; + # The following line is needed if I start using hyprland Home Manager Module + #wayland.windowManager.sway.systemd.enable = false; + # NOTE: This file contains options that resolve under home-manager.users. + home = { + inherit username; + stateVersion = "25.05"; + sessionVariables = { + EDITOR = "hx"; + }; + + homeDirectory = + if pkgs.stdenv.isLinux then + lib.mkDefault "/home/${username}" + else if pkgs.stdenv.isDarwin then + lib.mkDefault "/Users/${username}" + else + abort "Unsupported OS"; + }; + home.packages = with pkgs; [ ] + # linux only + # TODO: Add a test for linux + desktop environment + ++ (lib.optionals pkgs.stdenv.isLinux [ + cfspeedtest + helix + nil + ]) + # linux + desktop manager + #++ (lib.optionals (pkgs.stdenv.isLinux && osConfig.services.desktopManager.enabled != null) + #[ + # firefox + #]) + # darwin only + ++ (lib.optionals pkgs.stdenv.isDarwin [ + cfspeedtest + ripgrep + ]); + + programs = { + fish.enable = true; + home-manager.enable = true; + bat.enable = true; + fzf.enable = true; + jq.enable = true; + btop.enable = true; + zellij.enable = true; + + # Matrix Chat Apps + element-desktop.enable = true; + nheko.settings = true; + + # Additions from Windows + obsidian.enable = true; + obs-studio.enable = true; + keepassxc.enable = true; + wezterm.enable = true; + ghostty.enable = true; + gpg.enable = true; + # onedrive.enable = true; + # thunderbird.enable = true; + # vdirsyncer.enable = true; + nushell.enable = true; + helix.enable = true; + zoxide.enable = true; + fd.enable = true; + }; + + programs.starship = { + enable = true; + settings = { + add_newline = false; + line_break.disabled = true; + aws.disabled = true; + gcloud.disabled = true; + }; + }; + + programs.firefox = { + enable = true; + policies = { + DontCheckDefaultBrowser = true; + DisableTelemetry = true; + DisableFirefoxStudies = true; + DisablePocket = true; + DisableFirefoxScreenshots = true; + + UserMessaging = { + UrlbarInterventions = false; + SkipOnboarding = true; + }; + FirefoxSuggest = { + WebSuggestions = false; + SponsoredSuggestions = false; + ImproveSuggest = false; + }; + EnableTrackingProtection = { + Value = true; + Cryptomining = true; + Fingerprinting = true; + }; + + Homepage.StartPage = "previous-session"; + FirefoxHome = { + Search = true; + TopSites = false; + SponsoredTopSites = false; + Highlights = false; + Pocket = false; + SponsoredPocket = false; + Snippets = false; + }; + + Handlers.schemes.element = { + action = "useSystemDefault"; + ask = false; + }; + + Preferences = { + "browser.urlbar.suggest.searches" = true; + "browser.tabs.tabMinWidth" = 75; + + "browser.aboutConfig.showWarning" = false; + "browser.warnOnQuitShortcut" = false; + + "browser.tabs.loadInBackground" = true; + "browser.in-content.dark-mode" = true; + }; + }; + profiles = { + default = { + id = 0; + name = "default"; + isDefault = true; + settings = { + "widget.disable-workspace-management" = true; + }; + search = { + force = true; + default = "ddg"; # DuckDuckGo + }; + }; + }; + }; + + programs.git = { + enable = true; + userName = "Jay Looney"; + userEmail = "jay.m.looney@gmail.com"; + aliases = { + ol = "log --oneline"; + }; + ignores = [ "*~" "*.swp" ]; + extraConfig = { + push.default = "simple"; + credential.helper = "cache --timeout=7200"; + init.defaultBranch = "main"; + log.decorate = "full"; + log.date = "iso"; + merge.conflictStyle = "diff3"; + }; + }; + + # services.podman.enable = true; +}