From 75532a931c96d0f05f40faa088fdca9c5154b7d4 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sat, 18 Apr 2026 16:28:25 -0400 Subject: [PATCH] treewide: initial commit --- LICENSE | 165 +++++++++++++ flake.lock | 365 ++++++++++++++++++++++++++++ flake.nix | 56 +++++ nixos/common.nix | 120 +++++++++ nixos/default.nix | 35 +++ nixos/hardware.nix | 26 ++ nixos/hosts/tuxcord-ca/default.nix | 8 + nixos/hosts/tuxcord-ca/hardware.nix | 7 + nixos/hosts/tuxcord-ca/storage.nix | 37 +++ nixos/impermanence.nix | 94 +++++++ nixos/modules/default.nix | 9 + nixos/modules/fail2ban.nix | 41 ++++ nixos/modules/host.nix | 15 ++ nixos/modules/snapper.nix | 61 +++++ nixos/modules/substituters.nix | 43 ++++ nixos/modules/sysctl.nix | 27 ++ nixos/programs.nix | 101 ++++++++ nixos/users.nix | 27 ++ 18 files changed, 1237 insertions(+) create mode 100644 LICENSE create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nixos/common.nix create mode 100644 nixos/default.nix create mode 100644 nixos/hardware.nix create mode 100644 nixos/hosts/tuxcord-ca/default.nix create mode 100644 nixos/hosts/tuxcord-ca/hardware.nix create mode 100644 nixos/hosts/tuxcord-ca/storage.nix create mode 100644 nixos/impermanence.nix create mode 100644 nixos/modules/default.nix create mode 100644 nixos/modules/fail2ban.nix create mode 100644 nixos/modules/host.nix create mode 100644 nixos/modules/snapper.nix create mode 100644 nixos/modules/substituters.nix create mode 100644 nixos/modules/sysctl.nix create mode 100644 nixos/programs.nix create mode 100644 nixos/users.nix diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0a04128 --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..46851e6 --- /dev/null +++ b/flake.lock @@ -0,0 +1,365 @@ +{ + "nodes": { + "agenix": { + "inputs": { + "darwin": "darwin", + "home-manager": "home-manager", + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems" + }, + "locked": { + "lastModified": 1770165109, + "narHash": "sha256-9VnK6Oqai65puVJ4WYtCTvlJeXxMzAp/69HhQuTdl/I=", + "owner": "ryantm", + "repo": "agenix", + "rev": "b027ee29d959fda4b60b57566d64c98a202e0feb", + "type": "github" + }, + "original": { + "owner": "ryantm", + "repo": "agenix", + "type": "github" + } + }, + "darwin": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1744478979, + "narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "43975d782b418ebf4969e9ccba82466728c2851b", + "type": "github" + }, + "original": { + "owner": "lnl7", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "flake-compat": { + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1775087534, + "narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "git-hooks-nix": { + "inputs": { + "flake-compat": [ + "nix-super" + ], + "gitignore": [ + "nix-super" + ], + "nixpkgs": [ + "nix-super", + "nixpkgs" + ], + "nixpkgs-stable": [ + "nix-super", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1734279981, + "narHash": "sha256-NdaCraHPp8iYMWzdXAt5Nv6sA3MUzlCiGiR586TCwo0=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "aa9f40c906904ebd83da78e7f328cd8aeaeae785", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1745494811, + "narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "impermanence", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1768598210, + "narHash": "sha256-kkgA32s/f4jaa4UG+2f8C225Qvclxnqs76mf8zvTVPg=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "c47b2cc64a629f8e075de52e4742de688f930dc6", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "impermanence": { + "inputs": { + "home-manager": "home-manager_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1769548169, + "narHash": "sha256-03+JxvzmfwRu+5JafM0DLbxgHttOQZkUtDWBmeUkN8Y=", + "owner": "nix-community", + "repo": "impermanence", + "rev": "7b1d382faf603b6d264f58627330f9faa5cba149", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "impermanence", + "type": "github" + } + }, + "nix-alien": { + "inputs": { + "flake-compat": "flake-compat", + "nix-index-database": [ + "nix-index-database" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1776242217, + "narHash": "sha256-TRts0fKUPFcf1i6rZHFGUDTfti/x3oKEg/CqsPRpSgs=", + "owner": "thiagokokada", + "repo": "nix-alien", + "rev": "4c5e52dda0d6ab3de814e364046769321d3e1021", + "type": "github" + }, + "original": { + "owner": "thiagokokada", + "repo": "nix-alien", + "type": "github" + } + }, + "nix-index-database": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1775970782, + "narHash": "sha256-7jt9Vpm48Yy5yAWigYpde+HxtYEpEuyzIQJF4VYehhk=", + "owner": "nix-community", + "repo": "nix-index-database", + "rev": "bedba5989b04614fc598af9633033b95a937933f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-index-database", + "type": "github" + } + }, + "nix-super": { + "inputs": { + "flake-compat": "flake-compat_2", + "flake-parts": [ + "flake-parts" + ], + "git-hooks-nix": "git-hooks-nix", + "nixpkgs": "nixpkgs", + "nixpkgs-23-11": "nixpkgs-23-11", + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "lastModified": 1775685436, + "narHash": "sha256-a2/HpvUuKZsFuJ/O4d44c4aE0EFxdhBhJri/q/B9Q4U=", + "owner": "privatevoid-net", + "repo": "nix-super", + "rev": "89b3e67eec02a5b83045613601c920fd3916778d", + "type": "github" + }, + "original": { + "owner": "privatevoid-net", + "repo": "nix-super", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1771903837, + "narHash": "sha256-jEA8WggGKtMFeNeCKq3NK8cLEjJmG6/RLUElYYbBZ0E=", + "rev": "e764fc9a405871f1f6ca3d1394fb422e0a0c3951", + "type": "tarball", + "url": "https://releases.nixos.org/nixos/25.11/nixos-25.11.6495.e764fc9a4058/nixexprs.tar.xz" + }, + "original": { + "type": "tarball", + "url": "https://channels.nixos.org/nixos-25.11/nixexprs.tar.xz" + } + }, + "nixpkgs-23-11": { + "locked": { + "lastModified": 1717159533, + "narHash": "sha256-oamiKNfr2MS6yH64rUn99mIZjc45nGJlj9eGth/3Xuw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1774748309, + "narHash": "sha256-+U7gF3qxzwD5TZuANzZPeJTZRHS29OFQgkQ2kiTJBIQ=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "333c4e0545a6da976206c74db8773a1645b5870a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1776434932, + "narHash": "sha256-gyqXNMgk3sh+ogY5svd2eNLJ6oEwzbAeaoBrrxD0lKk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c7f47036d3df2add644c46d712d14262b7d86c0c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "agenix": "agenix", + "flake-parts": "flake-parts", + "impermanence": "impermanence", + "nix-alien": "nix-alien", + "nix-index-database": "nix-index-database", + "nix-super": "nix-super", + "nixpkgs": "nixpkgs_2" + } + }, + "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..aa7fee4 --- /dev/null +++ b/flake.nix @@ -0,0 +1,56 @@ +{ + inputs = { + agenix = { + url = "github:ryantm/agenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + flake-parts.url = "github:hercules-ci/flake-parts"; + + impermanence = { + url = "github:nix-community/impermanence"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + nix-alien = { + url = "github:thiagokokada/nix-alien"; + inputs = { + nix-index-database.follows = "nix-index-database"; + nixpkgs.follows = "nixpkgs"; + }; + }; + + nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; + + nix-super = { + url = "github:privatevoid-net/nix-super"; + inputs.flake-parts.follows = "flake-parts"; + }; + }; + + outputs = + inputs@{ flake-parts, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ + ./nixos + ]; + + perSystem = + { pkgs, ... }: + { + formatter = pkgs.nixfmt; + }; + + systems = [ + "x86_64-linux" + "aarch64-linux" + ]; + }; + + description = "tuxcord.net NixOS configuration"; +} diff --git a/nixos/common.nix b/nixos/common.nix new file mode 100644 index 0000000..4a89b76 --- /dev/null +++ b/nixos/common.nix @@ -0,0 +1,120 @@ +{ + inputs', + inputs, + lib, + pkgs, + self, + ... +}: +let + inherit (lib) + mkDefault + mkIf + ; +in +{ + imports = with inputs; [ + agenix.nixosModules.default + impermanence.nixosModules.default + nix-index-database.nixosModules.nix-index + + ./hardware.nix + ./impermanence.nix + ./modules + ./programs.nix + ./users.nix + ]; + + nix = { + package = inputs'.nix-super.packages.default; + + settings = { + auto-optimise-store = true; + experimental-features = [ + "ca-derivations" + "flakes" + "nix-command" + ]; + log-lines = 500; + show-trace = true; + trusted-users = [ + "@wheel" + ]; + + min-free = 10 * 1024 * 1024 * 1024; + max-free = 50 * 1024 * 1024 * 1024; + }; + + registry = + let + mappedRegistry = lib.mapAttrs' (name: flake: lib.nameValuePair name { inherit flake; }) inputs; + in + mappedRegistry // { default = mappedRegistry.nixpkgs; }; + + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 90d"; + }; + }; + + boot = { + loader = { + grub = { + enable = mkDefault true; + efiSupport = true; + efiInstallAsRemovable = true; + device = "nodev"; + splashImage = null; + configurationLimit = 100; + }; + timeout = 5; + }; + + kernelParams = [ + "boot.shell_on_fail" + "zswap.enabled=0" + ]; + + binfmt = { + emulatedSystems = mkIf pkgs.stdenv.hostPlatform.isx86 [ "aarch64-linux" ]; + preferStaticEmulators = true; + }; + + supportedFilesystems = [ "nfs" ]; + }; + + networking = { + networkmanager.enable = true; + + firewall = { + enable = true; + + allowedTCPPorts = [ + 22 + ]; + }; + }; + + services = { + openssh.enable = true; + }; + + virtualisation.podman.enable = true; + + zramSwap = { + enable = true; + + algorithm = mkDefault "lzo-rle"; + memoryPercent = 100; + }; + + nixpkgs.config.allowUnfree = true; + + environment.etc."nixos/current".source = lib.cleanSource ./..; + + system = { + configurationRevision = self.rev or self.dirtyRev; + stateVersion = "25.11"; + }; +} diff --git a/nixos/default.nix b/nixos/default.nix new file mode 100644 index 0000000..903398f --- /dev/null +++ b/nixos/default.nix @@ -0,0 +1,35 @@ +{ + inputs, + self, + withSystem, + ... +}: +let + mkSystem = + name: system: + withSystem system ( + { inputs', self', ... }: + inputs.nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { + inherit + inputs + inputs' + self + self' + ; + }; + + modules = [ + "${self}/nixos/common.nix" + "${self}/nixos/hosts/${name}" + { host = { inherit name; }; } + ]; + } + ); +in +{ + flake.nixosConfigurations = { + tuxcord-ca = mkSystem "tuxcord-ca" "x86_64-linux"; + }; +} diff --git a/nixos/hardware.nix b/nixos/hardware.nix new file mode 100644 index 0000000..a106eb5 --- /dev/null +++ b/nixos/hardware.nix @@ -0,0 +1,26 @@ +{ + boot = { + initrd.availableKernelModules = [ + "nvme" + "usbhid" + "ahci" + "ehci_pci" + "rtsx_pci_sdmmc" + "sd_mod" + "sr_mod" + "usb_storage" + "virtio_blk" + "virtio_pci" + "virtio_scsi" + "xhci_pci" + ]; + + kernelModules = [ "kvm-intel" ]; + }; + + hardware = { + i2c.enable = true; + + enableRedistributableFirmware = true; + }; +} diff --git a/nixos/hosts/tuxcord-ca/default.nix b/nixos/hosts/tuxcord-ca/default.nix new file mode 100644 index 0000000..95738a9 --- /dev/null +++ b/nixos/hosts/tuxcord-ca/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./hardware.nix + ./storage.nix + ]; + + time.timeZone = "Canada/Eastern"; +} diff --git a/nixos/hosts/tuxcord-ca/hardware.nix b/nixos/hosts/tuxcord-ca/hardware.nix new file mode 100644 index 0000000..f472bd7 --- /dev/null +++ b/nixos/hosts/tuxcord-ca/hardware.nix @@ -0,0 +1,7 @@ +{ + boot.initrd.availableKernelModules = [ + "ata_piix" + "sr_mod" + "xen_blkfront" + ]; +} diff --git a/nixos/hosts/tuxcord-ca/storage.nix b/nixos/hosts/tuxcord-ca/storage.nix new file mode 100644 index 0000000..f26d226 --- /dev/null +++ b/nixos/hosts/tuxcord-ca/storage.nix @@ -0,0 +1,37 @@ +{ + fileSystems = + let + defaultOptions = [ "compress=zstd" ]; + in + { + "/boot" = { + device = "/dev/xvda1"; + fsType = "vfat"; + options = [ "umask=0077" ]; + }; + + "/" = { + device = "/dev/xvda2"; + fsType = "btrfs"; + options = [ "subvol=@" ] ++ defaultOptions; + }; + + "/nix" = { + device = "/dev/xvda2"; + fsType = "btrfs"; + options = [ "subvol=@nix" ] ++ defaultOptions; + }; + + "/home" = { + device = "/dev/xvda2"; + fsType = "btrfs"; + options = [ "subvol=@home" ] ++ defaultOptions; + }; + + "/persist" = { + device = "/dev/xvda2"; + fsType = "btrfs"; + options = [ "subvol=@persist" ] ++ defaultOptions; + }; + }; +} diff --git a/nixos/impermanence.nix b/nixos/impermanence.nix new file mode 100644 index 0000000..85d252f --- /dev/null +++ b/nixos/impermanence.nix @@ -0,0 +1,94 @@ +{ + config, + lib, + pkgs, + ... +}: +{ + boot.initrd.systemd = { + extraBin = { + "mkdir" = "${pkgs.coreutils}/bin/mkdir"; + "date" = "${pkgs.coreutils}/bin/date"; + "stat" = "${pkgs.coreutils}/bin/stat"; + "mv" = "${pkgs.coreutils}/bin/mv"; + "find" = lib.getExe pkgs.findutils; + "btrfs" = lib.getExe pkgs.btrfs-progs; + }; + + services.impermanence-btrfs-rolling-root = { + unitConfig.DefaultDependencies = false; + serviceConfig.Type = "oneshot"; + + requiredBy = [ "initrd.target" ]; + before = [ "sysroot.mount" ]; + requires = [ "initrd-root-device.target" ]; + after = [ + "initrd-root-device.target" + "local-fs-pre.target" + ]; + + script = '' + mkdir /impermanence_tmp + mount /dev/disk/by-label/${config.host.name} /impermanence_tmp || mount /dev/disk/by-label/NIXOS_SD /impermanence_tmp + + timestamp=$(date --date="@$(stat -c %Y /impermanence_tmp/@)" "+%Y-%m-%d_%H:%M:%S") + if [[ -e /impermanence_tmp/@ ]]; then + mkdir -p /impermanence_tmp/roots + mv /impermanence_tmp/@ "/impermanence_tmp/roots/$timestamp" + fi + + delete_subvolume_recursively() { + IFS=$'\n' + for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do + delete_subvolume_recursively "/impermanence_tmp/$i" + done + btrfs subvolume delete "$1" + } + + for i in $(find /impermanence_tmp/roots/ -maxdepth 1 -mtime +30); do + delete_subvolume_recursively "$i" + done + + btrfs subvolume create /impermanence_tmp/@ + umount /impermanence_tmp + ''; + }; + }; + + fileSystems."/persist".neededForBoot = true; + + environment.persistence."/persist" = { + enable = true; + hideMounts = true; + + directories = [ + "/etc/ssh" + "/export" + "/mnt" + "/var/db/sudo/lectured" + "/var/lib/nfs" + "/var/lib/nixos" + "/var/lib/systemd/coredump" + "/var/log" + ]; + files = [ + "/etc/machine-id" + ]; + }; + + services.openssh.hostKeys = + let + statePath = config.environment.persistence."/persist".persistentStoragePath + "/etc/ssh"; + in + [ + { + path = statePath + "/ssh_host_rsa_key"; + type = "rsa"; + bits = 4096; + } + { + path = statePath + "/ssh_host_ed25519_key"; + type = "ed25519"; + } + ]; +} diff --git a/nixos/modules/default.nix b/nixos/modules/default.nix new file mode 100644 index 0000000..a52fff6 --- /dev/null +++ b/nixos/modules/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./fail2ban.nix + ./sysctl.nix + ./host.nix + ./snapper.nix + ./substituters.nix + ]; +} diff --git a/nixos/modules/fail2ban.nix b/nixos/modules/fail2ban.nix new file mode 100644 index 0000000..676db7e --- /dev/null +++ b/nixos/modules/fail2ban.nix @@ -0,0 +1,41 @@ +{ config, lib, ... }: +let + cfg = config.fail2ban; + inherit (lib) + mkEnableOption + mkIf + ; +in +{ + options.fail2ban = { + enable = mkEnableOption "" // { + default = true; + }; + }; + + config = mkIf cfg.enable { + networking.firewall.logRefusedConnections = false; + + services.fail2ban = { + enable = true; + + maxretry = 6; + bantime = "5m"; + bantime-increment = { + enable = true; + multipliers = "1 2 6 24 288 864 2016 8640"; + rndtime = "5m"; + }; + + jails = { + DEFAULT.settings.findtime = "15m"; + + sshd = lib.mkForce '' + enabled = true + mode = aggressive + port = ${lib.strings.concatMapStringsSep "," toString config.services.openssh.ports} + ''; + }; + }; + }; +} diff --git a/nixos/modules/host.nix b/nixos/modules/host.nix new file mode 100644 index 0000000..ef7fa4b --- /dev/null +++ b/nixos/modules/host.nix @@ -0,0 +1,15 @@ +{ config, lib, ... }: +let + cfg = config.host; + inherit (lib) mkOption types; +in +{ + options.host = { + name = mkOption { type = types.str; }; + }; + + config = { + environment.variables.HOSTNAME = cfg.name; + networking.hostName = cfg.name; + }; +} diff --git a/nixos/modules/snapper.nix b/nixos/modules/snapper.nix new file mode 100644 index 0000000..f766396 --- /dev/null +++ b/nixos/modules/snapper.nix @@ -0,0 +1,61 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.snapper; + inherit (lib) + mkEnableOption + mkOption + mkIf + types + ; +in +{ + options.snapper = { + enable = mkEnableOption "" // { + default = true; + }; + + interval = mkOption { + default = "daily"; + type = types.str; + }; + }; + + config = mkIf cfg.enable { + services.snapper = { + snapshotInterval = cfg.interval; + + configs = { + home = { + SUBVOLUME = "/home"; + TIMELINE_CREATE = true; + TIMELINE_CLEANUP = true; + + TIMELINE_LIMIT_HOURLY = 24; + TIMELINE_LIMIT_DAILY = 7; + TIMELINE_LIMIT_WEEKLY = 0; + TIMELINE_LIMIT_MONTHLY = 3; + TIMELINE_LIMIT_YEARLY = 0; + }; + + persist = { + SUBVOLUME = "/persist"; + TIMELINE_CREATE = true; + TIMELINE_CLEANUP = true; + + TIMELINE_LIMIT_HOURLY = 24; + TIMELINE_LIMIT_DAILY = 7; + TIMELINE_LIMIT_WEEKLY = 0; + TIMELINE_LIMIT_MONTHLY = 3; + TIMELINE_LIMIT_YEARLY = 0; + }; + }; + }; + + environment.systemPackages = [ pkgs.snapper ]; + }; +} diff --git a/nixos/modules/substituters.nix b/nixos/modules/substituters.nix new file mode 100644 index 0000000..ab80fc4 --- /dev/null +++ b/nixos/modules/substituters.nix @@ -0,0 +1,43 @@ +{ + config, + lib, + ... +}: +let + cfg = config.substituters; + inherit (lib) + mkEnableOption + mkIf + optionals + ; +in +{ + options.substituters = { + enable = mkEnableOption "" // { + default = true; + }; + + garnix = mkEnableOption "" // { + default = true; + }; + + nix-community = mkEnableOption "" // { + default = true; + }; + }; + + config = mkIf cfg.enable { + nix.settings = { + substituters = + (optionals cfg.garnix [ "https://cache.garnix.io" ]) + ++ (optionals cfg.nix-community [ "https://nix-community.cachix.org" ]); + trusted-public-keys = + (optionals cfg.garnix [ + "cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g=" + ]) + ++ (optionals cfg.nix-community [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + ]); + }; + }; +} diff --git a/nixos/modules/sysctl.nix b/nixos/modules/sysctl.nix new file mode 100644 index 0000000..d06b68e --- /dev/null +++ b/nixos/modules/sysctl.nix @@ -0,0 +1,27 @@ +{ + config, + lib, + ... +}: +let + cfg = config.sysctl; + inherit (lib) + mkEnableOption + mkIf + ; +in +{ + options.sysctl = { + enable = mkEnableOption "" // { + default = true; + }; + }; + + config = mkIf cfg.enable { + boot.kernel.sysctl = { + "vm.page-cluster" = 0; + "vm.swappiness" = 100; + "vm.watermark_boost_factor" = 1; + }; + }; +} diff --git a/nixos/programs.nix b/nixos/programs.nix new file mode 100644 index 0000000..2995ae1 --- /dev/null +++ b/nixos/programs.nix @@ -0,0 +1,101 @@ +{ + inputs', + lib, + pkgs, + ... +}: +let + inherit (lib) mkForce; +in +{ + programs = { + fish = { + enable = true; + shellAliases = mkForce { }; + }; + + zsh.enable = true; + + git = { + enable = true; + lfs.enable = true; + }; + + gnupg.agent.enable = true; + + ssh.startAgent = true; + + nix-index-database.comma.enable = true; + + nix-index = { + enableBashIntegration = false; + enableFishIntegration = false; + enableZshIntegration = false; + }; + + nix-ld.enable = true; + }; + + environment.systemPackages = with pkgs; [ + atop + bat + btdu + compsize + croc + deadnix + delta + difftastic + dnsutils + doggo + duf + dust + efibootmgr + eza + fastfetch + fd + file + gcc + gnumake + gnupg + htop + hwatch + inputs'.agenix.packages.default + inputs'.nix-alien.packages.default + inputs'.nix-super.packages.default + inxi + jq + jujutsu + killall + lsof + man-pages + multipath-tools + ncdu + neovim + nh + nix-output-monitor + openssl + parted + perf + pinentry-curses + procs + progress + pstree + pv + python3 + python3Packages.btrfs + ripgrep + screen + smartmontools + smem + socat + sshfs + statix + sysstat + tcpdump + tmux + unzip + vgrep + vim + whois + ]; +} diff --git a/nixos/users.nix b/nixos/users.nix new file mode 100644 index 0000000..9cba1a7 --- /dev/null +++ b/nixos/users.nix @@ -0,0 +1,27 @@ +{ pkgs, ... }: +{ + users.users = + let + adminGroups = [ + "adm" + "named" + "networkmanager" + "nginx" + "tuxcord" + "wheel" + ]; + in + { + error = { + isNormalUser = true; + shell = pkgs.fish; + extraGroups = adminGroups; + }; + + javalsai = { + isNormalUser = true; + shell = pkgs.zsh; + extraGroups = adminGroups; + }; + }; +}