From cc530d3d5f8e364486a067d3d00a12dd765eb857 Mon Sep 17 00:00:00 2001 From: Joseph Hanson Date: Thu, 20 Jun 2024 08:59:56 -0500 Subject: [PATCH] Mochi init --- .envrc | 1 + .forgejo/workflows/build.yml | 50 ++++++++ .gitignore | 6 + .pre-commit-config.yaml | 38 ++++++ .sops.yaml | 29 +++++ .taskfiles/pre-commit/Taskfile.yaml | 23 ++++ .taskfiles/sops/Taskfile.yaml | 18 +++ .vscode/extensions.json | 11 ++ .vscode/module.code-snippets | 32 +++++ .yamllint.yaml | 27 ++++ README.md | 23 ++++ Taskfile.yaml | 33 +++++ flake.nix | 0 nixos/home/jahanson/global.nix | 93 ++++++++++++++ nixos/home/jahanson/server.nix | 6 + nixos/home/jahanson/workstation.nix | 42 +++++++ nixos/home/modules/default.nix | 36 ++++++ .../modules/programs/browsers/default.nix | 5 + .../programs/browsers/firefox/default.nix | 32 +++++ .../programs/browsers/firefox/policies.nix | 20 +++ .../browsers/firefox/profile-default.nix | 32 +++++ nixos/home/modules/programs/de/default.nix | 5 + .../modules/programs/de/gnome/default.nix | 36 ++++++ nixos/home/modules/programs/default.nix | 6 + nixos/home/modules/security/default.nix | 5 + nixos/home/modules/security/ssh/default.nix | 21 ++++ nixos/home/modules/shell/default.nix | 8 ++ nixos/home/modules/shell/fish/default.nix | 75 ++++++++++++ nixos/home/modules/shell/git/default.nix | 69 +++++++++++ nixos/home/modules/shell/starship/default.nix | 115 ++++++++++++++++++ nixos/home/modules/shell/wezterm/default.nix | 43 +++++++ nixos/hosts/durincore/default.nix | 33 +++++ nixos/hosts/varda/default.nix | 34 ++++++ nixos/lib/default.nix | 43 +++++++ nixos/modules/.gitkeep | 0 nixos/modules/README.md | 9 ++ nixos/modules/default.nix | 3 + .../nixos/containers/backrest/default.nix | 56 +++++++++ nixos/modules/nixos/containers/default.nix | 5 + nixos/modules/nixos/de/default.nix | 5 + nixos/modules/nixos/de/gnome.nix | 101 +++++++++++++++ nixos/modules/nixos/default.nix | 62 ++++++++++ nixos/modules/nixos/hardware/default.nix | 5 + .../modules/nixos/hardware/nvidia/default.nix | 79 ++++++++++++ nixos/modules/nixos/lib.nix | 83 +++++++++++++ nixos/modules/nixos/programs/default.nix | 5 + .../modules/nixos/programs/shell/default.nix | 5 + nixos/modules/nixos/programs/shell/fish.nix | 28 +++++ nixos/modules/nixos/security/acme/default.nix | 36 ++++++ .../nixos/security/acme/secrets.sops.yaml | 50 ++++++++ nixos/modules/nixos/security/default.nix | 6 + .../nixos/services/cockpit/default.nix | 22 ++++ nixos/modules/nixos/services/default.nix | 12 ++ .../nixos/services/forgejo/default.nix | 92 ++++++++++++++ .../nixos/services/forgejo/secrets.sops.yaml | 51 ++++++++ .../modules/nixos/services/nginx/default.nix | 62 ++++++++++ .../modules/nixos/services/podman/default.nix | 51 ++++++++ .../nixos/services/postgresql/default.nix | 71 +++++++++++ .../nixos/services/radicale/default.nix | 110 +++++++++++++++++ .../nixos/services/radicale/secrets.sops.yaml | 50 ++++++++ .../nixos/services/reboot-required-check.nix | 45 +++++++ .../modules/nixos/services/restic/default.nix | 102 ++++++++++++++++ .../nixos/services/restic/secrets.sops.yaml | 52 ++++++++ nixos/modules/nixos/system/default.nix | 14 +++ nixos/modules/nixos/system/impermanence.nix | 55 +++++++++ nixos/modules/nixos/system/motd/default.nix | 98 +++++++++++++++ nixos/modules/nixos/system/nfs/default.nix | 24 ++++ nixos/modules/nixos/system/nix.nix | 38 ++++++ nixos/modules/nixos/system/openssh.nix | 38 ++++++ .../modules/nixos/system/pushover/default.nix | 54 ++++++++ nixos/modules/nixos/system/security.nix | 45 +++++++ nixos/modules/nixos/system/systempackages.nix | 20 +++ nixos/modules/nixos/system/time.nix | 22 ++++ nixos/modules/nixos/system/zfs.nix | 40 ++++++ nixos/profiles/README.md | 18 +++ nixos/profiles/global.nix | 44 +++++++ nixos/profiles/global/default.nix | 8 ++ nixos/profiles/global/nix.nix | 47 +++++++ nixos/profiles/global/secrets.sops.yaml | 53 ++++++++ nixos/profiles/global/sops.nix | 14 +++ nixos/profiles/global/system.nix | 13 ++ nixos/profiles/global/users.nix | 39 ++++++ nixos/profiles/hw-generic-x86.nix | 27 ++++ nixos/profiles/hw-hetzner-cax.nix | 26 ++++ nixos/profiles/hw-thinkpad-t470.nix | 30 +++++ nixos/profiles/role-dev.nix | 36 ++++++ nixos/profiles/role-server.nix | 47 +++++++ nixos/profiles/role-workstation.nix | 75 ++++++++++++ renovate.json | 13 ++ shell.nix | 30 +++++ 90 files changed, 3276 insertions(+) create mode 100644 .envrc create mode 100644 .forgejo/workflows/build.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 .sops.yaml create mode 100644 .taskfiles/pre-commit/Taskfile.yaml create mode 100644 .taskfiles/sops/Taskfile.yaml create mode 100644 .vscode/extensions.json create mode 100644 .vscode/module.code-snippets create mode 100644 .yamllint.yaml create mode 100644 README.md create mode 100644 Taskfile.yaml create mode 100644 flake.nix create mode 100644 nixos/home/jahanson/global.nix create mode 100644 nixos/home/jahanson/server.nix create mode 100644 nixos/home/jahanson/workstation.nix create mode 100644 nixos/home/modules/default.nix create mode 100644 nixos/home/modules/programs/browsers/default.nix create mode 100644 nixos/home/modules/programs/browsers/firefox/default.nix create mode 100644 nixos/home/modules/programs/browsers/firefox/policies.nix create mode 100644 nixos/home/modules/programs/browsers/firefox/profile-default.nix create mode 100644 nixos/home/modules/programs/de/default.nix create mode 100644 nixos/home/modules/programs/de/gnome/default.nix create mode 100644 nixos/home/modules/programs/default.nix create mode 100644 nixos/home/modules/security/default.nix create mode 100644 nixos/home/modules/security/ssh/default.nix create mode 100644 nixos/home/modules/shell/default.nix create mode 100644 nixos/home/modules/shell/fish/default.nix create mode 100644 nixos/home/modules/shell/git/default.nix create mode 100644 nixos/home/modules/shell/starship/default.nix create mode 100644 nixos/home/modules/shell/wezterm/default.nix create mode 100644 nixos/hosts/durincore/default.nix create mode 100644 nixos/hosts/varda/default.nix create mode 100644 nixos/lib/default.nix create mode 100644 nixos/modules/.gitkeep create mode 100644 nixos/modules/README.md create mode 100644 nixos/modules/default.nix create mode 100644 nixos/modules/nixos/containers/backrest/default.nix create mode 100644 nixos/modules/nixos/containers/default.nix create mode 100644 nixos/modules/nixos/de/default.nix create mode 100644 nixos/modules/nixos/de/gnome.nix create mode 100644 nixos/modules/nixos/default.nix create mode 100644 nixos/modules/nixos/hardware/default.nix create mode 100644 nixos/modules/nixos/hardware/nvidia/default.nix create mode 100644 nixos/modules/nixos/lib.nix create mode 100644 nixos/modules/nixos/programs/default.nix create mode 100644 nixos/modules/nixos/programs/shell/default.nix create mode 100644 nixos/modules/nixos/programs/shell/fish.nix create mode 100644 nixos/modules/nixos/security/acme/default.nix create mode 100644 nixos/modules/nixos/security/acme/secrets.sops.yaml create mode 100644 nixos/modules/nixos/security/default.nix create mode 100644 nixos/modules/nixos/services/cockpit/default.nix create mode 100644 nixos/modules/nixos/services/default.nix create mode 100644 nixos/modules/nixos/services/forgejo/default.nix create mode 100644 nixos/modules/nixos/services/forgejo/secrets.sops.yaml create mode 100644 nixos/modules/nixos/services/nginx/default.nix create mode 100644 nixos/modules/nixos/services/podman/default.nix create mode 100644 nixos/modules/nixos/services/postgresql/default.nix create mode 100644 nixos/modules/nixos/services/radicale/default.nix create mode 100644 nixos/modules/nixos/services/radicale/secrets.sops.yaml create mode 100644 nixos/modules/nixos/services/reboot-required-check.nix create mode 100644 nixos/modules/nixos/services/restic/default.nix create mode 100644 nixos/modules/nixos/services/restic/secrets.sops.yaml create mode 100644 nixos/modules/nixos/system/default.nix create mode 100644 nixos/modules/nixos/system/impermanence.nix create mode 100644 nixos/modules/nixos/system/motd/default.nix create mode 100644 nixos/modules/nixos/system/nfs/default.nix create mode 100644 nixos/modules/nixos/system/nix.nix create mode 100644 nixos/modules/nixos/system/openssh.nix create mode 100644 nixos/modules/nixos/system/pushover/default.nix create mode 100644 nixos/modules/nixos/system/security.nix create mode 100644 nixos/modules/nixos/system/systempackages.nix create mode 100644 nixos/modules/nixos/system/time.nix create mode 100644 nixos/modules/nixos/system/zfs.nix create mode 100644 nixos/profiles/README.md create mode 100644 nixos/profiles/global.nix create mode 100644 nixos/profiles/global/default.nix create mode 100644 nixos/profiles/global/nix.nix create mode 100644 nixos/profiles/global/secrets.sops.yaml create mode 100644 nixos/profiles/global/sops.nix create mode 100644 nixos/profiles/global/system.nix create mode 100644 nixos/profiles/global/users.nix create mode 100644 nixos/profiles/hw-generic-x86.nix create mode 100644 nixos/profiles/hw-hetzner-cax.nix create mode 100644 nixos/profiles/hw-thinkpad-t470.nix create mode 100644 nixos/profiles/role-dev.nix create mode 100644 nixos/profiles/role-server.nix create mode 100644 nixos/profiles/role-workstation.nix create mode 100644 renovate.json create mode 100644 shell.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml new file mode 100644 index 0000000..818b7df --- /dev/null +++ b/.forgejo/workflows/build.yml @@ -0,0 +1,50 @@ +name: "Build" +on: + pull_request: +jobs: + nix-build: + if: github.event.pull_request.draft == false + strategy: + fail-fast: false + matrix: + include: + - system: varda + os: native-aarch64 + - system: durincore + os: native-x86_64 + runs-on: ${{ matrix.os }} + env: + PATH: ${{ format('{0}:{1}', '/run/current-system/sw/bin', env.PATH) }} + steps: + - name: Checkout repository + uses: https://github.com/actions/checkout@v4 + with: + fetch-depth: 0 + - uses: https://github.com/cachix/cachix-action@v15 + if: ${{ !github.event.pull_request.head.repo.fork }} + with: + name: hsndev + # If you chose API tokens for write access OR if you have a private cache + authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + # env: + # USER: 'root' + + - name: Garbage collect build dependencies + run: nix-collect-garbage + + - name: Build new ${{ matrix.system }} system + shell: bash + run: | + set -o pipefail + nix build \ + ".#top.${{ matrix.system }}" \ + --profile ./profile \ + --fallback \ + -v \ + --log-format raw \ + > >(tee stdout.log) 2> >(tee /tmp/nix-build-err.log >&2) + - name: Push to Cachix + if: success() + env: + CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} + run: nix build ".#top.${{ matrix.system }}" --json | jq -r .[].drvPath | cachix push hsndev diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5506429 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +**/*.tmp.sops.yaml +**/*.sops.tmp.yaml +age.key +result* +.direnv +.kube diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..c4b880c --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,38 @@ +--- +fail_fast: false + +repos: + - repo: https://github.com/adrienverge/yamllint + rev: v1.35.1 + hooks: + - args: + - --config-file + - .yamllint.yaml + id: yamllint + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: fix-byte-order-marker + - id: mixed-line-ending + - id: check-added-large-files + args: [--maxkb=2048] + - id: check-merge-conflict + - id: check-executables-have-shebangs + - repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.5.5 + hooks: + - id: remove-crlf + - id: remove-tabs + exclude: (Makefile) + - repo: https://github.com/zricethezav/gitleaks + rev: v8.18.2 + hooks: + - id: gitleaks + - repo: https://github.com/yuvipanda/pre-commit-hook-ensure-sops + rev: v1.1 + hooks: + - id: sops-encryption + # Uncomment to exclude all markdown files from encryption + # exclude: *.\.md diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..d2a89a0 --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,29 @@ +--- +# config files for sops & used for encrypting keys that sops-nix decrypts. +# each machine key is derieved from its generated `ssh_hosts_ed` file +# via ssh-to-age +# sops encrypts the secrets ready to decrypt with the private key of any of the below machines +# OR my 'main' key thats kept outside this repo securely. + +# key-per-machine is a little more secure and a little more work than +# copying one key to each machine + +keys: + - users: + - &jahanson age18kj3xhlvgjeg2awwku3r8d95w360uysu0w5ejghnp4kh8qmtge5qwa2vjp + - hosts: + - &durincore age1d9p83j52m2xg0vh9k7q0uwlxwhs3y6tlv68yg9s2h9mdw2fmmsqshddz5m + - &gandalf age1nuj9sk2k8ede06f8gk5twdlc593uuc7lll2dvuy20nxw9zn97u5swrcjpj + - &telperion age1z3vjvkead2h934n3w4m5m7tg4tj5qlzagsq6ly84h3tcu7x4ldsqd3s5fg + - &varda age1a8z3p24v32l9yxm5z2l8h7rpc3nhacyfv4jvetk2lenrvsdstd3sdu2kaf + + +creation_rules: + - path_regex: .*\.sops\.yaml$ + key_groups: + - age: + - *durincore + - *gandalf + - *jahanson + - *telperion + - *varda diff --git a/.taskfiles/pre-commit/Taskfile.yaml b/.taskfiles/pre-commit/Taskfile.yaml new file mode 100644 index 0000000..637d1b1 --- /dev/null +++ b/.taskfiles/pre-commit/Taskfile.yaml @@ -0,0 +1,23 @@ +--- +# yaml-language-server: $schema=https://taskfile.dev/schema.json +version: "3" + +vars: + host: $HOSTNAME + +tasks: + + init: + desc: Initialize pre-commit hooks + cmds: + - pre-commit install --install-hooks + + update: + desc: Update pre-commit dependencies + cmds: + - pre-commit autoupdate + + run: + desc: Run pre-commit + cmds: + - pre-commit run --all-files diff --git a/.taskfiles/sops/Taskfile.yaml b/.taskfiles/sops/Taskfile.yaml new file mode 100644 index 0000000..3c1ef8a --- /dev/null +++ b/.taskfiles/sops/Taskfile.yaml @@ -0,0 +1,18 @@ +--- +# yaml-language-server: $schema=https://taskfile.dev/schema.json +version: "3" + +tasks: + re-encrypt: + desc: Decrypt and re-encrypt all sops secrets + silent: true + dir: "{{.USER_WORKING_DIR}}" + vars: + SECRET_FILES: + sh: find . -type f -name '*.sops.yaml' ! -name ".sops.yaml" + cmds: + - for: { var: SECRET_FILES } + cmd: | + echo "Re-encrypting {{ .ITEM }}" + sops --decrypt --in-place "{{ .ITEM }}" + sops --encrypt --in-place "{{ .ITEM }}" diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a99b1e7 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,11 @@ +{ + "recommendations": [ + "jnoortheen.nix-ide", + "mikestead.dotenv", + "redhat.ansible", + "redhat.vscode-yaml", + "signageos.signageos-vscode-sops", + "pkief.material-icon-theme", + "ms-vscode-remote.remote-ssh" + ] +} diff --git a/.vscode/module.code-snippets b/.vscode/module.code-snippets new file mode 100644 index 0000000..8c47588 --- /dev/null +++ b/.vscode/module.code-snippets @@ -0,0 +1,32 @@ +{ + "nix-module": { + "prefix": "nm", + "body": [ + "{ lib", + ", config", + ", pkgs", + ", ...", + "}:", + "with lib;", + "let", + " cfg = config.mySystem.${1}.${2};", + " app = \"${3}\"", + " appFolder = \"apps/${app}\";", + " persistentFolder = \"${config.mySystem.persistentFolder}/${appFolder}\";", + " user = app;", + " group = app;", + "in", + "{", + " options.mySystem.${1}.${2}.enable = mkEnableOption \"${4}\";", + "", + " config = mkIf cfg.enable {", + "", + " $5", + "", + " };", + "}", + "" + ], + "description": "nix-module" + } +} diff --git a/.yamllint.yaml b/.yamllint.yaml new file mode 100644 index 0000000..9cb571b --- /dev/null +++ b/.yamllint.yaml @@ -0,0 +1,27 @@ +--- +ignore: | + .direnv/ + .private/ + .vscode/ + *.sops.* + +extends: default + +rules: + truthy: + allowed-values: ["true", "false", "on"] + + comments: + min-spaces-from-content: 1 + + line-length: disable + + braces: + min-spaces-inside: 0 + max-spaces-inside: 1 + + brackets: + min-spaces-inside: 0 + max-spaces-inside: 0 + + indentation: enable diff --git a/README.md b/README.md new file mode 100644 index 0000000..7c5f4c4 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# jahanson's homelab + +## Goals + +- [ ] Learn nix +- [ ] Services I want to separate from my kubernetes cluster I will use Nix. +- [ ] Approval-based update automation for flakes. +- [ ] Expand usage to other shell environments such as WSL, etc +- [ ] keep it simple, use trusted boring tools + +## TODO + +- [ x ] Forgejo Actions +- [ ] Bring over hosts + - [ x ] Varda (forgejo) + - [ ] Telperion (network services) + - [ ] Gandalf (NixNAS) + - [ x ] Thinkpad T470 + +## Links & References + +- [truxnell/dotfiles](https://github.com//truxnell/nix-config/) +- [billimek/dotfiles](https://github.com/billimek/dotfiles/) diff --git a/Taskfile.yaml b/Taskfile.yaml new file mode 100644 index 0000000..c544229 --- /dev/null +++ b/Taskfile.yaml @@ -0,0 +1,33 @@ +--- +# go-task runner file - rest of config in .taskfiles/**.*.yaml +version: "3" + +includes: + sops: + taskfile: ".taskfiles/sops" + dir: .taskfiles/sops + pre: + taskfile: ".taskfiles/pre-commit" + dir: "{{.ROOT_DOR}}" + +tasks: + default: + silent: true + cmds: + - task -l + + lint: + desc: Run statix lint + cmds: + - statix check . + + check: + desc: Check project files + cmds: + - task: lint + - task: pc-run + + format: + desc: Check project files + cmds: + - nixpkgs-fmt {{.ROOT_DIR}} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..e69de29 diff --git a/nixos/home/jahanson/global.nix b/nixos/home/jahanson/global.nix new file mode 100644 index 0000000..7fec7ec --- /dev/null +++ b/nixos/home/jahanson/global.nix @@ -0,0 +1,93 @@ +{ pkgs, config, ... }: +with config; +{ + imports = [ + ../modules + ]; + + config = { + myHome.username = "jahanson"; + myHome.homeDirectory = "/home/jahanson/"; + + systemd.user.sessionVariables = { + EDITOR = "vim"; + }; + + home = { + # Install these packages for my user + packages = with pkgs; [ + # misc + file + which + tree + gnused + gnutar + gawk + zstd + gnupg + + # archives + zip + xz + unzip + p7zip + + # cli + _1password + bat + dbus + direnv + git + nix-index + python3 + fzf + ripgrep + vim + lsd + + # terminal file managers + nnn + ranger + yazi + + # networking tools + iperf3 + dnsutils # `dig` + `nslookup` + ldns # replacement of `dig`, it provide the command `drill` + aria2 # A lightweight multi-protocol & multi-source command-line download utility + socat # replacement of openbsd-netcat + nmap # A utility for network discovery and security auditing + ipcalc # it is a calculator for the IPv4/v6 addresses + + # system tools + sysstat + lm_sensors # for `sensors` command + ethtool + pciutils # lspci + usbutils # lsusb + + # system call monitoring + strace # system call monitoring + ltrace # library call monitoring + lsof # list open files + + btop # replacement of htop/nmon + iotop # io monitoring + iftop # network monitoring + + # dev utils + direnv # shell environment management + envsubst + + # nix tools + nvd + ]; + + sessionVariables = { + EDITOR = "vim"; + }; + + }; + + }; +} diff --git a/nixos/home/jahanson/server.nix b/nixos/home/jahanson/server.nix new file mode 100644 index 0000000..4ff97db --- /dev/null +++ b/nixos/home/jahanson/server.nix @@ -0,0 +1,6 @@ +{ ... }: +{ + imports = [ + ./global.nix + ]; +} diff --git a/nixos/home/jahanson/workstation.nix b/nixos/home/jahanson/workstation.nix new file mode 100644 index 0000000..b7051c0 --- /dev/null +++ b/nixos/home/jahanson/workstation.nix @@ -0,0 +1,42 @@ +{ pkgs, config, ... }: +with config; +{ + imports = [ + ./global.nix + ]; + + myHome.programs.firefox.enable = true; + + myHome.shell = { + starship.enable = true; + fish.enable = true; + + git = { + enable = true; + username = "Joseph Hanson"; + email = "joe@veri.dev"; + signingKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIDSAmssproxG+KsVn2DfuteBAemHrmmAFzCtldpKl4J"; + }; + }; + + home = { + # Install these packages for my user + packages = with pkgs; + [ + #apps + _1password-gui + discord + flameshot + vlc + + # cli + brightnessctl + + # dev utils + pre-commit # Pre-commit tasks for git + minio-client # S3 management + shellcheck # shell script linting + ]; + + }; +} diff --git a/nixos/home/modules/default.nix b/nixos/home/modules/default.nix new file mode 100644 index 0000000..d1d6bc8 --- /dev/null +++ b/nixos/home/modules/default.nix @@ -0,0 +1,36 @@ +{ lib, ... }: { + + imports = [ + ./shell + ./programs + ./security + ]; + + options.myHome.username = lib.mkOption { + type = lib.types.str; + description = "users username"; + default = "jahanson"; + }; + options.myHome.homeDirectory = lib.mkOption { + type = lib.types.str; + description = "users homedir"; + default = "jahanson"; + }; + + # Home-manager defaults + config = { + home.stateVersion = "24.11"; + + programs = { + home-manager.enable = true; + git.enable = true; + }; + + xdg.enable = true; + + nixpkgs.config = { + allowUnfree = true; + }; + }; + +} diff --git a/nixos/home/modules/programs/browsers/default.nix b/nixos/home/modules/programs/browsers/default.nix new file mode 100644 index 0000000..3062d5e --- /dev/null +++ b/nixos/home/modules/programs/browsers/default.nix @@ -0,0 +1,5 @@ +{ ... }: { + imports = [ + ./firefox + ]; +} diff --git a/nixos/home/modules/programs/browsers/firefox/default.nix b/nixos/home/modules/programs/browsers/firefox/default.nix new file mode 100644 index 0000000..2e4308f --- /dev/null +++ b/nixos/home/modules/programs/browsers/firefox/default.nix @@ -0,0 +1,32 @@ +{ lib, config, pkgs, ... }: +with lib; +let + cfg = config.myHome.programs.firefox; +in +{ + options.myHome.programs.firefox.enable = mkEnableOption "Firefox"; + + config = mkIf cfg.enable + { + programs.firefox = { + enable = true; + package = pkgs.firefox.override + { + extraPolicies = { + DontCheckDefaultBrowser = true; + DisablePocket = true; + # See nixpkgs' firefox/wrapper.nix to check which options you can use + nativeMessagingHosts = [ + # Gnome shell native connector + pkgs.gnome-browser-connector + # plasma connector + # plasma5Packages.plasma-browser-integration + ]; + }; + }; + policies = import ./policies.nix; + + profiles.default = import ./profile-default.nix { inherit pkgs; }; + }; + }; +} diff --git a/nixos/home/modules/programs/browsers/firefox/policies.nix b/nixos/home/modules/programs/browsers/firefox/policies.nix new file mode 100644 index 0000000..5af443b --- /dev/null +++ b/nixos/home/modules/programs/browsers/firefox/policies.nix @@ -0,0 +1,20 @@ +{ + DisableTelemetry = true; + DisableFirefoxStudies = true; + EnableTrackingProtection = { + Value = true; + Locked = true; + Cryptomining = true; + Fingerprinting = true; + }; + DisablePocket = true; + # DisableFirefoxAccounts = true; + # DisableAccounts = true; + # DisableFirefoxScreenshots = true; + # OverrideFirstRunPage = ""; + OverridePostUpdatePage = ""; + DontCheckDefaultBrowser = true; + DisplayBookmarksToolbar = "never"; # alternatives: "always" or "newtab" + DisplayMenuBar = "default-off"; # alternatives: "always", "never" or "default-on" + SearchBar = "unified"; # alternative: "separate" +} diff --git a/nixos/home/modules/programs/browsers/firefox/profile-default.nix b/nixos/home/modules/programs/browsers/firefox/profile-default.nix new file mode 100644 index 0000000..a0358be --- /dev/null +++ b/nixos/home/modules/programs/browsers/firefox/profile-default.nix @@ -0,0 +1,32 @@ +{ pkgs }: +{ + id = 0; + name = "default"; + isDefault = true; + settings = { + "browser.startup.homepage" = "https://status.hsn.dev"; + "browser.search.suggest.enabled.private" = false; + # 0 => blank page + # 1 => your home page(s) {default} + # 2 => the last page viewed in Firefox + # 3 => previous session windows and tabs + "browser.startup.page" = "3"; + + "browser.send_pings" = false; + # Do not track + "privacy.donottrackheader.enabled" = "true"; + "privacy.donottrackheader.value" = 1; + "browser.display.use_system_colors" = "true"; + + "browser.display.use_document_colors" = "false"; + "devtools.theme" = "dark"; + + "extensions.pocket.enabled" = false; + }; + extensions = with pkgs.nur.repos.rycee.firefox-addons; [ + ublock-origin + privacy-badger + link-cleaner + refined-github + ]; +} diff --git a/nixos/home/modules/programs/de/default.nix b/nixos/home/modules/programs/de/default.nix new file mode 100644 index 0000000..4bf617f --- /dev/null +++ b/nixos/home/modules/programs/de/default.nix @@ -0,0 +1,5 @@ +{ ... }: { + imports = [ + ./gnome + ]; +} diff --git a/nixos/home/modules/programs/de/gnome/default.nix b/nixos/home/modules/programs/de/gnome/default.nix new file mode 100644 index 0000000..42b1ce4 --- /dev/null +++ b/nixos/home/modules/programs/de/gnome/default.nix @@ -0,0 +1,36 @@ +# Adjusted manually from generated output of dconf2nix +# https://github.com/gvolpe/dconf2nix +{ lib, pkgs, osConfig, ... }: +with lib.hm.gvariant; { + config = lib.mkIf osConfig.mySystem.de.gnome.enable { + # add user packages + home.packages = with pkgs; [ + dconf2nix + ]; + + # worked out from dconf2nix + # dconf dump / | dconf2nix > dconf.nix + # can also dconf watch + dconf.settings = { + "org/gnome/mutter" = { + edge-tiling = true; + workspaces-only-on-primary = false; + }; + "org/gnome/desktop/wm/preferences" = { + workspace-names = [ "sys" "talk" "web" "edit" "run" ]; + }; + "org/gnome/shell" = { + disabled-extensions = [ "apps-menu@gnome-shell-extensions.gcampax.github.com" "light-style@gnome-shell-extensions.gcampax.github.com" "places-menu@gnome-shell-extensions.gcampax.github.com" "drive-menu@gnome-shell-extensions.gcampax.github.com" "window-list@gnome-shell-extensions.gcampax.github.com" "workspace-indicator@gnome-shell-extensions.gcampax.github.com" ]; + enabled-extensions = [ "appindicatorsupport@rgcjonas.gmail.com" "caffeine@patapon.info" "dash-to-dock@micxgx.gmail.com" "gsconnect@andyholmes.github.io" "Vitals@CoreCoding.com" "sp-tray@sp-tray.esenliyim.github.com" ]; + favorite-apps = [ "org.gnome.Nautilus.desktop" "firefox.desktop" "org.wezfurlong.wezterm.desktop" "PrusaGcodeviewer.desktop" "spotify.desktop" "org.gnome.Console.desktop" "codium.desktop" "discord.desktop" ]; + }; + "org/gnome/nautilus/preferences" = { + default-folder-viewer = "list-view"; + }; + "org/gnome/nautilus/icon-view" = { + default-zoom-level = "small"; + }; + + }; + }; +} diff --git a/nixos/home/modules/programs/default.nix b/nixos/home/modules/programs/default.nix new file mode 100644 index 0000000..c941a17 --- /dev/null +++ b/nixos/home/modules/programs/default.nix @@ -0,0 +1,6 @@ +{ ... }: { + imports = [ + ./browsers + ./de + ]; +} diff --git a/nixos/home/modules/security/default.nix b/nixos/home/modules/security/default.nix new file mode 100644 index 0000000..327a590 --- /dev/null +++ b/nixos/home/modules/security/default.nix @@ -0,0 +1,5 @@ +{ ... }: { + imports = [ + ./ssh + ]; +} diff --git a/nixos/home/modules/security/ssh/default.nix b/nixos/home/modules/security/ssh/default.nix new file mode 100644 index 0000000..7094444 --- /dev/null +++ b/nixos/home/modules/security/ssh/default.nix @@ -0,0 +1,21 @@ +{ config, lib, ... }: +with lib; let + cfg = config.myHome.security.ssh; +in +{ + options.myHome.security.ssh = { + enable = mkEnableOption "ssh"; + matchBlocks = mkOption { + type = types.attrs; + default = { }; + }; + }; + + config = mkIf cfg.enable { + programs.ssh = { + inherit (cfg) matchBlocks; + enable = true; + # addKeysToAgent = "yes"; + }; + }; +} diff --git a/nixos/home/modules/shell/default.nix b/nixos/home/modules/shell/default.nix new file mode 100644 index 0000000..c86c159 --- /dev/null +++ b/nixos/home/modules/shell/default.nix @@ -0,0 +1,8 @@ +{ ... }: { + imports = [ + ./fish + ./starship + ./wezterm + ./git + ]; +} diff --git a/nixos/home/modules/shell/fish/default.nix b/nixos/home/modules/shell/fish/default.nix new file mode 100644 index 0000000..7240d32 --- /dev/null +++ b/nixos/home/modules/shell/fish/default.nix @@ -0,0 +1,75 @@ +{ config, pkgs, lib, ... }: +with lib; let + inherit (config.myHome) username homeDirectory; + cfg = config.myHome.shell.fish; +in +{ + options.myHome.shell.fish = { + enable = mkEnableOption "fish"; + }; + + config = mkMerge [ + (mkIf cfg.enable { + programs.fish = { + enable = true; + + shellAliases = { + m = "less"; + ls = "${pkgs.lsd}/bin/lsd"; + ll = "${pkgs.lsd}/bin/lsd -l"; + la = "${pkgs.lsd}/bin/lsd -a"; + lt = "${pkgs.lsd}/bin/lsd --tree"; + lla = "${pkgs.lsd}/bin/lsd -la"; + tm = "tmux attach -t (basename $PWD) || tmux new -s (basename $PWD)"; + x = "exit"; + }; + + shellAbbrs = { + nrs = "sudo nixos-rebuild switch --flake ."; + nvdiff = "nvd diff /run/current-system result"; + }; + + interactiveShellInit = '' + # Erase fish_mode_prompt function + functions -e fish_mode_prompt + + function remove_path + if set -l index (contains -i $argv[1] $PATH) + set --erase --universal fish_user_paths[$index] + end + end + + function update_path + if test -d $argv[1] + fish_add_path -m $argv[1] + else + remove_path $argv[1] + end + end + + # Paths are in reverse priority order + update_path /opt/homebrew/opt/postgresql@16/bin + update_path /opt/homebrew/bin + update_path ${homeDirectory}/.krew/bin + update_path /nix/var/nix/profiles/default/bin + update_path /run/current-system/sw/bin + update_path /etc/profiles/per-user/${username}/bin + update_path /run/wrappers/bin + update_path ${homeDirectory}/.nix-profile/bin + update_path ${homeDirectory}/go/bin + update_path ${homeDirectory}/.cargo/bin + update_path ${homeDirectory}/.local/bin + + set -gx EDITOR "vim" + + set -gx LSCOLORS "Gxfxcxdxbxegedabagacad" + set -gx LS_COLORS 'di=01;34:ln=01;36:pi=33:so=01;35:bd=01;33:cd=33:or=31:ex=01;32:*.7z=01;31:*.bz2=01;31:*.gz=01;31:*.lz=01;31:*.lzma=01;31:*.lzo=01;31:*.rar=01;31:*.tar=01;31:*.tbz=01;31:*.tgz=01;31:*.xz=01;31:*.zip=01;31:*.zst=01;31:*.zstd=01;31:*.bmp=01;35:*.tiff=01;35:*.tif=01;35:*.TIFF=01;35:*.gif=01;35:*.jpeg=01;35:*.jpg=01;35:*.png=01;35:*.webp=01;35:*.pot=01;35:*.pcb=01;35:*.gbr=01;35:*.scm=01;35:*.xcf=01;35:*.spl=01;35:*.stl=01;35:*.dwg=01;35:*.ply=01;35:*.apk=01;31:*.deb=01;31:*.rpm=01;31:*.jad=01;31:*.jar=01;31:*.crx=01;31:*.xpi=01;31:*.avi=01;35:*.divx=01;35:*.m2v=01;35:*.m4v=01;35:*.mkv=01;35:*.MOV=01;35:*.mov=01;35:*.mp4=01;35:*.mpeg=01;35:*.mpg=01;35:*.sample=01;35:*.wmv=01;35:*.3g2=01;35:*.3gp=01;35:*.gp3=01;35:*.webm=01;35:*.flv=01;35:*.ogv=01;35:*.f4v=01;35:*.3ga=01;35:*.aac=01;35:*.m4a=01;35:*.mp3=01;35:*.mp4a=01;35:*.oga=01;35:*.ogg=01;35:*.opus=01;35:*.s3m=01;35:*.sid=01;35:*.wma=01;35:*.flac=01;35:*.alac=01;35:*.mid=01;35:*.midi=01;35:*.pcm=01;35:*.wav=01;35:*.ass=01;33:*.srt=01;33:*.ssa=01;33:*.sub=01;33:*.git=01;33:*.ass=01;33:*README=33:*README.rst=33:*README.md=33:*LICENSE=33:*COPYING=33:*INSTALL=33:*COPYRIGHT=33:*AUTHORS=33:*HISTORY=33:*CONTRIBUTOS=33:*PATENTS=33:*VERSION=33:*NOTICE=33:*CHANGES=33:*CHANGELOG=33:*log=33:*.txt=33:*.md=33:*.markdown=33:*.nfo=33:*.org=33:*.pod=33:*.rst=33:*.tex=33:*.texttile=33:*.bib=35:*.json=35:*.jsonl=35:*.jsonnet=35:*.libsonnet=35:*.rss=35:*.xml=35:*.fxml=35:*.toml=35:*.yaml=35:*.yml=35:*.dtd=35:*.cbr=35:*.cbz=35:*.chm=35:*.pdf=35:*.PDF=35:*.epub=35:*.awk=35:*.bash=35:*.bat=35:*.BAT=35:*.sed=35:*.sh=35:*.zsh=35:*.vim=35:*.py=35:*.ipynb=35:*.rb=35:*.gemspec=35:*.pl=35:*.PL=35:*.t=35:*.msql=35:*.mysql=35:*.pgsql=35:*.sql=35:*.r=35:*.R=35:*.cljw=35:*.scala=35:*.sc=35:*.dart=35:*.asm=35:*.cl=35:*.lisp=35:*.rkt=35:*.el=35:*.elc=35:*.eln=35:*.lua=35:*.c=35:*.C=35:*.h=35:*.H=35:*.tcc=35:*.c++=35:*.h++=35:*.hpp=35:*.hxx=35:*ii.=35:*.m=35:*.M=35:*.cc=35:*.cs=35:*.cp=35:*.cpp=35:*.cxx=35:*.go=35:*.f=35:*.F=35:*.nim=35:*.nimble=35:*.s=35:*.S=35:*.rs=35:*.scpt=35:*.swift=35:*.vala=35:*.vapi=35:*.hs=35:*.lhs=35:*.zig=35:*.v=35:*.pyc=35:*.tf=35:*.tfstate=35:*.tfvars=35:*.css=35:*.less=35:*.sass=35:*.scss=35:*.htm=35:*.html=35:*.jhtm=35:*.mht=35:*.eml=35:*.coffee=35:*.java=35:*.js=35:*.mjs=35:*.jsm=35:*.jsp=35:*.rasi=35:*.php=35:*.twig=35:*.vb=35:*.vba=35:*.vbs=35:*.Dockerfile=35:*.dockerignore=35:*.Makefile=35:*.MANIFEST=35:*.am=35:*.in=35:*.hin=35:*.scan=35:*.m4=35:*.old=35:*.out=35:*.SKIP=35:*.diff=35:*.patch=35:*.tmpl=35:*.j2=35:*PKGBUILD=35:*config=35:*.conf=35:*.service=31:*.@.service=31:*.socket=31:*.swap=31:*.device=31:*.mount=31:*.automount=31:*.target=31:*.path=31:*.timer=31:*.snapshot=31:*.allow=31:*.swp=31:*.swo=31:*.tmp=31:*.pid=31:*.state=31:*.lock=31:*.lockfile=31:*.pacnew=31:*.un=31:*.orig=31:' + ''; + }; + + home.sessionVariables.fish_greeting = ""; + + programs.nix-index.enable = true; + }) + ]; +} diff --git a/nixos/home/modules/shell/git/default.nix b/nixos/home/modules/shell/git/default.nix new file mode 100644 index 0000000..157703e --- /dev/null +++ b/nixos/home/modules/shell/git/default.nix @@ -0,0 +1,69 @@ +{ pkgs, config, lib, ... }: +let + cfg = config.myHome.shell.git; +in +{ + options.myHome.shell.git = { + enable = lib.mkEnableOption "git"; + username = lib.mkOption { + type = lib.types.str; + }; + email = lib.mkOption { + type = lib.types.str; + }; + signingKey = lib.mkOption { + type = lib.types.str; + }; + }; + + config = lib.mkMerge [ + (lib.mkIf cfg.enable { + programs.gh.enable = true; + programs.gpg.enable = true; + + programs.git = { + enable = true; + + userName = cfg.username; + userEmail = cfg.email; + + extraConfig = { + core.autocrlf = "input"; + init.defaultBranch = "main"; + pull.rebase = true; + rebase.autoStash = true; + # public key for signing commits + user.signingKey = cfg.signingKey; + # ssh instead of gpg + gpg.format = "ssh"; + # 1password signing gui git signing + gpg.ssh.program = "${pkgs._1password-gui}/bin/op-ssh-sign"; + # Auto sign commits without -S + commit.gpgsign = true; + }; + aliases = { + co = "checkout"; + }; + ignores = [ + # Mac OS X hidden files + ".DS_Store" + # Windows files + "Thumbs.db" + # asdf + ".tool-versions" + # Sops + ".decrypted~*" + "*.decrypted.*" + # Python virtualenvs + ".venv" + ]; + }; + + home.packages = [ + pkgs.git-filter-repo + pkgs.tig + pkgs.lazygit + ]; + }) + ]; +} diff --git a/nixos/home/modules/shell/starship/default.nix b/nixos/home/modules/shell/starship/default.nix new file mode 100644 index 0000000..ad07718 --- /dev/null +++ b/nixos/home/modules/shell/starship/default.nix @@ -0,0 +1,115 @@ +{ lib +, config +, ... +}: +with lib; let + cfg = config.myHome.shell.starship; +in +{ + options.myHome.shell.starship = { enable = mkEnableOption "starship"; }; + + config = mkIf cfg.enable { + programs.starship = { + enable = true; + settings = { + add_newline = false; + command_timeout = 1000; + format = lib.concatStrings [ + "$username" + "$hostname" + "$directory" + "$git_branch" + "$git_status" + "$\{custom.direnv\}" + "$fill" + "$python" + "$status" + "$cmd_duration" + "$line_break" + "$character" + ]; + + username = { + style_user = "yellow"; + style_root = "red"; + format = "[$user]($style)"; + show_always = false; + }; + + hostname = { + ssh_only = true; + format = "[@$hostname]($style) in "; + style = "green"; + }; + + directory = { + truncation_length = 3; + format = "[$path]($style)[$read_only]($read_only_style) "; + style = "blue"; + read_only = " "; + truncation_symbol = "../"; + truncate_to_repo = true; + fish_style_pwd_dir_length = 1; + }; + + git_branch = { + format = "on [$symbol$branch]($style) "; + style = "purple"; + symbol = " "; + }; + + git_status = { + format = "([$all_status$ahead_behind]($style) )"; + style = "purple"; + conflicted = " "; + ahead = " "; + behind = " "; + diverged = "󰆗 "; + up_to_date = " "; + untracked = " "; + stashed = " "; + modified = " "; + staged = " "; + renamed = " "; + deleted = " "; + }; + + fill = { + symbol = " "; + }; + + python = { + format = "[\${symbol}\${pyenv_prefix}(\${version} )(\($virtualenv\) )]($style)"; + symbol = "🐍 "; + }; + + status = { + disabled = false; + format = "[$symbol]($style) "; + symbol = " "; + success_symbol = " "; + style = "red"; + }; + + cmd_duration = { + min_time = 2000; + format = "took [$duration]($style) "; + style = "yellow"; + }; + + character = { + success_symbol = "[](green)"; + error_symbol = "[](green)"; + vicmd_symbol = "[](purple)"; + }; + + custom.direnv = { + format = "[$symbol]($style)"; + symbol = " "; + style = "blue"; + when = "env | grep -E '^DIRENV_FILE='"; + }; + }; + }; + }; +} diff --git a/nixos/home/modules/shell/wezterm/default.nix b/nixos/home/modules/shell/wezterm/default.nix new file mode 100644 index 0000000..73b90d7 --- /dev/null +++ b/nixos/home/modules/shell/wezterm/default.nix @@ -0,0 +1,43 @@ +{ config +, pkgs +, lib +, ... +}: +with lib; let + cfg = config.myHome.shell.wezterm; +in +{ + options.myHome.shell.wezterm = { + enable = mkEnableOption "wezterm"; + configPath = mkOption { + type = types.str; + }; + }; + + config = mkIf cfg.enable { + # xdg.configFile."wezterm/wezterm.lua".source = config.lib.file.mkOutOfStoreSymlink cfg.configPath; + programs.wezterm.package = pkgs.unstable.wezterm; + programs.wezterm = { + enable = true; + extraConfig = '' + local wez = require('wezterm') + return { + -- issue relating to nvidia drivers + -- https://github.com/wez/wezterm/issues/2011 + -- had to build out 550.67 manually to 'fix' + enable_wayland = true, + + color_scheme = "Dracula (Official)", + check_for_updates = false, + window_background_opacity = .90, + window_padding = { + left = '2cell', + right = '2cell', + top = '1cell', + bottom = '0cell', + }, + } + ''; + }; + }; +} diff --git a/nixos/hosts/durincore/default.nix b/nixos/hosts/durincore/default.nix new file mode 100644 index 0000000..4c32474 --- /dev/null +++ b/nixos/hosts/durincore/default.nix @@ -0,0 +1,33 @@ +{ ... }: { + config = { + + # hardware-configuration.nix - half of the hardware-configuration.nix file + + networking.hostId = "ad4380db"; + networking.hostName = "durincore"; + + fileSystems."/" = + { device = "rpool/root"; + fsType = "zfs"; + }; + + fileSystems."/home" = + { device = "rpool/home"; + fsType = "zfs"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/F1B9-CA7C"; + fsType = "vfat"; + options = [ "fmask=0077" "dmask=0077" ]; + }; + + swapDevices = [ ]; + + # System settings and services. + mySystem = { + system.motd.networkInterfaces = [ "enp0s31f6" "wlp4s0" ]; + }; + + }; +} diff --git a/nixos/hosts/varda/default.nix b/nixos/hosts/varda/default.nix new file mode 100644 index 0000000..f32fff3 --- /dev/null +++ b/nixos/hosts/varda/default.nix @@ -0,0 +1,34 @@ +{ ... }: { + imports = [ ]; + + networking.hostId = "cdab8473"; + networking.hostName = "varda"; # Define your hostname. + + fileSystems."/" = { + device = "rpool/root"; + fsType = "zfs"; + }; + + fileSystems."/home" = { + device = "rpool/home"; + fsType = "zfs"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/8091-E7F2"; + fsType = "vfat"; + }; + + swapDevices = [ ]; + + # System settings and services. + mySystem = { + system.motd.networkInterfaces = [ "enp1s0" ]; + security.acme.enable = true; + services = { + forgejo.enable = true; + nginx.enable = true; + }; + }; + +} diff --git a/nixos/lib/default.nix b/nixos/lib/default.nix new file mode 100644 index 0000000..a2e796a --- /dev/null +++ b/nixos/lib/default.nix @@ -0,0 +1,43 @@ +{ lib, ... }: + +with lib; +rec { + + firstOrDefault = first: default: if first != null then first else default; + existsOrDefault = x: set: default: if builtins.hasAttr x set then builtins.getAttr x set else default; + + # main service builder + mkService = options: ( + let + user = existsOrDefault "user" options "568"; + group = existsOrDefault "group" options "568"; + + enableBackups = (lib.attrsets.hasAttrByPath [ "persistence" "folder" ] options) + && (lib.attrsets.attrByPath [ "persistence" "enable" ] true options); + + # Security options for containers + containerExtraOptions = lib.optionals (lib.attrsets.attrByPath [ "container" "caps" "privileged" ] false options) [ "--privileged" ] + ++ lib.optionals (lib.attrsets.attrByPath [ "container" "caps" "readOnly" ] false options) [ "--read-only" ] + ++ lib.optionals (lib.attrsets.attrByPath [ "container" "caps" "tmpfs" ] false options) [ (map (folders: "--tmpfs=${folders}") tmpfsFolders) ] + ++ lib.optionals (lib.attrsets.attrByPath [ "container" "caps" "noNewPrivileges" ] false options) [ "--security-opt=no-new-privileges" ] + ++ lib.optionals (lib.attrsets.attrByPath [ "container" "caps" "dropAll" ] false options) [ "--cap-drop=ALL" ] + ; + in + { + virtualisation.oci-containers.containers.${options.app} = mkIf options.container.enable { + image = "${options.container.image}"; + user = "${user}:${group}"; + environment = { + TZ = options.timeZone; + } // options.container.env; + environmentFiles = lib.attrsets.attrByPath [ "container" "envFiles" ] [ ] options; + volumes = [ "/etc/localtime:/etc/localtime:ro" ] ++ + lib.optionals (lib.attrsets.hasAttrByPath [ "container" "persistentFolderMount" ] options) [ + "${options.persistence.folder}:${options.container.persistentFolderMount}:rw" + ] ++ lib.attrsets.attrByPath [ "container" "volumes" ] [ ] options; + extraOptions = containerExtraOptions; + }; + systemd.tmpfiles.rules = lib.optionals (lib.attrsets.hasAttrByPath [ "persistence" "folder" ] options) [ "d ${options.persistence.folder} 0750 ${user} ${group} -" ]; + } + ); +} diff --git a/nixos/modules/.gitkeep b/nixos/modules/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/nixos/modules/README.md b/nixos/modules/README.md new file mode 100644 index 0000000..b82e9a9 --- /dev/null +++ b/nixos/modules/README.md @@ -0,0 +1,9 @@ +## Modules + +A set of 'custom' modules with the aim to enable easy on/off/settings to build up a system modularly to my 'specs'. + +The main goal is to build up a `mySystem` options key which is easy to read and toggle functionality on and off. + +This option key will largely be manipulated by a profile to build up a host to a base, then toggle specific options from there. + +I will _try_ and only do modules for things I want to be able to configure, and just use nixos config directly for some simple static things. diff --git a/nixos/modules/default.nix b/nixos/modules/default.nix new file mode 100644 index 0000000..5c4694e --- /dev/null +++ b/nixos/modules/default.nix @@ -0,0 +1,3 @@ +{ + mySystem = import ./nixos; +} diff --git a/nixos/modules/nixos/containers/backrest/default.nix b/nixos/modules/nixos/containers/backrest/default.nix new file mode 100644 index 0000000..393118e --- /dev/null +++ b/nixos/modules/nixos/containers/backrest/default.nix @@ -0,0 +1,56 @@ +{ lib, config, ... }: +with lib; +let + app = "backrest"; + image = "garethgeorge/backrest:v1.1.0"; + user = "568"; #string + group = "568"; #string + port = 9898; #int + cfg = config.mySystem.services.${app}; + appFolder = "/var/lib/${app}"; + # persistentFolder = "${config.mySystem.persistentFolder}/var/lib/${appFolder}"; +in +{ + options.mySystem.services.${app} = + { + enable = mkEnableOption "${app}"; + addToHomepage = mkEnableOption "Add ${app} to homepage" // { default = true; }; + }; + + config = mkIf cfg.enable { + # ensure folder exist and has correct owner/group + systemd.tmpfiles.rules = [ + "d ${appFolder}/config 0750 ${user} ${group} -" + "d ${appFolder}/data 0750 ${user} ${group} -" + "d ${appFolder}/cache 0750 ${user} ${group} -" + ]; + + virtualisation.oci-containers.containers.${app} = { + image = "${image}"; + user = "${user}:${group}"; + environment = { + BACKREST_PORT = "9898"; + BACKREST_DATA = "/data"; + BACKREST_CONFIG = "/config/config.json"; + XDG_CACHE_HOME = "/cache"; + }; + volumes = [ + "${appFolder}/nixos/config:/config:rw" + "${appFolder}/nixos/data:/data:rw" + "${appFolder}/nixos/cache:/cache:rw" + "${config.mySystem.nasFolder}/backup/nixos/nixos:/repos:rw" + "/etc/localtime:/etc/localtime:ro" + ]; + }; + + services.nginx.virtualHosts."${app}.${config.networking.domain}" = { + useACMEHost = config.networking.domain; + forceSSL = true; + locations."^~ /" = { + proxyPass = "http://${app}:${builtins.toString port}"; + extraConfig = "resolver 10.88.0.1;"; + }; + }; + + }; +} diff --git a/nixos/modules/nixos/containers/default.nix b/nixos/modules/nixos/containers/default.nix new file mode 100644 index 0000000..1f6a0d1 --- /dev/null +++ b/nixos/modules/nixos/containers/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./backrest + ]; +} diff --git a/nixos/modules/nixos/de/default.nix b/nixos/modules/nixos/de/default.nix new file mode 100644 index 0000000..d543173 --- /dev/null +++ b/nixos/modules/nixos/de/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./gnome.nix + ]; +} diff --git a/nixos/modules/nixos/de/gnome.nix b/nixos/modules/nixos/de/gnome.nix new file mode 100644 index 0000000..12d3daa --- /dev/null +++ b/nixos/modules/nixos/de/gnome.nix @@ -0,0 +1,101 @@ +{ lib, config, pkgs, ... }: +with lib; +let + cfg = config.mySystem.de.gnome; +in +{ + options.mySystem.de.gnome.enable = mkEnableOption "GNOME"; + options.mySystem.de.gnome.systrayicons = mkEnableOption "Enable systray icons" // { default = true; }; + options.mySystem.de.gnome.gsconnect = mkEnableOption "Enable gsconnect (KDEConnect for GNOME)" // { default = true; }; + + config = mkIf cfg.enable { + + # Ref: https://nixos.wiki/wiki/GNOME + + # GNOME plz + services = { + displayManager = { + defaultSession = "gnome"; + autoLogin = { + enable = false; + user = "jahanson"; # TODO move to config overlay + }; + }; + + xserver = { + enable = true; + xkb.layout = "us"; # `localctl` will give you + + displayManager = { + gdm.enable = true; + }; + desktopManager = { + # GNOME + gnome.enable = true; + }; + }; + + udev.packages = optionals cfg.systrayicons [ pkgs.gnome.gnome-settings-daemon ]; # support appindicator + }; + + # systyray icons + # extra pkgs and extensions + environment = { + systemPackages = with pkgs; [ + wl-clipboard # ls ~/Downloads | wl-copy or wl-paste > clipboard.txt + playerctl # gsconnect play/pause command + pamixer # gcsconnect volume control + gnome.gnome-tweaks + gnome.dconf-editor + + # This installs the extension packages, but + # dont forget to enable them per-user in dconf settings -> "org/gnome/shell" + gnomeExtensions.vitals + gnomeExtensions.caffeine + gnomeExtensions.dash-to-dock + ] + ++ optionals cfg.systrayicons [ pkgs.gnomeExtensions.appindicator ]; + }; + + # enable gsconnect + # this method also opens the firewall ports required when enable = true + programs.kdeconnect = mkIf + cfg.gsconnect + { + enable = true; + package = pkgs.gnomeExtensions.gsconnect; + }; + + # GNOME connection to browsers - requires flag on browser as well + services.gnome.gnome-browser-connector.enable = lib.any + (user: user.programs.firefox.enable) + (lib.attrValues config.home-manager.users); + + # And dconf + programs.dconf.enable = true; + + # Exclude default GNOME packages that dont interest me. + environment.gnome.excludePackages = + (with pkgs; [ + gnome-photos + gnome-tour + gedit # text editor + ]) + ++ (with pkgs.gnome; [ + cheese # webcam tool + gnome-music + gnome-terminal + epiphany # web browser + geary # email reader + evince # document viewer + gnome-characters + totem # video player + tali # poker game + iagno # go game + hitori # sudoku game + atomix # puzzle game + ]); + }; + + +} diff --git a/nixos/modules/nixos/default.nix b/nixos/modules/nixos/default.nix new file mode 100644 index 0000000..ff18995 --- /dev/null +++ b/nixos/modules/nixos/default.nix @@ -0,0 +1,62 @@ +{ lib, config, ... }: +with lib; +{ + imports = [ + ./system + ./programs + ./services + ./de + ./hardware + ./containers + ./lib.nix + ./security + ]; + + options.mySystem.persistentFolder = mkOption { + type = types.str; + description = "persistent folder for nixos mutable files"; + default = "/persist"; + }; + + options.mySystem.nasFolder = mkOption { + type = types.str; + description = "folder where nas mounts reside"; + default = "/mnt/nas"; + }; + + options.mySystem.nasAddress = mkOption { + type = types.str; + description = "NAS Address or name for the backup nas"; + default = "10.1.1.13"; + }; + + options.mySystem.domain = mkOption { + type = types.str; + description = "domain for hosted services"; + default = ""; + }; + + options.mySystem.internalDomain = mkOption { + type = types.str; + description = "domain for local devices"; + default = ""; + }; + + options.mySystem.purpose = mkOption { + type = types.str; + description = "System purpose"; + default = "Production"; + }; + + options.mySystem.monitoring.prometheus.scrapeConfigs = mkOption { + type = lib.types.listOf lib.types.attrs; + description = "Prometheus scrape targets"; + default = [ ]; + }; + + config = { + systemd.tmpfiles.rules = [ + "d ${config.mySystem.persistentFolder} 777 - - -" #The - disables automatic cleanup, so the file wont be removed after a period + ]; + }; +} diff --git a/nixos/modules/nixos/hardware/default.nix b/nixos/modules/nixos/hardware/default.nix new file mode 100644 index 0000000..efa0833 --- /dev/null +++ b/nixos/modules/nixos/hardware/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./nvidia + ]; +} diff --git a/nixos/modules/nixos/hardware/nvidia/default.nix b/nixos/modules/nixos/hardware/nvidia/default.nix new file mode 100644 index 0000000..1d14f4c --- /dev/null +++ b/nixos/modules/nixos/hardware/nvidia/default.nix @@ -0,0 +1,79 @@ +{ lib, config, pkgs, ... }: +with lib; +let + cfg = config.mySystem.hardware.nvidia; +in +{ + options.mySystem.hardware.nvidia.enable = mkEnableOption "NVIDIA config"; + + config = mkIf cfg.enable { + + # ref: https://nixos.wiki/wiki/Nvidia + # Enable OpenGL + hardware.opengl = { + enable = true; + driSupport = true; + driSupport32Bit = true; + }; + + hardware.opengl.extraPackages = with pkgs; [ + vaapiVdpau + ]; + + # This is for the benefit of VSCODE running natively in wayland + environment.sessionVariables.NIXOS_OZONE_WL = "1"; + + hardware.nvidia = { + + # Modesetting is required. + modesetting.enable = true; + + # Nvidia power management. Experimental, and can cause sleep/suspend to fail. + # Enable this if you have graphical corruption issues or application crashes after waking + # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead + # of just the bare essentials. + powerManagement.enable = false; + + # Fine-grained power management. Turns off GPU when not in use. + # Experimental and only works on modern Nvidia GPUs (Turing or newer). + powerManagement.finegrained = false; + + # Use the NVidia open source kernel module (not to be confused with the + # independent third-party "nouveau" open source driver). + # Support is limited to the Turing and later architectures. Full list of + # supported GPUs is at: + # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus + # Only available from driver 515.43.04+ + # Currently alpha-quality/buggy, so false is currently the recommended setting. + open = false; + + # Enable the Nvidia settings menu, + # accessible via `nvidia-settings`. + nvidiaSettings = true; + + # Optionally, you may need to select the appropriate driver version for your specific GPU. + # package = config.boot.kernelPackages.nvidiaPackages.stable; + + # manual build nvidia driver, works around some wezterm issues + # https://github.com/wez/wezterm/issues/2011 + package = + # let + # rcu_patch = pkgs.fetchpatch { + # url = "https://github.com/gentoo/gentoo/raw/c64caf53/x11-drivers/nvidia-drivers/files/nvidia-drivers-470.223.02-gpl-pfn_valid.patch"; + # hash = "sha256-eZiQQp2S/asE7MfGvfe6dA/kdCvek9SYa/FFGp24dVg="; + # }; + # in + config.boot.kernelPackages.nvidiaPackages.mkDriver { + version = "550.67"; + sha256_64bit = "sha256-mSAaCccc/w/QJh6w8Mva0oLrqB+cOSO1YMz1Se/32uI="; + sha256_aarch64 = "sha256-+UuK0UniAsndN15VDb/xopjkdlc6ZGk5LIm/GNs5ivA="; + openSha256 = "sha256-M/1qAQxTm61bznAtCoNQXICfThh3hLqfd0s1n1BFj2A="; + settingsSha256 = "sha256-FUEwXpeUMH1DYH77/t76wF1UslkcW721x9BHasaRUaM="; + persistencedSha256 = "sha256-ojHbmSAOYl3lOi2X6HOBlokTXhTCK6VNsH6+xfGQsyo="; + # patches = [ rcu_patch ]; + }; + }; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + }; +} diff --git a/nixos/modules/nixos/lib.nix b/nixos/modules/nixos/lib.nix new file mode 100644 index 0000000..dbe8dc9 --- /dev/null +++ b/nixos/modules/nixos/lib.nix @@ -0,0 +1,83 @@ +{ lib, config, pkgs, ... }: +with lib; +{ + + # container builder + lib.mySystem.mkContainer = options: ( + let + # nix doesnt have an exhausive list of options for oci + # so here i try to get a robust list of security options for containers + # because everyone needs more tinfoild hat right? RIGHT? + + containerExtraOptions = lib.optionals (lib.attrsets.attrByPath [ "caps" "privileged" ] false options) [ "--privileged" ] + ++ lib.optionals (lib.attrsets.attrByPath [ "caps" "readOnly" ] false options) [ "--read-only" ] + ++ lib.optionals (lib.attrsets.attrByPath [ "caps" "tmpfs" ] false options) [ (map (folders: "--tmpfs=${folders}") tmpfsFolders) ] + ++ lib.optionals (lib.attrsets.attrByPath [ "caps" "noNewPrivileges" ] false options) [ "--security-opt=no-new-privileges" ] + ++ lib.optionals (lib.attrsets.attrByPath [ "caps" "dropAll" ] false options) [ "--cap-drop=ALL" ]; + + in + { + ${options.app} = { + image = "${options.image}"; + user = "${options.user}:${options.group}"; + environment = { + TZ = config.time.timeZone; + } // lib.attrsets.attrByPath [ "env" ] { } options; + environmentFiles = lib.attrsets.attrByPath [ "envFiles" ] [ ] options; + volumes = [ "/etc/localtime:/etc/localtime:ro" ] + ++ lib.attrsets.attrByPath [ "volumes" ] [ ] options; + ports = lib.attrsets.attrByPath [ "ports" ] [ ] options; + extraOptions = containerExtraOptions; + }; + } + ); + + # build a restic restore set for both local and remote + lib.mySystem.mkRestic = options: ( + let + excludePath = if builtins.hasAttr "excludePath" options then options.excludePath else [ ]; + timerConfig = { + OnCalendar = "02:05"; + Persistent = true; + RandomizedDelaySec = "3h"; + }; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + ]; + initialize = true; + backupPrepareCommand = '' + # remove stale locks - this avoids some occasional annoyance + # + ${pkgs.restic}/bin/restic unlock --remove-all || true + ''; + in + { + # local backup + "${options.app}-local" = { + inherit pruneOpts timerConfig initialize backupPrepareCommand; + # Move the path to the zfs snapshot path + paths = map (x: "${config.mySystem.system.resticBackup.mountPath}/${x}") options.paths; + passwordFile = config.sops.secrets."services/restic/password".path; + exclude = excludePath; + repository = "${config.mySystem.system.resticBackup.local.location}/${options.appFolder}"; + # inherit (options) user; + }; + + # remote backup + "${options.app}-remote" = { + inherit pruneOpts timerConfig initialize backupPrepareCommand; + # Move the path to the zfs snapshot path + paths = map (x: "${config.mySystem.system.resticBackup.mountPath}/${x}") options.paths; + environmentFile = config.sops.secrets."services/restic/env".path; + passwordFile = config.sops.secrets."services/restic/password".path; + repository = "${config.mySystem.system.resticBackup.remote.location}/${options.appFolder}"; + exclude = excludePath; + # inherit (options) user; + }; + + } + ); + +} diff --git a/nixos/modules/nixos/programs/default.nix b/nixos/modules/nixos/programs/default.nix new file mode 100644 index 0000000..5cf8372 --- /dev/null +++ b/nixos/modules/nixos/programs/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./shell + ]; +} diff --git a/nixos/modules/nixos/programs/shell/default.nix b/nixos/modules/nixos/programs/shell/default.nix new file mode 100644 index 0000000..56cb916 --- /dev/null +++ b/nixos/modules/nixos/programs/shell/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./fish.nix + ]; +} diff --git a/nixos/modules/nixos/programs/shell/fish.nix b/nixos/modules/nixos/programs/shell/fish.nix new file mode 100644 index 0000000..9ee8179 --- /dev/null +++ b/nixos/modules/nixos/programs/shell/fish.nix @@ -0,0 +1,28 @@ +{ lib, config, ... }: +with lib; +let + cfg = config.mySystem.shell.fish; +in +{ + options.mySystem.shell.fish = + { + enable = mkEnableOption "Fish"; + enablePlugins = mkOption + { + type = lib.types.bool; + description = "If we want to add fish plugins"; + default = true; + }; + }; + + # Install fish systemwide + config.programs.fish = mkIf cfg.enable { + enable = true; + vendor = { + completions.enable = true; + config.enable = true; + functions.enable = true; + }; + }; + +} diff --git a/nixos/modules/nixos/security/acme/default.nix b/nixos/modules/nixos/security/acme/default.nix new file mode 100644 index 0000000..c0a88b0 --- /dev/null +++ b/nixos/modules/nixos/security/acme/default.nix @@ -0,0 +1,36 @@ +{ lib, config, ... }: +with lib; +let + cfg = config.mySystem.security.acme; +in +{ + options.mySystem.security.acme.enable = mkEnableOption "acme"; + + config = mkIf cfg.enable { + sops.secrets = { + "security/acme/env".sopsFile = ./secrets.sops.yaml; + "security/acme/env".restartUnits = [ "lego.service" ]; + }; + + environment.persistence."${config.mySystem.system.impermanence.persistPath}" = lib.mkIf config.mySystem.system.impermanence.enable { + directories = [ "/var/lib/acme" ]; + }; + + security.acme = { + acceptTerms = true; + defaults.email = "admin@${config.networking.domain}"; + + certs.${config.networking.domain} = { + extraDomainNames = [ + "${config.networking.domain}" + "*.${config.networking.domain}" + ]; + dnsProvider = "cloudflare"; + dnsResolver = "1.1.1.1:53"; + credentialsFile = config.sops.secrets."security/acme/env".path; + }; + }; + + + }; +} diff --git a/nixos/modules/nixos/security/acme/secrets.sops.yaml b/nixos/modules/nixos/security/acme/secrets.sops.yaml new file mode 100644 index 0000000..42d2994 --- /dev/null +++ b/nixos/modules/nixos/security/acme/secrets.sops.yaml @@ -0,0 +1,50 @@ +security: + acme: + env: ENC[AES256_GCM,data:/exabYG1GvSCxe+TBeECudCN6DQLVBrifa9509skrNRYBsbm1UJRK+WxO0xcrAQkcb1Lse4WE95ueQurSFaY81w=,iv:oD2zcXbO12TlOeH0xLYsaHWw4PVjMHtbVm1LAWp89oo=,tag:dwGBevRXV1B4n/5Sveq5cg==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age18kj3xhlvgjeg2awwku3r8d95w360uysu0w5ejghnp4kh8qmtge5qwa2vjp + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGVEVHekhud2xUclpURFZB + bzgrSkh2TWFibndHcTBpb3AySjRnUWliYzJBCmlROE83ZmJNbWpLaTExOUNwTmZw + dElIUThUQVo3MjlobjVrdFMrZUJHM1EKLS0tIGVlcU16Vm12eERKN1o1Ym1yRnJB + UkR2YUlLSnBWT0QrWTJuS0hRMnhBM2MKBaaD1gtd52RwKKPf7Yi7fhVEot6kIhAg + oaS589WtWIiIiEs/Fde8QfOEJ4aydhuyfVFGxsJkb8a5QGkjKP4Faw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1z3vjvkead2h934n3w4m5m7tg4tj5qlzagsq6ly84h3tcu7x4ldsqd3s5fg + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiSEwyT21iZHl2cEtKZTRG + RGwwclFtTnNkK2c0U2U0U2NTWTkrckllbHhrCkprUTRxcFJnT3hTS3VuUjZXQUti + MDNWZGMrSmFDL2svaTJDZlEwcFpEeEUKLS0tIEVBMDlxZmVEU0UreS9KZnNodWcy + bUF2WVRySUd6NDJpbFRiYWszVlFYeGMK7Cl76mjrhdMNKy3SXQ4KqpUJl/P9peJc + O+EZ0Q1m0tZrShg1soqdMb1p/00ubvy+Rvxx5Tq0jsIF/Lq0Y3Q3CA== + -----END AGE ENCRYPTED FILE----- + - recipient: age1a8z3p24v32l9yxm5z2l8h7rpc3nhacyfv4jvetk2lenrvsdstd3sdu2kaf + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5U0cyRlFDaCsvSEZyeE1q + WXpUdU5teVpGT1J6dkJ3VHJudG5UaEIvMlYwCm8xcldxOTFEV3JJbUhYbHNjZjgw + T2tDZERTNnZtdVEvNWo5STZTdzZYbnMKLS0tIHpXQUREODAzOWIzcGVxZFJ1a2Rh + S2U3T2NUdkVKL3VhWGtRTXUrclJ3TnMKE+6waO9P3EWCGeBRmh3OH689ttLU0F0G + hEeBbwYSXfrXtHGSEwwNo++5vP1UVA7KUvLTF2G3mM2nhztJwacWtg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1d9p83j52m2xg0vh9k7q0uwlxwhs3y6tlv68yg9s2h9mdw2fmmsqshddz5m + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsSEREWEtSWTFUN1l3Uktp + YlJCNUZEMnBJL0xQc21VenBkVTgrcVBDQlJFCm51QkhVK2J4ODNQN3AyZ2V4dnQw + SVI2blo4SzdSYVdpeDluSFJ1YjFscXMKLS0tIEFMQXAyMGc2MHdMYjkxeHZOWHJ3 + TnJ6dFBkUGpXMTBjRU5MMVJGTWZmd2sKh83VVst9g3e9lbx2v3b46X23HHtQAeS/ + //oLEkBDuk5yqnNFtbcSGsWI9DBh9mD87bupw0Hz7GXTC/5LkApTkQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-05-18T16:39:41Z" + mac: ENC[AES256_GCM,data:tiHQmGUiTuM6aH5Vf9abJUIPDlQ73vmXHCNvkoBHanX7k9ScDxpByqgnDaIR2Tue4SusVVgXFpAlSda9fTT/bSgLUA1+0Qxo4YDLRz5I0pp4sCXAGVELHguADKwAbv+AyT7x4idzecLZ532RGqKkLWHljfOzHtAAlA8FBHH3ylk=,iv:iHlFeshdBreirhJGCBYUucUkz0oEbxYLo6dIeab73e0=,tag:ZeUXSWla9hDldeoqFIw+/g==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/nixos/modules/nixos/security/default.nix b/nixos/modules/nixos/security/default.nix new file mode 100644 index 0000000..32c8ab0 --- /dev/null +++ b/nixos/modules/nixos/security/default.nix @@ -0,0 +1,6 @@ +{ ... }: +{ + imports = [ + ./acme + ]; +} diff --git a/nixos/modules/nixos/services/cockpit/default.nix b/nixos/modules/nixos/services/cockpit/default.nix new file mode 100644 index 0000000..17d589f --- /dev/null +++ b/nixos/modules/nixos/services/cockpit/default.nix @@ -0,0 +1,22 @@ +{ lib, config, pkgs, ... }: +with lib; +let + cfg = config.mySystem.services.cockpit; +in +{ + options.mySystem.services.cockpit.enable = mkEnableOption "Cockpit"; + + config.services.cockpit = mkIf cfg.enable { + enable = true; + openFirewall = true; + package = pkgs.cockpit.overrideAttrs (old: { + # remove packagekit and selinux, don't work on NixOS + postBuild = '' + ${old.postBuild} + rm -rf \ + dist/packagekit \ + dist/selinux + ''; + }); + }; +} diff --git a/nixos/modules/nixos/services/default.nix b/nixos/modules/nixos/services/default.nix new file mode 100644 index 0000000..c382e27 --- /dev/null +++ b/nixos/modules/nixos/services/default.nix @@ -0,0 +1,12 @@ +{ + imports = [ + ./cockpit + ./forgejo + ./nginx + ./podman + ./postgresql + ./radicale + ./reboot-required-check.nix + ./restic + ]; +} diff --git a/nixos/modules/nixos/services/forgejo/default.nix b/nixos/modules/nixos/services/forgejo/default.nix new file mode 100644 index 0000000..d07b262 --- /dev/null +++ b/nixos/modules/nixos/services/forgejo/default.nix @@ -0,0 +1,92 @@ +{ lib, config, ... }: +with lib; +let + cfg = config.mySystem.services.forgejo; + http_port = 3000; + serviceUser = "forgejo"; + domain = "git.hsn.dev"; +in +{ + options.mySystem.services.forgejo = { + enable = mkEnableOption "Forgejo"; + }; + + config = mkIf cfg.enable { + services.nginx = { + virtualHosts.${domain} = { + forceSSL = true; + useACMEHost = config.networking.domain; + extraConfig = '' + client_max_body_size 512M; + ''; + locations."/".proxyPass = "http://127.0.0.1:${toString http_port}"; + }; + }; + + services.forgejo = { + enable = true; + # enable sql db dumps daily + dump.enable = true; + database.type = "postgres"; + # Enable support for Git Large File Storage + lfs.enable = true; + settings = { + server = { + DOMAIN = domain; + # You need to specify this to remove the port from URLs in the web UI. + ROOT_URL = "https://${domain}/"; + HTTP_PORT = http_port; + # Default landing page on 'explore' + LANDING_PAGE = "explore"; + }; + # You can temporarily allow registration to create an admin user. + service = { + DISABLE_REGISTRATION = true; + ENABLE_NOTIFY_MAIL = true; + REGISTER_EMAIL_CONFIRM = true; + REQUIRE_SIGNIN_VIEW = false; + }; + indexer = { + REPO_INDEXER_ENABLED = true; + REPO_INDEXER_PATH = "indexers/repos.bleve"; + MAX_FILE_SIZE = 1048576; + REPO_INDEXER_INCLUDE = ""; + REPO_INDEXER_EXCLUDE = "resources/bin/**"; + }; + picture = { + AVATAR_UPLOAD_PATH = "/var/lib/forgejo/data/avatars"; + REPOSITORY_AVATAR_UPLOAD_PATH = "/var/lib/forgejo/data/repo-avatars"; + }; + # Add support for actions, based on act: https://github.com/nektos/act + actions = { + ENABLED = true; + }; + # Sending emails is completely optional + # You can send a test email from the web UI at: + # Profile Picture > Site Administration > Configuration > Mailer Configuration + mailer = { + ENABLED = true; + SMTP_ADDR = "smtp.mailgun.org"; + FROM = "git@hsn.dev"; + USER = "git@mg.hsn.dev"; + SMTP_PORT = 587; + }; + session = { + COOKIE_SECURE = true; + COOKIE_NAME = "session"; + }; + }; + mailerPasswordFile = config.sops.secrets."services/forgejo/smtp/password".path; + }; + # sops + sops.secrets."services/forgejo/smtp/password" = { + sopsFile = ./secrets.sops.yaml; + owner = serviceUser; + mode = "400"; + restartUnits = [ "forgejo.service" ]; + }; + environment.persistence."${config.mySystem.system.impermanence.persistPath}" = lib.mkIf config.mySystem.system.impermanence.enable { + directories = [ "/var/lib/forgejo" ]; + }; + }; +} diff --git a/nixos/modules/nixos/services/forgejo/secrets.sops.yaml b/nixos/modules/nixos/services/forgejo/secrets.sops.yaml new file mode 100644 index 0000000..5f87110 --- /dev/null +++ b/nixos/modules/nixos/services/forgejo/secrets.sops.yaml @@ -0,0 +1,51 @@ +services: + forgejo: + smtp: + password: ENC[AES256_GCM,data:p5iDVW+V0aIlj9RTHpMgko/1ahVkiHXafgm2u2g3TTrYFORBqCJqv+lCSSm4mGIabn4=,iv:GIx/dnn1y6Is6uzKEkmo326AUSS+I5RnLsV2duKHPBo=,tag:7R4222rGEsK+egunnB+llg==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age18kj3xhlvgjeg2awwku3r8d95w360uysu0w5ejghnp4kh8qmtge5qwa2vjp + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVOU9SMEZvQUxhZWU2dzJ0 + Z1ZUODd0R2Rtb2lmaHhweC9Tb0J2anJuRno4Cis5UGZHc3pobkQ2OUJwSy9tV1RF + SmNvUi9Xek9oVFdPdzZQUnlJeWtBSEEKLS0tIFpoWTZOYlFOK2p4bTFaUVhGV1hz + dlpWOWhLT2VtYXdDQjJlWnh4T05TT3MKJtewm9QN1EfT8IQkkHdH0GGNDyg1wH6Z + Ja6lcZB580FPEHwoMC7cayQe5v82vbQsj6s8mOaUW9yRQLMQMkmOfA== + -----END AGE ENCRYPTED FILE----- + - recipient: age1z3vjvkead2h934n3w4m5m7tg4tj5qlzagsq6ly84h3tcu7x4ldsqd3s5fg + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6bUNpMWJ1YklkV1JPMnFi + S0tiajlKblV5aTU2djJaQjN0M1IwOU9pdTNRCnFycmQ5WHFadmxhZ1R6a1ZHYjlW + TjVCN2dUelc5Qkt5Y0ZtYUtNRHN0WTAKLS0tIDFKSUE2YzFmQzB1TjgrRDFEalJO + MDg0bU9NS3VObVVYNDAvY1JIRU5xZEEKSWzp9smLNYypodRIh49XPBxS536XtFWf + kJWaLiUfULifcN46F8Tyts9dGHXx/bOgM5rCFAqtqTL7EaJbam13pw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1a8z3p24v32l9yxm5z2l8h7rpc3nhacyfv4jvetk2lenrvsdstd3sdu2kaf + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuQ09PSWwyY2tGZzdyOGxq + KzZuUW95Z2QzVXY4dk5tRGZ3MXMxNW9INXlRCmkra2t2UUMwWnBhM0VoTnpUaWIx + UW13a3VxZWJyL0ZDdk1IVXJNQitpblkKLS0tIGMwZHJqOGt4Y2FCUUUrc2tEQjY0 + eWp3WmdOMUlTNVlUT3FMM0JCTnViQ28KE6rpeFodW4BAIDVdjpgPpRs26XgUya3b + Xbg6IuB90DvzNMKkoGB36Dh5cWUGFBsJ3QYopSDQGFbUepyDQa4Wvw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1d9p83j52m2xg0vh9k7q0uwlxwhs3y6tlv68yg9s2h9mdw2fmmsqshddz5m + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6VG9uejd2YTZ4c1p3akFZ + dUtEbXk3S1UzeEhLeld4VXVLK1dVKytlOEc4ClFwbVVUUG9SbzB2bDZwRHA2cE4y + STFLOWR3S0YrQ1FBbjJDV3o1aW1rNjgKLS0tIDlnQkZhRlpXanY5TzViVzdTNGpo + NDhZZ24zWmwwNVE4VDM0bllyUkdxVncKdyYx4r4ERRy2lz7b2oK4JvzF1RnIJ/mV + neTz0N1LSdmTUAOUtRT7D73tR6HhBZQNxH4LIsYiRllto46mEamx7g== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-05-18T16:39:41Z" + mac: ENC[AES256_GCM,data:TQ019mze1TDfHM3unUvhLzQOdPVhZ0lIw+CbcuSGIqpjITr7nGVRYtPMvHtY9taxaAQgpdJghOaP9MS/YR6KT9II54qYtel944rmOHxOIpB8Oy/mRHBJvx1JhQxHzxPx6hLsLxNagSbgIpyiNGwMiR2gedBLPI/BBNcPGESiMTA=,iv:m4UnG4p0eWzRmspSU/RL4HSeq3Fr5t+9FnNMxgCMOJE=,tag:w2aJxYjVoEHlaQAT+VAa7g==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/nixos/modules/nixos/services/nginx/default.nix b/nixos/modules/nixos/services/nginx/default.nix new file mode 100644 index 0000000..3ab62c4 --- /dev/null +++ b/nixos/modules/nixos/services/nginx/default.nix @@ -0,0 +1,62 @@ +{ lib, config, ... }: +with lib; +let + cfg = config.mySystem.services.nginx; +in +{ + options.mySystem.services.nginx.enable = mkEnableOption "nginx"; + + config = mkIf cfg.enable { + + services.nginx = { + enable = true; + + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + recommendedBrotliSettings = true; + + proxyResolveWhileRunning = true; # needed to ensure nginx loads even if it cant resolve vhosts + + statusPage = true; + enableReload = true; + + # Only allow PFS-enabled ciphers with AES256 + sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL"; + + appendHttpConfig = '' + # Minimize information leaked to other domains + add_header 'Referrer-Policy' 'origin-when-cross-origin'; + + # Disable embedding as a frame + add_header X-Frame-Options DENY; + + # Prevent injection of code in other mime types (XSS Attacks) + add_header X-Content-Type-Options nosniff; + + ''; + commonHttpConfig = '' + add_header X-Clacks-Overhead "GNU Terry Pratchett"; + ''; + # provide default host with returning error + # else nginx returns the first server + # in the config file... >:S + virtualHosts = { + "_" = { + default = true; + rejectSSL = true; + extraConfig = "return 444;"; + }; + }; + }; + + networking.firewall = { + allowedTCPPorts = [ 80 443 ]; + allowedUDPPorts = [ 80 443 ]; + }; + + # required for using acme certs + users.users.nginx.extraGroups = [ "acme" ]; + }; +} diff --git a/nixos/modules/nixos/services/podman/default.nix b/nixos/modules/nixos/services/podman/default.nix new file mode 100644 index 0000000..701ad7e --- /dev/null +++ b/nixos/modules/nixos/services/podman/default.nix @@ -0,0 +1,51 @@ +{ lib, config, pkgs, ... }: +with lib; +let + cfg = config.mySystem.services.podman; +in +{ + options.mySystem.services.podman.enable = mkEnableOption "Podman"; + + config = mkIf cfg.enable + { + virtualisation.podman = { + enable = true; + + dockerCompat = true; + extraPackages = [ pkgs.zfs ]; + + # regular cleanup + autoPrune.enable = true; + autoPrune.dates = "weekly"; + + # and add dns + defaultNetwork.settings = { + dns_enabled = true; + }; + }; + virtualisation.oci-containers = { + backend = "podman"; + }; + + environment.systemPackages = with pkgs; [ + podman-tui # status of containers in the terminal + lazydocker + ]; + + programs.fish.shellAliases = { + # lazydocker --> lazypodman + lazypodman="sudo DOCKER_HOST=unix:///run/podman/podman.sock lazydocker"; + }; + + networking.firewall.interfaces.podman0.allowedUDPPorts = [ 53 ]; + + # extra user for containers + users.users.kah = { + uid = 568; + group = "kah"; + }; + users.groups.kah = { }; + users.users.jahanson.extraGroups = [ "kah" ]; + }; + +} diff --git a/nixos/modules/nixos/services/postgresql/default.nix b/nixos/modules/nixos/services/postgresql/default.nix new file mode 100644 index 0000000..19f62d4 --- /dev/null +++ b/nixos/modules/nixos/services/postgresql/default.nix @@ -0,0 +1,71 @@ +{ lib, config, ... }: +with lib; +let + cfg = config.mySystem.${category}.${app}; + app = "postgresql"; + category = "services"; +in +{ + options.mySystem.${category}.${app} = + { + enable = mkEnableOption "${app}"; + addToHomepage = mkEnableOption "Add ${app} to homepage" // { default = true; }; + prometheus = mkOption + { + type = lib.types.bool; + description = "Enable prometheus scraping"; + default = true; + + }; + backupLocation = mkOption + { + type = lib.types.string; + description = "Location for sql backups to be stored."; + default = "/persist/backup/postgresql"; + }; + backup = mkOption + { + type = lib.types.bool; + description = "Enable backups"; + default = true; + }; + }; + + config = mkIf cfg.enable { + + services.postgresql = { + enable = true; + identMap = '' + # ArbitraryMapName systemUser DBUser + superuser_map root postgres + superuser_map postgres postgres + # Let other names login as themselves + superuser_map /^(.*)$ \1 + ''; + + authentication = '' + #type database DBuser auth-method optional_ident_map + local sameuser all peer map=superuser_map + ''; + + settings = { + max_connections = 200; + random_page_cost = 1.1; + }; + }; + + # enable backups + services.postgresqlBackup = mkIf cfg.backup { + enable = lib.mkForce true; + location = cfg.backupLocation; + }; + + ### firewall config + + # networking.firewall = mkIf cfg.openFirewall { + # allowedTCPPorts = [ port ]; + # allowedUDPPorts = [ port ]; + # }; + + }; +} diff --git a/nixos/modules/nixos/services/radicale/default.nix b/nixos/modules/nixos/services/radicale/default.nix new file mode 100644 index 0000000..73695ab --- /dev/null +++ b/nixos/modules/nixos/services/radicale/default.nix @@ -0,0 +1,110 @@ +{ lib, config, ... }: +with lib; +let + cfg = config.mySystem.${category}.${app}; + app = "radicale"; + category = "services"; + user = app; #string + group = app; #string + port = 5232; #int + appFolder = "/var/lib/${app}"; + url = "${app}.jahanson.tech"; +in +{ + options.mySystem.${category}.${app} = + { + enable = mkEnableOption "${app}"; + addToHomepage = mkEnableOption "Add ${app} to homepage" // { default = true; }; + monitor = mkOption + { + type = lib.types.bool; + description = "Enable gatus monitoring"; + default = true; + }; + prometheus = mkOption + { + type = lib.types.bool; + description = "Enable prometheus scraping"; + default = true; + }; + backups = mkOption + { + type = lib.types.bool; + description = "Enable local backups"; + default = true; + }; + }; + + config = mkIf cfg.enable { + + ## Secrets + sops.secrets."${category}/${app}/htpasswd" = { + sopsFile = ./secrets.sops.yaml; + owner = user; + inherit group; + restartUnits = [ "${app}.service" ]; + }; + + users.users.jahanson.extraGroups = [ group ]; + + environment.persistence."${config.mySystem.system.impermanence.persistPath}" = lib.mkIf config.mySystem.system.impermanence.enable { + hideMounts = true; + directories = [ "/var/lib/radicale/" ]; + }; + + ## service + services.radicale = { + enable = true; + settings = { + server.hosts = [ "0.0.0.0:${builtins.toString port}" ]; + auth = { + type = "htpasswd"; + htpasswd_filename = config.sops.secrets."${category}/${app}/htpasswd".path; + htpasswd_encryption = "plain"; + realm = "Radicale - Password Required"; + }; + storage.filesystem_folder = "/var/lib/radicale/collections"; + }; + }; + + ### gatus integration + mySystem.services.gatus.monitors = mkIf cfg.monitor [ + { + name = app; + group = "${category}"; + url = "https://${url}"; + interval = "1m"; + conditions = [ "[CONNECTED] == true" "[STATUS] == 200" "[RESPONSE_TIME] < 50" ]; + } + ]; + + ### Ingress + services.nginx.virtualHosts.${host} = { + useACMEHost = config.networking.domain; + forceSSL = true; + locations."/" = { + proxyPass = "http://127.0.0.1:${builtins.toString port}"; + }; + }; + + ### firewall config + + # networking.firewall = mkIf cfg.openFirewall { + # allowedTCPPorts = [ port ]; + # allowedUDPPorts = [ port ]; + # }; + + ### backups + warnings = [ + (mkIf (!cfg.backups && config.mySystem.purpose != "Development") + "WARNING: Backups for ${app} are disabled!") + ]; + + services.restic.backups = mkIf cfg.backups (config.lib.mySystem.mkRestic + { + inherit app user; + paths = [ appFolder ]; + inherit appFolder; + }); + }; +} diff --git a/nixos/modules/nixos/services/radicale/secrets.sops.yaml b/nixos/modules/nixos/services/radicale/secrets.sops.yaml new file mode 100644 index 0000000..8f721cf --- /dev/null +++ b/nixos/modules/nixos/services/radicale/secrets.sops.yaml @@ -0,0 +1,50 @@ +services: + radicale: + htpasswd: ENC[AES256_GCM,data:4y6QUrivlOpUVNAGDuPb9w==,iv:AS13cN3EKDEfRCc6USejkYG4SEFS4sPoYrfok8jsfYg=,tag:60ZhYvH/+SQhZKR6M9Zlfw==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age18kj3xhlvgjeg2awwku3r8d95w360uysu0w5ejghnp4kh8qmtge5qwa2vjp + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLc011SkxreTJSZERMemlS + clM0NnhPekF3bFZiUXUreDZEN3dkN3NmN0RNCmM3UEdlV3Azbk4yL2dpS3ZRQVpv + OWRQZ2E0eGU5cVIxRUU1c3RxMnpucEUKLS0tIHhjVXhtZEdVb3lvRnpoVGdJbkNq + WEM1bGRUOFVrOU5jbmhxSmpRK0F4WWsKoV2ABFGgcLb0qMmorOzNaAzPf6AbMfr0 + PUdIkaXLJrF3Qi3bts96KhlPLUA7llArSMrUBtkXeCit6xS+87Imuw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1z3vjvkead2h934n3w4m5m7tg4tj5qlzagsq6ly84h3tcu7x4ldsqd3s5fg + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBka1htN2tsN2ZZMkpDdHph + dk5EY1JkM0hONlRiaXFhdGVIT0xuVDA0b2tBCnlTVExGOHg5RFdiRzU0RWd3dEg3 + aXB2UkhQRUF6QnBRN0FnNjRqMWIwRkUKLS0tIHJxOWNmR09PRVFQK1E3Um1laHJj + VmdPdHl0OGtGODBIZHVzelByaVVoRTAKWb7/Th4zdNFo+K+rwi+nHpbftxnnMOlt + BV0hsMpFBaQZXw01n9uw71MZiJZAbZOMA9P+toMKL9UwWSx+isa3gA== + -----END AGE ENCRYPTED FILE----- + - recipient: age1a8z3p24v32l9yxm5z2l8h7rpc3nhacyfv4jvetk2lenrvsdstd3sdu2kaf + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNVTdVN1VnN1JpWkJFWC95 + Qmc3dUNQdUtWSjRwWlVSVlJ2aGZ1MXIrMEFJCjNtck5vcGVhNnFQNXk2MjlHSC9P + aDU3WHQwbWdtbTBMcWdCUFE4Ulg5RlkKLS0tIGFDYnpGNE1SY2cvaUk4cWtBVmN6 + VGRIaEpkUk1qN1RsakV2YkdCbGJhUGcK8l4O+ysy9MeOq5uqnzt9GdkkH53BPtFf + rmONh4pxPogBB0IsvZBz2NUsKkixnucEK0+SrF2X5x0wveMl/2Nm3Q== + -----END AGE ENCRYPTED FILE----- + - recipient: age1d9p83j52m2xg0vh9k7q0uwlxwhs3y6tlv68yg9s2h9mdw2fmmsqshddz5m + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3d2FMMStGS2dSYVcxMHNM + QXdPenBQMXJlWFJWcHp0U0h0SkNpWWlNdXgwClBTMk1TQXg4M3ZueVZha1dNN1gv + cTNuS3hBblNPQjBCa3o3N2xyNG9EZWMKLS0tIEo5SVc1b04xZndSNXQ4T3BOTmtr + M1NVZkphS2E1R2c3dWovcHlaTloxTkUKsDiyHq40XddMdcZ/2UmOUnPSu44SWTRZ + ZcDiYbfU4R7Ysgqaxl2iqBun/GOPWf4yeAbcynwXsLMUGG+XnsRWVw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-05-18T16:39:41Z" + mac: ENC[AES256_GCM,data:9HLkT8t+LOSeVCWbjMhXMi7XduJ0nw4nZz9/dYCeyMW0w0/NscYn2avSUSks/5j14xAt4/NFmuM+KxW6z2dEdXE7DsCo1nWh+WyaTpL1QUId5xSWc6abQaexaKeRu/3QJ1wLNFgotaCuut96iFFTmvDL+t266ozxst8N3iR7zhk=,iv:NQwgSFv6Ogybrs6BMYl9eLeu0kNIJpmHR0MJCYHbCxA=,tag:X3BkmlHDt3E3GFT1iDYJHg==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/nixos/modules/nixos/services/reboot-required-check.nix b/nixos/modules/nixos/services/reboot-required-check.nix new file mode 100644 index 0000000..c1446c6 --- /dev/null +++ b/nixos/modules/nixos/services/reboot-required-check.nix @@ -0,0 +1,45 @@ +{ lib, config, ... }: +with lib; +let + cfg = config.mySystem.services.rebootRequiredCheck; +in +{ + options.mySystem.services.rebootRequiredCheck.enable = mkEnableOption "Reboot required check"; + + config = mkIf cfg.enable { + # Enable timer + systemd.timers."reboot-required-check" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + # start at boot + OnBootSec = "0m"; + # check every hour + OnUnitActiveSec = "1h"; + Unit = "reboot-required-check.service"; + }; + }; + + # Below script will check if initrd, kernel, kernel-modules that were booted match the current system + # i.e. if a nixos-rebuild switch has upgraded anything + systemd.services."reboot-required-check" = { + script = '' + #!/usr/bin/env bash + + # compare current system with booted sysetm to determine if a reboot is required + if [[ "$(readlink /run/booted-system/{initrd,kernel,kernel-modules})" == "$(readlink /run/current-system/{initrd,kernel,kernel-modules})" ]]; then + # check if the '/var/run/reboot-required' file exists and if it does, remove it + if [[ -f /var/run/reboot-required ]]; then + rm /var/run/reboot-required || { echo "Failed to remove /var/run/reboot-required"; exit 1; } + fi + else + echo "reboot required" + touch /var/run/reboot-required || { echo "Failed to create /var/run/reboot-required"; exit 1; } + fi + ''; + serviceConfig = { + Type = "oneshot"; + User = "root"; + }; + }; + }; +} diff --git a/nixos/modules/nixos/services/restic/default.nix b/nixos/modules/nixos/services/restic/default.nix new file mode 100644 index 0000000..2dd01a6 --- /dev/null +++ b/nixos/modules/nixos/services/restic/default.nix @@ -0,0 +1,102 @@ +{ lib, config, pkgs, ... }: +with lib; +let + cfg = config.mySystem.system.resticBackup; +in +{ + options.mySystem.system.resticBackup = { + local = { + enable = mkEnableOption "Local backups" // { default = true; }; + location = mkOption + { + type = types.str; + description = "Location for local backups"; + default = ""; + }; + }; + remote = { + enable = mkEnableOption "Remote backups" // { default = true; }; + location = mkOption + { + type = types.str; + description = "Location for remote backups"; + default = ""; + }; + }; + mountPath = mkOption + { + type = types.str; + description = "Location for snapshot mount"; + default = "/mnt/nightly_backup"; + }; + }; + config = { + + # Warn if backups are disable and machine isnt a dev box + warnings = [ + (mkIf (!cfg.local.enable && config.mySystem.purpose != "Development") "WARNING: Local backups are disabled!") + (mkIf (!cfg.remote.enable && config.mySystem.purpose != "Development") "WARNING: Remote backups are disabled!") + ]; + + sops.secrets = mkIf (cfg.local.enable || cfg.remote.enable) { + "services/restic/password" = { + sopsFile = ./secrets.sops.yaml; + owner = "kah"; + group = "kah"; + }; + + "services/restic/env" = { + sopsFile = ./secrets.sops.yaml; + owner = "kah"; + group = "kah"; + }; + }; + + environment.persistence = mkIf (cfg.local.enable || cfg.remote.enable) { + "${config.mySystem.system.impermanence.persistPath}" = { + directories = [ "/var/lib/containers" ]; + }; + }; + + # useful commands: + # view snapshots - zfs list -t snapshot + + # below takes a snapshot of the zfs persist volume + # ready for restic syncs + # essentially its a nightly rotation of atomic state at 2am. + + # this is the safest option, as if you run restic + # on live services/databases/etc, you will have + # a bad day when you try and restore + # (backing up a in-use file can and will cause corruption) + + # ref: https://cyounkins.medium.com/correct-backups-require-filesystem-snapshots-23062e2e7a15 + systemd = mkIf (cfg.local.enable || cfg.remote.enable) { + + timers.restic_nightly_snapshot = { + description = "Nightly ZFS snapshot timer"; + wantedBy = [ "timers.target" ]; + partOf = [ "restic_nightly_snapshot.service" ]; + timerConfig.OnCalendar = "2:00"; + timerConfig.Persistent = "true"; + }; + + # recreate snapshot and mount, ready for backup + # I used mkdir -p over a nix tmpfile, as mkdir -p exits cleanly + # if the folder already exists, and tmpfiles complain + # if the folder exists and is already mounted. + services.restic_nightly_snapshot = { + description = "Nightly ZFS snapshot for Restic"; + path = with pkgs; [ zfs busybox ]; + serviceConfig.Type = "simple"; + script = '' + mkdir -p /mnt/nightly_backup/ && \ + umount ${cfg.mountPath} || true && \ + zfs destroy rpool/safe/persist@restic_nightly_snap || true && \ + zfs snapshot rpool/safe/persist@restic_nightly_snap && \ + mount -t zfs rpool/safe/persist@restic_nightly_snap ${cfg.mountPath} + ''; + }; + }; + }; +} diff --git a/nixos/modules/nixos/services/restic/secrets.sops.yaml b/nixos/modules/nixos/services/restic/secrets.sops.yaml new file mode 100644 index 0000000..c542c5f --- /dev/null +++ b/nixos/modules/nixos/services/restic/secrets.sops.yaml @@ -0,0 +1,52 @@ +services: + restic: + password: ENC[AES256_GCM,data:23E=,iv:qK5OxK70KSC6nxsiovOWLDG1+6Mdlf+DNibc/mm3uGA=,tag:GV3V+T/Y8dO/L7pv+OkHzg==,type:str] + repository: ENC[AES256_GCM,data:Sbao4Q==,iv:M9asdh36DY4Ys3RHugTeduECunSkrcL9yjE0j+CaCTk=,tag:Nmy8LNJbwr7cOTQd1p/kqQ==,type:str] + env: ENC[AES256_GCM,data:wNFPsVW6DwZF6Qyyztt0Jw==,iv:PrP6gq+IMTUSKWIKt8zV8o1wbR51vZuZ95Yjwt07ypU=,tag:bBO0tYVR4qrSTZxMoQKgZA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age18kj3xhlvgjeg2awwku3r8d95w360uysu0w5ejghnp4kh8qmtge5qwa2vjp + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaMzZ0Y0FRaUdzY0tMeEx5 + VUJxZkFRUlY3clI1ejVCT0xPNnN3NTh1OHhZCnh2YkxkemZ0ekwxT1NQKzIvTGlH + ejZISVJqVmM2UE1iM0M1eGpDSTN6VGcKLS0tIHJxSEhobUxoYWNXeE1LbWV6N0t1 + dGluUjZCbjFMMktnMFhHSVRscUtUNFEKFAEjmLUA0/9iZLQ4EhpPgyYYYkzQCpUL + bo83xqeLmxY7jU8HGF2YNyBe+I9LHpZvxDTiXzBDiK0Bry9b57hWgg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1z3vjvkead2h934n3w4m5m7tg4tj5qlzagsq6ly84h3tcu7x4ldsqd3s5fg + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLS1diU0xaU0M0amJEajM3 + YkpDeUh2VlNGa3liTFZMOGZYUDRoRUNGeldzCk5kSTcrOXNsclJTUnRoMEZqT0s5 + WTVKcFh4WVlSY0JlYUp0QmF4dWhCWlEKLS0tIGhoeERZWmZCcHR5bEtRZW1JczFy + bEl2Yy9mb1NnbUx6WFFHUGhjUXNqV2cK4M0cAXzjNzG09g2FHCZUw8NQkw6Qw3o9 + G3uFAkWw1Dny8PewS4tzOErAZlUQ0iKJDgUVqOrrBrfvctTFtBseAw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1a8z3p24v32l9yxm5z2l8h7rpc3nhacyfv4jvetk2lenrvsdstd3sdu2kaf + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3WE9jVFRMRC9iNFVaTnNw + OEovY3hwYW5kWnlrSTRIbFU5enFJVXlFVTJjCkdueno5bXZFS0VPU2RWdk5PUTRj + Tk53UGJVZXZ3MExER2txVlRsVDIvY1kKLS0tIFI3VlNyYzB1S1RLS2JEbW54MTdW + aHpBN3ZqWENXc1cvZE5Xa2FiaHNlU0UKQ5/xk21o60JLZ6xNcB0cFHkoTXMN99LD + okhdVhlpml06ODoMIsFq/PR3adjeWJRjB7C4/Bz/wzlEUmze3TQMew== + -----END AGE ENCRYPTED FILE----- + - recipient: age1d9p83j52m2xg0vh9k7q0uwlxwhs3y6tlv68yg9s2h9mdw2fmmsqshddz5m + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3L0h2T3crY2JpaGMreS8z + YkJLOTMvbTRKUFNlWXgzZkpPUVJ5eDFON3pFCnBEeDg1YnpxNXZvdWtPbndRT1VZ + ZUhPRFE3TGFYaGluSDRjbkFHdi81NVEKLS0tIFJYZ3NaSVd6a25qMmxZV1VUNk50 + Wmo2cHY4cUZFMkFlUmNKcmg2RjcrUncKmbMWBL8r6R777c3SvFmmRpRY2oRQsf+A + Yqlv0wmrD6A1B61SDRDwkmFggnk0PquznZD/y0JctqRqmcstAscyNQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-05-18T16:39:41Z" + mac: ENC[AES256_GCM,data:sMTQ25VnUOrMSN9Ro7GoovFWh9Y/4RmHXm/mRHNuOGpl2utXGGQhAGM0F2lpdQwJfd/cRneiDfEJ1GSV+yaSPfTm2KFVVM+Kzl7AyHQO6W1dEvaMhJgGvxixc0SkF9zuU0WXnNOxW67fKUuuZZ69TwMdcVmwF1u7pV9tsONtgf8=,iv:Heynu00CnyU17zNkv1riz2hpulbXOeoi7ukj7c3Qk1g=,tag:Jqkaqq3XSXvENl/8a1z2QA==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/nixos/modules/nixos/system/default.nix b/nixos/modules/nixos/system/default.nix new file mode 100644 index 0000000..43478ea --- /dev/null +++ b/nixos/modules/nixos/system/default.nix @@ -0,0 +1,14 @@ +{ + imports = [ + ./impermanence.nix + ./motd + ./nix.nix + ./nfs + ./openssh.nix + ./pushover + ./security.nix + ./systempackages.nix + ./time.nix + ./zfs.nix + ]; +} diff --git a/nixos/modules/nixos/system/impermanence.nix b/nixos/modules/nixos/system/impermanence.nix new file mode 100644 index 0000000..6285963 --- /dev/null +++ b/nixos/modules/nixos/system/impermanence.nix @@ -0,0 +1,55 @@ +{ lib, config, ... }: +let + cfg = config.mySystem.system.impermanence; +in +with lib; +{ + options.mySystem.system.impermanence = { + enable = mkEnableOption "system impermanence"; + rootBlankSnapshotName = lib.mkOption { + type = lib.types.str; + default = "blank"; + }; + rootPoolName = lib.mkOption { + type = lib.types.str; + default = "rpool/local/root"; + }; + persistPath = lib.mkOption { + type = lib.types.str; + default = "/persist"; + }; + }; + config = lib.mkIf cfg.enable { + # move ssh keys + + # bind a initrd command to rollback to blank root after boot + boot.initrd.postDeviceCommands = lib.mkAfter '' + zfs rollback -r ${cfg.rootPoolName}@${cfg.rootBlankSnapshotName} + ''; + + systemd.tmpfiles.rules = mkIf config.services.openssh.enable [ + "d /etc/ 0755 root root -" #The - disables automatic cleanup, so the file wont be removed after a period + "d /etc/ssh/ 0755 root root -" #The - disables automatic cleanup, so the file wont be removed after a period + ]; + + environment.persistence."${cfg.persistPath}" = { + hideMounts = true; + directories = + [ + "/var/log" # persist logs between reboots for debugging + "/var/lib/cache" # cache files (restic, nginx, contaienrs) + "/var/lib/nixos" # nixos state + ]; + files = [ + "/etc/machine-id" + "/etc/adjtime" # hardware clock adjustment + # ssh keys + "/etc/ssh/ssh_host_ed25519_key" + "/etc/ssh/ssh_host_ed25519_key.pub" + "/etc/ssh/ssh_host_rsa_key" + "/etc/ssh/ssh_host_rsa_key.pub" + ]; + }; + + }; +} diff --git a/nixos/modules/nixos/system/motd/default.nix b/nixos/modules/nixos/system/motd/default.nix new file mode 100644 index 0000000..a6c5025 --- /dev/null +++ b/nixos/modules/nixos/system/motd/default.nix @@ -0,0 +1,98 @@ +{ config, lib, pkgs, ... }: +let + motd = pkgs.writeShellScriptBin "motd" + '' + #! /usr/bin/env bash + source /etc/os-release + service_status=$(systemctl list-units | grep podman-) + RED="\e[31m" + GREEN="\e[32m" + BOLD="\e[1m" + ENDCOLOR="\e[0m" + LOAD1=`cat /proc/loadavg | awk {'print $1'}` + LOAD5=`cat /proc/loadavg | awk {'print $2'}` + LOAD15=`cat /proc/loadavg | awk {'print $3'}` + + MEMORY=`free -m | awk 'NR==2{printf "%s/%sMB (%.2f%%)\n", $3,$2,$3*100 / $2 }'` + + # time of day + HOUR=$(date +"%H") + if [ $HOUR -lt 12 -a $HOUR -ge 0 ] + then TIME="morning" + elif [ $HOUR -lt 17 -a $HOUR -ge 12 ] + then TIME="afternoon" + else + TIME="evening" + fi + + + uptime=`cat /proc/uptime | cut -f1 -d.` + upDays=$((uptime/60/60/24)) + upHours=$((uptime/60/60%24)) + upMins=$((uptime/60%60)) + upSecs=$((uptime%60)) + + figlet "$(hostname)" | lolcat -f + printf "$BOLD %-20s$ENDCOLOR %s\n" "Role:" "${config.mySystem.purpose}" + printf "\n" + ${lib.strings.concatStrings (lib.lists.forEach cfg.networkInterfaces (x: "printf \"$BOLD * %-20s$ENDCOLOR %s\\n\" \"IPv4 ${x}\" \"$(ip -4 addr show ${x} | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}')\"\n"))} + printf "$BOLD * %-20s$ENDCOLOR %s\n" "Release" "$PRETTY_NAME" + printf "$BOLD * %-20s$ENDCOLOR %s\n" "Kernel" "$(uname -rs)" + [ -f /var/run/reboot-required ] && printf "$RED * %-20s$ENDCOLOR %s\n" "A reboot is required" + printf "\n" + printf "$BOLD * %-20s$ENDCOLOR %s\n" "CPU usage" "$LOAD1, $LOAD5, $LOAD15 (1, 5, 15 min)" + printf "$BOLD * %-20s$ENDCOLOR %s\n" "Memory" "$MEMORY" + printf "$BOLD * %-20s$ENDCOLOR %s\n" "System uptime" "$upDays days $upHours hours $upMins minutes $upSecs seconds" + printf "\n" + if ! type "$zpool" &> /dev/null; then + printf "$BOLD Zpool status: $ENDCOLOR\n" + zpool status -x | sed -e 's/^/ /' + fi + if ! type "$zpool" &> /dev/null; then + printf "$BOLD Zpool usage: $ENDCOLOR\n" + zpool list -Ho name,cap,size | awk '{ printf("%-10s%+3s used out of %+5s\n", $1, $2, $3); }' | sed -e 's/^/ /' + fi + printf "\n" + + if [[ -n "$service_status" ]]; then + printf "$BOLDService status$ENDCOLOR\n" + while IFS= read -r line; do + if [[ $line =~ ".scope" ]]; then + continue + fi + if echo "$line" | grep -q 'failed'; then + service_name=$(echo $line | awk '{print $2;}' | sed 's/podman-//g') + printf "$RED• $ENDCOLOR%-50s $RED[failed]$ENDCOLOR\n" "$service_name" + elif echo "$line" | grep -q 'running'; then + service_name=$(echo $line | awk '{print $1;}' | sed 's/podman-//g') + printf "$GREEN• $ENDCOLOR%-50s $GREEN[active]$ENDCOLOR\n" "$service_name" + else + echo "service status unknown" + fi + done <<< "$service_status" + fi + ''; + cfg = config.mySystem.system.motd; +in +{ + options.mySystem.system.motd = { + enable = lib.mkEnableOption "MOTD"; + networkInterfaces = lib.mkOption { + description = "Network interfaces to monitor"; + type = lib.types.listOf lib.types.str; + # default = lib.mapAttrsToList (_: val: val.interface) + default = [ ]; + }; + + }; + config = lib.mkIf cfg.enable { + environment.systemPackages = [ + motd + pkgs.lolcat + pkgs.figlet + ]; + programs.fish.interactiveShellInit = lib.mkIf config.programs.fish.enable '' + motd + ''; + }; +} diff --git a/nixos/modules/nixos/system/nfs/default.nix b/nixos/modules/nixos/system/nfs/default.nix new file mode 100644 index 0000000..2cd0a01 --- /dev/null +++ b/nixos/modules/nixos/system/nfs/default.nix @@ -0,0 +1,24 @@ +{ lib +, config +, ... +}: +let + cfg = config.mySystem.services.nfs; +in +{ + options.mySystem.services.nfs = { + enable = lib.mkEnableOption "nfs"; + exports = lib.mkOption { + type = lib.types.str; + default = ""; + }; + }; + + config = lib.mkIf cfg.enable { + services.nfs.server.enable = true; + services.nfs.server.exports = cfg.exports; + networking.firewall.allowedTCPPorts = [ + 2049 + ]; + }; +} diff --git a/nixos/modules/nixos/system/nix.nix b/nixos/modules/nixos/system/nix.nix new file mode 100644 index 0000000..dd6adbf --- /dev/null +++ b/nixos/modules/nixos/system/nix.nix @@ -0,0 +1,38 @@ +{ lib, config, ... }: +with lib; +let + cfg = config.mySystem.nix; +in +{ + options.mySystem.nix = { + autoOptimiseStore = mkOption + { + type = lib.types.bool; + description = "If we want to auto optimise store"; + default = true; + }; + gc = { + enable = mkEnableOption "automatic garbage collection" // { + default = true; + }; + persistent = mkOption + { + type = lib.types.bool; + description = "Persistent timer for gc, runs at startup if timer missed"; + default = true; + }; + }; + }; + + config.nix = { + optimise.automatic = cfg.autoOptimiseStore; + # automatically garbage collect nix store + gc = mkIf cfg.gc.enable { + # garbage collection + automatic = cfg.gc.enable; + dates = "daily"; + options = "--delete-older-than 7d"; + inherit (cfg.gc) persistent; + }; + }; +} diff --git a/nixos/modules/nixos/system/openssh.nix b/nixos/modules/nixos/system/openssh.nix new file mode 100644 index 0000000..c82cffd --- /dev/null +++ b/nixos/modules/nixos/system/openssh.nix @@ -0,0 +1,38 @@ +{ lib, config, ... }: +with lib; +let + cfg = config.mySystem.services.openssh; +in +{ + options.mySystem.services.openssh = { + enable = mkEnableOption "openssh" // { default = true; }; + passwordAuthentication = mkOption + { + type = lib.types.bool; + description = "If password can be accepted for ssh (commonly disable for security hardening)"; + default = false; + }; + permitRootLogin = mkOption + { + type = types.enum [ "yes" "without-password" "prohibit-password" "forced-commands-only" "no" ]; + description = "If root can login via ssh (commonly disable for security hardening)"; + default = "prohibit-password"; + }; + }; + + config = mkIf cfg.enable { + services.openssh = { + enable = true; + openFirewall = true; + settings = { + # Harden + PasswordAuthentication = cfg.passwordAuthentication; + PermitRootLogin = cfg.permitRootLogin; + # Automatically remove stale sockets + StreamLocalBindUnlink = "yes"; + # Allow forwarding ports to everywhere + GatewayPorts = "clientspecified"; + }; + }; + }; +} diff --git a/nixos/modules/nixos/system/pushover/default.nix b/nixos/modules/nixos/system/pushover/default.nix new file mode 100644 index 0000000..68f02bd --- /dev/null +++ b/nixos/modules/nixos/system/pushover/default.nix @@ -0,0 +1,54 @@ +{ lib +, config +, pkgs +, ... +}: +with lib; +let + cfg = config.mySystem.system.systemd.pushover-alerts; +in +{ + options.mySystem.system.systemd.pushover-alerts.enable = mkEnableOption "Pushover alerts for systemd failures" // { default = true; }; + options.systemd.services = mkOption { + type = with types; attrsOf ( + submodule { + config.onFailure = [ "notify-pushover@%n.service" ]; + } + ); + }; + + config = { + # Warn if backups are disable and machine isnt a dev box + warnings = [ + (mkIf (!cfg.enable && config.mySystem.purpose != "Development") "WARNING: Pushover SystemD notifications are disabled!") + ]; + + systemd.services."notify-pushover@" = mkIf cfg.enable { + enable = true; + onFailure = lib.mkForce [ ]; # cant refer to itself on failure + description = "Notify on failed unit %i"; + serviceConfig = { + Type = "oneshot"; + EnvironmentFile = config.sops.secrets."services/pushover/env".path; + }; + + # Script calls pushover with some deets. + # Here im using the systemd specifier %i passed into the script, + # which I can reference with bash $1. + scriptArgs = "%i %H"; + script = '' + ${pkgs.curl}/bin/curl --fail -s -o /dev/null \ + --form-string "token=$PUSHOVER_API_KEY" \ + --form-string "user=$PUSHOVER_USER_KEY" \ + --form-string "priority=1" \ + --form-string "html=1" \ + --form-string "timestamp=$(date +%s)" \ + --form-string "url=https://$2:9090/system/services#/$1" \ + --form-string "url_title=View in Cockpit" \ + --form-string "title=Unit failure: '$1' on $2" \ + --form-string "message=$1 has failed on $2
Journal tail:

$(journalctl -u $1 -n 10 -o cat)" \ + https://api.pushover.net/1/messages.json 2&>1 + ''; + }; + }; +} diff --git a/nixos/modules/nixos/system/security.nix b/nixos/modules/nixos/system/security.nix new file mode 100644 index 0000000..9a84e33 --- /dev/null +++ b/nixos/modules/nixos/system/security.nix @@ -0,0 +1,45 @@ +{ lib, config, ... }: +with lib; +let + cfg = config.mySystem.security; +in +{ + options.mySystem.security = { + sshAgentAuth.enable = lib.mkEnableOption "openssh"; + wheelNeedsSudoPassword = lib.mkOption { + type = lib.types.bool; + description = "If wheel group users need password for sudo"; + default = true; + }; + increaseWheelLoginLimits = lib.mkOption { + type = lib.types.bool; + description = "If wheel group users receive increased login limits"; + default = true; + }; + }; + + config = + { + security = { + sudo.wheelNeedsPassword = cfg.wheelNeedsSudoPassword; + # Don't bother with the lecture or the need to keep state about who's been lectured + sudo.extraConfig = "Defaults lecture=\"never\""; + pam.sshAgentAuth.enable = cfg.sshAgentAuth.enable; + # Increase open file limit for sudoers + pam.loginLimits = mkIf cfg.increaseWheelLoginLimits [ + { + domain = "@wheel"; + item = "nofile"; + type = "soft"; + value = "524288"; + } + { + domain = "@wheel"; + item = "nofile"; + type = "hard"; + value = "1048576"; + } + ]; + }; + }; +} diff --git a/nixos/modules/nixos/system/systempackages.nix b/nixos/modules/nixos/system/systempackages.nix new file mode 100644 index 0000000..bfa6f37 --- /dev/null +++ b/nixos/modules/nixos/system/systempackages.nix @@ -0,0 +1,20 @@ +{ lib, config, ... }: +with lib; +let + cfg = config.mySystem.system; +in +{ + options.mySystem.system = { + packages = mkOption + { + type = with types; listOf package; + description = "List of system level package installs"; + default = [ ]; + }; + }; + # System packages deployed globally. + # This is NixOS so lets keep this liiight? + # Ideally i'd keep most of it to home-manager user only stuff + # and keep server role as light as possible + config.environment.systemPackages = cfg.packages; +} diff --git a/nixos/modules/nixos/system/time.nix b/nixos/modules/nixos/system/time.nix new file mode 100644 index 0000000..c1af81e --- /dev/null +++ b/nixos/modules/nixos/system/time.nix @@ -0,0 +1,22 @@ +{ lib, config, ... }: +let + cfg = config.mySystem.time; +in +{ + options.mySystem.time = { + timeZone = lib.mkOption { + type = lib.types.str; + description = "Timezone of system"; + default = "America/Chicago"; + }; + hwClockLocalTime = lib.mkOption { + type = lib.types.bool; + description = "If hardware clock is set to local time (useful for windows dual boot)"; + default = false; + }; + }; + config = { + time.timeZone = cfg.timeZone; + time.hardwareClockInLocalTime = cfg.hwClockLocalTime; + }; +} diff --git a/nixos/modules/nixos/system/zfs.nix b/nixos/modules/nixos/system/zfs.nix new file mode 100644 index 0000000..5cce269 --- /dev/null +++ b/nixos/modules/nixos/system/zfs.nix @@ -0,0 +1,40 @@ +{ lib, config, pkgs, ... }: +let + cfg = config.mySystem.system.zfs; +in +with lib; +{ + options.mySystem.system.zfs = { + enable = lib.mkEnableOption "zfs"; + mountPoolsAtBoot = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + }; + }; + config = lib.mkIf cfg.enable { + # setup boot + boot = { + supportedFilesystems = [ + "zfs" + ]; + zfs = { + forceImportRoot = false; # if stuck on boot, modify grub options , force importing isnt secure + extraPools = cfg.mountPoolsAtBoot; + }; + }; + services.zfs = { + autoScrub.enable = true; + # Defaults to weekly and is a bit too regular for my NAS + autoScrub.interval = "weekly"; + trim.enable = true; + }; + # Pushover notifications + environment.systemPackages = with pkgs; [ + busybox + ]; + services.zfs.zed.settings = { + ZED_PUSHOVER_TOKEN = "$(${pkgs.busybox}/bin/cat ${config.sops.secrets.pushover-api-key.path})"; + ZED_PUSHOVER_USER = "$(${pkgs.busybox}/bin/cat ${config.sops.secrets.pushover-user-key.path})"; + }; + }; +} diff --git a/nixos/profiles/README.md b/nixos/profiles/README.md new file mode 100644 index 0000000..b01c15c --- /dev/null +++ b/nixos/profiles/README.md @@ -0,0 +1,18 @@ +## Profiles + +Here are the profiles that each host picks from to build up a system. + +Pair a role with a device type and the correct software and settings will be enabled for that configuration. +Where possible use the `mySystem` option list to configure defaults via these profiles, so they _can_ be overridden later. + +## Global + +Default global settings that will apply to every device. Things like locale, timezone, etc that wont change machine to machine + +## Hardware + +Hardware settings so I can apply per set of machines as standard- i.e. all Raspi4's may benefit from a specific set of additions/hardware overlays. + +## Role + +The roles the machine has. Machines may have multiple roles. diff --git a/nixos/profiles/global.nix b/nixos/profiles/global.nix new file mode 100644 index 0000000..44ff840 --- /dev/null +++ b/nixos/profiles/global.nix @@ -0,0 +1,44 @@ +{ config, lib, pkgs, modulesPath, ... }: + +with lib; +{ + # NOTE + # Some 'global' areas have defaults set in their respective modules. + # These will be applied when the modules are loaded + # Not the global role. + # Not sure at this point a good way to manage globals in one place + # without mono-repo config. + + imports = + [ + (modulesPath + "/installer/scan/not-detected.nix") # Generated by nixos-config-generate + ./global + ]; + config = { + boot.tmp.cleanOnBoot = true; + mySystem = { + # basics for all devices + time.timeZone = "America/Chicago"; + security.increaseWheelLoginLimits = true; + system.packages = [ pkgs.bat ]; + domain = "hsn.dev"; + shell.fish.enable = true; + + # But wont enable plugins globally, leave them for workstations + # TODO: Make per device option + system.resticBackup.remote.location = "s3:https://x.r2.cloudflarestorage.com/nixos-restic"; + }; + + environment.systemPackages = with pkgs; [ + curl + wget + dnsutils + jq + yq + ]; + + networking.useDHCP = lib.mkDefault true; + networking.domain = config.mySystem.domain; + }; + +} diff --git a/nixos/profiles/global/default.nix b/nixos/profiles/global/default.nix new file mode 100644 index 0000000..395d6ee --- /dev/null +++ b/nixos/profiles/global/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./nix.nix + ./sops.nix + ./system.nix + ./users.nix + ]; +} diff --git a/nixos/profiles/global/nix.nix b/nixos/profiles/global/nix.nix new file mode 100644 index 0000000..a8f2521 --- /dev/null +++ b/nixos/profiles/global/nix.nix @@ -0,0 +1,47 @@ +{ lib, nixpkgs, ... }: +{ + ## Below is to align shell/system to flake's nixpkgs + ## ref: https://nixos-and-flakes.thiscute.world/best-practices/nix-path-and-flake-registry + + # Make `nix repl ''` use the same nixpkgs as the one used by this flake. + environment.etc."nix/inputs/nixpkgs".source = "${nixpkgs}"; + nix = { + # make `nix run nixpkgs#nixpkgs` use the same nixpkgs as the one used by this flake. + registry.nixpkgs.flake = nixpkgs; + channel.enable = false; # remove nix-channel related tools & configs, we use flakes instead. + + # but NIX_PATH is still used by many useful tools, so we set it to the same value as the one used by this flake. + # https://github.com/NixOS/nix/issues/9574 + settings.nix-path = lib.mkForce "nixpkgs=/etc/nix/inputs/nixpkgs"; + + settings = { + # Enable flakes + experimental-features = [ + "nix-command" + "flakes" + ]; + + # Substitutions + substituters = [ + "https://hsndev.cachix.org" + "https://nix-community.cachix.org" + "https://numtide.cachix.org" + ]; + + trusted-public-keys = [ + "hsndev.cachix.org-1:vN1/XGBZtMLnTFYDmTLDrullgZHSUYY3Kqt+Yg/C+tE=" + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "numtide.cachix.org-1:2ps1kLBUWjxIneOy1Ik6cQjb41X0iXVXeHigGmycPPE=" + ]; + + # Fallback quickly if substituters are not available. + connect-timeout = 25; + # Avoid copying unnecessary stuff over SSH + builders-use-substitutes = true; + trusted-users = [ "root" "@wheel" ]; + warn-dirty = false; + # The default at 10 is rarely enough. + log-lines = lib.mkDefault 25; + }; + }; +} diff --git a/nixos/profiles/global/secrets.sops.yaml b/nixos/profiles/global/secrets.sops.yaml new file mode 100644 index 0000000..5dca229 --- /dev/null +++ b/nixos/profiles/global/secrets.sops.yaml @@ -0,0 +1,53 @@ +services: + pushover: + env: ENC[AES256_GCM,data:Ug92K492ytxkRMHTw6fmYKgpkz47gBg9aLxqivo+t5GejJbIU1cOewo88/7ASmslceTAiY57NcBTM56eHw7U9+HEq1IjX6RukM/OxZ27R4aMkLCdf1c7DNJ5GOOvX2Zo,iv:uVXUIervTvgLnr60oeWeysB08TR/jy9AjNMWLW75teo=,tag:l2ZGGzMKcVTdnKx5q7XJiA==,type:str] +pushover-user-key: ENC[AES256_GCM,data:EWMIbhjq6+CH958H661xlxcVNLSKWHgxVyjTCU50,iv:Ph6z7Tri64WoPnCbTtrCA2ziprID1VXg8rynx6j6OOg=,tag:MZvq0AE1gp9Ga/73s6MWOw==,type:str] +pushover-api-key: ENC[AES256_GCM,data:1rnQ/dgls1iLtx3efKT37PyrZyArVbRe7BjmKYqZ,iv:pRvkTjRtpf5PhXG555OR+TVmgzwmJnF8+Pb2wfbTKWU=,tag:3DFYTgLxQFQIT4qTP9cQgQ==,type:str] +jahanson-password: ENC[AES256_GCM,data:HPLOlKHCpQIhat5qKKg=,iv:AawKpXj+2ZfEXg/eO2On4qtqHsoxksdRxH6nr+/oTGE=,tag:4wWfOGXybP6B88iGdFMF9A==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age18kj3xhlvgjeg2awwku3r8d95w360uysu0w5ejghnp4kh8qmtge5qwa2vjp + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGSTUzM1RzZEFVZTJBdFAz + UnlYSmllNUdWa3BEa1BWQnBtbXZ1YTBnR25RClVIdy9YTUFyZ2VOdHlyVnNxTS9W + Smw5dDc2S053ZElsdHZpdTRQc2dCWGsKLS0tIGZXUzNMTFlxaVFWNE1GREphanBu + Rkdyd2lXUE5ucUVYT1FOZVlJR0hORGcKC5k9U3D+rfp4yEOx88APxmobjvOnf9jn + POshirAInB/FjEOCb6gwmX8Y/0KJK1A69vwrx3+C4S+8xWcTQwnHqA== + -----END AGE ENCRYPTED FILE----- + - recipient: age1z3vjvkead2h934n3w4m5m7tg4tj5qlzagsq6ly84h3tcu7x4ldsqd3s5fg + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMeCtkNnllZ3RHSjdVWHpq + N0pXM3B3RVJ2QnNwVXpvN2Q3R09mSFU1QWtnCnRvYnR6eVZCaEJkMjMxeEFzRHZ2 + enVodXlHUVFGcEZpTnFHT1VkTGwzbFkKLS0tIFhCTzQ3Ny9TOVBTamZ5SHIzKzFZ + L2NsSjFGWHR4ZDBQR0FFZUdCUXpPRmcKdC6gSCxkHvThXEhp94b3Gx/5Tz4E2B6C + TcwMZVgCC2VkSMASj1Jg08AX+xmJ92gc2xl/v9hQ3MWJbR38KBkaBw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1a8z3p24v32l9yxm5z2l8h7rpc3nhacyfv4jvetk2lenrvsdstd3sdu2kaf + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvMk1XRjdHQUtYbnNrb1oy + SnlwVjBEUTd3dFdlaWh6UGlFTzR1RmpKYjE4CmhSKzFBOFFJSmtnM3Zwc3pKUy9j + SmJiNFhoVmd0ZzE0V2xDK0dzaGhZRGMKLS0tIHlqbWozZHV1R3JSclQ0ZWNRejlD + b1Q4RjJSWm1uSjRVNWd1WjBld1hUbk0KOB+7u0eLMslPCBE745dk7P8kVgELGp6m + glDmVIqsKmvutZ54AhCtI/pOuL5vlmnstRn8MCXcZgXbm3a80BSNFg== + -----END AGE ENCRYPTED FILE----- + - recipient: age1d9p83j52m2xg0vh9k7q0uwlxwhs3y6tlv68yg9s2h9mdw2fmmsqshddz5m + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOcUFiQk5yMGJBUitabTB6 + UHFVRXFVVWFoREV2dXZXcVJ0cG11TlhCUEVVCnAxQkJUUkU1VUhSaWNLQStpcUJu + ZzJBQjlUQXhuZk9PZXRJSktnQWFHZmcKLS0tIFI4TUNwREF5cXNXZEd1NUJ3MGFH + OFVrMXovMDVZTU5obE42NXkwektRa0UKmd1VNqD43WmhwICUohG2DLsZ9wYsGujp + IERwiWAiCppqOEULQeZti8ioPHJDs6tjpuAR+vZ1TD/uhdJP4xsfcA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-05-18T16:39:41Z" + mac: ENC[AES256_GCM,data:EXz+9dIdcI21WlJ9r/lewrfx9MjynA1eS82MMnO0BBiE2KV6XcMvrxStMIerXY/0nr2XGoZii8amo072naaHBTCwCsaDlx0Ry3oMyZYZNFwTM2mqIK93CymIkhe/qhMyNxDTmKc3QFEiRtimLnUx8YW27leS1b4mNFHcauXYNHA=,iv:EEmK39VBNXnJayk6z4MfHHsfj7OuwXUeLZQ06q2y2cE=,tag:9PLLS5BbwB1wmA+UV/oIwA==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/nixos/profiles/global/sops.nix b/nixos/profiles/global/sops.nix new file mode 100644 index 0000000..6e0f23b --- /dev/null +++ b/nixos/profiles/global/sops.nix @@ -0,0 +1,14 @@ +{ ... }: +{ + sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + # Secret for machine-specific pushover + sops.secrets."services/pushover/env" = { + sopsFile = ./secrets.sops.yaml; + }; + sops.secrets.pushover-user-key = { + sopsFile = ./secrets.sops.yaml; + }; + sops.secrets.pushover-api-key = { + sopsFile = ./secrets.sops.yaml; + }; +} diff --git a/nixos/profiles/global/system.nix b/nixos/profiles/global/system.nix new file mode 100644 index 0000000..be1040c --- /dev/null +++ b/nixos/profiles/global/system.nix @@ -0,0 +1,13 @@ +{ lib, pkgs, ... }: +{ + system = { + # Enable printing changes on nix build etc with nvd + activationScripts.report-changes = '' + PATH=$PATH:${lib.makeBinPath [ pkgs.nvd pkgs.nix ]} + nvd diff $(ls -dv /nix/var/nix/profiles/system-*-link | tail -2) + ''; + + # Do not change unless you know what you are doing + stateVersion = "24.11"; + }; +} diff --git a/nixos/profiles/global/users.nix b/nixos/profiles/global/users.nix new file mode 100644 index 0000000..a2e48b5 --- /dev/null +++ b/nixos/profiles/global/users.nix @@ -0,0 +1,39 @@ +{ pkgs, config, ... }: +let + ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups; +in +{ + sops.secrets = { + jahanson-password = { + sopsFile = ./secrets.sops.yaml; + neededForUsers = true; + }; + }; + + users.users.jahanson = { + isNormalUser = true; + shell = pkgs.fish; + hashedPasswordFile = config.sops.secrets.jahanson-password.path; + extraGroups = + [ + "wheel" + ] + ++ ifTheyExist [ + "network" + "samba-users" + "docker" + "podman" + "audio" # pulseaudio + "libvirtd" + ]; + + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBsUe5YF5z8vGcEYtQX7AAiw2rJygGf2l7xxr8nZZa7w" + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH3VVFenoJfnu+IFUlD79uxl7L8SFoRup33J2HGny4WEdRgGR41s0MpFKDBmxXZHy4O9Nh8NMMnpy5VhUefnIKI=" + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPHFQ3hDjjrKsecn3jmSWYlRXy4IJCrepgU1HaIV5VcmB3mUFmIZ/pCZnPmIG/Gbuqf1PP2FQDmHMX5t0hTYG9A=" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIETR70eQJiXaJuB+qpI1z+jFOPbEZoQNRcq4VXkojWfU" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIATyScd8ZRhV7uZmrQNSAbRTs9N/Dbx+Y8tGEDny30sA" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJyA/yMPPo+scxBaDFUk7WeEyMAMhXUro5vi4feOKsJT jahanson@durincore" + ]; + }; +} diff --git a/nixos/profiles/hw-generic-x86.nix b/nixos/profiles/hw-generic-x86.nix new file mode 100644 index 0000000..81e40fc --- /dev/null +++ b/nixos/profiles/hw-generic-x86.nix @@ -0,0 +1,27 @@ +{ lib, pkgs, ... }: +with lib; +{ + mySystem.system.packages = with pkgs; [ + ntfs3g + ]; + + boot = { + + initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; + kernelModules = [ ]; + extraModulePackages = [ ]; + + # for managing/mounting ntfs + supportedFilesystems = [ "ntfs" ]; + + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + grub.memtest86.enable = true; + + }; + }; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + +} diff --git a/nixos/profiles/hw-hetzner-cax.nix b/nixos/profiles/hw-hetzner-cax.nix new file mode 100644 index 0000000..cc11d44 --- /dev/null +++ b/nixos/profiles/hw-hetzner-cax.nix @@ -0,0 +1,26 @@ +{ lib, ... }: { + imports = [ ]; + + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + boot.initrd.availableKernelModules = [ "xhci_pci" "virtio_pci" "virtio_scsi" "usbhid" "sr_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + mySystem = { + services.openssh.enable = true; + security.wheelNeedsSudoPassword = false; + + # Restic backups disabled. + # TODO: configure storagebox for hetzner backups + system.resticBackup = + { + local.enable = false; + remote.enable = false; + }; + }; + + networking.useDHCP = lib.mkDefault true; + nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux"; +} diff --git a/nixos/profiles/hw-thinkpad-t470.nix b/nixos/profiles/hw-thinkpad-t470.nix new file mode 100644 index 0000000..30f0001 --- /dev/null +++ b/nixos/profiles/hw-thinkpad-t470.nix @@ -0,0 +1,30 @@ +{ config, lib, ... }: +{ + boot = { + # Use the systemd-boot EFI boot loader. + loader = { + systemd-boot = { + enable = true; + }; + efi = { + canTouchEfiVariables = true; + }; + }; + # Kernel mods + initrd = { + availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ]; + kernelModules = [ ]; + }; + kernelModules = [ "kvm-intel" ]; + extraModulePackages = [ ]; + }; + + networking = { + useDHCP = lib.mkDefault true; + }; + # networking.interfaces.enp0s31f6.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp4s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/nixos/profiles/role-dev.nix b/nixos/profiles/role-dev.nix new file mode 100644 index 0000000..9bcc585 --- /dev/null +++ b/nixos/profiles/role-dev.nix @@ -0,0 +1,36 @@ +{ config, lib, pkgs, imports, boot, self, inputs, ... }: +# Role for dev stations +# Could be a workstatio or a headless server. + +with config; +{ + # git & vim are in global + environment.systemPackages = with pkgs; [ + jq + yq + btop + dnsutils + nix + + # nix dev + dnscontrol # for updating internal DNS servers with homelab services + + # TODO Move + nil + nixpkgs-fmt + statix + # nvd + gh + + # bind # for dns utils like named-checkconf + inputs.nix-inspect.packages.${pkgs.system}.default + ]; + + programs.direnv = { + # TODO move to home-manager + enable = true; + nix-direnv.enable = true; + }; + + +} diff --git a/nixos/profiles/role-server.nix b/nixos/profiles/role-server.nix new file mode 100644 index 0000000..c3f789e --- /dev/null +++ b/nixos/profiles/role-server.nix @@ -0,0 +1,47 @@ +{ config, lib, pkgs, ... }: +# Role for headless servers +# covers raspi's, sbc, NUC etc, anything +# that is headless and minimal for running services +with lib; +{ + config = { + # Enable monitoring for remote scraiping + mySystem.services.promMonitoring.enable = true; + mySystem.services.rebootRequiredCheck.enable = true; + mySystem.security.wheelNeedsSudoPassword = false; + mySystem.services.cockpit.enable = true; + mySystem.system.motd.enable = true; + mySystem.services.gatus.monitors = [{ + name = config.networking.hostName; + group = "servers"; + url = "icmp://${config.networking.hostName}"; + interval = "1m"; + conditions = [ "[CONNECTED] == true" ]; + }]; + + nix.settings = { + # TODO factor out into mySystem + # Avoid disk full issues + max-free = lib.mkDefault (1000 * 1000 * 1000); + min-free = lib.mkDefault (128 * 1000 * 1000); + }; + + services.logrotate.enable = mkDefault true; + environment = { + noXlibs = mkDefault true; + systemPackages = [ pkgs.lazygit ]; + }; + documentation = { + enable = mkDefault false; + doc.enable = mkDefault false; + info.enable = mkDefault false; + man.enable = mkDefault false; + nixos.enable = mkDefault false; + }; + + programs.command-not-found.enable = mkDefault false; + sound.enable = false; + hardware.pulseaudio.enable = false; + services.udisks2.enable = mkDefault false; + }; +} diff --git a/nixos/profiles/role-workstation.nix b/nixos/profiles/role-workstation.nix new file mode 100644 index 0000000..c103b1e --- /dev/null +++ b/nixos/profiles/role-workstation.nix @@ -0,0 +1,75 @@ +{ config, lib, pkgs, ... }: +# Role for workstations +# Covers desktops/laptops, expected to have a GUI and do workloads +# Will have home-manager installs + +with config; +{ + mySystem = { + + de.gnome.enable = true; + + # Lets see if fish everywhere is OK on the pi's + # TODO decide if i drop to bash on pis? + shell.fish.enable = true; + + # TODO make nfs server configurable + # nfs.nas = { + # enable = true; + # lazy = true; + # }; + + system.resticBackup.local.enable = false; + system.resticBackup.remote.enable = false; + + }; + + boot = { + binfmt.emulatedSystems = [ "aarch64-linux" ]; # Enabled for raspi4 compilation + plymouth.enable = true; # hide console with splash screen + }; + + nix.settings = { + # TODO factor out into mySystem + # Avoid disk full issues + max-free = lib.mkDefault (1000 * 1000 * 1000); + min-free = lib.mkDefault (128 * 1000 * 1000); + }; + + # set xserver videodrivers if used + services.xserver.enable = true; + + services = { + fwupd.enable = config.boot.loader.systemd-boot.enable; # fwupd does not work in BIOS mode + thermald.enable = true; + smartd.enable = true; + + # required for yubikey + udev.packages = [ pkgs.yubikey-personalization ]; + pcscd.enable = true; + }; + + hardware = { + enableAllFirmware = true; + sensor.hddtemp = { + enable = true; + drives = [ "/dev/disk/by-id/*" ]; + }; + }; + + environment.systemPackages = with pkgs; [ + # Sensors etc + lm_sensors + cpufrequtils + cpupower-gui + vscode + vivaldi + termius + ]; + + i18n = { + defaultLocale = lib.mkDefault "en_US.UTF-8"; + }; + + programs.mtr.enable = true; +} diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..23f1358 --- /dev/null +++ b/renovate.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ], + "nix": { + "enabled": true + }, + "lockFileMaintenance": { + "enabled": true, + "extends": ["schedule:daily"] + } +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..d1fc12c --- /dev/null +++ b/shell.nix @@ -0,0 +1,30 @@ +# Shell for bootstrapping flake-enabled nix and home-manager +{ pkgs ? let + # If pkgs is not defined, instantiate nixpkgs from locked commit + lock = (builtins.fromJSON (builtins.readFile ./flake.lock)).nodes.nixpkgs.locked; + nixpkgs = fetchTarball { + url = "https://github.com/nixos/nixpkgs/archive/${lock.rev}.tar.gz"; + sha256 = lock.narHash; + }; + system = builtins.currentSystem; + overlays = [ ]; # Explicit blank overlay to avoid interference + in + import nixpkgs { inherit system overlays; } +, ... +}: +pkgs.mkShell { + # Enable experimental features without having to specify the argument + NIX_CONFIG = "experimental-features = nix-command flakes"; + + nativeBuildInputs = with pkgs; [ + nix + home-manager + git + nil + nixpkgs-fmt + go-task + sops + pre-commit + gitleaks + ]; +}