diff --git a/README.md b/README.md index f8a2a26..9b50571 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,98 @@ # nixos +## Installation +Follow the [NixOS manual](https://nixos.org/manual/nixos/stable/index.html#ch-installation) to obtain and boot +the installation medium. Use the graphical ISO image since it ships with useful programs such as `nmtui`; the +installation can still be done through the terminal. + +### Disk Partitioning +For [impermanence](https://nixos.wiki/wiki/Impermanence), partitioning should be done as outlined in the [tmpfs +as root](https://elis.nu/blog/2020/05/nixos-tmpfs-as-root/) blogpost, but with `/nix` as a [LUKS-encrypted file +system](https://nixos.org/manual/nixos/stable/index.html#sec-luks-file-systems). The boot partition will not be +encrypted, since that is poorly supported by systemd-boot. Persistent files will be saved under `/nix/persist`. + +The following is based on the [tmpfs as root](https://elis.nu/blog/2020/05/nixos-tmpfs-as-root/) blogpost, the NixOS +manual's [partitioning](https://nixos.org/manual/nixos/stable/index.html#sec-installation-manual-partitioning), +[formatting](https://nixos.orgmanual/nixos/stable/index.html#sec-installation-manual-partitioning-formatting) and +[LUKS-Encrypted File Systems](https://nixos.org/manual/nixos/stable/index.html#sec-luks-file-systems) sections, +ArchWiki's [LVM on LUKS](https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system#LVM_on_LUKS), +the unofficial NixOS wiki [Full Disk Encryption](https://nixos.wiki/wiki/Full_Disk_Encryption), and [this GitHub +gist](https://gist.github.com/martijnvermaat/76f2e24d0239470dd71050358b4d5134). + +We create a 1GiB EFI boot partition (`/dev/sda1`) and the rest will be our LUKS-encrypted volume: +```bash +# Create partition table +parted /dev/sda -- mklabel gpt + +# Create /boot partition +parted /dev/sda -- mkpart ESP fat32 1MiB 1024MiB +parted /dev/sda -- set 1 esp on + +# Create /nix partition +parted /dev/sda -- mkpart primary 1024MiB 100% + +# Create and open LUKS-encrypted container +cryptsetup --type=luks2 luksFormat --label=crypted /dev/sda2 +cryptsetup open /dev/sda2 crypted + +# Create LVM volume group +pvcreate /dev/mapper/crypted +vgcreate vg /dev/mapper/crypted + +# Create root logical volume +lvcreate -l 100%FREE vg -n root + +# Format partitions +mkfs.fat -F32 -n BOOT /dev/sda1 +mkfs.ext4 -L nix /dev/vg/root +``` + +The result should be the following (`lsblk -f`): +```text +NAME FSTYPE FSVER LABEL +vda +├─vda1 vfat FAT32 BOOT +└─vda2 crypto_LUKS 2 crypted + └─crypted LVM2_member LVM2 001 + └─vg-root ext4 1.0 nix +``` + +### Installation +Whereas the [NixOS manual](https://nixos.org/manual/nixos/stable/index.html#sec-installation-manual-installing) mounts +the newly-created `nixos` partition to `/mnt`, we will follow the _tmpfs as root_ blogpost and mount `/mnt` as `tmpfs`: +```bash +mount -t tmpfs none /mnt +mount --mkdir /dev/disk/by-label/BOOT /mnt/boot +mount --mkdir /dev/disk/by-label/nix /mnt/nix +mkdir -p /mnt/nix/persist/ +``` + +The remaining installation can be done (more or less) according to the [NixOS +manual](https://nixos.org/manual/nixos/stable/index.html#sec-installation-manual-installing). +```bash +cd /mnt/nix +git clone https://git.caspervk.net/caspervk/nixos.git tmp +cd tmp/ +nixos-generate-config --root /mnt --show-hardware-config +vim hosts/omega/hardware.nix +nixos-install --no-root-passwd --flake .#omega + +# Make sure to set a password +mkpasswd > /mnt/nix/persist/passwordfile +chmod 400 /mnt/nix/persist/passwordfile +``` + + +## Hardware Configuration +`hosts/*/hardware.nix`, while initially generated by `nixos-generate-config --show-hardware-config`, _is_ manually +modified. Irrelevant options are commented, instead of deleted, to allows for easier diffing on new versions of NixOS. + + +## Impermanence +To find out which of our darlings will be erased on reboot do `tree -x /`. + + +## Upgrading +```bash +sudo nixos-rebuild switch --flake .#omega +``` diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..d8fe028 --- /dev/null +++ b/flake.lock @@ -0,0 +1,65 @@ +{ + "nodes": { + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1687871164, + "narHash": "sha256-bBFlPthuYX322xOlpJvkjUBz0C+MOBjZdDOOJJ+G2jU=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "07c347bb50994691d7b0095f45ebd8838cf6bc38", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "release-23.05", + "repo": "home-manager", + "type": "github" + } + }, + "impermanence": { + "locked": { + "lastModified": 1690797372, + "narHash": "sha256-GImz19e33SeVcIvBB7NnhbJSbTpFFmNtWLh7Z85Y188=", + "owner": "nix-community", + "repo": "impermanence", + "rev": "e3a7acd113903269a1b5c8b527e84ce7ee859851", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "impermanence", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1690630041, + "narHash": "sha256-gbnvqm5goS9DSKAqGFpq3398aOpwejmq4qWikqmQyRo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d57e8c535d4cbb07f441c30988ce52eec69db7a8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "home-manager": "home-manager", + "impermanence": "impermanence", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..882a56e --- /dev/null +++ b/flake.nix @@ -0,0 +1,33 @@ +{ + description = "NixOS system"; + + inputs = { + nixpkgs = { + url = "github:NixOS/nixpkgs/nixos-23.05"; + }; + impermanence = { + url = "github:nix-community/impermanence"; + }; + nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; # use the same nixpkgs as the system + }; + home-manager = { + url = "github:nix-community/home-manager/release-23.05"; + inputs.nixpkgs.follows = "nixpkgs"; # use the same nixpkgs as the system + }; + }; + + outputs = { self, nixpkgs, ... }@inputs: { + nixosConfigurations = { + # Home desktop + omega = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = inputs; # pass flake inputs to modules + modules = [ + ./hosts/omega + ]; + }; + }; + }; +} diff --git a/home/default.nix b/home/default.nix new file mode 100644 index 0000000..e69de29 diff --git a/hosts/omega/default.nix b/hosts/omega/default.nix new file mode 100644 index 0000000..7390a60 --- /dev/null +++ b/hosts/omega/default.nix @@ -0,0 +1,36 @@ +{ ... }: + +{ + imports = [ + ./hardware.nix + ../../modules/base + ../../modules/desktop + ]; + + networking.hostName = "omega"; + + boot = { + loader = { + efi.canTouchEfiVariables = true; + systemd-boot.enable = true; + }; + initrd.luks.devices.crypted.device = "/dev/disk/by-label/crypted"; + }; + + # 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? + + # 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 can update Home Manager without changing this value. See + # the Home Manager release notes for a list of state version + # changes in each release. + home-manager.users.caspervk.home.stateVersion = "23.05"; # Did you read the comment? +} diff --git a/hosts/omega/hardware.nix b/hosts/omega/hardware.nix new file mode 100644 index 0000000..452f4e9 --- /dev/null +++ b/hosts/omega/hardware.nix @@ -0,0 +1,43 @@ +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ]; + boot.initrd.kernelModules = [ "dm-snapshot" ]; + boot.kernelModules = [ "kvm-amd" ]; + boot.extraModulePackages = [ ]; + + # https://elis.nu/blog/2020/05/nixos-tmpfs-as-root/ + fileSystems."/" = { + device = "none"; + fsType = "tmpfs"; + options = [ "defaults" "size=2G" "mode=755" ]; # mode=755 so only root can write to those files + }; + fileSystems."/boot" = { + device = "/dev/disk/by-label/BOOT"; + fsType = "vfat"; + }; + fileSystems."/nix" = { + device = "/dev/disk/by-label/nix"; + fsType = "ext4"; + }; + + swapDevices = [ + { + device = "/nix/persist/swapfile"; + size = 16*1024; # 16 GiB + } + ]; + + # 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.enp1s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/modules/base/default.nix b/modules/base/default.nix new file mode 100644 index 0000000..441e433 --- /dev/null +++ b/modules/base/default.nix @@ -0,0 +1,15 @@ +{ ... }: + +{ + imports = [ + ./fish.nix + ./git.nix + ./home-manager.nix + ./impermanence.nix + ./network.nix + ./ssh.nix + ./system.nix + ./users.nix + ./vim.nix + ]; +} diff --git a/modules/base/fish.nix b/modules/base/fish.nix new file mode 100644 index 0000000..a9c1159 --- /dev/null +++ b/modules/base/fish.nix @@ -0,0 +1,20 @@ +{ pkgs, ... }: { + # https://nixos.wiki/wiki/Fish + # https://nixos.wiki/wiki/Command_Shell + + environment.systemPackages = with pkgs; [ + fishPlugins.colored-man-pages + fishPlugins.fzf-fish + fishPlugins.puffer + fishPlugins.pure + ]; + + programs.fish = { + enable = true; + interactiveShellInit = '' + fzf_configure_bindings --directory=\cf --git_log=\cg + ''; + }; + users.defaultUserShell = pkgs.fish; + environment.shells = with pkgs; [ fish ]; +} diff --git a/modules/base/git.nix b/modules/base/git.nix new file mode 100644 index 0000000..c107b7a --- /dev/null +++ b/modules/base/git.nix @@ -0,0 +1,21 @@ +{ home-manager, ... }: { + + home-manager.users.caspervk = { + programs.git = { + enable = true; + userName = "Casper V. Kristensen"; + userEmail = "casper@vkristensen.dk"; + + delta = { + enable = true; + }; + + extraConfig = { + init.defaultBranch = "master"; + pull.rebase = true; + rebase.autoSquash = true; + rebase.autoStash = true; + }; + }; + }; +} diff --git a/modules/base/home-manager.nix b/modules/base/home-manager.nix new file mode 100644 index 0000000..fd5c725 --- /dev/null +++ b/modules/base/home-manager.nix @@ -0,0 +1,27 @@ +{ home-manager, ... }: { + # https://nix-community.github.io/home-manager/index.html#sec-flakes-nixos-module + # https://nixos.wiki/wiki/Home_Manager + + imports = [ + home-manager.nixosModules.home-manager + ]; + + home-manager = { + # Use the same nixpkgs as the system + useGlobalPkgs = true; + + # Install packages to /etc/profiles instead of $HOME/.nix-profile, not sure why + useUserPackages = true; + + users.caspervk = { + # Define the user and path Home Manager should manage + home = { + username = "caspervk"; + homeDirectory = "/home/caspervk"; + }; + + # Let Home Manager install and manage itself + programs.home-manager.enable = true; + }; + }; +} diff --git a/modules/base/impermanence.nix b/modules/base/impermanence.nix new file mode 100644 index 0000000..50d3e09 --- /dev/null +++ b/modules/base/impermanence.nix @@ -0,0 +1,32 @@ +{ pkgs, impermanence, ... }: { + # The impermanence module bind-mounts persistent files and directories, stored in /nix/persist, into the tmpfs root + # partition on startup. For example: /nix/persist/etc/machine-id is mounted to /etc/machine-id. + # https://github.com/nix-community/impermanence + # https://nixos.wiki/wiki/Impermanence + + imports = [ + impermanence.nixosModules.impermanence + ]; + + # We *don't* want to use tmpfs for /tmp in case we have to put big files there. Instead, we mount it to the disk and + # instruct systemd to clean it on boot. + boot.tmp.cleanOnBoot = true; + + environment.persistence."/nix/persist" = { + hideMounts = true; + directories = [ + { directory = "/tmp"; user = "root"; group = "root"; mode = "1777"; } # see comment above + # With great power comes great responsibility, we get it + { directory = "/var/db/sudo/lectured"; user = "root"; group = "root"; mode = "0700"; } + { directory = "/var/log"; user = "root"; group = "root"; mode = "0755"; } + ]; + files = [ + "/etc/machine-id" # needed for /var/log + ]; + users.caspervk = { + directories = [ + "/" # entire home directory + ]; + }; + }; +} diff --git a/modules/base/network.nix b/modules/base/network.nix new file mode 100644 index 0000000..290d40c --- /dev/null +++ b/modules/base/network.nix @@ -0,0 +1,23 @@ +{ pkgs, ... }: { + networking = { + firewall = { + allowedTCPPorts = [ 1234 1337 8000 8080 ]; + allowedUDPPorts = [ 1234 1337 8000 8080 ]; + }; + nameservers = [ "159.69.4.2#dns.caspervk.net" ]; + networkmanager = { + enable = true; + }; + }; + + services.resolved = { + enable = true; + dnssec = "true"; + fallbackDns = [ "159.69.4.2#dns.caspervk.net" ]; + extraConfig = '' + DNSOverTLS=yes + ''; + }; + + services.vnstat.enable = true; +} diff --git a/modules/base/ssh.nix b/modules/base/ssh.nix new file mode 100644 index 0000000..1832e24 --- /dev/null +++ b/modules/base/ssh.nix @@ -0,0 +1,18 @@ +{ ... }: { + services.openssh = { + enable = true; + ports = [ 222 ]; + settings = { + PasswordAuthentication = false; + }; + }; + + environment.persistence."/nix/persist" = { + files = [ + "/etc/ssh/ssh_host_ed25519_key" + "/etc/ssh/ssh_host_ed25519_key.pub" + "/etc/ssh/ssh_host_rsa_key" + "/etc/ssh/ssh_host_rsa_key.pub" + ]; + }; +} diff --git a/modules/base/system.nix b/modules/base/system.nix new file mode 100644 index 0000000..1caa2cd --- /dev/null +++ b/modules/base/system.nix @@ -0,0 +1,71 @@ +{ pkgs, nix-index-database, ... }: { + imports = [ + nix-index-database.nixosModules.nix-index + ]; + + nix = { + # https://nixos.wiki/wiki/Storage_optimization + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than=30d"; + }; + settings = { + auto-optimise-store = true; + experimental-features = [ "nix-command" "flakes" ]; + }; + }; + nixpkgs.config.allowUnfree = true; + + environment.systemPackages = with pkgs; [ + bat + clang + curl + dig + fd + fzf + gcc + git + gnumake + htop + inetutils + jq + magic-wormhole + ntp + python3 + pwgen + ripgrep + rsync + sqlite + tmux + traceroute + tree + unzip + wget + xkcdpass + yq + ]; + + # https://github.com/nix-community/comma + programs.nix-index-database.comma.enable = true; + programs.command-not-found.enable = false; + + i18n = { + defaultLocale = "en_DK.UTF-8"; + extraLocaleSettings = { + LC_ADDRESS = "en_DK.UTF-8"; + LC_IDENTIFICATION = "en_DK.UTF-8"; + LC_MEASUREMENT = "en_DK.UTF-8"; + LC_MONETARY = "en_DK.UTF-8"; + LC_NAME = "en_DK.UTF-8"; + LC_NUMERIC = "en_DK.UTF-8"; + LC_PAPER = "en_DK.UTF-8"; + LC_TELEPHONE = "en_DK.UTF-8"; + LC_TIME = "en_DK.UTF-8"; + }; + }; + + time = { + timeZone = "Europe/Copenhagen"; + }; +} diff --git a/modules/base/users.nix b/modules/base/users.nix new file mode 100644 index 0000000..c9c7585 --- /dev/null +++ b/modules/base/users.nix @@ -0,0 +1,28 @@ +{ pkgs, ... }: { + users = { + # Don't allow imperative modifications to users (incompatible with impermanence) + mutableUsers = false; + users = { + root = { + passwordFile = "/nix/persist/passwordfile"; + }; + caspervk = { + isNormalUser = true; + description = "Casper V. Kristensen"; + passwordFile = "/nix/persist/passwordfile"; + extraGroups = [ + "networkmanager" + "wheel" # allows sudo + "video" # allows controlling brightness + # todo: docker, systemd-journal, audio, input, power, nix ? + ]; + uid = 1000; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPB/qr63FB0ZqOe/iZGwIKNHD8a1Ud/mXVjQPmpIG7pM caspervk@omega" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII71DKQziktCkyMAmL25QKRK6nG2uJDkQXioIZp5JkMZ caspervk@zeta" + ]; + packages = with pkgs; []; + }; + }; + }; +} diff --git a/modules/base/vim.nix b/modules/base/vim.nix new file mode 100644 index 0000000..b30b051 --- /dev/null +++ b/modules/base/vim.nix @@ -0,0 +1,8 @@ +{ ... }: { + programs.neovim = { + enable = true; + defaultEditor = true; + viAlias = true; + vimAlias = true; + }; +} diff --git a/modules/desktop/default.nix b/modules/desktop/default.nix new file mode 100644 index 0000000..3f05ea2 --- /dev/null +++ b/modules/desktop/default.nix @@ -0,0 +1,9 @@ +{ ... }: + +{ + imports = [ + ./firefox.nix + ./ssh.nix + ./sway.nix + ]; +} diff --git a/modules/desktop/firefox.nix b/modules/desktop/firefox.nix new file mode 100644 index 0000000..7e4f021 --- /dev/null +++ b/modules/desktop/firefox.nix @@ -0,0 +1,7 @@ +{ pkgs, ... }: { + # https://nixos.wiki/wiki/Firefox + + environment.systemPackages = with pkgs; [ + firefox-wayland + ]; +} diff --git a/modules/desktop/ssh.nix b/modules/desktop/ssh.nix new file mode 100644 index 0000000..ee88aeb --- /dev/null +++ b/modules/desktop/ssh.nix @@ -0,0 +1,26 @@ +{ home-manager, ... }: { + # # https://nix-community.github.io/home-manager/options.html + + home-manager.users.caspervk = { + programs.ssh = { + enable = true; + matchBlocks = { + "delta" = { + hostname = "delta.caspervk.net"; + port = 222; + }; + "lambda" = { + hostname = "lambda.caspervk.net"; + port = 222; + }; + "sigma" = { + hostname = "sigma.caspervk.net"; + port = 222; + }; + "git.caspervk.net" = { + port = 2222; + }; + }; + }; + }; +} diff --git a/modules/desktop/sway.nix b/modules/desktop/sway.nix new file mode 100644 index 0000000..345703d --- /dev/null +++ b/modules/desktop/sway.nix @@ -0,0 +1,51 @@ +{ pkgs, home-manager, ... }: { + # https://nixos.wiki/wiki/Sway + # https://nix-community.github.io/home-manager/options.html + + home-manager.users.caspervk = { + wayland.windowManager.sway = { + enable = true; + config = { + assigns = { + "1: web" = [{ class = "^Firefox$"; }]; + }; + input = { + "*" = { + # Keyboard + xkb_layout = "us"; + xkb_variant = "altgr-intl"; + + # Trackpad + tap = "enabled"; + natural_scroll = "enable"; + dwt = "disabled"; # don't disable-while-typing + }; + }; + modifier = "Mod4"; # super + terminal = "alacritty"; + workspaceAutoBackAndForth = true; + }; + }; + }; + + environment.systemPackages = with pkgs; [ + alacritty + ]; + + # Audio + services.pipewire = { + enable = true; + alsa = { + enable = true; + support32Bit = true; + }; + jack.enable = true; + pulse.enable = true; + }; + + # Video + programs.light.enable = true; # allows controlling screen brightness + + # Allow sharing screen + #xdg.portal.wlr.enable = true; +} diff --git a/todo b/todo new file mode 100644 index 0000000..fd1a10a --- /dev/null +++ b/todo @@ -0,0 +1,4 @@ +https://unix.stackexchange.com/questions/522822/different-methods-to-run-a-non-nixos-executable-on-nixos +https://discourse.nixos.org/t/tips-tricks-for-nixos-desktop/28488 +https://github.com/sioodmy/dotfiles/blob/main/modules/core/users.nix +https://nixos.wiki/wiki/Comparison_of_secret_managing_schemes