aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortdback <tyler@tdback.net>2024-12-21 15:32:13 -0500
committertdback <tyler@tdback.net>2024-12-21 15:32:13 -0500
commit0a5754541bb01e96021ca7ee74f1256a8ee68bc4 (patch)
tree2d0b8089e98239963a1e240cff676b1515fc8431
initial commit to self-hosted git
-rw-r--r--LICENSE21
-rw-r--r--README.md24
-rw-r--r--flake.lock148
-rw-r--r--flake.nix78
-rw-r--r--hosts/eden/default.nix52
-rw-r--r--hosts/eden/hardware.nix38
-rw-r--r--hosts/hive/default.nix44
-rw-r--r--hosts/hive/hardware.nix39
-rw-r--r--hosts/oasis/default.nix51
-rw-r--r--hosts/oasis/hardware.nix39
-rw-r--r--hosts/raindog/default.nix44
-rw-r--r--hosts/raindog/hardware.nix38
-rw-r--r--hosts/sparrow/default.nix43
-rw-r--r--hosts/sparrow/hardware.nix41
-rw-r--r--hosts/woodpecker/default.nix39
-rw-r--r--hosts/woodpecker/hardware.nix44
-rw-r--r--modules/containers/freshrss/default.nix30
-rw-r--r--modules/containers/jellyfin/default.nix27
-rw-r--r--modules/containers/pinchflat/default.nix23
-rw-r--r--modules/containers/vaultwarden/default.nix34
-rw-r--r--modules/containers/watchtower/default.nix15
-rw-r--r--modules/customs/cgit/default.nix134
-rw-r--r--modules/customs/soft-serve/default.nix60
-rw-r--r--modules/default.nix26
-rw-r--r--modules/profiles/common/default.nix46
-rw-r--r--modules/profiles/fstrim/default.nix7
-rw-r--r--modules/profiles/libvirtd/default.nix21
-rw-r--r--modules/profiles/nvidia/default.nix16
-rw-r--r--modules/profiles/pipewire/default.nix13
-rw-r--r--modules/profiles/podman/default.nix12
-rw-r--r--modules/profiles/security/default.nix16
-rw-r--r--modules/profiles/share/default.nix11
-rw-r--r--modules/profiles/steam/default.nix8
-rw-r--r--modules/profiles/upgrade/default.nix30
-rw-r--r--modules/profiles/vpn/default.nix18
-rw-r--r--modules/profiles/wireguard/default.nix15
-rw-r--r--modules/profiles/wireshark/default.nix14
-rw-r--r--modules/profiles/x11/default.nix33
-rw-r--r--modules/profiles/zfs/default.nix28
-rw-r--r--modules/retired/forgejo/default.nix65
-rw-r--r--modules/retired/kavita/default.nix28
-rw-r--r--modules/retired/mealie/default.nix22
-rw-r--r--modules/retired/mumble/default.nix11
-rw-r--r--modules/retired/navidrome/default.nix31
-rw-r--r--modules/retired/pihole/default.nix52
-rw-r--r--modules/retired/stirling-pdf/default.nix23
-rw-r--r--modules/retired/xonotic/default.nix25
-rw-r--r--modules/scripts/motd/default.nix99
-rw-r--r--modules/scripts/pushover/default.nix47
-rw-r--r--modules/services/blocky/default.nix93
-rw-r--r--modules/services/cgit/default.nix28
-rw-r--r--modules/services/fediverse/default.nix26
-rw-r--r--modules/services/immich/default.nix18
-rw-r--r--modules/services/proxy/default.nix9
-rw-r--r--modules/services/searx/default.nix33
-rw-r--r--modules/services/sftpgo/default.nix21
-rw-r--r--modules/services/ssh/default.nix17
-rw-r--r--modules/services/web/default.nix10
-rw-r--r--modules/users/default.nix15
-rw-r--r--secrets/pushoverAppToken.age13
-rw-r--r--secrets/pushoverUserToken.agebin0 -> 683 bytes
-rw-r--r--secrets/secrets.nix19
-rw-r--r--users/default.nix3
-rw-r--r--users/tdback/default.nix32
-rw-r--r--users/tdback/desktop.nix70
-rw-r--r--users/tdback/modules/alacritty/default.nix71
-rw-r--r--users/tdback/modules/dunst/default.nix30
-rw-r--r--users/tdback/modules/email/default.nix78
-rw-r--r--users/tdback/modules/firefox/default.nix101
-rw-r--r--users/tdback/modules/git/default.nix9
-rw-r--r--users/tdback/modules/irc/default.nix30
-rw-r--r--users/tdback/modules/mpd/default.nix34
-rw-r--r--users/tdback/modules/ncmpcpp/default.nix65
-rw-r--r--users/tdback/modules/neomutt/default.nix69
-rw-r--r--users/tdback/modules/polybar/default.nix112
-rw-r--r--users/tdback/modules/rofi/default.nix81
-rw-r--r--users/tdback/modules/shell/default.nix59
-rw-r--r--users/tdback/modules/tmux/default.nix52
-rw-r--r--users/tdback/modules/x11/default.nix94
79 files changed, 3115 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f177f32
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Tyler Dunneback
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4fc6aab
--- /dev/null
+++ b/README.md
@@ -0,0 +1,24 @@
+# Flake Layout
+- `hosts/`
+ - `eden/` - my media server and makeshift NAS. Media is stored in a RAID-Z2
+ ZFS pool for redundancy, with a caching drive for increased read performance.
+ - `hive/` - my "social" server, responsible for hosting my fediverse server
+ and a few websites.
+ - `oasis/` - my SFTP and git forge server.
+ - `raindog/` - my DNS server and SearXNG host. The name is inspired by one of
+ my beautiful dogs, Rainey.
+ - `sparrow/` - my laptop.
+ - `woodpecker/` - my desktop.
+- `modules/`
+ - `containers/` - podman/docker container configurations.
+ - `customs/` - custom modules or overrides for existing modules in nixpkgs.
+ - `profiles/` - configurations intended to be imported into a given system.
+ - `retired/` - modules or configurations I don't use anymore, but want to
+ keep around for reference.
+ - `scripts/` - custom shell scripts wrapped in nix (primarily for servers).
+ - `services/` - service/daemon configurations.
+ - `users/` - default user configuration for my systems.
+- `secrets/` - [age](https://github.com/FiloSottile/age) encrypted secrets, via
+ [agenix](https://github.com/ryantm/agenix)
+- `users/` - [home-manager](https://github.com/nix-community/home-manager)
+ configuration per user.
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..b5ffc9d
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,148 @@
+{
+ "nodes": {
+ "agenix": {
+ "inputs": {
+ "darwin": "darwin",
+ "home-manager": "home-manager",
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1723293904,
+ "narHash": "sha256-b+uqzj+Wa6xgMS9aNbX4I+sXeb5biPDi39VgvSFqFvU=",
+ "owner": "ryantm",
+ "repo": "agenix",
+ "rev": "f6291c5935fdc4e0bef208cfc0dcab7e3f7a1c41",
+ "type": "github"
+ },
+ "original": {
+ "owner": "ryantm",
+ "repo": "agenix",
+ "type": "github"
+ }
+ },
+ "darwin": {
+ "inputs": {
+ "nixpkgs": [
+ "agenix",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1700795494,
+ "narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=",
+ "owner": "lnl7",
+ "repo": "nix-darwin",
+ "rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d",
+ "type": "github"
+ },
+ "original": {
+ "owner": "lnl7",
+ "ref": "master",
+ "repo": "nix-darwin",
+ "type": "github"
+ }
+ },
+ "home-manager": {
+ "inputs": {
+ "nixpkgs": [
+ "agenix",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1703113217,
+ "narHash": "sha256-7ulcXOk63TIT2lVDSExj7XzFx09LpdSAPtvgtM7yQPE=",
+ "owner": "nix-community",
+ "repo": "home-manager",
+ "rev": "3bfaacf46133c037bb356193bd2f1765d9dc82c1",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "home-manager",
+ "type": "github"
+ }
+ },
+ "home-manager_2": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1733050161,
+ "narHash": "sha256-lYnT+EYE47f5yY3KS/Kd4pJ6CO9fhCqumkYYkQ3TK20=",
+ "owner": "nix-community",
+ "repo": "home-manager",
+ "rev": "62d536255879be574ebfe9b87c4ac194febf47c5",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "ref": "release-24.11",
+ "repo": "home-manager",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1733120037,
+ "narHash": "sha256-En+gSoVJ3iQKPDU1FHrR6zIxSLXKjzKY+pnh9tt+Yts=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "f9f0d5c5380be0a599b1fb54641fa99af8281539",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-24.11",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs-unstable": {
+ "locked": {
+ "lastModified": 1733212471,
+ "narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "agenix": "agenix",
+ "home-manager": "home-manager_2",
+ "nixpkgs": "nixpkgs",
+ "nixpkgs-unstable": "nixpkgs-unstable"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..30d31b3
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,78 @@
+{
+ inputs = {
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
+ nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
+ home-manager = {
+ url = "github:nix-community/home-manager/release-24.11";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+ agenix = {
+ url = "github:ryantm/agenix";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+ };
+
+ outputs = { ... }@inputs:
+ let
+ helpers = import ./modules { inherit inputs; };
+ inherit (helpers) mergeSets makeSystem;
+ in
+ {
+ nixosConfigurations = mergeSets [
+ (makeSystem "woodpecker" inputs.nixpkgs [
+ {
+ type = "profiles";
+ modules = [ "common" "fstrim" "libvirtd" "nvidia" "pipewire" "security" "steam" "wireshark" "x11" ];
+ }
+ ])
+ (makeSystem "sparrow" inputs.nixpkgs [
+ {
+ type = "profiles";
+ modules = [ "common" "pipewire" "security" "vpn" "x11" ];
+ }
+ ])
+ (makeSystem "raindog" inputs.nixpkgs [
+ {
+ type = "profiles";
+ modules = [ "common" "security" "upgrade" ];
+ }
+ { type = "scripts"; modules = [ "motd" "pushover" ]; }
+ { type = "services"; modules = [ "blocky" "searx" "ssh" ]; }
+ ])
+ (makeSystem "oasis" inputs.nixpkgs [
+ {
+ type = "profiles";
+ modules = [ "common" "podman" "security" "upgrade" "wireguard" "zfs" ];
+ }
+ { type = "scripts"; modules = [ "motd" "pushover" ]; }
+ {
+ type = "services";
+ modules = [ "cgit" "proxy" "sftpgo" "ssh" ];
+ }
+ ])
+ (makeSystem "hive" inputs.nixpkgs [
+ {
+ type = "profiles";
+ modules = [ "common" "security" "upgrade" "wireguard" ];
+ }
+ { type = "scripts"; modules = [ "motd" "pushover" ]; }
+ {
+ type = "services";
+ modules = [ "fediverse" "proxy" "ssh" "web" ];
+ }
+ ])
+ (makeSystem "eden" inputs.nixpkgs [
+ {
+ type = "containers";
+ modules = [ "freshrss" "jellyfin" "pinchflat" "vaultwarden" "watchtower" ];
+ }
+ {
+ type = "profiles";
+ modules = [ "common" "podman" "security" "share" "upgrade" "wireguard" "zfs" ];
+ }
+ { type = "scripts"; modules = [ "motd" "pushover" ]; }
+ { type = "services"; modules = [ "immich" "proxy" "ssh" ]; }
+ ])
+ ];
+ };
+}
diff --git a/hosts/eden/default.nix b/hosts/eden/default.nix
new file mode 100644
index 0000000..02be58f
--- /dev/null
+++ b/hosts/eden/default.nix
@@ -0,0 +1,52 @@
+{ lib, inputs, ... }:
+{
+ system.stateVersion = "24.05";
+
+ imports = [ ./hardware.nix ];
+
+ home-manager = {
+ useGlobalPkgs = true;
+ useUserPackages = true;
+ users = import "${inputs.self}/users";
+ extraSpecialArgs = {
+ inherit inputs;
+ headless = true;
+ };
+ };
+
+ networking = {
+ hostName = "eden";
+ hostId = "bd03847d"; # Required for ZFS support.
+ nameservers = [ "10.44.0.1" ];
+ defaultGateway.address = "10.44.0.1";
+ interfaces.eno1 = {
+ useDHCP = false;
+ ipv4.addresses = [{
+ address = "10.44.4.101";
+ prefixLength = 16;
+ }];
+ };
+ };
+
+ time.timeZone = "America/Detroit";
+
+ boot = {
+ loader = {
+ systemd-boot.enable = true;
+ efi.canTouchEfiVariables = true;
+ };
+ zfs.extraPools = [ "lagoon" ];
+ };
+
+ motd = {
+ networkInterfaces = lib.lists.singleton "eno1";
+ servicesToCheck = [
+ "caddy"
+ "immich-machine-learning"
+ "immich-server"
+ "postgresql"
+ "redis-immich"
+ "zfs-zed"
+ ];
+ };
+}
diff --git a/hosts/eden/hardware.nix b/hosts/eden/hardware.nix
new file mode 100644
index 0000000..00210c4
--- /dev/null
+++ b/hosts/eden/hardware.nix
@@ -0,0 +1,38 @@
+# Do not modify this file! It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations. Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, modulesPath, ... }:
+
+{
+ imports =
+ [ (modulesPath + "/installer/scan/not-detected.nix")
+ ];
+
+ boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" "sr_mod" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ "kvm-intel" ];
+ boot.extraModulePackages = [ ];
+
+ fileSystems."/" =
+ { device = "/dev/disk/by-uuid/f3bedccb-3f2b-49ae-9be4-5ec9fe683027";
+ fsType = "ext4";
+ };
+
+ fileSystems."/boot" =
+ { device = "/dev/disk/by-uuid/78C3-E7F8";
+ fsType = "vfat";
+ options = [ "fmask=0022" "dmask=0022" ];
+ };
+
+ swapDevices = [ ];
+
+ # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
+ # (the default) this is the recommended approach. When using systemd-networkd it's
+ # still possible to use this option, but it's recommended to use it in conjunction
+ # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
+ networking.useDHCP = lib.mkDefault true;
+ # networking.interfaces.eno1.useDHCP = lib.mkDefault true;
+
+ nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
+ hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+}
diff --git a/hosts/hive/default.nix b/hosts/hive/default.nix
new file mode 100644
index 0000000..c164b92
--- /dev/null
+++ b/hosts/hive/default.nix
@@ -0,0 +1,44 @@
+{ lib, inputs, ... }:
+{
+ system.stateVersion = "24.05";
+
+ imports = [ ./hardware.nix ];
+
+ home-manager = {
+ useGlobalPkgs = true;
+ useUserPackages = true;
+ users = import "${inputs.self}/users";
+ extraSpecialArgs = {
+ inherit inputs;
+ headless = true;
+ };
+ };
+
+ networking = {
+ hostName = "hive";
+ nameservers = [ "10.44.0.1" ];
+ defaultGateway.address = "10.44.0.1";
+ interfaces.eno1 = {
+ useDHCP = false;
+ ipv4.addresses = [{
+ address = "10.44.4.102";
+ prefixLength = 16;
+ }];
+ };
+ };
+
+ time.timeZone = "America/Detroit";
+
+ boot.loader = {
+ systemd-boot.enable = true;
+ efi.canTouchEfiVariables = true;
+ };
+
+ motd = {
+ networkInterfaces = lib.lists.singleton "eno1";
+ servicesToCheck = [
+ "caddy"
+ "gotosocial"
+ ];
+ };
+}
diff --git a/hosts/hive/hardware.nix b/hosts/hive/hardware.nix
new file mode 100644
index 0000000..9e7a2f0
--- /dev/null
+++ b/hosts/hive/hardware.nix
@@ -0,0 +1,39 @@
+# Do not modify this file! It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations. Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, modulesPath, ... }:
+
+{
+ imports =
+ [ (modulesPath + "/installer/scan/not-detected.nix")
+ ];
+
+ boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "ehci_pci" "usb_storage" "usbhid" "sd_mod" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ "kvm-amd" ];
+ boot.extraModulePackages = [ ];
+
+ fileSystems."/" =
+ { device = "/dev/disk/by-uuid/e336b96d-b3b4-4098-a0ca-9001fd381f88";
+ fsType = "ext4";
+ };
+
+ fileSystems."/boot" =
+ { device = "/dev/disk/by-uuid/F804-40A9";
+ fsType = "vfat";
+ options = [ "fmask=0022" "dmask=0022" ];
+ };
+
+ swapDevices = [ ];
+
+ # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
+ # (the default) this is the recommended approach. When using systemd-networkd it's
+ # still possible to use this option, but it's recommended to use it in conjunction
+ # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
+ networking.useDHCP = lib.mkDefault true;
+ # networking.interfaces.eno1.useDHCP = lib.mkDefault true;
+ # networking.interfaces.wlp6s0.useDHCP = lib.mkDefault true;
+
+ nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
+ hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+}
diff --git a/hosts/oasis/default.nix b/hosts/oasis/default.nix
new file mode 100644
index 0000000..8ef44f9
--- /dev/null
+++ b/hosts/oasis/default.nix
@@ -0,0 +1,51 @@
+{ lib, inputs, ... }:
+{
+ system.stateVersion = "24.05";
+
+ imports = [ ./hardware.nix ];
+
+ home-manager = {
+ useGlobalPkgs = true;
+ useUserPackages = true;
+ users = import "${inputs.self}/users";
+ extraSpecialArgs = {
+ inherit inputs;
+ headless = true;
+ };
+ };
+
+ networking = {
+ hostName = "oasis";
+ hostId = "7a7d723a"; # Required for ZFS support.
+ nameservers = [ "10.44.0.1" ];
+ defaultGateway.address = "10.44.0.1";
+ interfaces.enp59s0 = {
+ useDHCP = false;
+ ipv4.addresses = [{
+ address = "10.44.4.103";
+ prefixLength = 16;
+ }];
+ };
+ };
+
+ time.timeZone = "America/Detroit";
+
+ boot = {
+ loader = {
+ systemd-boot.enable = true;
+ efi.canTouchEfiVariables = true;
+ };
+ zfs.extraPools = [ "tank" ];
+ };
+
+ motd = {
+ networkInterfaces = lib.lists.singleton "enp59s0";
+ servicesToCheck = [
+ "caddy"
+ "sftpgo"
+ "zfs-zed"
+ ];
+ };
+
+ services.sftpgo.dataDir = "/tank/sftpgo";
+}
diff --git a/hosts/oasis/hardware.nix b/hosts/oasis/hardware.nix
new file mode 100644
index 0000000..3870379
--- /dev/null
+++ b/hosts/oasis/hardware.nix
@@ -0,0 +1,39 @@
+# Do not modify this file! It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations. Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, modulesPath, ... }:
+
+{
+ imports =
+ [ (modulesPath + "/installer/scan/not-detected.nix")
+ ];
+
+ boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "sd_mod" "sdhci_pci" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ "kvm-intel" ];
+ boot.extraModulePackages = [ ];
+
+ fileSystems."/" =
+ { device = "/dev/disk/by-uuid/3e333010-7dae-47cf-9288-85d58ddda699";
+ fsType = "ext4";
+ };
+
+ fileSystems."/boot" =
+ { device = "/dev/disk/by-uuid/8430-1FF8";
+ fsType = "vfat";
+ options = [ "fmask=0022" "dmask=0022" ];
+ };
+
+ swapDevices = [ ];
+
+ # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
+ # (the default) this is the recommended approach. When using systemd-networkd it's
+ # still possible to use this option, but it's recommended to use it in conjunction
+ # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
+ networking.useDHCP = lib.mkDefault true;
+ # networking.interfaces.enp59s0.useDHCP = lib.mkDefault true;
+ # networking.interfaces.wlo1.useDHCP = lib.mkDefault true;
+
+ nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
+ hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+}
diff --git a/hosts/raindog/default.nix b/hosts/raindog/default.nix
new file mode 100644
index 0000000..0eb2d30
--- /dev/null
+++ b/hosts/raindog/default.nix
@@ -0,0 +1,44 @@
+{ lib, inputs, ... }:
+{
+ system.stateVersion = "24.05";
+
+ imports = [ ./hardware.nix ];
+
+ home-manager = {
+ useGlobalPkgs = true;
+ useUserPackages = true;
+ users = import "${inputs.self}/users";
+ extraSpecialArgs = {
+ inherit inputs;
+ headless = true;
+ };
+ };
+
+ networking = {
+ hostName = "raindog";
+ nameservers = [ "10.44.0.1" ];
+ defaultGateway.address = "10.44.0.1";
+ interfaces.eno1 = {
+ useDHCP = false;
+ ipv4.addresses = [{
+ address = "10.44.4.100";
+ prefixLength = 16;
+ }];
+ };
+ };
+
+ time.timeZone = "America/Detroit";
+
+ boot.loader = {
+ systemd-boot.enable = true;
+ efi.canTouchEfiVariables = true;
+ };
+
+ motd = {
+ networkInterfaces = lib.lists.singleton "eno1";
+ servicesToCheck = [
+ "blocky"
+ "searx"
+ ];
+ };
+}
diff --git a/hosts/raindog/hardware.nix b/hosts/raindog/hardware.nix
new file mode 100644
index 0000000..b2a5571
--- /dev/null
+++ b/hosts/raindog/hardware.nix
@@ -0,0 +1,38 @@
+# Do not modify this file! It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations. Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, modulesPath, ... }:
+
+{
+ imports =
+ [ (modulesPath + "/installer/scan/not-detected.nix")
+ ];
+
+ boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "sd_mod" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ "kvm-intel" ];
+ boot.extraModulePackages = [ ];
+
+ fileSystems."/" =
+ { device = "/dev/disk/by-uuid/d62103eb-e154-4b71-b813-54ca76815a80";
+ fsType = "ext4";
+ };
+
+ fileSystems."/boot" =
+ { device = "/dev/disk/by-uuid/5972-1878";
+ fsType = "vfat";
+ options = [ "fmask=0022" "dmask=0022" ];
+ };
+
+ swapDevices = [ ];
+
+ # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
+ # (the default) this is the recommended approach. When using systemd-networkd it's
+ # still possible to use this option, but it's recommended to use it in conjunction
+ # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
+ networking.useDHCP = lib.mkDefault true;
+ # networking.interfaces.eno1.useDHCP = lib.mkDefault true;
+
+ nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
+ hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+}
diff --git a/hosts/sparrow/default.nix b/hosts/sparrow/default.nix
new file mode 100644
index 0000000..824f5df
--- /dev/null
+++ b/hosts/sparrow/default.nix
@@ -0,0 +1,43 @@
+{ inputs, pkgs, ... }:
+{
+ system.stateVersion = "24.05";
+
+ imports = [ ./hardware.nix ];
+
+ home-manager = {
+ useGlobalPkgs = true;
+ useUserPackages = true;
+ users = import "${inputs.self}/users";
+ extraSpecialArgs = {
+ inherit inputs;
+ headless = false;
+ };
+ };
+
+ networking = {
+ hostName = "sparrow";
+ networkmanager.enable = true;
+ };
+
+ time.timeZone = "America/Detroit";
+
+ boot = {
+ loader = {
+ systemd-boot.enable = true;
+ efi.canTouchEfiVariables = true;
+ };
+ binfmt.emulatedSystems = [ "aarch64-linux" "riscv64-linux" ];
+ };
+
+ # Since I don't always carry my split keyboard, remap CAPS to left CTRL.
+ console.useXkbConfig = true;
+ services = {
+ xserver.xkb.options = "ctrl:swapcaps";
+ libinput.enable = true;
+ };
+
+ environment.systemPackages = with pkgs; [
+ acpi
+ unstable.qbittorrent
+ ];
+}
diff --git a/hosts/sparrow/hardware.nix b/hosts/sparrow/hardware.nix
new file mode 100644
index 0000000..d40b232
--- /dev/null
+++ b/hosts/sparrow/hardware.nix
@@ -0,0 +1,41 @@
+# Do not modify this file! It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations. Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, modulesPath, ... }:
+
+{
+ imports =
+ [ (modulesPath + "/installer/scan/not-detected.nix")
+ ];
+
+ boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "sd_mod" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ "kvm-intel" ];
+ boot.extraModulePackages = [ ];
+
+ fileSystems."/" =
+ { device = "/dev/disk/by-uuid/d296f7a3-68d2-406f-963d-8ec39ab0ea64";
+ fsType = "ext4";
+ };
+
+ fileSystems."/boot" =
+ { device = "/dev/disk/by-uuid/B159-723B";
+ fsType = "vfat";
+ options = [ "fmask=0022" "dmask=0022" ];
+ };
+
+ swapDevices = [{
+ device = "/.swapfile";
+ }];
+
+ # 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.<interface>.useDHCP`.
+ networking.useDHCP = lib.mkDefault true;
+ # networking.interfaces.enp0s31f6.useDHCP = lib.mkDefault true;
+ # networking.interfaces.wlp59s0.useDHCP = lib.mkDefault true;
+
+ nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
+ hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+}
diff --git a/hosts/woodpecker/default.nix b/hosts/woodpecker/default.nix
new file mode 100644
index 0000000..4f1dc2f
--- /dev/null
+++ b/hosts/woodpecker/default.nix
@@ -0,0 +1,39 @@
+{ inputs, ... }:
+{
+ system.stateVersion = "24.05";
+
+ imports = [ ./hardware.nix ];
+
+ home-manager = {
+ useGlobalPkgs = true;
+ useUserPackages = true;
+ users = import "${inputs.self}/users";
+ extraSpecialArgs = {
+ inherit inputs;
+ headless = false;
+ };
+ };
+
+ networking = {
+ hostName = "woodpecker";
+ nameservers = [ "10.44.0.1" ];
+ defaultGateway.address = "10.44.0.1";
+ interfaces.enp42s0 = {
+ useDHCP = false;
+ ipv4.addresses = [{
+ address = "10.44.4.50";
+ prefixLength = 16;
+ }];
+ };
+ };
+
+ time.timeZone = "America/Detroit";
+
+ boot = {
+ loader = {
+ systemd-boot.enable = true;
+ efi.canTouchEfiVariables = true;
+ };
+ binfmt.emulatedSystems = [ "aarch64-linux" "riscv64-linux" ];
+ };
+}
diff --git a/hosts/woodpecker/hardware.nix b/hosts/woodpecker/hardware.nix
new file mode 100644
index 0000000..3fc71e9
--- /dev/null
+++ b/hosts/woodpecker/hardware.nix
@@ -0,0 +1,44 @@
+# Do not modify this file! It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations. Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, modulesPath, ... }:
+
+{
+ imports =
+ [ (modulesPath + "/installer/scan/not-detected.nix")
+ ];
+
+ boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ "kvm-amd" ];
+ boot.extraModulePackages = [ ];
+
+ fileSystems."/" =
+ { device = "/dev/disk/by-uuid/90ec7fc1-192e-4bb5-9bb5-5e2776435f8d";
+ fsType = "ext4";
+ };
+
+ fileSystems."/boot" =
+ { device = "/dev/disk/by-uuid/3A26-C3FB";
+ fsType = "vfat";
+ options = [ "fmask=0022" "dmask=0022" ];
+ };
+
+ fileSystems."/home" =
+ { device = "/dev/disk/by-uuid/cd7e081e-cd0b-4dc5-b41c-8dda26437a78";
+ fsType = "ext4";
+ };
+
+ swapDevices = [ ];
+
+ # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
+ # (the default) this is the recommended approach. When using systemd-networkd it's
+ # still possible to use this option, but it's recommended to use it in conjunction
+ # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
+ networking.useDHCP = lib.mkDefault true;
+ # networking.interfaces.enp42s0.useDHCP = lib.mkDefault true;
+ # networking.interfaces.enp5s0.useDHCP = lib.mkDefault true;
+
+ nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
+ hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
+}
diff --git a/modules/containers/freshrss/default.nix b/modules/containers/freshrss/default.nix
new file mode 100644
index 0000000..3854a8e
--- /dev/null
+++ b/modules/containers/freshrss/default.nix
@@ -0,0 +1,30 @@
+{ lib, ... }:
+let
+ directory = "/opt/freshrss";
+ port = "8888";
+in
+{
+ systemd.tmpfiles.rules =
+ map (x: "d ${x} 0755 share share - -") (lib.lists.singleton directory);
+
+ virtualisation.oci-containers.containers.freshrss = {
+ image = "freshrss/freshrss:latest";
+ autoStart = true;
+ ports = [
+ "${port}:80"
+ ];
+ volumes = [
+ "${directory}/data:/var/www/FreshRSS/data"
+ "${directory}/extensions:/var/www/FreshRSS/extensions"
+ ];
+ environment = {
+ TZ = "America/Detroit";
+ CRON_MIN = "*/20";
+ };
+ };
+
+ services.caddy.virtualHosts."fresh.brownbread.net".extraConfig = ''
+ encode zstd gzip
+ reverse_proxy http://localhost:${port}
+ '';
+}
diff --git a/modules/containers/jellyfin/default.nix b/modules/containers/jellyfin/default.nix
new file mode 100644
index 0000000..96b6deb
--- /dev/null
+++ b/modules/containers/jellyfin/default.nix
@@ -0,0 +1,27 @@
+{ lib, ... }:
+let
+ directory = "/opt/jellyfin";
+in
+{
+ systemd.tmpfiles.rules =
+ map (x: "d ${x} 0755 share share - -") (lib.lists.singleton directory);
+
+ virtualisation.oci-containers.containers.jellyfin = {
+ image = "jellyfin/jellyfin:latest";
+ autoStart = true;
+ user = "994:994";
+ ports = [
+ "8096:8096/tcp"
+ ];
+ volumes = [
+ "${directory}/config:/config"
+ "${directory}/cache:/cache"
+ "/lagoon/media:/media"
+ ];
+ };
+
+ services.caddy.virtualHosts."buttered.brownbread.net".extraConfig = ''
+ encode zstd gzip
+ reverse_proxy http://localhost:8096
+ '';
+}
diff --git a/modules/containers/pinchflat/default.nix b/modules/containers/pinchflat/default.nix
new file mode 100644
index 0000000..9428c32
--- /dev/null
+++ b/modules/containers/pinchflat/default.nix
@@ -0,0 +1,23 @@
+{ ... }:
+let
+ directories = [
+ "/opt/pinchflat"
+ ];
+in
+{
+ systemd.tmpfiles.rules = map (x: "d ${x} 0755 share share - -") directories;
+ virtualisation.oci-containers.containers.pinchflat = {
+ image = "keglin/pinchflat:latest";
+ autoStart = true;
+ ports = [
+ "8945:8945"
+ ];
+ volumes = [
+ "/opt/pinchflat:/config"
+ "/lagoon/media/yt:/downloads"
+ ];
+ environment = {
+ TZ = "America/Detroit";
+ };
+ };
+}
diff --git a/modules/containers/vaultwarden/default.nix b/modules/containers/vaultwarden/default.nix
new file mode 100644
index 0000000..cc6b86f
--- /dev/null
+++ b/modules/containers/vaultwarden/default.nix
@@ -0,0 +1,34 @@
+{ lib, ... }:
+let
+ directory = "/opt/vaultwarden";
+ domain = "steel-mountain.brownbread.net";
+ port = "11001";
+in
+{
+ systemd.tmpfiles.rules =
+ map (x: "d ${x} 0755 share share - -") (lib.lists.singleton directory);
+
+ virtualisation.oci-containers.containers.vaultwarden = {
+ image = "vaultwarden/server:latest";
+ autoStart = true;
+ ports = [
+ "${port}:80"
+ ];
+ volumes = [
+ "${directory}/data:/data"
+ ];
+ environment = {
+ DOMAIN = domain;
+ WEBSOCKET_ENABLED = "true";
+ SIGNUPS_ALLOWED = "false";
+ SHOW_PASSWORD_HINT = "false";
+ };
+ };
+
+ services.caddy.virtualHosts.${domain}.extraConfig = ''
+ encode zstd gzip
+ reverse_proxy http://localhost:${port} {
+ header_up X-Real-IP {remote_host}
+ }
+ '';
+}
diff --git a/modules/containers/watchtower/default.nix b/modules/containers/watchtower/default.nix
new file mode 100644
index 0000000..bc819cd
--- /dev/null
+++ b/modules/containers/watchtower/default.nix
@@ -0,0 +1,15 @@
+{ ... }:
+{
+ virtualisation.oci-containers.containers.watchtower = {
+ image = "containrrr/watchtower:latest";
+ autoStart = true;
+ volumes = [
+ "/var/run/podman/podman.sock:/var/run/docker.sock:ro"
+ "/etc/localtime:/etc/localtime:ro"
+ ];
+ environment = {
+ WATCHTOWER_CLEANUP = "true";
+ WATCHTOWER_SCHEDULE = "0 0 5 * * *";
+ };
+ };
+}
diff --git a/modules/customs/cgit/default.nix b/modules/customs/cgit/default.nix
new file mode 100644
index 0000000..19eac01
--- /dev/null
+++ b/modules/customs/cgit/default.nix
@@ -0,0 +1,134 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+ cfg = config.services.cgit;
+
+ mkCgitrc = cfg:
+ pkgs.writeText "cgitrc" (let
+ cgitConfig = {
+ css = "/cgit.css";
+ logo = "/cgit.png";
+ favicon = "/favicon.ico";
+ about-filter = "${cfg.package}/lib/cgit/filters/about-formatting.sh";
+ source-filter = "${cfg.package}/lib/cgit/filters/syntax-highlighting.py";
+ enable-git-config = 1;
+ # Disable cgit's HTTP "dumb" protocol and use git itself to provide the
+ # HTTP "smart" protocol instead.
+ enable-http-clone = 0;
+ remove-suffix = 1;
+ clone-url = "https://${cfg.virtualHost}/$CGIT_REPO_URL.git";
+ scan-path = cfg.scanPath;
+ };
+ in
+ generators.toKeyValue { } (cfg.settings // cgitConfig)
+ );
+
+ mkCgitAssets = pkg: files:
+ builtins.map (f: ''
+ handle_path /${f} {
+ root * ${pkg}/cgit/${f}
+ file_server
+ }
+ '') files |> strings.concatStringsSep "\n";
+in
+{
+ disabledModules = [ "services/networking/cgit.nix" ];
+
+ options = {
+ services.cgit = {
+ enable = mkEnableOption "cgit";
+ package = mkPackageOption pkgs "cgit" { };
+ user = mkOption {
+ description = "User to run cgit service as";
+ type = types.str;
+ default = "git";
+ };
+ group = mkOption {
+ description = "Group to run cgit service as";
+ type = types.str;
+ default = "git";
+ };
+ scanPath = mkOption {
+ description = "A path which will be scanned for repositories";
+ type = types.path;
+ default = "/var/lib/cgit";
+ };
+ virtualHost = mkOption {
+ description = "Virtual host to serve cgit on";
+ type = types.str;
+ default = null;
+ };
+ authorizedKeys = mkOption {
+ description = "SSH keys for authorized git users";
+ type = types.listOf types.str;
+ default = [ ];
+ };
+ settings = mkOption {
+ description = "Additional cgit configuration. see cgitrc(5)";
+ type = with types; let settingType = oneOf [ bool int str ]; in
+ attrsOf (oneOf [
+ settingType
+ (listOf settingType)
+ ]);
+ default = { };
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ programs.git = {
+ enable = true;
+ config.init.defaultBranch = "main";
+ };
+
+ # Setup git user with git-shell for authenticated pushes.
+ users.users.${cfg.user} = {
+ isSystemUser = true;
+ home = cfg.scanPath;
+ group = cfg.group;
+ shell = "${pkgs.git}/bin/git-shell";
+ openssh.authorizedKeys.keys = cfg.authorizedKeys;
+ };
+
+ users.groups.${cfg.group} = {};
+
+ # Harden git user to prevent SSH port forwarding to other servers.
+ services.openssh = {
+ enable = true;
+ settings.AllowUsers = [ cfg.user ];
+ extraConfig = ''
+ Match user ${cfg.user}
+ AllowTCPForwarding no
+ AllowAgentForwarding no
+ PasswordAuthentication no
+ PermitTTY no
+ X11Forwarding no
+ '';
+ };
+
+ # Configure fcgiwrap instance for caddy to properly serve cgi scripts.
+ # Reference: https://github.com/NixOS/nixpkgs/blob/nixos-24.11/nixos/modules/services/networking/cgit.nix
+ services.fcgiwrap.instances.cgit = {
+ process = { inherit (cfg) user group; };
+ socket = { inherit (config.services.caddy) user group; };
+ };
+
+ services.caddy.virtualHosts.${cfg.virtualHost}.extraConfig =
+ let
+ socket = config.services.fcgiwrap.instances.cgit.socket.address;
+ in ''
+ encode zstd gzip
+
+ reverse_proxy unix/${socket} {
+ transport fastcgi {
+ env SCRIPT_FILENAME ${cfg.package}/cgit/cgit.cgi
+ env CGIT_CONFIG ${mkCgitrc cfg}
+ }
+ }
+
+ ${mkCgitAssets cfg.package [
+ "cgit.css" "cgit.png" "favicon.ico" "robots.txt"
+ ]}
+ '';
+ };
+}
diff --git a/modules/customs/soft-serve/default.nix b/modules/customs/soft-serve/default.nix
new file mode 100644
index 0000000..05156fd
--- /dev/null
+++ b/modules/customs/soft-serve/default.nix
@@ -0,0 +1,60 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+ cfg = config.services.soft-serve;
+ cfgFile = format.generate "config.yaml" cfg.settings;
+ format = pkgs.formats.yaml { };
+ dataDir = cfg.dataDir;
+ docUrl = "https://github.com/charmbracelet/soft-serve";
+in
+{
+ disabledModules = [ "services/misc/soft-serve.nix" ];
+
+ options = {
+ services.soft-serve = {
+ enable = mkEnableOption "soft-serve";
+ package = mkPackageOption pkgs "soft-serve" { };
+ dataDir = mkOption {
+ type = types.str;
+ default = "/var/lib/soft-serve";
+ description = ''
+ The directory where soft-serve stores its data files.
+ '';
+ };
+ settings = mkOption {
+ type = format.type;
+ default = { };
+ description = ''
+ soft-serve server configurations stored under your data directory.
+ See <${docUrl}>.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ systemd.tmpfiles.rules = [
+ "L+ ${dataDir}/config.yaml - - - - ${cfgFile}"
+ ];
+
+ systemd.services.soft-serve = {
+ description = "Soft Serve git server";
+ documentation = lists.singleton docUrl;
+ requires = lists.singleton "network-online.target";
+ after = lists.singleton "network-online.target";
+ wantedBy = lists.singleton "multi-user.target";
+ environment.SOFT_SERVE_DATA_PATH = dataDir;
+ serviceConfig = {
+ Type = "simple";
+ Restart = "always";
+ RestartSec = 1;
+ ExecStart = "${getExe cfg.package} serve";
+ WorkingDirectory = dataDir;
+ };
+ };
+
+ environment.systemPackages = with pkgs; [
+ git
+ ];
+ };
+}
diff --git a/modules/default.nix b/modules/default.nix
new file mode 100644
index 0000000..4930139
--- /dev/null
+++ b/modules/default.nix
@@ -0,0 +1,26 @@
+{ inputs }:
+let
+ genModules = { type, modules }:
+ builtins.map (module: "${inputs.self}/modules/${type}/${module}") modules;
+
+ makeModules = moduleAttrList:
+ builtins.concatMap (moduleAttr: genModules moduleAttr) moduleAttrList;
+in
+{
+ makeSystem = hostname: nixpkgsVersion: modules: {
+ ${hostname} = nixpkgsVersion.lib.nixosSystem {
+ system = "x86_64-linux";
+ modules = (makeModules modules) ++ [
+ "${inputs.self}/hosts/${hostname}"
+ "${inputs.self}/modules/users"
+ inputs.home-manager.nixosModules.home-manager
+ inputs.agenix.nixosModules.default
+ ];
+ specialArgs = { inherit inputs; };
+ };
+ };
+
+ mergeSets = inputs.nixpkgs.lib.lists.foldl' (
+ x: y: inputs.nixpkgs.lib.attrsets.recursiveUpdate x y
+ ) { };
+}
diff --git a/modules/profiles/common/default.nix b/modules/profiles/common/default.nix
new file mode 100644
index 0000000..c25fece
--- /dev/null
+++ b/modules/profiles/common/default.nix
@@ -0,0 +1,46 @@
+{ inputs, lib, pkgs, ... }:
+{
+ nix = {
+ settings = {
+ trusted-users = [ "@wheel" "root" ];
+ experimental-features = lib.mkDefault [
+ "nix-command"
+ "flakes"
+ "pipe-operators"
+ ];
+ auto-optimise-store = true;
+ };
+ gc = {
+ automatic = true;
+ dates = "weekly";
+ options = "--delete-older-than 14d";
+ };
+ };
+
+ nixpkgs = {
+ config = {
+ allowUnfree = true;
+ allowUnfreePredicate = (_: true);
+ };
+ overlays = [
+ (final: prev: {
+ unstable = import inputs.nixpkgs-unstable {
+ system = final.system;
+ config.allowUnfree = true;
+ };
+ })
+ ];
+ };
+
+ programs = {
+ git.enable = true;
+ htop.enable = true;
+ neovim = {
+ enable = true;
+ package = pkgs.unstable.neovim-unwrapped;
+ viAlias = true;
+ vimAlias = true;
+ defaultEditor = true;
+ };
+ };
+}
diff --git a/modules/profiles/fstrim/default.nix b/modules/profiles/fstrim/default.nix
new file mode 100644
index 0000000..03da691
--- /dev/null
+++ b/modules/profiles/fstrim/default.nix
@@ -0,0 +1,7 @@
+{ ... }:
+{
+ services.fstrim = {
+ enable = true;
+ interval = "weekly";
+ };
+}
diff --git a/modules/profiles/libvirtd/default.nix b/modules/profiles/libvirtd/default.nix
new file mode 100644
index 0000000..fa617d1
--- /dev/null
+++ b/modules/profiles/libvirtd/default.nix
@@ -0,0 +1,21 @@
+{ config, ... }:
+{
+ virtualisation.libvirtd = {
+ enable = true;
+ qemu = {
+ ovmf.enable = true;
+ runAsRoot = false;
+ };
+ onBoot = "ignore";
+ onShutdown = "shutdown";
+ };
+
+ programs.virt-manager.enable = true;
+
+ # Add any users in the 'wheel' group to the 'libvirtd' group.
+ users.groups.libvirtd.members = let users = config.users.users; in
+ builtins.attrNames users
+ |> builtins.filter (
+ x: builtins.elem "wheel" users.${x}.extraGroups
+ );
+}
diff --git a/modules/profiles/nvidia/default.nix b/modules/profiles/nvidia/default.nix
new file mode 100644
index 0000000..50e0f6f
--- /dev/null
+++ b/modules/profiles/nvidia/default.nix
@@ -0,0 +1,16 @@
+{ config, ... }:
+{
+ hardware.nvidia = {
+ package = config.boot.kernelPackages.nvidiaPackages.stable;
+ open = false;
+ nvidiaSettings = true;
+ forceFullCompositionPipeline = true;
+ modesetting.enable = true;
+ powerManagement = {
+ enable = false;
+ finegrained = false;
+ };
+ };
+
+ services.xserver.videoDrivers = [ "nvidia" ];
+}
diff --git a/modules/profiles/pipewire/default.nix b/modules/profiles/pipewire/default.nix
new file mode 100644
index 0000000..ac70f08
--- /dev/null
+++ b/modules/profiles/pipewire/default.nix
@@ -0,0 +1,13 @@
+{ ... }:
+{
+ services.pipewire = {
+ enable = true;
+ alsa = {
+ enable = true;
+ support32Bit = true;
+ };
+ pulse.enable = true;
+ };
+
+ security.rtkit.enable = true;
+}
diff --git a/modules/profiles/podman/default.nix b/modules/profiles/podman/default.nix
new file mode 100644
index 0000000..1ec3406
--- /dev/null
+++ b/modules/profiles/podman/default.nix
@@ -0,0 +1,12 @@
+{ ... }:
+{
+ virtualisation = {
+ containers.enable = true;
+ oci-containers.backend = "podman";
+ podman = {
+ enable = true;
+ dockerCompat = true;
+ defaultNetwork.settings.dns_enabled = true;
+ };
+ };
+}
diff --git a/modules/profiles/security/default.nix b/modules/profiles/security/default.nix
new file mode 100644
index 0000000..47fe1a3
--- /dev/null
+++ b/modules/profiles/security/default.nix
@@ -0,0 +1,16 @@
+{ lib, ... }:
+{
+ security = {
+ polkit.enable = true;
+
+ sudo.enable = lib.mkDefault false;
+ doas = {
+ enable = lib.mkDefault true;
+ extraRules = [{
+ groups = [ "wheel" ];
+ keepEnv = true;
+ persist = true;
+ }];
+ };
+ };
+}
diff --git a/modules/profiles/share/default.nix b/modules/profiles/share/default.nix
new file mode 100644
index 0000000..c4ee4ff
--- /dev/null
+++ b/modules/profiles/share/default.nix
@@ -0,0 +1,11 @@
+{ ... }:
+{
+ users = {
+ users.share = {
+ uid = 994;
+ isSystemUser = true;
+ group = "share";
+ };
+ groups.share.gid = 994;
+ };
+}
diff --git a/modules/profiles/steam/default.nix b/modules/profiles/steam/default.nix
new file mode 100644
index 0000000..c8008f9
--- /dev/null
+++ b/modules/profiles/steam/default.nix
@@ -0,0 +1,8 @@
+{ ... }:
+{
+ programs.steam = {
+ enable = true;
+ remotePlay.openFirewall = true;
+ dedicatedServer.openFirewall = true;
+ };
+}
diff --git a/modules/profiles/upgrade/default.nix b/modules/profiles/upgrade/default.nix
new file mode 100644
index 0000000..32c49a8
--- /dev/null
+++ b/modules/profiles/upgrade/default.nix
@@ -0,0 +1,30 @@
+{ inputs, config, ... }:
+{
+ system.autoUpgrade = {
+ enable = true;
+ flake = inputs.self.outPath;
+ flags = [
+ "--update-input"
+ "nixpkgs"
+ "-L"
+ ];
+ dates = "Sat *-*-* 06:00:00";
+ randomizedDelaySec = "45min";
+ allowReboot = true;
+ };
+
+ systemd.services."reboot-alert" =
+ let
+ hostname = config.networking.hostName;
+ dependencies = [ "network-online.target" ];
+ in {
+ wantedBy = [ "multi-user.target" ];
+ wants = dependencies;
+ after = dependencies;
+ serviceConfig.Type = "oneshot";
+ script = ''
+ /run/current-system/sw/bin/pushover -t "${hostname} restarted" \
+ "${hostname} has restarted on $(date '+%a, %b %d at %T %p %Z')."
+ '';
+ };
+}
diff --git a/modules/profiles/vpn/default.nix b/modules/profiles/vpn/default.nix
new file mode 100644
index 0000000..0482c31
--- /dev/null
+++ b/modules/profiles/vpn/default.nix
@@ -0,0 +1,18 @@
+{ pkgs, ... }:
+{
+ networking.nameservers = [ "9.9.9.9" ];
+
+ services = {
+ mullvad-vpn = {
+ enable = true;
+ package = pkgs.mullvad-vpn;
+ };
+
+ resolved = {
+ enable = true;
+ dnssec = "true";
+ domains = [ "~." ];
+ dnsovertls = "true";
+ };
+ };
+}
diff --git a/modules/profiles/wireguard/default.nix b/modules/profiles/wireguard/default.nix
new file mode 100644
index 0000000..8c25d7a
--- /dev/null
+++ b/modules/profiles/wireguard/default.nix
@@ -0,0 +1,15 @@
+{ ... }:
+let
+ port = 51820;
+in
+{
+ networking = {
+ firewall.allowedUDPPorts = [ port ];
+
+ wg-quick.interfaces.wg0 = {
+ autostart = true;
+ listenPort = port;
+ configFile = "/etc/wireguard/wg0.conf";
+ };
+ };
+}
diff --git a/modules/profiles/wireshark/default.nix b/modules/profiles/wireshark/default.nix
new file mode 100644
index 0000000..d4d0627
--- /dev/null
+++ b/modules/profiles/wireshark/default.nix
@@ -0,0 +1,14 @@
+{ config, pkgs, ... }:
+{
+ programs.wireshark = {
+ enable = true;
+ package = pkgs.wireshark;
+ };
+
+ # Add any users in the 'wheel' group to the 'wireshark' group.
+ users.groups.wireshark.members = let users = config.users.users; in
+ builtins.attrNames users
+ |> builtins.filter (
+ x: builtins.elem "wheel" users.${x}.extraGroups
+ );
+}
diff --git a/modules/profiles/x11/default.nix b/modules/profiles/x11/default.nix
new file mode 100644
index 0000000..52e7975
--- /dev/null
+++ b/modules/profiles/x11/default.nix
@@ -0,0 +1,33 @@
+{ pkgs, ... }:
+{
+ services = {
+ xserver = {
+ enable = true;
+ xkb.layout = "us";
+ displayManager.lightdm.enable = true;
+ windowManager.bspwm.enable = true;
+ };
+
+ displayManager.autoLogin = {
+ enable = true;
+ user = "tdback";
+ };
+ };
+
+ hardware.graphics.enable32Bit = true;
+
+ environment.systemPackages = with pkgs.xorg; [
+ libX11
+ xset
+ ];
+
+ fonts.packages = with pkgs; [
+ dejavu_fonts
+ dina-font
+ iosevka-comfy.comfy-motion-fixed
+ liberation_ttf
+ noto-fonts
+ noto-fonts-emoji
+ ubuntu_font_family
+ ];
+}
diff --git a/modules/profiles/zfs/default.nix b/modules/profiles/zfs/default.nix
new file mode 100644
index 0000000..8344450
--- /dev/null
+++ b/modules/profiles/zfs/default.nix
@@ -0,0 +1,28 @@
+{ lib, pkgs, ... }:
+{
+ boot = {
+ zfs.forceImportRoot = false;
+ supportedFilesystems.zfs = lib.mkForce true;
+ };
+
+ services.zfs = {
+ autoScrub.enable = true;
+ zed = {
+ enableMail = false;
+ settings = {
+ ZED_DEBUG_LOG = "/tmp/zed.debug.log";
+ ZED_EMAIL_ADDR = [ "root" ];
+ ZED_EMAIL_PROG = "/run/current-system/sw/bin/pushover";
+ ZED_EMAIL_OPTS = "-t '@SUBJECT@'";
+ ZED_NOTIFY_INTERVAL_SECS = 3600;
+ ZED_NOTIFY_VERBOSE = true;
+ ZED_USE_ENCLOSURE_LEDS = true;
+ ZED_SCRUB_AFTER_RESILVER = true;
+ };
+ };
+ };
+
+ environment.systemPackages = with pkgs; [
+ zfs
+ ];
+}
diff --git a/modules/retired/forgejo/default.nix b/modules/retired/forgejo/default.nix
new file mode 100644
index 0000000..9db55b2
--- /dev/null
+++ b/modules/retired/forgejo/default.nix
@@ -0,0 +1,65 @@
+{ inputs, config, lib, pkgs, ... }:
+let
+ domain = "git.tdback.net";
+ port = 3000;
+in
+{
+ services.forgejo = {
+ enable = true;
+ package = pkgs.unstable.forgejo;
+ stateDir = "/tank/forgejo";
+ database.type = "postgres";
+ lfs.enable = true;
+ settings = {
+ server = {
+ DOMAIN = domain;
+ ROOT_URL = "https://${domain}/";
+ HTTP_PORT = port;
+ };
+ service.DISABLE_REGISTRATION = true;
+ actions = {
+ ENABLED = true;
+ DEFAULT_ACTIONS_URL = "https://${domain}";
+ };
+ };
+ };
+
+ age.secrets.forgejoAdminPass = {
+ file = "${inputs.self}/secrets/forgejoAdminPass.age";
+ mode = "770";
+ owner = "forgejo";
+ group = "forgejo";
+ };
+
+ systemd.services.forgejo.preStart =
+ let
+ adminCmd = "${lib.getExe config.services.forgejo.package} admin user";
+ password = config.age.secrets.forgejoAdminPass.path;
+ user = "tdback";
+ email = "tyler@tdback.net";
+ in ''
+ ${adminCmd} create --admin --email ${email} --username ${user} --password "$(tr -d '\n' < ${password})" || true
+ '';
+
+ services.openssh.settings.AllowUsers = [ "forgejo" ];
+
+ services.caddy.virtualHosts.${domain}.extraConfig = ''
+ encode zstd gzip
+ reverse_proxy http://localhost:${builtins.toString port}
+ '';
+
+ age.secrets.forgejoRunnerToken.file = "${inputs.self}/secrets/forgejoRunnerToken.age";
+ services.gitea-actions-runner = {
+ package = pkgs.unstable.forgejo-runner;
+ instances.default = {
+ enable = true;
+ name = "monolith";
+ url = "https://${domain}";
+ tokenFile = config.age.secrets.forgejoRunnerToken.path;
+ labels = [
+ "ubuntu-latest:docker://node:20-bookworm"
+ "ubuntu-22.04:docker://node:20-bookworm"
+ ];
+ };
+ };
+}
diff --git a/modules/retired/kavita/default.nix b/modules/retired/kavita/default.nix
new file mode 100644
index 0000000..c72aca6
--- /dev/null
+++ b/modules/retired/kavita/default.nix
@@ -0,0 +1,28 @@
+{ ... }:
+let
+ directories = [
+ "/opt/kavita"
+ ];
+in
+{
+ systemd.tmpfiles.rules = map (x: "d ${x} 0755 share share - -") directories;
+ virtualisation.oci-containers.containers.kavita = {
+ image = "jvmilazz0/kavita:latest";
+ autoStart = true;
+ ports = [
+ "5000:5000"
+ ];
+ volumes = [
+ "/opt/kavita/config:/kavita/config"
+ "/lagoon/media/library/Books:/books"
+ ];
+ environment = {
+ TZ = "America/Detroit";
+ };
+ };
+
+ services.caddy.virtualHosts."library.tdback.net".extraConfig = ''
+ encode zstd gzip
+ reverse_proxy http://localhost:5000
+ '';
+}
diff --git a/modules/retired/mealie/default.nix b/modules/retired/mealie/default.nix
new file mode 100644
index 0000000..2d869ce
--- /dev/null
+++ b/modules/retired/mealie/default.nix
@@ -0,0 +1,22 @@
+{ config, pkgs, ... }:
+let
+ domain = "toasted.brownbread.net";
+in
+{
+ services.mealie = {
+ enable = true;
+ package = pkgs.unstable.mealie;
+ settings = {
+ BASE_URL = domain;
+ DB_ENGINE = "sqlite";
+ ALLOW_SIGNUP = "false";
+ SECURITY_MAX_LOGIN_ATTEMPTS = 3;
+ TZ = "America/Detroit";
+ };
+ };
+
+ services.caddy.virtualHosts.${domain}.extraConfig = ''
+ encode zstd gzip
+ reverse_proxy http://localhost:${builtins.toString config.services.mealie.port}
+ '';
+}
diff --git a/modules/retired/mumble/default.nix b/modules/retired/mumble/default.nix
new file mode 100644
index 0000000..29e3339
--- /dev/null
+++ b/modules/retired/mumble/default.nix
@@ -0,0 +1,11 @@
+{ pkgs, ... }:
+{
+ services.murmur = {
+ enable = true;
+ package = pkgs.murmur;
+ port = 64738;
+ openFirewall = true;
+ environmentFile = "/var/lib/murmur/murmurd.env";
+ password = "$MURMURD_PASSWORD";
+ };
+}
diff --git a/modules/retired/navidrome/default.nix b/modules/retired/navidrome/default.nix
new file mode 100644
index 0000000..d98117b
--- /dev/null
+++ b/modules/retired/navidrome/default.nix
@@ -0,0 +1,31 @@
+{ lib, ... }:
+let
+ directory = "/opt/navidrome";
+in
+{
+ systemd.tmpfiles.rules =
+ map (x: "d ${x} 0755 share share - -") (lib.lists.singleton directory);
+
+ virtualisation.oci-containers.containers.navidrome = {
+ image = "deluan/navidrome:latest";
+ autoStart = true;
+ ports = [
+ "4533:4533"
+ ];
+ volumes = [
+ "${directory}/data:/data"
+ "/lagoon/media/music:/music:ro"
+ ];
+ environment = {
+ ND_SCANSCHEDULE = "1h";
+ ND_LOGLEVEL = "info";
+ ND_SESSIONTIMEOUT = "24h";
+ ND_ENABLEUSEREDITING = "false";
+ };
+ };
+
+ services.caddy.virtualHosts."radioactive.brownbread.net".extraConfig = ''
+ encode zstd gzip
+ reverse_proxy http://localhost:4533
+ '';
+}
diff --git a/modules/retired/pihole/default.nix b/modules/retired/pihole/default.nix
new file mode 100644
index 0000000..034c91b
--- /dev/null
+++ b/modules/retired/pihole/default.nix
@@ -0,0 +1,52 @@
+{ inputs, config, lib, ... }:
+let
+ # TODO: Think about changing this to config.networking.interface...
+ # Will have to pull the first value in the list, which might be messy but it
+ # will definitely make it more producible across machines.
+ ip = "10.0.0.203";
+ interface = "eno1";
+ directory = "/opt/pihole";
+in
+{
+ systemd.tmpfiles.rules =
+ map (x: "d ${x} 0755 share share - -") (lib.lists.singleton directory);
+
+ virtualisation.oci-containers.containers.pihole = {
+ image = "pihole/pihole:latest";
+ autoStart = true;
+ ports = [
+ "53:53/udp"
+ "53:53/tcp"
+ "80:80/tcp"
+ ];
+ volumes = [
+ "${directory}/etc:/etc/pihole"
+ "${directory}/etc-dnsmasq.d:/etc/dnsmasq.d"
+ ];
+ environment = {
+ TZ = "America/Detroit";
+ FTLCONF_LOCAL_IPV4 = ip;
+ INTERFACE = interface;
+ };
+ extraOptions = [ "--network=host" ];
+ };
+
+ age.secrets.piholeAdminPass = {
+ file = "${inputs.self}/secrets/piholeAdminPass.age";
+ mode = "770";
+ owner = "share";
+ group = "share";
+ };
+
+ systemd.services.podman-pihole.postStart =
+ let
+ password = config.age.secrets.piholeAdminPass.path;
+ in ''
+ podman exec -it pihole pihole -a -p "$(tr -d '\n' < ${password})"
+ '';
+
+ networking.firewall = {
+ allowedTCPPorts = [ 53 80 ];
+ allowedUDPPorts = [ 53 ];
+ };
+}
diff --git a/modules/retired/stirling-pdf/default.nix b/modules/retired/stirling-pdf/default.nix
new file mode 100644
index 0000000..904fd6d
--- /dev/null
+++ b/modules/retired/stirling-pdf/default.nix
@@ -0,0 +1,23 @@
+{ ... }:
+let
+ directories = [
+ "/opt/stirling"
+ ];
+in
+{
+ systemd.tmpfiles.rules = map (x: "d ${x} 0755 share share - -") directories;
+ virtualisation.oci-containers.containers.pdf-tools = {
+ image = "frooodle/s-pdf:latest";
+ autoStart = true;
+ ports = [
+ "8060:8080"
+ ];
+ volumes = [
+ "/opt/stirling/training-data:/usr/share/tesseract-ocr/4.00/tessdata"
+ "/opt/stirling/configs:/configs"
+ ];
+ environment = {
+ DOCKER_ENABLE_SECURITY = "false";
+ };
+ };
+}
diff --git a/modules/retired/xonotic/default.nix b/modules/retired/xonotic/default.nix
new file mode 100644
index 0000000..7ae5442
--- /dev/null
+++ b/modules/retired/xonotic/default.nix
@@ -0,0 +1,25 @@
+{ pkgs, ... }:
+{
+ services.xonotic = {
+ enable = true;
+ package = pkgs.xonotic-dedicated;
+ openFirewall = true;
+ settings = {
+ hostname = "tdback's Xonotic Server";
+ net_address = "0.0.0.0";
+ port = 26000;
+ sv_motd = "GLHF! Please report any issues to @tdback on irc.libera.chat";
+
+ # Specify bots and player count.
+ maxplayers = 8;
+ minplayers = 4;
+ minplayers_per_team = 2;
+
+ # Configure mutators.
+ g_instagib = 0;
+ g_grappling_hook = 1;
+ g_jetpack = 0;
+ g_vampire = 0;
+ };
+ };
+}
diff --git a/modules/scripts/motd/default.nix b/modules/scripts/motd/default.nix
new file mode 100644
index 0000000..d59f787
--- /dev/null
+++ b/modules/scripts/motd/default.nix
@@ -0,0 +1,99 @@
+{ config, lib, pkgs, ... }:
+let
+ motd =
+ pkgs.writeShellScriptBin "motd" ''
+ #!/usr/bin/env bash
+ RED="\e[31m"
+ GREEN="\e[32m"
+ YELLOW="\e[33m"
+ BOLD="\e[1m"
+ ENDCOLOR="\e[0m"
+
+ case "$(date +'%H')" in
+ [0-9]|1[0-1])
+ TIME="morning"
+ ;;
+ 1[2-7])
+ TIME="afternoon"
+ ;;
+ *)
+ TIME="evening"
+ ;;
+ esac
+
+ UPTIME=$(cat /proc/uptime | cut -f1 -d.)
+ UPDAYS=$((UPTIME/60/60/24))
+ UPHOURS=$((UPTIME/60/60%24))
+ UPMINS=$((UPTIME/60%60))
+ UPSECS=$((UPTIME%60))
+
+ MEMORY=$(free -m | awk 'NR == 2 { printf "%s/%sMB (%.2f%%)\n", $3, $2, ($3 * 100) / $2 }')
+
+ SERVICES=$(systemctl list-units | grep -P 'podman-|${lib.strings.concatStringsSep "|" config.motd.servicesToCheck}')
+
+ printf "\n"
+ printf "''${BOLD}Good $TIME $(whoami), welcome to $(hostname)!$ENDCOLOR\n"
+ printf "\n"
+ ${lib.strings.concatStrings (lib.lists.forEach config.motd.networkInterfaces (x:
+ "printf \"$BOLD * %-20s$ENDCOLOR %s\\n\" \"IPv4 ${x}\" \"$(ip -4 addr show ${x} | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}')\"\n"
+ ))}
+ printf "$BOLD * %-20s$ENDCOLOR %s\n" "Release" "$(awk -F= '/PRETTY_NAME/ { print $2 }' /etc/os-release | tr -d '"')"
+ printf "$BOLD * %-20s$ENDCOLOR %s\n" "Kernel" "$(uname -rs)"
+ printf "\n"
+ printf "$BOLD * %-20s$ENDCOLOR %s\n" "CPU Usage" "$(awk '{ print $1 ", " $2 ", " $3 }' /proc/loadavg) (1, 5, 15 min)"
+ printf "$BOLD * %-20s$ENDCOLOR %s\n" "Memory" "$MEMORY"
+ printf "$BOLD * %-20s$ENDCOLOR %s\n" "System Uptime" "$UPDAYS days $UPHOURS hours $UPMINS minutes $UPSECS seconds"
+ printf "\n"
+
+ [ -z "$SERVICES" ] && exit
+
+ printf "''${BOLD}Service status:$ENDCOLOR\n"
+ while IFS= read -r line; do
+ if [[ ! $line =~ ".service" ]] || [[ $line =~ ".mount" ]]; then
+ continue
+ fi
+ if echo "$line" | grep -q 'failed'; then
+ name=$(echo "$line" | awk '{ print $1 }' | sed 's/podman-//g')
+ printf "$RED• $ENDCOLOR%-50s $RED[failed]$ENDCOLOR\n" "$name"
+ elif echo "$line" | grep -q 'running'; then
+ name=$(echo "$line" | awk '{ print $1 }' | sed 's/podman-//g')
+ printf "$GREEN• $ENDCOLOR%-50s $GREEN[active]$ENDCOLOR\n" "$name"
+ elif echo "$line" | grep -q 'exited'; then
+ name=$(echo "$line" | awk '{ print $1 }' | sed 's/podman-//g')
+ printf "$YELLOW• $ENDCOLOR%-50s $YELLOW[exited]$ENDCOLOR\n" "$name"
+ else
+ echo "service status unknown"
+ fi
+ done <<< "$SERVICES"
+ printf "\n"
+ '';
+in
+{
+ options.motd = {
+ networkInterfaces = lib.mkOption {
+ description = "Network interfaces to monitor.";
+ type = lib.types.listOf lib.types.str;
+ default = [ ];
+ };
+
+ servicesToCheck = lib.mkOption {
+ description = "Services to validate alongside podman containers.";
+ type = lib.types.listOf lib.types.str;
+ default = [ ];
+ };
+ };
+
+ config = {
+ environment.systemPackages = [
+ motd
+ ];
+
+ programs.bash.loginShellInit = ''
+ [ -z "$PS1" ] && return
+
+ if command -v motd &> /dev/null; then
+ motd
+ fi
+ '';
+ };
+}
diff --git a/modules/scripts/pushover/default.nix b/modules/scripts/pushover/default.nix
new file mode 100644
index 0000000..f20a5be
--- /dev/null
+++ b/modules/scripts/pushover/default.nix
@@ -0,0 +1,47 @@
+{ inputs, config, pkgs, ... }:
+let
+ pushover =
+ pkgs.writeShellScriptBin "pushover" ''
+ #!/bin/sh
+
+ die() { echo "$0: $*" >&2; exit 111; }
+
+ APP=$(cat ${config.age.secrets.pushoverAppToken.path})
+ USER=$(cat ${config.age.secrets.pushoverUserToken.path})
+
+ while getopts ":t:" args; do
+ case "$args" in
+ t)
+ TITLE="$OPTARG"
+ ;;
+ :)
+ die "missing option argument for -$OPTARG"
+ ;;
+ *)
+ die "invalid option -$OPTARG"
+ ;;
+ esac
+ done
+ shift $((OPTIND - 1))
+
+ MESSAGE="$*"
+ if [ -z "$MESSAGE" ] || [ "$MESSAGE" = " " ]; then
+ MESSAGE="No errors to report."
+ fi
+
+ /run/current-system/sw/bin/curl -s \
+ --form-string "token=$APP" \
+ --form-string "user=$USER" \
+ --form-string "title=$TITLE" \
+ --form-string "message=$MESSAGE" \
+ https://api.pushover.net/1/messages.json
+ '';
+in
+{
+ age.secrets = {
+ pushoverAppToken.file = "${inputs.self}/secrets/pushoverAppToken.age";
+ pushoverUserToken.file = "${inputs.self}/secrets/pushoverUserToken.age";
+ };
+
+ environment.systemPackages = [ pushover ];
+}
diff --git a/modules/services/blocky/default.nix b/modules/services/blocky/default.nix
new file mode 100644
index 0000000..ca58f4f
--- /dev/null
+++ b/modules/services/blocky/default.nix
@@ -0,0 +1,93 @@
+{ pkgs, ... }:
+{
+ services.blocky = {
+ enable = true;
+ package = pkgs.blocky;
+ settings = {
+ upstreams = {
+ init.strategy = "fast";
+ groups.default = [
+ "9.9.9.9"
+ "149.112.112.112"
+ ];
+ };
+ bootstrapDns = [{
+ upstream = "https://dns.quad9.net/dns-query";
+ ips = [ "9.9.9.9" ];
+ }];
+ ports = {
+ dns = 53;
+ tls = 853;
+ https = 443;
+ };
+ blocking = {
+ denylists = {
+ ads = [
+ "https://adaway.org/hosts.txt"
+ "https://v.firebog.net/hosts/AdguardDNS.txt"
+ "https://v.firebog.net/hosts/Admiral.txt"
+ "https://raw.githubusercontent.com/anudeepND/blacklist/master/adservers.txt"
+ "https://v.firebog.net/hosts/Easylist.txt"
+ "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=0&mimetype=plaintext"
+ "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/UncheckyAds/hosts"
+ "https://raw.githubusercontent.com/bigdargon/hostsVN/master/hosts"
+ ];
+ malicious = [
+ "https://osint.digitalside.it/Threat-Intel/lists/latestdomains.txt"
+ "https://v.firebog.net/hosts/Prigent-Crypto.txt"
+ "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Risk/hosts"
+ "https://phishing.army/download/phishing_army_blocklist_extended.txt"
+ "https://gitlab.com/quidsup/notrack-blocklists/raw/master/notrack-malware.txt"
+ "https://raw.githubusercontent.com/Spam404/lists/master/main-blacklist.txt"
+ "https://raw.githubusercontent.com/AssoEchap/stalkerware-indicators/master/generated/hosts"
+ "https://urlhaus.abuse.ch/downloads/hostfile/"
+ "https://v.firebog.net/hosts/Prigent-Malware.txt"
+ ];
+ other = [
+ "https://zerodot1.gitlab.io/CoinBlockerLists/hosts_browser"
+ ];
+ suspicious = [
+ "https://raw.githubusercontent.com/PolishFiltersTeam/KADhosts/master/KADhosts.txt"
+ "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Spam/hosts"
+ "https://v.firebog.net/hosts/static/w3kbl.txt"
+ "https://raw.githubusercontent.com/matomo-org/referrer-spam-blacklist/master/spammers.txt"
+ "https://someonewhocares.org/hosts/zero/hosts"
+ "https://raw.githubusercontent.com/VeleSila/yhosts/master/hosts"
+ "https://winhelp2002.mvps.org/hosts.txt"
+ "https://v.firebog.net/hosts/neohostsbasic.txt"
+ "https://raw.githubusercontent.com/RooneyMcNibNug/pihole-stuff/master/SNAFU.txt"
+ "https://paulgb.github.io/BarbBlock/blacklists/hosts-file.txt"
+ ];
+ tracking-telemetry = [
+ "https://v.firebog.net/hosts/Easyprivacy.txt"
+ "https://v.firebog.net/hosts/Prigent-Ads.txt"
+ "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.2o7Net/hosts"
+ "https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt"
+ "https://hostfiles.frogeye.fr/firstparty-trackers-hosts.txt"
+ "https://www.github.developerdan.com/hosts/lists/ads-and-tracking-extended.txt"
+ "https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/android-tracking.txt"
+ "https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/SmartTV.txt"
+ "https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/AmazonFireTV.txt"
+ "https://gitlab.com/quidsup/notrack-blocklists/raw/master/notrack-blocklist.txt"
+ ];
+ };
+ clientGroupsBlock.default = [
+ "ads"
+ "malicious"
+ "other"
+ "suspicious"
+ "tracking-telemetry"
+ ];
+ loading = {
+ concurrency = 16;
+ strategy = "failOnError";
+ };
+ };
+ };
+ };
+
+ networking.firewall = {
+ allowedTCPPorts = [ 53 443 853 ];
+ allowedUDPPorts = [ 53 ];
+ };
+}
diff --git a/modules/services/cgit/default.nix b/modules/services/cgit/default.nix
new file mode 100644
index 0000000..5309e6f
--- /dev/null
+++ b/modules/services/cgit/default.nix
@@ -0,0 +1,28 @@
+{ inputs, lib, pkgs, ... }:
+let
+ scanPath = "/tank/git";
+ domain = "git.tdback.net";
+in
+{
+ imports = lib.lists.singleton "${inputs.self}/modules/customs/cgit";
+
+ services.cgit = {
+ enable = true;
+ package = pkgs.cgit;
+ scanPath = scanPath;
+ virtualHost = domain;
+ authorizedKeys = [
+ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEzLpTEoej7P04KoNzokQ9IOnNZiKyi2+YQ8yU5WSKCb"
+ ];
+ settings = {
+ root-title = domain;
+ root-desc = "tdback's git repositories";
+ enable-index-links = 1;
+ enable-index-owner = 0;
+ enable-commit-graph = 1;
+ enable-log-filecount = 1;
+ enable-log-linecount = 1;
+ readme = ":README.md";
+ };
+ };
+}
diff --git a/modules/services/fediverse/default.nix b/modules/services/fediverse/default.nix
new file mode 100644
index 0000000..0c3c696
--- /dev/null
+++ b/modules/services/fediverse/default.nix
@@ -0,0 +1,26 @@
+{ pkgs, ... }:
+let
+ domain = "social.tdback.net";
+ port = 8080;
+in
+{
+ services.gotosocial = {
+ enable = true;
+ package = pkgs.unstable.gotosocial;
+ settings = {
+ application-name = "gotosocial";
+ host = "${domain}";
+ protocol = "https";
+ bind-address = "localhost";
+ port = port;
+ db-type = "sqlite";
+ db-address = "/var/lib/gotosocial/database.sqlite";
+ storage-local-base-path = "/var/lib/gotosocial/storage";
+ };
+ };
+
+ services.caddy.virtualHosts.${domain}.extraConfig = ''
+ encode zstd gzip
+ reverse_proxy http://localhost:${builtins.toString port}
+ '';
+}
diff --git a/modules/services/immich/default.nix b/modules/services/immich/default.nix
new file mode 100644
index 0000000..e33dd97
--- /dev/null
+++ b/modules/services/immich/default.nix
@@ -0,0 +1,18 @@
+{ pkgs, ... }:
+{
+ services.immich = {
+ enable = true;
+ package = pkgs.immich;
+ host = "localhost";
+ port = 2283;
+ mediaLocation = "/lagoon/media/immich";
+ environment = {
+ IMMICH_LOG_LEVEL = "log";
+ };
+ };
+
+ services.caddy.virtualHosts."photographs.brownbread.net".extraConfig = ''
+ encode zstd gzip
+ reverse_proxy http://localhost:2283
+ '';
+}
diff --git a/modules/services/proxy/default.nix b/modules/services/proxy/default.nix
new file mode 100644
index 0000000..e11beab
--- /dev/null
+++ b/modules/services/proxy/default.nix
@@ -0,0 +1,9 @@
+{ pkgs, ... }:
+{
+ services.caddy = {
+ enable = true;
+ package = pkgs.caddy;
+ };
+
+ networking.firewall.allowedTCPPorts = [ 80 443 ];
+}
diff --git a/modules/services/searx/default.nix b/modules/services/searx/default.nix
new file mode 100644
index 0000000..2b4a9d8
--- /dev/null
+++ b/modules/services/searx/default.nix
@@ -0,0 +1,33 @@
+{ pkgs, ... }:
+let
+ port = 8888;
+in
+{
+ services.searx = {
+ enable = true;
+ package = pkgs.searxng;
+ environmentFile = "/var/lib/searx/env";
+ settings = {
+ general = {
+ debug = false;
+ instance_name = "searx";
+ };
+ search = {
+ safe_search = 1;
+ autocomplete = "duckduckgo";
+ autocomplete_min = 4;
+ default_lang = "en-US";
+ };
+ server = {
+ port = port;
+ bind_address = "0.0.0.0";
+ secret_key = "@SEARX_SECRET_KEY@";
+ public_instance = false;
+ image_proxy = true;
+ };
+ ui.static_use_hash = true;
+ };
+ };
+
+ networking.firewall.allowedTCPPorts = [ port ];
+}
diff --git a/modules/services/sftpgo/default.nix b/modules/services/sftpgo/default.nix
new file mode 100644
index 0000000..27318b2
--- /dev/null
+++ b/modules/services/sftpgo/default.nix
@@ -0,0 +1,21 @@
+{ config, pkgs, ... }:
+{
+ services.sftpgo = {
+ enable = true;
+ package = pkgs.sftpgo;
+ settings = {
+ httpd.bindings = [{
+ port = 8080;
+ address = "0.0.0.0";
+ enable_web_client = true;
+ enable_web_admin = true;
+ }];
+ };
+ };
+
+ services.caddy.virtualHosts."${config.networking.hostName}.brownbread.net".extraConfig = ''
+ root * /web/client
+ encode zstd gzip
+ reverse_proxy http://localhost:8080
+ '';
+}
diff --git a/modules/services/ssh/default.nix b/modules/services/ssh/default.nix
new file mode 100644
index 0000000..ec8f188
--- /dev/null
+++ b/modules/services/ssh/default.nix
@@ -0,0 +1,17 @@
+{ lib, ... }:
+let
+ ports = lib.lists.singleton 2222;
+in
+{
+ services.openssh = {
+ enable = lib.mkDefault true;
+ ports = ports;
+ openFirewall = true;
+ startWhenNeeded = true;
+ settings = {
+ AllowUsers = [ "tdback" ];
+ PermitRootLogin = "no";
+ PasswordAuthentication = lib.mkDefault false;
+ };
+ };
+}
diff --git a/modules/services/web/default.nix b/modules/services/web/default.nix
new file mode 100644
index 0000000..b6a45af
--- /dev/null
+++ b/modules/services/web/default.nix
@@ -0,0 +1,10 @@
+{ ... }:
+{
+ services.caddy.virtualHosts = {
+ "tdback.net".extraConfig = ''
+ root * /var/www/tdback.net/
+ encode zstd gzip
+ file_server
+ '';
+ };
+}
diff --git a/modules/users/default.nix b/modules/users/default.nix
new file mode 100644
index 0000000..027ca0f
--- /dev/null
+++ b/modules/users/default.nix
@@ -0,0 +1,15 @@
+{ pkgs, ... }:
+{
+ users = {
+ users.tdback = {
+ isNormalUser = true;
+ uid = 1000;
+ home = "/home/tdback";
+ group = "tdback";
+ extraGroups = [ "wheel" "users" "networkmanager" "video" "audio" ];
+ shell = pkgs.bash;
+ ignoreShellProgramCheck = true;
+ };
+ groups.tdback.gid = 1000;
+ };
+}
diff --git a/secrets/pushoverAppToken.age b/secrets/pushoverAppToken.age
new file mode 100644
index 0000000..e81a894
--- /dev/null
+++ b/secrets/pushoverAppToken.age
@@ -0,0 +1,13 @@
+age-encryption.org/v1
+-> ssh-ed25519 gpkhBg F2i4P0GuB+EC6ZbH+QtkogDxEOH3p71aJ3dp3s8CEgM
+4/pDhOscOh7HHGojnkpTae9BYz9p8Nt9EDpT0cdrITU
+-> ssh-ed25519 NJIOsA rRfKrypbNoKe4ja1LIg6RbApf3la3ZV5OzcGHADdJws
+G59Dy/689mkNc9UBVOGa288iucWATUQw1TQS9hmTE9w
+-> ssh-ed25519 D2VkFQ NJNZDmBYw5GY+rRnCJRH44kbxDTrmjwyhgfSOf+8rDU
+f2SaYKM7bk7vQ0E7My3v5l5MC3b/2+vnezYYoZxPIB0
+-> ssh-ed25519 VoJMUA q4mjpsmZlHQUxsDT45t2TR3rs9vZ4YP2Wxc51zyphSI
+LeAd0zYKvt6Nm4MtEIxMi+QcHTqfAXU60QsfudfOqsI
+-> ssh-ed25519 WAT7cQ rgJZHOEQImza/yE7mgHf/oVdcQ4sCqhINajQxWay11M
+lynXczF6QwsPeLpcWmfPO9eXeETTgjbu0T6nCy9sQsc
+--- KACyQUO0R39fLv1hSz8rz0jVzdXwkkXPtbErA9t+1xU
+`YCjy!}cg`9?W4*emxl䠡7^>.; \ No newline at end of file
diff --git a/secrets/pushoverUserToken.age b/secrets/pushoverUserToken.age
new file mode 100644
index 0000000..6284ec7
--- /dev/null
+++ b/secrets/pushoverUserToken.age
Binary files differ
diff --git a/secrets/secrets.nix b/secrets/secrets.nix
new file mode 100644
index 0000000..f007165
--- /dev/null
+++ b/secrets/secrets.nix
@@ -0,0 +1,19 @@
+let
+ systems = {
+ eden = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIByi8x1IgXBC6iw6MJoO7xIkkU4bdIaQ3Mi6zEtm+IJh";
+ hive = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGEn+C6ktSqvvwNVf1zUeNKKtZJ1QgLVhQjU83+0RvSY";
+ oasis = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICCvgPNEJrWjeCUmF/izLhIzaAwSNYHW9o5meYmGHGzj";
+ raindog = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINq0rMkFlizGPijlHKMYS9CGWJ2T1ZJHqaLozWdoySz2";
+ };
+
+ users = {
+ tdback = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIErXJtbnTYwxgqv7v5HJgd0OUAlOeEzxX7TxEyBDM+at";
+ };
+
+ allSystems = builtins.attrValues systems;
+ allUsers = builtins.attrValues users;
+in
+{
+ "pushoverAppToken.age".publicKeys = allSystems ++ allUsers;
+ "pushoverUserToken.age".publicKeys = allSystems ++ allUsers;
+}
diff --git a/users/default.nix b/users/default.nix
new file mode 100644
index 0000000..2eb2feb
--- /dev/null
+++ b/users/default.nix
@@ -0,0 +1,3 @@
+{
+ tdback = import ./tdback;
+}
diff --git a/users/tdback/default.nix b/users/tdback/default.nix
new file mode 100644
index 0000000..8457428
--- /dev/null
+++ b/users/tdback/default.nix
@@ -0,0 +1,32 @@
+{ config, lib, pkgs, headless ? true, ... }:
+{
+ # Hacky way to import our desktop modules if we aren't a headless system.
+ imports = (lib.optional (!headless) ./desktop.nix) ++ [
+ ./modules/git
+ ./modules/shell
+ ];
+
+ home = {
+ username = "tdback";
+ homeDirectory = "/home/tdback";
+ stateVersion = "24.05";
+ packages = with pkgs.unstable; [
+ age
+ bat
+ croc
+ dig
+ file
+ fzf
+ jq
+ neovim
+ nixd
+ ripgrep
+ tealdeer
+ unzip
+ zip
+ ];
+ };
+
+ # Let home manager install and manage itself.
+ programs.home-manager.enable = true;
+}
diff --git a/users/tdback/desktop.nix b/users/tdback/desktop.nix
new file mode 100644
index 0000000..e2f754b
--- /dev/null
+++ b/users/tdback/desktop.nix
@@ -0,0 +1,70 @@
+{ config, pkgs, ... }:
+let
+ dirs = [ "desktop" "documents" "download" "music" "pictures" "publicShare" "templates" "videos" ];
+ defined = {
+ "documents" = "${config.home.homeDirectory}/documents";
+ "download" = "${config.home.homeDirectory}/downloads";
+ };
+ userDirs =
+ builtins.map (dir: { name = dir; value = defined.${dir} or null; }) dirs
+ |> builtins.listToAttrs;
+in
+{
+ imports = [
+ ./modules/alacritty
+ ./modules/dunst
+ ./modules/email
+ ./modules/firefox
+ ./modules/irc
+ ./modules/mpd
+ ./modules/ncmpcpp
+ ./modules/neomutt
+ ./modules/polybar
+ ./modules/rofi
+ ./modules/tmux
+ ./modules/x11
+ ];
+
+ home.packages = with pkgs.unstable; [
+ clang
+ feh
+ (ffmpeg.override { withXcb = true; })
+ flameshot
+ gimp
+ gitu
+ mpc-cli
+ mpv
+ pavucontrol
+ pamixer
+ pciutils
+ signal-desktop
+ sxiv
+ tidal-dl
+ xclip
+ yt-dlp
+ zathura
+ ];
+
+ xdg = {
+ enable = true;
+ userDirs = {
+ enable = true;
+ createDirectories = true;
+ } // userDirs;
+ };
+
+ qt = {
+ enable = true;
+ platformTheme.name = "gtk3";
+ style = {
+ name = "adwaita-dark";
+ package = pkgs.adwaita-qt;
+ };
+ };
+
+ gtk = {
+ enable = true;
+ gtk3.extraConfig.gtk-application-prefer-dark-theme = 1;
+ gtk4.extraConfig.gtk-application-prefer-dark-theme = 1;
+ };
+}
diff --git a/users/tdback/modules/alacritty/default.nix b/users/tdback/modules/alacritty/default.nix
new file mode 100644
index 0000000..6955536
--- /dev/null
+++ b/users/tdback/modules/alacritty/default.nix
@@ -0,0 +1,71 @@
+{ pkgs, ... }:
+{
+ programs.alacritty = {
+ enable = true;
+ package = pkgs.alacritty;
+ settings = {
+ env.TERM = "xterm-256color";
+ mouse.hide_when_typing = true;
+ scrolling.history = 10000;
+
+ window = {
+ decorations = "None";
+ opacity = 1.0;
+ title = "Alacritty";
+ padding.x = 4;
+ };
+
+ cursor.style.blinking = "Never";
+
+ font = {
+ size = 14.0;
+ normal = {
+ family = "Iosevka Comfy Motion Fixed";
+ style = "Regular";
+ };
+ italic = {
+ family = "Iosevka Comfy Motion Fixed";
+ style = "Italic";
+ };
+ bold = {
+ family = "Iosevka Comfy Motion Fixed";
+ style = "Bold";
+ };
+ bold_italic = {
+ family = "Iosevka Comfy Motion Fixed";
+ style = "Bold Italic";
+ };
+ };
+
+ # Tomorrow Night Bright colorscheme.
+ colors = {
+ draw_bold_text_with_bright_colors = true;
+
+ primary = {
+ background = "#000000";
+ foreground = "#eaeaea";
+ };
+ normal = {
+ black = "#000000";
+ red = "#d54e53";
+ green = "#b9ca4a";
+ yellow = "#e6c547";
+ blue = "#7aa6da";
+ magenta = "#c397d8";
+ cyan = "#70c0ba";
+ white = "#424242";
+ };
+ bright = {
+ black = "#666666";
+ red = "#ff3334";
+ green = "#9ec400";
+ yellow = "#e7c547";
+ blue = "#7aa6da";
+ magenta = "#b77ee0";
+ cyan = "#54ced6";
+ white = "#2a2a2a";
+ };
+ };
+ };
+ };
+}
diff --git a/users/tdback/modules/dunst/default.nix b/users/tdback/modules/dunst/default.nix
new file mode 100644
index 0000000..132e32b
--- /dev/null
+++ b/users/tdback/modules/dunst/default.nix
@@ -0,0 +1,30 @@
+{ pkgs, ... }:
+{
+ services.dunst = {
+ enable = true;
+ package = pkgs.dunst;
+
+ settings = {
+ global = {
+ width = 300;
+ height = 300;
+ offset = "30x50";
+ origin = "top-right";
+ frame_color = "#2c363c";
+ font = "Iosevka Comfy Motion Fixed 12";
+ };
+
+ urgency_normal = {
+ background = "#37474f";
+ foreground = "eceff1";
+ timeout = 5;
+ };
+ };
+
+ iconTheme = {
+ name = "Papirus-Dark";
+ package = pkgs.papirus-icon-theme;
+ size = "16x16";
+ };
+ };
+}
diff --git a/users/tdback/modules/email/default.nix b/users/tdback/modules/email/default.nix
new file mode 100644
index 0000000..3321462
--- /dev/null
+++ b/users/tdback/modules/email/default.nix
@@ -0,0 +1,78 @@
+{ pkgs, ... }:
+{
+ accounts.email = {
+ maildirBasePath = "mail";
+
+ accounts.fastmail = {
+ primary = true;
+ address = "tyler@tdback.net";
+ userName = "tyler@tdback.net";
+ realName = "Tyler Dunneback";
+ passwordCommand = "${pkgs.age}/bin/age -d -i ~/.ssh/mail ~/.mail.age";
+
+ folders = {
+ inbox = "Inbox";
+ drafts = "Drafts";
+ sent = "Sent";
+ trash = "Trash";
+ };
+
+ imap = {
+ host = "imap.fastmail.com";
+ port = 993;
+ tls = {
+ enable = true;
+ certificatesFile = "/etc/ssl/certs/ca-certificates.crt";
+ };
+ };
+
+ smtp = {
+ host = "smtp.fastmail.com";
+ port = 465;
+ tls = {
+ enable = true;
+ useStartTls = false;
+ certificatesFile = "/etc/ssl/certs/ca-certificates.crt";
+ };
+ };
+
+ mbsync = {
+ enable = true;
+ create = "both";
+ expunge = "none";
+ subFolders = "Verbatim";
+ patterns = [ "*" ];
+ };
+
+ msmtp = {
+ enable = true;
+ extraConfig = {
+ logfile = "~/.cache/msmtp/msmtp.log";
+ };
+ };
+
+ neomutt = {
+ enable = true;
+ sendMailCommand = "msmtp";
+ mailboxType = "maildir";
+ extraMailboxes = [
+ "Drafts"
+ "Sent"
+ "Trash"
+ "Archive"
+ ];
+ };
+ };
+ };
+
+ programs = {
+ mbsync.enable = true;
+ msmtp.enable = true;
+ };
+
+ services.mbsync = {
+ enable = true;
+ package = pkgs.isync;
+ frequency = "*:0/5";
+ };
+}
diff --git a/users/tdback/modules/firefox/default.nix b/users/tdback/modules/firefox/default.nix
new file mode 100644
index 0000000..dde8742
--- /dev/null
+++ b/users/tdback/modules/firefox/default.nix
@@ -0,0 +1,101 @@
+{ config, pkgs, ... }:
+let
+ lock-false = {
+ Value = false;
+ Status = "locked";
+ };
+ lock-true = {
+ Value = true;
+ Status = "locked";
+ };
+in
+{
+ programs.firefox = {
+ enable = true;
+ package = pkgs.firefox;
+
+ policies = {
+ # about:policies
+ DisableTelemetry = true;
+ DisableFirefoxStudies = true;
+ DisablePocket = true;
+ DisableFirefoxAccounts = true;
+ DisableAccounts = true;
+ DisplayBookmarksToolbar = "newtab";
+ DisplayMenuBar = "default-off";
+ SearchBar = "unified";
+ OfferToSaveLogins = false;
+ EnableTrackingProtection = {
+ Value= true;
+ Locked = true;
+ Cryptomining = true;
+ Fingerprinting = true;
+ };
+
+ # about:config
+ Preferences = {
+ "browser.contentblocking.category" = { Value = "strict"; Status = "locked"; };
+ "extensions.pocket.enabled" = lock-false;
+ "extensions.screenshots.disabled" = lock-true;
+ "browser.topsites.contile.enabled" = lock-false;
+ "browser.formfill.enable" = lock-false;
+ "browser.search.suggest.enabled" = lock-false;
+ "browser.search.suggest.enabled.private" = lock-false;
+ "browser.urlbar.suggest.searches" = lock-false;
+ "browser.urlbar.showSearchSuggestionsFirst" = lock-false;
+ "browser.newtabpage.activity-stream.feeds.section.topstories" = lock-false;
+ "browser.newtabpage.activity-stream.feeds.snippets" = lock-false;
+ "browser.newtabpage.activity-stream.section.highlights.includePocket" = lock-false;
+ "browser.newtabpage.activity-stream.section.highlights.includeBookmarks" = lock-false;
+ "browser.newtabpage.activity-stream.section.highlights.includeDownloads" = lock-false;
+ "browser.newtabpage.activity-stream.section.highlights.includeVisited" = lock-false;
+ "browser.newtabpage.activity-stream.showSponsored" = lock-false;
+ "browser.newtabpage.activity-stream.system.showSponsored" = lock-false;
+ "browser.newtabpage.activity-stream.showSponsoredTopSites" = lock-false;
+ };
+
+ ExtensionSettings = {
+ # Block all extensions except those defined below.
+ "*".installation_mode = "blocked";
+
+ # uBlock Origin
+ "uBlock0@raymondhill.net" = {
+ install_url = "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi";
+ installation_mode = "force_installed";
+ };
+
+ # Bitwarden
+ "{446900e4-71c2-419f-a6a7-df9c091e268b}" = {
+ install_url = "https://addons.mozilla.org/firefox/downloads/latest/bitwarden-password-manager/latest.xpi";
+ installation_mode = "force_installed";
+ };
+
+ # Dark Reader
+ "addon@darkreader.org" = {
+ install_url = "https://addons.mozilla.org/firefox/downloads/latest/darkreader/latest.xpi";
+ installation_mode = "force_installed";
+ };
+ };
+ };
+
+ profiles.${config.home.username}.search = {
+ force = true;
+ default = "searx";
+ order = [ "searx" ];
+ engines = {
+ "Amazon.com".metaData.hidden = true;
+ "Bing".metaData.hidden = true;
+ "eBay".metaData.hidden = true;
+ "Google".metaData.hidden = true;
+ "Wikipedia (en)".metaData.alias = "@w";
+ "searx" = {
+ urls = [{
+ template = "http://10.44.4.100:8888/?q={searchTerms}";
+ }];
+ updateInterval = 24 * 60 * 60 * 1000;
+ definedAliases = [ "@sx" ];
+ };
+ };
+ };
+ };
+}
diff --git a/users/tdback/modules/git/default.nix b/users/tdback/modules/git/default.nix
new file mode 100644
index 0000000..c608c6b
--- /dev/null
+++ b/users/tdback/modules/git/default.nix
@@ -0,0 +1,9 @@
+{ ... }:
+{
+ programs.git = {
+ enable = true;
+ userName = "tdback";
+ userEmail = "tyler@tdback.net";
+ extraConfig.init.defaultBranch = "main";
+ };
+}
diff --git a/users/tdback/modules/irc/default.nix b/users/tdback/modules/irc/default.nix
new file mode 100644
index 0000000..bc96909
--- /dev/null
+++ b/users/tdback/modules/irc/default.nix
@@ -0,0 +1,30 @@
+{ ... }:
+let
+ user = "tdback";
+in
+{
+ programs.irssi = {
+ enable = true;
+
+ extraConfig = ''
+ settings = { core = { real_name = "${user}"; }; };
+ '';
+
+ networks = {
+ liberachat = {
+ nick = "${user}";
+ saslExternal = true;
+ server = {
+ address = "irc.libera.chat";
+ port = 6697;
+ autoConnect = true;
+ ssl = {
+ enable = true;
+ verify = true;
+ certificateFile = "/home/${user}/.irssi/certs/libera.pem";
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/users/tdback/modules/mpd/default.nix b/users/tdback/modules/mpd/default.nix
new file mode 100644
index 0000000..d7338cb
--- /dev/null
+++ b/users/tdback/modules/mpd/default.nix
@@ -0,0 +1,34 @@
+{ pkgs, ... }:
+{
+ services.mpd = {
+ enable = true;
+ package = pkgs.mpd;
+
+ network = {
+ listenAddress = "127.0.0.1";
+ port = 6600;
+ };
+
+ musicDirectory = "~/media/music";
+
+ extraConfig = ''
+ log_file "syslog"
+ max_output_buffer_size "16384"
+
+ restore_paused "yes"
+ auto_update "yes"
+
+ audio_output {
+ type "pulse"
+ name "pulseaudio"
+ }
+
+ audio_output {
+ type "fifo"
+ name "Visualizer feed"
+ path "/tmp/mpd.fifo"
+ format "44100:16:2"
+ }
+ '';
+ };
+}
diff --git a/users/tdback/modules/ncmpcpp/default.nix b/users/tdback/modules/ncmpcpp/default.nix
new file mode 100644
index 0000000..a201e88
--- /dev/null
+++ b/users/tdback/modules/ncmpcpp/default.nix
@@ -0,0 +1,65 @@
+{ pkgs, ... }:
+{
+ programs.ncmpcpp = {
+ enable = true;
+ package = pkgs.ncmpcpp.override { visualizerSupport = true; };
+ mpdMusicDir = "~/Media/Music";
+ settings = {
+ ncmpcpp_directory = "~/.config/ncmpcpp";
+ lyrics_directory = "~/.local/share/lyrics";
+ song_list_format = "{%a - }{%t}|{$8%f$9}$R{$3%l$9}";
+ song_status_format = "{{%a{ \"%b\"{ (%y)}} - }{%t}}|{%f}";
+ song_library_format = "{%n - }{%t}|{%f}";
+ alternative_header_first_line_format = "$b$1$aqqu$/a$9 {%t}|{%f} $1$atqq$/a$9$/b";
+ alternative_header_second_line_format = "{{$4$b%a$/b$9}{ - $7%b$9}{ ($4%y$9)}}|{%D}";
+ current_item_prefix = "$(yellow)$r";
+ current_item_suffix = "$/r$(end)";
+ current_item_inactive_column_prefix = "$(white)$r";
+ current_item_inactive_column_suffix = "$/r$(end)";
+ now_playing_prefix = "$b";
+ now_playing_suffix = "$/b";
+ browser_playlist_prefix = "$2playlist$9 ";
+ selected_item_prefix = "$6";
+ selected_item_suffix = "$9";
+ modified_item_prefix = "$3> $9";
+ song_window_title_format = "{%a - }{%t}|{%f}";
+ browser_sort_mode = "type";
+ browser_sort_format = "{%a - }{%t}|{%f} {%l}";
+ visualizer_data_source = "/tmp/mpd.fifo";
+ visualizer_output_name = "Visualizer feed";
+ visualizer_in_stereo = true;
+ visualizer_type = "spectrum";
+ visualizer_look = "●▮";
+ visualizer_color = "blue, cyan, green, yellow, magenta, red";
+ visualizer_spectrum_smooth_look = true;
+ };
+
+ bindings = [
+ { key = "j"; command = "scroll_down"; }
+ { key = "k"; command = "scroll_up"; }
+ { key = "h"; command = [ "previous_column" "jump_to_parent_directory" ]; }
+ { key = "l"; command = [ "next_column" "enter_directory" "run_action" "play_item" ]; }
+ { key = "u"; command = "page_up"; }
+ { key = "d"; command = "page_down"; }
+ { key = "ctrl-u"; command = "page_up"; }
+ { key = "ctrl-d"; command = "page_down"; }
+ { key = "g"; command = "move_home"; }
+ { key = "G"; command = "move_end"; }
+ { key = "n"; command = "next_found_item"; }
+ { key = "N"; command = "previous_found_item"; }
+ { key = "J"; command = "move_sort_order_down"; }
+ { key = "K"; command = "move_sort_order_up"; }
+ { key = "f"; command = [ "show_browser" "change_browse_mode" ]; }
+ { key = "s"; command = [ "reset_search_engine" "show_search_engine" ]; }
+ { key = "m"; command = "toggle_media_library_columns_mode"; }
+ { key = "x"; command = "delete_playlist_items"; }
+ { key = "U"; command = "update_database"; }
+ { key = "P"; command = "show_playlist"; }
+ { key = "t"; command = "show_tag_editor"; }
+ { key = "v"; command = "show_visualizer"; }
+ { key = "."; command = "show_lyrics"; }
+ { key = "+"; command = "show_clock"; }
+ { key = "="; command = "volume_up"; }
+ ];
+ };
+}
diff --git a/users/tdback/modules/neomutt/default.nix b/users/tdback/modules/neomutt/default.nix
new file mode 100644
index 0000000..243aa6b
--- /dev/null
+++ b/users/tdback/modules/neomutt/default.nix
@@ -0,0 +1,69 @@
+{ pkgs, ... }:
+{
+ programs.neomutt = {
+ enable = true;
+ package = pkgs.neomutt;
+
+ vimKeys = true;
+ sort = "reverse-date";
+
+ checkStatsInterval = 60;
+
+ sidebar = {
+ enable = true;
+ shortPath = true;
+ width = 20;
+ };
+
+ binds = [
+ {
+ map = [ "index" "pager" ];
+ key = "\\Cp";
+ action = "sidebar-prev";
+ }
+ {
+ map = [ "index" "pager" ];
+ key = "\\Cn";
+ action = "sidebar-next";
+ }
+ {
+ map = [ "index" "pager" ];
+ key = "\\Cy";
+ action = "sidebar-open";
+ }
+ ];
+
+ macros = [
+ {
+ map = [ "index" "pager" ];
+ key = "gi";
+ action = "<change-folder>=Inbox<enter>";
+ }
+ {
+ map = [ "index" "pager" ];
+ key = "gs";
+ action = "<change-folder>=Sent<enter>";
+ }
+ {
+ map = [ "index" "pager" ];
+ key = "gd";
+ action = "<change-folder>=Drafts<enter>";
+ }
+ {
+ map = [ "index" "pager" ];
+ key = "gt";
+ action = "<change-folder>=Trash<enter>";
+ }
+ {
+ map = [ "index" "pager" ];
+ key = "ga";
+ action = "<change-folder>=Archive<enter>";
+ }
+ {
+ map = [ "index" ];
+ key = "S";
+ action = "<shell-escape>${pkgs.isync}/bin/mbsync -a<enter>";
+ }
+ ];
+ };
+}
diff --git a/users/tdback/modules/polybar/default.nix b/users/tdback/modules/polybar/default.nix
new file mode 100644
index 0000000..833a260
--- /dev/null
+++ b/users/tdback/modules/polybar/default.nix
@@ -0,0 +1,112 @@
+{ lib, pkgs, ... }:
+{
+ services.polybar = {
+ enable = true;
+ package = pkgs.polybar.override { pulseSupport = true; };
+ script = "polybar main &";
+ settings =
+ let
+ colors = {
+ alert = "#505050";
+ foreground = "#F1F1F1";
+ background = "#050505";
+ background-alt = "#373B41";
+ };
+ in
+ {
+ "bar/main" = {
+ bottom = true;
+ width = "100%";
+ height = "16pt";
+ line.size = "3pt";
+ font = [ "Iosevka Comfy Motion Fixed:size=8" ];
+
+ foreground = "${colors.foreground}";
+ background = "${colors.background}";
+
+ separator = "|";
+ padding = {
+ left = 1;
+ right = 1;
+ };
+
+ module.margin = 1;
+ modules = {
+ left = "bspwm";
+ center = "time";
+ right = "volume cpu memory date";
+ };
+
+ wm.restack = "bspwm";
+ cursor.click = "pointer";
+ };
+
+ "module/bspwm" = {
+ type = "internal/bspwm";
+ pin.workspaces = true;
+ label = {
+ focused = {
+ text = "%index%";
+ foreground = "${colors.foreground}";
+ padding = 1;
+ };
+ occupied = {
+ text = "%index%";
+ foreground = "${colors.alert}";
+ padding = 1;
+ };
+ urgent = {
+ text = "%index%";
+ foreground = "${colors.foreground}";
+ background = "${colors.background-alt}";
+ padding = 1;
+ };
+ empty.text = "";
+ };
+ };
+
+ "module/cpu" = {
+ type = "internal/cpu";
+ interval = 3;
+ label = "CPU %percentage%%";
+ };
+
+ "module/memory" = {
+ type = "internal/memory";
+ interval = 3;
+ label = "RAM %percentage_used%%";
+ };
+
+ "module/volume" = {
+ type = "internal/pulseaudio";
+ label = {
+ volume = "VOL %percentage%%";
+ muted = "VOL 0%";
+ };
+ click.right = "${lib.getExe pkgs.pavucontrol}";
+ };
+
+ "module/time" = {
+ type = "internal/date";
+ interval = 1;
+ label = "%time%";
+ time = "%H:%M";
+ };
+
+ "module/date" = {
+ type = "internal/date";
+ interval = 1;
+ label = "%date%";
+ date = "%m.%d.%Y";
+ };
+
+ "settings" = {
+ screenchange.reload = true;
+ pseudo.transparency = true;
+ };
+ };
+ };
+
+ # Make sure polybar starts only during graphical sessions.
+ systemd.user.services.polybar.Install.WantedBy = [ "graphical-session.target" ];
+}
diff --git a/users/tdback/modules/rofi/default.nix b/users/tdback/modules/rofi/default.nix
new file mode 100644
index 0000000..e3264df
--- /dev/null
+++ b/users/tdback/modules/rofi/default.nix
@@ -0,0 +1,81 @@
+{ config, pkgs, ... }:
+{
+ programs.rofi = {
+ enable = true;
+ package = pkgs.rofi;
+ font = "Iosevka Comfy Motion Fixed 12";
+ location = "center";
+ extraConfig = {
+ modi = "window,run,drun";
+ icon-theme = "Papirus";
+ show-icons = true;
+ display-drun = "";
+ display-window = "";
+ drun-display-format = "{icon} {name}";
+ };
+ theme =
+ let
+ inherit (config.lib.formats.rasi) mkLiteral;
+ in
+ {
+ "*" = {
+ bg = mkLiteral "#050505";
+ bg-alt = mkLiteral "#191919";
+ fg = mkLiteral "#FFFFFF";
+ fg-alt = mkLiteral"#787c99";
+ background-color = mkLiteral "@bg";
+ border = 0;
+ margin = 0;
+ padding = 0;
+ spacing = 0;
+ };
+
+ "window" = {
+ width = mkLiteral "40%";
+ };
+
+ "element" = {
+ padding = 12;
+ text-color = mkLiteral "@fg-alt";
+ };
+
+ "element selected" = {
+ text-color = mkLiteral "@fg";
+ };
+
+ "element-text" = {
+ background-color = mkLiteral "inherit";
+ text-color = mkLiteral "inherit";
+ vertical-align = mkLiteral "0.5";
+ };
+
+ "element-icon" = {
+ size = 38;
+ };
+
+ "entry" = {
+ background-color = mkLiteral "@bg-alt";
+ text-color = mkLiteral "@fg";
+ padding = 14;
+ placeholder = "Search...";
+ };
+
+ "inputbar" = {
+ children = map mkLiteral [ "prompt" "entry" ];
+ };
+
+ "listview" = {
+ columns = 2;
+ lines = 6;
+ background-color = mkLiteral "@bg";
+ };
+
+ "prompt" = {
+ enabled = true;
+ background-color = mkLiteral "@bg-alt";
+ text-color = mkLiteral "@fg";
+ padding = mkLiteral "14 10 0 14";
+ };
+ };
+ };
+}
diff --git a/users/tdback/modules/shell/default.nix b/users/tdback/modules/shell/default.nix
new file mode 100644
index 0000000..be63547
--- /dev/null
+++ b/users/tdback/modules/shell/default.nix
@@ -0,0 +1,59 @@
+{ pkgs, ... }:
+{
+ programs = {
+ zoxide = {
+ enable = true;
+ enableBashIntegration = true;
+ options = [ "--cmd cd" ];
+ };
+
+ bash = {
+ enable = true;
+ historyFile = "~/.bash_history";
+ historyControl = [ "ignoredups" "ignorespace" ];
+ shellOptions = [ "histappend" ];
+ initExtra = ''
+ PS1="
+ \[\e[34m\]\u\[\e[33m\] at \[\e[34m\]\h\[\e[33m\] in \[\e[34m\]\w
+ \[\e[33m\]λ\[\e[0m\] "
+
+ # Set sane options.
+ set -o noclobber
+ set -o vi
+ bind "\C-l":clear-screen
+ bind "\C-p":previous-history
+ bind "\C-n":next-history
+ '';
+
+ profileExtra = ''
+ # Add script directories to PATH.
+ PATH=$PATH:$HOME/scripts
+ PATH=$PATH:$HOME/.local/bin
+
+ # Clean up duplicate entries in PATH while preserving directory order.
+ PATH="$(echo $PATH | tr ':' '\n' | awk '!a[$0]++' | tr '\n' ':' | sed 's/:$//')"
+ '';
+
+ sessionVariables = {
+ BROWSER = "firefox";
+ EDITOR = "vi";
+ KEYTIMEOUT = 1;
+ LC_ALL = "en_US.UTF-8";
+ LESSHISTFILE = "-";
+ MANPAGER = "less -R --use-color -Dd+r -Du+b";
+ };
+
+ shellAliases = {
+ cp = "cp -i";
+ mv = "mv -i";
+ rm = "rm -I";
+ ls = "ls --color=auto";
+ cat = "bat -pp";
+ grep = "grep --color=auto";
+ diff = "diff --color=auto";
+ song = "yt-dlp --continue --no-check-certificate --format=bestaudio -x --add-metadata --audio-format=flac";
+ mkdir = "mkdir -p";
+ };
+ };
+ };
+}
diff --git a/users/tdback/modules/tmux/default.nix b/users/tdback/modules/tmux/default.nix
new file mode 100644
index 0000000..8ac1c74
--- /dev/null
+++ b/users/tdback/modules/tmux/default.nix
@@ -0,0 +1,52 @@
+{ pkgs, ... }:
+{
+ programs.tmux = {
+ enable = true;
+ package = pkgs.tmux;
+ terminal = "tmux-256color";
+ escapeTime = 0;
+ baseIndex = 0;
+ historyLimit = 10000;
+ mouse = true;
+ clock24 = true;
+ secureSocket = true;
+ aggressiveResize = true;
+ prefix = "C-t";
+ extraConfig = ''
+ # Prevent detaching from tmux when closing a session.
+ set -g detach-on-destroy off
+
+ # Kill the current session.
+ bind X kill-session
+
+ # Splitting panes.
+ unbind v
+ unbind h
+ unbind %
+ unbind '"'
+ bind v split-window -h -c "#{pane_current_path}" # split vertically
+ bind h split-window -v -c "#{pane_current_path}" # split horizontally
+
+ # Navigating panes.
+ bind ^ last-window
+ bind C-h select-pane -L
+ bind C-j select-pane -D
+ bind C-k select-pane -U
+ bind C-l select-pane -R
+
+ # Copy mode movements.
+ set-window-option -g mode-keys vi
+ unbind -T copy-mode-vi Space;
+ unbind -T copy-mode-vi Enter;
+ bind -T copy-mode-vi v send-keys -X begin-selection
+ bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "xclip -in -selection clipboard"
+
+ # Customizing status bar.
+ set -g status-position bottom
+ set -g status-style "bg=#050505 fg=#C5C8C6"
+ set -g status-right ""
+ setw -g window-status-current-format " #I#[fg=colour250]:#[fg=colour255]#W#[fg=colour50]#F"
+ setw -g window-status-format " #I#[fg=colour237]:#[fg=colour250]#W#[fg=colour244]#F"
+ '';
+ };
+}
diff --git a/users/tdback/modules/x11/default.nix b/users/tdback/modules/x11/default.nix
new file mode 100644
index 0000000..41025a4
--- /dev/null
+++ b/users/tdback/modules/x11/default.nix
@@ -0,0 +1,94 @@
+{ pkgs, ... }:
+{
+ xsession.windowManager.bspwm = {
+ enable = true;
+ package = pkgs.bspwm;
+ settings = let color = "#3B4252"; in {
+ window_gap = 0;
+ top_padding = 0;
+ bottom_padding = 0;
+ right_padding = 0;
+ left_padding = 0;
+ top_monocle_padding = 0;
+ bottom_monocle_padding = 0;
+ right_monocle_padding = 0;
+ left_monocle_padding = 0;
+ split_ratio = 0.5;
+ borderless_monocle = true;
+ gapless_monocle = true;
+ normal_border_color = color;
+ active_border_color = color;
+ focused_border_color = color;
+ };
+
+ rules = {
+ "Zathura".state = "tiled";
+ };
+
+ startupPrograms = [
+ "${pkgs.xorg.setxkbmap}/bin/setxkbmap -layout us"
+ "${pkgs.xorg.xsetroot}/bin/xsetroot -cursor_name left_ptr"
+ "${pkgs.xorg.xset}/bin/xset r rate 350 40"
+ "~/.fehbg"
+ ];
+
+ extraConfig = ''
+ ${pkgs.bspwm}/bin/bspc monitor -d 1 2 3 4 5 6 7 8 9
+ '';
+ };
+
+ services.sxhkd = {
+ enable = true;
+ package = pkgs.sxhkd;
+ keybindings = {
+ # Program hotkeys.
+ "alt + Tab" = "rofi -show window";
+ "super + r" = "rofi -show drun";
+ "super + x" = "alacritty";
+ "super + b" = "firefox";
+ "super + p" = "flameshot full -p $HOME/.local/screenshots";
+ "super + shift + p" = "flameshot gui -p $HOME/.local/screenshots";
+ "super + Escape" = "systemctl --user restart polybar";
+ "super + alt + {q,r}" = "bspc {quit,wm -r}";
+
+ # Function hotkeys.
+ "XF86AudioPrev" = "mpc prev";
+ "XF86AudioNext" = "mpc next";
+ "XF86AudioPlay" = "mpc toggle";
+ "XF86AudioLowerVolume" = "pamixer -d 5";
+ "XF86AudioRaiseVolume" = "pamixer -i 5";
+ "XF86AudioMute" = "pamixer -t";
+
+ # Manipulate window manager.
+ "super + q" = "bspc node -{c,k}";
+ "super + f" = "bspc node focused.tiled -t fullscreen";
+ "super + t" = "bspc node focused.fullscreen -t tiled";
+ "super + shift + f" = "bspc node focused.tiled -t floating";
+ "super + shift + t" = "bspc node focused.floating -t tiled";
+ "super + {_,shift + }{h,j,k,l}" = "bspc node -{f,s} {west,south,north,east}";
+ "super + {_,shift}c" = "bspc node -f {next,prev}.local.!hidden.window";
+ "super + bracket{left,right}" = "bspc desktop -f {prev,next}.local";
+ "super + {grave,Tab}" = "bspc {node,desktop} -f last";
+ "super + {o,i}" = "bspc wm -h off; bspc node {older,newer} -f; bspc wm -h on";
+ "super + {_,shift + }{1-9,0}" = "bspc {desktop -f, node -d} '^{1-9,10}'";
+ "super + alt + {h,j,k,l}" = "bspc node -z {left -20 0, bottom 0 20, top 0 -20, right 20 0}";
+ "super + alt + shift {h,j,k,l}" = "bspc node -z {right -20 0, top 0 20, bottom 0 -20, left 20 0}";
+ "super + {Left,Down,Up,Right}" = "bspc node -v {-20 0,0 20,0 -20,20 0}";
+ };
+ };
+
+ # Generate X11 init scripts.
+ home.file = {
+ ".xinitrc".text = ''
+ [ -f ~/.xprofile ] && . ~/.xprofile
+ [ -f ~/.Xresources ] && xrdb -merge ~/.Xresources
+ exec bspwm
+ '';
+ ".xprofile".text = ''
+ xrandr --output DP-0 --primary --mode 1920x1080 --rotate normal --rate 165
+ '';
+ ".Xresources".text = ''
+ Xcursor.size: 24
+ '';
+ };
+}