commit 120dbdbc642afb2a5fb320d1df0af7329ea2d802 Author: root Date: Mon Dec 22 16:46:52 2025 -0300 initial commit diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..3f58548 --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,9 @@ +keys: + - &root age1y0tj3kt67pfnj38t9c8g2ghry3a0mhcq8rrqv5xr4jekwepxaelqzu3dkf + - &user age16v8w7q4wmn22hhakq2uzaus2508rhldm7lcwh0kukshzjzyhuqesqz44ze +creation_rules: + - path_regex: secrets/[^/]+\.yaml$ + key_groups: + - age: + - *root + - *user diff --git a/configuration.nix b/configuration.nix new file mode 100644 index 0000000..0b4d9ff --- /dev/null +++ b/configuration.nix @@ -0,0 +1,143 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page, on +# https://search.nixos.org/options and in the NixOS manual (`nixos-help`). + +{ + config, + lib, + pkgs, + hostname, + ... +}: +{ + sops.age.keyFile = "/.persist/root/.config/sops/age/keys.txt"; + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + + boot.initrd.systemd.enable = true; + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + # Set your time zone. + time.timeZone = "America/Sao_Paulo"; + + # Select internationalisation properties. + i18n.defaultLocale = "en_US.UTF-8"; + #console = { + # # font = "Lat2-Terminus16"; + # keyMap = "us"; + # useXkbConfig = true; # use xkb.options in tty. + #}; + + # services.xserver.xkb.layout = "us"; + # services.xserver.xkb.options = "eurosign:e,caps:escape"; + services.printing.enable = true; + + services = { + xserver.xkb = { + layout = "us"; + variant = "altgr-intl"; + }; + pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + # jack.enable = true; + }; + xserver.videoDrivers = [ + "nvidia" + "amdgpu" + ]; + logind.settings.Login = { + HandlePowerKey = "ignore"; + HandlePowerKeyLongPress = "ignore"; + HandleRebootKey = "ignore"; + HandleRebootKeyLongPress = "ignore"; + HandleHibernateKey = "ignore"; + HandleHibernateKeyLongPress = "ignore"; + }; + getty = { + autologinUser = "user"; + autologinOnce = true; + }; + # greetd = { + # enable = true; + # settings = rec { + # initial_session = { + # command = "${pkgs.niri}/bin/niri-session"; + # user = "user"; + # }; + # default_session = initial_session; + # }; + # }; + tailscale.enable = true; + }; + + # systemd.services.greetd.serviceConfig = { + # Type = "idle"; + # StandardInput = "tty"; + # StandardOutput = "tty"; + # StandardError = "journal"; + # TTYReset = true; + # TTYVHangup = true; + # TTYVTDisallocate = true; + # Restart = "no"; + # }; + + hardware = { + graphics = { + enable = true; + enable32Bit = true; + }; + nvidia = { + modesetting.enable = true; + powerManagement.enable = false; + powerManagement.finegrained = false; + open = true; + nvidiaSettings = false; + package = config.boot.kernelPackages.nvidiaPackages.stable; + }; + bluetooth = { + enable = true; + powerOnBoot = true; + settings = { + General = { + Enable = "Source,Sink,Media,Socket"; + }; + }; + }; + }; + + xdg.portal = { + enable = true; + xdgOpenUsePortal = true; + # config.common.default = [ "*" ]; + extraPortals = [ + pkgs.xdg-desktop-portal-gnome + # pkgs.gnome-keyring + pkgs.xdg-desktop-portal-gtk + ]; + }; + + qt = { + enable = true; + }; + + fonts.packages = with pkgs; [ + fira-code-symbols + nerd-fonts.monaspace + ]; + + environment.sessionVariables = { + NIXOS_OZONE_WL = "1"; + EDITOR = "nvim"; + QT_FONT_DPI = "144"; + }; + + system.stateVersion = "25.11"; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..6811064 --- /dev/null +++ b/flake.lock @@ -0,0 +1,320 @@ +{ + "nodes": { + "disko": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1746728054, + "narHash": "sha256-eDoSOhxGEm2PykZFa/x9QG5eTH0MJdiJ9aR00VAofXE=", + "owner": "nix-community", + "repo": "disko", + "rev": "ff442f5d1425feb86344c028298548024f21256d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "latest", + "repo": "disko", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "neovim-nightly-overlay", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1765835352, + "narHash": "sha256-XswHlK/Qtjasvhd1nOa1e8MgZ8GS//jBoTqWtrS1Giw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "a34fae9c08a15ad73f295041fec82323541400a9", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": [ + "nur", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1733312601, + "narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1765980955, + "narHash": "sha256-rB45jv4uwC90vM9UZ70plfvY/2Kdygs+zlQ07dGQFk4=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "89c9508bbe9b40d36b3dc206c2483ef176f15173", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "impermanence": { + "locked": { + "lastModified": 1737831083, + "narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=", + "owner": "nix-community", + "repo": "impermanence", + "rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "impermanence", + "type": "github" + } + }, + "microvm": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "spectrum": "spectrum" + }, + "locked": { + "lastModified": 1766005889, + "narHash": "sha256-UCFkQ37BKDmPEHDkW1BaqJo6AZFoVcogtuyxTg4/a8M=", + "owner": "microvm-nix", + "repo": "microvm.nix", + "rev": "bb9e99bdb3662354299605cc1a75a2b1a86bd29a", + "type": "github" + }, + "original": { + "owner": "microvm-nix", + "repo": "microvm.nix", + "type": "github" + } + }, + "neovim-nightly-overlay": { + "inputs": { + "flake-parts": "flake-parts", + "neovim-src": "neovim-src", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1766102654, + "narHash": "sha256-F2g1gDd88D5KI6j2YIfXn0Vcug+wNqcwFyKWQ/CnPUY=", + "owner": "nix-community", + "repo": "neovim-nightly-overlay", + "rev": "f5c873a02a0607bf5847d85af629dbb86dd75f4e", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "neovim-nightly-overlay", + "type": "github" + } + }, + "neovim-src": { + "flake": false, + "locked": { + "lastModified": 1766102038, + "narHash": "sha256-17Rz4usR1sLsj0IhMU+GuVViwqRmgDOHGyaOAhLfJis=", + "owner": "neovim", + "repo": "neovim", + "rev": "04357f2eff750ca7cb32f19d43bf7dd64249a0f9", + "type": "github" + }, + "original": { + "owner": "neovim", + "repo": "neovim", + "type": "github" + } + }, + "niri-branch": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1766290957, + "narHash": "sha256-BW0AVMiN2juvEiUdu6MpTwjQKWg/jdoz30ecwacy1sQ=", + "owner": "argosnothing", + "repo": "niri", + "rev": "0cb2199a527892d73ec749a7ed4f113b9d1c8299", + "type": "github" + }, + "original": { + "owner": "argosnothing", + "ref": "hidden-workspaces", + "repo": "niri", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1766025857, + "narHash": "sha256-Lav5jJazCW4mdg1iHcROpuXqmM94BWJvabLFWaJVJp0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "def3da69945bbe338c373fddad5a1bb49cf199ce", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1765779637, + "narHash": "sha256-KJ2wa/BLSrTqDjbfyNx70ov/HdgNBCBBSQP3BIzKnv4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "1306659b587dc277866c7b69eb97e5f07864d8c4", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1766070988, + "narHash": "sha256-G/WVghka6c4bAzMhTwT2vjLccg/awmHkdKSd2JrycLc=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "c6245e83d836d0433170a16eb185cefe0572f8b8", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nur": { + "inputs": { + "flake-parts": "flake-parts_2", + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1766201826, + "narHash": "sha256-j9CFs4N5z4sFnAwiuGoAZk6t9eEGF4Ukb/VFqsZcnOY=", + "owner": "nix-community", + "repo": "NUR", + "rev": "4479648d80a1650a0338d79fd3ed9f02ec662d9c", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "NUR", + "type": "github" + } + }, + "root": { + "inputs": { + "disko": "disko", + "home-manager": "home-manager", + "impermanence": "impermanence", + "microvm": "microvm", + "neovim-nightly-overlay": "neovim-nightly-overlay", + "niri-branch": "niri-branch", + "nixpkgs": "nixpkgs_2", + "nur": "nur", + "sops-nix": "sops-nix" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "niri-branch", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1757989933, + "narHash": "sha256-9cpKYWWPCFhgwQTww8S94rTXgg8Q8ydFv9fXM6I8xQM=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "8249aa3442fb9b45e615a35f39eca2fe5510d7c3", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1765836173, + "narHash": "sha256-hWRYfdH2ONI7HXbqZqW8Q1y9IRbnXWvtvt/ONZovSNY=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "443a7f2e7e118c4fc63b7fae05ab3080dd0e5c63", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + }, + "spectrum": { + "flake": false, + "locked": { + "lastModified": 1759482047, + "narHash": "sha256-H1wiXRQHxxPyMMlP39ce3ROKCwI5/tUn36P8x6dFiiQ=", + "ref": "refs/heads/main", + "rev": "c5d5786d3dc938af0b279c542d1e43bce381b4b9", + "revCount": 996, + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + }, + "original": { + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..73dedd0 --- /dev/null +++ b/flake.nix @@ -0,0 +1,80 @@ +{ + description = "NixOS flake"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + sops-nix = { + url = "github:Mic92/sops-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + microvm = { + url = "github:microvm-nix/microvm.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + disko = { + url = "github:nix-community/disko/latest"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + impermanence.url = "github:nix-community/impermanence"; + neovim-nightly-overlay.url = "github:nix-community/neovim-nightly-overlay"; + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nur.url = "github:nix-community/NUR"; + niri-branch = { + url = "github:argosnothing/niri/hidden-workspaces"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + inputs@{ nixpkgs, ... }: + let + hostname = "amelia"; + system = "x86_64-linux"; + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = true; + overlays = [ inputs.neovim-nightly-overlay.overlays.default ]; + }; + in + { + nixosConfigurations."${hostname}" = nixpkgs.lib.nixosSystem { + inherit system pkgs; + specialArgs = { + # inherit quickshell; + hostname = hostname; + }; + modules = [ + ./users.nix + ./storage.nix + ./configuration.nix + ./impermanence.nix + ./networking.nix + ./packages.nix + ./kernel + ./home + inputs.sops-nix.nixosModules.sops + inputs.microvm.nixosModules.host + inputs.disko.nixosModules.disko + inputs.impermanence.nixosModules.impermanence + inputs.home-manager.nixosModules.home-manager + { + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.sharedModules = [ + inputs.sops-nix.homeManagerModules.sops + ]; + nixpkgs.overlays = [ + inputs.nur.overlays.default + (_: prev: { + niri = inputs.niri-branch.packages.${prev.system}.niri; + }) + ]; + } + # ./networking/wireguard + ]; + }; + }; +} diff --git a/home/bin/tmux-sessionizer b/home/bin/tmux-sessionizer new file mode 100755 index 0000000..7722601 --- /dev/null +++ b/home/bin/tmux-sessionizer @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +if [[ $# -eq 1 ]]; then + selected=$1 +else + selected=$( + ( + find ~/work -mindepth 1 -maxdepth 1 -type d + find ~/dev -mindepth 1 -maxdepth 1 -type d + ) | fzf + ) + +fi + +if [[ -z $selected ]]; then + exit 0 +fi + +selected_name=$(basename "$selected" | tr . _) +tmux_running=$(pgrep tmux) + +if [[ -z $TMUX ]] && [[ -z $tmux_running ]]; then + tmux new-session -s "$selected_name" -c "$selected" + exit 0 +fi + +if ! tmux has-session -t="$selected_name" 2> /dev/null; then + tmux new-session -ds "$selected_name" -c "$selected" +fi + +tmux switch-client -t "$selected_name" diff --git a/home/default.nix b/home/default.nix new file mode 100644 index 0000000..4c7f8e2 --- /dev/null +++ b/home/default.nix @@ -0,0 +1,7 @@ +{ ... }: +{ + imports = [ + ./user.nix + ./root.nix + ]; +} diff --git a/home/nvim/default.nix b/home/nvim/default.nix new file mode 100644 index 0000000..77814ec --- /dev/null +++ b/home/nvim/default.nix @@ -0,0 +1,180 @@ +{ + config, + pkgs, + lib, + ... +}: +with lib; +let + cfg = config.custom.neovim; +in +{ + options.custom.neovim = { + enable = mkEnableOption "Custom Neovim"; + + colorscheme = mkOption { + type = types.str; + default = "unokai"; + }; + + hostname = mkOption { + type = types.str; + }; + }; + + config = mkIf cfg.enable { + programs.neovim = { + enable = true; + defaultEditor = true; + viAlias = true; + vimAlias = false; + vimdiffAlias = true; + plugins = with pkgs.vimPlugins; [ + { + plugin = blink-cmp; + type = "lua"; + config = '' + require("blink.cmp").setup({ + keymap = { + preset = "default", + [""] = { "select_and_accept", "snippet_forward", "fallback" }, + [""] = { "snippet_backward", "fallback" }, + }, + }) + ''; + } + { + plugin = conform-nvim; + type = "lua"; + config = '' + require("conform").setup({ + formatters_by_ft = { + lua = { "stylua" }, + javascript = { "prettierd" }, + nix = { "nixfmt" }, + python = { "black" }, + php = { "php_cs_fixer" }, + zig = { "zigfmt" }, + css = { "prettierd" }, + scss = { "prettierd" }, + less = { "prettierd" }, + blade = { "blade-formatter" }, + go = { "go fmt" }, + }, + }) + vim.api.nvim_create_autocmd("BufWritePre", { + pattern = "*", + callback = function(args) + require("conform").format({ bufnr = args.buf }) + end, + }) + vim.keymap.set("n", "c", function() + require("conform").format({ + lsp_fallback = true, + async = true, + timeout_ms = 500, + }) + end, { desc = "conform format" }) + ''; + } + # (codecompanion-nvim.overrideAttrs (_: { + # src = pkgs.fetchFromGitHub { + # owner = "olimorris"; + # repo = "codecompanion.nvim"; + # tag = "v18.2.1"; + # sha256 = "sha256-94uX1Ie+BiKSPGCYcUwoZ6DZwSz8tUxaNsa+xTv1ejw="; + # }; + # })) + kanagawa-nvim + leap-nvim + { + plugin = mini-icons; + type = "lua"; + config = ''require("mini.icons").setup()''; + } + { + plugin = nvim-treesitter.withAllGrammars; + type = "lua"; + config = '' + require("nvim-treesitter").setup({ + highlight = { + enable = true, + additional_vim_regex_highlighting = false, + }, + indent = { enable = true }, + refactor = { + highlight_definitions = { enable = true }, + }, + }) + ''; + } + { + plugin = nvim-treesitter-context; + type = "lua"; + config = ''require("treesitter-context").setup()''; + } + { + plugin = nvim-treesitter-textobjects; + # type = "lua"; + # config = '' + # vim.g.no_plugin_maps = true + # require("treesitter-textobjects").setup() + # ''; + } + nvim-lspconfig + { + plugin = nvim-surround; + type = "lua"; + config = ''require("nvim-surround").setup()''; + } + { + plugin = nvim-web-devicons; + type = "lua"; + config = ''require("nvim-web-devicons").setup()''; + } + { + plugin = oil-nvim; + type = "lua"; + config = '' + require("oil").setup() + vim.keymap.set("n", "o", "Oil", { desc = "Oil" }) + ''; + } + phpactor + { + plugin = render-markdown-nvim; + type = "lua"; + config = ''require("render-markdown").setup()''; + } + snacks-nvim + tokyonight-nvim + { + plugin = undotree; + type = "lua"; + config = ''vim.keymap.set("n", "u", vim.cmd.UndotreeToggle, { desc = "undotree" })''; + } + { + plugin = vimtex; + type = "lua"; + config = '' + vim.g.vimtex_view_method = "zathura" + vim.g.vimtex_compiler_method = "latexmk" + ''; + } + { + plugin = which-key-nvim; + type = "lua"; + config = ''require("which-key").setup()''; + } + ]; + extraConfig = '' + colorscheme ${cfg.colorscheme} + ''; + extraLuaConfig = '' + ${builtins.readFile ./settings.lua} + ${builtins.replaceStrings [ "@HOSTNAME@" ] [ cfg.hostname ] (builtins.readFile ./plugins.lua)} + require("custom") + ''; + }; + }; +} diff --git a/home/nvim/plugins.lua b/home/nvim/plugins.lua new file mode 100644 index 0000000..837c242 --- /dev/null +++ b/home/nvim/plugins.lua @@ -0,0 +1,148 @@ +local hostname = "@HOSTNAME@" + +local servers = { + textlab = {}, + lua_ls = {}, + rust_analyzer = {}, + nixd = { + nixpkgs = { + expr = 'import (builtins.getFlake "/etc/nixos").inputs.nixpkgs {}', + }, + formatting = { command = { "nixfmt" } }, + options = { + nixos = { + expr = '(builtins.getFlake "/etc/nixos").nixosConfigurations.' .. hostname .. ".options", + }, + home_manager = { + expr = '(builtins.getFlake "/etc/nixos").homeConfigurations.' .. hostname .. ".options", + }, + }, + }, + phpactor = {}, + zls = { + settings = { + zls = { + enable_build_on_save = true, + semantic_tokens = "partial", + }, + }, + }, + css = {}, + scss = {}, + less = {}, + blade = {}, + html = { filetypes = { "html", "blade" } }, + htmx = { filetypes = { "html", "blade" } }, + gopls = {}, +} +for server, config in pairs(servers) do + vim.lsp.config(server, config) + vim.lsp.enable(server) +end + +vim.api.nvim_create_autocmd("LspAttach", { + group = vim.api.nvim_create_augroup("UserConfigLsp", {}), + callback = function(ev) + vim.keymap.set("n", "gD", vim.lsp.buf.declaration, { buffer = ev.buf, desc = "go to declaration" }) + vim.keymap.set("n", "gd", vim.lsp.buf.definition, { buffer = ev.buf, desc = "go to definition" }) + -- vim.keymap.set("n", "gi", vim.lsp.buf.implementaion, { buffer = ev.buf, desc = "go to implementation" }) + vim.keymap.set("n", "rn", vim.lsp.buf.rename, { buffer = ev.buf, desc = "lsp rename" }) + vim.keymap.set("n", "a", vim.lsp.buf.code_action, { buffer = ev.buf, desc = "code action" }) + vim.keymap.set({ "n", "i" }, "", vim.lsp.buf.signature_help, { buffer = ev.buf, desc = "signature help" }) + vim.keymap.set("n", "gr", vim.lsp.buf.references, { buffer = ev.buf, desc = "references" }) + end, +}) + +local snacks = require("snacks") +snacks.setup({ + bigfile = {}, + dim = {}, + image = {}, + indent = {}, + lazygit = {}, + picker = {}, + quickfile = {}, + notifier = {}, +}) +vim.keymap.set("n", "tf", function() + snacks.picker.grep() +end, { desc = "grep picker" }) +vim.keymap.set("n", "te", snacks.picker.files, { desc = "file picker" }) +vim.keymap.set("n", "lg", function() + snacks.lazygit() +end, { desc = "lazygit" }) + +local leap = require("leap") +leap.opts.preview = function(ch0, ch1, ch2) + return not (ch1:match("%s") or (ch0:match("%a") and ch1:match("%a") and ch2:match("%a"))) +end +leap.opts.equivalence_classes = { + " \t\r\n", + "([{", + ")]}", + "'\"`", +} +vim.api.nvim_set_hl(0, "LeapBackdrop", { link = "Comment" }) + +do + -- Return an argument table for `leap()`, tailored for f/t-motions. + local function as_ft(key_specific_args) + local common_args = { + inputlen = 1, + inclusive = true, + -- To limit search scope to the current line: + -- pattern = function (pat) return '\\%.l'..pat end, + opts = { + labels = "", -- force autojump + safe_labels = vim.fn.mode(1):match("[no]") and "" or nil, -- [1] + }, + } + return vim.tbl_deep_extend("keep", common_args, key_specific_args) + end + + local clever = require("leap.user").with_traversal_keys -- [2] + local clever_f = clever("f", "F") + local clever_t = clever("t", "T") + + for key, key_specific_args in pairs({ + f = { opts = clever_f }, + F = { backward = true, opts = clever_f }, + t = { offset = -1, opts = clever_t }, + T = { backward = true, offset = 1, opts = clever_t }, + }) do + vim.keymap.set({ "n", "x", "o" }, key, function() + require("leap").leap(as_ft(key_specific_args)) + end) + end +end + +vim.api.nvim_create_autocmd("CmdlineLeave", { + group = vim.api.nvim_create_augroup("LeapOnSearch", {}), + callback = function() + local ev = vim.v.event + local is_search_cmd = (ev.cmdtype == "/") or (ev.cmdtype == "?") + local cnt = vim.fn.searchcount().total + if is_search_cmd and not ev.abort and (cnt > 1) then + -- Allow CmdLineLeave-related chores to be completed before + -- invoking Leap. + vim.schedule(function() + -- We want "safe" labels, but no auto-jump (as the search + -- command already does that), so just use `safe_labels` + -- as `labels`, with n/N removed. + local labels = require("leap").opts.safe_labels:gsub("[nN]", "") + -- For `pattern` search, we never need to adjust conceallevel + -- (no user input). We cannot merge `nil` from a table, but + -- using the option's current value has the same effect. + local vim_opts = { ["wo.conceallevel"] = vim.wo.conceallevel } + require("leap").leap({ + pattern = vim.fn.getreg("/"), -- last search pattern + windows = { vim.fn.win_getid() }, + opts = { safe_labels = "", labels = labels, vim_opts = vim_opts }, + }) + end) + end + end, +}) + +vim.keymap.set({ "n", "x", "o" }, "s", "(leap)", { desc = "leap" }) +vim.keymap.set({ "n", "x", "o" }, "S", "(leap-from-window)", { desc = "leap across window" }) diff --git a/home/nvim/settings.lua b/home/nvim/settings.lua new file mode 100644 index 0000000..9bd98b9 --- /dev/null +++ b/home/nvim/settings.lua @@ -0,0 +1,151 @@ +vim.opt.number = true +vim.opt.relativenumber = true +vim.opt.cursorline = true +vim.opt.wrap = false +vim.opt.scrolloff = 10 +vim.opt.sidescrolloff = 8 + +vim.opt.tabstop = 4 +vim.opt.shiftwidth = 4 +vim.opt.softtabstop = 4 +vim.opt.expandtab = true +vim.opt.smartindent = true +vim.opt.autoindent = true + +vim.opt.ignorecase = true +vim.opt.smartcase = true +vim.opt.hlsearch = false +vim.opt.incsearch = true + +vim.opt.termguicolors = true +vim.opt.signcolumn = "yes" +vim.opt.colorcolumn = "120" +vim.opt.showmatch = false +--- vim.opt.matchtime = 2 +vim.opt.conceallevel = 0 +vim.opt.concealcursor = "" +vim.opt.synmaxcol = 1000 +vim.opt.isfname:append("@-@") + +vim.opt.backup = false +vim.opt.writebackup = false +vim.opt.swapfile = false +vim.opt.undofile = true +vim.opt.undodir = vim.fn.expand("~/.cache/vim/undodir") +vim.opt.updatetime = 100 +vim.opt.timeoutlen = 500 +vim.opt.ttimeoutlen = 0 +vim.opt.autoread = true +vim.opt.autowrite = false + +vim.opt.hidden = true +--- vim.opt.errorbells = false +vim.opt.backspace = "indent,eol,start" +vim.opt.autochdir = false +vim.opt.path:append("**") +vim.opt.selection = "exclusive" +vim.opt.mouse = "a" +vim.opt.modifiable = true +vim.opt.encoding = "UTF-8" + +-- Split behavior +vim.opt.splitbelow = true +vim.opt.splitright = true + +vim.g.mapleader = " " +vim.g.maplocalleader = " " + +vim.o.exrc = true + +vim.cmd("set title") +vim.cmd("set ic") + +-- Delete without yanking +vim.keymap.set({ "n", "v" }, "d", '"_d', { desc = "Delete without yanking" }) +vim.keymap.set({ "n", "v" }, "", '"+y', { desc = "Copy to clipboard" }) + +-- Wayland clipboard mappings +vim.keymap.set({ "n", "v" }, "y", '"+y', { desc = "Yank to system clipboard" }) +vim.keymap.set("n", "Y", '"+Y', { desc = "Yank line to system clipboard" }) +vim.keymap.set({ "n", "v" }, "p", '"+p', { desc = "Paste from system clipboard" }) +vim.keymap.set({ "n", "v" }, "P", '"+P', { desc = "Paste from system clipboard before cursor" }) + +-- Better J behavior +vim.keymap.set("n", "J", "mzJ`z", { desc = "Join lines and keep cursor position" }) + +--- center when jumping +vim.keymap.set("n", "n", "nzzzv", { desc = "Next search result (centered)" }) +vim.keymap.set("n", "N", "Nzzzv", { desc = "Previous search result (centered)" }) +vim.keymap.set("n", "", "zz", { desc = "Half page down (centered)" }) +vim.keymap.set("n", "", "zz", { desc = "Half page up (centered)" }) + +--- window navigation +vim.keymap.set("n", "", "h", { desc = "Move to left window" }) +vim.keymap.set("n", "", "l", { desc = "Move to right window" }) +vim.keymap.set("n", "", "k", { desc = "Move to top window" }) +vim.keymap.set("n", "", "j", { desc = "Move to bottom window" }) + +--- indenting in visual mode +-- vim.keymap.set("v", "<", "", ">gv", { desc = "Indent right and reselect" }) + +local augroup = vim.api.nvim_create_augroup("UserConfig", {}) + +-- Highlight yanked text +vim.api.nvim_create_autocmd("TextYankPost", { + group = augroup, + callback = function() + vim.highlight.on_yank() + end, +}) + +--- return to last edit position when opening files +vim.api.nvim_create_autocmd("BufReadPost", { + group = augroup, + callback = function() + local mark = vim.api.nvim_buf_get_mark(0, '"') + local lcount = vim.api.nvim_buf_line_count(0) + if mark[1] > 0 and mark[1] <= lcount then + pcall(vim.api.nvim_win_set_cursor, 0, mark) + end + end, +}) + +--- close terminal when process exits +vim.api.nvim_create_autocmd("TermClose", { + group = augroup, + callback = function() + if vim.v.event.status == 0 then + vim.api.nvim_buf_delete(0, {}) + end + end, +}) + +-- Disable syntax highlighting for large files +vim.api.nvim_create_autocmd("BufReadPre", { + pattern = "*", + callback = function() + local size = vim.fn.getfsize(vim.fn.expand("")) + if size > 1024 * 1024 then -- 1MB threshold + vim.cmd("syntax off") + vim.opt_local.wrap = false + vim.opt_local.number = false + vim.opt_local.relativenumber = false + end + end, +}) +--- create directory when saving files +-- vim.api.nvim_create_autocmd("BufWritePre", { +-- group = augroup, +-- callback = function() +-- local dir = vim.fn.expand(":p:h") +-- if vim.fn.isdirectory(dir) == 0 and dir ~= "oil:" then +-- vim.fn.mkdir(dir, "p") +-- end +-- end, +-- }) + +--- command line completion +vim.opt.wildmenu = true +vim.opt.wildmode = "longest:full,full" +vim.opt.wildignore:append({ "*.o", "*.obj", "*.pyc", "*.class", "*.jar" }) diff --git a/home/root.nix b/home/root.nix new file mode 100644 index 0000000..81e0a43 --- /dev/null +++ b/home/root.nix @@ -0,0 +1,87 @@ +{ hostname, ... }: +{ + home-manager.users.root = + { config, ... }: + { + imports = [ ./nvim ]; + custom.neovim = { + enable = true; + hostname = hostname; + colorscheme = "unokai"; + }; + home.stateVersion = "25.11"; + + sops.defaultSopsFile = ../secrets/home.yaml; + sops.age.keyFile = "/.persist/${config.home.homeDirectory}/.config/sops/age/keys.txt"; + sops.secrets."root/ssh/desktop" = { + path = "${config.home.homeDirectory}/.ssh/desktop"; + mode = "0600"; + }; + home.file."/.ssh/desktop.pub".text = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILquARrJ3Vyh5z6aeVoiYrkLpgiMts+V/JzFEvs3Cnth root@icefox.sh"; + + programs = { + ssh = { + enable = true; + enableDefaultConfig = false; + matchBlocks = { + "icefox.sh" = { + user = "git"; + identityFile = config.sops.secrets."root/ssh/desktop".path; + }; + }; + }; + delta = { + enable = true; + options = { + navigate = true; + line-numbers = true; + side-by-side = true; + }; + enableGitIntegration = true; + }; + git = { + enable = true; + lfs.enable = true; + settings = { + user = { + email = "root@icefox.sh"; + name = "root"; + }; + gpg.format = "ssh"; + user.signingkey = "${config.home.homeDirectory}/.ssh/desktop.pub"; + commit.gpgsign = true; + tag.gpgsign = true; + core = { + editor = "nvim"; + whitespace = "fix,only-indent-error,trailing-space,space-before-tab"; + quotepath = false; + }; + diff = { + algorithm = "histogram"; + renames = "copies"; + }; + merge = { + conflictstyle = "zdiff3"; + }; + init = { + defaultBranch = "master"; + }; + push = { + autoSetupRemote = true; + default = "current"; + }; + pull = { + rebase = true; + }; + fetch = { + prune = true; + }; + help = { + autocorrect = "prompt"; + }; + }; + }; + }; + }; +} diff --git a/home/user.nix b/home/user.nix new file mode 100644 index 0000000..833a51a --- /dev/null +++ b/home/user.nix @@ -0,0 +1,355 @@ +{ hostname, lib, ... }: +{ + home-manager.users.user = + { + config, + pkgs, + ... + }: + { + home.username = "user"; + home.homeDirectory = "/home/user"; + home.stateVersion = "25.11"; + home.enableNixpkgsReleaseCheck = false; + + sops.defaultSopsFile = ../secrets/home.yaml; + sops.age.keyFile = "/.persist/${config.home.homeDirectory}/.config/sops/age/keys.txt"; + sops.secrets."user/ssh/desktop" = { + path = "${config.home.homeDirectory}/.ssh/desktop"; + mode = "0600"; + }; + home.file."/.ssh/desktop.pub".text = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILABd/iSJ4gn/ystDqNxLJTG0n0z5VIC9YXlmdUfOhHf desktop@icefox.sh"; + sops.secrets."user/ssh/legacy_ed25519" = { + path = "${config.home.homeDirectory}/.ssh/legacy_ed25519"; + mode = "0600"; + }; + home.file."/.ssh/legacy_ed25519.pub".text = + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILkchxtY21PzSLHJ5SoYPrl03+NRzRqznbdCqNyGuOX/ master@michizure.net"; + + dconf.settings = { + "org/gnome/desktop/interface" = { + text-scaling-factor = 1.5; + }; + }; + xresources.properties = { + "Xcursor.size" = 18; + "Xft.dpi" = 144; + "Xft.autohint" = 0; + "Xft.lcdfilter" = "lcddefault"; + "Xft.hintstyle" = "hintfull"; + "Xft.hinting" = 1; + "Xft.antialias" = 1; + "Xft.rgba" = "rgb"; + }; + + systemd.user.services.xrdb-configure = { + Unit = { + Description = "Load Xresources"; + }; + Intall = { + WantedBy = [ "graphical-session.target" ]; + }; + Service = { + ExecStart = "${pkgs.xorg.xrdb}/bin/xrdb -merge ${config.home.homeDirectory}/.Xresources"; + Type = "oneshot"; + }; + }; + sops.secrets."user/gpg/legacy_fnzr" = { }; + home.activation.importGpgKey = config.lib.dag.entryAfter [ "writeBoundary" ] '' + if [[ -f "${config.sops.secrets."user/gpg/legacy_fnzr".path}" ]]; then + ${pkgs.gnupg}/bin/gpg --batch --import "${ + config.sops.secrets."user/gpg/legacy_fnzr".path + }" || true + echo "YOUR_KEY_FINGERPRINT:6:" | ${pkgs.gnupg}/bin/gpg --import-ownertrust || true + fi + ''; + xdg.configFile."containers/containers.conf".text = '' + [engine] + compose_warning_logs=false + ''; + # xdg.configFile."mimeapps.list".force = true; + xdg.userDirs = { + enable = true; + createDirectories = true; + + download = "${config.home.homeDirectory}/downloads"; + documents = "${config.home.homeDirectory}/documents"; + desktop = "${config.home.homeDirectory}/desktop"; + pictures = "${config.home.homeDirectory}/pictures"; + music = "${config.home.homeDirectory}/music"; + videos = "${config.home.homeDirectory}/videos"; + templates = "${config.home.homeDirectory}"; + publicShare = "${config.home.homeDirectory}"; + + extraConfig = { + XDG_SCREENSHOTS_DIR = "${config.home.homeDirectory}/pictures/screenshots"; + }; + }; + + programs = { + ssh = { + enable = true; + enableDefaultConfig = false; + matchBlocks = { + "github.com" = { + identityFile = config.sops.secrets."user/ssh/legacy_ed25519".path; + }; + "icefox.sh" = { + user = "git"; + identityFile = config.sops.secrets."user/ssh/desktop".path; + }; + }; + }; + delta = { + enable = true; + options = { + navigate = true; + line-numbers = true; + side-by-side = true; + }; + enableGitIntegration = true; + }; + git = { + enable = true; + lfs.enable = true; + settings = { + user = { + email = "felipe@icefox.sh"; + name = "icefox"; + }; + gpg.format = "ssh"; + user.signingkey = "${config.home.homeDirectory}/.ssh/desktop.pub"; + commit.gpgsign = true; + tag.gpgsign = true; + core = { + editor = "nvim"; + whitespace = "fix,only-indent-error,trailing-space,space-before-tab"; + quotepath = false; + }; + diff = { + algorithm = "histogram"; + renames = "copies"; + }; + merge = { + conflictstyle = "zdiff3"; + }; + init = { + defaultBranch = "master"; + }; + push = { + autoSetupRemote = true; + default = "current"; + }; + pull = { + rebase = true; + }; + fetch = { + prune = true; + }; + help = { + autocorrect = "prompt"; + }; + url."git@github.com:".insteadOf = "https://github.com/"; + }; + }; + }; + + programs.tmux = { + enable = true; + baseIndex = 1; + keyMode = "vi"; + mouse = true; + + plugins = with pkgs.tmuxPlugins; [ + sensible + yank + pain-control + tmux-powerline + tmux-which-key + { + plugin = resurrect; + extraConfig = "set -g @ressurect-strategy-nvim 'session'"; + } + { + plugin = continuum; + extraConfig = '' + set -g @continuum-restore 'on' + set -g @continuum-save-interval '60' + ''; + } + ]; + extraConfig = '' + set -g status-position top + set -g focus-events on + set -g allow-passthrough on + + bind -n M-n select-window -t 1 + bind -n M-e select-window -t 2 + bind -n M-i select-window -t 3 + bind -n M-a select-window -t 4 + + bind -n M-, run-shell "tmux neww tmux-sessionizer" + bind -n M-/ run-shell "tmux switch-client -t default" + bind -n M-. run-shell "tmux switchc -l" + ''; + }; + + home.packages = with pkgs; [ + xorg.xrdb + (writeShellApplication { + name = "tmux-sessionizer"; + runtimeInputs = [ + tmux + fzf + ]; + text = builtins.readFile ./bin/tmux-sessionizer; + }) + ]; + + imports = [ ./nvim ]; + custom.neovim = { + enable = true; + colorscheme = "tokyonight"; + hostname = hostname; + }; + + programs.fish = { + enable = true; + plugins = [ + { + name = "puffer"; + src = pkgs.fetchFromGitHub { + owner = "nickeb96"; + repo = "puffer-fish"; + rev = "83174b0"; + sha256 = "sha256-Dhx5+XRxJvlhdnFyimNxFyFiASrGU4ZwyefsDwtKnSg="; + }; + } + ]; + + interactiveShellInit = '' + set fish_greeting + ''; + }; + + programs.starship = { + enable = true; + }; + + programs.zoxide = { + enable = true; + enableFishIntegration = true; + }; + + programs.chromium = { + enable = true; + package = pkgs.symlinkJoin { + name = "chromium-firejail-hm"; + paths = [ pkgs.chromium ]; + buildInputs = [ pkgs.makeWrapper ]; + postBuild = '' + rm $out/bin/chromium + ln -s /run/current-system/sw/bin/chromium $out/bin/chromium + ''; + }; + }; + + programs.ghostty = { + enable = true; + settings = { + font-family = "MonaspiceNe Nerd Font Mono"; + "font-family " = "Fire Code Symbol"; + font-size = "14"; + font-feature = "+calt, +liga, +dlig, +ss01, +ss02, +ss03, +ss04, +ss05, +ss06, +ss07, +ss08, +ss09, +ss10"; + }; + enableFishIntegration = true; + systemd.enable = true; + }; + + programs.librewolf = { + enable = true; + package = pkgs.librewolf; + + nativeMessagingHosts = [ + pkgs.browserpass + pkgs.tridactyl-native + ]; + profiles.default = { + id = 0; + name = "default"; + isDefault = true; + containersForce = true; + containers = { + personal = { + id = 1; + color = "blue"; + icon = "fingerprint"; + }; + google = { + id = 2; + color = "pink"; + icon = "briefcase"; + }; + }; + + search = { + force = true; + default = "ddg"; + order = [ + "ddg" + "Kagi" + "NixOS" + ]; + engines = { + "Kagi" = { + urls = [ { template = "https://kagi.com/search?q={searchTerms}"; } ]; + icon = "https://kagi.com/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "kg" ]; + }; + "nx" = { + urls = [ { template = "https://mynixos.com/search?q={searchTerms}"; } ]; + icon = "https://mynixos.com/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "nx" ]; + }; + "ddg" = { + metaData.alias = "dd"; + }; + "google".metaData.hidden = true; + "bing".metaData.hidden = true; + "amazondotcom-us".metaData.hidden = true; + "ebay".metaData.hidden = true; + }; + }; + + settings = { + "layout.css.prefers-color-scheme.content-override" = 2; + "privacy.resistFingerprinting" = true; + "privacy.resistFingerprinting.exemptions" = "prefers-color-scheme"; + "browser.theme.dark-private-windows" = true; + }; + extensions = { + packages = with pkgs.nur.repos.rycee.firefox-addons; [ + ublock-origin + tridactyl + gopass-bridge + multi-account-containers + foxyproxy-standard + ]; + # force = true; + # settings."uBlock0@raymondhill.net".settings = { + # selectedFilterLists = [ + # "ublock-filters" + # "ublock-badware" + # "ublock-privacy" + # "ublock-unbreak" + # "ublock-quick-fixes" + # ]; + # }; + }; + }; + }; + }; +} diff --git a/impermanence.nix b/impermanence.nix new file mode 100644 index 0000000..a74c2b9 --- /dev/null +++ b/impermanence.nix @@ -0,0 +1,54 @@ +{ + environment.persistence."/.persist" = { + enable = true; + hideMounts = true; + directories = [ + "/etc/nixos" + "/var/lib/nixos" + ]; + users.root = { + home = "/root"; + files = [ + ".config/sops/age/keys.txt" + ]; + }; + files = [ + # + ]; + + users.user = { + files = [ + ".config/sops/age/keys.txt" + ]; + directories = [ + ".config/nvim" + ".config/niri" + ".config/ghostty" + ".config/tmux" + ".config/tmux-powerline" + ".ssh" + ]; + }; + }; + + environment.persistence."/.nobackup" = { + enable = true; + hideMounts = true; + directories = [ + "/var/log" + "/var/cache" + "/var/lib/docker" + ]; + users.root = { + home = "/root"; + directories = [ + ".cache" + ]; + }; + users.user = { + directories = [ + ".cache" + ]; + }; + }; +} diff --git a/kernel/default.nix b/kernel/default.nix new file mode 100644 index 0000000..ad6b726 --- /dev/null +++ b/kernel/default.nix @@ -0,0 +1,77 @@ +{ + lib, + pkgs, + ... +}: +{ + imports = [ + ./hardened.nix + ./vfio.nix + # ./apparmor.nix + ]; + + custom.kernel.hardened.enable = true; + custom.kernel.vfio.enable = false; + # security.apparmor.enable = false; + + specialisation.unhardened.configuration = { + custom.kernel.hardened.enable = lib.mkForce false; + # security.apparmor.enable = lib.mkForce false; + }; + + specialisation.vfio.configuration = { + custom.kernel.vfio.enable = lib.mkForce true; + }; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.enableRedistributableFirmware = true; + hardware.cpu.amd.updateMicrocode = true; + + security.rtkit.enable = true; + security.sudo.enable = false; + security.doas = { + enable = true; + + extraRules = [ + { + users = [ "user" ]; + keepEnv = true; + persist = true; + } + ]; + }; + + boot = { + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + kernelPackages = pkgs.linuxPackages_zen; + kernelParams = [ + "amd_iommu=on" + ]; + initrd.availableKernelModules = [ + "nvme" + "xhci_pci" + "ahci" + "usbhid" + "sd_mod" + "uas" + "usbcore" + "usb_storage" + "vfat" + "nls_cp437" + "nls_iso8859_1" + "virtio_pci" + "virtio_blk" + "virtio_net" + "virtio_ring" + ]; + initrd.kernelModules = [ + "amdgpu" + "nvidia" + "nvidia_modeset" + "nvidia_drm" + ]; + }; +} diff --git a/kernel/hardened.nix b/kernel/hardened.nix new file mode 100644 index 0000000..3cd7949 --- /dev/null +++ b/kernel/hardened.nix @@ -0,0 +1,207 @@ +{ + lib, + config, + pkgs, + ... +}: +let + cfg = config.custom.kernel.hardened; +in +{ + options.custom.kernel.hardened = { + enable = lib.mkEnableOption "hardened kernel options"; + }; + config = lib.mkIf cfg.enable { + environment.systemPackages = [ + pkgs.kernel-hardening-checker + pkgs.lynis + ]; + + security = { + auditd.enable = true; + audit.enable = true; + audit.rules = [ "-a always,exit -F arch=b64 -S execve" ]; + protectKernelImage = true; + lockKernelModules = false; # this breaks iptables, wireguard, and virtd + + # force-enable the Page Table Isolation (PTI) Linux kernel feature + forcePageTableIsolation = true; + + # User namespaces are required for sandboxing. + # this means you cannot set `"user.max_user_namespaces" = 0;` in sysctl + allowUserNamespaces = true; + + # Disable unprivileged user namespaces, unless containers are enabled + unprivilegedUsernsClone = config.virtualisation.containers.enable; + allowSimultaneousMultithreading = true; + }; + + boot.kernel.sysctl = { + "fs.suid_dumpable" = 0; + # prevent pointer leaks + "kernel.kptr_restrict" = 2; + # restrict kernel log to CAP_SYSLOG capability + "kernel.dmesg_restrict" = 1; + # Note: certian container runtimes or browser sandboxes might rely on the following + # restrict eBPF to the CAP_BPF capability + "kernel.unprivileged_bpf_disabled" = 1; + # should be enabled along with bpf above + # "net.core.bpf_jit_harden" = 2; + # restrict loading TTY line disciplines to the CAP_SYS_MODULE + "dev.tty.ldisk_autoload" = 0; + # prevent exploit of use-after-free flaws + "vm.unprivileged_userfaultfd" = 0; + # kexec is used to boot another kernel during runtime and can be abused + "kernel.kexec_load_disabled" = 1; + # Kernel self-protection + # SysRq exposes a lot of potentially dangerous debugging functionality to unprivileged users + # 4 makes it so a user can only use the secure attention key. A value of 0 would disable completely + "kernel.sysrq" = 4; + # disable unprivileged user namespaces, Note: Docker, NH, and other apps may need this + "kernel.unprivileged_userns_clone" = 1; + # restrict all usage of performance events to the CAP_PERFMON capability + "kernel.perf_event_paranoid" = 3; + + # Network + # protect against SYN flood attacks (denial of service attack) + "net.ipv4.tcp_syncookies" = 1; + # protection against TIME-WAIT assassination + "net.ipv4.tcp_rfc1337" = 1; + # enable source validation of packets received (prevents IP spoofing) + "net.ipv4.conf.default.rp_filter" = 1; + "net.ipv4.conf.all.rp_filter" = 1; + + "net.ipv4.conf.all.accept_redirects" = 0; + "net.ipv4.conf.default.accept_redirects" = 0; + "net.ipv4.conf.all.secure_redirects" = 0; + "net.ipv4.conf.default.secure_redirects" = 0; + # Protect against IP spoofing + "net.ipv6.conf.all.accept_redirects" = 0; + "net.ipv6.conf.default.accept_redirects" = 0; + "net.ipv4.conf.all.send_redirects" = 0; + "net.ipv4.conf.default.send_redirects" = 0; + + # prevent man-in-the-middle attacks + "net.ipv4.icmp_echo_ignore_all" = 1; + + # ignore ICMP request, helps avoid Smurf attacks + "net.ipv4.conf.all.forwarding" = 0; + "net.ipv4.conf.default.accept_source_route" = 0; + "net.ipv4.conf.all.accept_source_route" = 0; + "net.ipv6.conf.all.accept_source_route" = 0; + "net.ipv6.conf.default.accept_source_route" = 0; + # Reverse path filtering causes the kernel to do source validation of + "net.ipv6.conf.all.forwarding" = 0; + "net.ipv6.conf.all.accept_ra" = 0; + "net.ipv6.conf.default.accept_ra" = 0; + + ## TCP hardening + # Prevent bogus ICMP errors from filling up logs. + "net.ipv4.icmp_ignore_bogus_error_responses" = 1; + + # Disable TCP SACK + "net.ipv4.tcp_sack" = 0; + "net.ipv4.tcp_dsack" = 0; + "net.ipv4.tcp_fack" = 0; + + # Userspace + # restrict usage of ptrace + "kernel.yama.ptrace_scope" = 2; + + # ASLR memory protection (64-bit systems) + "vm.mmap_rnd_bits" = 32; + "vm.mmap_rnd_compat_bits" = 16; + + # only permit symlinks to be followed when outside of a world-writable sticky directory + "fs.protected_symlinks" = 1; + "fs.protected_hardlinks" = 1; + # Prevent creating files in potentially attacker-controlled environments + "fs.protected_fifos" = 2; + "fs.protected_regular" = 2; + + # Randomize memory + "kernel.randomize_va_space" = 2; + # Exec Shield (Stack protection) + "kernel.exec-shield" = 1; + + ## TCP optimization + # TCP Fast Open is a TCP extension that reduces network latency by packing + # data in the sender’s initial TCP SYN. Setting 3 = enable TCP Fast Open for + # both incoming and outgoing connections: + "net.ipv4.tcp_fastopen" = 3; + # Bufferbloat mitigations + slight improvement in throughput & latency + "net.ipv4.tcp_congestion_control" = "bbr"; + "net.core.default_qdisc" = "cake"; + }; + + boot.kernelParams = [ + "audit=1" + # make it harder to influence slab cache layout + "slab_nomerge" + # enables zeroing of memory during allocation and free time + # helps mitigate use-after-free vulnerabilaties + "init_on_alloc=1" + "init_on_free=1" + # randomizes page allocator freelist, improving security by + # making page allocations less predictable + "page_alloc.shuffel=1" + # enables Kernel Page Table Isolation, which mitigates Meltdown and + # prevents some KASLR bypasses + "pti=on" + # randomizes the kernel stack offset on each syscall + # making attacks that rely on a deterministic stack layout difficult + "randomize_kstack_offset=on" + # disables vsyscalls, they've been replaced with vDSO + "vsyscall=none" + # disables debugfs, which exposes sensitive info about the kernel + "debugfs=off" + # certain exploits cause an "oops", this makes the kernel panic if an "oops" occurs + "oops=panic" + # only alows kernel modules that have been signed with a valid key to be loaded + # making it harder to load malicious kernel modules + # can make VirtualBox or Nvidia drivers unusable + #"module.sig_enforce=1" + # prevents user space code excalation + "lockdown=confidentiality" + # "rd.udev.log_level=3" + # "udev.log_priority=3" + ]; + + boot.blacklistedKernelModules = [ + # Obscure networking protocols + "dccp" # Datagram Congestion Control Protocol + "sctp" # Stream Control Transmission Protocol + "rds" # Reliable Datagram Sockets + "tipc" # Transparent Inter-Process Communication + "n-hdlc" # High-level Data Link Control + "ax25" # Amateur X.25 + "netrom" # NetRom + "x25" # X.25 + "rose" + "decnet" + "econet" + "af_802154" # IEEE 802.15.4 + "ipx" # Internetwork Packet Exchange + "appletalk" + "psnap" # SubnetworkAccess Protocol + "p8023" # Novell raw IEE 802.3 + "p8022" # IEE 802.3 + "can" # Controller Area Network + "atm" + # Various rare filesystems + "cramfs" + "freevxfs" + "jffs2" + "hfs" + "hfsplus" +# "udf" + # "nfs" # Network File System + # "nfsv3" + # "nfsv4" + "gfs2" # Global File System 2 + # vivid driver is only useful for testing purposes and has been the + # cause of privilege escalation vulnerabilities + "vivid" + ]; + }; +} diff --git a/kernel/vfio.nix b/kernel/vfio.nix new file mode 100644 index 0000000..c07e9aa --- /dev/null +++ b/kernel/vfio.nix @@ -0,0 +1,47 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.custom.kernel.vfio; +in +{ + options.custom.kernel.vfio = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + }; + }; + config = lib.mkIf cfg.enable { + boot = { + extraModulePackages = [ config.boot.kernelPackages.kvmfr ]; + extraModprobeConfig = '' + options kvmfr static_size_mb=128 + ''; + kernelParams = [ + "vfio-pci.ids=10de:2204,10de:1aef" + ]; + kernelModules = [ "kvmfr" ]; + + initrd.kernelModules = [ + "kvmfr" + "kvm-amd" + + "vfio_pci" + "vfio_iommu_type1" + "vfio" + ]; + }; + services = { + udev.extraRules = '' + SUBSYSTEM=="kvmfr", OWNER="master", GROUP="kvm", MODE="0660" + ''; + }; + + environment.systemPackages = [ + pkgs.looking-glass-client + ]; + }; +} diff --git a/networking.nix b/networking.nix new file mode 100644 index 0000000..0516b8b --- /dev/null +++ b/networking.nix @@ -0,0 +1,116 @@ +{ + config, + hostname, + pkgs, + ... +}: +let + inetInterface = "enp1s0"; +in +{ + sops.secrets = { + "wg0/address".sopsFile = ./secrets/vpn.yaml; + "wg0/dns".sopsFile = ./secrets/vpn.yaml; + "wg0/conf".sopsFile = ./secrets/vpn.yaml; + }; + + networking = { + hostName = hostname; + networkmanager.enable = false; + firewall.trustedInterfaces = [ "vlan66" ]; + useDHCP = false; + useNetworkd = true; + + # vlans.vlan66 = { + # id = 66; + # interface = "br0"; + # }; + # interfaces = { + # br0.useDHCP = true; + # vlan66.useDHCP = true; + # }; + # bridges.br0 = { + # interfaces = [ inetInterface ]; + # }; + # firewall.allowedTCPPorts = [ 8080 12000 12001 12002 12003 12004 12005 ]; + }; + + systemd.network = { + netdevs."20-br0" = { + netdevConfig = { + Kind = "bridge"; + Name = "br0"; + }; + }; + + netdevs."30-vlan66" = { + netdevConfig = { + Kind = "vlan"; + Name = "vlan66"; + }; + vlanConfig = { + Id = 66; + }; + }; + + networks."10-lan-up-link" = { + matchConfig.Name = "en* eth*"; + networkConfig.Bridge = "br0"; + }; + + networks."20-br0" = { + matchConfig.Name = "br0"; + networkConfig = { + VLAN = [ "vlan66" ]; + DHCP = "yes"; + }; + }; + + networks."30-vlan66" = { + matchConfig.Name = "vlan66"; + networkConfig.DHCP = "yes"; + }; + }; + + systemd.services."netns@wg0ns" = { + description = "wg0 network namespace"; + before = [ "network.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = pkgs.writers.writeBash "wg0ns-up" '' + ${pkgs.coreutils}/bin/mkdir -p /etc/netns/wg0ns + cat ${config.sops.secrets."wg0/dns".path} >> /etc/netns/wg0ns/resolv.conf + ${pkgs.iproute2}/bin/ip netns add wg0ns + ''; + ExecStop = "${pkgs.iproute2}/bin/ip netns del wg0ns"; + }; + }; + + systemd.services.wg0 = { + description = "wg0 network interface"; + bindsTo = [ "netns@wg0ns.service" ]; + requires = [ "network-online.target" ]; + after = [ "netns@wg0ns.service" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = pkgs.writers.writeBash "wg-up" '' + ${pkgs.iproute2}/bin/ip link add wg0 type wireguard + ${pkgs.iproute2}/bin/ip link set wg0 netns wg0ns + ${pkgs.iproute2}/bin/ip -n wg0ns address add $(< ${config.sops.secrets."wg0/address".path}) dev wg0 + ${pkgs.iproute2}/bin/ip netns exec wg0ns \ + ${pkgs.wireguard-tools}/bin/wg setconf wg0 ${config.sops.secrets."wg0/conf".path} + ${pkgs.iproute2}/bin/ip -n wg0ns link set lo up + ${pkgs.iproute2}/bin/ip -n wg0ns link set wg0 up + ${pkgs.iproute2}/bin/ip -n wg0ns route add default dev wg0 + ''; + ExecStop = pkgs.writers.writeBash "wg-down" '' + ${pkgs.iproute2}/bin/ip -n wg0ns route del default dev wg0 + ${pkgs.iproute2}/bin/ip -n wg0ns link del wg0 + ''; + }; + }; +} diff --git a/packages.nix b/packages.nix new file mode 100644 index 0000000..109cd3c --- /dev/null +++ b/packages.nix @@ -0,0 +1,210 @@ +{ pkgs, lib, ... }: +{ + environment.systemPackages = with pkgs; [ + bat + black + blade-formatter + cmake + cifs-utils + coreutils + bluetuith + bluez + bluez-tools + cargo + claude-code + clevis + cliphist + dunst + eza + fd + ffmpeg + fira-code-symbols + fish + freetube + fuzzel + fzf + git + gh + ghostty + gopass + gopass-jsonapi + gopls + hyprpicker + htmx-lsp + imagemagick + inkscape + pavucontrol + pciutils + poppler + jetbrains.datagrip + jq + lazygit + lf + libreoffice + libvirt + linux-firmware + lua-language-server + luarocks + lutris + mpv + nerd-fonts.monaspace + neovim + niri + nixd + nixfmt-rfc-style + (wrapOBS { + plugins = with obs-studio-plugins; [ + wlrobs + obs-pipewire-audio-capture + ]; + }) + php + php84Packages.composer + php84Packages.php-cs-fixer + phpactor + podman-compose + podman-tui + prettierd + playerctl + qemu_full + qmk + resvg + ripgrep + rust-analyzer + sshfs + starship + stow + stylua + sops + superhtml + swayimg + texlab + texlive.combined.scheme-full + tmux + thunderbird + tor-browser + unzip + virt-manager + virt-viewer + vscode-langservers-extracted + wineWow64Packages.waylandFull + winetricks + wl-clipboard + xdg-user-dirs + xwayland-satellite + yazi + zathura + zig_0_15 + zls_0_15 + zoxide + ]; + + hardware.keyboard.qmk.enable = true; + + programs = { + fish.enable = true; + virt-manager.enable = true; + direnv.enable = true; + gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + nix-ld.enable = true; + niri.enable = true; + dconf.enable = true; + }; + + virtualisation.containers.enable = true; + virtualisation.podman = { + enable = true; + dockerCompat = true; + defaultNetwork.settings.dns_enabled = true; + }; + + virtualisation.spiceUSBRedirection.enable = true; + virtualisation.libvirtd = { + enable = true; + extraConfig = '' + user="user" + ''; + onBoot = "ignore"; + onShutdown = "shutdown"; + qemu = { + package = pkgs.qemu_full; + verbatimConfig = '' + cgroup_device_acl = [ + "/dev/null", "/dev/full", "/dev/zero", + "/dev/random", "/dev/urandom", "/dev/ptmx", + "/dev/kvm", "/dev/kvmfr0" + ] + ''; + runAsRoot = false; + }; + }; + + programs.steam = { + enable = true; + remotePlay.openFirewall = true; + dedicatedServer.openFirewall = true; + localNetworkGameTransfers.openFirewall = true; + }; + + programs.firejail = { + enable = true; + wrappedBinaries = { + chromium = { + executable = "${pkgs.chromium}/bin/chromium"; + profile = "${pkgs.firejail}/etc/firejail/chromium.profile"; + extraArgs = [ + "--env=GTK_THEME=Adwaita:dark" + "--netns=wg0ns" + "--dns=1.1.1.1" + ]; + }; + mpv = { + executable = "${lib.getBin pkgs.mpv}/bin/mpv"; + profile = "${pkgs.firejail}/etc/firejail/mpv.profile"; + }; + claude = { + executable = "${pkgs.claude-code}/bin/claude"; + # profile = "${pkgs.firejail}/etc/firejail/nodejs-common.profile"; + extraArgs = [ + "--netns=wg0ns" + "--dns=1.1.1.1" + "--whitelist=~/.cargo" + "--whitelist=$${HOME}/.claude" + "--whitelist=$${HOME}/.config/claude-code" + "--whitelist=$${HOME}/dev" + "--whitelist=$${HOME}/work" + "--whitelist=/tmp" + "--read-only=/nix" + "--caps.drop=all" + "--ipc-namespace" + "--seccomp" + "--seccomp.block-secondary" + "--nodvd" + "--nogroups" + "--notv" + "--nou2f" + "--protocol=unix,inet,inet6,netlink" + ]; + }; + tor-browser = { + executable = "${pkgs.tor-browser}/bin/tor-browser"; + profile = "${pkgs.firejail}/etc/firejail/tor-browser-en-us.profile"; + extraArgs = [ + "--netns=wg0ns" + "--dns=1.1.1.1" + ]; + }; + freetube = { + executable = "${pkgs.freetube}/bin/freetube"; + profile = "${pkgs.firejail}/etc/firejail/freetube.profile"; + extraArgs = [ + "--netns=wg0ns" + "--dns=1.1.1.1" + ]; + }; + }; + }; +} diff --git a/secrets/home.yaml b/secrets/home.yaml new file mode 100644 index 0000000..97ba836 --- /dev/null +++ b/secrets/home.yaml @@ -0,0 +1,36 @@ +root: + password: ENC[AES256_GCM,data:qA7sbNvWvfmWiLX4pIYOzDmuCwc3+7I1KvTHHYF5jDHR0CNRuya0XglP8TNK5qGLEJkdmD9WphdWvYY60NTOf5NFhDnqtm3ZIw==,iv:B42jl40hQbRqMRfV39fNne0E3KKCwriAQ5MQ0DF4QQA=,tag:hH/u0Qw6A2is4XOOQpnr2Q==,type:str] + ssh: + desktop: ENC[AES256_GCM,data:mjenzt2rI9vZ4VnpWttAmojzEaGDgDTO0Tc5ICTZzKRC8fDIWc/YH81mCkU8BpPJGPiCQSCPz+/r7MEjcfjC0Xhf5xnSxespw/2eiCoeR4qWGMC4SlizusR+DBxwvW71MBn8icZkJyWc9zKPAfDyZQhtVUthvcQYTVsJEvMkRYSkTQgKJI0iEpq2x4j8fKr/FY4EQsidm5BFykOYOFejECWkkcMf0i+FBS60EsH3aZV+5c5fNNlj9GIdmX5rMp8iHa/RlGfxiu0QIaZRa+Q9h+h/d2Utf5qRFv2qpq+Fk7tI9JErtwwB+tKdXbavPjgWt3YtqI4O0f+01BWKRTPzFeiRANoONuGRgcx+b/GkAaHV4P+7uqIgmWgkwqCliYkgdwFtE2dWS6M/DEO+KP+GyKUykusdx2xODp+gA/CpiJM5OWPxmsgkDkuM/aLr3cBdzUHSJ028RCWBkTO/LsUOKNBpQ/9ePM5AoGVG7//gPlPEqURh5QrsJRJnr75E1qAI1Eu5XVIFrprPx3lxJEDWv6YPjUm6Aj6g2+b9,iv:rvJGN0ha+cACzf8u9dBRu1HOMx1jyx8Gwe2MJpJ6pb4=,tag:wkbymeExmj98vzDMSG5uTQ==,type:str] +user: + password: ENC[AES256_GCM,data:s5U1eR8aM4AM4J8j1VcRM8eSS/V6iJY/Dj9Ggis466Yxg+eUYWEimY1IWWVvFReRZ8WkbACysA56YZrLdEDowc1+lzeZQvPwYg==,iv:T7W1APCEozr7Eck06cDb3+VdVwjhQ3QoOrp7t+Hr2/4=,tag:MCH47JYaLyNEboW1oHC1kQ==,type:str] + gpg: + legacy_fnzr: ENC[AES256_GCM,data:aokSG2rHR6iX94GCcCmCxcz1lXSRvO03uhaUVGrNJT5aDjNjrjLya4TpUEVLvZXy87VaZobfuR+KQIcyi5zFHNCberq3q7h2zmtKhCEsnuy97oam7X39o/Jker/36geFxkDW5kvYAtcYL16Zi6cMB2+VvI7Sv0YGawGvvFfYjHjaV/wl0QPv+jyvM/HT9V7EMqJ7CER2QQVdkPuJHQSy/LsZqtcFGEDTuiGY7jZO4wWPByQ6PNPg4SiGeRfHz9rPvKO4LxQGt6keynM7VApZjTKOMcmaTgdOEgop5Sa9nZ+b5J7BJuP69vwnyREiP6u5T5l7QSxhFei+2K9iBMke+nbwM468lwnV9pUlpbBNxMwqVIRKiAGkcyZilmhlQd9Q4Dy5LwszItOM97+gN70IFkrzf6sO3nKsQWRr7kSwOAwvn1EQGEjj+KE1KM+cu+Y31PBBzkxtWBISJA1qzGcO35aeKNv8wGDGFliecg0Dz4SmtPXwP5Cd46U5XM/w8GMGRFg0b6anink1se7hOuYYSm9PzfJKbDOEL7eV5mhAGC2Qwv1q3Vwss+r1l6/b4myesP+OeVyeGCDMhCqO9VA6sQuBuddS2hYzh7tjI+p+0VXW7wonApNCKAMY90QLu2+8f33twYncWETbK/PkTz1jr4VVQIzh65kDclGPePfC2QMMRlT8eAL8y7u2RvDl6jteeQKiLsG7sz1NCXg484GfD8l9eMW3slLtY0b+9XHuCv09kkGkoktSw2udjoF4s9iJsGKOFRGZ/nLnpoXh0ftlKHvohhfqrTmwwvbPLYg9rn59dO6ZgIwH8hVi+ERWTtfpPERYPbIGLh7iRQf6iPI2d5oiE4wVjOsidiR5fhrb+0S8oALAV1Jhm5Y5Md0ePLrnPJxOXvAqCE1WXpjmZzl37qj+1FV/FFyh3Pq+GfmSN4fEllj7rkFppGBOQ19+8mV1JFkOVfkzwqV4NP8c08FigeO3T4vyvxu4jfMbovjS6Mi8Olia7pNGB6kZogHQXIGH7WE1tqmGFnEOvOHz+YKJ48apCtZ/ePo02lu/xZM4GNO5Q1LXpZtO67tpuepBjtmSGhBhUtt2ssdLpJVsDNbuLKDrT8ZA1wD7gA2C9wx+ycT5+JqE3o99J3unxVI=,iv:o3mrSYQINgMTaQBleo9hdNZZaPC4/OFf7RaJIvDVjv0=,tag:5v0SZBOpjdkFAezrKzQfLQ==,type:str] + ssh: + desktop: ENC[AES256_GCM,data:BXzI4BQmwunDe+PnmRjeDdZgaDVaJCqErhfUiDPtgOtx0+y1wPSTQoHBWM0+qnPTo0GtK2LmjlDGSoXUUl/aavwGyHG+/XMZcRs3LLGZqAOCWCAoA4N8nJIv2PFPCDdboK99HSR70eqHWgHk8McRrqpwDUaCsTaizU+e7R7bKX08kBp+k02fE2OW7OJHTfK6H+qH8yV8PpBXGpiPG/8OMsLa9m+1burb0KeMVRVk8Jd+kQ9meYj0xUH05l/VV7jeZ5XmZQOCtNxIRDnALjfWDJ44QLcdt1OoA8WZCoUV1437u88hYi45vo8IvFK46DBMnQGnGioITkOoIzBYAPFf/RWzyJZChrQ8qgCIfoOszbGrjXu5j1upa0KvLe4EkOBCeGNi+vPG75Q6Ma25jBLXxIq+xBeoSZyW5w9GLNEjXT7D6hXiVpypBQK3AW4JjOLywXDYG5dJzqrS4QQvilKIqj/EWSGiYkrHNJd+jVaBx/M6HrgW9Vfs0JuSz1bWgzASjqn/3zx6UzbaREm+j5Is6t1PPsix+zPKAo09,iv:gmtvM+6auTFlH3fxtq+HXq5PuzGTnIRgLIVfvPuk3hw=,tag:d0kpvr12rA/HcYOw7hDBUw==,type:str] + legacy_ed25519: ENC[AES256_GCM,data:0VbcLU1XtHfgi5mM+qYZ74ZE48DiKc2lzw2Ro13XyLvQMHP6fiTKZkrPFA/LQW+sQBG2Ax5dbAYaf4Gxe5wIWKn0kU8uai17//IS2ahN91fQ2GKC3ofURfwmTEZXnQPHXjK1Kygb6uMGWYOjjiY4JCXsEr2Ur5OTH5Cn7wrOPLFp4V7rK66RlrUuYoB52uGC8ds/KZWSRKZKSRJ2fIJkAZtOFUTzU1nbScKC7pVjt1pZmCI2dYzVD3xo/p90wZAXTTq6B6pprtnApHnzEW8kP5RVUdc9euMQm/HlQUh0RexUlfJCkloVxYD0RRiGL9RFABxQCdeyK6VNcgRZ32M6cUji0FSDgE04qTz0HN062Um/ebB65zFmTAN4GZLClIUqJVa9qXweESGkzbUV5t1J7IXDtG+ZdJmPokX31ozF69Vtcf53LQOee1d4zseP+niOR63tYOkZWkthRRLx4yxXSODyZcVe7ASbwICnxmf3bh1Qbn/4LU3NSBF1DZXiVIKR9COMdO8vqx4H2zZLrkn06I33J9sjoI4ejEFX,iv:Tjts8BRYhE+Nn9dyAL2yNpvPF8oMTwyVvoQkmwAsjrA=,tag:PuHmgIvHt+Dv85EI2WFxng==,type:str] + legacy_rsa: ENC[AES256_GCM,data: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,iv:oGGm7bveDXNmxqe5Zina03vSVLJx9P3VBC/DbuI6KzY=,tag:taEL0E4Uinv1MQPxeRbPzA==,type:str] +sops: + age: + - recipient: age1y0tj3kt67pfnj38t9c8g2ghry3a0mhcq8rrqv5xr4jekwepxaelqzu3dkf + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOZ3dERmxMbEJmSVhVRmVw + TUZZL0FzTHprci9ENHFodnRVWmRSbk1ab2xnCnZYeXN3MWRJZENlYmtWeFM0azdR + ZDFFYSsxRE9pdGZWV05hWnlacDlKbWcKLS0tIGNveTkwWEN2ajhaZ1JiaXRENzk0 + bFhna3RyY1kxK0IyVWlnR2FpMXk3UjQKvJaecXqAecBljJ9cNcHX13nxSxVey3LG + NdvJaMfEV4m3SqRF7YUoTzGYhucYjtX58E5SuvHnaP2qa21aDF+AZQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age16v8w7q4wmn22hhakq2uzaus2508rhldm7lcwh0kukshzjzyhuqesqz44ze + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSZnV1T0JKTXoyeUlZQ3o4 + QkR4OHZUbzQrbjdSK2VLTDNzMU9qdlUvVVUwClI4SDhMZTRDRXY3NlJSZ3REdmpJ + L2Y1N1p1VDFuK3VhbjJLaEVaenNQbWMKLS0tIEZGN3VlRFZqUFZQR1hCMTA5SEZN + NVlzQlQvMVc2dHZNK2pEWk80MStwY1UK38mxk1dJWi6XRKSwzcDA9qt8i1Grw2KJ + ac2EbJIFwYLOaMNOKF9hu+NrMdruRpU/2B8HlYYZjpNWmLb9jwI4wQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-12-22T18:37:14Z" + mac: ENC[AES256_GCM,data:BQj7pieRocXUP7as5/coL76WrpBPOwEzHlR+vTEOkBTD89hOnfUo0f2gJi/Ho4KldnCHKjQVGoLhA7l/NIuKXGs8OQ+0IYW9EOoEROi01EePW++Nw7rtOLBRQWojO9HpOmrOz8/fqMHq/vxrdrLql5gomNHJgPllBoAcALCUl2E=,iv:sPB13YhGgDO+KA+azVBqtIPrqRuoPpRfEljV5Xg4ig4=,tag:BnCePF7ii63Glq6dCI7YDg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/secrets/vpn.yaml b/secrets/vpn.yaml new file mode 100644 index 0000000..e354b18 --- /dev/null +++ b/secrets/vpn.yaml @@ -0,0 +1,28 @@ +wg0: + address: ENC[AES256_GCM,data:9Tnph2SHKeEt9Ss=,iv:CPR1N7fqqlaThGltSpfqeAOc5bAe13KWskGWj3jI8LQ=,tag:xha/hQOVqfUoGyfKbHhnuQ==,type:str] + dns: ENC[AES256_GCM,data:fXJG1uVYXcM=,iv:6FeSHSHMZHrXo3HLhR0Rpl2PI/9LDYHJwMkNwJv4QGk=,tag:KmuMHk2LgUW5TLAeQkqcMw==,type:str] + conf: ENC[AES256_GCM,data:SRDnI+2PvK7Zz1L5XBvrBNejgJEg8DK+qVO5XEtx6Nal+f7IeB3Ascp8Bkit5fd5myn/RxiK80wYmvLkDmcJAk46UjHKOpbxJl1s5FmKDuZJ3c3MXLwH7k2PeZP14VDDlyQqlcyGBrSu74L64ZMh/6EWGKbONTD1Wt3Ykg+/RegzQFDr2CPbj6XQeXsNS2p0ugicP5ffBMTUa9KSYDMQVV80mjSZ246aeY0owU1VUsitdvsCbfxtFd5gr/9zdfOXOvGY/BKxAlvVbszCalNs9DgJDHt/,iv:FP90SvUGnsZJS7F/uxtbOqTvGOgtC4+r2+YgF5FBoQY=,tag:9G1tkXHTpbytmG9T6sTpMw==,type:str] +sops: + age: + - recipient: age1y0tj3kt67pfnj38t9c8g2ghry3a0mhcq8rrqv5xr4jekwepxaelqzu3dkf + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtOHZSRkpBVVdUUk9OYUFH + cVBra014WXJyRTJ0QWFKallLQlc0SXhNSlFBCmpwME92M2lCN2liVjZBRndlSVBk + OEpUU1YyakdCa0xVaHdhRlpXbGxYdUEKLS0tIDFlV1k0Qkx1UDd2NUVHTTI3NDZE + OWhIdUxDcHB4Z3dTdDkyZWF6NEJCYzAKfPB9AZFQ08yqil+4AhIi6EMy8PXI4CAz + lK4ON/M67T0UrlWN/m3pryOOr4Lj4oiZvdOR0BCO3kn4Pj0nq5jQOA== + -----END AGE ENCRYPTED FILE----- + - recipient: age16v8w7q4wmn22hhakq2uzaus2508rhldm7lcwh0kukshzjzyhuqesqz44ze + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMSC9Td1NTMzk2NlJDTDNM + UVUzTSt1dGkrUVRGT1UzeXcwR1REN1U0dW5JCnNJRzdKZHVyR0dzaUw2TlVzQnQ2 + SHhSSGlDWUNBSXZiME5GM0JPTFRseDQKLS0tIEFnOXgzWFo2Rmo2THN4VFFIY1h0 + OEZ4WUp1QlVrTkVTN1BHMG0yaXFuSk0KLw3ZuvWTurJDTpyoq5YafLm8YFT4v4Vh + s+ay8ju3kA1CKjMF3gBQF08EoCdP/jU6tZerNwwcs17el5zIvRmG7Q== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-12-17T22:57:50Z" + mac: ENC[AES256_GCM,data:xsXO2t9IyEvuWbz+eYvtcJ6qLdkiKZKnn1wJxbdm6D4A3piAuja0GaS5frahGiEo2jhNMZfm3lVeYvbFCttO5qJjagfT2CIFH3c9kVQO6R9MtbDDi620vrctv9YsLydIulDdEYB1J3JWXIcmyd8yaSIlu9532NqV2Bog3zwq4Io=,iv:50FOOKQkXDq8N3qpAlaE0dtidhscC/DvzOv4aJ/u7Uk=,tag:KaP6Yhf/aMxEAtg6c5w0JQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/storage.nix b/storage.nix new file mode 100644 index 0000000..53773f8 --- /dev/null +++ b/storage.nix @@ -0,0 +1,90 @@ +{ ... }: +{ + disko.devices.disk = { + main = { + type = "disk"; + device = "/dev/vda"; + content = { + type = "gpt"; + partitions = { + ESP = { + size = "2G"; + type = "EF00"; + start = "1M"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + root = { + size = "100%"; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + mountpoint = "/.root-disk"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + subvolumes = { + "@root" = { + mountpoint = "/"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@home" = { + mountpoint = "/home"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@nix" = { + mountpoint = "/nix"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@persist" = { + mountpoint = "/.persist"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@nobackup" = { + mountpoint = "/.nobackup"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@snapshots" = { + mountpoint = "/.snapshots"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }; + }; + fileSystems."/.persist".neededForBoot = true; + fileSystems."/.nobackup".neededForBoot = true; + + swapDevices = [ + { + device = "/.nobackup/swapfile"; + size = 64 * 1024; + } + ]; +} diff --git a/users.nix b/users.nix new file mode 100644 index 0000000..b83a7fc --- /dev/null +++ b/users.nix @@ -0,0 +1,37 @@ +{ + config, + pkgs, + ... +}: +{ + sops.secrets."user/password" = { + neededForUsers = true; + sopsFile = ./secrets/home.yaml; + }; + sops.secrets."root/password" = { + neededForUsers = true; + sopsFile = ./secrets/home.yaml; + }; + users = { + mutableUsers = false; + + users = { + root = { + homeMode = "700"; + hashedPasswordFile = config.sops.secrets."root/password".path; + }; + user = { + uid = 1000; + homeMode = "700"; + shell = pkgs.fish; + isNormalUser = true; + group = "user"; + extraGroups = [ "libvirt" ]; + hashedPasswordFile = config.sops.secrets."user/password".path; + }; + }; + groups = { + user.gid = 1000; + }; + }; +}