#+title: NixOS Configuration #+AUTHOR: Preston Pan #+DESCRIPTION: My NixOS system, written entirely in a literate configuration #+html_head: * Introduction This is my NixOS configuration. It is a part of my monorepo, and this file automatically tangles to all the under the nix/ directory in my monorepo [[https://ret2pop.net/gitweb/monorepo.git][git repository]]. My monorepo also stores my website, as my website stores my [[file:elfeed.org][elfeed]] and [[file:emacs.org][emacs]] configurations. Additionally, I want to track my emacs configuration with my Nix configuration. Having them in one repository means that my emacs configuration is pinned to my flake. Hence, my monorepo serves a dual purpose, as do many of the files within my monorepo. They are often data files used in my configuration (i.e. emacs, elfeed, org-roam, agenda, journal, etc...) and they are webpages as well. This page is one such example of this concept. * Flake.nix The flake is the entry point of the NixOS configuration. Here, I have a list of all the systems that I use with all the modules that they use. My NixOS configuration is heavily modularized, so that adding new configurations that add modifications is made simple. #+begin_src nix :tangle ../nix/flake.nix { description = "Emacs centric configurations for a complete networked system"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; nur.url = "github:nix-community/NUR"; sops-nix.url = "github:Mic92/sops-nix"; scripts.url = "github:ret2pop/scripts"; wallpapers.url = "github:ret2pop/wallpapers"; sounds.url = "github:ret2pop/sounds"; nix-topology = { url = "github:oddlama/nix-topology"; inputs.nixpkgs.follows = "nixpkgs"; }; deep-research = { url = "github:ret2pop/ollama-deep-researcher"; }; home-manager = { url = "github:nix-community/home-manager/release-25.05"; inputs.nixpkgs.follows = "nixpkgs"; }; disko = { url = "github:nix-community/disko"; inputs.nixpkgs.follows = "nixpkgs"; }; lanzaboote = { url = "github:nix-community/lanzaboote/v0.4.1"; inputs.nixpkgs.follows = "nixpkgs"; }; nixos-dns = { url = "github:Janik-Haag/nixos-dns"; inputs.nixpkgs.follows = "nixpkgs"; }; }; outputs = { self, nixpkgs, home-manager, nur, disko, lanzaboote, sops-nix, nix-topology, nixos-dns, deep-research, ... }@attrs: let hostnames = [ "affinity" "continuity" "installer" "spontaneity" # add hostnames here ]; system = "x86_64-linux"; pkgs = import nixpkgs { inherit system; }; generate = nixos-dns.utils.generate nixpkgs.legacyPackages."${system}"; dnsConfig = { inherit (self) nixosConfigurations; extraConfig = import ./dns/default.nix; }; # function that generates all systems from hostnames mkConfigs = map (hostname: {name = "${hostname}"; value = nixpkgs.lib.nixosSystem { inherit system; specialArgs = attrs; modules = if (hostname == "installer") then [ (./. + "/systems/${hostname}/default.nix") { networking.hostName = "${hostname}"; } nix-topology.nixosModules.default ] else [ { environment.systemPackages = with nixpkgs.lib; [ deep-research.packages."${system}".deep-research ]; } nix-topology.nixosModules.default lanzaboote.nixosModules.lanzaboote disko.nixosModules.disko home-manager.nixosModules.home-manager sops-nix.nixosModules.sops nixos-dns.nixosModules.dns { nixpkgs.overlays = [ nur.overlays.default ]; home-manager.extraSpecialArgs = attrs // { systemHostName = "${hostname}"; }; networking.hostName = "${hostname}"; } (./. + "/systems/${hostname}/default.nix") ]; }; }); mkDiskoFiles = map (hostname: { name = "${hostname}"; value = self.nixosConfigurations."${hostname}".config.monorepo.vars.diskoSpec; }); in { nixosConfigurations = builtins.listToAttrs (mkConfigs hostnames); evalDisko = builtins.listToAttrs (mkDiskoFiles (builtins.filter (x: x != "installer") hostnames)); topology."${system}" = import nix-topology { pkgs = import nixpkgs { inherit system; overlays = [ nix-topology.overlays.default ]; }; modules = [ ./topology/default.nix { nixosConfigurations = self.nixosConfigurations; } ]; }; devShell."${system}" = with pkgs; mkShell { buildInputs = [ fira-code python3 poetry statix deadnix ]; }; packages."${system}" = { zoneFiles = generate.zoneFiles dnsConfig; octodns = generate.octodnsConfig { inherit dnsConfig; config = { providers = { cloudflare = { class = "octodns_cloudflare.CloudflareProvider"; token = "env/CLOUDFLARE_TOKEN"; }; config = { check_origin = false; }; }; }; zones = { "ret2pop.net." = nixos-dns.utils.octodns.generateZoneAttrs [ "cloudflare" ]; "nullring.xyz." = nixos-dns.utils.octodns.generateZoneAttrs [ "cloudflare" ]; }; }; }; }; } #+end_src Note that the configurations are automatically generated with he mkConfigs function. * Sops Configuration In order to use the sops configuration, you must change the age public key to the one that you own: #+begin_src yaml :tangle ../nix/.sops.yaml keys: - &primary age165ul43e8rc0qwzz2f2q9cw02psm2mkudsrwavq2e0pxs280p64yqy2z0dr creation_rules: - path_regex: secrets/secrets.yaml$ key_groups: - age: - *primary #+end_src also note that you will have to write your own secrets.yaml file, with an entry called ~mail~, which is used for the imaps and smtps password. * Nix DNS #+begin_src nix :tangle ../nix/dns/default.nix { defaultTTL = 120; } #+end_src * Nix Topology Nix Topology generates a nice graph of all my hosts. You can view this graph by running ~nix build .#topology.x86_64-linux.config.output~. #+begin_src nix :tangle ../nix/topology/default.nix { config, ... }: let inherit (config.lib.topology); in { nodes = { spontaneity = { interfaces.wan.network = "remote"; }; installer = { interfaces.lan.network = "home"; }; affinity = { interfaces.lan = { network = "home"; physicalConnections = [ { node = "spontaneity"; interface = "wan"; } { node = "installer"; interface = "lan"; } ]; }; }; continuity = { interfaces.lan = { network = "home"; physicalConnections = [ { node = "spontaneity"; interface = "wan"; } { node = "affinity"; interface = "lan"; } ]; }; }; }; networks = { home = { name = "Home Network"; cidrv4 = "192.168.1.1/24"; }; remote = { name = "Remote Network"; cidrv4 = "144.202.27.169/32"; }; }; } #+end_src * Modules ** Vars Variables used for regular configuration in your system ~default.nix~ file. The options are largely self-documenting. #+begin_src nix :tangle ../nix/modules/vars.nix { lib, ... }: { options.monorepo.vars = { device = lib.mkOption { type = lib.types.str; default = "/dev/sda"; example = "/dev/nvme0n1"; description = "device that NixOS is installed to"; }; diskoSpec = lib.mkOption { type = lib.types.attrs; description = "retains a copy of the disko spec for reflection"; }; userName = lib.mkOption { type = lib.types.str; default = "preston"; example = "myUser"; description = "system username"; }; fullName = lib.mkOption { type = lib.types.str; default = "Preston Pan"; example = "John Doe"; description = "Full Name"; }; gpgKey = lib.mkOption { type = lib.types.str; default = "AEC273BF75B6F54D81343A1AC1FE6CED393AE6C1"; example = "1234567890ABCDEF..."; description = "GPG key fingerprint"; }; remoteHost = lib.mkOption { type = lib.types.str; default = "ret2pop.net"; example = "example.com"; description = "Address to push to and pull from for website and git repos"; }; timeZone = lib.mkOption { type = lib.types.str; default = "America/Vancouver"; example = "America/Chicago"; description = "Linux timezone"; }; monitors = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ "HDMI-A-1" "eDP-1" "DP-2" "DP-3" "DP-4" "LVDS-1" ]; example = []; description = "Monitors that waybar will use"; }; }; } #+end_src ** Default Profile Again, these are self documenting variables that you may see used below. These are to be used under ~default.nix~ in the ~systems~ folder. #+begin_src nix :tangle ../nix/modules/default.nix { lib, config, pkgs, ... }: { imports = [ ./configuration.nix ./vars.nix ]; options = { monorepo = { profiles = { cuda.enable = lib.mkEnableOption "Enables CUDA support"; documentation.enable = lib.mkEnableOption "Enables documentation on system."; secureBoot.enable = lib.mkEnableOption "Enables secure boot. See sbctl."; pipewire.enable = lib.mkEnableOption "Enables pipewire low latency audio setup"; tor.enable = lib.mkEnableOption "Enables tor along with torsocks"; home.enable = lib.mkEnableOption "Enables home user"; server.enable = lib.mkEnableOption "Enables server services"; ttyonly.enable = lib.mkEnableOption "TTY only, no xserver"; grub.enable = lib.mkEnableOption "Enables grub instead of systemd-boot"; workstation.enable = lib.mkEnableOption "Enables workstation services"; }; }; }; config = { environment.systemPackages = lib.mkIf config.monorepo.profiles.documentation.enable (with pkgs; [ linux-manual man-pages man-pages-posix iproute2 silver-searcher ripgrep ]); boot.loader.grub = lib.mkIf config.monorepo.profiles.grub.enable { enable = true; }; monorepo = { profiles = { documentation.enable = lib.mkDefault true; pipewire.enable = lib.mkDefault true; tor.enable = lib.mkDefault true; home.enable = lib.mkDefault true; }; }; }; } #+end_src ** X11 My Xorg configuration is used as a backup for when wayland applications don't work. Note that using this configuration is extremely inefficient and my i3 configuration is unoptimized. Still, it is suitable for using Krita. #+begin_src nix :tangle ../nix/modules/xserver.nix { lib, config, pkgs, ... }: { services.xserver = { enable = (! config.monorepo.profiles.ttyonly.enable); displayManager = { startx.enable = (! config.monorepo.profiles.ttyonly.enable); }; windowManager = { i3 = { enable = ! config.monorepo.profiles.ttyonly.enable; package = pkgs.i3-gaps; }; }; desktopManager = { runXdgAutostartIfNone = true; }; xkb = { layout = "us"; variant = ""; options = "caps:escape"; }; videoDrivers = (if config.monorepo.profiles.cuda.enable then [ "nvidia" ] else []); }; } #+end_src You should add your own video drivers in a custom machine configuration. ** Docker In order to run docker containers, I need this file: #+begin_src nix :tangle ../nix/modules/docker.nix { lib, config, vars, ... }: { virtualisation.docker.enable = true; } #+end_src ** Pipewire My low latency pipewire configuration is used for music production, as well as for regular desktop usage. Pipewire is much better than pulseaudio because it supports jack with the same underlying interface and it breaks significantly less often. #+begin_src nix :tangle ../nix/modules/pipewire.nix { lib, config, ... }: { services.pipewire = { enable = lib.mkDefault config.monorepo.profiles.pipewire.enable; alsa = { enable = true; support32Bit = true; }; pulse.enable = true; jack.enable = true; wireplumber.enable = true; extraConfig = { pipewire."92-low-latency" = { "context.properties" = { "default.clock.rate" = 48000; "default.clock.quantum" = 256; "default.clock.min-quantum" = 32; "default.clock.max-quantum" = 512; }; pipewire-pulse."92-low-latency" = { "context.properties" = [ { name = "libpipewire-module-protocol-pulse"; args = { }; } ]; "pulse.properties" = { "pulse.min.req" = "32/48000"; "pulse.default.req" = "32/48000"; "pulse.max.req" = "32/48000"; "pulse.min.quantum" = "32/48000"; "pulse.max.quantum" = "32/48000"; }; "stream.properties" = { "node.latency" = "32/48000"; "resample.quality" = 1; }; }; }; }; }; } #+end_src ** SSH My SSH daemon configuration. #+begin_src nix :tangle ../nix/modules/ssh.nix { config, lib, ... }: { services.openssh = { enable = true; settings = { PasswordAuthentication = lib.mkDefault (! config.monorepo.profiles.server.enable); AllowUsers = [ config.monorepo.vars.userName "root" "git" ]; PermitRootLogin = "prohibit-password"; KbdInteractiveAuthentication = false; }; }; } #+end_src ** Tor This is my tor configuration, used for my cryptocurrency wallets and whatever else I want it to do. #+begin_src nix :tangle ../nix/modules/tor.nix { config, lib, ... }: { services.tor = { enable = lib.mkDefault config.monorepo.profiles.tor.enable; openFirewall = true; client = { enable = lib.mkDefault config.monorepo.profiles.tor.enable; socksListenAddress = { IsolateDestAddr = true; addr = "127.0.0.1"; port = 9050; }; dns.enable = true; }; torsocks = { enable = lib.mkDefault config.monorepo.profiles.tor.enable; server = "127.0.0.1:9050"; }; }; } #+end_src ** Kubo IPFS I use IPFS for my website and also for my ISOs for truly declarative and deterministic configuration. NixOS might be moving to IPFS for binary cache distribution and package distribution soon, and I'm waiting on that. #+begin_src nix :tangle ../nix/modules/kubo.nix { config, pkgs, lib, ... }: { services.kubo = { enable = lib.mkDefault config.monorepo.profiles.workstation.enable; }; } #+end_src ** Murmur #+begin_src nix :tangle ../nix/modules/murmur.nix { lib, config, ... }: { services.murmur = { enable = lib.mkDefault config.monorepo.profiles.server.enable; logFile = "/var/log/murmur.log"; openFirewall = true; hostName = "0.0.0.0"; welcometext = "Wecome to the Null Murmur instance!"; registerName = "nullring"; registerHostname = "nullring.xyz"; sslCert = "/var/lib/acme/nullring.xyz/fullchain.pem"; sslKey = "/var/lib/acme/nullring.xyz/sslKey.pem"; }; } #+end_src ** i2pd I use i2p for some p2p connections. We enable it with the server profile: #+begin_src nix :tangle ../nix/modules/i2pd.nix { config, lib, ... }: { services.i2pd = { enable = lib.mkDefault config.monorepo.profiles.server.enable; address = "0.0.0.0"; inTunnels = { }; outTunnels = { }; }; } #+end_src ** Icecast This is an internet radio which will host a ton of music. #+begin_src nix :tangle ../nix/modules/icecast.nix { lib, config, ... }: { services.icecast = { enable = lib.mkDefault config.monorepo.profiles.server.enable; listen.address = "0.0.0.0"; extraConfig = '' 0 /stream.m3u 3600
''; }; admin.password = "changeme"; } #+end_src ** IRC A great protocol. It's the most widely usable by any netizen, as it is just pure plaintext and the operating costs are trivial. *** NgIRCD I run my own IRC server to bridge with my Matrix server and my discord guild. #+begin_src nix :tangle ../nix/modules/ngircd.nix { lib, config, ... }: { services.ngircd = { enable = lib.mkDefault config.monorepo.profiles.server.enable; config = '' [Global] Name = nullring.xyz Info = NullRing IRC Instance Listen = 0.0.0.0 MotdFile = /etc/motd.txt Network = NullRing Ports = 6667 [Options] PAM = no [SSL] CertFile = /var/lib/acme/nullring.xyz/fullchain.pem CipherList = HIGH:!aNULL:@STRENGTH:!SSLv3 KeyFile = /var/lib/acme/nullring.xyz/key.pem Ports = 6697 ''; }; environment.etc."motd.txt" = { source = ../data/motd.txt; mode = "644"; user = "ngircd"; group = "ngircd"; }; } #+end_src *** MOTD I also have a MOTD file that I want to add, which displays when users connect to the server: #+begin_src fundamental :tangle ../nix/data/motd.txt Welcome to the NullRing experience! The main channel is #nullring; we're glad to have you! Rules: 1. Don't be annoying. 2. No illegal content. And if you're here to have constructive, philisophical and theoretical conversations, this is the place for you! #+end_src *** ZNC I want to be able to create some sort of identity persistence on IRC for users: #+begin_src nix :tangle ../nix/modules/znc.nix { lib, config, ... }: { services.znc = { enable = lib.mkDefault config.monorepo.profiles.server.enable; openFirewall = true; confOptions = { useSSL = true; passBlock = '' Method = sha256 Hash = d4abdd69aa24de69693885c5bd83a4a0e9ee989e1a69a905041b0dad9abc06ea Salt = sDY,?H5AxC-!gH3a.:)D Hash = ${config.sops.secrets.znc_password_hash} Salt = ${config.sops.secrets.znc_password_salt} ''; modules = [ "partyline" "webadmin" "adminlog" "log" ]; networks = { "libera" = { server = "irc.libera.chat"; port = 6697; useSSL = true; modules = [ "simple_away" ]; }; }; }; }; } #+end_src Note that the password hash and whatnot is completely random so there is almost no point to cracking it with hashcat. ** Conduit This is a modern matrix server that is meant to be lightweight while still federating and hosting the same protocol. #+begin_src nix :tangle ../nix/modules/conduit.nix { config, lib, ... }: { services.matrix-conduit = { enable = lib.mkDefault config.monorepo.profiles.server.enable; settings.global = { server_name = "matrix.${config.monorepo.vars.remoteHost}"; trusted_servers = [ "matrix.org" "nixos.org" ]; address = "0.0.0.0"; port = 6167; allow_registration = true; }; }; } #+end_src ** Matterbridge Then I want to connect all these servers together with Matterbridge: #+begin_src nix :tangle ../nix/modules/matterbridge.nix { lib, config, ... }: { services.matterbridge = { enable = lib.mkDefault config.monorepo.profiles.server.enable; configPath = "/etc/matterbridge.toml"; }; } #+end_src ** Ollama Use ollama for serving large language models to my other computers. #+begin_src nix :tangle ../nix/modules/ollama.nix { config, lib, ... }: { services.ollama = { enable = lib.mkDefault config.monorepo.profiles.workstation.enable; acceleration = "cuda"; host = "0.0.0.0"; openFirewall = true; }; } #+end_src ** Bitcoind #+begin_src nix :tangle ../nix/modules/bitcoin.nix { config, lib, ... }: { services.bitcoind."${config.monorepo.vars.userName}" = { enable = lib.mkDefault config.monorepo.profiles.workstation.enable; prune = 10000; }; } #+end_src ** Git Server I run my own git server in order to have a mirror in case github goes down. #+begin_src nix :tangle ../nix/modules/git-daemon.nix { config, lib, ... }: { services.gitDaemon = { enable = lib.mkDefault config.monorepo.profiles.server.enable; exportAll = true; basePath = "/srv/git"; }; } #+end_src ** Nginx These are all my virtual hosts. For many of these servers we have to have a reverse proxy in order to expose the locally running instances to the outside world under a domain. #+begin_src nix :tangle ../nix/modules/nginx.nix { config, lib, services, ... }: { services.nginx = { enable = lib.mkDefault config.monorepo.profiles.server.enable; user = "nginx"; # Use recommended settings recommendedGzipSettings = true; recommendedOptimisation = true; recommendedProxySettings = true; recommendedTlsSettings = true; appendHttpConfig = ''''; gitweb = { enable = true; virtualHost = "${config.monorepo.vars.remoteHost}"; }; virtualHosts = { "matrix.${config.monorepo.vars.remoteHost}" = { enableACME = true; forceSSL = true; listen = [ { addr = "0.0.0.0"; port = 443; ssl = true; } { addr = "[::]"; port = 443; ssl = true; } { addr = "0.0.0.0"; port = 8448; ssl = true; } { addr = "[::]"; port = 8448; ssl = true; } ]; locations."/_matrix/" = { proxyPass = "http://127.0.0.1:6167"; extraConfig = '' proxy_set_header Host $host; proxy_buffers 32 16k; proxy_read_timeout 5m; ''; }; extraConfig = '' merge_slashes off; ''; }; "${config.monorepo.vars.remoteHost}" = { serverName = "${config.monorepo.vars.remoteHost}"; serverAliases = [ "ret2pop.nullring.xyz" ]; root = "/var/www/ret2pop-website/"; addSSL = true; enableACME = true; }; "nullring.xyz" = { serverName = "nullring.xyz"; root = "/var/www/nullring/"; addSSL = true; enableACME = true; }; "mail.${config.monorepo.vars.remoteHost}" = { serverName = "mail.${config.monorepo.vars.remoteHost}"; root = "/var/www/dummy"; addSSL = true; enableACME = true; }; }; }; } #+end_src ** Git Web Interface I enable the git web interface to show off my git repos to the world. This was the easiest frontend to set up on NixOS. #+begin_src nix :tangle ../nix/modules/gitweb.nix { lib, config, ... }: { services.gitweb = { gitwebTheme = true; projectroot = "/srv/git/"; }; } #+end_src ** Nvidia #+begin_src nix :tangle ../nix/modules/nvidia.nix { config, lib, pkgs, ... }: { hardware = { graphics.extraPackages = (if config.monorepo.profiles.cuda.enable then with pkgs; [ vaapiVdpau libvdpau-va-gl nvidia-vaapi-driver ] else []); nvidia = { modesetting.enable = lib.mkDefault config.monorepo.profiles.cuda.enable; powerManagement = { enable = lib.mkDefault config.monorepo.profiles.cuda.enable; finegrained = false; }; nvidiaSettings = lib.mkDefault config.monorepo.profiles.cuda.enable; open = lib.mkDefault false; package = config.boot.kernelPackages.nvidiaPackages.stable; }; }; } #+end_src ** CUDA #+begin_src nix :tangle ../nix/modules/cuda.nix { config, lib, pkgs, ... }: { environment.systemPackages = (if config.monorepo.profiles.cuda.enable then with pkgs; [ cudatoolkit cudaPackages.cudnn cudaPackages.libcublas linuxPackages.nvidia_x11 ] else []); } #+end_src ** Maddy #+begin_src nix :tangle ../nix/modules/maddy.nix { lib, config, options, ... }: { services.maddy = { enable = lib.mkDefault config.monorepo.profiles.server.enable; openFirewall = true; primaryDomain = "ret2pop.net"; tls = { loader = "acme"; }; config = builtins.replaceStrings [ "imap tcp://0.0.0.0:143" "submission tcp://0.0.0.0:587" ] [ "imap tls://0.0.0.0:993 tcp://0.0.0.0:143" "submission tls://0.0.0.0:465 tcp://0.0.0.0:587" ] options.services.maddy.config.default; }; } #+end_src ** Main Configuration This is the backbone of the all the NixOS configurations, with all these options being shared because they enhance security. #+begin_src nix :tangle ../nix/modules/configuration.nix { config, pkgs, lib, ... }: { imports = [ ./matterbridge.nix ./xserver.nix ./ssh.nix ./pipewire.nix ./tor.nix ./kubo.nix ./nvidia.nix ./cuda.nix ./nginx.nix ./git-daemon.nix ./ollama.nix ./i2pd.nix ./gitweb.nix ./conduit.nix ./bitcoin.nix ./murmur.nix ./ngircd.nix ./znc.nix ./docker.nix ]; documentation = { enable = lib.mkDefault config.monorepo.profiles.documentation.enable; man.enable = lib.mkDefault config.monorepo.profiles.documentation.enable; dev.enable = lib.mkDefault config.monorepo.profiles.documentation.enable; }; environment = { etc = { securetty.text = '' # /etc/securetty: list of terminals on which root is allowed to login. # See securetty(5) and login(1). ''; }; }; systemd = { coredump.enable = false; network.config.networkConfig.IPv6PrivacyExtensions = "kernel"; tmpfiles.settings = { "restricthome"."/home/*".Z.mode = "~0700"; "restrictetcnixos"."/etc/nixos/*".Z = { mode = "0000"; user = "root"; group = "root"; }; }; }; boot = { extraModprobeConfig = '' options snd-usb-audio vid=0x1235 pid=0x8200 device_setup=1 ''; extraModulePackages = [ ]; initrd = { availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "sd_mod" "nvme" "sd_mod" "ehci_pci" "rtsx_pci_sdmmc" "usbhid" ]; kernelModules = [ ]; }; lanzaboote = { enable = config.monorepo.profiles.secureBoot.enable; pkiBundle = "/etc/secureboot"; }; loader = { systemd-boot.enable = lib.mkForce (! config.monorepo.profiles.grub.enable); efi.canTouchEfiVariables = lib.mkForce (! config.monorepo.profiles.grub.enable); }; kernelModules = [ "snd-seq" "snd-rawmidi" "xhci_hcd" "kvm_intel" ]; kernelParams = [ "usbcore.autosuspend=-1" "debugfs=off" "page_alloc.shuffle=1" "slab_nomerge" "page_poison=1" # madaidan "pti=on" "randomize_kstack_offset=on" "vsyscall=none" "module.sig_enforce=1" "lockdown=confidentiality" # cpu "spectre_v2=on" "spec_store_bypass_disable=on" "tsx=off" "l1tf=full,force" "kvm.nx_huge_pages=force" # hardened "extra_latent_entropy" # mineral "init_on_alloc=1" "random.trust_cpu=off" "random.trust_bootloader=off" "intel_iommu=on" "amd_iommu=force_isolation" "iommu=force" "iommu.strict=1" "init_on_free=1" "quiet" "loglevel=0" ]; blacklistedKernelModules = [ "netrom" "rose" "adfs" "affs" "bfs" "befs" "cramfs" "efs" "erofs" "exofs" "freevxfs" "f2fs" "hfs" "hpfs" "jfs" "minix" "nilfs2" "ntfs" "omfs" "qnx4" "qnx6" "sysv" "ufs" ]; kernel.sysctl = { "kernel.ftrace_enabled" = false; "net.core.bpf_jit_enable" = false; "kernel.kptr_restrict" = 2; # madaidan "kernel.smtcontrol" = "on"; "vm.swappiness" = 1; "vm.unprivileged_userfaultfd" = 0; "dev.tty.ldisc_autoload" = 0; "kernel.kexec_load_disabled" = 1; "kernel.sysrq" = 4; "kernel.perf_event_paranoid" = 3; # net "net.ipv4.icmp_echo_ignore_broadcasts" = true; "net.ipv4.conf.all.accept_redirects" = false; "net.ipv4.conf.all.secure_redirects" = false; "net.ipv4.conf.default.accept_redirects" = false; "net.ipv4.conf.default.secure_redirects" = false; "net.ipv6.conf.all.accept_redirects" = false; "net.ipv6.conf.default.accept_redirects" = false; }; }; networking = { useDHCP = lib.mkDefault true; networkmanager = { enable = true; }; firewall = { allowedTCPPorts = [ 22 11434 ]; allowedUDPPorts = [ ]; }; }; hardware = { enableAllFirmware = true; cpu.intel.updateMicrocode = true; graphics.enable = ! config.monorepo.profiles.ttyonly.enable; bluetooth = { enable = true; powerOnBoot = true; }; }; services = { pulseaudio.enable = ! config.monorepo.profiles.pipewire.enable; chrony = { enable = true; enableNTS = true; servers = [ "time.cloudflare.com" "ptbtime1.ptb.de" "ptbtime2.ptb.de" ]; }; jitterentropy-rngd.enable = true; resolved.dnssec = true; # usbguard.enable = true; usbguard.enable = false; dbus.apparmor = "enabled"; kanata.enable = true; # Misc. udev = { extraRules = ''''; packages = with pkgs; [ platformio-core platformio-core.udev openocd ]; }; printing.enable = true; udisks2.enable = true; }; programs = { nix-ld.enable = true; zsh.enable = true; light.enable = true; ssh.enableAskPassword = false; }; nixpkgs = { hostPlatform = lib.mkDefault "x86_64-linux"; config = { allowUnfree = true; cudaSupport = lib.mkDefault config.monorepo.profiles.cuda.enable; }; }; security = { acme = { acceptTerms = true; defaults.email = "ret2pop@gmail.com"; }; apparmor = { enable = true; killUnconfinedConfinables = true; }; pam.loginLimits = [ { domain = "*"; item = "nofile"; type = "-"; value = "32768"; } { domain = "*"; item = "memlock"; type = "-"; value = "32768"; } ]; rtkit.enable = true; lockKernelModules = true; protectKernelImage = true; allowSimultaneousMultithreading = true; forcePageTableIsolation = true; tpm2 = { enable = true; pkcs11.enable = true; tctiEnvironment.enable = true; }; auditd.enable = true; audit.enable = true; chromiumSuidSandbox.enable = (! config.monorepo.profiles.ttyonly.enable); sudo.enable = true; }; xdg.portal = { enable = (! config.monorepo.profiles.ttyonly.enable); wlr.enable = true; extraPortals = with pkgs; if (! config.monorepo.profiles.ttyonly.enable) then [ xdg-desktop-portal-gtk xdg-desktop-portal xdg-desktop-portal-hyprland ] else []; config.common.default = "*"; }; environment.etc."gitconfig".text = '' [init] defaultBranch = main ''; environment.extraInit = '' umask 0022 ''; environment.systemPackages = with pkgs; [ restic sbctl git vim curl nmap (writeShellScriptBin "new-repo" '' #!/bin/bash cd /srv/git git init --bare "$1" vim "$1/description" chown -R git:git "$1" '' ) ]; users.groups.nginx = lib.mkDefault {}; users.groups.git = lib.mkDefault {}; users.groups.ircd = lib.mkDefault {}; users.groups.ngircd = lib.mkDefault {}; users.users = { ngircd = { isSystemUser = lib.mkDefault true; group = "ngircd"; extraGroups = [ "acme" "nginx" ]; }; ircd = { isSystemUser = lib.mkDefault true; group = "ircd"; home = "/home/ircd"; }; nginx = { group = "nginx"; isSystemUser = lib.mkDefault true; extraGroups = [ "acme" ]; }; root.openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICts6+MQiMwpA+DfFQxjIN214Jn0pCw/2BDvOzPhR/H2 preston@continuity-dell" ]; git = { isSystemUser = true; home = "/srv/git"; shell = "${pkgs.git}/bin/git-shell"; group = "git"; openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICts6+MQiMwpA+DfFQxjIN214Jn0pCw/2BDvOzPhR/H2 preston@continuity-dell" ]; }; "${config.monorepo.vars.userName}" = { openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICts6+MQiMwpA+DfFQxjIN214Jn0pCw/2BDvOzPhR/H2 preston@continuity-dell" ]; initialPassword = "${config.monorepo.vars.userName}"; isNormalUser = true; description = config.monorepo.vars.fullName; extraGroups = [ "networkmanager" "wheel" "video" "docker" "jackaudio" "tss" "dialout" "docker" ]; shell = pkgs.zsh; packages = []; }; }; nixpkgs.config.permittedInsecurePackages = [ "olm-3.2.16" ]; nix = { settings = { experimental-features = "nix-command flakes"; trusted-users = [ "@wheel" ]; }; }; time.timeZone = config.monorepo.vars.timeZone; i18n.defaultLocale = "en_CA.UTF-8"; system.stateVersion = "24.11"; } #+end_src ** Disko This is the disko configuration for my continuity system. It features a boot and ext4 partition, with configurable disk. *** Simple This configuration is used for simple partitioning schemes with EFI. #+begin_src nix :tangle ../nix/disko/drive-simple.nix { lib, config, ... }: let spec = { disko.devices = { disk = { my-disk = { device = config.monorepo.vars.device; type = "disk"; content = { type = "gpt"; partitions = { ESP = { type = "EF00"; size = "500M"; priority = 1; content = { type = "filesystem"; format = "vfat"; mountpoint = "/boot"; mountOptions = [ "umask=0077" ]; }; }; root = { size = "100%"; priority = 2; content = { type = "filesystem"; format = "ext4"; mountpoint = "/"; }; }; }; }; }; }; }; }; in { monorepo.vars.diskoSpec = spec; disko.devices = spec.disko.devices; } #+end_src *** BIOS For machines that use BIOS instead of EFI. #+begin_src nix :tangle ../nix/disko/drive-bios.nix { config, lib, ... }: let spec = { disko.devices = { disk = { main = { device = config.monorepo.vars.device; type = "disk"; content = { type = "gpt"; partitions = { boot = { size = "1M"; type = "EF02"; }; root = { label = "disk-main-root"; size = "100%"; content = { type = "filesystem"; format = "ext4"; mountpoint = "/"; }; }; }; }; }; }; }; }; in { monorepo.vars.diskoSpec = spec; disko.devices = spec.disko.devices; } #+end_src ** Home *** Default Home Profile As you can see, I have my installed home packages installed based on the profiles enabled. Also, I have many imports that we'll go through next. #+begin_src nix :tangle ../nix/modules/home/default.nix { lib, config, pkgs, sops-nix, ... }: { imports = [ sops-nix.homeManagerModules.sops ../vars.nix ./fcitx.nix ./secrets.nix ./emacs.nix ./firefox.nix ./git.nix ./hyprland.nix ./mpv.nix ./yt-dlp.nix ./wofi.nix ./kitty.nix ./waybar.nix ./zsh.nix ./mbsync.nix ./msmtp.nix ./gammastep.nix ./mpd.nix ./mako.nix ./user.nix ]; options = { monorepo.profiles = { enable = lib.mkEnableOption "Enables home manager desktop configuration"; # Programs graphics.enable = lib.mkEnableOption "Enables graphical programs for user"; lang-c.enable = lib.mkEnableOption "Enables C language support"; lang-sh.enable = lib.mkEnableOption "Enables sh language support"; lang-rust.enable = lib.mkEnableOption "Enables Rust language support"; lang-python.enable = lib.mkEnableOption "Enables python language support"; lang-sol.enable = lib.mkEnableOption "Enables solidity language support"; lang-openscad.enable = lib.mkEnableOption "Enables openscad language support"; lang-js.enable = lib.mkEnableOption "Enables javascript language support"; lang-nix.enable = lib.mkEnableOption "Enables nix language support"; lang-coq.enable = lib.mkEnableOption "Enables coq language support"; lang-lean.enable = lib.mkEnableOption "Enables lean language support"; lang-haskell.enable = lib.mkEnableOption "Enables haskell language support"; crypto.enable = lib.mkEnableOption "Enables various cryptocurrency wallets"; art.enable = lib.mkEnableOption "Enables various art programs"; music.enable = lib.mkEnableOption "Enables mpd"; workstation.enable = lib.mkEnableOption "Enables workstation packages (music production and others)"; cuda.enable = lib.mkEnableOption "Enables CUDA user package builds"; hyprland.enable = lib.mkEnableOption "Enables hyprland"; email = { email = lib.mkOption { type = lib.types.str; default = "ret2pop@gmail.com"; example = "john@example.com"; description = "Email address and imaps/smtps account"; }; imapsServer = lib.mkOption { type = lib.types.str; default = "imap.gmail.com"; example = "imap.example.com"; description = "imaps server address"; }; smtpsServer = lib.mkOption { type = lib.types.str; default = "smtp.gmail.com"; example = "smtp.example.com"; description = "smtp server address"; }; enable = lib.mkEnableOption "Enables email"; }; }; }; config = { home.packages = (if config.monorepo.profiles.email.enable then [ pkgs.mu ] else []) ++ (if config.monorepo.profiles.lang-c.enable then (with pkgs; [ autobuild clang gdb gnumake bear clang-tools ]) else []) ++ (if config.monorepo.profiles.workstation.enable then (with pkgs; [ mumble ]) else []) ++ (if config.monorepo.profiles.lang-js.enable then (with pkgs; [ nodejs bun yarn typescript typescript-language-server vscode-langservers-extracted ]) else []) ++ (if config.monorepo.profiles.lang-rust.enable then (with pkgs; [ cargo rust-analyzer rustfmt ]) else []) ++ (if config.monorepo.profiles.lang-python.enable then (with pkgs; [ poetry python3 python312Packages.jedi ]) else []) ++ (if config.monorepo.profiles.lang-sol.enable then (with pkgs; [ solc ]) else []) ++ (if config.monorepo.profiles.lang-openscad.enable then (with pkgs; [ openscad openscad-lsp ]) else []) ++ (if config.monorepo.profiles.lang-sh.enable then (with pkgs; [ bash-language-server ]) else []) ++ (if config.monorepo.profiles.lang-haskell.enable then (with pkgs; [ haskell-language-server haskellPackages.hlint ghc ]) else []) ++ (if config.monorepo.profiles.lang-coq.enable then (with pkgs; [ coq ]) else []) ++ (if config.monorepo.profiles.lang-lean.enable then (with pkgs; [ lean4 ]) else []) ++ (if config.monorepo.profiles.lang-nix.enable then (with pkgs; [ nil nixd nixfmt-rfc-style nix-prefetch-scripts ]) else []) ++ (if config.monorepo.profiles.crypto.enable then (with pkgs; [ bitcoin electrum monero-cli monero-gui ]) else []) ++ (if config.monorepo.profiles.art.enable then (with pkgs; [ inkscape # krita ]) else []) ++ (if config.monorepo.profiles.music.enable then (with pkgs; [ mpc-cli sox ]) else []) ++ (if config.monorepo.profiles.workstation.enable then (with pkgs; [ alsa-utils alsa-scarlett-gui ardour audacity # blender foxdot fluidsynth qjackctl qsynth qpwgraph imagemagick supercollider inkscape kdePackages.kdenlive # kicad murmur ]) else []); monorepo.profiles = { enable = lib.mkDefault true; music.enable = lib.mkDefault config.monorepo.profiles.enable; hyprland.enable = lib.mkDefault config.monorepo.profiles.enable; email.enable = lib.mkDefault config.monorepo.profiles.enable; # Programming graphics.enable = lib.mkDefault config.monorepo.profiles.enable; lang-c.enable = lib.mkDefault config.monorepo.profiles.enable; lang-rust.enable = lib.mkDefault config.monorepo.profiles.enable; lang-python.enable = lib.mkDefault config.monorepo.profiles.enable; lang-sol.enable = lib.mkDefault config.monorepo.profiles.enable; lang-sh.enable = lib.mkDefault config.monorepo.profiles.enable; lang-openscad.enable = lib.mkDefault config.monorepo.profiles.enable; lang-js.enable = lib.mkDefault config.monorepo.profiles.enable; lang-nix.enable = lib.mkDefault config.monorepo.profiles.enable; lang-coq.enable = lib.mkDefault config.monorepo.profiles.enable; lang-lean.enable = lib.mkDefault config.monorepo.profiles.enable; lang-haskell.enable = lib.mkDefault config.monorepo.profiles.enable; crypto.enable = lib.mkDefault config.monorepo.profiles.enable; art.enable = lib.mkDefault config.monorepo.profiles.enable; workstation.enable = lib.mkDefault config.monorepo.profiles.enable; }; }; } #+end_src *** Firefox I conditionally enable metamask based on the cryptocurrency option. Everything else here should be straightforward. #+begin_src nix :tangle ../nix/modules/home/firefox.nix { lib, config, pkgs, ... }: { programs.firefox = { enable = lib.mkDefault config.monorepo.profiles.graphics.enable; package = pkgs.firefox-bin; policies = { EnableTrackingProtection = true; OfferToSaveLogins = false; }; profiles = { default = { id = 0; name = "default"; isDefault = true; extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [ ublock-origin tree-style-tab firefox-color vimium ] ++ (lib.optional config.monorepo.profiles.crypto.enable pkgs.nur.repos.rycee.firefox-addons.metamask); settings = { media = { memory_cache_max_size = 65536; cache_readahead_limit = 7200; cache_resume_threshold = 3600; peerconnection.ice = { proxy_only_if_behind_proxy = true; default_address_only = true; }; }; gfx = { content.skia-font-cache-size = 20; canvas.accelerated = { cache-items = 4096; cache-size = 512; }; }; network = { http = { max-connections = 1800; max-persistent-connections-per-server = 10; max-urgent-start-excessive-connections-per-host = 5; referer.XOriginTrimmingPolicy = 2; }; buffer.cache = { size = 262144; count = 128; }; dns = { max_high_priority_threads = 8; disablePrefetch = true; }; pacing.requests.enabled = false; dnsCacheExpiration = 3600; ssl_tokens_cache_capacity = 10240; prefetch-next = false; predictor.enabled = false; cookie.sameSite.noneRequiresSecure = true; IDN_show_punycode = true; auth.subresource-http-auth-allow = 1; captive-portal-service.enabled = false; connectivity-service.enabled = false; }; browser = { download = { always_ask_before_handling_new_types = true; manager.addToRecentDocs = false; open_pdf_attachments_inline = true; start_downloads_in_tmp_dir = true; }; urlbar = { suggest.quicksuggest.sponsored = false; suggest.quicksuggest.nonsponsored = false; suggest.calculator = true; update2.engineAliasRefresh = true; unitConversion.enabled = true; trending.featureGate = false; }; search = { separatePrivateDefault.ui.enabled = true; suggest.enabled = false; }; newtabpage.activity-stream = { feeds = { topsites = false; section.topstories = false; telemetry = false; }; asrouter.userprefs.cfr = { addons = false; features = false; }; telemetry = false; }; privatebrowsing = { vpnpromourl = ""; forceMediaMemoryCache = true; }; display = { focus_ring_on_anything = true; focus_ring_style = 0; focus_ring_width = 0; }; cache.jsbc_compression_level = 3; helperApps.deleteTempFileOnExit = true; uitour.enabled = false; sessionstore.interval = 60000; formfill.enable = false; xul.error_pages.expert_bad_cert = true; contentblocking.category = "strict"; ping-centre.telemetry = false; discovery.enabled = false; shell.checkDefaultBrowser = false; preferences.moreFromMozilla = false; tabs.tabmanager.enabled = false; aboutConfig.showWarning = false; aboutwelcome.enabled = false; bookmarks.openInTabClosesMenu = false; menu.showViewImageInfo = true; compactmode.show = true; safebrowsing.downloads.remote.enabled = false; tabs.crashReporting.sendReport = false; crashReports.unsubmittedCheck.autoSubmit2 = false; privateWindowSeparation.enabled = false; }; security = { mixed_content = { block_display_content = true; upgrade_display_content = true; }; insecure_connection_text = { enabled = true; pbmode.enabled = true; }; OCSP.enabled = 0; remote_settings.crlite_filters.enabled = true; pki.crlite_mode = 2; ssl.treat_unsafe_negotiation_as_broken = true; tls.enable_0rtt_data = false; }; toolkit = { telemetry = { unified = false; enabled = false; server = "data:,"; archive.enabled = false; newProfilePing.enabled = false; shutdownPingSender.enabled = false; updatePing.enabled = false; bhrPing.enabled = false; firstShutdownPing.enabled = false; coverage.opt-out = true; }; coverage = { opt-out = true; endpoint.base = ""; }; legacyUserProfileCustomizations.stylesheets = true; }; dom = { security = { https_first = true; https_first_schemeless = true; sanitizer.enabled = true; }; enable_web_task_scheduling = true; }; layout = { css = { grid-template-masonry-value.enabled = true; has-selector.enabled = true; prefers-color-scheme.content-override = 2; }; word_select.eat_space_to_next_word = false; }; urlclassifier = { trackingSkipURLs = "*.reddit.com, *.twitter.com, *.twimg.com, *.tiktok.com"; features.socialtracking.skipURLs = "*.instagram.com, *.twitter.com, *.twimg.com"; }; privacy = { globalprivacycontrol.enabled = true; history.custom = true; userContext.ui.enabled = true; trackingprotection = { enabled = true; pbmode.enabled = true; socialtracking.enabled = true; }; }; full-screen-api = { transition-duration = { enter = "0 0"; leave = "0 0"; }; warning = { delay = -1; timeout = 0; }; }; permissions.default = { desktop-notification = 2; geo = 2; }; signon = { formlessCapture.enabled = false; privateBrowsingCapture.enabled = false; }; datareporting = { policy.dataSubmissionEnabled = false; healthreport.uploadEnabled = false; }; extensions = { pocket.enabled = false; getAddons.showPane = false; htmlaboutaddons.recommendations.enabled = false; postDownloadThirdPartyPrompt = false; }; app = { shield.optoutstudies.enabled = false; normandy.enabled = false; normandy.api_url = ""; }; image.mem.decode_bytes_at_a_time = 32768; editor.truncate_user_pastes = false; pdfjs.enableScripting = false; geo.provider.network.url = "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%"; permissions.manager.defaultsUrl = ""; webchannel.allowObject.urlWhitelist = ""; breakpad.reportURL = ""; captivedetect.canonicalURL = ""; cookiebanners.service.mode = 1; findbar.highlightAll = true; content.notify.interval = 100000; }; }; }; }; } #+end_src *** Fcitx This is a virtual keyboard program for writing in multiple languages. I use this sometimes. #+begin_src nix :tangle ../nix/modules/home/fcitx.nix { config, pkgs, lib, ... }: { i18n.inputMethod = { type = "fcitx5"; enable = lib.mkDefault config.monorepo.profiles.graphics.enable; fcitx5.addons = with pkgs; [ fcitx5-gtk fcitx5-chinese-addons fcitx5-configtool fcitx5-mozc fcitx5-rime ]; }; } #+end_src Note that I configure fcitx with chinese and some japanese input enabled. *** Emacs I install all my emacs packages within Nix so that they build deterministically with native compilation, and because I can fetch their exact versions. Note that I have a stub configuration here that tells emacs to load my real configuration at ~~/monorepo/config/emacs.org~ as an org file which gets automatically tangled to an emacs-lisp file. #+begin_src nix :tangle ../nix/modules/home/emacs.nix { lib, config, pkgs, ... }: { programs.emacs = { enable = lib.mkDefault config.monorepo.profiles.graphics.enable; package = pkgs.emacs-pgtk; extraConfig = '' (setq debug-on-error t) (org-babel-load-file (expand-file-name "~/monorepo/config/emacs.org"))''; extraPackages = epkgs: [ epkgs.all-the-icons epkgs.auctex epkgs.catppuccin-theme epkgs.chatgpt-shell epkgs.company epkgs.company-solidity epkgs.counsel epkgs.dashboard epkgs.doom-modeline epkgs.elfeed epkgs.elfeed-org epkgs.elfeed-tube epkgs.elfeed-tube-mpv epkgs.ellama epkgs.elpher epkgs.ement epkgs.emmet-mode epkgs.emms epkgs.enwc epkgs.evil epkgs.evil-collection epkgs.evil-commentary epkgs.evil-org epkgs.f epkgs.flycheck epkgs.general epkgs.gptel epkgs.gruvbox-theme epkgs.haskell-mode epkgs.htmlize epkgs.irony-eldoc epkgs.ivy epkgs.ivy-pass epkgs.kiwix epkgs.latex-preview-pane epkgs.lsp-ivy epkgs.lsp-mode epkgs.lsp-haskell epkgs.lyrics-fetcher epkgs.magit epkgs.magit-delta epkgs.mu4e epkgs.minuet epkgs.nix-mode epkgs.org-fragtog epkgs.org-journal epkgs.org-roam epkgs.org-roam-ui epkgs.org-superstar epkgs.page-break-lines epkgs.password-store epkgs.pdf-tools epkgs.pinentry epkgs.platformio-mode epkgs.projectile epkgs.rustic epkgs.scad-mode epkgs.simple-httpd epkgs.solidity-flycheck epkgs.solidity-mode epkgs.sudo-edit epkgs.treemacs epkgs.treemacs-evil epkgs.treemacs-magit epkgs.treemacs-projectile epkgs.treesit-auto epkgs.typescript-mode epkgs.unicode-fonts epkgs.use-package epkgs.vterm epkgs.wgrep epkgs.web-mode epkgs.websocket epkgs.which-key epkgs.writegood-mode epkgs.writeroom-mode epkgs.yaml-mode epkgs.yasnippet epkgs.yasnippet-snippets ]; }; } #+end_src *** Gammastep This is a program like redshift for making your screen emit more red and less blue light. Here I have the long and lat set for Vancouver, but you should replace it if you live outside the timezone. #+begin_src nix :tangle ../nix/modules/home/gammastep.nix { lib, config, ... }: { services.gammastep = { enable = lib.mkDefault config.monorepo.profiles.graphics.enable; provider = "manual"; latitude = 49.282730; longitude = -123.120735; temperature = { day = 5000; night = 3000; }; settings = { general = { adjustment-method = "wayland"; }; }; }; } #+end_src *** Git My git configuration uses information set in the ~vars.nix~ in order to set configuration options. Make sure those are set correctly. I've set it to sign by default. #+begin_src nix :tangle ../nix/modules/home/git.nix { lib, config, ... }: { programs.git = { enable = lib.mkDefault config.monorepo.profiles.graphics.enable; userName = config.monorepo.vars.fullName; userEmail = config.monorepo.profiles.email.email; signing = { key = config.monorepo.vars.gpgKey; signByDefault = true; }; extraConfig = { init.defaultBranch = "main"; }; aliases = { co = "checkout"; c = "commit"; a = "add"; s = "switch"; b = "branch"; }; }; } #+end_src *** Hyprland My compositor/window manager. This automatically starts on startup. Instructions on how to use this component will come soon. #+begin_src nix :tangle ../nix/modules/home/hyprland.nix { lib, config, wallpapers, pkgs, scripts, ... }: { wayland.windowManager.hyprland = { enable = lib.mkDefault config.monorepo.profiles.hyprland.enable; package = pkgs.hyprland; xwayland.enable = true; systemd.enable = true; settings = { "$mod" = "SUPER"; bezier = [ "overshot,0,1,0,0.95" ]; animation = [ "workspaces, 1, 10, overshot" ]; exec-once = [ "waybar" "swww-daemon --format xrgb" "swww img ${wallpapers}/imagination.png" "fcitx5-remote -r" "fcitx5 -d --replace" "fcitx5-remote -r" "emacs" "firefox" ]; env = [ "LIBVA_DRIVER_NAME,nvidia" "XDG_SESSION_TYPE,wayland" "GBM_BACKEND,nvidia-drm" "__GLX_VENDOR_LIBRARY_NAME,nvidia" "ELECTRON_OZONE_PLATFORM_HINT,auto" ]; blurls = [ "waybar" ]; monitor = [ "Unknown-1,disable" ]; windowrulev2 = [ "workspace 1, class:^(emacs)$" "workspace 2, class:^(firefox)$" "workspace 2, title:^(.*Tor Browser.*)$" "workspace 2, title:^(.*Chromium-browser.*)$" "workspace 2, class:^(chromium)$" "workspace 3, class:^(discord)$" "workspace 3, class:^(vesktop)$" "workspace 3, title:^(.*fluffychat.*)$" "workspace 3, class:^(.*element-desktop.*)$" "workspace 4, class:^(.*qpwgraph.*)$" "workspace 4, class:^(.*mpv.*)$" "workspace 5, title:^(.*Monero.*)$" "workspace 5, title:^(.*org\.bitcoin\..*)$" "workspace 5, title:^(.*Bitcoin Core - preston.*)$" "workspace 5, title:^(.*org\.getmonero\..*)$" "workspace 5, title:^(.*Monero - preston.*)$" "workspace 5, title:^(.*electrum.*)$" "pseudo,title:fcitx" ]; bind = [ "$mod, F, exec, firefox" "$mod, T, exec, tor-browser" "$mod, Return, exec, kitty" "$mod, E, exec, emacs" "$mod, B, exec, bitcoin-qt" "$mod, M, exec, monero-wallet-gui" "$mod, V, exec, vesktop" "$mod, D, exec, wofi --show run" "$mod, P, exec, bash ${scripts}/powermenu.sh" "$mod, Q, killactive" "$mod SHIFT, H, movewindow, l" "$mod SHIFT, L, movewindow, r" "$mod SHIFT, K, movewindow, u" "$mod SHIFT, J, movewindow, d" "$mod, H, movefocus, l" "$mod, L, movefocus, r" "$mod, K, movefocus, u" "$mod, J, movefocus, d" ", XF86AudioPlay, exec, mpc toggle" ", Print, exec, grim" ] ++ ( builtins.concatLists (builtins.genList ( x: let ws = let c = (x + 1) / 10; in builtins.toString (x + 1 - (c * 10)); in [ "$mod, ${ws}, workspace, ${toString (x + 1)}" "$mod SHIFT, ${ws}, movetoworkspace, ${toString (x + 1)}" ] ) 10) ); bindm = [ "$mod, mouse:272, movewindow" "$mod, mouse:273, resizewindow" "$mod ALT, mouse:272, resizewindow" ]; binde = [ ", XF86AudioRaiseVolume, exec, wpctl set-volume -l 1.5 @DEFAULT_AUDIO_SINK@ 5%+" ", XF86AudioLowerVolume, exec, wpctl set-volume -l 1.5 @DEFAULT_AUDIO_SINK@ 5%-" ", XF86AudioNext, exec, mpc next" ", XF86AudioPrev, exec, mpc prev" ", XF86MonBrightnessUp , exec, xbacklight -inc 10" ", XF86MonBrightnessDown, exec, xbacklight -dec 10" ]; decoration = { blur = { enabled = true; size = 5; passes = 2; }; rounding = 5; }; device = { name = "beken-usb-gaming-mouse-1"; sensitivity = -0.5; }; input = { kb_options = "caps:swapescape"; repeat_delay = 300; repeat_rate = 50; natural_scroll = true; touchpad = { natural_scroll = true; disable_while_typing = true; tap-to-click = true; }; }; cursor = { no_hardware_cursors = true; }; misc = { force_default_wallpaper = 0; disable_hyprland_logo = true; }; }; }; } #+end_src *** Kitty I've set my terminal, kitty, to use catppuccin colors. #+begin_src nix :tangle ../nix/modules/home/kitty.nix { lib, config, ... }: { programs.kitty = { enable = lib.mkDefault (config.monorepo.profiles.hyprland.enable && config.monorepo.profiles.graphics.enable); settings = { enable_audio_bell = false; font_family = "Iosevka Nerd Font"; font_size = 14; confirm_os_window_close = 0; background_opacity = "0.9"; # Catppuccin theme foreground = "#cdd6f4"; background = "#1e1e2e"; selection_foreground = "#1e1e2e"; selection_background = "#f5e0dc"; cursor = "#f5e0dc"; cursor_text_color = "#1e1e2e"; url_color = "#f5e0dc"; active_border_color = "#B4BEFE"; inactive_border_color = "#6C7086"; bell_border_color = "#F9E2AF"; wayland_titlebar_color = "#1E1E2E"; macos_titlebar_color = "#1E1E2E"; active_tab_foreground = "#11111B"; active_tab_background = "#CBA6F7"; inactive_tab_foreground = "#CDD6F4"; inactive_tab_background = "#181825"; tab_bar_background = "#11111B"; mark1_foreground = "#1E1E2E"; mark1_background = "#B4BEFE"; mark2_foreground = "#1E1E2E"; mark2_background = "#CBA6F7"; mark3_foreground = "#1E1E2E"; mark3_background = "#74C7EC"; color0 = "#45475A"; color8 = "#585B70"; color1 = "#F38BA8"; color9 = "#F38BA8"; color2 = "#A6E3A1"; color10 = "#A6E3A1"; color3 = "#F9E2AF"; color11 = "#F9E2AF"; color4 = "#89B4FA"; color12 = "#89B4FA"; color5 = "#F5C2E7"; color13 = "#F5C2E7"; color6 = "#94E2D5"; color14 = "#94E2D5"; color7 = "#BAC2DE"; color15 = "#A6ADC8"; }; }; } #+end_src *** Mako This is my notification system. My flake automatically fetches the notification sound, so you are all set from the get-go! #+begin_src nix :tangle ../nix/modules/home/mako.nix { lib, config, sounds, ... }: { services.mako = { enable = lib.mkDefault config.monorepo.profiles.graphics.enable; settings = { on-notify = "exec mpv ${sounds}/polite.ogg --no-config --no-video"; background-color = "#11111bf8"; text-color = "#cdd6f4"; border-color = "#89b4faff"; border-radius = 1; font = "Fira Code 10"; default-timeout = 3000; }; }; } #+end_src *** Mbsync Note that in order to use my email configuration, your imaps and smtps servers must be encrypted. This module uses the ~vars.nix~ as well as the home ~default.nix~ options. #+begin_src nix :tangle ../nix/modules/home/mbsync.nix { lib, config, ... }: { programs.mbsync = { enable = lib.mkDefault config.monorepo.profiles.email.enable; extraConfig = '' IMAPAccount ret2pop Host ${config.monorepo.profiles.email.imapsServer} User ${config.monorepo.profiles.email.email} PassCmd "cat ${config.sops.secrets.mail.path}" Port 993 TLSType IMAPS AuthMechs * CertificateFile /etc/ssl/certs/ca-certificates.crt IMAPStore ret2pop-remote Account ret2pop MaildirStore ret2pop-local Path ~/email/ret2pop/ Inbox ~/email/ret2pop/INBOX SubFolders Verbatim Channel ret2pop Far :ret2pop-remote: Near :ret2pop-local: Patterns * Create Near Sync All Expunge None SyncState * ''; }; } #+end_src *** MSMTP This is the program I use to send email from emacs. It is really the same thing as above, just set the options to the ones you want in your system ~default.nix~. #+begin_src nix :tangle ../nix/modules/home/msmtp.nix { lib, config, ... }: { programs.msmtp = { enable = lib.mkDefault config.monorepo.profiles.email.enable; extraConfig = '' # Set default values for all following accounts. defaults auth on tls on tls_trust_file /etc/ssl/certs/ca-certificates.crt tls_certcheck off logfile ~/.msmtp.log # Gmail account ${config.monorepo.vars.userName} host ${config.monorepo.profiles.email.smtpsServer} port 587 from ${config.monorepo.profiles.email.email} user ${config.monorepo.profiles.email.email} passwordeval "cat ${config.sops.secrets.mail.path}" # Set a default account account default : ${config.monorepo.vars.userName} ''; }; } #+end_src *** Mpd This mpd configuration uses pipewire by default, and it should just work if you place music in the ~~/music~ directory and then run ~mpc add /~ afterwards. #+begin_src nix :tangle ../nix/modules/home/mpd.nix { lib, config, ... }: { services.mpd = { enable = lib.mkDefault config.monorepo.profiles.music.enable; dbFile = "/home/${config.monorepo.vars.userName}/.config/mpd/db"; dataDir = "/home/${config.monorepo.vars.userName}/.config/mpd/"; network.port = 6600; musicDirectory = "/home/${config.monorepo.vars.userName}/music"; playlistDirectory = "/home/${config.monorepo.vars.userName}/.config/mpd/playlists"; network.listenAddress = "0.0.0.0"; extraConfig = '' audio_output { type "pipewire" name "pipewire output" } audio_output { type "httpd" name "My HTTP Stream" encoder "opus" # optional port "8000" # quality "5.0" # do not define if bitrate is defined bitrate "128000" # do not define if quality is defined format "48000:16:1" always_on "yes" # prevent MPD from disconnecting all listeners when playback is stopped. tags "yes" # httpd supports sending tags to listening streams. } audio_output { type "shout" encoding "ogg" name "my cool stream" host "localhost" port "8000" mount "/example.ogg" user "source" password "" bitrate "64" format "44100:16:1" description "Nullring public radio" } ''; }; } #+end_src *** MPV I have some emacs + yt-dlp integrations with mpv with my rss feed, and therefore we need it here: #+begin_src nix :tangle ../nix/modules/home/mpv.nix { lib, config, ... }: { programs.mpv = { enable = lib.mkDefault config.monorepo.profiles.graphics.enable; config = { profile = "gpu-hq"; force-window = true; ytdl-format = "bestvideo+bestaudio"; cache-default = 4000000; }; }; } #+end_src *** Secrets This uses sops in order to declaratively create the secrets on my system by unencrypting the yaml file specified. Yes, this is safe to include in the repo. #+begin_src nix :tangle ../nix/modules/home/secrets.nix { config, ... }: { sops = { defaultSopsFile = ../../secrets/secrets.yaml; age = { keyFile = "/home/${config.monorepo.vars.userName}/.ssh/keys.txt"; }; secrets = { mail = { format = "yaml"; path = "${config.sops.defaultSymlinkPath}/mail"; }; cloudflare-dns = { format = "yaml"; path = "${config.sops.defaultSymlinkPath}/cloudflare-dns"; }; digikey = { format = "yaml"; path = "${config.sops.defaultSymlinkPath}/digikey"; }; dn42 = { format = "yaml"; path = "${config.sops.defaultSymlinkPath}/dn42"; }; znc = { format = "yaml"; path = "${config.sops.defaultSymlinkPath}/znc"; }; znc_password_salt = { format = "yaml"; path = "${config.sops.defaultSymlinkPath}/znc_password_salt"; }; znc_password_hash = { format = "yaml"; path = "${config.sops.defaultSymlinkPath}/znc_password_hash"; }; matrix_bridge = { format = "yaml"; path = "${config.sops.defaultSymlinkPath}/matrix_bridge"; }; }; defaultSymlinkPath = "/run/user/1000/secrets"; defaultSecretsMountPoint = "/run/user/1000/secrets.d"; }; } #+end_src *** Waybar This is the bar I use for my hyprland configuration. You will need to adjust the monitors field in the ~default.nix~ for it to really appear. #+begin_src nix :tangle ../nix/modules/home/waybar.nix { lib, config, ... }: { programs.waybar = { enable = lib.mkDefault config.monorepo.profiles.hyprland.enable; style = '' ,* { border: none; border-radius: 0px; font-family: Iosevka Nerd Font, FontAwesome, Noto Sans CJK; font-size: 14px; font-style: normal; min-height: 0; } window#waybar { background: rgba(30, 30, 46, 0.5); border-bottom: 1px solid #45475a; color: #cdd6f4; } #workspaces { background: #45475a; margin: 5px 5px 5px 5px; padding: 0px 5px 0px 5px; border-radius: 16px; border: solid 0px #f4d9e1; font-weight: normal; font-style: normal; } #workspaces button { padding: 0px 5px; border-radius: 16px; color: #a6adc8; } #workspaces button.active { color: #f4d9e1; background-color: transparent; border-radius: 16px; } #workspaces button:hover { background-color: #cdd6f4; color: black; border-radius: 16px; } #custom-date, #clock, #battery, #pulseaudio, #network, #custom-randwall, #custom-launcher { background: transparent; padding: 5px 5px 5px 5px; margin: 5px 5px 5px 5px; border-radius: 8px; border: solid 0px #f4d9e1; } #custom-date { color: #D3869B; } #custom-power { color: #24283b; background-color: #db4b4b; border-radius: 5px; margin-right: 10px; margin-top: 5px; margin-bottom: 5px; margin-left: 0px; padding: 5px 10px; } #tray { background: #45475a; margin: 5px 5px 5px 5px; border-radius: 16px; padding: 0px 5px; /*border-right: solid 1px #282738;*/ } #clock { color: #cdd6f4; background-color: #45475a; border-radius: 0px 0px 0px 24px; padding-left: 13px; padding-right: 15px; margin-right: 0px; margin-left: 10px; margin-top: 0px; margin-bottom: 0px; font-weight: bold; /*border-left: solid 1px #282738;*/ } #battery { color: #89b4fa; } #battery.charging { color: #a6e3a1; } #battery.warning:not(.charging) { background-color: #f7768e; color: #f38ba8; border-radius: 5px 5px 5px 5px; } #backlight { background-color: #24283b; color: #db4b4b; border-radius: 0px 0px 0px 0px; margin: 5px; margin-left: 0px; margin-right: 0px; padding: 0px 0px; } #network { color: #f4d9e1; border-radius: 8px; margin-right: 5px; } #pulseaudio { color: #f4d9e1; border-radius: 8px; margin-left: 0px; } #pulseaudio.muted { background: transparent; color: #928374; border-radius: 8px; margin-left: 0px; } #custom-randwall { color: #f4d9e1; border-radius: 8px; margin-right: 0px; } #custom-launcher { color: #e5809e; background-color: #45475a; border-radius: 0px 24px 0px 0px; margin: 0px 0px 0px 0px; padding: 0 20px 0 13px; /*border-right: solid 1px #282738;*/ font-size: 20px; } #custom-launcher button:hover { background-color: #FB4934; color: transparent; border-radius: 8px; margin-right: -5px; margin-left: 10px; } #custom-playerctl { background: #45475a; padding-left: 15px; padding-right: 14px; border-radius: 16px; /*border-left: solid 1px #282738;*/ /*border-right: solid 1px #282738;*/ margin-top: 5px; margin-bottom: 5px; margin-left: 0px; font-weight: normal; font-style: normal; font-size: 16px; } #custom-playerlabel { background: transparent; padding-left: 10px; padding-right: 15px; border-radius: 16px; /*border-left: solid 1px #282738;*/ /*border-right: solid 1px #282738;*/ margin-top: 5px; margin-bottom: 5px; font-weight: normal; font-style: normal; } #window { background: #45475a; padding-left: 15px; padding-right: 15px; border-radius: 16px; /*border-left: solid 1px #282738;*/ /*border-right: solid 1px #282738;*/ margin-top: 5px; margin-bottom: 5px; font-weight: normal; font-style: normal; } #custom-wf-recorder { padding: 0 20px; color: #e5809e; background-color: #1E1E2E; } #cpu { background-color: #45475a; /*color: #FABD2D;*/ border-radius: 16px; margin: 5px; margin-left: 5px; margin-right: 5px; padding: 0px 10px 0px 10px; font-weight: bold; } #memory { background-color: #45475a; /*color: #83A598;*/ border-radius: 16px; margin: 5px; margin-left: 5px; margin-right: 5px; padding: 0px 10px 0px 10px; font-weight: bold; } #disk { background-color: #45475a; /*color: #8EC07C;*/ border-radius: 16px; margin: 5px; margin-left: 5px; margin-right: 5px; padding: 0px 10px 0px 10px; font-weight: bold; } #custom-hyprpicker { background-color: #45475a; /*color: #8EC07C;*/ border-radius: 16px; margin: 5px; margin-left: 5px; margin-right: 5px; padding: 0px 11px 0px 9px; font-weight: bold; } ''; settings = { mainBar = { layer = "top"; position = "top"; height = 50; output = config.monorepo.vars.monitors; modules-left = [ "hyprland/workspaces" ]; modules-center = [ "hyprland/window" ]; modules-right = [ "battery" "clock" ]; battery = { format = "{icon} {capacity}%"; format-icons = ["" "" "" "" "" ]; }; clock = { format = "⏰ {:%a %d, %b %H:%M}"; }; }; }; }; } #+end_src *** Wofi This is a run launcher for wayland. I also use it for my powermenu. #+begin_src nix :tangle ../nix/modules/home/wofi.nix { lib, config, ... }: { programs.wofi = { enable = lib.mkDefault config.monorepo.profiles.graphics.enable; settings = { location = "bottom-right"; allow_markup = true; show = "drun"; width = 750; height = 400; always_parse_args = true; show_all = false; term = "kitty"; hide_scroll = true; print_command = true; insensitive = true; prompt = "Run what, Commander?"; columns = 2; }; style = '' @define-color rosewater #f5e0dc; @define-color rosewater-rgb rgb(245, 224, 220); @define-color flamingo #f2cdcd; @define-color flamingo-rgb rgb(242, 205, 205); @define-color pink #f5c2e7; @define-color pink-rgb rgb(245, 194, 231); @define-color mauve #cba6f7; @define-color mauve-rgb rgb(203, 166, 247); @define-color red #f38ba8; @define-color red-rgb rgb(243, 139, 168); @define-color maroon #eba0ac; @define-color maroon-rgb rgb(235, 160, 172); @define-color peach #fab387; @define-color peach-rgb rgb(250, 179, 135); @define-color yellow #f9e2af; @define-color yellow-rgb rgb(249, 226, 175); @define-color green #a6e3a1; @define-color green-rgb rgb(166, 227, 161); @define-color teal #94e2d5; @define-color teal-rgb rgb(148, 226, 213); @define-color sky #89dceb; @define-color sky-rgb rgb(137, 220, 235); @define-color sapphire #74c7ec; @define-color sapphire-rgb rgb(116, 199, 236); @define-color blue #89b4fa; @define-color blue-rgb rgb(137, 180, 250); @define-color lavender #b4befe; @define-color lavender-rgb rgb(180, 190, 254); @define-color text #cdd6f4; @define-color text-rgb rgb(205, 214, 244); @define-color subtext1 #bac2de; @define-color subtext1-rgb rgb(186, 194, 222); @define-color subtext0 #a6adc8; @define-color subtext0-rgb rgb(166, 173, 200); @define-color overlay2 #9399b2; @define-color overlay2-rgb rgb(147, 153, 178); @define-color overlay1 #7f849c; @define-color overlay1-rgb rgb(127, 132, 156); @define-color overlay0 #6c7086; @define-color overlay0-rgb rgb(108, 112, 134); @define-color surface2 #585b70; @define-color surface2-rgb rgb(88, 91, 112); @define-color surface1 #45475a; @define-color surface1-rgb rgb(69, 71, 90); @define-color surface0 #313244; @define-color surface0-rgb rgb(49, 50, 68); @define-color base #1e1e2e; @define-color base-rgb rgb(30, 30, 46); @define-color mantle #181825; @define-color mantle-rgb rgb(24, 24, 37); @define-color crust #11111b; @define-color crust-rgb rgb(17, 17, 27); * { font-family: 'Iosevka Nerd Font', monospace; font-size: 14px; } /* Window */ window { margin: 0px; padding: 10px; border: 0.16em solid @lavender; border-radius: 0.1em; background-color: @base; animation: slideIn 0.5s ease-in-out both; } /* Slide In */ @keyframes slideIn { 0% { opacity: 0; } 100% { opacity: 1; } } /* Inner Box */ #inner-box { margin: 5px; padding: 10px; border: none; background-color: @base; animation: fadeIn 0.5s ease-in-out both; } /* Fade In */ @keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } /* Outer Box */ #outer-box { margin: 5px; padding: 10px; border: none; background-color: @base; } /* Scroll */ #scroll { margin: 0px; padding: 10px; border: none; background-color: @base; } /* Input */ #input { margin: 5px 20px; padding: 10px; border: none; border-radius: 0.1em; color: @text; background-color: @base; animation: fadeIn 0.5s ease-in-out both; } #input image { border: none; color: @red; } #input * { outline: 4px solid @red!important; } /* Text */ #text { margin: 5px; border: none; color: @text; animation: fadeIn 0.5s ease-in-out both; } #entry { background-color: @base; } #entry arrow { border: none; color: @lavender; } /* Selected Entry */ #entry:selected { border: 0.11em solid @lavender; } #entry:selected #text { color: @mauve; } #entry:drop(active) { background-color: @lavender!important; } ''; }; } #+end_src *** yt-dlp A classic program that allows you to download from youtube. Also has integrations with mpv. #+begin_src nix :tangle ../nix/modules/home/yt-dlp.nix { lib, config, ... }: { programs.yt-dlp = { enable = lib.mkDefault config.monorepo.profiles.graphics.enable; settings = { embed-thumbnail = true; embed-subs = true; sub-langs = "all"; downloader = "aria2c"; downloader-args = "aria2c:'-c -x8 -s8 -k1M'"; }; }; } #+end_src *** Zsh My zsh config has some useful aliases that one should read through. Otherwise it is pretty standard. #+begin_src nix :tangle ../nix/modules/home/zsh.nix { lib, config, pkgs, systemHostName, ... }: { programs.zsh = { enable = true; initContent = '' umask 0022 export EXTRA_CCFLAGS="-I/usr/include" source ${pkgs.zsh-vi-mode}/share/zsh-vi-mode/zsh-vi-mode.plugin.zsh export QT_QPA_PLATFORM="wayland" export OLLAMA_MODEL="qwen3:14b" ''; localVariables = { EDITOR = "emacsclient --create-frame --alternate-editor=vim"; INPUT_METHOD = "fcitx"; QT_IM_MODULE = "fcitx"; GTK_IM_MODULE = "fcitx"; XMODIFIERS = "@im=fcitx"; XIM_SERVERS = "fcitx"; WXSUPPRESS_SIZER_FLAGS_CHECK = "1"; }; shellAliases = { c = "clear"; g = "git"; v = "vim"; py = "python3"; rb = "sudo nixos-rebuild switch --flake $HOME/monorepo/nix#${systemHostName}"; nfu = "cd ~/monorepo/nix && git add . && git commit -m \"new flake lock\" && nix flake update"; usync = "rsync -azvP --chmod=\"Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r\" ~/website_html/ root@${config.monorepo.vars.remoteHost}:/var/www/ret2pop-website/"; usite = "cd ~/src/publish-org-roam-ui && bash local.sh && rm -rf ~/website_html/graph_view; cp -r ~/src/publish-org-roam-ui/out ~/website_html/graph_view && rsync -azvP --chmod=\"Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r\" ~/website_html/ root@${config.monorepo.vars.remoteHost}:/var/www/ret2pop-website/"; sai = "eval \"$(ssh-agent -s)\" && ssh-add ~/.ssh/id_ed25519 && ssh-add -l"; i3 = "exec ${pkgs.i3-gaps}/bin/i3"; }; loginExtra = '' if [[ "$(tty)" = "/dev/tty1" ]]; then exec Hyprland fi ''; }; } #+end_src *** Pantalaimon This is used with ement as a proxy in order to connect to a remote matrix server while having encryption. #+begin_src nix :tangle ../nix/modules/home/pantalaimon.nix { lib, config, ... }: { services.pantalaimon = { enable = lib.mkDefault config.monorepo.profiles.graphics.enable; settings = { Default = { LogLevel = "Debug"; SSL = true; }; local-matrix = { Homeserver = "https://social.nullring.xyz"; ListenAddress = "127.0.0.1"; ListenPort = "8008"; }; }; }; } #+end_src *** User This configuration is the backbone configuration for the default user. It specifies some generally useful packages and something every home should have, as well as some dependencies for these configurations. #+begin_src nix :tangle ../nix/modules/home/user.nix { lib, config, pkgs, ... }: { home = { activation.startup-files = lib.hm.dag.entryAfter [ "installPackages" ] '' if [ ! -d "/home/${config.monorepo.vars.userName}/email/ret2pop/" ]; then mkdir -p /home/${config.monorepo.vars.userName}/email/ret2pop/ fi if [ ! -d "/home/${config.monorepo.vars.userName}/music" ]; then mkdir -p /home/${config.monorepo.vars.userName}/music fi if [ ! -d /home/${config.monorepo.vars.userName}/org ]; then mkdir -p /home/${config.monorepo.vars.userName}/org fi if [ ! -d /home/${config.monorepo.vars.userName}/src ]; then mkdir -p /home/${config.monorepo.vars.userName}/src fi touch /home/${config.monorepo.vars.userName}/org/agenda.org touch /home/${config.monorepo.vars.userName}/org/notes.org ''; enableNixpkgsReleaseCheck = false; username = config.monorepo.vars.userName; homeDirectory = "/home/${config.monorepo.vars.userName}"; stateVersion = "24.11"; packages = with pkgs; (if config.monorepo.profiles.graphics.enable then [ # wikipedia # kiwix kiwix-tools # passwords age sops # formatting ghostscript texliveFull pandoc # Emacs Deps graphviz jq # Apps # octaveFull vesktop grim swww vim telegram-desktop # Sound/media pavucontrol alsa-utils imagemagick ffmpeg helvum # Net curl rsync git iamb # Tor torsocks tor-browser # fonts nerd-fonts.iosevka noto-fonts noto-fonts-cjk-sans noto-fonts-emoji fira-code font-awesome_6 (aspellWithDicts (dicts: with dicts; [ en en-computers en-science ])) # Misc. pinentry x11_ssh_askpass xdg-utils acpilight pfetch libnotify htop (writeShellScriptBin "remote-build" '' #!/bin/bash nixos-rebuild --sudo --ask-sudo-password --target-host "$1" switch --flake $HOME/monorepo/nix#spontaneity '' ) (writeShellScriptBin "install-vps" '' #!/bin/bash nix run github:nix-community/nixos-anywhere -- --generate-hardware-config nixos-generate-config $HOME/monorepo/nix/systems/spontaneity/hardware-configuration.nix --flake $HOME/monorepo/nix#spontaneity --target-host "$1" '') ] else [ pfetch # net curl torsocks rsync ]); }; services = { gpg-agent = { pinentry.package = pkgs.pinentry-emacs; enable = true; extraConfig = '' allow-emacs-pinentry allow-loopback-pinentry ''; }; }; programs.bash.enable = true; gtk = { enable = lib.mkDefault config.monorepo.profiles.graphics.enable; theme = null; iconTheme = null; }; fonts.fontconfig.enable = true; } #+end_src * Systems ** Home This module dynamically imports the correct corresponding home.nix at the path. #+begin_src nix :tangle ../nix/systems/home.nix { config, sops-nix, ... }: { home-manager = { sharedModules = [ sops-nix.homeManagerModules.sops ]; useGlobalPkgs = true; useUserPackages = true; users."${config.monorepo.vars.userName}" = import (./. + "/${config.networking.hostName}/home.nix"); }; } #+end_src ** Includes These are the common includes for each of my systems. This ensures that we don't have to duplicate includes every time we want to add a new system. #+begin_src nix :tangle ../nix/systems/includes.nix { config, lib, ... }: { imports = [ ./home.nix ../modules/default.nix ]; } #+end_src ** Continuity This is pretty understandable, if you understand all the above. #+begin_src nix :tangle ../nix/systems/continuity/default.nix { ... }: { imports = [ ../../disko/drive-simple.nix ../includes.nix ]; config = { # drive to install to monorepo.vars.device = "/dev/sda"; }; } #+end_src *** Home Each system has a corresponding home configuration in order to set monorepo home options. #+begin_src nix :tangle ../nix/systems/continuity/home.nix { lib, config, pkgs, ... }: { imports = [ ../../modules/home/default.nix ]; config.monorepo.profiles.workstation.enable = false; } #+end_src ** Affinity This is my configuration for my workstation. It runs ollama, as well as several other useful services. #+begin_src nix :tangle ../nix/systems/affinity/default.nix { config, lib, home-manager, ... }: { imports = [ ../includes.nix ../../disko/drive-simple.nix ]; config = { monorepo = { vars.device = "/dev/nvme0n1"; profiles = { server.enable = false; cuda.enable = true; workstation.enable = true; }; }; }; } #+end_src *** Home #+begin_src nix :tangle ../nix/systems/affinity/home.nix { lib, config, pkgs, ... }: { imports = [ ../../modules/home/default.nix ]; config.monorepo = { profiles.cuda.enable = true; }; } #+end_src ** Spontaneity Spontaneity is my VPS instance. #+begin_src nix :tangle ../nix/systems/spontaneity/default.nix { config, lib, ... }: { imports = [ ../includes.nix # nixos-anywhere generates this file ./hardware-configuration.nix ../../disko/drive-bios.nix ]; config = { monorepo = { vars.device = "/dev/vda"; profiles = { server.enable = true; ttyonly.enable = true; grub.enable = true; }; }; boot.loader.grub.device = "nodev"; networking = { firewall.allowedTCPPorts = [ 80 443 465 993 8448 6697 6667 ]; domains = { enable = true; baseDomains = { "${config.monorepo.vars.remoteHost}" = { a.data = "66.42.84.130"; aaaa.data = "2001:19f0:5401:10d0:5400:5ff:fe4a:7794"; }; "nullring.xyz" = { a.data = "66.42.84.130"; aaaa.data = "2001:19f0:5401:10d0:5400:5ff:fe4a:7794"; }; }; subDomains = { "${config.monorepo.vars.remoteHost}" = {}; "matrix.${config.monorepo.vars.remoteHost}" = {}; "www.${config.monorepo.vars.remoteHost}" = {}; "mail.${config.monorepo.vars.remoteHost}" = {}; "nullring.xyz" = {}; "git.nullring.xyz" = {}; "matrix.nullring.xyz" = {}; "talk.nullring.xyz" = {}; "mail.nullring.xyz" = {}; "ret2pop.nullring.xyz" = {}; }; }; }; }; } #+end_src *** Home #+begin_src nix :tangle ../nix/systems/spontaneity/home.nix { lib, config, pkgs, ... }: { imports = [ ../../modules/home/default.nix ]; config.monorepo.profiles.enable = false; } #+end_src ** Installer My installer installs my systems almost completely without interaction. You can also make them install the exact version of the system that you want it to by pinning the commits to make it always work in the exact same deterministic way. *** Commit Hash Pinning Modify this to pin the installer image hash to make the installer image always work deterministically. #+begin_src nix :tangle ../nix/systems/installer/commits.nix { diskoCommitHash = "c8a0e78d86b12ea67be6ed0f7cae7f9bfabae75a"; monorepoCommitHash = "64a1acc961466c845b2601c0d0e165b16eb73fe2"; monorepoUrl = "https://github.com/ret2pop/monorepo"; } #+end_src *** ISO Default Profile This contains the installation script I use to install my systems. #+begin_src nix :tangle ../nix/systems/installer/default.nix { pkgs, config, lib, modulesPath, ... }: let commits = import ./commits.nix; in { imports = [ (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") ]; networking = { networkmanager = { enable = true; }; firewall = { allowedTCPPorts = [ 22 ]; allowedUDPPorts = [ ]; }; wireless.enable = false; }; services.openssh = { enable = true; ports = [ 22 ]; settings = { PasswordAuthentication = false; AllowUsers = null; UseDns = true; PermitRootLogin = lib.mkForce "prohibit-password"; }; }; users.extraUsers.root.password = "nixos"; users.extraUsers.nixos.password = "nixos"; users.users = { root.openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICts6+MQiMwpA+DfFQxjIN214Jn0pCw/2BDvOzPhR/H2 preston@continuity-dell" ]; nixos = { packages = with pkgs; [ git curl gum (writeShellScriptBin "nix_installer" '' #!/usr/bin/env bash set -euo pipefail if [ "$(id -u)" -eq 0 ]; then echo "ERROR! $(basename "$0") should be run as a regular user" exit 1 fi cd "$HOME" ping -q -c1 google.com &>/dev/null && echo "online! Proceeding with the installation..." || nmtui gum style --border normal --margin "1" --padding "1 2" "Choose a system to install or select `new` in order to create a new system." SYSTEM="$(gum choose $(find "$HOME/monorepo/nix/systems" -mindepth 1 -maxdepth 1 -type d -printf "%f\n" | grep -v -E 'installer'; printf "New"))" if [[ "$SYSTEM" == "New" ]]; then gum style --border normal --margin "1" --padding "1 2" "Choose a system name" SYSTEM="$(gum input --placeholder "system name")" gum style --border normal --margin "1" --padding "1 2" "Select a drive file or create a new drive file." DRIVE="$(gum choose $(find "$HOME/monorepo/nix/disko" -mindepth 1 -maxdepth 1 -type f -printf "%f\n"; printf "New"))" if [[ "$DRIVE" == "New" ]]; then gum style --border normal --margin "1" --padding "1 2" "Choose a name to call your drive file." DRIVE="$(gum input --placeholder "drive file name (ex: partition_scheme.nix)")" fi fi if [ ! -d "$HOME/monorepo/" ]; then git clone ${commits.monorepoUrl} cd "$HOME/monorepo" git checkout "${commits.monorepoCommitHash}" cd "$HOME" fi if [ ! -d "$HOME/monorepo/nix/systems/$SYSTEM" ]; then mkdir -p "$HOME/monorepo/nix/systems/$SYSTEM" cp "$HOME/monorepo/nix/systems/continuity/home.nix" "$HOME/monorepo/nix/systems/$SYSTEM/home.nix" cat > "$HOME/monorepo/nix/systems/$SYSTEM/default.nix" </dev/null vim "$HOME/monorepo/nix/systems/$SYSTEM/default.nix" gum style --border normal --margin "1" --padding "1 2" "Edit the home default.nix with options." gum input --placeholder "Press Enter to continue" >/dev/null vim "$HOME/monorepo/nix/systems/$SYSTEM/home.nix" sed -i "/# add hostnames here/i \ \"$1\"" "$HOME/monorepo/nix/flake.nix" if [ ! -f "$HOME/monorepo/nix/disko/$DRIVE" ]; then cp "$HOME/monorepo/nix/disko/drive-simple.nix" "$HOME/monorepo/nix/disko/$DRIVE" gum style --border normal --margin "1" --padding "1 2" "Edit the drive file with your preferred partitioning scheme." gum input --placeholder "Press Enter to continue" >/dev/null vim "$HOME/monorepo/nix/disko/$DRIVE" fi cd "$HOME/monorepo" && git add . && cd "$HOME" fi nix --extra-experimental-features 'nix-command flakes' eval "$HOME/monorepo/nix#evalDisko.$SYSTEM" > "$HOME/drive.nix" gum style --border normal --margin "1" --padding "1 2" "Formatting the drive is destructive!" if gum confirm "Are you sure you want to continue?"; then echo "Proceeding..." else echo "Aborting." exit 1 fi sudo nix --experimental-features "nix-command flakes" run "github:nix-community/disko/${commits.diskoCommitHash}" -- --mode destroy,format,mount "$HOME/drive.nix" cd /mnt sudo nixos-install --flake "$HOME/monorepo/nix#$SYSTEM" target_user="$(ls /mnt/home | head -n1)" if [ -z "$target_user" ]; then echo "No user directories found in /mnt/home" exit 1 fi sudo cp -r "$HOME/monorepo" "/mnt/home/$target_user/" echo "rebooting..."; sleep 3; reboot '') ]; }; }; systemd = { services.sshd.wantedBy = pkgs.lib.mkForce [ "multi-user.target" ]; targets = { sleep.enable = false; suspend.enable = false; hibernate.enable = false; hybrid-sleep.enable = false; }; }; } #+end_src * Add System Script Here is a script to add a new system automatically: #+begin_src bash :tangle ../nix/add-system.sh #!/usr/bin/env bash sed -i "/# add hostnames here/i \ \"$1\"" "$HOME/monorepo/nix/flake.nix" sed -i "/# add hostnames here/i \ \"$1\"" "$HOME/monorepo/config/nix.org" mkdir -p "$HOME/monorepo/nix/systems/$1" cat > "$HOME/monorepo/nix/systems/$1/default.nix" <