commit b910dc465e305e5b4600d685b18c2600c3669aa6 Author: Sebastian Wendel Date: Thu Jul 4 13:47:18 2024 +0200 first commit diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..61cf455 --- /dev/null +++ b/.envrc @@ -0,0 +1,5 @@ +use flake + +dotenv_if_exists .envrc.local + +eval "$shellHook" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..447d929 --- /dev/null +++ b/.gitignore @@ -0,0 +1,53 @@ +.envrc.local +.*.swo +.*.swp +.direnv +.DS_Store +.pre-commit-config.yaml +result* +*.qcow2 +*.log +temp +*.pyc +TODOS.md +.devenv + +# terraform +.terraform +*.tf.json +*.tfstate + +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars +*.tfvars.json + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100755 index 0000000..33d3bea --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,11 @@ +{ + "recommendations": [ + "arrterian.nix-env-selector", + "bbenoist.nix", + "brettm12345.nixfmt-vscode", + "hashicorp.hcl", + "jnoortheen.nix-ide", + "mikestead.dotenv", + ], + "unwantedRecommendations": [] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100755 index 0000000..d3eea4f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,33 @@ +{ + "files.associations": { + "flake.lock": "json", + "*.hcl": "hcl", + }, + "[terraform]": { + "editor.defaultFormatter": "hashicorp.terraform", + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "file", + }, + "[terraform-vars]": { + "editor.defaultFormatter": "hashicorp.terraform", + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "file", + }, + "[hcl]": { + "editor.defaultFormatter": "hashicorp.terraform", + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "file", + }, + "[nix]": { + "editor.defaultFormatter": "jnoortheen.nix-ide", + "editor.formatOnSave": true, + "editor.insertSpaces": true, + "editor.tabSize": 2, + "editor.codeLens": true, + "emmet.triggerExpansionOnTab": true, + "editor.quickSuggestions": { + "comments": "on", + "strings": "on" + } + } +} diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..0e9c25d --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,24 @@ +# The MIT License (MIT) + +Copyright © 2023 Sebastian Wendel + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the “Software”), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c46a9d7 --- /dev/null +++ b/README.md @@ -0,0 +1,202 @@ + +# srx digital - nix platform repository + +Nix Flake Logo + +This is the platform repository of [srx.digital](https://srx.digital), a Nix development and operations company based in Hamburg, Germany. + +[NixOS](https://nixos.org/) is a Linux distribution built on the [Nix package manager](https://nixos.wiki/wiki/Nix_package_manager), utilizing declarative configuration to ensure reproducible and reliable system setups. + +This repository contains opinionated configurations for deploying NixOS systems and cloud infrastructures with [Terraform](https://www.terraform.io/), written in pure [Nix](https://nixos.org/learn) expressions. It offers developers and DevOps engineers an insight into the potential of Nix. + +## 📜 Principles of Operation + +This repository uses 100% Infrastructure as Code and does not need to be configured manually. All services are monitored and backed up. Common services are modularized for reuse, but the separation of custom configurations is in progress. Reusable components will be moved to a separate Flake module in the near future. + +📌 **Note** + +> Some customer-specific configurations are stored in a private Git repository and imported as the `srx-nixos-shadow` flake to protect customer infrastructure. Due to its private nature, some tasks may fail and should be commented out. Generally, all expressions should evaluate without issues. + +## 🛠️ Components + +- [flake-parts](https://github.com/hercules-ci/flake-parts): Simplify Nix Flakes with the module system. +- [git-hooks](https://github.com/cachix/git-hooks.nix): Seamless integration of git hooks with Nix. +- [agenix](https://github.com/ryantm/agenix): Encrypted secrets for NixOS and Home Manager. +- [deploy-rs](https://github.com/serokell/deploy-rs): A multi-profile Nix-flake deployment tool. +- [nixos-anywhere](https://github.com/nix-community/nixos-anywhere): Install NixOS anywhere via SSH. +- [disko](https://github.com/nix-community/disko): Declarative disk partitioning. +- [srvos](https://github.com/nix-community/srvos): NixOS profiles for servers. +- [Tang & Clevis](https://fosdem.org/2024/schedule/event/fosdem-2024-3044-clevis-tang-unattended-boot-of-an-encrypted-nixos-system/): An automated encryption framework for full disk encryption. +- [Lanzaboote](https://github.com/nix-community/lanzaboote): Secure Boot for NixOS. +- [home-manager](https://github.com/nix-community/home-manager): Manage user environments using Nix. +- [terranix](https://terranix.org/): Create [OpenTofu](https://opentofu.org/) JSON files the NixOS way. +- [kubenix](https://kubenix.org/): Kubernetes management with Nix. +- [stylix](https://stylix.danth.me/): Apply consistent color schemes, fonts, and wallpapers. +- [hydra](https://github.com/NixOS/hydra): The Nix-based continuous build system. + +## 📁 Repository layout + +```txt +├── hosts - NixOS server configurations +├── lib - Reusable Nix libraries +├── modules - Reusable NixOS modules +├── nix - Flake-parts modules +├── overlays - Nix package overlays +├── secrets.nix - Age-encrypted secrets +├── terranix - Terraform Nix expressions +├── default.nix - Legacy support with flake-compat +├── flake.lock - Lock file for version pinning +└── flake.nix - Flakes configuration +``` + +## 🚀 Getting started + +### 📋 Prerequisites + +Before proceeding, ensure the following tools are installed: + +- [Git](https://git-scm.com/): For cloning and managing the repository. +- [direnv](https://direnv.net/): To automatically enter Nix environments. +- [Nix package manager](https://nixos.org/download#download-nix): Essential for Nix or NixOS operations. + +### 🛠️ Commands + +Run `menu` or `nix flake show` to view all commands and aliases provided by the devshell, as defined in [nix/devshell.nix](nix/devshell.nix). + +### 🖥️ NixOS + +#### 🔐 Secrets + +Secrets are encrypted using [agenix](https://github.com/ryantm/agenix). To add secret files and new hosts with their SSH public key, edit [nix/hosts.nix](nix/hosts.nix). + +- `agenix --edit` edits FILE using $EDITOR +- `agenix --decrypt` decrypts FILE to STDOUT +- `agenix --rekey` re-encrypts all secrets with specified recipients + +#### 🏭 Development + +To begin, run `nix develop` in the source tree to enter the development shell, or use [direnv](https://direnv.net/) for automatic entry. Check [flake.nix](flake.nix) or run `nix flake show` to view the flake definition. Server definitions are described in the [hosts](hosts) folder. Module definitions are located in the [nix/modules.nix](nix/modules.nix) and [modules](modules) folders. + +#### 🧪 local Testing + +To build and run a local [QEMU](https://www.qemu.org/) VM, use the following steps: + +1. Build the system with: + + ```sh + nixos-rebuild build-vm --flake .#dev-vm + ``` + +2. Configure the network settings: + + ```sh + export QEMU_NET_OPTS="hostfwd=tcp::2221-:22" + ``` + +3. Start the VM: + + ```sh + result/bin/run-dev-vm-vm + ``` + +4. Access the VM via SSH: + + ```sh + ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@localhost -p 2221 + ``` + +#### 🎯 Deployment + +[deploy-rs](https://github.com/serokell/deploy-rs) is a straightforward deployment tool for NixOS systems. It is configured in [nix/deploy.nix](nix/deploy.nix), where you can adjust `autoRollback` or `magicRollback` options. + +To deploy, run: + +```sh +deploy .#dev-vm +``` + +For more information on usage, refer to the [`deploy --help`](https://github.com/serokell/deploy-rs) documentation. + +### 🪐 Terraform + +This project uses [OpenTofu](https://opentofu.org/) and [terranix](https://terranix.org/) for creating Terraform JSON files the Nix way. + +#### 🔗 Environment Variables + +Create a local and private [.envrc.local](.envrc.local) file to authenticate with remote services during local development and operations. + +- **AWS_ACCESS_KEY_ID** and **AWS_SECRET_ACCESS_KEY**: Required for accessing S3 services, crucial for state management. Refer to [Terraform S3 State](https://developer.hashicorp.com/terraform/language/settings/backends/s3) for more details. +- **GITHUB_TOKEN**: Authenticates against GitHub for repository access and API interactions. [Details](https://docs.github.com/en/actions/security-guides/automatic-token-authentication). +- **HYDRA_HOST**, **HYDRA_USERNAME**, **HYDRA_PASSWORD**: Configures and authenticates with a Hydra server for CI/CD operations. [Hydra provider documentation](https://github.com/DeterminateSystems/terraform-provider-hydra). +- **GRAFANA_AUTH**: Enables Grafana server authentication for dashboard access and API use. [Grafana provider usage](https://registry.terraform.io/providers/grafana/grafana/). +- **MINIO_ENABLE_HTTPS**, **MINIO_ENDPOINT**, **MINIO_ROOT_USER**, **MINIO_ROOT_PASSWORD**: Sets up MinIO services, ensuring secure and authenticated connections. [MinIO provider usage](https://registry.terraform.io/providers/aminueza/minio). + +#### 📦 State Management + +The [Terraform state](https://developer.hashicorp.com/terraform/language/state) is stored outside the repository in an S3 Bucket, configured in [terraform.nix](terranix/minio/terraform.nix) and hosted by [minio.nix](hosts/srxgp00/services/minio/default.nix). + +#### 🔧 Configuration + +Terraform version and providers are pinned and configured in [nix/terranix.nix](nix/terranix.nix). Terraform resources are declared in the [terranix](terranix) folder. + +#### 🕹️ Terraform Commands + +- `nix run .#tf-init` - Initializes the working directory. +- `nix run .#tf-state` - Performs basic state modifications. +- `nix run .#tf-import` - Import existing infrastructure resources. +- `nix run .#tf-validate` - Validates using [tfsec](https://github.com/aquasecurity/tfsec), configured in [tfsec.nix](terranix/tfsec.nix). +- `nix run .#tf-plan` - Creates the execution plan. +- `nix run .#tf-apply` - Executes the actions proposed in the plan. +- `nix run .#tf-destroy` - Destroys all remote objects. + +#### 🧰 Helpers + +- `nix run .#tf2nix resource.tf` - Converts HCL files to Nix. +- `nix run .#json2nix resource.yaml` - Converts JSON or YAML files to Nix. + +#### 🧩 Common Functions + +Generalized functions for reuse are in [lib/terraform.nix](lib/terraform.nix) and [nix/terranix.nix](nix/terranix.nix). + +### 🔄 Updates + +This project uses [nix flakes](https://nixos.wiki/wiki/Flakes) to manage [nixpkgs](https://github.com/NixOS/nixpkgs) versions. To upgrade, use `nix flake update` for all inputs or `nix flake update nixpkgs` to update a single flake input. + +To check if a remote system is behind your flake state, run `nix run .#nix-upgrades`: + +```sh +🔍 Scanning for upgradable hosts... + +dev-vm: ⚠️ Modified: 24.05.20240618.938aa15 +``` + +### 🤖 CI/CD + +I utilize the [Nix Hydra project](https://github.com/NixOS/hydra) to test and build all packages and hosts, strictly following the `Zero Hydra Failures` paradigm to ensure every build is successful and stable. + +You can view all our jobs and their statuses at [build.nix.srx.digital](https://build.nix.srx.digital/). + +## 🚧 Reporting issues + +If you experience any issues with the infrastructure, please [post a new issue to this repository](https://code.srx.digital/srx/srx-platform-nix/issues). + +## 💬 Contact + +Need help with Nix? Write me an e-mail to book an appointment for Nix/NixOS/DevOps related topics. You can find me at: + +- [SRX Digital - Development & Operations](https://srx.digital/) +- [Nix Hamburg Matrix channel](https://matrix.to/#/#nix-hh:curious.bio) for live discussions. + +## 📚 Links + +- [Nix packages search](https://search.nixos.org/packages) +- [NixOS options search](https://search.nixos.org/options) +- [Nix Manual](https://nix.dev/manual/nix/stable/) +- [NixOS Manual](https://nixos.org/manual/nixos/stable/) +- [NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/) +- [NixOS Wiki](https://nixos.wiki/wiki/Main_Page) +- [Awesome Nix](https://github.com/nix-communi/awesome-nix) + +## 📜 License + +All files in this repository are licensed under the terms of the MIT License (MIT). Please refer to the full license text in [LICENSE](LICENSE.md). diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..01fb7ce --- /dev/null +++ b/default.nix @@ -0,0 +1,14 @@ +{ system ? builtins.currentSystem, src ? ./. }: +let + inherit (lock.nodes.flake-compat.locked) owner repo rev narHash; + + lock = builtins.fromJSON (builtins.readFile ./flake.lock); + + flake-compat = fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; + sha256 = narHash; + }; + + flake = import flake-compat { inherit src system; }; +in +flake.defaultNix diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..e62a21c --- /dev/null +++ b/flake.lock @@ -0,0 +1,2550 @@ +{ + "nodes": { + "agenix": { + "inputs": { + "darwin": "darwin", + "home-manager": [ + "home-manager" + ], + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems" + }, + "locked": { + "lastModified": 1718371084, + "narHash": "sha256-abpBi61mg0g+lFFU0zY4C6oP6fBwPzbHPKBGw676xsA=", + "owner": "ryantm", + "repo": "agenix", + "rev": "3a56735779db467538fb2e577eda28a9daacaca6", + "type": "github" + }, + "original": { + "owner": "ryantm", + "repo": "agenix", + "type": "github" + } + }, + "base16": { + "inputs": { + "fromYaml": "fromYaml" + }, + "locked": { + "lastModified": 1708890466, + "narHash": "sha256-LlrC09LoPi8OPYOGPXegD72v+//VapgAqhbOFS3i8sc=", + "owner": "SenchoPens", + "repo": "base16.nix", + "rev": "665b3c6748534eb766c777298721cece9453fdae", + "type": "github" + }, + "original": { + "owner": "SenchoPens", + "repo": "base16.nix", + "type": "github" + } + }, + "base16-fish": { + "flake": false, + "locked": { + "lastModified": 1622559957, + "narHash": "sha256-PebymhVYbL8trDVVXxCvZgc0S5VxI7I1Hv4RMSquTpA=", + "owner": "tomyun", + "repo": "base16-fish", + "rev": "2f6dd973a9075dabccd26f1cded09508180bf5fe", + "type": "github" + }, + "original": { + "owner": "tomyun", + "repo": "base16-fish", + "type": "github" + } + }, + "base16-foot": { + "flake": false, + "locked": { + "lastModified": 1696725948, + "narHash": "sha256-65bz2bUL/yzZ1c8/GQASnoiGwaF8DczlxJtzik1c0AU=", + "owner": "tinted-theming", + "repo": "base16-foot", + "rev": "eedbcfa30de0a4baa03e99f5e3ceb5535c2755ce", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-foot", + "type": "github" + } + }, + "base16-helix": { + "flake": false, + "locked": { + "lastModified": 1696727917, + "narHash": "sha256-FVrbPk+NtMra0jtlC5oxyNchbm8FosmvXIatkRbYy1g=", + "owner": "tinted-theming", + "repo": "base16-helix", + "rev": "dbe1480d99fe80f08df7970e471fac24c05f2ddb", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-helix", + "type": "github" + } + }, + "base16-kitty": { + "flake": false, + "locked": { + "lastModified": 1665001328, + "narHash": "sha256-aRaizTYPpuWEcvoYE9U+YRX+Wsc8+iG0guQJbvxEdJY=", + "owner": "kdrag0n", + "repo": "base16-kitty", + "rev": "06bb401fa9a0ffb84365905ffbb959ae5bf40805", + "type": "github" + }, + "original": { + "owner": "kdrag0n", + "repo": "base16-kitty", + "type": "github" + } + }, + "base16-schemes": { + "flake": false, + "locked": { + "lastModified": 1702718998, + "narHash": "sha256-VTczZi1C4WSzejpTFbneMonAdarRLtDnFehVxWs6ad0=", + "owner": "tinted-theming", + "repo": "base16-schemes", + "rev": "2b6f2d0677216ddda50c9cabd6ee70fae4665f81", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-schemes", + "type": "github" + } + }, + "base16-tmux": { + "flake": false, + "locked": { + "lastModified": 1696725902, + "narHash": "sha256-wDPg5elZPcQpu7Df0lI5O8Jv4A3T6jUQIVg63KDU+3Q=", + "owner": "tinted-theming", + "repo": "base16-tmux", + "rev": "c02050bebb60dbb20cb433cd4d8ce668ecc11ba7", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-tmux", + "type": "github" + } + }, + "base16-vim": { + "flake": false, + "locked": { + "lastModified": 1716150083, + "narHash": "sha256-ZMhnNmw34ogE5rJZrjRv5MtG3WaqKd60ds2VXvT6hEc=", + "owner": "tinted-theming", + "repo": "base16-vim", + "rev": "6e955d704d046b0dc3e5c2d68a2a6eeffd2b5d3d", + "type": "github" + }, + "original": { + "owner": "tinted-theming", + "repo": "base16-vim", + "type": "github" + } + }, + "bats-assert": { + "flake": false, + "locked": { + "lastModified": 1636059754, + "narHash": "sha256-ewME0l27ZqfmAwJO4h5biTALc9bDLv7Bl3ftBzBuZwk=", + "owner": "bats-core", + "repo": "bats-assert", + "rev": "34551b1d7f8c7b677c1a66fc0ac140d6223409e5", + "type": "github" + }, + "original": { + "owner": "bats-core", + "repo": "bats-assert", + "type": "github" + } + }, + "bats-support": { + "flake": false, + "locked": { + "lastModified": 1548869839, + "narHash": "sha256-Gr4ntadr42F2Ks8Pte2D4wNDbijhujuoJi4OPZnTAZU=", + "owner": "bats-core", + "repo": "bats-support", + "rev": "d140a65044b2d6810381935ae7f0c94c7023c8c3", + "type": "github" + }, + "original": { + "owner": "bats-core", + "repo": "bats-support", + "type": "github" + } + }, + "blobs": { + "flake": false, + "locked": { + "lastModified": 1604995301, + "narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=", + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "type": "gitlab" + } + }, + "cachix": { + "inputs": { + "devenv": "devenv_2", + "flake-compat": [ + "devenv", + "flake-compat" + ], + "nixpkgs": [ + "devenv", + "nixpkgs" + ], + "pre-commit-hooks": [ + "devenv", + "pre-commit-hooks" + ] + }, + "locked": { + "lastModified": 1712055811, + "narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=", + "owner": "cachix", + "repo": "cachix", + "rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "cachix", + "type": "github" + } + }, + "cadquery-src": { + "flake": false, + "locked": { + "lastModified": 1702838737, + "narHash": "sha256-Ng3Ehf9E5q3VQ6qf7P9lVnpsS1mWmTTV4nEnDKU6OVA=", + "owner": "CadQuery", + "repo": "cadquery", + "rev": "245b6f39e597d324cbe8652b385a2130cdce545b", + "type": "github" + }, + "original": { + "owner": "CadQuery", + "repo": "cadquery", + "rev": "245b6f39e597d324cbe8652b385a2130cdce545b", + "type": "github" + } + }, + "commonmark-simple": { + "flake": false, + "locked": { + "lastModified": 1707333942, + "narHash": "sha256-o1am93UXviPVdwwPPL5DcD8M4gwFple8SKw/lVmixa8=", + "owner": "srid", + "repo": "commonmark-simple", + "rev": "0308362957d77eea462c2c99d110820fbf30b4b8", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "commonmark-simple", + "type": "github" + } + }, + "commonmark-simple_2": { + "flake": false, + "locked": { + "lastModified": 1705078713, + "narHash": "sha256-YgDHJG8M47ZXGLWu8o7MhXbIrgQ0Ai32Gr8nKvZGGw8=", + "owner": "srid", + "repo": "commonmark-simple", + "rev": "fc106c94f781f6a35ef66900880edc08cbe3b034", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "commonmark-simple", + "type": "github" + } + }, + "commonmark-wikilink": { + "flake": false, + "locked": { + "lastModified": 1711394028, + "narHash": "sha256-eu5gMmgRz6Y51TBCaB26uJKNN3z1LRfUcTV4+PMy5Gw=", + "owner": "srid", + "repo": "commonmark-wikilink", + "rev": "57dcf665082ffc1b6f35a427e203ed115821b15c", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "commonmark-wikilink", + "type": "github" + } + }, + "commonmark-wikilink_2": { + "flake": false, + "locked": { + "lastModified": 1705502834, + "narHash": "sha256-79fzI4fPhCkfusDXctQwwmjIcWMrLfTvUtKBY32asuM=", + "owner": "srid", + "repo": "commonmark-wikilink", + "rev": "f6d7bdf7f1fce09ba2a4259b0306b0eef24c0cf7", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "commonmark-wikilink", + "type": "github" + } + }, + "cq-editor-src": { + "flake": false, + "locked": { + "lastModified": 1701895648, + "narHash": "sha256-mHXEaA6vphps6F0WemdB6fGRY4lzpcxLU7WuYEp8c20=", + "owner": "CadQuery", + "repo": "CQ-editor", + "rev": "4ef178af06d24a53fee87d576f8cada14c0111a3", + "type": "github" + }, + "original": { + "owner": "CadQuery", + "repo": "CQ-editor", + "rev": "4ef178af06d24a53fee87d576f8cada14c0111a3", + "type": "github" + } + }, + "cq-flake": { + "inputs": { + "cadquery-src": "cadquery-src", + "cq-editor-src": "cq-editor-src", + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": "nixpkgs", + "ocp-src": "ocp-src", + "ocp-stubs-src": "ocp-stubs-src", + "pybind11-stubgen-src": "pybind11-stubgen-src", + "pywrap-src": "pywrap-src" + }, + "locked": { + "lastModified": 1703111559, + "narHash": "sha256-nlpTdCXw+/EVWAOtnMuFz0pudsiY4mpofYPESAi8+oY=", + "owner": "vinszent", + "repo": "cq-flake", + "rev": "cdccdf10d5cb3cf286e65db294fe72f548d2832b", + "type": "github" + }, + "original": { + "owner": "vinszent", + "repo": "cq-flake", + "type": "github" + } + }, + "crane": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1718474113, + "narHash": "sha256-UKrfy/46YF2TRnxTtKCYzqf2f5ZPRRWwKCCJb7O5X8U=", + "owner": "ipetkov", + "repo": "crane", + "rev": "0095fd8ea00ae0a9e6014f39c375e40c2fbd3386", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "darwin": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1700795494, + "narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d", + "type": "github" + }, + "original": { + "owner": "lnl7", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "deploy-rs": { + "inputs": { + "flake-compat": [ + "flake-compat" + ], + "nixpkgs": [ + "nixpkgs" + ], + "utils": [ + "flake-utils" + ] + }, + "locked": { + "lastModified": 1718194053, + "narHash": "sha256-FaGrf7qwZ99ehPJCAwgvNY5sLCqQ3GDiE/6uLhxxwSY=", + "owner": "serokell", + "repo": "deploy-rs", + "rev": "3867348fa92bc892eba5d9ddb2d7a97b9e127a8a", + "type": "github" + }, + "original": { + "owner": "serokell", + "repo": "deploy-rs", + "type": "github" + } + }, + "devenv": { + "inputs": { + "cachix": "cachix", + "flake-compat": [ + "flake-compat" + ], + "nix": "nix_2", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit-hooks": [ + "git-hooks" + ] + }, + "locked": { + "lastModified": 1719953558, + "narHash": "sha256-7S0E9elPniVfV0pq2FCNgTXirl9MqYMDVIafmSzmGcU=", + "owner": "cachix", + "repo": "devenv", + "rev": "a7fa60374d7830ee978a06652a9f6e26b4aba30c", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "devenv_2": { + "inputs": { + "flake-compat": [ + "devenv", + "cachix", + "flake-compat" + ], + "nix": "nix", + "nixpkgs": "nixpkgs_2", + "poetry2nix": "poetry2nix", + "pre-commit-hooks": [ + "devenv", + "cachix", + "pre-commit-hooks" + ] + }, + "locked": { + "lastModified": 1708704632, + "narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=", + "owner": "cachix", + "repo": "devenv", + "rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "python-rewrite", + "repo": "devenv", + "type": "github" + } + }, + "devshell": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1717408969, + "narHash": "sha256-Q0OEFqe35fZbbRPPRdrjTUUChKVhhWXz3T9ZSKmaoVY=", + "owner": "numtide", + "repo": "devshell", + "rev": "1ebbe68d57457c8cae98145410b164b5477761f4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "disko": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719864345, + "narHash": "sha256-e4Pw+30vFAxuvkSTaTypd9zYemB/QlWcH186dsGT+Ms=", + "owner": "nix-community", + "repo": "disko", + "rev": "544a80a69d6e2da04e4df7ec8210a858de8c7533", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "disko", + "type": "github" + } + }, + "dns": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719459426, + "narHash": "sha256-4Kn9Pb3lvsik/VYsEAYgXpkcmLhrr0tTE6oIT2PMSPA=", + "owner": "nix-community", + "repo": "dns.nix", + "rev": "e6693931023206f1f3c2bfc57d2c98b5f27f52e6", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "dns.nix", + "type": "github" + } + }, + "dns_2": { + "inputs": { + "flake-utils": [ + "srx-nixos-shadow", + "flake-utils" + ], + "nixpkgs": [ + "srx-nixos-shadow", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719459426, + "narHash": "sha256-4Kn9Pb3lvsik/VYsEAYgXpkcmLhrr0tTE6oIT2PMSPA=", + "owner": "nix-community", + "repo": "dns.nix", + "rev": "e6693931023206f1f3c2bfc57d2c98b5f27f52e6", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "dns.nix", + "type": "github" + } + }, + "ema": { + "inputs": { + "emanote": "emanote_2", + "flake-parts": [ + "srx-nixos-shadow", + "emanote", + "flake-parts" + ], + "flake-root": [ + "srx-nixos-shadow", + "emanote", + "flake-root" + ], + "haskell-flake": [ + "srx-nixos-shadow", + "emanote", + "haskell-flake" + ], + "nixpkgs": [ + "srx-nixos-shadow", + "emanote", + "nixpkgs" + ], + "treefmt-nix": [ + "srx-nixos-shadow", + "emanote", + "treefmt-nix" + ] + }, + "locked": { + "lastModified": 1710101403, + "narHash": "sha256-7n+2ekoXM5ltDoirVyCX3Ob94dm7L8SllI1JMmFmeGA=", + "owner": "srid", + "repo": "ema", + "rev": "51566e4155602b0a243a369b37dc503ebdebabce", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "ema", + "type": "github" + } + }, + "ema_2": { + "inputs": { + "flake-parts": [ + "srx-nixos-shadow", + "emanote", + "ema", + "emanote", + "flake-parts" + ], + "flake-root": [ + "srx-nixos-shadow", + "emanote", + "ema", + "emanote", + "flake-root" + ], + "haskell-flake": [ + "srx-nixos-shadow", + "emanote", + "ema", + "emanote", + "haskell-flake" + ], + "nixpkgs": [ + "srx-nixos-shadow", + "emanote", + "ema", + "emanote", + "nixpkgs" + ], + "treefmt-nix": [ + "srx-nixos-shadow", + "emanote", + "ema", + "emanote", + "treefmt-nix" + ] + }, + "locked": { + "lastModified": 1707484760, + "narHash": "sha256-2wHRjoFJUpVnH7H/80bnaw8h3WELZqP9dM6DfjXWtAo=", + "owner": "srid", + "repo": "ema", + "rev": "e3539ddd27b72a6bb90c8614ae63c70ff3351936", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "ema", + "type": "github" + } + }, + "emanote": { + "inputs": { + "commonmark-simple": "commonmark-simple", + "commonmark-wikilink": "commonmark-wikilink", + "ema": "ema", + "emanote-template": "emanote-template_2", + "flake-parts": [ + "srx-nixos-shadow", + "flake-parts" + ], + "flake-root": "flake-root_3", + "haskell-flake": "haskell-flake_2", + "heist-extra": "heist-extra_2", + "nix-health": "nix-health", + "nixpkgs": [ + "srx-nixos-shadow", + "nixpkgs" + ], + "systems": "systems_6", + "treefmt-nix": "treefmt-nix_2", + "unionmount": "unionmount_2" + }, + "locked": { + "lastModified": 1716931809, + "narHash": "sha256-VO93zEGfBaJc1tLRQeDgnqxqXjhXZhjfED+NvyZgZu8=", + "owner": "srid", + "repo": "emanote", + "rev": "fcf67dca2e7a95e4c5ac187586dc1e92dea530cf", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "emanote", + "type": "github" + } + }, + "emanote-template": { + "flake": false, + "locked": { + "lastModified": 1703877265, + "narHash": "sha256-2xdikzzHrIHr1s2pAJrBJU8mZP258Na3V4P4RWteDZM=", + "owner": "srid", + "repo": "emanote-template", + "rev": "9d458b63c80162519ae55814e60f17cc9d3f95a3", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "emanote-template", + "type": "github" + } + }, + "emanote-template_2": { + "flake": false, + "locked": { + "lastModified": 1711847690, + "narHash": "sha256-A/5b7vB1+FI2qsuPJL/pZ9CkWozSCbOoaqqN4y+Pmxc=", + "owner": "srid", + "repo": "emanote-template", + "rev": "32330b5e3bdca89ca67f5c212be6db43dbb13cd8", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "emanote-template", + "type": "github" + } + }, + "emanote_2": { + "inputs": { + "commonmark-simple": "commonmark-simple_2", + "commonmark-wikilink": "commonmark-wikilink_2", + "ema": "ema_2", + "emanote-template": "emanote-template", + "flake-parts": "flake-parts_2", + "flake-root": "flake-root_2", + "haskell-flake": "haskell-flake", + "heist-extra": "heist-extra", + "nixpkgs": "nixpkgs_4", + "systems": "systems_5", + "treefmt-nix": "treefmt-nix", + "unionmount": "unionmount" + }, + "locked": { + "lastModified": 1709754457, + "narHash": "sha256-JBpIQsCSaQzLY5LnCO9xj3O7nnv0ekgO1ZTSkevRfi4=", + "owner": "srid", + "repo": "emanote", + "rev": "922f79430416b09e91d735a27b01ddbb48ef7b83", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "emanote", + "type": "github" + } + }, + "firefox-addons": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "dir": "pkgs/firefox-addons", + "lastModified": 1719875691, + "narHash": "sha256-DtfpH7yivPHcfXV0EL70NwCKlg6nVTZGNngWkPshQjM=", + "owner": "rycee", + "repo": "nur-expressions", + "rev": "f2c6c0e41d6c2c82524b9d104bcfd1750a426d1b", + "type": "gitlab" + }, + "original": { + "dir": "pkgs/firefox-addons", + "owner": "rycee", + "repo": "nur-expressions", + "type": "gitlab" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "locked": { + "lastModified": 1717312683, + "narHash": "sha256-FrlieJH50AuvagamEvWMIE6D2OAnERuDboFDYAED/dE=", + "owner": "nix-community", + "repo": "flake-compat", + "rev": "38fd3954cf65ce6faf3d0d45cd26059e059f07ea", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_3": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_4": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719877454, + "narHash": "sha256-g5N1yyOSsPNiOlFfkuI/wcUjmtah+nxdImJqrSATjOU=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "4e3583423212f9303aa1a6337f8dffb415920e4f", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1704982712, + "narHash": "sha256-2Ptt+9h8dczgle2Oo6z5ni5rt/uLMG47UFTR1ry/wgg=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "07f6395285469419cf9d078f59b5b49993198c00", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_3": { + "inputs": { + "nixpkgs-lib": [ + "srx-nixos-shadow", + "hercules-ci-effects", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1712014858, + "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", + "type": "github" + }, + "original": { + "id": "flake-parts", + "type": "indirect" + } + }, + "flake-root": { + "locked": { + "lastModified": 1713493429, + "narHash": "sha256-ztz8JQkI08tjKnsTpfLqzWoKFQF4JGu2LRz8bkdnYUk=", + "owner": "srid", + "repo": "flake-root", + "rev": "bc748b93b86ee76e2032eecda33440ceb2532fcd", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "flake-root", + "type": "github" + } + }, + "flake-root_2": { + "locked": { + "lastModified": 1692742795, + "narHash": "sha256-f+Y0YhVCIJ06LemO+3Xx00lIcqQxSKJHXT/yk1RTKxw=", + "owner": "srid", + "repo": "flake-root", + "rev": "d9a70d9c7a5fd7f3258ccf48da9335e9b47c3937", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "flake-root", + "type": "github" + } + }, + "flake-root_3": { + "locked": { + "lastModified": 1692742795, + "narHash": "sha256-f+Y0YhVCIJ06LemO+3Xx00lIcqQxSKJHXT/yk1RTKxw=", + "owner": "srid", + "repo": "flake-root", + "rev": "d9a70d9c7a5fd7f3258ccf48da9335e9b47c3937", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "flake-root", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1689068808, + "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_3": { + "inputs": { + "systems": "systems_7" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "fromYaml": { + "flake": false, + "locked": { + "lastModified": 1689549921, + "narHash": "sha256-iX0pk/uB019TdBGlaJEWvBCfydT6sRq+eDcGPifVsCM=", + "owner": "SenchoPens", + "repo": "fromYaml", + "rev": "11fbbbfb32e3289d3c631e0134a23854e7865c84", + "type": "github" + }, + "original": { + "owner": "SenchoPens", + "repo": "fromYaml", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": [ + "flake-compat" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1719259945, + "narHash": "sha256-F1h+XIsGKT9TkGO3omxDLEb/9jOOsI6NnzsXFsZhry4=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "0ff4381bbb8f7a52ca4a851660fc7a437a4c6e07", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "git-hooks_2": { + "inputs": { + "flake-compat": "flake-compat_4", + "gitignore": "gitignore_2", + "nixpkgs": [ + "nixvim", + "nixpkgs" + ], + "nixpkgs-stable": [ + "nixvim", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719259945, + "narHash": "sha256-F1h+XIsGKT9TkGO3omxDLEb/9jOOsI6NnzsXFsZhry4=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "0ff4381bbb8f7a52ca4a851660fc7a437a4c6e07", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gitignore_2": { + "inputs": { + "nixpkgs": [ + "nixvim", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gnome-shell": { + "flake": false, + "locked": { + "lastModified": 1713702291, + "narHash": "sha256-zYP1ehjtcV8fo+c+JFfkAqktZ384Y+y779fzmR9lQAU=", + "owner": "GNOME", + "repo": "gnome-shell", + "rev": "0d0aadf013f78a7f7f1dc984d0d812971864b934", + "type": "github" + }, + "original": { + "owner": "GNOME", + "ref": "46.1", + "repo": "gnome-shell", + "type": "github" + } + }, + "haskell-flake": { + "locked": { + "lastModified": 1709233214, + "narHash": "sha256-kraFY5MmY7yxsEtSF8qPrFVmA6MXkF+sJfo7EV1dcY8=", + "owner": "srid", + "repo": "haskell-flake", + "rev": "3a8c1b58cff60886260156a20a3b3ad725bbf885", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "haskell-flake", + "type": "github" + } + }, + "haskell-flake_2": { + "locked": { + "lastModified": 1712823089, + "narHash": "sha256-AGkk2WK/E9mLcoEdfegZ1aYNh6HtOdPuEx4O+r44u3I=", + "owner": "srid", + "repo": "haskell-flake", + "rev": "92e393141a123c9695bc15dbe1ca0a1b7fef142b", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "haskell-flake", + "type": "github" + } + }, + "heist-extra": { + "flake": false, + "locked": { + "lastModified": 1706086475, + "narHash": "sha256-scXMVFKSaS4Wi4y6I84oPKHaTmLECsvq8eLxGL0XH5o=", + "owner": "srid", + "repo": "heist-extra", + "rev": "c6d8ef79b415fab276fb461d5860bbf2628e6e43", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "heist-extra", + "type": "github" + } + }, + "heist-extra_2": { + "flake": false, + "locked": { + "lastModified": 1710541479, + "narHash": "sha256-9e4U78eutom6D3EJqsCdV8iQxNgYA/pi001r5CZdm0A=", + "owner": "srid", + "repo": "heist-extra", + "rev": "589b7636f620dcdfc0dc07dea720feed1ab3e0fa", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "heist-extra", + "type": "github" + } + }, + "hercules-ci-effects": { + "inputs": { + "flake-parts": "flake-parts_3", + "nixpkgs": "nixpkgs_5" + }, + "locked": { + "lastModified": 1719226092, + "narHash": "sha256-YNkUMcCUCpnULp40g+svYsaH1RbSEj6s4WdZY/SHe38=", + "owner": "hercules-ci", + "repo": "hercules-ci-effects", + "rev": "11e4b8dc112e2f485d7c97e1cee77f9958f498f5", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "hercules-ci-effects", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719827385, + "narHash": "sha256-qs+nU20Sm8czHg3bhGCqiH+8e13BJyRrKONW34g3i50=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "391ca6e950c2525b4f853cbe29922452c14eda82", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "release-24.05", + "repo": "home-manager", + "type": "github" + } + }, + "impermanence": { + "locked": { + "lastModified": 1719091691, + "narHash": "sha256-AxaLX5cBEcGtE02PeGsfscSb/fWMnyS7zMWBXQWDKbE=", + "owner": "nix-community", + "repo": "impermanence", + "rev": "23c1f06316b67cb5dabdfe2973da3785cfe9c34a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "impermanence", + "type": "github" + } + }, + "kubenix": { + "inputs": { + "flake-compat": "flake-compat_3", + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems_4", + "treefmt": "treefmt" + }, + "locked": { + "lastModified": 1719313214, + "narHash": "sha256-3CY/B/60A5rikhU5OlgDdNZMsOSIA1MteA2UPm4EHU0=", + "owner": "hall", + "repo": "kubenix", + "rev": "d6ddf1b4e8804e3c9564696a493ac14c0bcb19e2", + "type": "github" + }, + "original": { + "owner": "hall", + "repo": "kubenix", + "type": "github" + } + }, + "lanzaboote": { + "inputs": { + "crane": "crane", + "flake-compat": [ + "flake-compat" + ], + "flake-parts": [ + "flake-parts" + ], + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit-hooks-nix": [ + "git-hooks" + ], + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1719818887, + "narHash": "sha256-Bogl1pJlgby7OpR16jp8zwOWV7FHRxCsnNxHcisyIq0=", + "owner": "nix-community", + "repo": "lanzaboote", + "rev": "0e6457c98547ec8866714d4222545e7e8c1ae429", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "lanzaboote", + "type": "github" + } + }, + "microvm": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "spectrum": "spectrum" + }, + "locked": { + "lastModified": 1719525795, + "narHash": "sha256-nWGOQgqyhj7YynykVlM/DKxaYshhraV27R5tqQgWAEg=", + "owner": "astro", + "repo": "microvm.nix", + "rev": "3692c11ceed00632345b106b24a8cd2c9ffe5569", + "type": "github" + }, + "original": { + "owner": "astro", + "repo": "microvm.nix", + "type": "github" + } + }, + "nix": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "lastModified": 1712911606, + "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", + "owner": "domenkozar", + "repo": "nix", + "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "devenv-2.21", + "repo": "nix", + "type": "github" + } + }, + "nix-darwin": { + "inputs": { + "nixpkgs": [ + "nixvim", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719845423, + "narHash": "sha256-ZLHDmWAsHQQKnmfyhYSHJDlt8Wfjv6SQhl2qek42O7A=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "ec12b88104d6c117871fad55e931addac4626756", + "type": "github" + }, + "original": { + "owner": "lnl7", + "repo": "nix-darwin", + "type": "github" + } + }, + "nix-fast-build": { + "inputs": { + "flake-parts": [ + "flake-parts" + ], + "nixpkgs": [ + "nixpkgs" + ], + "treefmt-nix": [ + "treefmt-nix" + ] + }, + "locked": { + "lastModified": 1719475157, + "narHash": "sha256-8zW6eWvE9T03cMpo/hY8RRZIsSCfs1zmsJOkEZzuYwM=", + "owner": "Mic92", + "repo": "nix-fast-build", + "rev": "030e586195c97424844965d2ce680140f6565c02", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "nix-fast-build", + "type": "github" + } + }, + "nix-filter": { + "locked": { + "lastModified": 1678109515, + "narHash": "sha256-C2X+qC80K2C1TOYZT8nabgo05Dw2HST/pSn6s+n6BO8=", + "owner": "numtide", + "repo": "nix-filter", + "rev": "aa9ff6ce4a7f19af6415fb3721eaa513ea6c763c", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "nix-filter", + "type": "github" + } + }, + "nix-filter_2": { + "locked": { + "lastModified": 1710156097, + "narHash": "sha256-1Wvk8UP7PXdf8bCCaEoMnOT1qe5/Duqgj+rL8sRQsSM=", + "owner": "numtide", + "repo": "nix-filter", + "rev": "3342559a24e85fc164b295c3444e8a139924675b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "nix-filter", + "type": "github" + } + }, + "nix-github-actions": { + "inputs": { + "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1688870561, + "narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=", + "owner": "nix-community", + "repo": "nix-github-actions", + "rev": "165b1650b753316aa7f1787f3005a8d2da0f5301", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-github-actions", + "type": "github" + } + }, + "nix-hamburg-website": { + "inputs": { + "flake-parts": [ + "flake-parts" + ], + "nix-filter": "nix-filter", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit": [ + "git-hooks" + ], + "treefmt-nix": [ + "treefmt-nix" + ] + }, + "locked": { + "lastModified": 1715951121, + "narHash": "sha256-9b2Ifbur3NJ3pidZxoffSLiXLpgpWJqAYtQFr/TWERE=", + "ref": "refs/heads/main", + "rev": "a101b3de595b168b95c18503be041557d3d3eb3f", + "revCount": 20, + "type": "git", + "url": "ssh://forgejo@code.srx.digital/nix-hamburg/nix-hamburg.astro.nix" + }, + "original": { + "type": "git", + "url": "ssh://forgejo@code.srx.digital/nix-hamburg/nix-hamburg.astro.nix" + } + }, + "nix-health": { + "locked": { + "dir": "module", + "lastModified": 1716931776, + "narHash": "sha256-M4YqLtNAkj8pqG6dp7wHKz9EOecB3bWHp7WHyXIlMMc=", + "owner": "juspay", + "repo": "nix-health", + "rev": "2f8d8dc30121923192c78a8f5152c5c89fdf1809", + "type": "github" + }, + "original": { + "dir": "module", + "owner": "juspay", + "repo": "nix-health", + "type": "github" + } + }, + "nix-index-database": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719832725, + "narHash": "sha256-dr8DkeS74KVNTgi8BE0BiUKALb+EKlMIV86G2xPYO64=", + "owner": "nix-community", + "repo": "nix-index-database", + "rev": "2917972ed34ce292309b3a4976286f8b5c08db27", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-index-database", + "type": "github" + } + }, + "nix-vscode-extensions": { + "inputs": { + "flake-compat": [ + "flake-compat" + ], + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719883589, + "narHash": "sha256-Xiir5+DZfsVLzI/DmVdCL9rt6RbfNPS0uW0pdymm4wM=", + "owner": "nix-community", + "repo": "nix-vscode-extensions", + "rev": "3be7b0b799d739c3e15f3fd0a909d682c173962f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-vscode-extensions", + "type": "github" + } + }, + "nix_2": { + "inputs": { + "flake-compat": [ + "devenv", + "flake-compat" + ], + "nixpkgs": [ + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression_2" + }, + "locked": { + "lastModified": 1712911606, + "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", + "owner": "domenkozar", + "repo": "nix", + "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "devenv-2.21", + "repo": "nix", + "type": "github" + } + }, + "nixlib": { + "locked": { + "lastModified": 1719708727, + "narHash": "sha256-XFNKtyirrGNdehpg7lMNm1skEcBApjqGhaHc/OI95HY=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "1bba8a624b3b9d4f68db94fb63aaeb46039ce9e6", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixos-anywhere": { + "inputs": { + "disko": [ + "disko" + ], + "flake-parts": [ + "flake-parts" + ], + "nixos-images": "nixos-images", + "nixos-stable": "nixos-stable", + "nixpkgs": [ + "nixpkgs" + ], + "treefmt-nix": [ + "treefmt-nix" + ] + }, + "locked": { + "lastModified": 1719852663, + "narHash": "sha256-83rF68wdvOc9iyHSIxlgk/PMoFXilIYabOxC+meamyo=", + "owner": "nix-community", + "repo": "nixos-anywhere", + "rev": "f99d120b3788a286989db4e592a698f5d310d2f6", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-anywhere", + "type": "github" + } + }, + "nixos-generators": { + "inputs": { + "nixlib": "nixlib", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719841141, + "narHash": "sha256-WOyohxFJJdfDvEB7N3eTcX44lNU2rZes1inHsyHL7mM=", + "owner": "nix-community", + "repo": "nixos-generators", + "rev": "140dcc2b9a0eb87ba5e9011076a1a7af19179ab1", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-generators", + "type": "github" + } + }, + "nixos-hardware": { + "locked": { + "lastModified": 1719895800, + "narHash": "sha256-xNbjISJTFailxass4LmdWeV4jNhAlmJPwj46a/GxE6M=", + "owner": "NixOS", + "repo": "nixos-hardware", + "rev": "6e253f12b1009053eff5344be5e835f604bb64cd", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixos-hardware", + "type": "github" + } + }, + "nixos-images": { + "inputs": { + "nixos-stable": [ + "nixos-anywhere", + "nixos-stable" + ], + "nixos-unstable": [ + "nixos-anywhere", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1717994219, + "narHash": "sha256-ueTu01bYU5QXdL77psMkApYHpk339xNHg/M7ZzP3uPI=", + "owner": "nix-community", + "repo": "nixos-images", + "rev": "e2fd329c3a39a90bb43e1e2cf47c180ed57831bf", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-images", + "type": "github" + } + }, + "nixos-stable": { + "locked": { + "lastModified": 1717696253, + "narHash": "sha256-1+ua0ggXlYYPLTmMl3YeYYsBXDSCqT+Gw3u6l4gvMhA=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9b5328b7f761a7bbdc0e332ac4cf076a3eedb89b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1703013332, + "narHash": "sha256-+tFNwMvlXLbJZXiMHqYq77z/RfmpfpiI3yjL6o/Zo9M=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "54aac082a4d9bb5bbc5c4e899603abfb76a3f6d6", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-24_05": { + "locked": { + "lastModified": 1717144377, + "narHash": "sha256-F/TKWETwB5RaR8owkPPi+SPJh83AQsm6KrQAlJ8v/uA=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "805a384895c696f802a9bf5bf4720f37385df547", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-24.05", + "type": "indirect" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1703961334, + "narHash": "sha256-M1mV/Cq+pgjk0rt6VxoyyD+O8cOUiai8t9Q6Yyq4noY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b0d36bd0a420ecee3bc916c91886caca87c894e9", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-regression_2": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1718811006, + "narHash": "sha256-0Y8IrGhRmBmT7HHXlxxepg2t8j1X90++qRN3lukGaIk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "03d771e513ce90147b65fe922d87d3a0356fc125", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1692808169, + "narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9201b5ff357e781bf014d0330d18555695df7ba8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1719838683, + "narHash": "sha256-Zw9rQjHz1ilNIimEXFeVa1ERNRBF8DoXDhLAZq5B4pE=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "d032c1a6dfad4eedec7e35e91986becc699d7d69", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1704842529, + "narHash": "sha256-OTeQA+F8d/Evad33JMfuXC89VMetQbsU4qcaePchGr4=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "eabe8d3eface69f5bb16c18f8662a702f50c20d5", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_5": { + "locked": { + "lastModified": 1713714899, + "narHash": "sha256-+z/XjO3QJs5rLE5UOf015gdVauVRQd2vZtsFkaXBq2Y=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6143fc5eeb9c4f00163267708e26191d1e918932", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixvim": { + "inputs": { + "devshell": [ + "devshell" + ], + "flake-compat": [ + "flake-compat" + ], + "flake-parts": [ + "flake-parts" + ], + "git-hooks": "git-hooks_2", + "home-manager": [ + "home-manager" + ], + "nix-darwin": "nix-darwin", + "nixpkgs": [ + "nixpkgs" + ], + "treefmt-nix": [ + "treefmt-nix" + ] + }, + "locked": { + "lastModified": 1719929751, + "narHash": "sha256-CaXyTEyn5le7ad13CzigKAf8TI1iSy+PQFRkZZIatpM=", + "owner": "nix-community", + "repo": "nixvim", + "rev": "3d969603481c745f8faa411f1e8b7c97517c67a3", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixvim", + "type": "github" + } + }, + "nur": { + "locked": { + "lastModified": 1719956777, + "narHash": "sha256-Vl8Tsb/XE1dcHvDiA50vJbVYEZBmdWnqaGWD3ONGTzE=", + "owner": "nix-community", + "repo": "NUR", + "rev": "4ecd7170303a6e7eb0e34d44dfaf157b7b146adb", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "NUR", + "type": "github" + } + }, + "ocp-src": { + "flake": false, + "locked": { + "lastModified": 1701196143, + "narHash": "sha256-PMkMYEVBHt0i7ahgqF8jLhHHp7IRS7hd+JyydovNJ4A=", + "owner": "cadquery", + "repo": "ocp", + "rev": "4b98a5dc79fa900f7429975708f6a8c2e41cecd1", + "type": "github" + }, + "original": { + "owner": "cadquery", + "repo": "ocp", + "rev": "4b98a5dc79fa900f7429975708f6a8c2e41cecd1", + "type": "github" + } + }, + "ocp-stubs-src": { + "flake": false, + "locked": { + "lastModified": 1672527176, + "narHash": "sha256-m9Rg36GYlYfwEfF0PQJWEXf8TyM5HmjeuhJCODiurvY=", + "owner": "cadquery", + "repo": "ocp-stubs", + "rev": "e838ff400d5ee2f4a0579d2a713b19311855288f", + "type": "github" + }, + "original": { + "owner": "cadquery", + "repo": "ocp-stubs", + "type": "github" + } + }, + "poetry2nix": { + "inputs": { + "flake-utils": "flake-utils", + "nix-github-actions": "nix-github-actions", + "nixpkgs": [ + "devenv", + "cachix", + "devenv", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1692876271, + "narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=", + "owner": "nix-community", + "repo": "poetry2nix", + "rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "poetry2nix", + "type": "github" + } + }, + "pybind11-stubgen-src": { + "flake": false, + "locked": { + "lastModified": 1700678104, + "narHash": "sha256-76u1GcHPPh8oYQeQZDJ4K/so0U7F6rznZ1xa6syqI9s=", + "owner": "CadQuery", + "repo": "pybind11-stubgen", + "rev": "6dc681d838d3ec9a8a9aa4260c8392d3fb700ff0", + "type": "github" + }, + "original": { + "owner": "CadQuery", + "repo": "pybind11-stubgen", + "type": "github" + } + }, + "pywrap-src": { + "flake": false, + "locked": { + "lastModified": 1676015766, + "narHash": "sha256-QhAvJHV5tFq9bjKOzEpcudZNnmUmNVrJ+BLCZJhO31g=", + "owner": "CadQuery", + "repo": "pywrap", + "rev": "f3bcde70fd66a2d884fa60a7a9d9f6aa7c3b6e16", + "type": "github" + }, + "original": { + "owner": "CadQuery", + "repo": "pywrap", + "type": "github" + } + }, + "root": { + "inputs": { + "agenix": "agenix", + "base16-schemes": "base16-schemes", + "cq-flake": "cq-flake", + "deploy-rs": "deploy-rs", + "devenv": "devenv", + "devshell": "devshell", + "disko": "disko", + "dns": "dns", + "firefox-addons": "firefox-addons", + "flake-compat": "flake-compat_2", + "flake-parts": "flake-parts", + "flake-root": "flake-root", + "flake-utils": "flake-utils_2", + "git-hooks": "git-hooks", + "home-manager": "home-manager", + "impermanence": "impermanence", + "kubenix": "kubenix", + "lanzaboote": "lanzaboote", + "microvm": "microvm", + "nix-fast-build": "nix-fast-build", + "nix-hamburg-website": "nix-hamburg-website", + "nix-index-database": "nix-index-database", + "nix-vscode-extensions": "nix-vscode-extensions", + "nixos-anywhere": "nixos-anywhere", + "nixos-generators": "nixos-generators", + "nixos-hardware": "nixos-hardware", + "nixpkgs": "nixpkgs_3", + "nixvim": "nixvim", + "nur": "nur", + "simple-nixos-mailserver": "simple-nixos-mailserver", + "srvos": "srvos", + "srx-digital-website": "srx-digital-website", + "srx-nixos-shadow": "srx-nixos-shadow", + "stylix": "stylix", + "systems": "systems_8", + "terranix": "terranix", + "treefmt-nix": "treefmt-nix_3", + "vault-secrets": "vault-secrets" + } + }, + "rust-overlay": { + "inputs": { + "flake-utils": [ + "lanzaboote", + "flake-utils" + ], + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1718504420, + "narHash": "sha256-F2HT/abCfr0CDpkvXwYCscJyD66XDTLMVfdrIMRp2ck=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "0043c3f92304823cc2c0a4354b0feaa61dfb4cd9", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "simple-nixos-mailserver": { + "inputs": { + "blobs": "blobs", + "flake-compat": [ + "flake-compat" + ], + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-24_05": "nixpkgs-24_05" + }, + "locked": { + "lastModified": 1718697807, + "narHash": "sha256-Enla61WFisytTYbWygPynEbu8vozjeGc6Obkj2GRj7o=", + "owner": "simple-nixos-mailserver", + "repo": "nixos-mailserver", + "rev": "290a995de5c3d3f08468fa548f0d55ab2efc7b6b", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "repo": "nixos-mailserver", + "type": "gitlab" + } + }, + "spectrum": { + "flake": false, + "locked": { + "lastModified": 1708358594, + "narHash": "sha256-e71YOotu2FYA67HoC/voJDTFsiPpZNRwmiQb4f94OxQ=", + "ref": "refs/heads/main", + "rev": "6d0e73864d28794cdbd26ab7b37259ab0e1e044c", + "revCount": 614, + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + }, + "original": { + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + } + }, + "srvos": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719835186, + "narHash": "sha256-o0FB8SQVLOnbsYTk2Bt6gXwsfqEv4ZHsGP50/kM/gR0=", + "owner": "nix-community", + "repo": "srvos", + "rev": "14b3b0aa48fa291f1be26ab8948d5b9eadaed0b8", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "srvos", + "type": "github" + } + }, + "srx-digital-website": { + "inputs": { + "flake-parts": [ + "flake-parts" + ], + "nix-filter": "nix-filter_2", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit": [ + "git-hooks" + ], + "treefmt-nix": [ + "treefmt-nix" + ] + }, + "locked": { + "lastModified": 1715951577, + "narHash": "sha256-jeD4kUPQ/D6JejNcCOEVp3vR74E9ViRqyyoN0ADz7Xo=", + "ref": "refs/heads/main", + "rev": "bc1debcba00827af290174b4228b38e6eac19782", + "revCount": 58, + "type": "git", + "url": "ssh://forgejo@code.srx.digital/srx/srx.astro.nix" + }, + "original": { + "type": "git", + "url": "ssh://forgejo@code.srx.digital/srx/srx.astro.nix" + } + }, + "srx-nixos-shadow": { + "inputs": { + "dns": "dns_2", + "emanote": "emanote", + "flake-compat": [ + "flake-compat" + ], + "flake-parts": [ + "flake-parts" + ], + "flake-utils": "flake-utils_3", + "hercules-ci-effects": "hercules-ci-effects", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit-hooks": [ + "git-hooks" + ], + "treefmt-nix": [ + "treefmt-nix" + ] + }, + "locked": { + "lastModified": 1720092823, + "narHash": "sha256-OYIdNAbRFgLdkzhAxhjpaw5hLQPJQ5oKIht+zckAX8Y=", + "ref": "refs/heads/main", + "rev": "ee18bff34a774eaaa7def58f97a9321021d16287", + "revCount": 13, + "type": "git", + "url": "ssh://forgejo@code.srx.digital/srx/srx-nixos-shadow" + }, + "original": { + "type": "git", + "url": "ssh://forgejo@code.srx.digital/srx/srx-nixos-shadow" + } + }, + "stylix": { + "inputs": { + "base16": "base16", + "base16-fish": "base16-fish", + "base16-foot": "base16-foot", + "base16-helix": "base16-helix", + "base16-kitty": "base16-kitty", + "base16-tmux": "base16-tmux", + "base16-vim": "base16-vim", + "flake-compat": [ + "flake-compat" + ], + "gnome-shell": "gnome-shell", + "home-manager": [ + "home-manager" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719525570, + "narHash": "sha256-xSO/H67GAHEW0siD2PHoO/e97MbROL3r3s5SpF6A6Dc=", + "owner": "danth", + "repo": "stylix", + "rev": "1ff9d37d27377bfe8994c24a8d6c6c1734ffa116", + "type": "github" + }, + "original": { + "owner": "danth", + "repo": "stylix", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_4": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "id": "systems", + "type": "indirect" + } + }, + "systems_5": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_6": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_7": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_8": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "terranix": { + "inputs": { + "bats-assert": "bats-assert", + "bats-support": "bats-support", + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "terranix-examples": "terranix-examples" + }, + "locked": { + "lastModified": 1695406838, + "narHash": "sha256-xiUfVD6rtsVWFotVtUW3Q1nQh4obKzgvpN1wqZuGXvM=", + "owner": "terranix", + "repo": "terranix", + "rev": "fc9077ca02ab5681935dbf0ecd725c4d889b9275", + "type": "github" + }, + "original": { + "owner": "terranix", + "repo": "terranix", + "type": "github" + } + }, + "terranix-examples": { + "locked": { + "lastModified": 1636300201, + "narHash": "sha256-0n1je1WpiR6XfCsvi8ZK7GrpEnMl+DpwhWaO1949Vbc=", + "owner": "terranix", + "repo": "terranix-examples", + "rev": "a934aa1cf88f6bd6c6ddb4c77b77ec6e1660bd5e", + "type": "github" + }, + "original": { + "owner": "terranix", + "repo": "terranix-examples", + "type": "github" + } + }, + "treefmt": { + "inputs": { + "nixpkgs": [ + "kubenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1688026376, + "narHash": "sha256-qJmkr9BWDpqblk4E9/rCsAEl39y2n4Ycw6KRopvpUcY=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "df3f32b0cc253dfc7009b7317e8f0e7ccd70b1cf", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "srx-nixos-shadow", + "emanote", + "ema", + "emanote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1693468138, + "narHash": "sha256-DddblCahuTW8K0ncPOheTlG3igE8b15LJjafF1PWhOo=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "6930a5ba0a722385baf273885a03f561dcb1af67", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "treefmt-nix_2": { + "inputs": { + "nixpkgs": [ + "srx-nixos-shadow", + "emanote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1711963903, + "narHash": "sha256-N3QDhoaX+paWXHbEXZapqd1r95mdshxToGowtjtYkGI=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "49dc4a92b02b8e68798abd99184f228243b6e3ac", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "treefmt-nix_3": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719887753, + "narHash": "sha256-p0B2r98UtZzRDM5miGRafL4h7TwGRC4DII+XXHDHqek=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "bdb6355009562d8f9313d9460c0d3860f525bc6c", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "unionmount": { + "flake": false, + "locked": { + "lastModified": 1691619410, + "narHash": "sha256-V9/OcGu9cy4kV9jta12A6w5BEj8awSEVYrXPpg8YckQ=", + "owner": "srid", + "repo": "unionmount", + "rev": "ed73b627f88c8f021f41ba4b518ba41beff9df42", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "unionmount", + "type": "github" + } + }, + "unionmount_2": { + "flake": false, + "locked": { + "lastModified": 1710078535, + "narHash": "sha256-gKBgBtuiRTD3/3EeY8aMgFzuaSEffJacBxsCB3ct1eg=", + "owner": "srid", + "repo": "unionmount", + "rev": "41ae982fa118770bf4d3a3f2d48ac1ffb61c9f09", + "type": "github" + }, + "original": { + "owner": "srid", + "repo": "unionmount", + "type": "github" + } + }, + "vault-secrets": { + "inputs": { + "flake-compat": [ + "flake-compat" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1714988039, + "narHash": "sha256-ZYPX1Skhy9ZEfeRkAzdqO+MvjBdF4a7blrXcTJ3q/Yw=", + "owner": "serokell", + "repo": "vault-secrets", + "rev": "44ef2078d9149aa3b23fe132e8c8d8bbd624c06c", + "type": "github" + }, + "original": { + "owner": "serokell", + "repo": "vault-secrets", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..14952dd --- /dev/null +++ b/flake.nix @@ -0,0 +1,285 @@ +{ + description = "SRX NixOS Platform"; + + nixConfig = { + extra-trusted-substituters = [ + "https://nix-config.cachix.org" + "https://nix-community.cachix.org" + "https://tweag-jupyter.cachix.org" + "https://serokell.cachix.org" + "https://cache.nix.srx.digital" + ]; + extra-trusted-public-keys = [ + "nix-config.cachix.org-1:Vd6raEuldeIZpttVQfrUbLvXJHzzzkS0pezXCVVjDG4=" + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "tweag-jupyter.cachix.org-1:UtNH4Zs6hVUFpFBTLaA4ejYavPo5EFFqgd7G7FxGW9g=" + "serokell.cachix.org-1:5DscEJD6c1dD1Mc/phTIbs13+iW22AVbx0HqiSb+Lq8=" + "cache.nix.srx.digital-1:+sJ/hAmjuhTpRakfhkCj7i2LoqNyBgm+YItJUSAWWlg=" + ]; + }; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05"; + + nixos-hardware.url = "github:NixOS/nixos-hardware"; + + nur.url = "github:nix-community/NUR"; + + nixos-anywhere = { + url = "github:nix-community/nixos-anywhere"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-parts.follows = "flake-parts"; + disko.follows = "disko"; + treefmt-nix.follows = "treefmt-nix"; + }; + }; + + nixos-generators = { + url = "github:nix-community/nixos-generators"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + flake-parts = { + url = "github:hercules-ci/flake-parts"; + inputs.nixpkgs-lib.follows = "nixpkgs"; + }; + + flake-utils.url = "github:numtide/flake-utils"; + + flake-compat.url = "github:nix-community/flake-compat"; + + devenv = { + url = "github:cachix/devenv"; + inputs = { + nixpkgs.follows = "nixpkgs"; + pre-commit-hooks.follows = "git-hooks"; + flake-compat.follows = "flake-compat"; + }; + }; + + devshell = { + url = "github:numtide/devshell"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; + + flake-root.url = "github:srid/flake-root"; + + srvos = { + url = "github:nix-community/srvos"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + home-manager = { + url = "github:nix-community/home-manager/release-24.05"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + lanzaboote = { + url = "github:nix-community/lanzaboote"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-compat.follows = "flake-compat"; + flake-parts.follows = "flake-parts"; + flake-utils.follows = "flake-utils"; + pre-commit-hooks-nix.follows = "git-hooks"; + }; + }; + + nix-fast-build = { + url = "github:Mic92/nix-fast-build"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-parts.follows = "flake-parts"; + treefmt-nix.follows = "treefmt-nix"; + }; + }; + + systems.url = "github:nix-systems/default"; + + agenix = { + url = "github:ryantm/agenix"; + inputs = { + home-manager.follows = "home-manager"; + nixpkgs.follows = "nixpkgs"; + }; + }; + + disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + nixvim = { + url = "github:nix-community/nixvim"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-parts.follows = "flake-parts"; + flake-compat.follows = "flake-compat"; + devshell.follows = "devshell"; + home-manager.follows = "home-manager"; + treefmt-nix.follows = "treefmt-nix"; + }; + }; + + deploy-rs = { + url = "github:serokell/deploy-rs"; + inputs = { + flake-compat.follows = "flake-compat"; + nixpkgs.follows = "nixpkgs"; + utils.follows = "flake-utils"; + }; + }; + + treefmt-nix = { + url = "github:numtide/treefmt-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + git-hooks = { + url = "github:cachix/git-hooks.nix"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-compat.follows = "flake-compat"; + }; + }; + + base16-schemes = { + url = "github:tinted-theming/base16-schemes"; + flake = false; + }; + + stylix = { + url = "github:danth/stylix"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-compat.follows = "flake-compat"; + home-manager.follows = "home-manager"; + }; + }; + + kubenix = { + url = "github:hall/kubenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + microvm = { + url = "github:astro/microvm.nix"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; + + vault-secrets = { + url = "github:serokell/vault-secrets"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-compat.follows = "flake-compat"; + }; + }; + + dns = { + url = "github:nix-community/dns.nix"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; + + impermanence.url = "github:nix-community/impermanence"; + + simple-nixos-mailserver = { + url = "gitlab:simple-nixos-mailserver/nixos-mailserver"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-compat.follows = "flake-compat"; + }; + }; + + terranix = { + url = "github:terranix/terranix"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; + + nix-vscode-extensions = { + url = "github:nix-community/nix-vscode-extensions"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + flake-compat.follows = "flake-compat"; + }; + }; + + firefox-addons = { + url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; + + cq-flake = { + url = "github:vinszent/cq-flake"; + inputs.flake-utils.follows = "flake-utils"; + }; + + srx-nixos-shadow = { + url = "git+ssh://forgejo@code.srx.digital/srx/srx-nixos-shadow"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-compat.follows = "flake-compat"; + flake-parts.follows = "flake-parts"; + pre-commit-hooks.follows = "git-hooks"; + treefmt-nix.follows = "treefmt-nix"; + }; + }; + + srx-digital-website = { + url = "git+ssh://forgejo@code.srx.digital/srx/srx.astro.nix"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-parts.follows = "flake-parts"; + treefmt-nix.follows = "treefmt-nix"; + pre-commit.follows = "git-hooks"; + }; + }; + + nix-hamburg-website = { + url = "git+ssh://forgejo@code.srx.digital/nix-hamburg/nix-hamburg.astro.nix"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-parts.follows = "flake-parts"; + treefmt-nix.follows = "treefmt-nix"; + pre-commit.follows = "git-hooks"; + }; + }; + }; + + outputs = inputs@ { flake-parts, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ "x86_64-linux" "aarch64-linux" ]; + imports = [ + ./nix/hosts.nix + ./nix/packages.nix + ./nix/modules.nix + ./nix/overlay.nix + ./nix/nixos.nix + ./nix/home-manager.nix + ./nix/deploy.nix + ./nix/devshell.nix + ./nix/terranix.nix + ]; + }; +} diff --git a/hosts/dev-vm/clevis.age b/hosts/dev-vm/clevis.age new file mode 100644 index 0000000..036d92b Binary files /dev/null and b/hosts/dev-vm/clevis.age differ diff --git a/hosts/dev-vm/default.nix b/hosts/dev-vm/default.nix new file mode 100644 index 0000000..cdca9c3 --- /dev/null +++ b/hosts/dev-vm/default.nix @@ -0,0 +1,27 @@ +{ self, ... }: +{ + imports = [ + self.nixosModules.roles-workstation + ./hardware.nix + ./storage.nix + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "dev-vm"; + hostId = "ea0023ed"; + }; + + systemd.network = { + enable = true; + networks."10-uplink" = { + matchConfig.Name = "enp1s0"; + address = [ "192.168.122.26/24" ]; + routes = [ + { routeConfig.Gateway = "192.168.122.1"; } + { routeConfig.Gateway = "fe80::1"; } + ]; + }; + }; +} diff --git a/hosts/dev-vm/hardware.nix b/hosts/dev-vm/hardware.nix new file mode 100644 index 0000000..87356ba --- /dev/null +++ b/hosts/dev-vm/hardware.nix @@ -0,0 +1,37 @@ +{ self, modulesPath, config, ... }: +{ + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + (modulesPath + "/profiles/qemu-guest.nix") + self.nixosModules.filesystems-zfs + ]; + + age.secrets.clevisSystem.file = ./clevis.age; + + boot = { + initrd = { + systemd = { + enable = true; + inherit (config.systemd) network; + }; + network.enable = true; + availableKernelModules = [ + "ahci" + "xhci_pci" + "virtio_pci" + "virtio_scsi" + "sr_mod" + "virtio_blk" + ]; + clevis = { + enable = true; + useTang = true; + devices."vda".secretFile = config.age.secrets.clevisSystem.path; + }; + }; + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + }; +} diff --git a/hosts/dev-vm/storage.nix b/hosts/dev-vm/storage.nix new file mode 100644 index 0000000..ce31e8c --- /dev/null +++ b/hosts/dev-vm/storage.nix @@ -0,0 +1,143 @@ +{ lib, ... }: +let + disks = [ + "/dev/vda" + # "/dev/vdb" + ]; + compression = "zstd"; + rootFsOptions = { + acltype = "posixacl"; + dnodesize = "auto"; + normalization = "formD"; + xattr = "sa"; + relatime = "on"; + canmount = "off"; + mountpoint = "none"; + inherit compression; + "com.sun:auto-snapshot" = "false"; + }; + passwordFile = "/etc/hostname"; + system = lib.genAttrs disks + (device: + let + name = builtins.replaceStrings [ "_" ] [ "-" ] (lib.lists.last (builtins.split "/" device)); + in + { + type = "disk"; + inherit name device; + content = { + type = "gpt"; + partitions = { + boot = { + size = "1M"; + type = "EF02"; + }; + esp = { + size = "1G"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + swap = { + size = "8G"; + type = "8200"; + content.type = "swap"; + }; + system = { + size = "100%"; + content = { + type = "luks"; + inherit name; + content = { + type = "zfs"; + pool = "system"; + }; + inherit passwordFile; + settings.allowDiscards = true; + }; + }; + }; + }; + }); + default = mountpoint: { + type = "zfs_fs"; + options = { + inherit mountpoint; + }; + inherit mountpoint; + }; + auto_snapshot = mountpoint: { + type = "zfs_fs"; + options = { + inherit mountpoint; + "com.sun:auto-snapshot" = "true"; + }; + inherit mountpoint; + }; + can_not_mount = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + }; + mountpoint = null; + mountOptions = [ ]; + }; +in +{ + disko.devices = { + disk = system; + zpool = { + system = { + type = "zpool"; + options = { + ashift = "12"; + autotrim = "on"; + }; + inherit rootFsOptions; + mountpoint = null; + datasets = { + "reserved" = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + refreservation = "10GiB"; + }; + mountpoint = null; + mountOptions = [ ]; + }; + "nixos" = can_not_mount; + "nixos/etc" = default "/etc"; + "nixos/nix" = default "/nix"; + "user" = can_not_mount; + "user/root" = default "/root"; + "user/home" = auto_snapshot "/home"; + "data" = can_not_mount; + "data/lib" = auto_snapshot "/var/lib"; + "data/log" = default "/var/log"; + "data/cache" = default "/var/cache"; + "data/backup" = default "/var/backup"; + }; + }; + }; + nodev = { + "/" = { + fsType = "tmpfs"; + mountOptions = [ + "defaults" + "size=1G" + "mode=755" + "noatime" + ]; + }; + "/tmp" = { + fsType = "tmpfs"; + mountOptions = [ "size=1G" ]; + }; + }; + }; +} diff --git a/hosts/srxfdm00/default.nix b/hosts/srxfdm00/default.nix new file mode 100644 index 0000000..971dd49 --- /dev/null +++ b/hosts/srxfdm00/default.nix @@ -0,0 +1,16 @@ +{ self, ... }: +{ + imports = [ + self.nixosModules.roles-core + ./hardware.nix + ./services/wireguard.nix + # ./services/moonraker.nix + # ./services/fluidd.nix + # ./services/klipper + # ./services/octoprint.nix + ]; + + networking.hostName = "srxfdm00"; + + system.stateVersion = "24.05"; +} diff --git a/hosts/srxfdm00/hardware.nix b/hosts/srxfdm00/hardware.nix new file mode 100644 index 0000000..a39d535 --- /dev/null +++ b/hosts/srxfdm00/hardware.nix @@ -0,0 +1,11 @@ +{ self, ... }: +{ + imports = [ + self.nixosModules.hardware-rpi4 + ]; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/44444444-4444-4444-8888-888888888888"; + fsType = "ext4"; + }; +} diff --git a/hosts/srxfdm00/services/fluidd.nix b/hosts/srxfdm00/services/fluidd.nix new file mode 100644 index 0000000..a46adc6 --- /dev/null +++ b/hosts/srxfdm00/services/fluidd.nix @@ -0,0 +1,19 @@ +{ + services = { + fluidd = { + enable = true; + + nginx = { + default = true; + locations."/webcam".proxyPass = "http://127.0.0.1:8080/stream"; + }; + }; + + nginx.clientMaxBodySize = "1000m"; + }; + + networking.firewall = { + allowedTCPPorts = [ 80 ]; + allowedUDPPorts = [ 80 ]; + }; +} diff --git a/hosts/srxfdm00/services/klipper/default.nix b/hosts/srxfdm00/services/klipper/default.nix new file mode 100644 index 0000000..aac3a17 --- /dev/null +++ b/hosts/srxfdm00/services/klipper/default.nix @@ -0,0 +1,33 @@ +{ lib, config, ... }: +{ + services.klipper = { + enable = true; + octoprintIntegration = lib.mkIf config.services.octoprint.enable true; + user = lib.mkForce "klipper"; + group = lib.mkForce "klipper"; + firmwares.mcu = { + enable = true; + serial = /dev/serial/by-id/usb-Klipper_stm32f446xx_360015001750535556323420-if00; + configFile = ./firmware.ini; + enableKlipperFlash = true; + }; + configFile = ./settings.cfg; + }; + + users = { + groups.${config.services.klipper.group} = { }; + users.${config.services.klipper.user} = { + group = "${config.services.klipper.group}"; + extraGroups = [ "dialout" ]; + isSystemUser = true; + }; + }; + + security.sudo.extraRules = [{ + commands = [{ + command = "/run/current-system/sw/bin/poweroff"; + options = [ "NOPASSWD" ]; + }]; + groups = [ config.services.klipper.group ]; + }]; +} diff --git a/hosts/srxfdm00/services/klipper/firmware.ini b/hosts/srxfdm00/services/klipper/firmware.ini new file mode 100644 index 0000000..b807bc6 --- /dev/null +++ b/hosts/srxfdm00/services/klipper/firmware.ini @@ -0,0 +1,109 @@ +CONFIG_LOW_LEVEL_OPTIONS=y +# CONFIG_MACH_AVR is not set +# CONFIG_MACH_ATSAM is not set +# CONFIG_MACH_ATSAMD is not set +# CONFIG_MACH_LPC176X is not set +CONFIG_MACH_STM32=y +# CONFIG_MACH_HC32F460 is not set +# CONFIG_MACH_RP2040 is not set +# CONFIG_MACH_PRU is not set +# CONFIG_MACH_AR100 is not set +# CONFIG_MACH_LINUX is not set +# CONFIG_MACH_SIMU is not set +CONFIG_BOARD_DIRECTORY="stm32" +CONFIG_MCU="stm32f446xx" +CONFIG_CLOCK_FREQ=180000000 +CONFIG_USBSERIAL=y +CONFIG_FLASH_SIZE=0x80000 +CONFIG_FLASH_BOOT_ADDRESS=0x8000000 +CONFIG_RAM_START=0x20000000 +CONFIG_RAM_SIZE=0x20000 +CONFIG_STACK_SIZE=512 +CONFIG_FLASH_APPLICATION_ADDRESS=0x8008000 +CONFIG_STM32_SELECT=y +# CONFIG_MACH_STM32F103 is not set +# CONFIG_MACH_STM32F207 is not set +# CONFIG_MACH_STM32F401 is not set +# CONFIG_MACH_STM32F405 is not set +# CONFIG_MACH_STM32F407 is not set +# CONFIG_MACH_STM32F429 is not set +CONFIG_MACH_STM32F446=y +# CONFIG_MACH_STM32F765 is not set +# CONFIG_MACH_STM32F031 is not set +# CONFIG_MACH_STM32F042 is not set +# CONFIG_MACH_STM32F070 is not set +# CONFIG_MACH_STM32F072 is not set +# CONFIG_MACH_STM32G070 is not set +# CONFIG_MACH_STM32G071 is not set +# CONFIG_MACH_STM32G0B0 is not set +# CONFIG_MACH_STM32G0B1 is not set +# CONFIG_MACH_STM32G431 is not set +# CONFIG_MACH_STM32H723 is not set +# CONFIG_MACH_STM32H743 is not set +# CONFIG_MACH_STM32H750 is not set +# CONFIG_MACH_STM32L412 is not set +# CONFIG_MACH_N32G452 is not set +# CONFIG_MACH_N32G455 is not set +CONFIG_MACH_STM32F4=y +CONFIG_HAVE_STM32_USBOTG=y +CONFIG_HAVE_STM32_CANBUS=y +CONFIG_HAVE_STM32_USBCANBUS=y +CONFIG_STM32_DFU_ROM_ADDRESS=0x1fff0000 +CONFIG_STM32_FLASH_START_8000=y +# CONFIG_STM32_FLASH_START_10000 is not set +# CONFIG_STM32_FLASH_START_0000 is not set +# CONFIG_STM32_CLOCK_REF_8M is not set +CONFIG_STM32_CLOCK_REF_12M=y +# CONFIG_STM32_CLOCK_REF_16M is not set +# CONFIG_STM32_CLOCK_REF_20M is not set +# CONFIG_STM32_CLOCK_REF_24M is not set +# CONFIG_STM32_CLOCK_REF_25M is not set +# CONFIG_STM32_CLOCK_REF_INTERNAL is not set +CONFIG_CLOCK_REF_FREQ=12000000 +CONFIG_STM32F0_TRIM=16 +CONFIG_STM32_USB_PA11_PA12=y +# CONFIG_STM32_SERIAL_USART1 is not set +# CONFIG_STM32_SERIAL_USART1_ALT_PB7_PB6 is not set +# CONFIG_STM32_SERIAL_USART2 is not set +# CONFIG_STM32_SERIAL_USART2_ALT_PD6_PD5 is not set +# CONFIG_STM32_SERIAL_USART3 is not set +# CONFIG_STM32_SERIAL_USART3_ALT_PD9_PD8 is not set +# CONFIG_STM32_CANBUS_PA11_PA12 is not set +# CONFIG_STM32_CANBUS_PA11_PB9 is not set +# CONFIG_STM32_MMENU_CANBUS_PB8_PB9 is not set +# CONFIG_STM32_MMENU_CANBUS_PI9_PH13 is not set +# CONFIG_STM32_MMENU_CANBUS_PB5_PB6 is not set +# CONFIG_STM32_MMENU_CANBUS_PB12_PB13 is not set +# CONFIG_STM32_MMENU_CANBUS_PD0_PD1 is not set +# CONFIG_STM32_USBCANBUS_PA11_PA12 is not set +CONFIG_USB=y +CONFIG_USB_VENDOR_ID=0x1d50 +CONFIG_USB_DEVICE_ID=0x614e +CONFIG_USB_SERIAL_NUMBER_CHIPID=y +CONFIG_USB_SERIAL_NUMBER="12345" + +# +# USB ids +# +# end of USB ids + +CONFIG_WANT_GPIO_BITBANGING=y +CONFIG_WANT_DISPLAYS=y +CONFIG_WANT_SENSORS=y +CONFIG_WANT_LIS2DW=y +CONFIG_WANT_SOFTWARE_I2C=y +CONFIG_WANT_SOFTWARE_SPI=y +CONFIG_NEED_SENSOR_BULK=y +CONFIG_CANBUS_FREQUENCY=1000000 +CONFIG_INITIAL_PINS="" +CONFIG_HAVE_GPIO=y +CONFIG_HAVE_GPIO_ADC=y +CONFIG_HAVE_GPIO_SPI=y +CONFIG_HAVE_GPIO_SDIO=y +CONFIG_HAVE_GPIO_I2C=y +CONFIG_HAVE_GPIO_HARD_PWM=y +CONFIG_HAVE_STRICT_TIMING=y +CONFIG_HAVE_CHIPID=y +CONFIG_HAVE_STEPPER_BOTH_EDGE=y +CONFIG_HAVE_BOOTLOADER_REQUEST=y +CONFIG_INLINE_STEPPER_HACK=y \ No newline at end of file diff --git a/hosts/srxfdm00/services/klipper/settings.cfg b/hosts/srxfdm00/services/klipper/settings.cfg new file mode 100644 index 0000000..518cd5b --- /dev/null +++ b/hosts/srxfdm00/services/klipper/settings.cfg @@ -0,0 +1,583 @@ +# Copymaster3D Voron2 V2.4 R2-SB Kit +# 350 x 350 x 350mm - With StealthBurner +# E3D V6 Hotend Kit 0.4 nozzle +# BigtreeTech Octopus V1.1 STM32F446ZET6 +# TMC2209 UART + +[mcu] +serial: /dev/serial/by-id/usb-Klipper_stm32f446xx_360015001750535556323420-if00 +restart_method: command + +[printer] +kinematics: corexy +max_velocity: 300 +max_accel: 4000 +max_z_velocity: 25 +max_z_accel: 400 +square_corner_velocity: 5.0 + +##################################################################### +# X/Y Stepper Settings +##################################################################### + +## B Stepper - Left +## Connected to MOTOR_0 +## Endstop connected to DIAG_0 +[stepper_x] +step_pin: PF13 +dir_pin: PF12 +enable_pin: !PF14 +rotation_distance: 40 +microsteps: 32 +full_steps_per_rotation: 400 +endstop_pin: ^PG6 +position_min: 0 +position_endstop: 350 +position_max: 350 +homing_speed: 100 +homing_retract_dist: 3 +homing_positive_dir: true + +[tmc2209 stepper_x] +uart_pin: PC4 +interpolate: false +run_current: 0.8 +sense_resistor: 0.110 +stealthchop_threshold: 0 + +## A Stepper - Right +## Connected to MOTOR_1 +## Endstop connected to DIAG_1 +[stepper_y] +step_pin: PG0 +dir_pin: PG1 +enable_pin: !PF15 +rotation_distance: 40 +microsteps: 32 +full_steps_per_rotation: 400 +endstop_pin: PG9 +position_min: 0 +position_endstop: 350 +position_max: 350 +homing_speed: 100 +homing_retract_dist: 3 +homing_positive_dir: true + +[tmc2209 stepper_y] +uart_pin: PD11 +interpolate: false +run_current: 0.8 +sense_resistor: 0.110 +stealthchop_threshold: 0 + +##################################################################### +# Z Stepper Settings +##################################################################### + +## Z0 Stepper - Front Left +## Connected to MOTOR_2 +## Endstop connected to DIAG_2 +[stepper_z] +step_pin: PF11 +dir_pin: PG3 +enable_pin: !PG5 +rotation_distance: 40 +gear_ratio: 80:16 +microsteps: 32 +endstop_pin: ^PG10 +position_endstop: 1.725 +position_max: 310 +position_min: -5 +homing_speed: 100 +second_homing_speed: 3 +homing_retract_dist: 3 + +[tmc2209 stepper_z] +uart_pin: PC6 +interpolate: false +run_current: 0.8 +sense_resistor: 0.110 +stealthchop_threshold: 0 + +## Z1 Stepper - Rear Left +## Connected to MOTOR_3 +[stepper_z1] +step_pin: PG4 +dir_pin: !PC1 +enable_pin: !PA0 +rotation_distance: 40 +gear_ratio: 80:16 +microsteps: 32 + +[tmc2209 stepper_z1] +uart_pin: PC7 +interpolate: false +run_current: 0.8 +sense_resistor: 0.110 +stealthchop_threshold: 0 + +## Z2 Stepper - Rear Right +## Connected to MOTOR_4 +[stepper_z2] +step_pin: PF9 +dir_pin: PF10 +enable_pin: !PG2 +rotation_distance: 40 +gear_ratio: 80:16 +microsteps: 32 + +[tmc2209 stepper_z2] +uart_pin: PF2 +interpolate: false +run_current: 0.8 +sense_resistor: 0.110 +stealthchop_threshold: 0 + +## Z3 Stepper - Front Right +## Connected to MOTOR_5 +[stepper_z3] +step_pin: PC13 +dir_pin: !PF0 +enable_pin: !PF1 +rotation_distance: 40 +gear_ratio: 80:16 +microsteps: 32 + +[tmc2209 stepper_z3] +uart_pin: PE4 +interpolate: false +run_current: 0.8 +sense_resistor: 0.110 +stealthchop_threshold: 0 + + +##################################################################### +# Extruder +##################################################################### + +## Connected to MOTOR_6 +## Heater - HE0 +## Thermistor - T0 +[extruder] +step_pin: PE2 +dir_pin: !PE3 +enable_pin: !PD4 +## Update value below when you perform extruder calibration +## If you ask for 100mm of filament, but in reality it is 98mm: +## rotation_distance = * / 100 +rotation_distance: 22.6789511 +gear_ratio: 50:10 +microsteps: 32 +full_steps_per_rotation: 200 +nozzle_diameter: 0.400 +filament_diameter: 1.75 +heater_pin: PA2 +sensor_type: ATC Semitec 104GT-2 +sensor_pin: PF4 +min_temp: 10 +max_temp: 270 +max_power: 1.0 +min_extrude_temp: 170 +control: pid +pid_Kp: 21.464 +pid_Ki: 0.878 +pid_Kd: 131.198 +pressure_advance: 0.05 +pressure_advance_smooth_time: 0.040 + +## E0 on MOTOR6 +[tmc2209 extruder] +uart_pin: PE1 +interpolate: false +run_current: 0.5 +sense_resistor: 0.110 +stealthchop_threshold: 0 + +##################################################################### +# Bed Heater +##################################################################### + +## SSR Pin - HE1 +## Thermistor - TB +[heater_bed] +heater_pin: PA3 +sensor_type: Generic 3950 +sensor_pin: PF3 +## Adjust max_power so it doesn't exceed the SSR rating. The Omron G3NA-210B-DC5 SSR is rated at 4 amps without a heatsink. +## The formula is "4 / (Wattage_of_bed_heater / Mains_voltage) = max_power" +## If max_power is greater than 1.0, use 1.0 +max_power: 0.6 +min_temp: 0 +max_temp: 120 +control: pid +pid_Kp: 38.507 +pid_Ki: 0.820 +pid_Kd: 451.976 + +##################################################################### +# Probe +##################################################################### + +## Inductive Probe +## This probe is not used for Z height, only Quad Gantry Leveling +[probe] +# Omron TL-Q5MC2 NPN Inductive Probe (NC) +# https://www.mouser.de/datasheet/2/307/omrns03968_1-2279740.pdf +pin: PG15 +x_offset: 0 +y_offset: 25.0 +z_offset: 0 +speed: 10.0 +samples: 3 +samples_result: median +sample_retract_dist: 3.0 +samples_tolerance: 0.006 +samples_tolerance_retries: 3 + +##################################################################### +# Fan Control +##################################################################### + +## Print Cooling Fan - FAN0 +[fan] +pin: PA8 +kick_start_time: 0.5 +## Depending on your fan, you may need to increase this value +## if your fan will not start. Can change cycle_time (increase) +## if your fan is not able to slow down effectively +off_below: 0.10 + +## Hotend Fan - FAN1 +[heater_fan hotend_fan] +pin: PE5 +max_power: 1.0 +kick_start_time: 0.5 +heater: extruder +heater_temp: 50.0 +## If you are experiencing back flow, you can reduce fan_speed +#fan_speed: 1.0 + +## Controller fan - FAN2 +[controller_fan controller_fan] +pin: PD12 +kick_start_time: 0.5 +heater: heater_bed + +## Exhaust fan - FAN3 +#[heater_fan exhaust_fan] +#pin: PD13 +#max_power: 1.0 +#shutdown_speed: 0.0 +#kick_start_time: 5.0 +#heater: heater_bed +#heater_temp: 60 +#fan_speed: 1.0 + +##################################################################### +# LED Control +##################################################################### + +## Chamber Lighting - HE2 Connector +#[output_pin caselight] +##Octopus 1.0 & 1.1, Octopus PRO 1.0 +#pin: PB10 +##Octopus PRO 1.1 +#pin: PB0 +#pwm:true +#shutdown_value: 0 +#value:1 +#cycle_time: 0.01 + +[neopixel headlight] +## Stealthburner lighting - RGB_LED +pin: PB0 +chain_count: 3 +color_order: GRBW +initial_RED: 1.0 +initial_GREEN: 0.0 +initial_BLUE: 0.0 +initial_WHITE: 0.0 + +##################################################################### +# Additional Sensors +##################################################################### + +# [temperature_sensor chamber_temp] +# ## Chamber Temperature - T1 +# sensor_type: ATC Semitec 104NT-4-R025H42G +# sensor_pin: PF5 +# min_temp: 0 +# max_temp: 100 +# gcode_id: chamber_th + +##################################################################### +# Homing and Gantry Adjustment Routines +##################################################################### + +[idle_timeout] +timeout: 1800 + +[safe_z_home] +home_xy_position: 233,346 +speed:100 +z_hop:10 +z_hop_speed:10 + +[quad_gantry_level] +gantry_corners: + -60,-10 + 410,420 +points: + 50,25 + 50,275 + 300,275 + 300,25 +speed: 100 +horizontal_move_z: 10 +retries: 5 +retry_tolerance: 0.0075 +max_adjust: 10 + +[bed_mesh] +speed: 300 +horizontal_move_z: 15 +mesh_min: 40, 40 +mesh_max: 310,310 +fade_start: 0.6 +fade_end: 10.0 +probe_count: 5,5 +algorithm: bicubic + +[bed_mesh default] +version: 1 +points: + -0.095299, -0.102799, -0.102799, -0.097799, -0.102799 + -0.144049, -0.146549, -0.135299, -0.137799, -0.141549 + -0.159049, -0.156549, -0.141549, -0.141549, -0.159049 + -0.141549, -0.154049, -0.157799, -0.159049, -0.172799 + -0.097799, -0.120299, -0.120299, -0.110299, -0.109049 +x_count: 5 +y_count: 5 +mesh_x_pps: 2 +mesh_y_pps: 2 +algo: bicubic +tension: 0.2 +min_x: 40.0 +max_x: 310.0 +min_y: 40.0 +max_y: 310.0 + +######################################## +# EXP1 / EXP2 (display) pins +######################################## + +[board_pins] +aliases: + EXP1_1=PE8, + EXP1_2=PE7, + EXP1_3=PE9, + EXP1_4=PE10, + EXP1_5=PE12, + EXP1_6=PE13, + EXP1_7=PE14, + EXP1_8=PE15, + EXP1_9=, + EXP1_10=<5V>, + EXP2_1=PA6, + EXP2_2=PA5, + EXP2_3=PB1, + EXP2_4=PA4, + EXP2_5=PB2, + EXP2_6=PA7, + EXP2_7=PC15, + EXP2_8=, + EXP2_9=, + EXP2_10=<5V> + +##################################################################### +# Displays +##################################################################### + +[display] # mini12864 LCD Display +lcd_type: uc1701 +cs_pin: EXP1_3 +a0_pin: EXP1_4 +rst_pin: EXP1_5 +encoder_pins: ^EXP2_5, ^EXP2_3 +click_pin: ^!EXP1_2 +contrast: 63 +spi_software_miso_pin: EXP2_1 +spi_software_mosi_pin: EXP2_6 +spi_software_sclk_pin: EXP2_2 + +[neopixel btt_mini12864] # Neopixel RGB in mini12864 +pin: EXP1_6 +chain_count: 3 +initial_RED: 0.1 +initial_GREEN: 0.5 +initial_BLUE: 0.0 +color_order: RGB + +[delayed_gcode setdisplayneopixel] # Index 1 = display, Index 2 and 3 = Knob +initial_duration: 1 +gcode: + SET_LED LED=btt_mini12864 RED=1 GREEN=1 BLUE=1 INDEX=1 TRANSMIT=0 + SET_LED LED=btt_mini12864 RED=1 GREEN=0 BLUE=0 INDEX=2 TRANSMIT=0 + SET_LED LED=btt_mini12864 RED=1 GREEN=0 BLUE=0 INDEX=3 + +[virtual_sdcard] +path: /var/lib/moonraker/gcodes + +[pause_resume] + +##################################################################### +# Macros +##################################################################### + +[gcode_macro PARK] +gcode: + {% set th = printer.toolhead %} + G0 X{th.axis_maximum.x // 2} Y{th.axis_maximum.y // 2} Z30 + +[gcode_macro G32] +gcode: + SAVE_GCODE_STATE NAME=STATE_G32 + G90 + G28 + QUAD_GANTRY_LEVEL + BED_MESH_CALIBRATE + G28 + PARK + RESTORE_GCODE_STATE NAME=STATE_G32 + +[gcode_macro PRINT_START] +gcode: + G32 ; home all axes + G90 ; absolute positioning + G1 Z20 F3000 ; move nozzle away from bed + +[gcode_macro PRINT_END] +gcode: + # safe anti-stringing move coords + {% set th = printer.toolhead %} + {% set x_safe = th.position.x + 20 * (1 if th.axis_maximum.x - th.position.x > 20 else -1) %} + {% set y_safe = th.position.y + 20 * (1 if th.axis_maximum.y - th.position.y > 20 else -1) %} + {% set z_safe = [th.position.z + 2, th.axis_maximum.z]|min %} + + SAVE_GCODE_STATE NAME=STATE_PRINT_END + + M400 ; wait for buffer to clear + G92 E0 ; zero the extruder + G1 E-5.0 F1800 ; retract filament + + TURN_OFF_HEATERS + + G90 ; absolute positioning + G0 X{x_safe} Y{y_safe} Z{z_safe} F20000 ; move nozzle to remove stringing + G0 X{th.axis_maximum.x//2} Y{th.axis_maximum.y - 2} F3600 ; park nozzle at rear + M107 ; turn off fan + + BED_MESH_CLEAR + + # The purpose of the SAVE_GCODE_STATE/RESTORE_GCODE_STATE + # command pair is to restore the printer's coordinate system + # and speed settings since the commands above change them. + # However, to prevent any accidental, unintentional toolhead + # moves when restoring the state, explicitly set MOVE=0. + RESTORE_GCODE_STATE NAME=STATE_PRINT_END MOVE=0 + +[gcode_macro CANCEL_PRINT] +rename_existing: BASE_CANCEL_PRINT +gcode: + M220 S100 ; Reset Speed factor override percentage to default (100%) + M221 S100 ; Reset Extrude factor override percentage to default (100%) + G91 ; Set coordinates to relative + {% if printer.extruder.temperature >= 170 %} + G1 F1800 E-1 ; Retract filament 3 mm to prevent oozing + {% endif %} + ;if all axis are homed, lift the hotend to leave room for hot filament to ooze and to keep it clear of the bed. + {% if printer.toolhead.homed_axes == "xyz" %} + G1 F6000 Z10 ; Move Z Axis up 10 mm to allow filament ooze freely + G90 ; Set coordinates to absolute + G1 X10 Y221 F1000 ; Move Printer Head Out of Way + {% endif %} + ;set part fan speed to zero. + M106 S0 + ;bed and hotend are left at the print temps in case I want to restart. + CLEAR_PAUSE + BASE_CANCEL_PRINT + +[gcode_macro INJECT_FILAMENT] +gcode: + {% set E = params.E|default(62) %} + M117 Injecting filament + G91 + G1 E{E} F2100 + G90 + +[gcode_macro CLEAN_NOZZLE] +gcode: + {% if "xyz" in printer.toolhead.homed_axes %} + {% if printer.extruder.temperature >= 200 %} + M117 Cleaning nozzle + G91 + G0 Z10 F10000 + SAVE_GCODE_STATE NAME=clean_nozzle + G90 + G0 X200 Y305 F10000 + SAVE_GCODE_STATE NAME=clean_nozzle_above + G0 Z1.4 F10000 + G0 X250 F10000 + G0 Y304 X200 + G0 Y305 X250 + G0 Y304 X200 + G0 Y305 X250 + G0 Y304 X200 + G0 Y304 X250 + G0 Y305 X200 + G0 Y304 X250 + G0 Y303 X200 + G0 Y303 X250 + G0 Y304 X200 + G0 Y303 X250 + G0 Y304 X200 + G0 Y305 X250 + G0 Y303 X200 + G0 Y305 X250 + RESTORE_GCODE_STATE NAME=clean_nozzle_above MOVE=1 + M117 Cleaned! + RESTORE_GCODE_STATE NAME=clean_nozzle MOVE=1 + G91 + G0 Z-10 F10000 + G90 + {% endif %} + {% else %} + { action_raise_error("Please home your axes!") } + M117 Please home first! + {% endif %} + +[gcode_macro PRIME_NOZZLE] +gcode: + {% set E = params.E|default(0.5) %} # retract size + {% if not "xyz" in printer.toolhead.homed_axes %} + { action_raise_error("Please home your axes!") } + M117 Please home first! + {% else %} + {% if not printer.extruder.temperature >= 200 %} + { action_raise_error("Heat up nozzle first!") } + M117 Heat up nozzle first! + {% else %} + {% if not printer["filament_switch_sensor toolhead_sensor"].filament_detected %} + G90 + G0 X200 Y305 F10000 + INJECT_FILAMENT + CLEAN_NOZZLE + {% endif %} + {% endif %} + {% endif %} + + +[gcode_macro EXTRUDER_MAINTENANCE] +gcode: + {% set th = printer.toolhead %} + G0 X{th.axis_maximum.x // 2} Y0 Z{th.axis_maximum.z // 2} diff --git a/hosts/srxfdm00/services/moonraker.nix b/hosts/srxfdm00/services/moonraker.nix new file mode 100644 index 0000000..08a80bd --- /dev/null +++ b/hosts/srxfdm00/services/moonraker.nix @@ -0,0 +1,44 @@ +{ lib, config, ... }: +{ + services.moonraker = { + enable = true; + group = "${config.services.klipper.group}"; + + allowSystemControl = true; + + settings = { + server = { + max_upload_size = 16384; + }; + octoprint_compat = { + enable_ufp = true; + webcam_enabled = true; + }; + zeroconf = { }; + history = { }; + authorization = { + force_logins = true; + cors_domains = [ + "*.local" + "*.lan" + "*://localhost:*" + "http://*.lan" + "http://*.local" + ]; + trusted_clients = [ + "10.0.0.0/8" + "127.0.0.0/8" + "169.254.0.0/16" + "172.16.0.0/12" + "192.168.1.0/24" + "FE80::/10" + "::1/128" + ]; + }; + }; + }; + + security.polkit.enable = lib.mkIf config.services.moonraker.allowSystemControl true; + + networking.firewall.allowedTCPPorts = [ config.services.moonraker.port ]; +} diff --git a/hosts/srxfdm00/services/octoprint.nix b/hosts/srxfdm00/services/octoprint.nix new file mode 100644 index 0000000..54240c6 --- /dev/null +++ b/hosts/srxfdm00/services/octoprint.nix @@ -0,0 +1,11 @@ +{ pkgs, ... }: +{ + services.octoprint = { + enable = true; + openFirewall = true; + plugins = with pkgs.octoprint.plugins; [ + themeify + stlviewer + ]; + }; +} diff --git a/hosts/srxfdm00/services/wireguard.nix b/hosts/srxfdm00/services/wireguard.nix new file mode 100644 index 0000000..75edb39 --- /dev/null +++ b/hosts/srxfdm00/services/wireguard.nix @@ -0,0 +1,39 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.12/24" ]; + networkConfig = { + IPMasquerade = "ipv4"; + IPForward = true; + }; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; +} diff --git a/hosts/srxfdm00/vpn_srx.age b/hosts/srxfdm00/vpn_srx.age new file mode 100644 index 0000000..6cb0416 Binary files /dev/null and b/hosts/srxfdm00/vpn_srx.age differ diff --git a/hosts/srxgp00/default.nix b/hosts/srxgp00/default.nix new file mode 100644 index 0000000..b17e06c --- /dev/null +++ b/hosts/srxgp00/default.nix @@ -0,0 +1,56 @@ +{ self, lib, ... }: +{ + imports = [ + self.nixosModules.roles-server + self.nixosModules.filesystems-zfs + self.nixosModules.services-security-tang + self.nixosModules.services-netboot + self.nixosModules.services-monitoring-loki + self.nixosModules.custom-dns-knot + + ./hardware.nix + ./storage.nix + ./services/wireguard + ./services/nginx + ./services/oauth2-proxy + # ./services/openldap + ./services/mysql + ./services/influxdb + ./services/postgresql + ./services/minio + ./services/restic + ./services/grafana + ./services/prometheus + ./services/keycloak + ./services/mailserver + ./services/coturn + ./services/dendrite + ./services/hydra + ./services/plausible + ./services/forgejo + ./services/vaultwarden + ./services/hedgedoc + ./services/nextcloud + ./services/paperless + ./services/jellyfin + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "srxgp00"; + domain = "srx.digital"; + hostId = "8556b001"; + }; + + systemd.network.networks."10-uplink".networkConfig.Address = "2a01:4f9:6b:2573::1/64"; + + services.knot.settings.server = { + identity = "ns1.srx.dev"; + listen = lib.mkForce [ + "10.80.0.1@53" + "65.108.77.254@53" + "2a01:4f9:6b:2573::1@53" + ]; + }; +} diff --git a/hosts/srxgp00/hardware.nix b/hosts/srxgp00/hardware.nix new file mode 100644 index 0000000..99ced29 --- /dev/null +++ b/hosts/srxgp00/hardware.nix @@ -0,0 +1,22 @@ +{ self, inputs, modulesPath, ... }: +{ + imports = with inputs; [ + (modulesPath + "/installer/scan/not-detected.nix") + self.nixosModules.hardware + self.nixosModules.hardware-cpu-amd + srvos.nixosModules.hardware-hetzner-online-amd + ]; + + boot = { + initrd = { + availableKernelModules = [ + "xhci_pci" + "ahci" + "nvme" + ]; + kernelModules = [ ]; + }; + swraid.enable = true; + zfs.devNodes = "/dev/disk/by-uuid"; + }; +} diff --git a/hosts/srxgp00/services/coturn/auth-secret.age b/hosts/srxgp00/services/coturn/auth-secret.age new file mode 100644 index 0000000..db2942e --- /dev/null +++ b/hosts/srxgp00/services/coturn/auth-secret.age @@ -0,0 +1,22 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw RrFIECbXxeuPEyGxWOHSWr23wh7cJ2ojtxeOuiQG1Tw +HL4pQADIbm67noLw+WHr7VWbkCeGLW0Gg9iW2FinQP4 +-> ssh-ed25519 JzjriQ mhhYpWUGZoDWLO9KHbikn+P/sm//F+Rr7+KXWx9elW4 +qe/oMpinF6trDHeb5gu1dJ+f4AIbydlQ5Kko+7hcDBE +-> ssh-rsa 6hPx7A +JadRDjvcFPCFeXxmyk3Xlns1jpnlACM6AYX7XCiPwlqxjsdM3z3Ffo3rXg3CD2C+ +v7nJ4WJ0vxiGwKy5R2RIpKpV+ufCEpifjlwxmyJMiyW2XT4zKGdFKvDmz487yhIV +l1xQYEfxL9rLrGRu14nFT7ogmpQL1XxDjBu+wRaBamLL/XoMtDQnOh0WxOy606jW +o2BXUpibE637bTQ9I5W8CjRg0vmx9DxfRpe1K/v91dB39TTekxPiK4hqZKN4CfvU +vKua/lT102auTHT9CVnUS9hbfgAlMYL/iOpV7RgjpMLbMn1km9seTzLwmq0ZaKIO +ZFmhPtSAFPziUtgsejlJHF2ubGoOyeZ29Ufch8QemEF4JTg53bavJrSBeo3GH0Ed +khu874/lgzD7qEj+ZobZrY+asHb5vN4bjdiMsSC2P3/h/P1I+a3/UzU1Q+l4zIdi +IUNvEuZassxef1IN7WFMX+58Mnhe5xFIACGDyGmFANX1CwW/SHGJVR50kuBYlivD +tzhCs09LSvA3XCLTmv3xAlPNuVo4yWMtBSIA5wjyI9Aii3LiwrNu7WJZVHm/P7HR +8vtLiUJHqE4/cntL3hdu1y9JT6Q5p+iIOorkVOxP/YYkzber1E4tlB53gX3nn9Zc +UlwcjYu98Rlr7ZQpBHfNlG2kPVk4eB+wQ0FANEpN/DM +-> ssh-ed25519 Dfencg Hhxyaq+w1z3iliBW3YkShIb2/UozH4iDMnkPKINJkn0 +tjpcXjYEam9qj6MNlLXbc4i/pTK1UXek2zK7K9E7rfc +--- 8hw3Ug1U7dk7EF0kMJXJVFKGralF+GDOzh6D1gTihHY + +FUJqiuXfLW,s4zQ-L*YPӿZt˽ \ No newline at end of file diff --git a/hosts/srxgp00/services/coturn/default.nix b/hosts/srxgp00/services/coturn/default.nix new file mode 100644 index 0000000..9abd7e1 --- /dev/null +++ b/hosts/srxgp00/services/coturn/default.nix @@ -0,0 +1,81 @@ +{ config, ... }: +{ + age.secrets.coturnAuthSecret = { + file = ./auth-secret.age; + owner = "turnserver"; + }; + + services = { + coturn = rec { + enable = true; + no-cli = true; + + min-port = 49000; + max-port = 50000; + + realm = "turn.srx.digital"; + + use-auth-secret = true; + static-auth-secret-file = config.age.secrets.coturnAuthSecret.path; + + cert = "${config.security.acme.certs.${realm}.directory}/fullchain.pem"; + pkey = "${config.security.acme.certs.${realm}.directory}/key.pem"; + + extraConfig = '' + prometheus + listening-ip=65.108.77.254 + listening-ip=2a01:4f9:6b:2573::1 + no-multicast-peers + denied-peer-ip=127.0.0.0-127.255.255.255 + denied-peer-ip=0.0.0.0-0.255.255.255 + denied-peer-ip=10.0.0.0-10.255.255.255 + denied-peer-ip=100::-100::ffff:ffff:ffff:ffff + denied-peer-ip=100.64.0.0-100.127.255.255 + denied-peer-ip=169.254.0.0-169.254.255.255 + denied-peer-ip=172.16.0.0-172.31.255.255 + denied-peer-ip=192.0.0.0-192.0.0.255 + denied-peer-ip=192.0.2.0-192.0.2.255 + denied-peer-ip=192.168.0.0-192.168.255.255 + denied-peer-ip=192.88.99.0-192.88.99.255 + denied-peer-ip=198.18.0.0-198.19.255.255 + denied-peer-ip=198.51.100.0-198.51.100.255 + denied-peer-ip=203.0.113.0-203.0.113.255 + denied-peer-ip=240.0.0.0-255.255.255.255 + denied-peer-ip=::1 + denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff + denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff + denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff + denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff + denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff + denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255 + ''; + }; + + nginx.virtualHosts.${config.services.coturn.realm} = { + forceSSL = true; + enableACME = true; + }; + + prometheus.scrapeConfigs = [{ + job_name = "coturn"; + scrape_interval = "60s"; + metrics_path = "/metrics"; + scheme = "http"; + static_configs = [{ targets = [ "${config.services.coturn.realm}:9641" ]; }]; + }]; + }; + + networking.firewall = + let + range = with config.services.coturn; [{ + from = min-port; + to = max-port; + }]; + in + { + allowedTCPPorts = [ 3478 ]; + allowedTCPPortRanges = range; + allowedUDPPorts = [ 3478 ]; + allowedUDPPortRanges = range; + }; +} diff --git a/hosts/srxgp00/services/dendrite/default.nix b/hosts/srxgp00/services/dendrite/default.nix new file mode 100644 index 0000000..ece0622 --- /dev/null +++ b/hosts/srxgp00/services/dendrite/default.nix @@ -0,0 +1,185 @@ +{ pkgs, config, ... }: +let + name = "dendrite"; + domain_name = "srx.digital"; + server_name = "matrix.${domain_name}"; + admin_domain = "admin.${server_name}"; + chat_domain = "chat.${server_name}"; + bindHost = "localhost"; +in +{ + age.secrets = { + dendriteEnvironment.file = ./environment.age; + dendritePrivateKey.file = ./private-key.age; + }; + + services = { + dendrite = { + enable = true; + openRegistration = false; + environmentFile = config.age.secrets.dendriteEnvironment.path; + settings = { + global = { + server_name = domain_name; + private_key = "$CREDENTIALS_DIRECTORY/private_key"; + + database = { + connection_string = "postgres:///${name}?host=/run/postgresql"; + max_open_conns = 90; + max_idle_conns = 5; + conn_max_lifetime = -1; + }; + + logging = [{ + type = "std"; + level = "info"; + }]; + + metrics.enabled = true; + + trusted_third_party_id_servers = [ + "matrix.org" + "vector.im" + "nixos.org" + ]; + + dns_cache = { + enabled = true; + cache_size = 4096; + cache_lifetime = "600s"; + }; + }; + + media_api.dynamic_thumbnails = true; + mscs.mscs = [ "msc2836" ]; + + client_api = { + registration_disabled = true; + rate_limiting.enabled = false; + registration_shared_secret = "$REGISTRATION_SHARED_SECRET"; + }; + + sync_api = { + search.enable = true; + real_ip_header = "X-Real-IP"; + }; + + federation_api = { + key_perspectives = [{ + server_name = "matrix.org"; + keys = [ + { + key_id = "ed25519:auto"; + public_key = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; + } + { + key_id = "ed25519:a_RXGa"; + public_key = "l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ"; + } + ]; + }]; + }; + + turn = { + turn_uris = [ + "turn:${config.services.coturn.realm}:3478?transport=udp" + "turn:${config.services.coturn.realm}:3478?transport=tcp" + ]; + turn_shared_secret = config.services.coturn.static-auth-secret-file; + }; + }; + + }; + + postgresql = { + ensureDatabases = [ name ]; + ensureUsers = [{ + inherit name; + ensureDBOwnership = true; + }]; + }; + + postgresqlBackup.databases = [ name ]; + + nginx.virtualHosts = { + ${domain_name} = { + forceSSL = true; + enableACME = true; + locations."= /.well-known/matrix/client".alias = pkgs.writeText "matrix-client" ( + builtins.toJSON { "m.homeserver".base_url = "https://${server_name}"; } + ); + locations."= /.well-known/matrix/server".extraConfig = + let + server."m.server" = "${server_name}:443"; + in + '' + add_header Content-Type application/json; + return 200 '${builtins.toJSON server}'; + ''; + }; + + ${server_name} = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://${bindHost}:${toString config.services.dendrite.httpPort}"; + }; + + ${admin_domain} = { + enableACME = true; + forceSSL = true; + locations."/".root = pkgs.synapse-admin; + }; + + ${chat_domain} = { + enableACME = true; + forceSSL = true; + locations."/".root = pkgs.element-web.override { + conf = { + brand = "srx digital"; + branding = { + welcome_background_url = "https://images.unsplash.com/photo-1480843669328-3f7e37d196ae?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"; + auth_header_logo_url = "https://${domain_name}/favicon.svg"; + }; + default_server_config = { + "m.homeserver" = { + base_url = "https://${server_name}"; + server_name = "${server_name}"; + }; + "m.identity_server".base_url = "https://${server_name}"; + }; + help_url = "https://${domain_name}"; + }; + }; + }; + }; + + prometheus.scrapeConfigs = [{ + job_name = "dendrite"; + scrape_interval = "60s"; + metrics_path = "/metrics"; + scheme = "http"; + static_configs = [{ targets = [ "${bindHost}:${toString config.services.dendrite.httpPort}" ]; }]; + }]; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${server_name}:443" ]; + tags.host = server_name; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${server_name}" ]; + tags.host = server_name; + interval = "10m"; + }]; + }; + }; + + systemd.services.dendrite = { + serviceConfig.LoadCredential = [ "private_key:${config.age.secrets.dendritePrivateKey.path}" ]; + requires = [ "postgresql.service" "keycloak.service" ]; + after = [ "postgresql.service" "keycloak.service" ]; + }; +} + diff --git a/hosts/srxgp00/services/dendrite/environment.age b/hosts/srxgp00/services/dendrite/environment.age new file mode 100644 index 0000000..6ca9e38 --- /dev/null +++ b/hosts/srxgp00/services/dendrite/environment.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw /AFAsp3kPh6uhjFn9GjZN84mywODGn3dO4JDRu/Ltk8 +9SWydf6/WZl1V9KpxVhslYZ2afTfFIoSxa1qeKi34KA +-> ssh-ed25519 JzjriQ YsdZUPErOFyRsPnDh/A7t7JnrGWVvs8lkcQh/vRVDh8 +20qNy3Ll2CXS6xcmcNOAUNFCvD7jvFrzmWnNPSdNAjo +-> ssh-rsa 6hPx7A +uQJDNP/W09WfODdzLW/oHrby2IbHsPwYqIqrnhnJQpMBaE27GcQyQ3/oX0fpFVOY +yY3LSMSa16O5pP+T9f/SC8Kklt/AKJ9bn/9E35olnhv9X9Qh/5aCk7FmAXvACguu +0OYyB/c6r8e8t2C9uitvYNwa2W5v7I6QdpiTVZBCncp/VN0aPsS+kAVxtKQndbjF +7rUmN0MtqeMP37/cIJHnK9ZoGuotkW0h+heI1Wjd808Kx4kdCJnon/NPJ873CEFQ +XEK29u0wRRRBJPKdNnWu6KDViUIoHynl4Rl0Qzi4LA20X+6+nlx2Gel99tSBSu7p +Bc5m0xiYYy69QamuSmEesvyUB//zIBPQToxiQdZD4n++9d/+HDQ/QYOOEHlpi5DA +KpHqCte6eKStSlKAvAt7A4ccSMuVXebT9NhsAUcuTp8i6z8oLH0N/H/L/MDgzgvi +FtiKdThJYlyiLDziKX6LcRVaeJxg+sLBwnNfrWVuWoka2q37LbcUlFrSDF0Us0dl +0/Y/rAC6KJztcc/zBkbnuWCZlaaBtVcLE6vpbicCTss8R+UhJCC7cin1Cnhvqgl3 +lKmln3MpsAniHCje/SWgqRyXx6fVpCDKwe+qIW1SaCekQWUo/hpJuTLfoPvBdozx +kXCiAhp9ZvHB3+mA9cUzET/DQ6WVjIGpHNncv/oKEW0 +-> ssh-ed25519 Dfencg qd8p5uFbUwDuSQn2Ql6uDYvB49V1auQCsVge0jUJzGo +amF9Mfa/Wgym1Wf0s8KoutpZvIFaYIELGd54ZG+0VSM +--- cBsNcjTDQXyuYeSA60Buo9IhJ45tzsBjplwrtbVgLEI +C|-}ѼP r[)+6Ďq@$1㻥7tPwZK-(gcN0kZⷻ](>;vqrjv5\U{Za^Ǣ3dhq,[B|VFlu|%S~/gwh \ No newline at end of file diff --git a/hosts/srxgp00/services/dendrite/private-key.age b/hosts/srxgp00/services/dendrite/private-key.age new file mode 100644 index 0000000..10f9670 --- /dev/null +++ b/hosts/srxgp00/services/dendrite/private-key.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw JXCOHhmEwyJskFn5WwcNHZmg7QlabhxVgxgikGertgE +5LlKRT0UivqcDoaXPFxtMmCsbmpRmexqK1iOcthJW7k +-> ssh-ed25519 JzjriQ fcLWfzAqfTVyWTf0ac8PqX0WtxbhSmxVoy95CPHjEFQ +IAASir2G1vnmkwBWTI/YLo0l39/cllqxGnuleMiEZmI +-> ssh-rsa 6hPx7A +Y+TtSaCA6ViMsNbsCOSUeTv0jhtR6oKEn7A+H+lwJ778lmqxjSAAiChiU8aIGQ5H ++n27+w696fISNkvRYYr1qzkqCA5qCL/gBAzTVMt5zungOem6pyF2jsdiwUiW4jFv +caVcfa0LhnHkQtgcc4qxSomxmQ8jnSzmsXBpR0EQddTZl++fxmhlpO47JI1zHUV1 +rTU7kYR4/6+Y8+qeImySexDAfxfSbig+O9v3Ph5yBM/dQKTKGCWilUSXGvy9sG/0 +hru1lWZ9KU/Hqu+19Ng28dbg1+nVjq13Q7vkwg4dgf5s9CJBzEp+A3kjZn6e5m+G +G3pv5LwfrihKfrEJVT10ARBw8ZVJIX/MD54xvIdOIndTg7LHJq0CIdL6yBjnpm5U +J+jf13HMoXLgf/HzxBA2o2dsz6zIiLfz5kLGXwNAO1nKrmQZs1jOpRcR1kksM4Ih +XYGT4w3unkpEhRHwnNZg6W3d6+5impU7OLGGRAZYdu7LwpcgXY1IA0XfqLc7n+VW +AKfaDlHHqwZAQy/ccNyaeuFf28R3uxkNvFcGeWOFw3A5iEyzBqyAHsbJJ5vD/LmB +3LktOTfrqz6JUKQSy4OI+zlt3yKLC4x/ot9rAWMjHKrtU4Ugf/ZSgzkXao+RfpiZ +FURQfpoHxT3in6bxjo+p5gsbtdElhqDL9bQdOLXNnx8 +-> ssh-ed25519 Dfencg rGosZgGJT6tEZiJcZte/yBr8ymn7R/VCoa9KimfNNQk +S0JvXPtI/qwfA5J+M19ecFk0QsUM8KJfeivzzzvKyFA +--- PQcVC0cWPhooEvu7xzoT0mUVGX9H0gqbewEtLogLMEU +p\ lm$խXa.m0 K8ψqMSEqRϫW(}एl ssh-ed25519 jDpDqw jT12Vok7oCoHwjYXiJbXak9fKwfcAoZvniEBmaDcPBs +Qn0Pt+4ItG3W/4FmGwS4bmoKLOolJIDvBMe7/yjJDpA +-> ssh-ed25519 JzjriQ L9XwYsGzK7D5bse4rtJI3NlgTsb6kShilXXKLK4wjD0 +LrZ7K+tOp38fh0i0v6y0ngWSHIuDiu1TA7OX5AWrNWs +-> ssh-rsa 6hPx7A +CVypkGjpStOfHiWyi0/edlGJVO2CsLj2DGnbpCh+EiTPp5MIimXJsv547uPNCdqV +XxFwbGU833q8QLju3ESfx6bfPAwd7waaEXmovcPgIz3YXO+9cZNITFYwwfBWUWx0 +w7e5mp6XtYxxLIvIjz9wb/S9W+/h9LAqxoOVdevj6WQt5estpNgkBVg9eilZInsL +h66xccTpuEdzhPgTcxmFTPYJf0fScm6DQoao1MzZV7Pe9XD/ryqngw0JHBlokd68 +HNvLy49tR9MmPbML5tVhK5SHkUYD7DqCkKKxafXiVtX/kAn2MqTMPVw8nqbivgvZ +6zy5/nrQfbCS8GyFRkjcIydAFzaVh4u1bczuBS7X1YEkqJRyw3OcdaAfo/7IxHK6 +TLBR1IXELRIsVhwysDaZSsr2cLnuTC8HRC9p2qdnb0/ijKBt/Ud6vIlozUB6nD5l +ybG/AQaUS3qniieFVHKCZ1ky8Fc52qIuRrRQ77cFg6a947ag79YyJV26hbyEum8Y +/rV47QEI1o8NxSXDs8ivQN32b5OKEHVEqi5G82gmA+JR1txsnYwxgvwRcpqfxhp0 +yYQIltOoauObii0FpeL7CgcInTZR6M5Pirci/ockBOvRh69VvSx9galc7ae4izCR +mkT8p14JkDcbkkCvA3StBdcHJn3cYk8nS21A5np2R9U +-> ssh-ed25519 Dfencg sRiDIIupHKr2ntrv85rAARp4d/v4Nu+eh7WbVZHBFRU +X5mxkEQkN1zaDBOKVP6bjwCkO+BbFllT+IviAhjXutg +--- s9jOcB3p945ujdml4LdOf7UGJeXWl+HPwCOItXCDMtY +z:(+kICPX a +F0*-{'4]: ssh-ed25519 jDpDqw 1QcQUWrDCoAbMO+vVjHW8/7TVERv/u/yYg5FEWDNIjs +9grSDCY6vp1JCEVFMlSPVl52/3hAXid955IlwwEQ8N4 +-> ssh-ed25519 JzjriQ EixF6itE/FEMMmVg5tvuvolhRzljxHOtHrNUBDSX/2E +6EGocnqczp6fV/hNtD4r9cQuNP3AXrHBzwkI4umsnNE +-> ssh-rsa 6hPx7A +Zvw2oBZweTCbDjm/246mYtzuES9+qb0NHIp1c2ins+yDqD3WWEz0clfb1zw+/QNL +5g9lKuADFhBYksMA7M+ZmixMfWFeYt/Df88qpNrXCTLzkKdM31tc2xBmcDRsaC3m +qhrUu+V45rZJAy2hmvEcizWhuOEbvIFkpWuX72FEjXPNUHECyawBC5fl9xstGGZV +jPXKt0rq7cMnmFEw/q510ApsY8ZYa1B7Oz6ySx0YBD0cLnTheqPnWAQ0apXtca4a +k6w/jd1B0nJ9rF8HotQ+HUC579GoeGhWqMPaXIAEUlM1rwxik3lW3C5eA/JqRqNq +ZFvmG7ivQ0eySBxSHmaDp/IM6joLY1k4ECi6duRepmKt+B8rPfP79XLRqtyf+oiL +9ELrXCg4je6qSZZcrWI56Ag6Hz7/Ox4hlKnGjFfSqpZnix1EF6H5MXfidztJIftb +mQEFt1sst1Z3x5x3ILjAb+8xGHoMaAQd/QKdlfqzPrF8Q7uV5xoMBEOYggjmG33L +TKxJobVpE5vXEVO68whdPTcZ+mCZc06W7+ouJOWCmSJ1sfY8sK5qKiEU/2URvzQR +vslFUJ2DgwHNY5qoHs+FmUCoBT8t4eS+3rKJWDPAF+enBD+L5z2AeRX5vFNmrlFV +5+De4ZreFd41lTSS+hTrnxCHHqbVrTVctTp3z/9cR0A +-> ssh-ed25519 Dfencg AhPbUI130CBwlCyxzxGLpQS2K7KfKfqEV/QxcSDMzBE +FBM5u2+4EhYvPlCjr/txAZ+hf1RkM7D8GuBEBm4NXyc +--- My/nXxUyWQWXzxxUF/buVxAJa1fQsChLTVq7Ccq8HP8 +rzj}&/iG7%.Az@EIlmcO9qr=ny>A/3} \ No newline at end of file diff --git a/hosts/srxgp00/services/grafana/default.nix b/hosts/srxgp00/services/grafana/default.nix new file mode 100644 index 0000000..f114c5b --- /dev/null +++ b/hosts/srxgp00/services/grafana/default.nix @@ -0,0 +1,99 @@ +{ config, ... }: +let + name = "grafana"; + domain = "metrics.srx.digital"; +in +{ + age.secrets = { + grafanaOidcSecret.file = ./oidc-secret.age; + grafanaOidcSecret.owner = name; + }; + + services = { + grafana = { + enable = true; + settings = { + analytics.reporting_enabled = false; + + server = { + inherit domain; + root_url = "https://${config.services.grafana.settings.server.domain}"; + http_port = 3003; + enforce_domain = true; + enable_gzip = true; + }; + + database = { + type = "postgres"; + url = "postgres:///${name}?host=/run/postgresql&user=${name}"; + }; + + smtp = { + enabled = true; + host = "mail.srx.digital"; + from_name = "SRX Metrics"; + from_address = "no-reply@srx.digital"; + user = "no-reply@srx.digital"; + key_file = config.age.secrets.forgejoMailerPassword.path; + startTLS_policy = "MandatoryStartTLS"; + }; + + security = { + cookie_secure = true; + disable_gravatar = true; + strict_transport_security = true; + admin_user = "service"; + }; + + "auth.generic_oauth" = { + enabled = true; + auto_login = false; + name = "OpenID"; + icon = "signin"; + allow_sign_up = true; + client_id = "metrics"; + client_secret = "$__file{${toString config.age.secrets.grafanaOidcSecret.path}}"; + scopes = "openid profile email"; + auth_url = "https://id.srx.digital/realms/srx/protocol/openid-connect/auth"; + token_url = "https://id.srx.digital/realms/srx/protocol/openid-connect/token"; + api_url = "https://id.srx.digital/realms/srx/protocol/openid-connect/userinfo"; + }; + }; + + provision.enable = true; + }; + + postgresql = { + ensureDatabases = [ name ]; + ensureUsers = [{ + inherit name; + ensureDBOwnership = true; + }]; + }; + + postgresqlBackup.databases = [ name ]; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${config.services.grafana.settings.server.domain}:443" ]; + tags.host = config.services.grafana.settings.server.domain; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${config.services.grafana.settings.server.domain}" ]; + tags.host = config.services.grafana.settings.server.domain; + interval = "10m"; + }]; + }; + }; + + services.nginx.virtualHosts."${domain}" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://${config.services.grafana.settings.server.http_addr}:${toString config.services.grafana.settings.server.http_port}"; + proxyWebsockets = true; + }; + }; +} diff --git a/hosts/srxgp00/services/grafana/oidc-secret.age b/hosts/srxgp00/services/grafana/oidc-secret.age new file mode 100644 index 0000000..6d3ee34 --- /dev/null +++ b/hosts/srxgp00/services/grafana/oidc-secret.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw C7WQ0F+OHuWXvlbxVoaAyZh1+CVIISqijYrINi6qywU +V3Kupx4Ht1qZKNwxBDBQ1i6JZBY0DYuLv6rn7EYc01Y +-> ssh-ed25519 JzjriQ LxStntQkytwa0u8nL3B7RyicbKDdCRWxeDmi8Ao0NQ4 +c52RbPkcOILVtf2SOhomRElFYEO4YKHJAWAqF0uupvc +-> ssh-rsa 6hPx7A +OKfMxzebbZAlQSgfxsryiMb9KIS7q2nlMHy4ZAyH+2+zGLK4l+FsnyAMosY5vDcF +Iw5qa1CbRijtRDg5g9jh2tDej+Q35Z+xF7r+AauCEFfEz0LDxF74wrWOp4GtxWU6 +NdQaDmlGRcibx07W1joQAruJJLuxijw0MRz4zczZ6sc72HLbBz3xE6cCub4CDv7I +QSGvMQ0cCKj/tlFRA35Ju3GlWIZaMBtRli5DSBbsjkkb+0lr2g/KxLF7nNlKb8DV +9wSRZ34DBB/cEAbKqHxnr4Dbg8qOWPuYN47KjZQf2Fp4B1TXw0EAQb0a+JTWDI+g +uM0kq26k4TjiLObo/dGXQw/70XLPSCXlquwI81a3XXWUjE2vkoq2wgTPIbcO+Zka +WesYDIbMiVMkH9CORtn/00goJjU2KWfbHp3rxQ8PVu6juXPnxJuDNAPNWmE1/mxN +TIe2QKuvomf+8oWpM428CFObPTgSvV1A1pWTRmX8CSgAzBfzgjUfuco1UrzOqM5R +qpS7YfgpoHmOGWFILwjxwgEa6/VLYajvNmxpZtF1XTkReWJsvfmcan7g9P6+kW+a +C4CRAyZ4UotJWdurcMIYhpG0AbxnOQ43uqWuXSx26rQdPZSt+DxdrnigoyqMCmFR +byiIg97v/7aRNApPjoo9LiCE3kWNhD71Z0oAxY7U7uM +-> ssh-ed25519 Dfencg dTb8RftZcE9uEQfKul4jVnO2lHlLPigN4U8PAYHEcBk +bTFhBh7Rw7grDwXnZSuol/pppLMolAxafYVdNVELxHg +--- HTwqUOKnllUy3ADExAh6DdIHGj9dCMRBHEIIxRE7f0g +-ؗo$JUw|x";yJ !B;SzDv+J%ufEq%u( \ No newline at end of file diff --git a/hosts/srxgp00/services/hedgedoc/default.nix b/hosts/srxgp00/services/hedgedoc/default.nix new file mode 100644 index 0000000..f625f48 --- /dev/null +++ b/hosts/srxgp00/services/hedgedoc/default.nix @@ -0,0 +1,97 @@ +{ config, ... }: +{ + age.secrets.hedgedocEnvironment = { + file = ./environment.age; + owner = "hedgedoc"; + }; + + services = { + hedgedoc = { + enable = true; + environmentFile = config.age.secrets.hedgedocEnvironment.path; + + settings = { + domain = "pad.srx.digital"; + host = "127.0.0.1"; + port = 3005; + + allowAnonymous = true; + allowAnonymousEdits = true; + allowEmailRegister = true; + allowFreeURL = true; + allowGravatar = false; + + enableStatsAp = true; + hsts.enable = true; + protocolUseSSL = true; + useCDN = false; + + csp = { + enable = true; + upgradeInsecureRequest = "auto"; + addDefaults = true; + allowFraming = false; + allowPDFEmbed = false; + }; + + db = { + database = "hedgedoc"; + dialect = "postgres"; + host = "/run/postgresql"; + }; + + oauth2 = { + baseURL = "https://pad.srx.dev"; + userProfileURL = "https://id.srx.digital/realms/srx/protocol/openid-connect/userinfo"; + userProfileUsernameAttr = "preferred_username"; + userProfileDisplayNameAttr = "name"; + userProfileEmailAttr = "email"; + tokenURL = "https://id.srx.digital/realms/srx/protocol/openid-connect/token"; + authorizationURL = "https://id.srx.digital/realms/srx/protocol/openid-connect/auth"; + scope = "openid email profile roles"; + clientID = "pad"; + clientSecret = "$CMD_OAUTH2_CLIENT_SECRET"; + }; + }; + }; + + postgresql = { + ensureDatabases = [ config.services.hedgedoc.settings.db.database ]; + ensureUsers = [{ + name = config.services.hedgedoc.settings.db.database; + ensureDBOwnership = true; + }]; + }; + + postgresqlBackup.databases = [ config.services.hedgedoc.settings.db.database ]; + + nginx.virtualHosts."${toString config.services.hedgedoc.settings.domain}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = + "http://${config.services.hedgedoc.settings.host}:${toString config.services.hedgedoc.settings.port}"; + }; + + prometheus.scrapeConfigs = [{ + job_name = "hedgedoc"; + scrape_interval = "60s"; + metrics_path = "/metrics"; + scheme = "http"; + static_configs = [{ targets = [ "${config.services.hedgedoc.settings.host}:${toString config.services.hedgedoc.settings.port}" ]; }]; + }]; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${config.services.hedgedoc.settings.domain}:443" ]; + tags.host = config.services.hedgedoc.settings.domain; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${config.services.hedgedoc.settings.domain}" ]; + tags.host = config.services.hedgedoc.settings.domain; + interval = "10m"; + }]; + }; + }; +} diff --git a/hosts/srxgp00/services/hedgedoc/environment.age b/hosts/srxgp00/services/hedgedoc/environment.age new file mode 100644 index 0000000..3be50b3 Binary files /dev/null and b/hosts/srxgp00/services/hedgedoc/environment.age differ diff --git a/hosts/srxgp00/services/hydra/default.nix b/hosts/srxgp00/services/hydra/default.nix new file mode 100644 index 0000000..5f2e2d3 --- /dev/null +++ b/hosts/srxgp00/services/hydra/default.nix @@ -0,0 +1,209 @@ +{ lib, pkgs, config, ... }: +let + host = { + hydra = "build.nix.srx.digital"; + cache = "cache.nix.srx.digital"; + }; + job_name = "hydra"; + listenHost = "127.0.0.1"; + s3 = { + host = "s3.srx.digital"; + bucket = "nix-cache"; + region = "eu-central-1"; + scheme = "https"; + }; + metrics = { + notify = 9161; + runner = 9162; + }; +in +{ + age.secrets = { + hydra-env-secret = { + file = ./secrets.age; + group = "hydra"; + mode = "0440"; + }; + hydra-private-key = { + file = ./private-key.age; + group = "hydra"; + mode = "0440"; + }; + }; + + nix = { + settings = { + allowed-uris = [ + "github:" + "gitlab:" + "https:" + "git+https:" + "git+ssh:" + ]; + + trusted-users = [ + "hydra" + "hydra-evaluator" + "hydra-queue-runner" + ]; + + allowed-users = [ "hydra-www" ]; + builders-use-substitutes = true; + secret-key-files = config.age.secrets.hydra-private-key.path; + }; + + buildMachines = [{ + hostName = "localhost"; + sshUser = "hydra-queue-runner"; + systems = [ "x86_64-linux" "aarch64-linux" ]; + supportedFeatures = [ "kvm" "nixos-test" "big-parallel" "benchmark" ]; + maxJobs = 8; + }]; + }; + + systemd.services = { + hydra-server.path = [ pkgs.msmtp ]; + hydra-queue-runner = { + path = [ pkgs.msmtp ]; + serviceConfig = { + EnvironmentFile = config.age.secrets.hydra-env-secret.path; + LimitNOFILE = 65535; + }; + restartIfChanged = false; + wantedBy = lib.mkForce [ ]; + requires = lib.mkForce [ ]; + }; + hydra-notify = { + path = [ pkgs.msmtp ]; + serviceConfig.EnvironmentFile = config.age.secrets.hydra-env-secret.path; + }; + hydra-evaluator.serviceConfig.EnvironmentFile = config.age.secrets.hydra-env-secret.path; + }; + + services = { + hydra = { + enable = true; + inherit listenHost; + hydraURL = "https://${host.hydra}"; + logo = pkgs.fetchurl { + url = "https://code.srx.digital/avatars/af0c14fc152841cfdcbe4ab098278c35d6fab7cfb236a9744c19cd299d45ef5d"; + hash = "sha256-mEpreI0azCqPMA3jGT4V5FJN0e94nFTMAIzP+HfufCQ="; + }; + notificationSender = "no-reply@srx.digital"; + smtpHost = "mail.srx.digital"; + useSubstitutes = true; + extraConfig = '' + email_notification = 1 + + max_db_connections = 350 + max_concurrent_evals = 1 + + + timeout = ${toString (60 * 60)} + + + + cache_size = 32m + + + + + listen_address = ${config.services.hydra.listenHost} + port = ${toString metrics.notify} + + + + queue_runner_metrics_address = ${config.services.hydra.listenHost}:${toString metrics.runner} + + store_uri = s3://${s3.bucket}?endpoint=${s3.host}®ion=${s3.region}&secret-key=${config.age.secrets.hydra-private-key.path}&write-nar-listing=1&ls-compression=br&log-compression=br + binary_cache_public_uri = https://${host.cache} + + upload_logs_to_binary_cache = true + compress_build_logs = false + + max_output_size = ${toString (10 * 1024 * 1024 * 1024)} + ''; + }; + + nginx.virtualHosts = { + "${host.hydra}" = { + forceSSL = true; + enableACME = true; + locations = { + "/".proxyPass = "http://${config.services.hydra.listenHost}:${toString config.services.hydra.port}"; + "/static/".alias = "${config.services.hydra.package}/libexec/hydra/root/static/"; + }; + }; + + "${host.cache}" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost${config.services.minio.listenAddress}/${s3.bucket}/"; + extraConfig = '' + proxy_set_header Connection ""; + chunked_transfer_encoding off; + ''; + }; + extraConfig = '' + ignore_invalid_headers off; + client_max_body_size 0; + proxy_buffering off; + ''; + }; + }; + + postgresqlBackup.databases = lib.optionals config.services.hydra.enable [ job_name ]; + + prometheus.scrapeConfigs = [ + { + job_name = "hydra"; + metrics_path = "/prometheus"; + scheme = "https"; + static_configs = [{ targets = [ "${host.hydra}:443" ]; }]; + } + { + job_name = "hydra_notify"; + metrics_path = "/metrics"; + scheme = "http"; + static_configs = [ + { targets = [ "${config.services.hydra.listenHost}:${toString metrics.notify}" ]; } + ]; + } + { + job_name = "hydra_queue_runner"; + metrics_path = "/metrics"; + scheme = "http"; + static_configs = [ + { targets = [ "${config.services.hydra.listenHost}:${toString metrics.runner}" ]; } + ]; + } + { + job_name = "hydra-webserver"; + metrics_path = "/metrics"; + scheme = "http"; + static_configs = [{ + targets = [ "${config.services.hydra.listenHost}:${toString config.services.hydra.port}" ]; + }]; + } + ]; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host.hydra}:443" ]; + tags.host = host.hydra; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host.hydra}" ]; + tags.host = host.hydra; + interval = "10m"; + }]; + }; + }; + + users.users.hydra-queue-runner.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPtiFwECxheHv30ELg61uS6Ixc0QAIdG26BGl5f2+RsJ hydra-queue-runner@srxgp00" + ]; +} diff --git a/hosts/srxgp00/services/hydra/private-key.age b/hosts/srxgp00/services/hydra/private-key.age new file mode 100644 index 0000000..747fbd7 --- /dev/null +++ b/hosts/srxgp00/services/hydra/private-key.age @@ -0,0 +1,24 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw n3Z3q336cK7bhfkYbK4QN2FW15bHXSzEBZ2yMPE16Qs +3xhoh7ajmNN4JVp8FFUeFvFysSRsxW7uwvlecvAeLA0 +-> ssh-ed25519 JzjriQ I+ZfvxfUK3bxFHDjqPr1aRNNVRK4wT9EGZSrPNZzWT4 +sLyL1zzVQBfvt9+WjqBXtiDKOsEpzzh9t0I0AfOx7dk +-> ssh-rsa 6hPx7A +WW4cpr4fyH58Z1PoM0S/O9sHATvN0r043jj7WLd6nhff0LBurAh3x1QVBeWOpAz5 +dGekgdxXql3R76fNyUVZeC1pKRKrZD4QI3Ovbcb3VFYLvwuAIf93gTARxJrMpozc +KZ5+jBX7tw0cwyvAcZBY5pMQmJOFsMX2qmh06rufX4SpvPeh7I3FtFS8MOGY4hVW +mhMxuyryT9DhKXT0ck06AAjcr5x4pZP8CjbVZipjQ0HXsg44Lsqn4XQTI2W2VN7K +8bSml5nJ9oyeKBKKJccdlq7ydMqCKyRS1SEvET4S6tbNnuAW4KYKXfc6FvoQSJ/X +Yc+HnnbivSCTfsbA2AW0i1n3NuXpA2Oxo+z3BDXemX6mmbqKFgjxVyl3rUtAakAW +BsjpVKFnsJ1cbIrt0uyup7WQ+DnHKf0b/zqOCKvmBj04kQfEvcSPhI/N3e8bqtDr +X9D5ej7f5LbH/0NMNMAIVQuVqYRZ9AkA0ewautyc8KnE+lmW/5rDR0FwtC0ZupK0 +RFevUeHg1p6bWqtiF9aFn3TAR9M2lCKK8IIo5k5oc07uKdQpUdxTtqdw7ABRM0m7 +TvbxYHwYMfSNucKWpW9grJDMcczfdtivdlnI61m5B1VDG7FmavmqqCS5GCCZE+bO +iOGFDBO+zk3xuU0KBy9/xfr2SK1eDTKYD4VREa8tAl0 +-> ssh-ed25519 Dfencg nTEW+fbvaSeUOA3OekA416m8e+FNTY+BD1qImGj7JRw +Hz5/IOgsOjy4l1V2ajavDlx1cNlO6HQ19y1WurUcYR0 +--- 49LYxbN12cDPp4KAg6tlytMyYHjulnZY1NFp9QdWq5E +6EQ҈*[ED +^?KàxaxPkڬE4/ R)5ޯ].n=Dk@M +m +؍@"|V\[98e1x|bj~5N"º35D}qץ \ No newline at end of file diff --git a/hosts/srxgp00/services/hydra/secrets.age b/hosts/srxgp00/services/hydra/secrets.age new file mode 100644 index 0000000..2ab6f43 Binary files /dev/null and b/hosts/srxgp00/services/hydra/secrets.age differ diff --git a/hosts/srxgp00/services/influxdb/default.nix b/hosts/srxgp00/services/influxdb/default.nix new file mode 100644 index 0000000..1b4e9e8 --- /dev/null +++ b/hosts/srxgp00/services/influxdb/default.nix @@ -0,0 +1,43 @@ +{ pkgs, config, ... }: +let + host = "tsdb.srx.digital"; +in +{ + environment.systemPackages = with pkgs; [ influxdb2-cli ]; + + services = { + influxdb2 = { + enable = true; + settings = { + reporting-disabled = true; + http-bind-address = "127.0.0.1:8086"; + }; + }; + + grafana.provision.datasources.settings.datasources = [{ + type = "influxdb"; + name = "influxdb"; + url = "http://${config.services.influxdb2.settings.http-bind-address}"; + }]; + + nginx.virtualHosts."${host}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://${config.services.influxdb2.settings.http-bind-address}"; + }; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; + }; +} diff --git a/hosts/srxgp00/services/jellyfin/default.nix b/hosts/srxgp00/services/jellyfin/default.nix new file mode 100644 index 0000000..bd083a0 --- /dev/null +++ b/hosts/srxgp00/services/jellyfin/default.nix @@ -0,0 +1,25 @@ +let + host = "media.srx.digital"; + port = 8096; +in +{ + services.nginx.virtualHosts."${toString host}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://srxnas00.vpn.srx.dev:${toString port}"; + }; + + services.telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; +} diff --git a/hosts/srxgp00/services/keycloak/databasePassword.age b/hosts/srxgp00/services/keycloak/databasePassword.age new file mode 100644 index 0000000..9d35e36 --- /dev/null +++ b/hosts/srxgp00/services/keycloak/databasePassword.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw OBYvz2ORZFwdIvca0uIXDXWdpfRiaFp/5G7syyGrcyU +vxYdkAiCVBfqzeqKfLFI9PsuDo7DhCCE5b/igNePfPk +-> ssh-ed25519 JzjriQ Dsy0LuOggSmN77ZPMWFzY6xOGi88uiN2prxrUeF/lW0 +BoLCPpQSKQM/GE+oAipiKp1n9Q3ChOXQIdGlnhGof80 +-> ssh-rsa 6hPx7A +npus090BSB1GRvneHlBqi1QZtPCIOTN+QMKCXSitoDYpyh7sJu5qGNmFrRE/g9+I +Iwoj+LNiV95YZVLl2Ta3/AiLXNOzcHp/JixDmOfn8cT3NrT3TF6kXLWBodqHIT3b +4tWsUn08rwzG3lrNKabudB/63Qpn8Hm1AzNPhQaBLs2gfHTGsKJluuqDggM/i/B0 +t2DkTvYNLvyKkYl4SFV2IYN+QlL0USuNiLsMUObbFpSl1Djh1oI75sibFMywkhbM +iy1/R04JvEXSmsZSVr9OU/q0dKR1w2b1W3rq8018EB9UVvbpD7NkmNqO1UhmECtM +HM/e+gslGHdkZTZuAYx/cUayA4QlWUOiM9KseoXRYjhiEEJ1q/yTst4AkmZIb2bF +ZG5D2WlPF/wP7Y/hwZv4kV76390DRSP8qyetWEKyM5G//DS1S44T6g4FXa1HtOLV +SkuixhTtszX3NYi1/0GiUhKujKicADeL14q0TroKI49ScqZEfYYo2yBunRVqxltQ +dV50wegZRHCAALGYVuC7r33Ke1Y6zLmThZYpaOc5OwpiLHGFNsYFe8VOLw8Z6yz/ +YkAZncDH/ej20YzKIWF7A6L32shw2mp8anCxu3i+uguLwLBvrC+BAGgEPfgyRKB5 +BXxmupzmXyygijXpHdVlDQzGIFXVVKQMyeSLABSaz58 +-> ssh-ed25519 Dfencg D/NzwQbbP1VMl11ezv7RLCZobWPd2jocy/Xx/GG7fQM +gOAksl62iBAesCjnKYCEjaYUCNEnhnpvbwjTthb/YsU +--- uWbkqQse85XYIZmig8Sj9Qthf4bHtSmWorvKnFFonO0 +s{ KRup*.A:8"}J va1Wx/,'Hc_~^ 8 \ No newline at end of file diff --git a/hosts/srxgp00/services/keycloak/default.nix b/hosts/srxgp00/services/keycloak/default.nix new file mode 100644 index 0000000..ae69055 --- /dev/null +++ b/hosts/srxgp00/services/keycloak/default.nix @@ -0,0 +1,48 @@ +{ config, ... }: +{ + age.secrets.keycloakDatabasePassword.file = ./databasePassword.age; + + services = { + keycloak = { + enable = true; + database.passwordFile = config.age.secrets.keycloakDatabasePassword.path; + settings = { + hostname = "id.srx.digital"; + proxy = "edge"; + http-host = "127.0.0.1"; + http-port = 8787; + hostname-strict-backchannel = true; + metrics-enabled = true; + }; + }; + + postgresqlBackup.databases = [ config.services.keycloak.database.name ]; + + nginx.virtualHosts."${config.services.keycloak.settings.hostname}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://${config.services.keycloak.settings.http-host}:${toString config.services.keycloak.settings.http-port}"; + }; + + prometheus.scrapeConfigs = [{ + job_name = "keycloak"; + static_configs = [{ + targets = [ "${config.services.keycloak.settings.http-host}:${toString config.services.keycloak.settings.http-port}" ]; + }]; + }]; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${config.services.keycloak.settings.hostname}:443" ]; + tags.host = config.services.keycloak.settings.hostname; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${config.services.keycloak.settings.hostname}" ]; + tags.host = config.services.keycloak.settings.hostname; + interval = "10m"; + }]; + }; + }; +} diff --git a/hosts/srxgp00/services/mailserver/accounts.nix b/hosts/srxgp00/services/mailserver/accounts.nix new file mode 100644 index 0000000..bc5c215 --- /dev/null +++ b/hosts/srxgp00/services/mailserver/accounts.nix @@ -0,0 +1,10 @@ +{ + age.secrets = { + # nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' + mailbox-Oom7oh.file = ./mailbox-Oom7oh.age; + mailbox-ugai0U.file = ./mailbox-ugai0U.age; + mailbox-Osoo5u.file = ./mailbox-Osoo5u.age; + mailbox-Ies6sh.file = ./mailbox-Ies6sh.age; + mailbox-xaev9B.file = ./mailbox-xaev9B.age; + }; +} diff --git a/hosts/srxgp00/services/mailserver/autoconfig.nix b/hosts/srxgp00/services/mailserver/autoconfig.nix new file mode 100644 index 0000000..b526746 --- /dev/null +++ b/hosts/srxgp00/services/mailserver/autoconfig.nix @@ -0,0 +1,31 @@ +{ config, ... }: +let + domains = { + tld = "srx.digital"; + mail = "mail.${domains.tld}"; + web = "autoconfig.${domains.tld}"; + }; +in +{ + services.go-autoconfig = { + enable = true; + settings = { + service_addr = "127.0.0.1:1327"; + domain = "${domains.tld}"; + imap = { + server = "${domains.mail}"; + port = 993; + }; + smtp = { + server = "${domains.mail}"; + port = 465; + }; + }; + }; + + services.nginx.virtualHosts."${domains.web}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://${config.services.go-autoconfig.settings.service_addr}"; + }; +} diff --git a/hosts/srxgp00/services/mailserver/default.nix b/hosts/srxgp00/services/mailserver/default.nix new file mode 100644 index 0000000..38042da --- /dev/null +++ b/hosts/srxgp00/services/mailserver/default.nix @@ -0,0 +1,171 @@ +{ lib, config, inputs, ... }: +let + host = "mail.srx.digital"; +in +{ + imports = with inputs; [ + srx-nixos-shadow.nixosModules.mail + simple-nixos-mailserver.nixosModule + + ./accounts.nix + ./autoconfig.nix + ./webclient.nix + # ./dmarc.nix + ]; + + mailserver = { + # https://nixos-mailserver.readthedocs.io/en/latest/options.html + enable = true; + fqdn = "${host}"; + + domains = [ + "srx.dev" + "srx.digital" + "sourceindex.de" + "nix-hamburg.de" + ]; + + enableImap = false; + enablePop3 = false; + enablePop3Ssl = true; + + enableManageSieve = lib.mkForce true; + localDnsResolver = false; + + messageSizeLimit = 52428800; + + sieveDirectory = "/var/lib/sieve"; + mailDirectory = "/var/lib/vmail"; + dkimKeyDirectory = "/var/lib/dkim"; + certificateScheme = "acme-nginx"; + + monitoring.enable = lib.mkForce false; + + backup = { + enable = true; + snapshotRoot = "/var/backup/mail"; + }; + + fullTextSearch = { + enable = true; + autoIndex = true; + indexAttachments = true; + enforced = "yes"; + autoIndexExclude = [ + "\\Trash" + "\\Spam" + "\\Junk" + ]; + memoryLimit = 20480; + }; + + policydSPFExtraConfig = '' + skip_addresses = 10.0.0.0/16,127.0.0.0/8,::ffff:,::1 + ''; + }; + + services = { + dovecot2 = { + mailPlugins.globally.enable = [ "old_stats" ]; + extraConfig = '' + plugin { + old_stats_refresh = 30 secs + old_stats_track_cmds = yes + } + + service old-stats { + unix_listener old-stats { + user = ${config.services.prometheus.exporters.dovecot.user} + group = ${config.services.prometheus.exporters.dovecot.group} + mode = 0660 + } + + fifo_listener old-stats-mail { + mode = 0660 + user = ${config.services.dovecot2.user} + group = ${config.services.dovecot2.group} + } + + fifo_listener old-stats-user { + mode = 0660 + user = ${config.services.dovecot2.user} + group = ${config.services.dovecot2.group} + } + } + + metric imap_select_no { + filter = event=imap_command_finished AND cmd_name=SELECT AND tagged_reply_state=NO + } + + metric imap_select_no_notfound { + filter = event=imap_command_finished AND cmd_name=SELECT AND tagged_reply="NO*Mailbox doesn't exist:*" + } + + metric storage_http_gets { + filter = event=http_request_finished AND category=storage AND method=get + } + + metric imap_command { + filter = event=imap_command_finished + group_by = cmd_name tagged_reply_state + } + + metric push_notifications { + filter = event=push_notification_finished + } + ''; + }; + + fail2ban = { + enable = true; + jails = { + dovecot = '' + enabled = true + filter = dovecot[mode=aggressive] + maxretry = 5 + ''; + + postfix = '' + enabled = true + filter = postfix + maxretry = 5 + ''; + + postfix-sasl = '' + enabled = true + filter = postfix[mode=auth] + maxretry = 5 + ''; + }; + }; + + prometheus = { + exporters = { + postfix.enable = true; + dovecot = { + enable = true; + socketPath = "/var/run/dovecot2/old-stats"; + }; + }; + + scrapeConfigs = [ + { + job_name = "postfix"; + scrape_interval = "60s"; + metrics_path = "/metrics"; + static_configs = [ + { targets = [ "localhost:${toString config.services.prometheus.exporters.postfix.port}" ]; } + ]; + } + { + job_name = "dovecot"; + scrape_interval = "60s"; + metrics_path = "/metrics"; + static_configs = [ + { targets = [ "localhost:${toString config.services.prometheus.exporters.dovecot.port}" ]; } + ]; + } + ]; + }; + }; +} diff --git a/hosts/srxgp00/services/mailserver/dmarc.nix b/hosts/srxgp00/services/mailserver/dmarc.nix new file mode 100644 index 0000000..b4e7a50 --- /dev/null +++ b/hosts/srxgp00/services/mailserver/dmarc.nix @@ -0,0 +1,34 @@ +{ config, ... }: +{ + age.secrets = { + mailBoxDmarc.file = ./mailbox-dmarc.age; + mailBoxDmarcClient = { + file = ./mailbox-dmarc-client.age; + owner = config.services.prometheus.exporters.dmarc.user; + }; + }; + + mailserver.loginAccounts."dmarc@srx.digital".hashedPasswordFile = + config.age.secrets.mailBoxDmarc.path; + + services.prometheus = { + exporters.dmarc = { + enable = true; + imap = { + host = "mail.srx.digital"; + username = "dmarc@srx.digital"; + passwordFile = config.age.secrets.mailBoxDmarcClient.path; + }; + }; + scrapeConfigs = [{ + job_name = "dmarc"; + scrape_interval = "60s"; + metrics_path = "/metrics"; + static_configs = [{ + targets = [ + "${config.services.prometheus.exporters.dmarc.listenAddress}:${toString config.services.prometheus.exporters.dmarc.port}" + ]; + }]; + }]; + }; +} diff --git a/hosts/srxgp00/services/mailserver/ldap-bind-secret.age b/hosts/srxgp00/services/mailserver/ldap-bind-secret.age new file mode 100644 index 0000000..b8ace9a --- /dev/null +++ b/hosts/srxgp00/services/mailserver/ldap-bind-secret.age @@ -0,0 +1,30 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpEcERxdyBEYzFJ +UnhtcnNmREx5ZkVab05PY25qcUZZYW9oaXNPTmhqWW1PcXJIQVNvClVYQWIwYUgz +TGxWYUNBcXBkMmxBTExRZmhaalJjbjJReUdDZ1FWMThxZEkKLT4gc3NoLWVkMjU1 +MTkgSnpqcmlRIEFwU3NtQzRnODVENCtHblhLTW15WnFHSHFPNVI4em9MbG42cFlT +MnlveVkKd0tOWlpIK2lWQkJqa1BVOW44bWQvRy9mRjNUdzUyK3FZZkhNVVg5ZEZY +UQotPiBzc2gtcnNhIDZoUHg3QQp3VUNpNG0zQ0ozZFdFME05Yml2WWxDbTJTSmVS +VFJoa0ZOd2FDcFRxbE1UaTRVcWFWRG5MYktrVk5pNHMzZ3hNCmpOb2dNcnYrUUNO +WUZnYUVhbzcxa1FvVnU4aU5DYTVWaDF4Z00yY1JRTWlabDlvankrdFpnVlVNZGwz +a2R6SFgKcHZsMXphdGQyMjBWOXlSekJBNWpqWExSSy8wbW1wMUJBaTBJZExUOWhr +aUpHVTlBdVIxaTE1TXBzVW9KdjFWegpBTmQ2WklTOEVPNCtWNmVuNVhPV2UzOCs0 +c0RGbDBrYUFFVXZrUVNxQnFsVDV0Nnpib1pPTE1KeFZhMm1TQStxCjRsc21qZURp +MS9hbCtxODFQVE9IaUsvVjFzbEdmYjNYMUtuQXZYemRnWDFRYlhPdldpVFFpMHU5 +bXdhMENiYUcKV2wrQXltaTJZZm1vVlUzQmJmWjljZi9uQXZwU1VydU1paWdVQkVK +SWNNU2VnMkhUUi9xbWljajk3eFFPcUhBegpGaE1qb2poQU4rNEtZQnNGR0F4TC9Q +V29ORzNXNm9QNTdQemFQUXVCYXd6QTl4T0J4UlVuNU5Ga2drUE9KZllxClYrOXVF +NGJEUGlLaktMQStGcTQ1ZzhQU21pazhrMTdhOTltWlp0aWp5VllDMjc3UTR5ZUcy +ZncyQS9xZ004ekEKcG5oNGdZbTdjMjdWUFdBYnRsRWtiNCtoV2p5OWNNU2xHekJC +ODRkYmNKdTQxNDQ4NURmd2pXSkFGaW9hdXNBbQoxMHFta28vaTZDVDkwMWRHQmVK +WWVqbHVuOEJSRkVhTk5kbmdQeW5TTWRQQys5RVlOV0F2WjdzNHhUcU9xSklUCjdJ +NGhEVzdEWjZYdTNjbEZSdUJYTGFBRlNzc2VVOFNPMWhxN3MzOC9BM2cKLT4gc3No +LWVkMjU1MTkgUUF0anFRIEFWRVFkZ2ViRmRMTUFZWFJsZVlIcEJPZE1reFhjOUdV +d1BwTDRkdnpMbmcKNU5Bem55Q1AzODRWNVplQ2xmTnZybVIyK2ZtTHRzcHRDdURO +VmdhQmxJQQotPiBPbEJjKXBMLWdyZWFzZSBIOyFOPiAiMkRuIDJwcSB6b0E2c3E4 +CjROcnlyQVc2enhzUHlBOUtyNk5OL3FIbkx6VE5JUW0weEpjbjlrT1lxMG91ZmRl +OHNQTThHcnFxVnZOSENXUXIKc2s2cWc0NAotLS0gODhIUjFxMHV6K2tMNGlYU1cy +K214VmpGVytBNzFxVU1xTWlKQkxMV253VQoywXcrQeeo8fLE17veSy7lDzOahKD0 +oY0GUlps1e6YVBXiFyZpo9NM/DnnNRgFsC3uMBHRIe3c19kwaVPFQTaE2nG99jrp +iLnw +-----END AGE ENCRYPTED FILE----- diff --git a/hosts/srxgp00/services/mailserver/ldap-config-secret.age b/hosts/srxgp00/services/mailserver/ldap-config-secret.age new file mode 100644 index 0000000..55628cf --- /dev/null +++ b/hosts/srxgp00/services/mailserver/ldap-config-secret.age @@ -0,0 +1,29 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpEcERxdyAxUVA0 +MVYySnhnUzI0YnI1eForZko0L2VKSWNHd1lQQzNPYkE3Y2p1alVBCkRMSTNxd3RF +NFZob2loa2dIUkFQclV0VU1YUU5qNUx5OWczYVJzbmx4OE0KLT4gc3NoLWVkMjU1 +MTkgSnpqcmlRIEZid2hWMi9yengyZUZtN0U5VnNVbE51UExpN2pQSlMyMHc2WElV +Qm9JU00KYXJaMy8vY0pKR0kraXY0QVhZdFZCWjJjR0p5b04raGNuLzVXVExrV2ZB +cwotPiBzc2gtcnNhIDZoUHg3QQoxUmZqbjRBd2IxQkRJZUZTcXZqNDZScTh6NGlW +ZE42R3A0NEc0UjdhWXd2UEpFekY2aXZ6K29jWDNpNlp5dExXCjJ0ejZlelRjRGcx +WjlvOUVxU1JBN2lUMFRGWkFZUUtHc1JOaXlpTDZSZ3B3NHg1MThESG5aQUVIN29H +Z1lUaVIKVzZYV1A4YjI5bTEzd0E3SWtmcnZkRnQzWTJ2d2pmLzVVZW1wNWlZY3Ur +eWhPMVB1MzJUNEVvY1JEUXAzMlA3RQp3RVJiQnZnZ1lPSFcrSTllM1ZDUnB0RS84 +Wm8zTFVzYU92S1JJZHdUN3ArSGNzc0lldUJydVdmMTNqNGd1Y2lXCmFpWEk5d1VS +enA2d3J6TUg5M2FDQU1nRWhVd21kNWRRZVpuTGo4YUk3Q0xXbVhYK2dnT240dnov +K0RUcG1JRXcKbnVBdzFrQWVlQWpyMFhQNmRvekhvRXpzWE9PellNaTEwdDNSVFZF +cWJjNVdWUTIxSWdKckpGdEpBbjZFNm5IZApOcCtZZk9UbUg5ZUNiQy9SN0JHeXQ4 +WHlVemlsbERYcDY2VjQyYzJ6UW0wMHZMM2dpaFAvbHBjanN4SXh4NGNxCmhpRWU3 +d3YzaktZL2E4UGE0bnVkbUNpYUYzYnZMR1dVZzJwcGFkUm9MRnNoS055QjZYNEFs +aC9aWUtRVCtpN2UKSEZ1VkpCL0dyMXJQNTlpdW9qaEc4SjlnOGY3MnNIcFEvdGJL +RlNvU0xndk8vSVVDeVNyUlY0amw3Ukpzc1JBNQpOeWY2Z0grTWtiTE5VNG5EdWlS +Vk03OFRiSnlsSHB3Qkg0Q1NMMzR3R1JXSElvakVqblNlR3JtWjJubnQxd0haCndw +bDJpZVJUTW9aWURzTW1TeVFnaXZsOHN1cXpGLzNXTmJ1VjFWNXFGTWsKLT4gc3No +LWVkMjU1MTkgUUF0anFRIFhjdmZTb3NUZVY0MWZMbGU1U0hweEFHMWFxKzRwdWgx +bG1sc3JoLzZZbVEKVWhnR1RlL1lVWGNOZnYwRXdSN28yMVY2cG0vcFd0UlRsVW81 +UFJrL29YOAotPiBxLWdyZWFzZSBVQGVyICdDNVloNjRsIHNqXzI7JQpaaGowT2NP +YzNoZUFPZTF2clQ3VnExVnRUTkpmVXhKTm5nSGdmRUVCCi0tLSBYY0RsalNZRlMx +RFQ3RzdjOVpGRTJ6MDByU1ZtMDNJWXI4Q1JLSGQxMVhjCma15P6/4SfGzxHhqxMm +mseZxfDqWy6KgTPOIcxGbU3itwueFJgFwYVWHynlx7TAfSJZFVNMYQycE/KeoVE9 +TgP8/rHeWD66IaQ= +-----END AGE ENCRYPTED FILE----- diff --git a/hosts/srxgp00/services/mailserver/mailbox-Ies6sh.age b/hosts/srxgp00/services/mailserver/mailbox-Ies6sh.age new file mode 100644 index 0000000..12a2026 --- /dev/null +++ b/hosts/srxgp00/services/mailserver/mailbox-Ies6sh.age @@ -0,0 +1,22 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw IqUKNln5TWRzlKY6CHjia6VuDYlMpjL+D3NKHI+fHjQ +EODXEkWjzP68TC9/JOQ3piORAEECNnYlH71mLUmbHZc +-> ssh-ed25519 JzjriQ 2InSkL416EOGoG70EBVjFSwNWwS6Vx3uatbERPipmng +6f5XnAluFpTpqxPWu/O6DQzvkcfI/ipXJgk3gc8oB38 +-> ssh-rsa 6hPx7A +I5U3iYOzM33IXleaRta1ONJKwbh50DLr+65ad8G8XiZ3AMn5e5zhlxKVzXJ9G84V +iNHd1mOn+fdOGXJNs5ze60TyJaVlG/E1uNE7yj+yu9D99KZB7LIh6a+OcO6PYdYQ +339QHQ90hs1nlt9oKc7Z6tHZh4o4ROOPSP0FleB4c1N5l8OXD8NzLbUtiTKfMdTd +4vRQUcgzhe8giqPRl0Qy8arCijS43dCUBNeQPK1MqJXsl76QLaJJDRQ7ouOV918K ++JNLMhEwM9O6berEp++y0VcED3vBNkfbijJhKH0ogE4/kKJhxS4YQQKThLzxjUsd +2OSFlan+9lahEGo0vqFAn5rDpsTEL16RLKYGg1Z234ZZ3ukLqyi4eimfT8Os/PE9 +QgCDJ+PkR+z8ZMh38SICNiHoFZXW9ziVXlxtojtHzenHkdi/3NKpsjwFlmFs1eRs +fM5T2Vgyucf5WgBeoPa3wr5MJvnc3KtcTZdB4z/kn26QLQCCMJNC6+6gdg4CZHJj +bSgtzmNwjdsiUg3MNFcmY3u5R4eEnMZFK11XP9/IxCJOYtVymKca6iihDZi9OGa1 +WZuSfuHDcxAbcWnaO5b6pSjr3QbrFPOdIdDFzODjjet2843XN7/ToNpsJX3rd50m +ngWwO+amNj182WBy+PWK4FLBYom0hONyq0PJjVqK8ko +-> ssh-ed25519 Dfencg 7Gqsm3fValaJV9P60O+tC7dRHnubFWt3S+M806QGqRQ +VRRS9cdXvEYk1T7eIB9/KDfjO/7YrnPsmiHiYEhV7RU +--- uooLSbExMNA6pRi4MxSHNOS8ziNYp/19fkd1jdIsZjA +V +݉x.ΕɎ$,ܠgT:`_Gޏh?, Q"D0 1oriMƆ bgۻRoΑ \ No newline at end of file diff --git a/hosts/srxgp00/services/mailserver/mailbox-Oom7oh.age b/hosts/srxgp00/services/mailserver/mailbox-Oom7oh.age new file mode 100644 index 0000000..4e98767 --- /dev/null +++ b/hosts/srxgp00/services/mailserver/mailbox-Oom7oh.age @@ -0,0 +1,22 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw AsYcnmBOaBvP0KN6Fn5eHCY+LH+OtOAS/h9n/QzVFCM +Ev5qsh+Eqd8nSax1BU0vOpk/gw1XUDz306hzoFDpick +-> ssh-ed25519 JzjriQ BeuJoHDNgji4cWsv7iSJFiRVnI0jyPiO96O6Nt2ijEo +eilK7JsfMKkEO1RrjeSPWeGjn1a5GN3OxTN/Vypx+Ng +-> ssh-rsa 6hPx7A +SKD7bmzmJeqjJthm9Q++I+UHfcYWiBNSksF7N0agLso6w5t2EZ41TxY6WyJyeLA7 +3oAWHoHlwrFa2GCnazP3Mf4d7l04zJwLNHeok2D7P4q6r0a0saN1z01GHP4UbBnX +fiMKHFWn1bzT3UjtEcbo2RKVbWNsiwFXff5wZBzM2V/buTG9ipV9lf1qsdaCeA2W +MAEtIBqh5LdmacHR2bJkqzFwo4cCOHdYDs5HWxS8iJKXQ0K+He+pFv2fI1wuaLnM +cWC79MvSwAHy0KEbDfbBlUZPVPC7Bl4KInVxAKsqAOILjAAxH9fIVpIV7yGCxBew +lZZjbNYY9lL+b8YnFHKpUd/1Uh8qIJPBmkjVlAIaOT+mlwQMixJ0+nowABtyyKgm +7AoRBUlGlXpJg5xlkHLNJWx9c7Jp3q03VOHDAhR7qP93bXZbKZWVOxcOOijnF+/g +uwGTCGAAxnyTQl/mL5KYAXQCCSa+wDLalVemaToFkenwJryLTghAjvlvwvSYdgMx +t6EbgMEe+VW9XnFhrOlnuUsdC9Lpv59/eylNPu28lfSmg2bEi22b29C+bNweOwWm +9coXVF9GOk+40iC9bBKsLPPQbs+o4x9n/kYF6zCPIOtlNmFHWog63gWc1NR9Y+JH +32JK9OBkJynabaUs8LmgBosDbmfPmSZbnN9QSOKfho0 +-> ssh-ed25519 Dfencg jX/fnsqLBNa+wUpuuG9m0jCGlTg6BeylyMEGFQkFEiM +t9/eZWkxCGggy10XfvTperveQbPTthPt6mrwlO4dHn8 +--- 64kfsS5RRpZyihA0J+QFREM9cQNjULs/HA3B0BKx8zM +V*L3V7|6DX&e ~3|sO寧gϧ2c+ +WpZMN\ٷl!%ǻ&4l $5d;NA8q \ No newline at end of file diff --git a/hosts/srxgp00/services/mailserver/mailbox-Osoo5u.age b/hosts/srxgp00/services/mailserver/mailbox-Osoo5u.age new file mode 100644 index 0000000..44e26bb --- /dev/null +++ b/hosts/srxgp00/services/mailserver/mailbox-Osoo5u.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw 0ek8rx0G8dE/y32fvD2NWPNf3BeRpUDyKN6YSag9qnk +zU2szwIaM0luqkXTqjr4qb/WEi8qwIfRfWAv2RZ3Hi8 +-> ssh-ed25519 JzjriQ NAMwKbrCpOm9wIl0zcd1JP8byAU64O2/yTmsf0yG3A0 +HebNORNtGrhBE3Ujcx56li8FgJUiyw9OimyCDw9kriM +-> ssh-rsa 6hPx7A +R1OIFZEF7GSLllqP+QMVm40hCAx8uChBTN4/lKXl8QdOYQSLZH6L817yWt+UF3Vs +0Q/skWWODUDj6apdh63iypkqSbhxWVHy7XlWki3oJNBp8fmioPtmZ7UHKWxzEtil +7ZtgJ/vkbJywFa8Is0rTs+Q8thTpthn2Ezdz/SbFy9X8f3fQRn7xgYTh08p3dJrF +tecmByC9Q6Jci0Xgw4+ZtjJbjgaYAQaMuyLVT+nx2v7fn/jnIckk6JifulvSxihC +mYf5qy9zG2R0J2ikdE4V/j8dFQS5+o3OU0qPqvXhNSKNWz71qLa3zJytHD6cZEcS +CUPJLQzI3oP8hbOk+NJ0m6ZGa3p219qSiNKq/P/EoiUKzJs4EJHlHWa3VOvjg+KM +uZeFYuHSAZcAjbtK3dCa9pESrsVzb/mDIwlT1K5PcHcyT2SQbTqXNFapqFJ9DzVR +hQTbuy/uL7nTTsMuMq71K+d1T+HGquVaLjqqXCiippppYhaenLvotrT+Zgl0mpin +ds/n9G5BBuXSM6pzOs97xTxUup2j0Xq7ykr3x8Cd6kyGc25b3AVbSHVLbfQ/4U7B +X/RmfIISYwPZvEiygc3mzyzLQEeLxi2q35yfmSJOk6DdUbGsGoF4ufXT0GjKj+gN +iYiHteEqoZ+MGkyviowtCuVSD5soF2pLrdEfm3txnfw +-> ssh-ed25519 Dfencg QVprlje+Zb4bsWPvtqsmd66mMvgAavFzDZYI0MoWA2k +1OqfCxvJ8oESIN0R3yD8f3HX0b7TqmjMqEFn+Hx8q04 +--- 9ilMGkwGdMFexB4xqRnlw+Z70McoFNsAJ9bD+4FddDU +`}M)vUoڝdSnL2V[_6FpdfDps0-ˇ)NaFfLަL?!A 9 \ No newline at end of file diff --git a/hosts/srxgp00/services/mailserver/mailbox-dmarc-client.age b/hosts/srxgp00/services/mailserver/mailbox-dmarc-client.age new file mode 100644 index 0000000..fe0dcbb --- /dev/null +++ b/hosts/srxgp00/services/mailserver/mailbox-dmarc-client.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw VRdFs1jw4vLlb9+U8wQI1O4dR/d5eO01YJXsX51LsxU +h+7Ke2y2TA5MdGp4UpouKUkz3+tSY4M0fB/leuShITo +-> ssh-ed25519 JzjriQ 5ayIpvnxJVz2xjczZfawxKa6v6dY+QjB7m2YFFX/FCg +IwRDDARLTk+ecqvcaAD+s4XGDEIMb9YHV3VsVWCoxVQ +-> ssh-rsa 6hPx7A +wEQcgNdS1VWnw0uQrxBifBRuS3rYEqlPRlLYSnvWOuSv91ySpiKnG53WnRCbMWZ4 +Zjrgd5Rqzd5M3ZLebguO5OOW63kuc6ZPtJPigYBjjUIVtMlZDYLeVsx4t1RAzULO +EWTDuuK3npQ3+zkAJ172iUsFzH8CQ3HXNy3BI+SS80SddI5cx8BuPpXhL/1uv8sf +vEQ/dz7oMLX8o4Cy8vLXKM1H6mm01qcqlF2E4eXIvk9OeqnkAbr6y8NU1pY6Q8F4 +CCVdVk7CSndnGk5R0x8bEaGnLMtMrNGKwjJoO9pMFKH9Dicnw1rNNxHfz4aGHUNV +XejAzYDtKxRge/wxfpd0sL2ybOhGse1IfjlWcSYeOycJVwGoRVYyFmUGgYUsdV3o +YzVWIyP7rcG7e7rwBd5ch3JqIgMFk3tZzBTaDHqk/NlxlSQd99Foz9FAV2/rT8eG +8fqH7+i3bpukHoV3VjF7boknj8pUqynGsivy7Awb6xF/dZTeOOnjztgScpF02RWW +S23HlI9QSkeir7cSHmtSBNmjGChJ0ruWDxt+qMnttak+eyzSpn/PPJMJZy/VquJL +BlLyE/IUkvuOJ+WBf7ZcyM1MIRTS7zJFrGOX3RV+7bgrHSHc+cZvmPJWK5GmXuJw +ZQtzmwQkbdZaAEADwtbHZScPSqVizxcx0M4yZHW4XCg +-> ssh-ed25519 Dfencg q01T3MDcsYOgbf0M70ohPJVmMxm7uU5zkEcjqpS2MTg +0kqqufEzwCLEBPk7w/nxZxWX5AcAJKQnOhdciUQmJeg +--- d0At3NFxZg2VONRpp4H7HucYjo8u/jmMMoGlono5Y8k +QZ|kc_t;rO ssh-ed25519 jDpDqw LL0r/vdSlTSYHqUh7eBfPr+WGPZU0iaC2+wjLrV77Ek +msGNfMkfyMsUJu3aSG7C7stpgZ0gwqI8IVZlFT1MKbE +-> ssh-ed25519 JzjriQ MYqtyTLYdp4JyA1a/ci6C44/9ye90RebTpfpM099xj0 +mCDfmBUgPmo4EjENSKvRkRokuQHqFXoivVBR2Tku5/g +-> ssh-rsa 6hPx7A +NUNRebYgygx3knvHH6jySx9ML0XSbCUy3FxNHWhXB1HSv1MxtPG57XTSsgISvmA0 ++Q/4p/1fB99FDvuZZyY1xDoCguJsUGMDzwfeb9J9bYwyuJR0h7ZB3UJWz417PcBV +KEGHYC6H7sdse/wC60deta4ZoftiwPHSxim7nta6uuUuVWkXlZxy/21ypknDo1NY +v/Ek6LhvzzhvYDwotjuQPVXOo4DulFE7AoNo5Xqd4VuzkifBZ7U6zxHRz17sNcOY +sLJW/6uEASbH9jarEv0PN9qcou5WtWEOiSoNdRs5SPWuq+SrFNRMmQOlz9m/9RNd +2zaNpeectLO7mMBq5VC+SIPUGNy+wq2oDg/NKt9WNHMfActciv/q0gJDDUHLYaMz +XponS47ngYP6SRS47g0IiufcT0KJsD8b8aMqyBL2zBslLoSXPThzYrzmfKMe2NKl +GVNDYn7LQkspZkL9Y4PcHcc6fiVHjqZxL1Rsx+H+yaXYz5PlTsL+g1jFeySsHPrT +NtQ7U0dbgSgG6yXMyYEl2QqHE1RFWjhDz7PWORJD0xCDTGBT5tp2crNeZ8sHYWqA +ipz52GgWszBTTYmMBYbke3MCj3/lJP1imcrNhIBILSLVHc0mkZl2srmLbCsvNq6U +Yxrdr4Q1l0julNiil7IFdZHo41LJpfCYSaCRvLXSyps +-> ssh-ed25519 Dfencg FnGT29dYaYptFPwz8wyMmTFIzgDDRQUYrzVPO/Y2dQ8 +k38BfgRhf5J5ZT1JsRcI/VS5iPCnQtXucZDEnVjYoA4 +--- 4fsRMPbGZKgCJyas/nepabKgC+8HGEZgjvBbVvGAfrA +AGgY^cCz^PJ_مg3v8`g.z^.B%; UߘЂP>"3!m=c+s \ No newline at end of file diff --git a/hosts/srxgp00/services/mailserver/webclient.nix b/hosts/srxgp00/services/mailserver/webclient.nix new file mode 100644 index 0000000..cec8604 --- /dev/null +++ b/hosts/srxgp00/services/mailserver/webclient.nix @@ -0,0 +1,31 @@ +{ pkgs, ... }: +let + host = "mail.srx.digital"; +in +{ + services.roundcube = { + enable = true; + hostName = "${host}"; + dicts = with pkgs.aspellDicts; [ en fr es de ]; + extraConfig = '' + $config['imap_host'] = "ssl://${host}"; + $config['smtp_host'] = "ssl://${host}"; + $config['smtp_user'] = "%u"; + $config['smtp_pass'] = "%p"; + ''; + }; + + services.telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; +} diff --git a/hosts/srxgp00/services/minio/default.nix b/hosts/srxgp00/services/minio/default.nix new file mode 100644 index 0000000..4a8460a --- /dev/null +++ b/hosts/srxgp00/services/minio/default.nix @@ -0,0 +1,103 @@ +{ lib, pkgs, config, ... }: +let + host = "s3.srx.digital"; + admin = "admin.s3.srx.digital"; +in +{ + age.secrets = { + minioRootCredentials.file = ./user_admin.age; + minioPrometheusCredentials.file = ./user_prometheus.age; + }; + + environment.shellAliases.minio-client = "${pkgs.minio-client}/bin/mc"; + + services = { + minio = { + enable = true; + region = "eu-central-1"; + listenAddress = ":9900"; + consoleAddress = ":9901"; + rootCredentialsFile = config.age.secrets.minioRootCredentials.path; + }; + + nginx.virtualHosts = { + "${host}" = { + forceSSL = true; + enableACME = true; + extraConfig = '' + ignore_invalid_headers off; + client_max_body_size 0; + proxy_buffering off; + ''; + locations."/" = { + proxyPass = "http://localhost${config.services.minio.listenAddress}"; + extraConfig = '' + proxy_set_header Connection ""; + chunked_transfer_encoding off; + ''; + }; + }; + "${admin}" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost${config.services.minio.consoleAddress}"; + proxyWebsockets = true; + }; + }; + }; + + prometheus.exporters.minio = { + enable = true; + minioBucketStats = true; + minioAddress = "https://${host}/"; + }; + }; + + systemd.services = { + minio.serviceConfig.Environment = [ + "MINIO_SERVER_URL=https://${host}/" + "MINIO_BROWSER_REDIRECT=false" + ]; + + prometheus-minio-exporter.serviceConfig = { + EnvironmentFile = config.age.secrets.minioPrometheusCredentials.path; + ExecStart = lib.mkForce '' + ${pkgs.prometheus-minio-exporter}/bin/minio-exporter \ + -web.listen-address ${config.services.prometheus.exporters.minio.listenAddress}:${toString config.services.prometheus.exporters.minio.port} \ + -minio.server ${config.services.prometheus.exporters.minio.minioAddress} \ + -minio.access-key $MINIO_PROMETHEUS_USER \ + -minio.access-secret $MINIO_PROMETHEUS_PASSWORD \ + ${lib.optionalString config.services.prometheus.exporters.minio.minioBucketStats "-minio.bucket-stats"} + ''; + }; + }; + + services.telegraf.extraConfig.inputs = { + x509_cert = [ + { + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + } + { + sources = [ "https://${admin}:443" ]; + tags.host = admin; + interval = "10m"; + } + ]; + + http_response = [ + { + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + } + { + urls = [ "https://${admin}" ]; + tags.host = admin; + interval = "10m"; + } + ]; + }; +} diff --git a/hosts/srxgp00/services/minio/user_admin.age b/hosts/srxgp00/services/minio/user_admin.age new file mode 100644 index 0000000..ec628e1 Binary files /dev/null and b/hosts/srxgp00/services/minio/user_admin.age differ diff --git a/hosts/srxgp00/services/minio/user_prometheus.age b/hosts/srxgp00/services/minio/user_prometheus.age new file mode 100644 index 0000000..b465fc3 Binary files /dev/null and b/hosts/srxgp00/services/minio/user_prometheus.age differ diff --git a/hosts/srxgp00/services/mysql/default.nix b/hosts/srxgp00/services/mysql/default.nix new file mode 100644 index 0000000..25da40b --- /dev/null +++ b/hosts/srxgp00/services/mysql/default.nix @@ -0,0 +1,14 @@ +{ pkgs, ... }: +{ + services = { + mysql = { + enable = true; + package = pkgs.mariadb; + }; + + mysqlBackup = { + enable = true; + calendar = "05:00:00"; + }; + }; +} diff --git a/hosts/srxgp00/services/nextcloud/adminpass.age b/hosts/srxgp00/services/nextcloud/adminpass.age new file mode 100644 index 0000000..f8f4f4a --- /dev/null +++ b/hosts/srxgp00/services/nextcloud/adminpass.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw gXLNgjhGBM10SZ1U2F269Hi0snqwdMBR9cxDA5vABDs +BVTnuH5HbgS2SQoZEFl7GsXvcYO7Eq1lH2zGhflfUR0 +-> ssh-ed25519 JzjriQ 3c/vRp79jgta5Ow2TfO3VOKABVTSSpshM43eU7o/uRo +LQt1o3Fm5T2ot6Dly9pNbl1YOt+0SQxqnSxMiapzWJs +-> ssh-rsa 6hPx7A +VzCl3ya8O0fD+nzqrTfZvH/W+JSQ1k6K30hKprc0FqhIMWWpmG7k9MDt28zlKqbI +V2Im+QWT3UNohQ7uKo+RsBTkGTRtL/kyGCUqqjfQEyDMgXSdjb05kaE0/jjFR+Tp +MrhuXn390S7Bb/vWW3pv+BqcyHMwHIp9raQeOULu0qBhCVkDaqZbKHqMXOyYyrrn +ooAbofosADSIQkKDkFoBdhIraPejKp7US1ytEG5SaG5uSZXUlgE4iwm8BFos6xKt +CJ8OX/RaNwylA2mkf704wZmY8DPt+0AGuzhyXvfQwB+InQLvNHLEnUl7ErCbxENH +lNWG5+EI7oYQycYg7UN1ofnBSbuvchERPVmDPRx7GSwqrIXj0uWtyys/NERYl1gV +GRdnzC90U+HBhN5l46hnHpyYuO6h434cAPeVa7pE6BQ2ZXvE07vPdyG0uMobq05x +7jLQoX6IAMzBLfzu8g7JpBRyRULhXm9ejPgnH3qCEvXWrRnwc16+1moMADXLyq62 +WtKxFlYALyZ3DnAUW2alZYMdSFTvGQ30GhX/7lSj2ndQ/3XppsX8BtGGVMkSX3g6 +Zc6Re4xqiXKDcqmtn1MJUNSm2kFC+Y/FXYmf92rkmnE0DfoEROwKs45PFX+Thz7P +NjRNPb0rjVJu+YipuOl4Bz1AC96U2BUTBcmwFP8ux8Y +-> ssh-ed25519 Dfencg H6B2Vjd4e6PJwMfsPBaYCYNCDehCryWXD/yvQgKPixk +1GbC05c7ruTO+Ca9KO6fpfMugigGKNhWR0Xw6qB5D0Y +--- ylP9OpryQ/nl1nCS46mGrOsS+8wR4YclZRQRK7hl3To +*e^+uK_ȋz?E Iŀl]޾FAŹYńu$׭r3c| \ No newline at end of file diff --git a/hosts/srxgp00/services/nextcloud/default.nix b/hosts/srxgp00/services/nextcloud/default.nix new file mode 100644 index 0000000..fa8657a --- /dev/null +++ b/hosts/srxgp00/services/nextcloud/default.nix @@ -0,0 +1,153 @@ +{ config, pkgs, ... }: +{ + age.secrets = { + nextcloudAdminPass = { + file = ./adminpass.age; + owner = "nextcloud"; + }; + + nextcloudSecrets = { + file = ./secrets.age; + owner = "nextcloud"; + }; + }; + + environment.systemPackages = with pkgs; [ + ffmpeg + ocrmypdf + tesseract + ]; + + services = { + nextcloud = { + enable = true; + hostName = "cloud.srx.digital"; + + package = pkgs.nextcloud29; + extraAppsEnable = true; + + configureRedis = true; + webfinger = true; + https = true; + maxUploadSize = "1024M"; + + extraApps = { + inherit (pkgs.nextcloud29Packages.apps) mail; + inherit (pkgs.nextcloud29Packages.apps) contacts; + inherit (pkgs.nextcloud29Packages.apps) calendar; + inherit (pkgs.nextcloud29Packages.apps) deck; + inherit (pkgs.nextcloud29Packages.apps) forms; + inherit (pkgs.nextcloud29Packages.apps) polls; + oidc_login = pkgs.fetchNextcloudApp { + url = "https://github.com/pulsejet/nextcloud-oidc-login/releases/download/v3.1.1/oidc_login.tar.gz"; + sha256 = "sha256-EVHDDFtz92lZviuTqr+St7agfBWok83HpfuL6DFCoTE="; + license = "gpl3"; + }; + }; + + phpOptions = { + post_max_size = "1024M"; + upload_max_filesize = "1024M"; + expose_php = "Off"; + short_open_tag = "Off"; + catch_workers_output = "yes"; + display_errors = "stderr"; + error_reporting = "E_ALL & ~E_DEPRECATED & ~E_STRICT"; + "opcache.enable_cli" = "1"; + "opcache.fast_shutdown" = "1"; + "opcache.interned_strings_buffer" = "16"; + "opcache.max_accelerated_files" = "10000"; + "opcache.memory_consumption" = "1024"; + "opcache.revalidate_freq" = "1"; + "openssl.cafile" = "/etc/ssl/certs/ca-certificates.crt"; + }; + + poolSettings = { + "pm" = "dynamic"; + "pm.max_children" = "512"; + "pm.max_requests" = "4096"; + "pm.max_spare_servers" = "512"; + "pm.min_spare_servers" = "32"; + "pm.start_servers" = "64"; + }; + + config = { + dbtype = "pgsql"; + dbhost = "/run/postgresql"; + adminuser = "service"; + adminpassFile = config.age.secrets.nextcloudAdminPass.path; + }; + + secretFile = config.age.secrets.nextcloudSecrets.path; + + settings = { + overwriteProtocol = "https"; + default_phone_region = "+49"; + oidc_login_client_id = "cloud"; + oidc_login_provider_url = "https://id.srx.digital/realms/srx"; + oidc_login_logout_url = "https://${config.services.nextcloud.hostName}/apps/oidc.login/oidc"; + oidc_login_scope = "openid email profile roles"; + oidc_login_attributes = { + id = "preferred_username"; + mail = "email"; + }; + oidc_create_groups = true; + oidc_login_auto_redirect = true; + oidc_login_button_text = "Log in with OpenID"; + oidc_login_disable_registration = false; + oidc_login_end_session_redirect = true; + oidc_login_hide_password_form = true; + oidc_login_redir_fallback = true; + oidc_login_update_avatar = false; + allow_user_to_change_display_name = false; + lost_password_link = "disabled"; + overwritehost = config.services.nextcloud.hostName; + "htaccess.IgnoreFrontController" = true; + }; + }; + + postgresql = { + ensureDatabases = [ config.services.nextcloud.config.dbname ]; + ensureUsers = [{ + name = config.services.nextcloud.config.dbuser; + ensureDBOwnership = true; + }]; + }; + + postgresqlBackup.databases = [ "nextcloud" ]; + + + nginx.virtualHosts = { + "${config.services.nextcloud.hostName}" = { + forceSSL = true; + enableACME = true; + }; + + "srx.digital".locations = { + "= /.well-known/carddav".return = "301 https://${config.services.nextcloud.hostName}/remote.php/dav"; + "= /.well-known/caldav".return = "301 https://${config.services.nextcloud.hostName}/remote.php/dav"; + "= /.well-known/webdav".return = "301 https://${config.services.nextcloud.hostName}/remote.php/dav"; + }; + }; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${config.services.nextcloud.hostName}:443" ]; + tags.host = config.services.nextcloud.hostName; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${config.services.nextcloud.hostName}" ]; + tags.host = config.services.nextcloud.hostName; + interval = "10m"; + }]; + }; + }; + + systemd.services.nextcloud-setup = { + wantedBy = [ "multi-user.target" ]; + requires = [ "postgresql.service" ]; + after = [ "network.target" "postgresql.service" ]; + }; +} diff --git a/hosts/srxgp00/services/nextcloud/secrets.age b/hosts/srxgp00/services/nextcloud/secrets.age new file mode 100644 index 0000000..6676653 --- /dev/null +++ b/hosts/srxgp00/services/nextcloud/secrets.age @@ -0,0 +1,22 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw gt4LnY8JEyRm05USTTnnmoGb+yhY2ivHF7AYyDRS2zs +rLxQQOl158KA7sFDoSA1Dq9eo4hvKqyFQKuMiJYIKPw +-> ssh-ed25519 JzjriQ jLuV616OJ/W3mUU47Srd5zMrCK8R7mYM6s5ol/0Pl2s +MjUPz0mq7v+Ye4ZRR7yTXL8To+o7KZFrXjiHf3WQA7E +-> ssh-rsa 6hPx7A +3iihKSQ2x0fzSzXM+PRWTSrW4xqE0Gx73uZHWRnX/FlmipfC6tl5Dha9jPOKY8q1 +spUKmpvjs/N/MELP1z5NJMhnLXKO5S4FA81R2VJ/iR9XqTK+wx0reuytBsE291du +5PyKcMzFT+Nr6frPaHji9UC8J1GDb5zUXApRE2aAZjSeA0wA5bYXM0/bI8nt72hj +rK0Jn31I3oHHxU6jMFRMRv2yDHinSM88fF9c5qIDr7CHGyVZVi6aKUYi5WRXl0gV +JFQJ64Te9jPdpYk0SmvBtcTDQfBzYjEQDut4j2ssPkM+QqT96yCaRBdQ38J0oxEc +z/aeBJ3CQ2Sgq7D7wp+1Tj0gL2dgRtf6BriWSc+gJlwHk74xiruCj1V7PS0cGYqj +0f4p1zpdwnst0z/guzbpZfwXaMvHCYe44cpdY0WvuV6oRIifHC0ValbNUlnAdoyw +A6+/wuyBzcTDda5muhh6C4d6OzibcX0s5yuZ9NtqiLzPFgeCUNKcdAGlcQvq39Mh +89tKLWrSFVfbL3E/xQqiLX9x3W2iXPp4wETGnF8tcTeJpqYRL63g+/VpqYg0ZTki +jadSj01JWsr3uis/yAhV07rAIf+r6laPzpt50UuFmyadL5ODEVFyeh3SkndC/Cq0 +f4kq3FBrTjB+i+qw/a3Db2at6xT0ZATMzcvK2CK+Nig +-> ssh-ed25519 Dfencg 21+CtN2dIcGrA2/9M9gwiHfvundfX2IDWm3joukktQM +245qkkTOClX/swsR5gI4pYmmtCkGwKQC55E7RilEcGw +--- LsD1y9ZZvjrUAkeIg6lHAwh0CwbtBdT6f5HWNXLOX5k +|2>zUuLU'OHAс Jԡug +1+ 6k:waQa$6D?-H \ No newline at end of file diff --git a/hosts/srxgp00/services/nginx/checkip.nix b/hosts/srxgp00/services/nginx/checkip.nix new file mode 100644 index 0000000..7814f57 --- /dev/null +++ b/hosts/srxgp00/services/nginx/checkip.nix @@ -0,0 +1,33 @@ +{ pkgs, ... }: +let + host = "checkip.srx.digital"; +in +{ + services = { + nginx = { + additionalModules = [ pkgs.nginxModules.echo ]; + virtualHosts."${host}" = { + enableACME = true; + forceSSL = true; + locations."/".extraConfig = '' + default_type text/plain; + echo $remote_addr; + ''; + }; + }; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; + }; +} diff --git a/hosts/srxgp00/services/nginx/default.nix b/hosts/srxgp00/services/nginx/default.nix new file mode 100644 index 0000000..af5d8bf --- /dev/null +++ b/hosts/srxgp00/services/nginx/default.nix @@ -0,0 +1,10 @@ +{ self, ... }: +{ + imports = [ + self.nixosModules.services-web-nginx + ./checkip.nix + ./nix-hamburg.nix + ./srx.digital.nix + ./srx81.de.nix + ]; +} diff --git a/hosts/srxgp00/services/nginx/nix-hamburg.nix b/hosts/srxgp00/services/nginx/nix-hamburg.nix new file mode 100644 index 0000000..c8119b1 --- /dev/null +++ b/hosts/srxgp00/services/nginx/nix-hamburg.nix @@ -0,0 +1,27 @@ +{ pkgs, ... }: +let + host = "nix-hamburg.de"; +in +{ + services = { + nginx.virtualHosts."${host}" = { + enableACME = true; + forceSSL = true; + locations."/".root = pkgs.nix-hamburg; + }; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; + }; +} diff --git a/hosts/srxgp00/services/nginx/srx.digital.nix b/hosts/srxgp00/services/nginx/srx.digital.nix new file mode 100644 index 0000000..837e119 --- /dev/null +++ b/hosts/srxgp00/services/nginx/srx.digital.nix @@ -0,0 +1,26 @@ +{ pkgs, ... }: +let + host = "srx.digital"; +in +{ + services = { + nginx.virtualHosts."${host}" = { + enableACME = true; + forceSSL = true; + locations."/".root = pkgs.srx-digital; + }; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; + }; +} diff --git a/hosts/srxgp00/services/nginx/srx81.de.nix b/hosts/srxgp00/services/nginx/srx81.de.nix new file mode 100644 index 0000000..527d6ca --- /dev/null +++ b/hosts/srxgp00/services/nginx/srx81.de.nix @@ -0,0 +1,26 @@ +let + host = "srx81.de"; +in +{ + services = { + nginx.virtualHosts."${host}" = { + enableACME = true; + forceSSL = true; + locations."/" = { }; + }; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; + }; +} diff --git a/hosts/srxgp00/services/oauth2-proxy/default.nix b/hosts/srxgp00/services/oauth2-proxy/default.nix new file mode 100644 index 0000000..f0ebd88 --- /dev/null +++ b/hosts/srxgp00/services/oauth2-proxy/default.nix @@ -0,0 +1,80 @@ +{ config, ... }: +let + domain = "srx.digital"; + host = "auth.${domain}"; + oidc = "https://id.${domain}/realms/srx"; +in +{ + age.secrets.oauth2-proxy.file = ./secrets.age; + + services = { + oauth2-proxy = { + enable = true; + keyFile = config.age.secrets.oauth2-proxy.path; + + nginx.domain = host; + cookie.domain = ".${domain}"; + email.domains = [ domain ]; + + reverseProxy = true; + passBasicAuth = true; + setXauthrequest = true; + + provider = "keycloak-oidc"; + clientID = "nginx"; + loginURL = oidc; + scope = "openid profile email"; + + extraConfig = { + metrics-address = "127.0.0.1:5673"; + oidc-issuer-url = oidc; + code-challenge-method = "S256"; + session-store-type = "redis"; + redis-connection-url = "redis://${config.services.redis.servers.oauth2-proxy.bind}:${toString config.services.redis.servers.oauth2-proxy.port}/0"; + }; + }; + + redis.servers.oauth2-proxy = { + enable = true; + port = 6386; + }; + + nginx.virtualHosts."${host}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = config.services.oauth2-proxy.httpAddress; + }; + + prometheus.scrapeConfigs = [{ + job_name = "oauth2-proxy"; + static_configs = [{ targets = [ config.services.oauth2-proxy.extraConfig.metrics-address ]; }]; + }]; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; + }; + + systemd.services.oauth2-proxy = { + requires = [ + "nginx.service" + "keycloak.service" + "redis-oauth2-proxy.service" + ]; + after = [ + "nginx.service" + "keycloak.service" + "redis-oauth2-proxy.service" + ]; + }; +} diff --git a/hosts/srxgp00/services/oauth2-proxy/secrets.age b/hosts/srxgp00/services/oauth2-proxy/secrets.age new file mode 100644 index 0000000..d77af79 --- /dev/null +++ b/hosts/srxgp00/services/oauth2-proxy/secrets.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw W2dbMcjU4bR5zQ0k2Z/6hR7hwzZ9PkAEv61suzJs/E4 +NiLEBUVQVEbTN6heg+JDCvt7b5hFDc3zOItKwJLttbU +-> ssh-ed25519 JzjriQ gBWt7o4AKcR9ByJCnLe6S6mh8v1Fq2mqk/BPK4Y2z24 +Ginz/IkisV4BRmjcj4ZmwCUawibIo4KYO5NeASxS5ns +-> ssh-rsa 6hPx7A +UWmmiSoCzvY0Jk+Uf76MgiHS5ha/Qze8arOTWctfge+DM6ur8eGxJUq5U7FoPj2s +Grv4hS/NxcXg006S+ID8/c1jWBtU8mCZG8lck5iNMpfnQZ+cRGPdv/Wef19ORtTp +LDCPjzWNJg6G985HPQu6G6+RbYJGJnN1Kf6c9mrmXNIJmiJoRIBjxbLicfHzjYKl +dyIQ20RpOwrhrl6QWhZl1A+KCqh2oMExm4qaocBD2+IKp8GZRWPFX4YBkqWzphnx +R8u+1bxcN7ZCkB09FaLoVCgQabh01hGpDSUcvQbHfvn1YJtXVegqUUrf6atU7NbT +z51z2EEIZ1lHYE1qGDTBHAl81y5gSSmW2ccHKDQ9CsuIByXgjOGLo0/FLB+fr3oA +bHaCvKQvRfz3wXS19X78xLz1MZHBFDWpVmRqEkNijQJGu1Ihii8ATNeu/IVS3erF +WIxYjs65xYr0+zY6+90n07E1+Gt+qW4ZBstslz/eP0f9iVa2uOCsvnQU8MKrurBM +43WqRlIz7HjeHXUlBBtzelGfjL1WRTM786haIeNlzkl2XDZ2Av1qUdhPBGA7rSl7 +jNVF4Rj9YurRtB78IF3XFGDmyNt5/TNw0qOF32jKpetO26GiYV/Ia+QKwLklnUuz +hT+7JzO5uQx9u4EqElQvBwSnk3NQ3+EBuBt8lZP56Ns +-> ssh-ed25519 Dfencg G/63XTx+5UrL9Kd6frbq/q7EG5b8RJ4y57+mfVSEMlY +MNTaYp9jlvoBMI2PxdiccpqEYBY8mARp3tqPZuSo4bs +--- fzhYndI2/14JjCXprVjEvTDo2pSvalSTpxAVXqFA8g0 +j~ugy0O<d_4r9j[횄- <1.~ -[}LdaPÃFh "tҽF%)xd0gD!Q|!"5r\[OtP,1"T@k{ \ No newline at end of file diff --git a/hosts/srxgp00/services/openldap/default.nix b/hosts/srxgp00/services/openldap/default.nix new file mode 100644 index 0000000..fb15a74 --- /dev/null +++ b/hosts/srxgp00/services/openldap/default.nix @@ -0,0 +1,133 @@ +{ pkgs, config, ... }: +let + domain = "srx.digital"; + host = "ldap.${domain}"; + adminUser = "service"; + testUser = "hans"; + # domainSet = lib.splitString "." domain; + # domainTLD = lib.lists.last domainSet; + # domainSLD = lib.lists.last (lib.lists.reverseList domainSet); + # distinguishedName = "dc=${domainSLD},dc=${domainTLD}"; + distinguishedName = "dc=srx,dc=digital"; + bindDnAdmin = "cn=${adminUser},${distinguishedName}"; +in +{ + age.secrets = { + ldapConfigSecret = { + file = ./ldap-config-secret.age; + owner = "openldap"; + }; + + ldapBindSecret = { + file = ./ldap-bind-secret.age; + owner = "openldap"; + }; + }; + + services.openldap = { + enable = true; + urlList = [ + "ldaps://" + "ldapi://" + ]; + configDir = "/var/lib/openldap/slapd.d"; + settings = { + attrs = { + olcReferral = "ldap://${host}"; + olcLogLevel = [ "stats" ]; + olcSecurity = "ssf=128"; + olcTLSProtocolMin = "3.3"; + olcTLSCipherSuite = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:!RC4:HIGH:!MD5:!EDH:!EXP:!SSLV2:!eNULL"; + olcTLSCACertificateFile = "${config.security.acme.certs.${host}.directory}/fullchain.pem"; + olcTLSCertificateKeyFile = "${config.security.acme.certs.${host}.directory}/key.pem"; + olcTLSCertificateFile = "${config.security.acme.certs.${host}.directory}/chain.pem"; + }; + children = { + "cn=schema".includes = [ + "${pkgs.openldap}/etc/schema/core.ldif" + "${pkgs.openldap}/etc/schema/cosine.ldif" + "${pkgs.openldap}/etc/schema/inetorgperson.ldif" + "${pkgs.openldap}/etc/schema/dyngroup.ldif" + "${pkgs.openldap}/etc/schema/namedobject.ldif" + "${pkgs.openldap}/etc/schema/nis.ldif" + ]; + "olcDatabase={0}config" = { + attrs = { + objectClass = "olcDatabaseConfig"; + olcDatabase = "{0}config"; + olcAccess = [ "{0}to * by * none break" ]; + }; + }; + "olcDatabase={-1}frontend" = { + attrs = { + objectClass = "olcDatabaseConfig"; + olcDatabase = "{-1}frontend"; + olcAccess = [ + "{0}to * by dn.exact=uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth manage stop by * none stop" + ]; + }; + }; + "olcDatabase={2}monitor" = { + attrs = { + objectClass = "olcMonitorConfig"; + olcDatabase = "{2}Monitor"; + }; + }; + "olcDatabase={1}mdb" = { + attrs = { + objectClass = [ + "olcDatabaseConfig" + "olcMdbConfig" + ]; + olcDatabase = "{1}mdb"; + olcDbDirectory = "${config.services.openldap.configDir}"; + olcDbIndex = [ + "objectClass eq" + "cn pres,eq" + "uid pres,eq" + "sn pres,eq,subany" + ]; + olcSuffix = distinguishedName; + olcRootDN = bindDnAdmin; + olcRootPW.path = "${config.age.secrets.ldapBindSecret.path}"; + }; + }; + }; + }; + declarativeContents = { + ${distinguishedName} = '' + dn: ${distinguishedName} + objectClass: top + objectClass: dcObject + objectClass: organization + o: ${domain} + + dn: ou=posix,${distinguishedName} + objectClass: top + objectClass: organizationalUnit + + dn: ou=accounts,ou=posix,${distinguishedName} + objectClass: top + objectClass: organizationalUnit + + dn: uid=${testUser},ou=accounts,ou=posix,${distinguishedName} + objectClass: person + objectClass: posixAccount + userPassword: somePasswordHash + homeDirectory: /home/${testUser} + uidNumber: 1234 + gidNumber: 1234 + cn: "" + sn: "" + ''; + }; + }; + + security.acme.certs."${host}" = { + domain = "${host}"; + inherit (config.services.openldap) group; + reloadServices = [ config.services.openldap.group ]; + }; + + security.dhparams.enable = true; +} diff --git a/hosts/srxgp00/services/openldap/ldap-bind-secret.age b/hosts/srxgp00/services/openldap/ldap-bind-secret.age new file mode 100644 index 0000000..75c19f7 Binary files /dev/null and b/hosts/srxgp00/services/openldap/ldap-bind-secret.age differ diff --git a/hosts/srxgp00/services/openldap/ldap-config-secret.age b/hosts/srxgp00/services/openldap/ldap-config-secret.age new file mode 100644 index 0000000..63025a8 --- /dev/null +++ b/hosts/srxgp00/services/openldap/ldap-config-secret.age @@ -0,0 +1,22 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw tQJi3a3tKiJl5ZfNkro+cOEGDAbUh+vbGf+L4MTCu0k +UioTuNzRsHau5sCRfw7L1y2z52EKlQKscNAv6aCEKl8 +-> ssh-ed25519 JzjriQ UxmUpbg8QKiYsKjkHk00uDc2LcKRye+uwPGiwMD0wmA +/pBpwVPDdiH8TMNksH2V8FtysncRGvtO3sdoSeU2GG4 +-> ssh-rsa 6hPx7A +iJBX2tRnuY0ZMquFrij61pUpuJsgKIy7cgaISaW0vSFtiplmorYVKY2DUmHJ1qbO +4cCb7P72XDs+5utQyTvO80WTKEFMUxAYpVb8VJ3MuP9mRNvlptcI1lCB47IhcKzK +YZFXpbRAMp4u9kTxZiaYakiQsPoaDK6FjQ9XEG1JxjOn1u4XB/WHxG9blW+AIpn9 +1h+Fs7DJF1tU20MlwaLLF5XooxLbDKr/MKeiR1k0y3H6eDtEiQH+Ay42/e1yPwAG +BOO08YxEzAl8sLg8rzlyCu7O1uTvP2wlvqBMV324iu1ug6Le7Gh4ilQyGSLsYOxK +m6rggC5kUEhfBT+60ACReFJx/T/8A/KTYLiQ03F/lmimaCPqnNwkydjSCmIOOiYc +u+hFS6/9TyNM97svMhmq0ttwOhf+zIXVB0zHJ2w9Pj4U77KPrd/C6Ctvn2Q6XK1a +y3EAhTErk4R5fXUiQIcN/5V4lkGPAnwrlqRu4fZAhX/os16M8YZkRoKPNp+aI9Ji +RXBIenbhBNv/9N6/ID1aTZ8Epq420mcT/VEXN/9KkiReWt9ju+lf1NQcCzW4ETZT +WGWay1k0/MFkXBXBW/r1D1p595U8jNB1kfyz/AKTbY/MP2G5FTdM+GsBQ+E6lE9+ +B5xY/iwbrOj6HIuWqGXtk2/c9mOuBTFwCtx06KScayU +-> ssh-ed25519 Dfencg 1sbJD67nv/ArocTaWkLnM9YclfGlRCa696NkshUhaAk +eFbUDRH4GGJVNHv89qwxMdlpjpl+4o3jxPYT9bm+Du8 +--- KVW/9rQkJ+rdNKHcKAlIXpI4yNcdXzmx0NaePNSuyns +5B5g Ód[W{Y&zMP:9:.2 +z$m#z { l7Ć* \ No newline at end of file diff --git a/hosts/srxgp00/services/paperless/default.nix b/hosts/srxgp00/services/paperless/default.nix new file mode 100644 index 0000000..629bfaa --- /dev/null +++ b/hosts/srxgp00/services/paperless/default.nix @@ -0,0 +1,53 @@ +{ config, ... }: +let + name = "paperless"; + host = "paper.srx.digital"; +in +{ + age.secrets.paperlessPassword = { + file = ./password.age; + owner = "paperless"; + }; + + services = { + paperless = { + enable = true; + passwordFile = config.age.secrets.paperlessPassword.path; + settings = { + PAPERLESS_OCR_LANGUAGE = "deu+eng"; + PAPERLESS_ADMIN_USER = "service"; + PAPERLESS_DBHOST = "/run/postgresql"; + }; + }; + + postgresql = { + ensureDatabases = [ name ]; + ensureUsers = [{ + inherit name; + ensureDBOwnership = true; + }]; + }; + + postgresqlBackup.databases = [ name ]; + + nginx.virtualHosts."${host}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://${config.services.paperless.address}:${toString config.services.paperless.port}"; + }; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; + }; +} diff --git a/hosts/srxgp00/services/paperless/password.age b/hosts/srxgp00/services/paperless/password.age new file mode 100644 index 0000000..90a3632 --- /dev/null +++ b/hosts/srxgp00/services/paperless/password.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw ImlVc99pq750TSzRKTcl+MiuH48A0a8i/CzWr3hMTCA +6HmkKtwIhBoLBYUSsr73gSZwZ2nOJPGhtVF/oZxjzAM +-> ssh-ed25519 JzjriQ d8yMMWhdt6idbv8bxxHRvSRDXsfuOUm90YTfrXoD1EE +yQtX8LadpLxetD1zMxPge0wjIjV/9TDcjCmseGdrYuQ +-> ssh-rsa 6hPx7A +qKpB3nXTGN3gGW8K9XE3bfRTJpukEuIpb3Km/4hppWaA72gWXZOeSICTMZEf7u6/ +oRYJpOX9DR1dbX4dXYTuyidyUWUQ6jr5xwzpVNO2EGfZj8bqfRjB4CBzf1ixYZx6 +je6rsFPc10BU8rwYxb3F6ZdIJGpwmVnqNDHBcgl0uprUyGhEAAytKuS+QJO6h1/T +SvB49ToPr2gOLbYicuIL85Zo2PsHlQLQzt+2+jLWPShFUb9PPyyqbnp70TSu2vkD +UZMyxoe861E7ocx28zrm968TzR/UsRo8vLixvcAKlee02OpNe3eWnRlduDuoeR28 +aUSXKnqPs3BPpce4/pcpnYXpqCUtrWILV6OQQ0qq3dZSif82CyHx9e8ftXyYMUZ2 +1HBVLO7qMgx5oN1U70Oxy3ZOwv3UIqHhOe42BiF0cNpIEEtdWVl2RjVyN6pL/3ci +SZO2r2aS29oEOtxGGwQXlJJn1T7z94isotFFOst0/s4Qwp+bUv6G85CdVI3OJaJ2 +5ACu4j/mtP7v6MkY/yTVU62Ne57BxI3Y4TvV8cJqIneeVQlsZwyE0YM1C6Lvp0J6 +UUQjQRItfrX3bXuZZ6N6joPLN6wFARmxgIXAJtevaDC9IkSgpPWDSrs/Vfhj5IBD +zkuwSije7KzjKLQxQs2Qv5FabKN13xqu/VOPnAWBvCw +-> ssh-ed25519 Dfencg tglNj/t+eye5AZIEtxRjAg/TQtYWUxJO8wCKPM7ITHQ +3lZEIz8qPuoiyiNM8i8gFzX4spMmbNut51DQ9AOMjHc +--- rD33wYC+pDGERf8tYF96oGcUHZapBLHnVxPfi3PDu54 + i>tD$ U_I}Z@{ h1s0`9[S.ooH QQ \ No newline at end of file diff --git a/hosts/srxgp00/services/plausible/default.nix b/hosts/srxgp00/services/plausible/default.nix new file mode 100644 index 0000000..eb3c0dc --- /dev/null +++ b/hosts/srxgp00/services/plausible/default.nix @@ -0,0 +1,48 @@ +{ config, ... }: +let + host = "analytics.srx.digital"; +in +{ + age.secrets = { + plausibleAminPassword.file = ./password.age; + plausibleSecretKey.file = ./secret.age; + plausibleMailPassword.file = ./mail.age; + }; + + services = { + plausible = { + enable = true; + adminUser = { + activate = true; + email = "hostmaster@srx.digital"; + passwordFile = config.age.secrets.plausibleAminPassword.path; + }; + server = { + baseUrl = "https://${host}"; + disableRegistration = true; + secretKeybaseFile = config.age.secrets.plausibleSecretKey.path; + }; + mail.email = "no-reply@srx.digital"; + }; + + nginx.virtualHosts."${host}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://localhost:${toString config.services.plausible.server.port}"; + }; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; + }; +} diff --git a/hosts/srxgp00/services/plausible/mail.age b/hosts/srxgp00/services/plausible/mail.age new file mode 100644 index 0000000..487aa5a Binary files /dev/null and b/hosts/srxgp00/services/plausible/mail.age differ diff --git a/hosts/srxgp00/services/plausible/password.age b/hosts/srxgp00/services/plausible/password.age new file mode 100644 index 0000000..e1ad754 --- /dev/null +++ b/hosts/srxgp00/services/plausible/password.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw BHpRYwBogzVgKIZ4UGrIhHs7KPGi5X1LHj3ePqbP4hY +9q1B89pSlI5ZD/42TAHGHL+yHa0a6hQR5Glezc6F/yg +-> ssh-ed25519 JzjriQ a8pElvBQ5eblGFHamtwGR4DnsvbBeiks1apLIdPs2AA +lhufHExUpSpVfAbUsLVOc3cR2oOMek2aiBEWTmxM468 +-> ssh-rsa 6hPx7A +FFtNqcWwHH4Jr51oLzZnyGRuAwLQ+RFEHhXnjrt2xtSOV8b6LmDprr7swahjz7Cl +fjda2A0rBElySjfzc4QIAzNtqjTGIzcmeGxuQrEWhbQyGoARWgp/EQxSln7ydD1x +ancyiPWTgnd2Wld0mAxoMRhp/0EbNdRlA3JIxlIeb5qxQyxSy72Yg9S3qxjwi9SM +q0WbjW4Tg4IRh2J/okP0H7KLfABi0qXB9pfWCtBtuUxNMZ2ekEzouS8SBumd6oUR +AYpCGt/eAn/AwOXCdAD73onsB8odB0MVpH1RYZRU9wOuHPIuTZjH+h3AI4779AnM +jLDvMEZVe0KMXuYrb/94djkyfnIeECEzOtc7W5i8vS283zoAJdjqwIRY5P1JOB3K +XbutCM1QnWTmx3GZ99UwyAYEfRHWMHdsBOxygJXYgXFSWQJa0monKayX2s0GPHEz +s1/CwqJ95TPsucPfC59q7UVkIinDTk1osR42hjqoKbOPWvPR0O9yajhijvMiNJJp +fkEieUAzIT/YzoAkbRbC4Myzitq97VPsHIfFy2jPG1tf5gVN2yxZj3EFIKxM5tEN +kvx+WLhY/1HPP4c31hXs0+U6Gw5sML/j9ntJnD0cmPsyoeWbjUNhuX8ulM4zUv/X +k2d3k61F9nLMU6yEPw+V8mzPqf0UQaL7VW2UapTPkRQ +-> ssh-ed25519 Dfencg TLzld5xDEsoRFtEsMsahiRYg9A51L4ub8j0+vSRP/T0 +9x8xqil/0DQUgWFPAp7yc9iWnJ9uX9MosTmwP+fjEKY +--- 0H2hrCIaBG759rpwwPW6x456cJTgayK838A178Vy12A +lg M*?2rqv~d 5+(4o[*YJ \ No newline at end of file diff --git a/hosts/srxgp00/services/plausible/secret.age b/hosts/srxgp00/services/plausible/secret.age new file mode 100644 index 0000000..da72f8d --- /dev/null +++ b/hosts/srxgp00/services/plausible/secret.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw oIY2chGlJnQwRKGYUPMAmueSm/hRcj4qyEGRP4v99DA +iNW2k9EEprnMGRA2BHitSztk49lbbaQt/QJR40BC2K4 +-> ssh-ed25519 JzjriQ mq5SPS7+UlBdCS6ZTtHy7MGZyIGudllK0QKTCzAbfR4 +mGaMwonri+MgWovKK6iNrM6N4eTBZrHX5FrPij+lLz0 +-> ssh-rsa 6hPx7A +KQmnB9QgfxBMTAUnO3l7YjDqQAskGQV3Hve7IRg4b4sG7HFW3aI9SIKXpECzVvT4 +5kHqrSJNeQvo8fUdxdqvfXDPaxaVz+sWUmfbTzcZagAg6jkxEqlxeUzDw6mMgUu+ +QjJsSFIwOIyNTlAjdcbH9ZdEKZKGsmbaPvMJlqrDs+PPKpXdkemHDcO2QrWdKqlX +N227ljuOf05Qgbn+JJw3m91tMscxDERFCfCt28jLX2IaPdriexLiJv6LDSLIyf3y +uhwtbVX24PmKhCPeL/PKYjFKyCXrWyhNSlOE7bQSgWSdfxinvSsjc8DWwfC7vhvo +aouEhAzXGd1AnQTBuUz8N68fQckSw5RVgYt4fbemN0Y22GFK51ZstjYmP+33xMTb +CKrs9/wB+nEmIzQ3N7yj+xbCoYmpJ7Ce2Q/qdp4MYUn3wVgoU4SiwWAZUe4aXgAd +LmGo1UF9MgPETDEhf4TDNQoQWL4mxNxHDTEUSfjsDd/yL1DVt0hfzoVsGgSXDHD2 +GeTv0/nCu/NhWW8Lxo/HEcSg3JzFk0kd53LzvXTqqx8vnXW1lyzZcsZZp05gJxqo +iiKIzzUBbDhXR+pkhab9J6DOxKxIZabjjejsb8cKS8clOTwsyqExsbi/dYoQaFmd +Sr9B6FlpANDdhSTcnmOXJ9GHtNzjMNiiYil7TyMfl5M +-> ssh-ed25519 Dfencg /fWY2Ahqeu99jIPhbcbzlPZDz1Pev45LNSis0aCx0n0 +IblFmuMc9XhDTrpG/iy0jeGpn8vmYytSdCeXpKeeJX0 +--- Xezwhc5YCpsxxJWuvyNwYozTh1OXst7iT6xCuepciLI +pzsߩĽfTdD%wx /^*v܀'ME ZpozzΌH.[6ԁIJ1@ 88jĤz \ No newline at end of file diff --git a/hosts/srxgp00/services/postgresql/default.nix b/hosts/srxgp00/services/postgresql/default.nix new file mode 100644 index 0000000..8099c3e --- /dev/null +++ b/hosts/srxgp00/services/postgresql/default.nix @@ -0,0 +1,14 @@ +{ lib, pkgs, ... }: +{ + services = { + postgresql.package = lib.mkForce pkgs.postgresql_14; + + postgresqlBackup = { + enable = true; + startAt = "*-*-* 05:00:00"; + compression = "none"; + }; + + prometheus.exporters.postgres.enable = true; + }; +} diff --git a/hosts/srxgp00/services/prometheus/alertmanager-env.age b/hosts/srxgp00/services/prometheus/alertmanager-env.age new file mode 100644 index 0000000..c14049e Binary files /dev/null and b/hosts/srxgp00/services/prometheus/alertmanager-env.age differ diff --git a/hosts/srxgp00/services/prometheus/alertmanager.nix b/hosts/srxgp00/services/prometheus/alertmanager.nix new file mode 100644 index 0000000..9f0840e --- /dev/null +++ b/hosts/srxgp00/services/prometheus/alertmanager.nix @@ -0,0 +1,107 @@ +{ config, ... }: +let + host = "alerts.srx.digital"; +in +{ + age.secrets.prometheusAlertmanagerEnv.file = ./alertmanager-env.age; + + services = { + prometheus = { + scrapeConfigs = [{ + job_name = "alertmanager"; + static_configs = [{ + targets = [ "${config.services.prometheus.alertmanager.listenAddress}:${toString config.services.prometheus.alertmanager.port}" ]; + }]; + }]; + + alertmanager = { + enable = true; + webExternalUrl = "https://${host}"; + listenAddress = "localhost"; + + environmentFile = config.age.secrets.prometheusAlertmanagerEnv.path; + configuration = { + global = { + smtp_smarthost = "mail.srx.digital:587"; + smtp_auth_username = "$SMTP_USERNAME"; + smtp_auth_password = "$SMTP_PASSWORD"; + smtp_from = "$SMTP_USERNAME"; + }; + + route = { + receiver = "default"; + routes = [ + { + receiver = "mail"; + group_by = [ "host" ]; + group_wait = "30s"; + group_interval = "2m"; + repeat_interval = "2h"; + } + { + receiver = "telegram"; + group_by = [ "host" ]; + group_wait = "30s"; + group_interval = "2m"; + repeat_interval = "2h"; + } + ]; + }; + + receivers = [ + { name = "default"; } + { + name = "mail"; + email_configs = [{ + to = "$SMTP_RECEIVER"; + send_resolved = true; + }]; + } + { + name = "telegram"; + telegram_configs = [{ + bot_token = "$TELEGRAM_BOT_TOKEN"; + chat_id = -419206986; + parse_mode = "HTML"; + }]; + } + ]; + }; + }; + + alertmanagers = [{ + scheme = "http"; + path_prefix = "/"; + static_configs = [{ + targets = [ + "${config.services.prometheus.alertmanager.listenAddress}:${toString config.services.prometheus.alertmanager.port}" + ]; + }]; + }]; + }; + + nginx.virtualHosts."${host}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://${config.services.prometheus.alertmanager.listenAddress}:${toString config.services.prometheus.alertmanager.port}"; + }; + + oauth2-proxy.nginx.virtualHosts."${host}" = { + allowed_email_domains = [ "srx.digital" ]; + }; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; + }; +} diff --git a/hosts/srxgp00/services/prometheus/check/apcupsd.nix b/hosts/srxgp00/services/prometheus/check/apcupsd.nix new file mode 100644 index 0000000..a241c6f --- /dev/null +++ b/hosts/srxgp00/services/prometheus/check/apcupsd.nix @@ -0,0 +1,7 @@ +{ config, ... }: +{ + services.prometheus.scrapeConfigs = [{ + job_name = "apcupsd"; + static_configs = [{ targets = [ "srxnas00.vpn.srx.dev:${toString config.services.prometheus.exporters.apcupsd.port}" ]; }]; + }]; +} diff --git a/hosts/srxgp00/services/prometheus/default.nix b/hosts/srxgp00/services/prometheus/default.nix new file mode 100644 index 0000000..4591258 --- /dev/null +++ b/hosts/srxgp00/services/prometheus/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./prometheus.nix + ./alertmanager.nix + ./rules.nix + ./check/apcupsd.nix + ]; +} diff --git a/hosts/srxgp00/services/prometheus/prometheus.nix b/hosts/srxgp00/services/prometheus/prometheus.nix new file mode 100644 index 0000000..138235b --- /dev/null +++ b/hosts/srxgp00/services/prometheus/prometheus.nix @@ -0,0 +1,93 @@ +{ config, ... }: +let + host = "status.srx.digital"; + hosts = [ + "srxgp00.vpn.srx.dev" + "srxgp01.vpn.srx.dev" + "srxgp02.vpn.srx.dev" + "srxk8s00.vpn.srx.dev" + "srxnas00.vpn.srx.dev" + "srxnas01.vpn.srx.dev" + "copepod.vpn.srx.dev" + "diatome.vpn.srx.dev" + "opd00.vpn.srx.dev" + ]; + openwrt = [ + "srxap01.op.hq.hh.srx.digital" + "srxfw01.op.hq.hh.srx.digital" + ]; +in +{ + services = { + prometheus = { + enable = true; + extraFlags = [ "--storage.tsdb.retention.time=30d" ]; + scrapeConfigs = [ + { + job_name = "prometheus"; + static_configs = [{ + targets = [ + "srxgp00.vpn.srx.dev:${toString config.services.prometheus.port}" + ]; + }]; + } + { + job_name = "node"; + static_configs = [ + { + targets = builtins.concatMap + (name: [ + "${name}:${toString config.services.prometheus.exporters.node.port}" + ]) + hosts; + } + ]; + } + { + job_name = "telegraf"; + static_configs = [{ + targets = builtins.concatMap (name: [ "${name}:9273" ]) hosts; + }]; + } + { + job_name = "openwrt"; + static_configs = [{ + targets = builtins.concatMap (name: [ "${name}:9273" ]) openwrt; + }]; + } + ]; + }; + + nginx.virtualHosts."${host}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://${config.services.prometheus.listenAddress}:${toString config.services.prometheus.port}"; + }; + + oauth2-proxy.nginx.virtualHosts."${host}" = { + allowed_email_domains = [ "srx.digital" ]; + }; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; + + grafana.provision.datasources.settings.datasources = [{ + name = "Prometheus"; + type = "prometheus"; + access = "proxy"; + url = "http://${config.services.prometheus.listenAddress}:${toString config.services.prometheus.port}"; + isDefault = true; + }]; + }; +} diff --git a/hosts/srxgp00/services/prometheus/rules.nix b/hosts/srxgp00/services/prometheus/rules.nix new file mode 100644 index 0000000..1e60e53 --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules.nix @@ -0,0 +1,37 @@ +{ lib, pkgs, ... }: +let + getRuleFiles = lib.mapAttrs' + ( + f: _: lib.nameValuePair (lib.removeSuffix ".nix" f) (import (./rules + "/${f}")) + ) + (builtins.readDir ./rules); + + formatRules = + rules: + (lib.mapAttrsToList ( + name: opts: { + alert = name; + expr = opts.condition; + for = opts.time or "1m"; + labels = opts.labels or { }; + annotations.description = opts.description; + } + )) + rules; + + writeRuleFile = + name: value: + (pkgs.writeText "prometheus-rules-${name}.yaml" ( + builtins.toJSON { + groups = [ + { + inherit name; + rules = formatRules value; + } + ]; + } + )); +in +{ + services.prometheus.ruleFiles = lib.attrsets.mapAttrsToList writeRuleFile getRuleFiles; +} diff --git a/hosts/srxgp00/services/prometheus/rules/apcupsd.nix b/hosts/srxgp00/services/prometheus/rules/apcupsd.nix new file mode 100644 index 0000000..6e0289b --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/apcupsd.nix @@ -0,0 +1,41 @@ +{ + apcupsd_line_volts = { + condition = "apcupsd_line_volts < 200"; + description = "The UPS line voltage on {{$labels.instance}} dropped below 200V, indicating a potential blackout: {{$value}} V!"; + }; + + apcupsd_battery_volts = { + condition = "apcupsd_battery_volts < 20"; + description = "The UPS battery voltage on {{$labels.instance}} dropped below 20V: {{$value}} V!"; + }; + + apcupsd_battery_volts_nominal = { + condition = "apcupsd_battery_nominal_volts < 20"; + description = "The nominal UPS battery voltage on {{$labels.instance}} dropped below 20V: {{$value}} V!"; + }; + + apcupsd_temperature = { + condition = "apcupsd_internal_temperature_celsius > 40"; + description = "The internal UPS temperature on {{$labels.instance}} exceeds 40°C: {{$value}}°C!"; + }; + + apcupsd_ups_load = { + condition = "apcupsd_ups_load_percent > 80"; + description = "The UPS load on {{$labels.instance}} is higher than 80%: {{$value}}%!"; + }; + + apcupsd_battery_time_left = { + condition = "apcupsd_battery_time_left_seconds < 600"; + description = "Less than 10 minutes of UPS battery charge remaining on {{$labels.instance}}: {{$value}} seconds!"; + }; + + apcupsd_battery_charge = { + condition = "apcupsd_battery_charge_percent < 80"; + description = "Less than 80% battery charge remaining on {{$labels.instance}}: {{$value}}%!"; + }; + + apcupsd_status_not_online = { + condition = ''apcupsd_info{status != "ONLINE"}''; + description = "The UPS status on {{$labels.instance}} is not online: {{$labels.status}}!"; + }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/dendrite.nix b/hosts/srxgp00/services/prometheus/rules/dendrite.nix new file mode 100644 index 0000000..39436a5 --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/dendrite.nix @@ -0,0 +1,6 @@ +{ + dendrite_up = { + condition = "dendrite_up != 1"; + description = "Dendrite on {{$labels.instance}} seems to be down!"; + }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/dns.nix b/hosts/srxgp00/services/prometheus/rules/dns.nix new file mode 100644 index 0000000..b7f0b79 --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/dns.nix @@ -0,0 +1,16 @@ +{ + dns_query = { + condition = "dns_query_result_code != 0"; + description = "{{$labels.domain}} : could retrieve A record {{$labels.instance}} from server {{$labels.server}}: {{$labels.result}}!"; + }; + + dns_secure_query = { + condition = "secure_dns_state != 0"; + description = "{{$labels.domain}} : could retrieve A record {{$labels.instance}} from server {{$labels.server}}: {{$labels.result}} for protocol {{$labels.protocol}}!"; + }; + + dnssec_zone_days_left = { + condition = "dnssec_zone_record_resolves == 1 and dnssec_zone_record_days_left <= 10"; + description = "{{$labels.domain}} : could retrieve A record {{$labels.instance}} from server {{$labels.server}}: {{$labels.result}} for protocol {{$labels.protocol}}!"; + }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/encryption.nix b/hosts/srxgp00/services/prometheus/rules/encryption.nix new file mode 100644 index 0000000..4ecb677 --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/encryption.nix @@ -0,0 +1,8 @@ +{ + # cert_expiry = { + # # condition = "x509_cert_expiry < 7*24*3600"; + # # description = "{{$labels.instance}}: The TLS certificate from {{$labels.source}} will expire in less than 7 days: {{$value}}s"; + # condition = ''x509_cert_expiry{issuer_common_name="R3"} < ${toString (60 * 60 * 24 * 5)}''; + # description = "{{ $labels.san }} does expire in less than 5 days"; + # }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/forgejo.nix b/hosts/srxgp00/services/prometheus/rules/forgejo.nix new file mode 100644 index 0000000..2ef725a --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/forgejo.nix @@ -0,0 +1,6 @@ +{ + # forgejo_http_500 = { + # condition = ''rate(promhttp_metric_handler_requests_total{job="forgejo", code="500"}[5m]) > 3''; + # description = "{{$labels.instance}}: forgejo instances error rate went up: {{$value}} errors in 5 minutes"; + # }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/harddisk.nix b/hosts/srxgp00/services/prometheus/rules/harddisk.nix new file mode 100644 index 0000000..ae23393 --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/harddisk.nix @@ -0,0 +1,26 @@ +{ + # smart_errors = { + # condition = ''smart_device_health_ok{enabled!="Disabled"} != 1''; + # description = "{{$labels.instance}}: S.M.A.R.T reports: {{$labels.device}} ({{$labels.model}}) has errors."; + # }; + + mdraid_not_active = { + condition = ''node_md_state{state="active"} != 1''; + description = "{{$labels.instance}} with device {{$labels.device}} is in {{$labels.state}}."; + }; + + mdraid_is_recovering = { + condition = ''node_md_state{state="recovering"} == 1''; + description = "{{$labels.instance}} with device {{$labels.device}} is in {{$labels.state}}."; + }; + + mdraid_disks_down = { + condition = "mdstat_DisksDown != 0"; + description = "{{$labels.instance}} with device {{$labels.device}} is in {{$labels.state}}."; + }; + + mdraid_disks_faild = { + condition = "mdstat_DisksFailed != 0"; + description = "{{$labels.instance}} with device {{$labels.device}} is in {{$labels.state}}."; + }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/http.nix b/hosts/srxgp00/services/prometheus/rules/http.nix new file mode 100644 index 0000000..a2f57d2 --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/http.nix @@ -0,0 +1,16 @@ +{ + http = { + condition = "http_response_result_code != 0"; + description = "{{$labels.server}} : http request failed from {{$labels.instance}}: {{$labels.result}}!"; + }; + + # http_not_ok = { + # condition = "0 * (http_response_http_response_code != 200) + 1"; + # description = "{{ $labels.exported_server }} does not return Ok for more than 5 minutes"; + # }; + + # http_match_failed = { + # condition = "http_response_response_string_match == 0"; + # description = "{{$labels.server}} : http body not as expected; status code: {{$labels.status_code}}!"; + # }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/instance.nix b/hosts/srxgp00/services/prometheus/rules/instance.nix new file mode 100644 index 0000000..894637a --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/instance.nix @@ -0,0 +1,17 @@ +{ + instance_down = { + condition = "up == 0"; + time = "5m"; + description = "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."; + }; + + instance_reboot = { + condition = "system_uptime < 300"; + description = "{{$labels.host}} just rebooted."; + }; + + instance_uptime = { + condition = "system_uptime > 2592000"; + description = "{{$labels.host}} has been up for more than 30 days."; + }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/mail.nix b/hosts/srxgp00/services/prometheus/rules/mail.nix new file mode 100644 index 0000000..e09efb7 --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/mail.nix @@ -0,0 +1,11 @@ +{ + postfix_queue_length = { + condition = "avg_over_time(postfix_queue_length[1h]) > 10"; + description = "{{$labels.instance}}: postfix mail queue has undelivered {{$value}} items"; + }; + + # https://doc.dovecot.org/configuration_manual/stats/old_statistics/ + # dovecot_up + # dovecot_user_auth_failures + # dovecot_user_auth_db_tempfails +} diff --git a/hosts/srxgp00/services/prometheus/rules/memory.nix b/hosts/srxgp00/services/prometheus/rules/memory.nix new file mode 100644 index 0000000..c16ef7c --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/memory.nix @@ -0,0 +1,18 @@ +{ + memory_under_pressure = { + condition = "rate(node_vmstat_pgmajfault[1m]) > 1000"; + description = "{{$labels.instance}}: The node is under heavy memory pressure. High rate of major page faults: {{$value}}"; + }; + + ram_using_90percent = { + condition = "mem_buffered + mem_free + mem_cached < mem_total * 0.1"; + time = "1h"; + description = "{{$labels.host}} is using at least 90% of its RAM for at least 1 hour."; + }; + + swap_using_30percent = { + condition = "mem_swap_total - (mem_swap_cached + mem_swap_free) > mem_swap_total * 0.3"; + time = "30m"; + description = "{{$labels.host}} is using 30% of its swap space for at least 30 minutes."; + }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/network.nix b/hosts/srxgp00/services/prometheus/rules/network.nix new file mode 100644 index 0000000..f76e87b --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/network.nix @@ -0,0 +1,17 @@ +{ + ## ssh: connect to host srxgp00.srx.digital port 22: Connection refused + # connection_failed = { + # condition = "net_response_result_code != 0"; + # description = "{{$labels.server}}: connection to {{$labels.port}}({{$labels.protocol}}) failed from {{$labels.instance}}"; + # }; + + # ping = { + # condition = "ping_result_code != 0"; + # description = "{{$labels.url}}: ping from {{$labels.instance}} has failed!"; + # }; + + # ping_high_latency = { + # condition = "ping_average_response_ms > 5000"; + # description = "{{$labels.instance}}: ping probe from {{$labels.source}} is encountering high latency!"; + # }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/nix.nix b/hosts/srxgp00/services/prometheus/rules/nix.nix new file mode 100644 index 0000000..bb070b3 --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/nix.nix @@ -0,0 +1,7 @@ +{ + # nixpkgs_out_of_date = { + # condition = ''(time() - flake_input_last_modified{input="nixpkgs"}) / (60 * 60 * 24) > 7''; + # time = "1h"; + # description = "{{$labels.host}} cannot reach nfs export [{{$labels.server}}]:{{$labels.path}}"; + # }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/prometheus.nix b/hosts/srxgp00/services/prometheus/rules/prometheus.nix new file mode 100644 index 0000000..db3f7ff --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/prometheus.nix @@ -0,0 +1,38 @@ +{ + prometheus_wal_corruption = { + condition = ''prometheus_tsdb_wal_corruptions_total > 1''; + description = "Prometheus TSDB database has a corrupt Write-Ahead Log (WAL) of {{ $value }}."; + }; + + prometheus_too_many_restarts = { + condition = ''changes(process_start_time_seconds{job=~"prometheus|pushgateway|alertmanager|telegraf"}[15m]) > 2''; + description = "Prometheus has restarted more than twice in the last 15 minutes. It might be crashlooping."; + }; + + prometheus_not_connected_to_alertmanager = { + condition = "prometheus_notifications_alertmanagers_discovered < 1"; + description = "Prometheus cannot connect the alertmanager VALUE = {{ $value }} LABELS = {{ $labels }}"; + }; + + prometheus_rule_evaluation_failures = { + condition = "increase(prometheus_rule_evaluation_failures_total[3m]) > 0"; + description = + "Prometheus encountered {{ $value }} rule evaluation failures, leading to potentially ignored alerts. VALUE = {{ $value }} LABELS = {{ $labels }}"; + }; + + prometheus_template_expansion_failures = { + condition = "increase(prometheus_template_text_expansion_failures_total[3m]) > 0"; + time = "0m"; + description = "Prometheus encountered {{ $value }} template text expansion failures VALUE = {{ $value }} LABELS = {{ $labels }}"; + }; + + prometheus_alertmanager_config_not_synced = { + condition = ''count(count_values("config_hash", alertmanager_config_hash)) > 1''; + description = "Configurations of AlertManager cluster instances are out of sync."; + }; + + # prometheus_alerts_silences_changed = { + # condition = ''abs(delta(alertmanager_silences{state="active"}[1h])) >= 1''; + # description = "alertmanager: number of active silences has changed: {{$value}}"; + # }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/services.nix b/hosts/srxgp00/services/prometheus/rules/services.nix new file mode 100644 index 0000000..9754cc4 --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/services.nix @@ -0,0 +1,22 @@ +{ + systemd_service_failed = { + condition = ''systemd_units_active_code{name!~"nixpkgs-update-.*.service"} == 3''; + description = "{{$labels.host}} failed to (re)start service {{$labels.name}}."; + }; + + service_not_running = { + condition = ''systemd_units_active_code{name=~"teamspeak3-server.service|tt-rss.service", sub!="running"}''; + description = "{{$labels.host}} should have a running {{$labels.name}}."; + }; + + telegraf_down = { + condition = ''min(up{job=~"telegraf"}) by (source, job, instance, org) == 0''; + time = "3m"; + description = "{{$labels.instance}}: {{$labels.job}} telegraf exporter from {{$labels.source}} is down."; + }; + + oom_kills = { + condition = "increase(kernel_vmstat_oom_kill[5m]) > 0"; + description = "{{$labels.instance}}: OOM kill detected"; + }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/storage.nix b/hosts/srxgp00/services/prometheus/rules/storage.nix new file mode 100644 index 0000000..48d5c5a --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/storage.nix @@ -0,0 +1,60 @@ +{ + filesystem_device_error = { + condition = ''node_filesystem_device_error{fstype!="tmpfs",fstype!="ramfs",device_error!="permission denied"} != 0''; + time = "5m"; + description = "{{ $labels.instance }} with device {{ $labels.device }} of filesystem type {{ $labels.fstype }} has an error for more than 5 minutes."; + }; + + filesystem_full_80percent = { + condition = ''disk_used_percent{mode!="ro", path!="/boot"} >= 80''; + time = "10m"; + description = "{{$labels.instance}} device {{$labels.device}} on {{$labels.path}} got less than 20% space left on its filesystem."; + }; + + filesystem_inodes_full = { + condition = "disk_inodes_free / disk_inodes_total < 0.10"; + time = "10m"; + description = "{{$labels.instance}} device {{$labels.device}} on {{$labels.path}} got less than 10% inodes left on its filesystem."; + }; + + filesystem_tmpfs_root_full = { + condition = ''node_filesystem_free_bytes{fstype="tmpfs",mountpoint="/"} <= 128000000''; + time = "10m"; + description = "{{$labels.host}}: {{$labels.name}} only 128MB left on / tmpfs filesystem."; + }; + + unusual_disk_read_latency = { + condition = "rate(diskio_read_time[1m]) / rate(diskio_reads[1m]) > 0.1 and rate(diskio_reads[1m]) > 0"; + description = '' + {{$labels.instance}}: Disk latency is growing (read operations > 100ms) + ''; + }; + + unusual_disk_write_latency = { + condition = "rate(diskio_write_time[1m]) / rate(diskio_write[1m]) > 0.1 and rate(diskio_write[1m]) > 0"; + description = '' + {{$labels.instance}}: Disk latency is growing (write operations > 100ms) + ''; + }; + + ext4_errors = { + condition = "ext4_errors_value > 0"; + description = "{{$labels.instance}}: ext4 has reported {{$value}} I/O errors: check /sys/fs/ext4/*/errors_count"; + }; + + zfs_zpool_errors = { + condition = "zpool_status_errors > 0"; + description = "{{$labels.instance}} reports: zpool {{$labels.name}} has {{$value}} errors"; + }; + + zfs_errors = { + condition = "zfs_arcstats_l2_io_error + zfs_dmu_tx_error + zfs_arcstats_l2_writes_error > 0"; + description = "{{$labels.instance}} reports: {{$value}} ZFS IO errors."; + }; + + nfs_export_not_present = { + condition = "nfs_export_present == 0"; + time = "1h"; + description = "{{$labels.host}} cannot reach nfs export [{{$labels.server}}]:{{$labels.path}}"; + }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/tasks.nix b/hosts/srxgp00/services/prometheus/rules/tasks.nix new file mode 100644 index 0000000..1e2678a --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/tasks.nix @@ -0,0 +1,11 @@ +{ + daily_task_not_run = { + condition = ''time() - task_last_run{state="ok",frequency="daily"} > (24 + 6) * 60 * 60''; + description = "{{$labels.host}}: {{$labels.name}} was not run in the last 24h"; + }; + + daily_task_failed = { + condition = ''task_last_run{state="fail"}''; + description = "{{$labels.host}}: {{$labels.name}} failed to run"; + }; +} diff --git a/hosts/srxgp00/services/prometheus/rules/workload.nix b/hosts/srxgp00/services/prometheus/rules/workload.nix new file mode 100644 index 0000000..7f119e1 --- /dev/null +++ b/hosts/srxgp00/services/prometheus/rules/workload.nix @@ -0,0 +1,7 @@ +{ + load15 = { + condition = "system_load15 / system_n_cpus >= 2.0"; + time = "10m"; + description = "{{$labels.host}} is running with load15 > 1 for at least 5 minutes: {{$value}}"; + }; +} diff --git a/hosts/srxgp00/services/restic/default.nix b/hosts/srxgp00/services/restic/default.nix new file mode 100644 index 0000000..ea58877 --- /dev/null +++ b/hosts/srxgp00/services/restic/default.nix @@ -0,0 +1,31 @@ +{ config, pkgs, ... }: +{ + age.secrets = { + resticRepoKey.file = ./repo_key.age; + resticRepoSsh.file = ./repo_ssh.age; + }; + + environment.systemPackages = with pkgs; [ restic ]; + + services.restic.backups.base = { + paths = [ "/var/lib" "/var/backup" ]; + exclude = [ "/var/lib/prometheus2" ]; + repository = "sftp:u388681@u388681.your-storagebox.de:/home"; + passwordFile = config.age.secrets.resticRepoKey.path; + extraOptions = [ "sftp.command='ssh -p 23 -i /run/agenix/resticRepoSsh u388681@u388681.your-storagebox.de -s sftp'" ]; + initialize = true; + checkOpts = [ "--with-cache" ]; + timerConfig.OnCalendar = "04:00"; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 1" + ]; + }; + + home-manager.users.root.home.sessionVariables = { + RESTIC_PASSWORD_FILE = config.age.secrets.resticRepoKey.path; + RESTIC_REPOSITORY = config.services.restic.backups.base.repository; + }; +} diff --git a/hosts/srxgp00/services/restic/repo_key.age b/hosts/srxgp00/services/restic/repo_key.age new file mode 100644 index 0000000..c175b7f --- /dev/null +++ b/hosts/srxgp00/services/restic/repo_key.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw 7D0to1lD5NYopXp6MRwGP6GZWEjWaeAmV/nBba7OQQA +5IV3RHhr9e/rxSEedOqcC1WfQkdbfrKT1wgZ/ymac5A +-> ssh-ed25519 JzjriQ 2bnS1m0OzNYgOucjqFZtW8ocC+UTkJSGZCpTAWyANCY +tGZ0KxDH8k7urTXxlb9LFMgtm7gvUrEqIdvw7AQWigo +-> ssh-rsa 6hPx7A +RPYNdYz6UOvv8HbT3VXOqGpp7z2kJ3VSEBQIA/oJjZgO/PyI7fkzu95lua0pVit+ +aidXMhA+q3vcFCmoWB/aFmn2T7dlqOO+AkdUFZPP7Z06LxgDbCJIPmX8g9b4NYHE +fWfwdolq05Rrm7qrAFc8+anAvk30+2F2I3f7usXvDCYm0O/tAzgBcui12rm3nO+J +SXZ9t6TL+0svgN2gFDxjzmeZvro3LeUL7n1y9dXbj0rIi8g/7ppXy9kUVJEfDuZh +8muyRTKXNHb53AD/Z+NIN9kCj/aWEyy9IcxEvGGYWNQ+R62dRBSYo1hNYZ/7Rv02 +0A5SFywjwh61kTEETmvYfzEJdByT3FgdJnGIG30YRlwO95DSiY0iRMtGPBMYaTms +mM3QlWqLKOFfYwPibm36kf1JvrvdV2nh2Fr+mV5lw1R0sVj2Ak9RzdGXWEkmhSzM +Mjw1RRmZBhC9a3MKM661xe+bWEvrvbL9ycRp0o5lcS1CWDSLjzo3syme8fkLBjU/ +L+Pb6GOKA2kNsIlDDC4w32g5oSFCfyfcbCfSJ4+BYg6zFm0ZFjbZLZTZ+I3jOmrr +2uMWzvgxjWJtr2eYC9eE0PTC5z9AzHUkf+aRcHT2y7QlJMY6/1aiC5qbR1sto7+Z +9tndCYJiiZuUP2GxDqz0qLvd0AwLzh+ywn+Atm1hvp0 +-> ssh-ed25519 Dfencg Uvz/a9lKs8vo6gYow1hXZaJ6GqekZgoWWJ6dDyrmEC0 +fJN3p/QyQp6UjmNYaiAsW4GasMwGo3JLb2zTxCgqVbs +--- 6Pmav0/SMX4SmlTO/yLcScfVSHwfLLnxki0vjI8N8jo +5Jԇ8yÌSܟz Q4GLkر0'x $ \ No newline at end of file diff --git a/hosts/srxgp00/services/restic/repo_ssh.age b/hosts/srxgp00/services/restic/repo_ssh.age new file mode 100644 index 0000000..48f90aa Binary files /dev/null and b/hosts/srxgp00/services/restic/repo_ssh.age differ diff --git a/hosts/srxgp00/services/vaultwarden/default.nix b/hosts/srxgp00/services/vaultwarden/default.nix new file mode 100644 index 0000000..070fb66 --- /dev/null +++ b/hosts/srxgp00/services/vaultwarden/default.nix @@ -0,0 +1,120 @@ +{ config, ... }: +let + host = "vault.srx.digital"; + owner = "vaultwarden"; +in +{ + age.secrets.vaultwarden = { + file = ./secrets.age; + inherit owner; + group = owner; + }; + + environment.etc = { + "fail2ban/filter.d/vaultwarden.conf".text = '' + [INCLUDES] + before = common.conf + + [Definition] + failregex = ^.*Username or password is incorrect\. Try again\. IP: \. Username:.*$ + ignoreregex = + journalmatch = _SYSTEMD_UNIT=vaultwarden.service + ''; + + "fail2ban/filter.d/vaultwarden-admin.conf".text = '' + [INCLUDES] + before = common.conf + + [Definition] + failregex = ^.*Invalid admin token\. IP: .*$ + ignoreregex = + journalmatch = _SYSTEMD_UNIT=vaultwarden.service + ''; + }; + + services = { + vaultwarden = { + enable = true; + + environmentFile = config.age.secrets.vaultwarden.path; + dbBackend = "postgresql"; + + config = { + DOMAIN = "https://${host}"; + SIGNUPS_ALLOWED = false; + + DATABASE_URL = "postgresql://@/${owner}"; + + SMTP_HOST = "mail.srx.digital"; + SMTP_FROM = "no-reply@srx.digital"; + SMTP_USERNAME = "no-reply@srx.digital"; + SMTP_PORT = 465; + SMTP_SSL = true; + SMTP_SECURITY = "force_tls"; + + ROCKET_ADDRESS = "::1"; + ROCKET_PORT = 8812; + + ENABLE_WEBSOCKET = true; + }; + }; + + postgresql = { + enable = true; + ensureDatabases = [ owner ]; + + ensureUsers = [ + { + name = owner; + ensureDBOwnership = true; + } + ]; + }; + + postgresqlBackup.databases = [ owner ]; + + nginx.virtualHosts."${host}" = { + enableACME = true; + forceSSL = true; + + locations."/".proxyPass = "http://[::1]:${toString config.services.vaultwarden.config.ROCKET_PORT}/"; + + locations."/notifications/hub" = { + proxyPass = "http://[::1]:${toString config.services.vaultwarden.config.ROCKET_PORT}/"; + proxyWebsockets = true; + }; + }; + + fail2ban.jails = { + vaultwarden = '' + enabled = true + filter = vaultwarden + port = 80,443,8000 + maxretry = 5 + ''; + + vaultwarden-admin = '' + enabled = true + port = 80,443 + filter = vaultwarden-admin + maxretry = 3 + bantime = 14400 + findtime = 14400 + ''; + }; + + telegraf.extraConfig.inputs = { + x509_cert = [{ + sources = [ "https://${host}:443" ]; + tags.host = host; + interval = "10m"; + }]; + + http_response = [{ + urls = [ "https://${host}" ]; + tags.host = host; + interval = "10m"; + }]; + }; + }; +} diff --git a/hosts/srxgp00/services/vaultwarden/secrets.age b/hosts/srxgp00/services/vaultwarden/secrets.age new file mode 100644 index 0000000..92e3023 --- /dev/null +++ b/hosts/srxgp00/services/vaultwarden/secrets.age @@ -0,0 +1,22 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw qZBccj3l3NXQaKEGeRnn58SvCVdSCoF67tr7TGFvM0Y +H41HjuG8QmApI3qCPzOZB+zqv4PrgAFrX9qu3NuiB/o +-> ssh-ed25519 JzjriQ Gzpr05qnZskY5Vi0p/6RNCKo7EimD+18j2+JNDfBujw +kSsEfpmcCn18N20nJnHDid65DOMojxbJO9RDJNenT/4 +-> ssh-rsa 6hPx7A +ZY88w1W0jRbEMHqUv9Pot7mIXD60z8dL0RfFB588ahbnniBe+0dBUpphMAhGgkY8 +Rpk3ZgM679AOiNSmW7Umv0tgN1YmvuF1fS2OmPb/yQTobLPoVRDQYtn620SclUx8 +7VCNUN7IgiwwzUggTzHedUryEw9yROLFBmPIqB5I5OZWhv3Qw9urVEXgI6WkkFm6 +PkpRwjjiPtgOV2P0GMOK+s1qqne7/IYwhpIGAit1oqTSfP6+BFx1Gmv9a9QvB7tW +AB0cZBRVVmMDZ9e4QDeCvOJgNG3p9G2NIMNOSbMHwaqYbEd52Nu+//YednvuPGU+ +UF/ryHivOQO1moLlsPBD1vEIy/oVYDQPfzKRCHToig/iqXnQnwn3aEE0qK7DJpun +bPVcYUfBzzKKBE00gV27f11Z0njj8Ut94JyaARQkp0LSYz7Wx2YlcUIIWUEMrBHr +RLVEO0mavy983EpxGqZvhm/9f3lsHiJgA9osGOvRMq/kwaKn+XwrFpDLTGJYjQRZ +N3Z0ujxvb2NxhwWGhWOthCi7zRtpMcI5fvivMsvaN3++9jffj021qODoVcGU4z1y +mmM/SyR+KLL7sUzyGpwq/ESQdfjyIpCDgoqi32N2FecvrXC6+1Hxm5DBlsxNMlw9 +9KQu7/V6HbosBY7BkzaqFIiSDJGwi2wsfxL0B4IT8Ac +-> ssh-ed25519 Dfencg mbnAJcIZWV9jB7rsKj/jmWcvXcs+mbpfyVTIXv4VD0k +gg1qVUpCg2lRX3TTty3lsP4TLp81i4MzQNOU1BR3VCA +--- VPEeIrf8pMfnTs65lDhxkd/3b5yKX5DMeoxN2T7PrEY + EҸk,/M&@}]@Z%5duSm3^ų~.PQRQ5\ڶ'Fl:M? QƜ*'WmBnxd~ ))A&!7^ST3J +[{ZPiv_*@SRFu~RO;bW(zE@VnmJ^}*dq#9&ZYV׫G,8cX+9E2Yt:\1b:8TϤBKrwFڇ& E9kUͼƽ%bu,(>lp)] \ No newline at end of file diff --git a/hosts/srxgp00/services/wireguard/default.nix b/hosts/srxgp00/services/wireguard/default.nix new file mode 100644 index 0000000..a80dfa3 --- /dev/null +++ b/hosts/srxgp00/services/wireguard/default.nix @@ -0,0 +1,164 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [ + { + wireguardPeerConfig = { + # srxnas01.vpn.srx.dev + PublicKey = "vXNyMPTm2Gwmu5xwR4NA6neuH849YdTtIzQ03L1IZVY="; + AllowedIPs = [ "10.80.0.2/32" "10.50.0.0/23" ]; + }; + } + { + wireguardPeerConfig = { + # srxws00.vpn.srx.dev + PublicKey = "vi/DohCorqMv8lR8TwI27YM6F9uRggD9T2E5PdbiCBs="; + AllowedIPs = [ "10.80.0.3/32" ]; + }; + } + { + wireguardPeerConfig = { + # srxmc00.vpn.srx.dev + PublicKey = "bxA6bVjEn6UmOizdmujDPe2DxU2iSVJus+FQPdlKJGI="; + AllowedIPs = [ "10.80.0.14/32" ]; + }; + } + { + wireguardPeerConfig = { + # srxnas00.vpn.srx.dev + PublicKey = "kiEzfTU5pWSy7r/RuRXE8/4rnvctebVq1mZ+8BfLzQk="; + AllowedIPs = [ "10.80.0.4/32" "192.168.178.0/24" ]; + }; + } + { + wireguardPeerConfig = { + # srxgp01.vpn.srx.dev + PublicKey = "FFErzX2/KEv/k5FNrp9w7j8+JKz5P+D8WqunoksHxg8="; + AllowedIPs = [ "10.80.0.5/32" ]; + }; + } + { + wireguardPeerConfig = { + # srxgp02.vpn.srx.dev + PublicKey = "WYJaYVzyJTbrOKz3dW8PKl3c6vRcJQx0/AE6LGWRfl4="; + AllowedIPs = [ "10.80.0.6/32" ]; + }; + } + { + wireguardPeerConfig = { + # srxk8s00.vpn.srx.dev + PublicKey = "ukZbSy6XDELBg2jGjnwINr73G7OyT0tmAkVuTKs7zjc="; + AllowedIPs = [ "10.80.0.7/32" ]; + }; + } + { + wireguardPeerConfig = { + # srxws01.vpn.srx.dev + PublicKey = "UszZ79FXBcXllXmRC9/LKw+Qc+fNHvZnCA9+DYdXKx0="; + AllowedIPs = [ "10.80.0.8/32" ]; + }; + } + { + wireguardPeerConfig = { + # srxtab00.vpn.srx.dev + PublicKey = "pYYc6p3KNHMtTPXojK8urO3MURnaG9/wyEg7hOUDUGM="; + AllowedIPs = [ "10.80.0.9/32" ]; + }; + } + { + wireguardPeerConfig = { + # srxfdm00.vpn.srx.dev + PublicKey = "eJ6OhRhTwSyxdT466SQbrjAIMFSZ8C1yVFMEeDxHxSw="; + AllowedIPs = [ "10.80.0.12/32" ]; + }; + } + { + wireguardPeerConfig = { + # srxnb00.srx.digital + PublicKey = "3nWyVTUqkH/6b45FmRV7DKy13wp9g6vgxqL28GFZpFA="; + AllowedIPs = [ "10.80.0.100/32" ]; + }; + } + { + wireguardPeerConfig = { + # copepod.curious.bio + PublicKey = "WTAG/4iEQO1S5H6uwQB2z+r9q8nMkVILILrSnqu23zc="; + AllowedIPs = [ "10.80.0.10/32" ]; + }; + } + { + wireguardPeerConfig = { + # diatome.curious.bio + PublicKey = "lyz3nEnjCMi2fX0HAstSUbfOkXYn6HNgkYz0I6w3r3w="; + AllowedIPs = [ "10.80.0.50/32" "10.10.0.0/24" ]; + }; + } + { + wireguardPeerConfig = { + # opd00.octopod.de + PublicKey = "D3/wnVy1BUgNvSwkhPMoaZIbxycUpjVHByEmlznZj2U="; + AllowedIPs = [ "10.80.0.66/32" ]; + }; + } + ]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.1/24" ]; + routes = [ + { + routeConfig = { + Gateway = "10.80.0.2"; + Destination = "10.50.0.0/23"; + }; + } + { + routeConfig = { + Gateway = "10.80.0.4"; + Destination = "192.168.178.0/24"; + }; + } + { + routeConfig = { + Gateway = "10.80.0.50"; + Destination = "10.10.0.0/24"; + }; + } + ]; + + networkConfig = { + IPMasquerade = "ipv4"; + IPForward = true; + }; + }; + }; + + networking = { + nat = { + enable = true; + externalInterface = "enp9s0"; + internalInterfaces = [ "vpn_srx" ]; + }; + + firewall = { + allowedUDPPorts = [ 51820 ]; + trustedInterfaces = [ "vpn_srx" ]; + }; + }; +} diff --git a/hosts/srxgp00/storage.nix b/hosts/srxgp00/storage.nix new file mode 100644 index 0000000..3ad0d46 --- /dev/null +++ b/hosts/srxgp00/storage.nix @@ -0,0 +1,140 @@ +{ lib, ... }: +let + pool = "rpool"; + disks = [ "/dev/nvme0n1" "/dev/nvme1n1" ]; +in +{ + disko.devices = { + disk = lib.genAttrs disks (device: { + type = "disk"; + inherit device; + content = { + type = "gpt"; + partitions = { + BOOT = { + size = "1M"; + type = "EF02"; + }; + ESP = { + size = "512M"; + type = "EF00"; + content = { + name = "boot"; + type = "mdraid"; + }; + }; + SYSTEM = { + size = "100%"; + content = { + inherit pool; + type = "zfs"; + }; + }; + }; + }; + }); + zpool = { + ${pool} = { + type = "zpool"; + mode = "mirror"; + options = { + ashift = "12"; + autotrim = "on"; + }; + rootFsOptions = { + acltype = "posixacl"; + compression = "zstd"; + normalization = "formD"; + dnodesize = "auto"; + relatime = "on"; + xattr = "sa"; + canmount = "off"; + mountpoint = "none"; + "com.sun:auto-snapshot" = "false"; + }; + mountpoint = null; + datasets = + let + default = mountpoint: { + type = "zfs_fs"; + inherit mountpoint; + mountOptions = [ "X-mount.mkdir" ]; + }; + can_not_mount = { + type = "zfs_fs"; + options = { + canmount = lib.mkForce "off"; + mountpoint = lib.mkForce "none"; + }; + mountpoint = lib.mkForce null; + mountOptions = lib.mkForce [ ]; + }; + in + { + "reserved" = { + type = "zfs_fs"; + options = { + refreservation = "10GiB"; + canmount = lib.mkForce "off"; + mountpoint = lib.mkForce "none"; + }; + mountpoint = lib.mkForce null; + }; + "nixos" = can_not_mount; + "nixos/etc" = default "/etc"; + "nixos/nix" = default "/nix"; + "user" = can_not_mount; + "user/root" = default "/root"; + "user/home" = { + type = "zfs_fs"; + options."com.sun:auto-snapshot" = "true"; + mountpoint = "/home"; + mountOptions = [ "X-mount.mkdir" ]; + }; + "data" = can_not_mount; + "data/log" = default "/var/log"; + "data/lib" = { + type = "zfs_fs"; + options."com.sun:auto-snapshot" = "true"; + mountpoint = "/var/lib"; + mountOptions = [ "X-mount.mkdir" ]; + }; + "data/cache" = default "/var/cache"; + "data/backup" = default "/var/backup"; + }; + }; + }; + nodev = { + "/" = { + fsType = "tmpfs"; + mountOptions = [ + "defaults" + "size=1G" + "mode=755" + ]; + }; + "/tmp" = { + fsType = "tmpfs"; + mountOptions = [ "size=1G" ]; + }; + }; + mdadm = { + boot = { + type = "mdadm"; + level = 1; + metadata = "1.0"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + }; + }; + + virtualisation.containers.storage.settings.storage = { + driver = lib.mkForce "zfs"; + graphroot = "/var/lib/containers/storage"; + runroot = "/run/containers/storage"; + }; +} diff --git a/hosts/srxgp00/vpn_srx.age b/hosts/srxgp00/vpn_srx.age new file mode 100644 index 0000000..b0d8e9a Binary files /dev/null and b/hosts/srxgp00/vpn_srx.age differ diff --git a/hosts/srxgp01/default.nix b/hosts/srxgp01/default.nix new file mode 100644 index 0000000..0bda64f --- /dev/null +++ b/hosts/srxgp01/default.nix @@ -0,0 +1,39 @@ +{ inputs, lib, ... }: +{ + imports = with inputs; [ + self.nixosModules.roles-server + self.nixosModules.filesystems-zfs + self.nixosModules.services-security-tang + self.nixosModules.custom-dns-knot + ./hardware.nix + ./storage.nix + ./services/wireguard.nix + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "srxgp01"; + domain = "srx.digital"; + hostId = "8666b002"; + }; + + systemd.network.networks."10-uplink" = { + matchConfig.Name = "enp3s0"; + networkConfig = { + Address = "2a0a:4cc0:1:131a::1/64"; + DHCP = "ipv4"; + Gateway = "fe80::1"; + IPv6AcceptRA = "no"; + }; + }; + + services.knot.settings.server = { + identity = "ns2.srx.dev"; + listen = lib.mkForce [ + "10.80.0.5@53" + "152.53.17.250@53" + "2a0a:4cc0:1:131a::1@53" + ]; + }; +} diff --git a/hosts/srxgp01/hardware.nix b/hosts/srxgp01/hardware.nix new file mode 100644 index 0000000..e6d027d --- /dev/null +++ b/hosts/srxgp01/hardware.nix @@ -0,0 +1,21 @@ +{ modulesPath, ... }: +{ + imports = [ + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot = { + initrd = { + availableKernelModules = [ + "xhci_pci" + "virtio_scsi" + "sr_mod" + ]; + kernelModules = [ ]; + }; + loader.systemd-boot.enable = true; + zfs.devNodes = "/dev/disk/by-uuid"; + }; + + services.qemuGuest.enable = true; +} diff --git a/hosts/srxgp01/services/wireguard.nix b/hosts/srxgp01/services/wireguard.nix new file mode 100644 index 0000000..1d5ac8d --- /dev/null +++ b/hosts/srxgp01/services/wireguard.nix @@ -0,0 +1,35 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.5/24" ]; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; +} diff --git a/hosts/srxgp01/storage.nix b/hosts/srxgp01/storage.nix new file mode 100644 index 0000000..a609334 --- /dev/null +++ b/hosts/srxgp01/storage.nix @@ -0,0 +1,121 @@ +{ lib, ... }: +let + pool = "rpool"; + disks = [ "/dev/vda" ]; +in +{ + disko.devices = { + disk = lib.genAttrs disks (device: { + type = "disk"; + inherit device; + content = { + type = "gpt"; + partitions = { + BOOT = { + size = "1M"; + type = "EF02"; + }; + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + SYSTEM = { + size = "100%"; + content = { + inherit pool; + type = "zfs"; + }; + }; + }; + }; + }); + zpool = { + ${pool} = { + type = "zpool"; + options = { + ashift = "12"; + autotrim = "on"; + }; + rootFsOptions = { + acltype = "posixacl"; + compression = "zstd"; + normalization = "formD"; + dnodesize = "auto"; + relatime = "on"; + xattr = "sa"; + canmount = "off"; + mountpoint = "none"; + "com.sun:auto-snapshot" = "false"; + }; + mountpoint = null; + datasets = + let + default = mountpoint: { + type = "zfs_fs"; + inherit mountpoint; + mountOptions = [ "X-mount.mkdir" ]; + }; + can_not_mount = { + type = "zfs_fs"; + options = { + canmount = lib.mkForce "off"; + mountpoint = lib.mkForce "none"; + }; + mountpoint = lib.mkForce null; + mountOptions = lib.mkForce [ ]; + }; + in + { + "reserved" = { + type = "zfs_fs"; + options = { + refreservation = "10GiB"; + canmount = lib.mkForce "off"; + mountpoint = lib.mkForce "none"; + }; + mountpoint = lib.mkForce null; + }; + "nixos" = can_not_mount; + "nixos/etc" = default "/etc"; + "nixos/nix" = default "/nix"; + "user" = can_not_mount; + "user/root" = default "/root"; + "user/home" = { + type = "zfs_fs"; + options."com.sun:auto-snapshot" = "true"; + mountpoint = "/home"; + mountOptions = [ "X-mount.mkdir" ]; + }; + "data" = can_not_mount; + "data/log" = default "/var/log"; + "data/lib" = { + type = "zfs_fs"; + options."com.sun:auto-snapshot" = "true"; + mountpoint = "/var/lib"; + mountOptions = [ "X-mount.mkdir" ]; + }; + "data/backup" = default "/var/backup"; + }; + }; + }; + nodev = { + "/" = { + fsType = "tmpfs"; + mountOptions = [ + "defaults" + "size=1G" + "mode=755" + ]; + }; + "/tmp" = { + fsType = "tmpfs"; + mountOptions = [ "size=1G" ]; + }; + }; + }; +} diff --git a/hosts/srxgp01/vpn_srx.age b/hosts/srxgp01/vpn_srx.age new file mode 100644 index 0000000..405df8b --- /dev/null +++ b/hosts/srxgp01/vpn_srx.age @@ -0,0 +1,22 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw WnhWeNKot4zApDkMal8vjIxpmMul39tcmJZF9YJtVj0 +0gwUYEKdSrYO+fq4U70V9W5LugfiLwEzW7bSCPweHsI +-> ssh-ed25519 JzjriQ R1FaxvVeyyqLEPGVdsmaTpWit+QSC5BnS5jqYvPUUkg +6Cwb4mi+EPpk/LzJ7VpApkTD/6MegBjS2rRLtGkzpDU +-> ssh-rsa 6hPx7A +RAXOjZ8LeeFgSdBOS0qD02s68zRcTYWTpulwm10W4eqZB2AbplvZublnG0PNPrYu +lUu2ptHFQq5jfl9YeOZczGcdsuDR82ahrKgtSiAcbvIyswOLxmnE+SVj5TuMIGsE +N8RTGZpT1+ZhdT+QzfiA1BraoaHvND+bRuVpQ6mt6QzZNSsfOSRec2/p88KAGUdR +6nzgqvxvbBZJ9jAz2pmnMSAHJAELgtTMeSdTrpwTJdemUaORXTbOnAFsjMdPoMdV +5x9gRXCk/o+Jl4OBHnVArpRTmEvt719SLMYDqQuYzVbaOGBZ6dcZ1Hzf1K65o4HZ +LMNorjzSkrCTMmtL3jG8fKcyc3rQK6RWA7OJayVcf5fVkoPA/JLuHqjKND/0lMem +bXNEtaeMjfizVFf90f/wzzIdfOkSQW+gzMcSbIlliZZ4mGrgYByfVuUwfR84mAP4 +jThEtSJPc+VujTL9PCHyw8li5TvhdBmPPFfzWUpWCE2lqjtCXBZNtNzFBoy5z/k4 +2i6U19uN1Fi2waKAkYoy07/etMez90Q8k/e3M4AzIHwnP1X1NDWM5AofI8Srr1pX +8+kZbf2c+/zTa5HlfOzew1/c3rSbqeqUwtKNPrPn0ge0TUnRhjauq+3rIgqVPQfU +/Jv9u2hyiJynIbV2kwFHLwpb/rddRYeXR5jH1tz7etA +-> ssh-ed25519 OWgoVA JEXll+XDPdskWuqvYB2i4mtgaj6aI+Ers3I4Q+5Ysmc +qsTvL91fYwCg7WBfe1LIDDc5jZtUkwj2l/PUk6PlXPw +--- 4O0bS87UH3sI7wO4FnsKPnEIvG114VccYplGIRrCSMY +OSMf!YLY6Z!C3̢ +朗Y!o#(*Jc=}{r&V: \ No newline at end of file diff --git a/hosts/srxgp02/default.nix b/hosts/srxgp02/default.nix new file mode 100644 index 0000000..6ec9fea --- /dev/null +++ b/hosts/srxgp02/default.nix @@ -0,0 +1,37 @@ +{ inputs, lib, ... }: +{ + imports = with inputs; [ + self.nixosModules.roles-server + self.nixosModules.services-security-tang + self.nixosModules.custom-dns-knot + ./hardware.nix + ./storage.nix + ./services/wireguard.nix + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "srxgp02"; + domain = "srx.digital"; + }; + + systemd.network.networks."10-uplink" = { + matchConfig.Name = "ens6"; + networkConfig = { + Address = "2a02:247a:275:9300::1/128"; + DHCP = "ipv4"; + Gateway = "fe80::1"; + IPv6AcceptRA = "no"; + }; + }; + + services.knot.settings.server = { + identity = "ns3.srx.dev"; + listen = lib.mkForce [ + "10.80.0.6@53" + "212.132.77.48@53" + "2a02:247a:275:9300::1@53" + ]; + }; +} diff --git a/hosts/srxgp02/hardware.nix b/hosts/srxgp02/hardware.nix new file mode 100644 index 0000000..c92a05c --- /dev/null +++ b/hosts/srxgp02/hardware.nix @@ -0,0 +1,16 @@ +{ inputs, ... }: +{ + imports = with inputs; [ + self.nixosModules.hardware-cpu-amd + ]; + + boot.initrd = { + availableKernelModules = [ + "ata_piix" + "uhci_hcd" + "virtio_pci" + "virtio_blk" + ]; + kernelModules = [ ]; + }; +} diff --git a/hosts/srxgp02/services/wireguard.nix b/hosts/srxgp02/services/wireguard.nix new file mode 100644 index 0000000..3a8f924 --- /dev/null +++ b/hosts/srxgp02/services/wireguard.nix @@ -0,0 +1,35 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.6/24" ]; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; +} diff --git a/hosts/srxgp02/storage.nix b/hosts/srxgp02/storage.nix new file mode 100644 index 0000000..7d6465c --- /dev/null +++ b/hosts/srxgp02/storage.nix @@ -0,0 +1,93 @@ +{ lib, ... }: +let + disks = [ "/dev/vda" ]; +in +{ + disko.devices = { + disk = lib.genAttrs disks (device: { + name = lib.last (lib.splitString "/" device); + inherit device; + content = { + type = "gpt"; + partitions = { + BOOT = { + size = "1M"; + type = "EF02"; + }; + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + SYSTEM = { + size = "100%"; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + subvolumes = { + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/var" = { + mountpoint = "/var"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/etc" = { + mountpoint = "/etc"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/root" = { + mountpoint = "/root"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/home" = { + mountpoint = "/home"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }); + nodev = { + "/" = { + fsType = "tmpfs"; + mountOptions = [ + "size=512M" + "mode=755" + "noatime" + ]; + }; + "/tmp" = { + fsType = "tmpfs"; + mountOptions = [ "size=512M" ]; + }; + }; + }; +} diff --git a/hosts/srxgp02/vpn_srx.age b/hosts/srxgp02/vpn_srx.age new file mode 100644 index 0000000..f7b8989 --- /dev/null +++ b/hosts/srxgp02/vpn_srx.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw 7ynUC8MwwumjA2zybiAhqeGcvxOMJ61okSqJaMOe5ms +tzk+xLLRYFeQ3Mjti8UpHPil3DdSqhwzarClsoxfvF0 +-> ssh-ed25519 JzjriQ oLtd6Vmsf1m9odSHk5uq0vW9bmv7BjPnjw/v/NQoGhg ++wmkgZvLkvW6W5GaCHvFuBo4EfxfrEEHO5Prc/9YeQw +-> ssh-rsa 6hPx7A +rI3QyXZF476fOotDKZrpyA/unO6V44THBYnUBhlMMsudwk+FGYkPNMrzg4Yb+PPI +W9BJpT6qv+xEfRdLstwQQlopSX1TB1uEQEh3wsG3cyGKY46wzgPkivWIXTvPJSRh +fi/b5UgAqMjDJ7kyr9/iY1WlkW2t5MpEi52lSG75JehR1H77EJ3nFvW4wh0bVhfv +9zkRuLp0qEpn/lUUu7ZXDeKyA4926ktSEv+osraxdeFf5bgJcjhpxb9Xhawm6tko +q2afnfBGwFhDLgcoJT/nKdRyJPzfVCW5Ly6w6d8wWJ6DO7oYj9uA2DDaht6WSdt7 +5j+J2T3IPuaqiL60ZSjhsLs7xmFqDUIffe3ISjXVHwm/hqw7SwnjIO2AE0ZuPheL +sno093olsaxcB1KqjE69UZjYZTwe6rBzv3Ex+7r5Eon4nyj7zNLM3/+FTHGeJ7wy +5LQeCHvGjL21XV0OIibQpCBzp1+UvWMx1iIonV3ZDeo63fF5wgFruqVTzYlzPZ0Y +X9CRT986o5Slkkbn8R3qLv1NQ43nj2kOAuKmyHQD7KjzFILnaHfEj9SfBJO7gj09 +vln8/i8JJWmtEtGSQsM5w0nUyg1XO+deBogtYwGZuR3cMbTQ3Sx/l7B6/04zG9Eq +p7TbZQroYTiCpN+1sFM+CU5+IH6suTm/V5ceSaA3lms +-> ssh-ed25519 aP/BWw 3iooFYwuEefd1N+jLMQ3sYiQq0XBmX2azY0eXrOFl0Q +ELLsGeEcX5ogjfFWY1701v4Ivtvq/hziRUPHSv6rChE +--- OT8IzDy21tnteI84bMhLrPMmX/hzYZIf/dv8wqYtiBE +O2+0w }Kz@"7 Ve?:?˹WO <!1<B \ No newline at end of file diff --git a/hosts/srxk8s00/default.nix b/hosts/srxk8s00/default.nix new file mode 100644 index 0000000..56724c3 --- /dev/null +++ b/hosts/srxk8s00/default.nix @@ -0,0 +1,29 @@ +{ inputs, ... }: +{ + imports = with inputs; [ + self.nixosModules.roles-server + self.nixosModules.filesystems-zfs + ./hardware.nix + ./storage.nix + ./services/wireguard.nix + ./services/k3s.nix + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "srxk8s00"; + domain = "srx.digital"; + hostId = "8585b085"; + }; + + systemd.network.networks."10-uplink" = { + matchConfig.Name = "enp1s0"; + networkConfig = { + Address = "2a01:4f8:1c0c:5214::1/64"; + DHCP = "ipv4"; + Gateway = "fe80::1"; + IPv6AcceptRA = "no"; + }; + }; +} diff --git a/hosts/srxk8s00/hardware.nix b/hosts/srxk8s00/hardware.nix new file mode 100644 index 0000000..d03af2c --- /dev/null +++ b/hosts/srxk8s00/hardware.nix @@ -0,0 +1,19 @@ +{ modulesPath, ... }: +{ + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot = { + initrd = { + availableKernelModules = [ + "sr_mod" + "virtio_scsi" + "xhci_pci" + ]; + kernelModules = [ ]; + }; + loader.systemd-boot.enable = true; + }; +} diff --git a/hosts/srxk8s00/services/k3s.nix b/hosts/srxk8s00/services/k3s.nix new file mode 100644 index 0000000..fb28ea2 --- /dev/null +++ b/hosts/srxk8s00/services/k3s.nix @@ -0,0 +1,39 @@ +{ self, lib, config, ... }: +{ + imports = [ self.nixosModules.services-container-k3s ]; + + services.k3s = { + enable = true; + role = "server"; + extraFlags = toString [ + "--tls-san=k8s.vpn.srx.dev" + "--cluster-domain=k8s.vpn.srx.dev" + + "--bind-address=10.80.0.7" + "--advertise-address=10.80.0.7" + "--cluster-cidr=10.42.0.0/16,2001:cafe:42::/56" + "--service-cidr=10.43.0.0/16,2001:cafe:43::/112" + "--node-external-ip=78.46.220.70,2a01:4f8:1c0c:5214::1" + # "--node-external-ip=10.80.0.7,78.46.220.70,2a01:4f8:1c0c:5214::1" + + "--container-runtime-endpoint unix:///run/containerd/containerd.sock" + "--write-kubeconfig-mode 644" + + "--disable traefik" + + "--snapshotter=zfs" + "--node-label storage.os.srx.digital/fs=zfs" + + "--node-label os.srx.digital/release=${config.system.nixos.release}" + "--node-label os.srx.digital/codename=${config.system.nixos.codeName}" + "--node-label os.srx.digital/version=${config.system.nixos.version}" + "--node-label os.srx.digital/kernel=${config.boot.kernelPackages.kernel.version}" + ]; + }; + + virtualisation.containers.storage.settings.storage = { + driver = lib.mkForce "zfs"; + graphroot = "/var/lib/containers/storage"; + runroot = "/run/containers/storage"; + }; +} diff --git a/hosts/srxk8s00/services/wireguard.nix b/hosts/srxk8s00/services/wireguard.nix new file mode 100644 index 0000000..61212b8 --- /dev/null +++ b/hosts/srxk8s00/services/wireguard.nix @@ -0,0 +1,35 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.7/24" ]; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; +} diff --git a/hosts/srxk8s00/storage.nix b/hosts/srxk8s00/storage.nix new file mode 100644 index 0000000..80ba3d8 --- /dev/null +++ b/hosts/srxk8s00/storage.nix @@ -0,0 +1,122 @@ +{ lib, ... }: +let + disks = [ "/dev/sda" ]; + pool = "rpool"; +in +{ + disko.devices = { + disk = lib.genAttrs disks (device: { + type = "disk"; + inherit device; + content = { + type = "gpt"; + partitions = { + BOOT = { + size = "1M"; + type = "EF02"; + }; + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + SYSTEM = { + size = "100%"; + content = { + inherit pool; + type = "zfs"; + }; + }; + }; + }; + }); + zpool = { + ${pool} = { + type = "zpool"; + options = { + ashift = "12"; + autotrim = "on"; + }; + rootFsOptions = { + acltype = "posixacl"; + compression = "zstd"; + normalization = "formD"; + dnodesize = "auto"; + relatime = "on"; + xattr = "sa"; + canmount = "off"; + mountpoint = "none"; + "com.sun:auto-snapshot" = "false"; + }; + mountpoint = null; + datasets = + let + default = mountpoint: { + type = "zfs_fs"; + inherit mountpoint; + mountOptions = [ "X-mount.mkdir" ]; + }; + can_not_mount = { + type = "zfs_fs"; + options = { + canmount = lib.mkForce "off"; + mountpoint = lib.mkForce "none"; + }; + mountpoint = lib.mkForce null; + mountOptions = lib.mkForce [ ]; + }; + in + { + "reserved" = { + type = "zfs_fs"; + options = { + refreservation = "10GiB"; + canmount = lib.mkForce "off"; + mountpoint = lib.mkForce "none"; + }; + mountpoint = lib.mkForce null; + }; + "nixos" = can_not_mount; + "nixos/etc" = default "/etc"; + "nixos/nix" = default "/nix"; + "user" = can_not_mount; + "user/root" = default "/root"; + "user/home" = { + type = "zfs_fs"; + options."com.sun:auto-snapshot" = "true"; + mountpoint = "/home"; + mountOptions = [ "X-mount.mkdir" ]; + }; + "data" = can_not_mount; + "data/log" = default "/var/log"; + "data/lib" = { + type = "zfs_fs"; + options."com.sun:auto-snapshot" = "true"; + mountpoint = "/var/lib"; + mountOptions = [ "X-mount.mkdir" ]; + }; + "data/backup" = default "/var/backup"; + "data/containerd" = default "/var/lib/containerd/io.containerd.snapshotter.v1.zfs"; + }; + }; + }; + nodev = { + "/" = { + fsType = "tmpfs"; + mountOptions = [ + "defaults" + "size=1G" + "mode=755" + ]; + }; + "/tmp" = { + fsType = "tmpfs"; + mountOptions = [ "size=1G" ]; + }; + }; + }; +} diff --git a/hosts/srxk8s00/vpn_srx.age b/hosts/srxk8s00/vpn_srx.age new file mode 100644 index 0000000..f51c104 --- /dev/null +++ b/hosts/srxk8s00/vpn_srx.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw 9YryRmhy0lZrVhxChemltvwGdT4lsuK/RDWMtrNMU3E +S7VLEgSKYjdOuhUbdPQz4ZrqV6z8m5bSBHD0Zmw9PFQ +-> ssh-ed25519 JzjriQ fonWi7/x79+GFQcEks0aL9lN3pO4DE5tUsAPX5SlbT0 +EHdq9DobUfdnPKllFJCsoIDrVowDehX8iOpboLZO39I +-> ssh-rsa 6hPx7A +AcBhB3wNfGw2NnFAUd8Q3YhhJdv3PXGvqtqJiG+YnPz6c4Grh4aEQTDwG1KX746Q +qdMY8Ex5vhPfuuo9Tss3Cx7iaSf+ZpeiP7Y1jVVBdU3p+MQbBkTTrMHA/soE/D1c +7v2k7c4e23sSGOhQhS5dtTlbaGOaOHHxUoTKPUM5BoViPNA2Hg2dKst13jd+OxEN +reWNs9RMIkU9qq2Q3zcil3SYQW1JxWSG49TCd/k54w7cokUy9zbCxBR625RE9Jo6 +1aPdNRPfJG516uyKUFgrpu++4eagnr07UhlbeFzHwxjdldU5dE+9sTFzdCaHQ+Gt +2QXbzV6LXuRaXrkA533B7eJW+Zdh/GIdp56YYHFQiVydeZ2frqBnyz8wBiQhB2Xx +ayoZjUJtLbyzNrJH7Sf1QxA9Wm58DUccZG/cqTbOSTUNOLNWDxgjxvL+lv1eIsKQ +xD+FMKIJp76PWFD/hUaBJTlLyQsHH4QZAH5/lR2LToJ3FpRvsRq/SueW46D7K6fe +sulRIU7+aRv7EnS+q+MBTT9UUwn4YH90bJiLACqXnneqpz7A5vrzSRS6Qz21SijN +LblSstibPzRHD9XsQeKJds7RHX0FJBwxIL8kkF+lz4aaWyKrjo9yIEBM30zgKnop +tfXAfv8gUXarOMRfS0ejEFkZKGqjWmd1ihNVC3V4On4 +-> ssh-ed25519 v+/Ozg q+s4IJMnprnuqLVVJMyqy52e570rSsmA2DL7CJkuMHw +2p4781Rf32IcOVW/Jpw7RwULbo5uOPVI40dkXLvIzoU +--- OaFcaS6xsFWh6frrV9qit8HD/O8WD95KOMPJYAgXydY +gsk~);A~W\Q"ln?:^/C/n\կĖ-.e&T߮6C{&~[it \ No newline at end of file diff --git a/hosts/srxmc00/cifs_nas.age b/hosts/srxmc00/cifs_nas.age new file mode 100644 index 0000000..6d4301c --- /dev/null +++ b/hosts/srxmc00/cifs_nas.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw yIGqiRUQgfQjhMntccdHKN2JVQrXU/PX7h7H+Ir2CH8 +tHODqdTUtQd9NqR1HnmcLVhDEp3GfZyyOL/6+DYpUOE +-> ssh-ed25519 JzjriQ C7anMW0cKyRi9K6rAhVg6j0of2yTk/VHYKJg7dHbzmk +bk0qIXglNi8DeH7v3ulgwJLoDHBlst6ph+tiyOGv8k4 +-> ssh-rsa 6hPx7A +PzF2gOmBtoPNPTgyyKFMGjMOGbKs3VgpJJNKx9lY/nFyqTV5u3PPKwG9ngAkc2Ne +u2jLdir3SQkmOSTXXLmQTKRdMoZuyneDlhFvfgdfI/4v9FN71vPXuq7qIY+SfuL3 +qTUp0YlILc66TrWJnOqXv3R3wvEsbRxeGj1rMAK3axOAN+gMjdoUUX6xJG49DT2J +oslfBAxdcoNxrtlsBCI4p+FtPULOqMJelQCYAT8a8TJLdZjXqlCbCCu6ULy20fsd +8xSuSVcs81c2lk0wsav9uqBWRJcphmvS2IrFMY9EiHlcaTYJIwS50pl36ZY6ylLa +d8FtmrjQT2SWkifWPgCx4MaHPPu5MfvqvGNyAIn+5K3fari45HAqekVY7QEQcytU +/cxnt40EPt2Xxe6xZBhSrd7Aw2dIKAf06pdfU0WsmV0UZFM6cwzqMbQ+sh0sNsR8 +p4IyNaU21RAod4xGPORImqGwzMVFLG7HLI9PMECoyVVYsEkZWIE5tSazjrzcc8ik +FA6ORpaHObs0vF+GGzH80W3O2HBDHIxClkb1KdNtNK6+Joh0vrBex0BV+KMYCBPD +PSCPD8ybikK75dDsB80Yfqh3Ek62n5rlN3a2LAYrm68CT8jGrn3yUY/ROxE0Eril +yq+dn7qy43Fc7WXeP89qS9VF2kSc7tyG8YYYuXSryK8 +-> ssh-ed25519 5VC2zg tadTAjVvntLemams1E9SRD9BFWiL7UxkNYp/7pAqyzU +qxPmYHFc3h+YLprMxBZEZFYoNrSEJbTIZtWSyCftHB4 +--- YU8k/iMQJjFmYA+LQa8I9EJs/h1R8m3mkJskVKUal9Y +Ej_2lEpH[|Xj]R/IS^DASMjGe"DBmv \ No newline at end of file diff --git a/hosts/srxmc00/default.nix b/hosts/srxmc00/default.nix new file mode 100644 index 0000000..8d29223 --- /dev/null +++ b/hosts/srxmc00/default.nix @@ -0,0 +1,32 @@ +{ lib, self, ... }: +{ + imports = [ + self.nixosModules.hardware + self.nixosModules.roles-media-center + ./hardware.nix + ./storage.nix + ./networking/wireguard.nix + ./networking/wireless.nix + ./services/mounts + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "srxmc00"; + domain = "srx.digital"; + networkmanager.enable = lib.mkForce false; + }; + + systemd.network = { + enable = true; + networks."10-wan" = { + matchConfig.Name = "enp1s0"; + networkConfig.DHCP = "ipv4"; + }; + networks."11-wifi" = { + matchConfig.Name = "wlp0s12f0"; + networkConfig.DHCP = "ipv4"; + }; + }; +} diff --git a/hosts/srxmc00/hardware.nix b/hosts/srxmc00/hardware.nix new file mode 100644 index 0000000..8480f00 --- /dev/null +++ b/hosts/srxmc00/hardware.nix @@ -0,0 +1,38 @@ +{ lib, config, self, inputs, ... }: +{ + imports = with inputs; [ + self.nixosModules.hardware + self.nixosModules.hardware-cpu-intel + # self.nixosModules.hardware-gpu-intel + self.nixosModules.hardware-bluetooth + self.nixosModules.hardware-security-secureboot + srvos.nixosModules.mixins-systemd-boot + ]; + + boot = { + initrd = { + availableKernelModules = [ + "ahci" + "nvme" + "sd_mod" + "usb_storage" + "usbhid" + "xhci_pci" + "r8169" + ]; + kernelModules = [ ]; + systemd = { + enable = true; + inherit (config.systemd) network; + }; + clevis.enable = true; + }; + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + }; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + powerManagement.cpuFreqGovernor = "performance"; +} diff --git a/hosts/srxmc00/networking/wireguard.nix b/hosts/srxmc00/networking/wireguard.nix new file mode 100644 index 0000000..e628bd3 --- /dev/null +++ b/hosts/srxmc00/networking/wireguard.nix @@ -0,0 +1,35 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.14/24" ]; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; +} diff --git a/hosts/srxmc00/networking/wireless.nix b/hosts/srxmc00/networking/wireless.nix new file mode 100644 index 0000000..af1f5c9 --- /dev/null +++ b/hosts/srxmc00/networking/wireless.nix @@ -0,0 +1,12 @@ +{ config, ... }: +{ + age.secrets.wifiClient.file = ../wifi_client.age; + + networking.wireless = { + enable = true; + networks."@SSID@".psk = "@PASSWD@"; + environmentFile = config.age.secrets.wifiClient.path; + }; + + services.telegraf.extraConfig.inputs.wireless = { }; +} diff --git a/hosts/srxmc00/services/mounts/default.nix b/hosts/srxmc00/services/mounts/default.nix new file mode 100644 index 0000000..6c3e1b4 --- /dev/null +++ b/hosts/srxmc00/services/mounts/default.nix @@ -0,0 +1,48 @@ +{ + + age.secrets.cifsNas.file = ../../cifs_nas.age; + + fileSystems = { + "/mnt/movies" = { + device = "//192.168.178.71/movies"; + fsType = "cifs"; + options = [ + "noauto" + "X-mount.mkdir" + "x-systemd.automount" + "x-systemd.device-timeout=5s" + "x-systemd.idle-timeout=60" + "x-systemd.mount-timeout=5s" + "credentials=/run/agenix/cifsNas" + ]; + }; + + "/mnt/videos" = { + device = "//192.168.178.71/videos"; + fsType = "cifs"; + options = [ + "noauto" + "X-mount.mkdir" + "x-systemd.automount" + "x-systemd.device-timeout=5s" + "x-systemd.idle-timeout=60" + "x-systemd.mount-timeout=5s" + "credentials=/run/agenix/cifsNas" + ]; + }; + + "/mnt/music" = { + device = "//192.168.178.71/music"; + fsType = "cifs"; + options = [ + "noauto" + "X-mount.mkdir" + "x-systemd.automount" + "x-systemd.device-timeout=5s" + "x-systemd.idle-timeout=60" + "x-systemd.mount-timeout=5s" + "credentials=/run/agenix/cifsNas" + ]; + }; + }; +} diff --git a/hosts/srxmc00/storage.nix b/hosts/srxmc00/storage.nix new file mode 100644 index 0000000..8aed04e --- /dev/null +++ b/hosts/srxmc00/storage.nix @@ -0,0 +1,98 @@ +{ lib, ... }: +let + disks = [ "/dev/disk/by-id/wwn-0x5000000000002b6f" ]; +in +{ + disko.devices = { + disk = lib.genAttrs disks (device: { + name = lib.last (lib.splitString "/" device); + inherit device; + content = { + type = "gpt"; + partitions = { + ESP = { + label = "EFI"; + name = "ESP"; + type = "EF00"; + start = "1MiB"; + end = "512MiB"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + SYSTEM = { + size = "100%"; + content = { + type = "luks"; + name = "crypted"; + passwordFile = "/etc/hostname"; + settings.allowDiscards = true; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + subvolumes = { + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/var" = { + mountpoint = "/var"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/etc" = { + mountpoint = "/etc"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/root" = { + mountpoint = "/root"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/home" = { + mountpoint = "/home"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }; + }); + nodev = { + "/" = { + fsType = "tmpfs"; + mountOptions = [ + "size=1G" + "mode=755" + "noatime" + ]; + }; + "/tmp" = { + fsType = "tmpfs"; + mountOptions = [ "size=1G" ]; + }; + }; + }; +} diff --git a/hosts/srxmc00/vpn_srx.age b/hosts/srxmc00/vpn_srx.age new file mode 100644 index 0000000..67ad1f4 Binary files /dev/null and b/hosts/srxmc00/vpn_srx.age differ diff --git a/hosts/srxmc00/wifi_client.age b/hosts/srxmc00/wifi_client.age new file mode 100644 index 0000000..92febae --- /dev/null +++ b/hosts/srxmc00/wifi_client.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw EDyZ7jbudtHWerEUwUIU0yR7j/84bgbO1BVmWnpKmBc +F4k9tOk3YW/VSv73wAU6soKNOTyMfzanzDzIVtkFABc +-> ssh-ed25519 JzjriQ GqJXNeK19JpRtrvhfvoBUa03YMGbLyf472pbch6Kl0Y +iW9UlEX3033xeU9QQWJsEUAf8u+cay9ON/CdZbEo8bo +-> ssh-rsa 6hPx7A +2L6MeBaDoNQx1xH7oDrjZ4j8WNtmqS99lR7ow7SEuf3mGBv0cka9qnv865LRE49K +NPRhZPXO+p6laL8l3dRNnT3lKKLPMe0EMzJBO+ZlclHBet0Gq4d1Op1UqDrS11rq +sBnfs8GxQuY/6KEarY/0wz53HFSv3zv3mD3Cq8TTYzJMe8jPBJAXpkwjG5uWltw8 +e0YOfUBbilYpE7B11Fg8r1516nno30qnr+cDAJWZLY4QxymX41sUiToiYrAM0THn +xFWtU8kWhkfNAgREU3zLQ4vZTay0Qbw7oKzUhBHByjxKEsanythS5x+JyV+KHsZw +ZJtSAAmeZ4E0Wh69hvFXqZewe9vFf2gqFbcGxSevPrHzhdHXucnbC1nO4OQloPZU +Pst9Iu428bcT8QAK5M4G4UN7rrPMVzntMmUI8XsyFECRA9i/nRGVSEGXb9FxlLeF +UqFHnI5NowTCR5HMfZt2ZiEhVICN1r86nZdgWauWp4kpAWWk5yyc/bOEp56ZJCwy +56jD4x/hViJygevfEbqBPINzI9w3AK4TTdGqOaXK3w93NQN2TlfY5EN70cw7HqvU +vmkhKcuSbozgCRs9YsxwCt+CMD89Xlltn4U/6o/QLTqGjCS2khTHBxkV8R8T4XUc +rCOsmeRsVqddlcVf3CSs6xNcAwJKwtugOdeRKWFm/zA +-> ssh-ed25519 5VC2zg di3NQcPdTUlFG7Kb6TaNAHvVPf32TE8tLV88QEkqa1g +4MYQ3nB2NUfzgciXO1cQuh3U5aJwhlv1brXZYtJ657c +--- lp5sWjUswhDxr4XUvMf/eTDrDdXUmrf6PNWZd1aPi4E +h%K7..,̿<1/5I‰x/7(N}qWbPhDѻ "M,t/,@Z0٤}m\ \ No newline at end of file diff --git a/hosts/srxnas00/default.nix b/hosts/srxnas00/default.nix new file mode 100644 index 0000000..8d51dd2 --- /dev/null +++ b/hosts/srxnas00/default.nix @@ -0,0 +1,42 @@ +{ self, ... }: +{ + imports = [ + self.nixosModules.hardware + self.nixosModules.roles-nas + self.nixosModules.roles-desktop + self.nixosModules.services-security-tang + ./hardware.nix + ./storage.nix + ./network/wireguard + ./network/knsupdate + ./storage/nfs + ./services/apcupsd + ./services/mosquitto + ./services/home-assistant + ./services/zigbee2mqtt + ./services/rtl-sdr + ./services/minidlna + ./services/jellyfin + ./services/vdr + ./services/netboot + ./services/vault + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "srxnas00"; + domain = "srx.digital"; + hostId = "4e34e4ef"; + }; + + systemd.network = { + enable = true; + networks."10-uplink" = { + matchConfig.Name = "enp1s0"; + networkConfig.DHCP = "ipv4"; + }; + }; + + systemd.oomd.enable = false; +} diff --git a/hosts/srxnas00/dns_update.age b/hosts/srxnas00/dns_update.age new file mode 100644 index 0000000..9978a80 --- /dev/null +++ b/hosts/srxnas00/dns_update.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw E4NgDWizGATiF5OHbAb5hgyj5Pam8tF+KvGKZV4Wngc +Jkc7H++MW6C4VAT17Ja5VrK/+S1id3Yxqchw9fW8/1w +-> ssh-ed25519 JzjriQ onB8XvHpoFBqq70He+Q5RGT+6125pNuuyX2oFJs692c +1E1naGOAQmxnrW3MgTeLze8JgU0wOi+cISVhpQx16BE +-> ssh-rsa 6hPx7A +ETBzZkMgH60pQxGyXdQfrFwOIU02nDdaC31ton0vBvEdY7EQ9x1EwfwG5GAKnS4M +WtUnOdOqPC2W0i8MSOnbODk9nNbZAyxVP0wn4N3RimFjgWNOY2QO0gzTI+tA7MIl +prFIwSn9QRYzcBkQSQ1aNVjOZ/xc920YCNHDfXyUkPad6I5qAKXbHjd+kg01pTTE +OkGuBuxlX6jNbsjtPHDRCynWwFlOSjIzaEeYSN1qLDwocAMnVej3aVZtLFUkQCOn +LXXBUHJv9IYWW0TAmYeltL23a/IgNN7cBnecclXz4bGDNS6MX/gF8OPFgwvufn9A +3v8Bd6RlKmSt1gg6q/k3Kb68GIGrgV+dh03Gwv7Scam3/RclCaVx8ll2bvXRtdbf +nfreO7A19g5PK8U2I2FgItLuK0F6D7cc8NB3soZ2gGQnB5uqU4UIV+zzapC4ZvSX +S/xJN9mSwDgVfoKYfoux+u8dB+BoRICm3VZMoVZ3RsfeHXOMja0Mb03Q0ikuO7A2 +TvHxvQqiUzAtP0+I9rznHlzWgNybQTqob5pOkd7ZM3K36OfXg9sDA8vyuNaEOu5b +cqIUi3ZF8ibN6toclyYa/Cv02WKxhLAK3k5mgdMMOEvAXn1SOaJA2nyhAyS/zekp +UWOSUBjGR61FK5YsW9JAM2rXHNyhTtj6Cn++lvUJeKw +-> ssh-ed25519 ZeuIrQ X6hyEa0SQYh1S7fT1D60jXjtAYkzFM5hcoQGGAn1zSE +seXKUxh6t60VfFc+Uf6JUemeotHhK9LGjbkbXNXQcJo +--- MymLkRE7ZVLzdgiwVcBhQCCTroE+Lx02mpY70TEc6H8 +BC4@4px6qLOWFlSQ9Vkr_p{CxRn׻AU.SYnhΩH&lX' \ No newline at end of file diff --git a/hosts/srxnas00/hardware.nix b/hosts/srxnas00/hardware.nix new file mode 100644 index 0000000..f7ef28f --- /dev/null +++ b/hosts/srxnas00/hardware.nix @@ -0,0 +1,39 @@ +{ self, inputs, config, modulesPath, ... }: +{ + imports = with inputs; [ + (modulesPath + "/installer/scan/not-detected.nix") + self.nixosModules.hardware + self.nixosModules.hardware-cpu-intel + # self.nixosModules.hardware-gpu-intel + self.nixosModules.hardware-security-secureboot + self.nixosModules.filesystems-zfs + srvos.nixosModules.mixins-systemd-boot + ]; + + boot = { + initrd = { + availableKernelModules = [ + "ahci" + "nvme" + "sd_mod" + "usb_storage" + "usbhid" + "xhci_pci" + "r8169" + ]; + kernelModules = [ ]; + systemd = { + enable = true; + inherit (config.systemd) network; + }; + network.enable = true; + clevis.enable = true; + }; + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + }; + + powerManagement.cpuFreqGovernor = "powersave"; +} diff --git a/hosts/srxnas00/network/knsupdate/default.nix b/hosts/srxnas00/network/knsupdate/default.nix new file mode 100644 index 0000000..758c9fa --- /dev/null +++ b/hosts/srxnas00/network/knsupdate/default.nix @@ -0,0 +1,16 @@ +{ config, ... }: +{ + age.secrets.knsupdate = { + file = ../../dns_update.age; + owner = config.users.users.knsupdate.group; + }; + + srx.service.knsupdate = { + enable = true; + server = "dns.vpn.srx.dev"; + ttl = 120; + ipVersions = [ 4 ]; + interval = "*:0/1"; + keyFile = config.age.secrets.knsupdate.path; + }; +} diff --git a/hosts/srxnas00/network/wireguard/default.nix b/hosts/srxnas00/network/wireguard/default.nix new file mode 100644 index 0000000..5bfa835 --- /dev/null +++ b/hosts/srxnas00/network/wireguard/default.nix @@ -0,0 +1,36 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" "192.168.178.0/24" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.4/24" ]; + networkConfig.IPForward = true; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; +} diff --git a/hosts/srxnas00/networking/default.nix b/hosts/srxnas00/networking/default.nix new file mode 100644 index 0000000..a6e51b1 --- /dev/null +++ b/hosts/srxnas00/networking/default.nix @@ -0,0 +1,68 @@ +{ + imports = [ + ./wireguard/srx.nix + ./wireless.nix + # ./networks/op.nix + # ./networks/wan.nix + # ./networks/usr.nix + # ./networks/dmz.nix + # ./networks/gst.nix + # ./wireguard/mullvad.nix + # ./dns/knsupdate.nix + # ./dns/blocky.nix + # ./kea + ]; + + networking.useNetworkd = true; + + systemd.network = { + enable = true; + # netdevs = { + # bond0 = { + # netdevConfig = { + # Kind = "bond"; + # Name = "bond0"; + # }; + # bondConfig = { + # Mode = "802.3ad"; + # LACPTransmitRate = "fast"; + # TransmitHashPolicy = "layer3+4"; + # DownDelaySec = 0.2; + # UpDelaySec = 0.2; + # MIIMonitorSec = 0.1; + # }; + # }; + # }; + + networks = { + enp2s0 = { + matchConfig.Name = "enp2s0"; + matchConfig.MACAddress = "00:1e:06:45:12:27"; + address = [ "192.168.178.10/24" ]; + routes = [ + { routeConfig.Gateway = "192.168.178.1"; } + { routeConfig.Gateway = "fe80::1"; } + ]; + bridgeConfig = { }; + linkConfig.RequiredForOnline = "routable"; + }; + + # enp2s0 = { + # # matchConfig.MACAddress = "00:1e:06:45:12:27"; + # # networkConfig.Bond = "bond0"; + # networkConfig.LinkLocalAddressing = "no"; + # }; + + # enp3s0 = { + # matchConfig.MACAddress = "00:1e:06:45:12:28"; + # networkConfig.Bond = "bond0"; + # }; + + # bond0 = { + # matchConfig.Name = "bond0"; + # linkConfig.RequiredForOnline = "carrier"; + # networkConfig.LinkLocalAddressing = "no"; + # }; + }; + }; +} diff --git a/hosts/srxnas00/networking/dns/blocky.nix b/hosts/srxnas00/networking/dns/blocky.nix new file mode 100644 index 0000000..2d3a0c5 --- /dev/null +++ b/hosts/srxnas00/networking/dns/blocky.nix @@ -0,0 +1,123 @@ +{ config, ... }: +{ + networking.firewall.interfaces = { + br_usr = { + allowedUDPPorts = [ config.services.blocky.settings.ports.dns ]; + allowedTCPPorts = [ config.services.blocky.settings.ports.dns ]; + }; + }; + + # networking.firewall.extraCommands = '' + # ip6tables --table nat --flush OUTPUT + # ${lib.flip (lib.concatMapStringsSep "\n") ["udp" "tcp"] (proto: '' + # ip6tables --table nat --append OUTPUT \ + # --protocol ${proto} --destination ::1 --destination-port 53 \ + # --jump REDIRECT --to-ports ${toString config.services.blocky.settings.ports.dns} + # '')} + # ''; + + services.blocky = { + enable = true; + settings = { + # https://0xerr0r.github.io/blocky/configuration/ + + upstreams = { + groups = { + default = [ + "https://dns.digitale-gesellschaft.ch/dns-query" + "tcp-tls:dns2.digitalcourage.de:853" + "tcp-tls:dns3.digitalcourage.de:853" + "tcp-tls:fdns1.dismail.de:853" + "tcp-tls:one.one.one.one:853" + ]; + unencrypted = [ + "1.0.0.1" + "1.1.1.1" + "2606:4700:4700::1001" + "2606:4700:4700::1111" + "dns2.digitalcourage.de" + ]; + }; + timeout = "2s"; + }; + + startVerifyUpstream = true; + connectIPVersion = "dual"; + + blocking = { + blackLists = { + # https://disconnect.me/trackerprotection + ads = [ + "http://sysctl.org/cameleon/hosts" + "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" + "https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt" + "https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt" + ]; + fakenews = [ + "https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews/hosts" + ]; + }; + + whiteLists = { }; + + clientGroupsBlock = { + default = [ "ads" ]; + sensitive = [ + "ads" + "fakenews" + ]; + }; + + blockType = "zeroIp"; + blockTTL = "1m"; + + loading = { + downloads = { + timeout = "4m"; + attempts = 5; + cooldown = "10s"; + }; + refreshPeriod = "4h"; + strategy = "failOnError"; + }; + }; + + filtering.queryTypes = [ ]; + + caching = { + minTime = "5m"; + maxTime = "30m"; + maxItemsCount = 0; + prefetching = true; + prefetchExpires = "2h"; + prefetchThreshold = 5; + prefetchMaxItemsCount = 0; + cacheTimeNegative = "30m"; + }; + + ports = { + dns = 53; + http = 4040; + }; + + log = { + level = "info"; + format = "text"; + timestamp = true; + privacy = true; + }; + + hostsFile = { + sources = [ "/etc/hosts" ]; + hostsTTL = "60m"; + filterLoopback = true; + loading.refreshPeriod = "30m"; + }; + + prometheus = { + enable = true; + path = "/metrics"; + }; + }; + }; +} diff --git a/hosts/srxnas00/networking/dns/knsupdate.nix b/hosts/srxnas00/networking/dns/knsupdate.nix new file mode 100644 index 0000000..a752fec --- /dev/null +++ b/hosts/srxnas00/networking/dns/knsupdate.nix @@ -0,0 +1,16 @@ +{ config, ... }: +{ + age.secrets.knsupdate = { + file = ../../dns_update.age; + owner = config.users.users.knsupdate.group; + }; + + srx.service.knsupdate = { + enable = true; + server = "dns.vpn.srx.dev"; + ttl = 120; + interval = "*:0/1"; + ipVersions = [ 4 ]; + keyFile = config.age.secrets.knsupdate.path; + }; +} diff --git a/hosts/srxnas00/networking/dns/unbound.nix b/hosts/srxnas00/networking/dns/unbound.nix new file mode 100644 index 0000000..52d3037 --- /dev/null +++ b/hosts/srxnas00/networking/dns/unbound.nix @@ -0,0 +1,68 @@ +{ pkgs, ... }: +{ + services.unbound = { + enable = true; + settings = { + remote-control = { + control-enable = true; + control-use-cert = false; + }; + server = { + num-threads = 4; + verbosity = 1; + prefetch = true; + prefetch-key = true; + serve-expired = true; + cache-min-ttl = 60; + cache-max-ttl = 3600; + infra-cache-slabs = "8"; + key-cache-slabs = "8"; + msg-cache-slabs = "8"; + rrset-cache-slabs = "8"; + msg-cache-size = "256m"; + rrset-cache-size = "512m"; + interface = [ + "0.0.0.0" + "'::0'" + ]; + access-control = builtins.concatLists [ + [ + # localhost + "::1/128 allow" + "127.0.0.0/8 allow" + ] + [ + # default + "0.0.0.0/0 deny" + "::/0 deny" + ] + ]; + tls-cert-bundle = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; + unblock-lan-zones = true; + insecure-lan-zones = true; + domain-insecure = [ + "d.f.ip6.arpa" + "ffdd" + ]; + }; + forward-zone = [ + { + name = "."; + forward-tls-upstream = true; + forward-addr = [ + # Quad9 + "2620:fe::fe@853#dns.quad9.net" + "9.9.9.9@853#dns.quad9.net" + "2620:fe::9@853#dns.quad9.net" + "149.112.112.112@853#dns.quad9.net" + # Cloudflare DNS + "2606:4700:4700::1111@853#cloudflare-dns.com" + "1.1.1.1@853#cloudflare-dns.com" + "2606:4700:4700::1001@853#cloudflare-dns.com" + "1.0.0.1@853#cloudflare-dns.com" + ]; + } + ]; + }; + }; +} diff --git a/hosts/srxnas00/networking/kea/default.nix b/hosts/srxnas00/networking/kea/default.nix new file mode 100644 index 0000000..d6758a3 --- /dev/null +++ b/hosts/srxnas00/networking/kea/default.nix @@ -0,0 +1,223 @@ +{ lib, config, ... }: +let + dns = { + host = "srx.dev"; + servers = "dns.vpn.${dns.host}"; + zone = "op.hq.hh.${dns.host}"; + }; +in +{ + networking.firewall.interfaces = { + br_usr = { + allowedUDPPorts = [ 67 ]; + allowedTCPPorts = [ 67 ]; + }; + }; + + services.kea = { + ctrl-agent = { + enable = true; + settings = { + control-sockets = { + dhcp4 = { + socket-name = "/run/kea/kea-dhcp4.socket"; + socket-type = "unix"; + }; + dhcp6 = { + socket-name = "/run/kea/kea-dhcp6.socket"; + socket-type = "unix"; + }; + }; + }; + }; + + # dhcp-ddns = { + # # https://kea.readthedocs.io/en/kea-2.2.0/arm/ddns.html#adding-forward-dns-servers + # enable = true; + # settings = { + # forward-ddns = { + # ddns-hosts = [ + # { + # name = "${dns.host}."; + # key-name = "update"; + # dns-servers = [ + # { + # ip-address = inputs.dns.servers; + # port = 53; + # } + # ]; + # } + # ]; + # }; + # }; + # }; + + dhcp4 = { + enable = true; + settings = { + interfaces-config.interfaces = [ "br_usr" ]; + + control-socket = { + socket-name = "/run/kea/kea-dhcp4.socket"; + socket-type = "unix"; + }; + + lease-database = { + name = "/var/lib/kea/dhcp4.leases"; + persist = true; + type = "memfile"; + }; + + rebind-timer = 2000; + renew-timer = 1000; + valid-lifetime = 4000; + + match-client-id = false; + + client-classes = [ + { + name = "iPXE"; + test = "substring(option[77].hex, 0, 4) == 'iPXE'"; + boot-file-name = "http://netboot.srx.digital/boot.php"; + } + { + name = "UEFI-32-7"; + test = "substring(option[60].hex,0,20) == 'PXEClient:Arch:00007'"; + boot-file-name = "ipxe.efi"; + } + { + name = "UEFI-32-8"; + test = "substring(option[60].hex,0,20) == 'PXEClient:Arch:00008'"; + boot-file-name = "ipxe.efi"; + } + { + name = "UEFI-32-9"; + test = "substring(option[60].hex,0,20) == 'PXEClient:Arch:00009'"; + boot-file-name = "ipxe.efi"; + } + { + name = "Legacy"; + test = "substring(option[60].hex,0,20) == 'PXEClient:Arch:00000'"; + boot-file-name = "undionly.kpxe"; + } + ]; + + subnet4 = [ + { + interface = "br_usr"; + subnet = "10.50.0.0/23"; + pools = [{ pool = "10.50.0.100 - 10.50.0.250"; }]; + option-data = [ + { + name = "routers"; + data = "10.50.0.1"; + } + { + name = "domain-name"; + data = dns.host; + } + { + name = "domain-name-servers"; + # data = "10.50.0.10"; + data = "10.50.0.1"; + } + { + name = "domain-search"; + data = dns.zone; + } + ]; + reservations = [ + { + hostname = "srxws00.${dns.zone}"; + ip-address = "10.50.0.200"; + hw-address = "f4:a8:0d:07:f4:5c"; + next-server = "10.50.0.10"; + } + { + hostname = "srxws00.${dns.zone}"; + ip-address = "10.50.0.201"; + hw-address = "c8:94:02:b9:a8:83"; + next-server = "10.50.0.10"; + } + { + hostname = "vm-pxe-test1.${dns.zone}"; + ip-address = "10.50.0.250"; + hw-address = "52:54:00:21:33:86"; + next-server = "10.50.0.10"; + } + { + hostname = "vm-pxe-test2.${dns.zone}"; + ip-address = "10.50.0.251"; + hw-address = "52:54:00:db:34:7f"; + next-server = "10.50.0.10"; + } + { + hostname = "nixos-karos.${dns.zone}"; + ip-address = "10.50.0.123"; + hw-address = "b4:a9:fc:7d:d8:dc"; + next-server = "10.50.0.10"; + } + ]; + } + ]; + + # dhcp-ddns.enable-updates = true; + # ddns-send-updates = true; + # ddns-qualifying-suffix = "${dns.zone}."; + }; + }; + + dhcp6 = { + enable = true; + settings = { + interfaces-config.interfaces = [ "br_usr" ]; + + control-socket = { + socket-name = "/run/kea/kea-dhcp6.socket"; + socket-type = "unix"; + }; + + lease-database = { + name = "/var/lib/kea/dhcp6.leases"; + persist = true; + type = "memfile"; + }; + + preferred-lifetime = 3000; + rebind-timer = 2000; + renew-timer = 1000; + valid-lifetime = 4000; + + subnet6 = [ + { + interface = "br_usr"; + subnet = "fd42:fab:2381:500::/119"; + pools = [{ pool = "fd42:fab:2381:500::50-fd42:fab:2381:500::1ff"; }]; + option-data = [ + { + name = "dns-servers"; + # data = "fd42:fab:2381:500::10"; + data = "fd42:fab:2381:500::1"; + } + ]; + } + ]; + # dhcp-ddns.enable-updates = true; + # ddns-send-updates = true; + # ddns-qualifying-suffix = "${dns.zone}."; + }; + }; + }; + + services.prometheus.exporters.kea = { + enable = lib.mkIf config.services.kea.dhcp4.enable or config.services.kea.dhcp6.enable true; + controlSocketPaths = + lib.optionals config.services.kea.dhcp4.enable [ "/run/kea/kea-dhcp4.socket" ] + ++ lib.optionals config.services.kea.dhcp6.enable [ "/run/kea/kea-dhcp6.socket" ]; + }; + + systemd.services.kea-ctrl-agent = { + requires = [ "network-online.target" ]; + after = [ "network-online.target" ]; + }; +} diff --git a/hosts/srxnas00/networking/networks/dmz.nix b/hosts/srxnas00/networking/networks/dmz.nix new file mode 100644 index 0000000..2e52f65 --- /dev/null +++ b/hosts/srxnas00/networking/networks/dmz.nix @@ -0,0 +1,40 @@ +{ + systemd.network = { + netdevs = { + vlan_dmz = { + netdevConfig = { + Kind = "vlan"; + Name = "vlan_dmz"; + }; + vlanConfig.Id = 600; + }; + + br_dmz = { + netdevConfig = { + Kind = "bridge"; + Name = "br_dmz"; + }; + }; + }; + + networks = { + bond0.vlan = [ "vlan_dmz" ]; + + vlan_dmz = { + matchConfig.Name = "vlan_dmz"; + networkConfig.Bridge = "br_dmz"; + linkConfig.RequiredForOnline = "enslaved"; + }; + + br_dmz = { + matchConfig.Name = "br_dmz"; + address = [ + "10.60.0.10/23" + "fd42:fab:2381:600::10/120" + ]; + bridgeConfig = { }; + linkConfig.RequiredForOnline = "routable"; + }; + }; + }; +} diff --git a/hosts/srxnas00/networking/networks/gst.nix b/hosts/srxnas00/networking/networks/gst.nix new file mode 100644 index 0000000..b076e9c --- /dev/null +++ b/hosts/srxnas00/networking/networks/gst.nix @@ -0,0 +1,40 @@ +{ + systemd.network = { + netdevs = { + vlan_gst = { + netdevConfig = { + Kind = "vlan"; + Name = "vlan_gst"; + }; + vlanConfig.Id = 400; + }; + + br_gst = { + netdevConfig = { + Kind = "bridge"; + Name = "br_gst"; + }; + }; + }; + + networks = { + bond0.vlan = [ "vlan_gst" ]; + + vlan_gst = { + matchConfig.Name = "vlan_gst"; + networkConfig.Bridge = "br_gst"; + linkConfig.RequiredForOnline = "enslaved"; + }; + + br_gst = { + matchConfig.Name = "br_gst"; + address = [ + "192.168.52.10/24" + "fd42:fab:2381:400::10/120" + ]; + bridgeConfig = { }; + linkConfig.RequiredForOnline = "routable"; + }; + }; + }; +} diff --git a/hosts/srxnas00/networking/networks/op.nix b/hosts/srxnas00/networking/networks/op.nix new file mode 100644 index 0000000..1ca5ef7 --- /dev/null +++ b/hosts/srxnas00/networking/networks/op.nix @@ -0,0 +1,40 @@ +{ + systemd.network = { + netdevs = { + vlan_op = { + netdevConfig = { + Kind = "vlan"; + Name = "vlan_op"; + }; + vlanConfig.Id = 500; + }; + + br_op = { + netdevConfig = { + Kind = "bridge"; + Name = "br_op"; + }; + }; + }; + + networks = { + bond0.vlan = [ "vlan_op" ]; + + vlan_op = { + matchConfig.Name = "vlan_op"; + networkConfig.Bridge = "br_op"; + linkConfig.RequiredForOnline = "enslaved"; + }; + + br_op = { + matchConfig.Name = "br_op"; + address = [ + "10.40.0.10/23" + "fd42:fab:2381:400::10/120" + ]; + bridgeConfig = { }; + linkConfig.RequiredForOnline = "routable"; + }; + }; + }; +} diff --git a/hosts/srxnas00/networking/networks/usr.nix b/hosts/srxnas00/networking/networks/usr.nix new file mode 100644 index 0000000..8f94cf0 --- /dev/null +++ b/hosts/srxnas00/networking/networks/usr.nix @@ -0,0 +1,44 @@ +{ + systemd.network = { + netdevs = { + vlan_usr = { + netdevConfig = { + Kind = "vlan"; + Name = "vlan_usr"; + }; + vlanConfig.Id = 300; + }; + + br_usr = { + netdevConfig = { + Kind = "bridge"; + Name = "br_usr"; + }; + }; + }; + + networks = { + bond0.vlan = [ "vlan_usr" ]; + + vlan_usr = { + matchConfig.Name = "vlan_usr"; + networkConfig.Bridge = "br_usr"; + linkConfig.RequiredForOnline = "enslaved"; + }; + + br_usr = { + matchConfig.Name = "br_usr"; + address = [ + "10.50.0.10/23" + "fd42:fab:2381:500::10/119" + ]; + routes = [ + { routeConfig.Gateway = "10.50.0.1"; } + { routeConfig.Gateway = "fe80::1"; } + ]; + bridgeConfig = { }; + linkConfig.RequiredForOnline = "routable"; + }; + }; + }; +} diff --git a/hosts/srxnas00/networking/networks/wan.nix b/hosts/srxnas00/networking/networks/wan.nix new file mode 100644 index 0000000..cf10376 --- /dev/null +++ b/hosts/srxnas00/networking/networks/wan.nix @@ -0,0 +1,23 @@ +{ + systemd.network = { + netdevs = { + vlan_wan = { + netdevConfig = { + Kind = "vlan"; + Name = "vlan_wan"; + }; + vlanConfig.Id = 200; + }; + }; + + networks = { + bond0.vlan = [ "vlan_wan" ]; + + vlan_wan = { + matchConfig.Name = "vlan_wan"; + networkConfig.DHCP = "yes"; + linkConfig.RequiredForOnline = "routable"; + }; + }; + }; +} diff --git a/hosts/srxnas00/networking/wireguard/mullvad.nix b/hosts/srxnas00/networking/wireguard/mullvad.nix new file mode 100644 index 0000000..4962faf --- /dev/null +++ b/hosts/srxnas00/networking/wireguard/mullvad.nix @@ -0,0 +1,180 @@ +{ config, ... }: +let + Name = "vpn_mvd"; + Description = "EAobLeO0BWJWUQ0JIWFTIld3PjCSC2Je0iY2hzaW/BU="; + MTUBytes = "1300"; + ListenPort = 51821; + FirewallMark = 42; + Table = 51820; +in +{ + age.secrets.vpnMvd = { + file = ../../vpn_mvd.age; + owner = "systemd-network"; + }; + + # networking.wg-quick.interfaces.vpn_mvd = { + # address = ["10.65.243.251/32" "fc00:bbbb:bbbb:bb01::2:f3fa/128"]; + # privateKeyFile = config.age.secrets.vpnMvd.path; + # peers = [ + # { + # allowedIPs = ["0.0.0.0/0" "::0/0"]; + # publicKey = "UrQiI9ISdPPzd4ARw1NHOPKKvKvxUhjwRjaI0JpJFgM="; + # endpoint = "193.32.249.66:51820"; + # } + # ]; + # }; + + # networking.wireguard.interfaces.wg0 = { + # preSetup = '' + # ip netns add ${socketNamespace} + # ''; + # inherit socketNamespace; + # }; + + boot.kernel.sysctl."net.ipv4.conf.all.src_valid_mark" = 1; + + systemd.network = { + netdevs."${Name}" = { + netdevConfig = { + Kind = "wireguard"; + inherit Name Description MTUBytes; + }; + + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnMvd.path; + inherit ListenPort FirewallMark; + }; + + wireguardPeers = [ + { + wireguardPeerConfig = { + Endpoint = "193.32.249.66:51820"; + PublicKey = "UrQiI9ISdPPzd4ARw1NHOPKKvKvxUhjwRjaI0JpJFgM="; + AllowedIPs = [ + "0.0.0.0/0" + "::0/0" + ]; + PersistentKeepalive = 15; + }; + } + ]; + }; + + networks."${Name}" = { + matchConfig = { + inherit Name; + }; + address = [ + "10.65.243.251/32" + "fc00:bbbb:bbbb:bb01::2:f3fa/128" + ]; + networkConfig = { + DNS = "10.64.0.1"; + DNSDefaultRoute = true; + inherit Description; + }; + linkConfig = { + # ActivationPolicy = "up"; + ActivationPolicy = "manual"; + inherit MTUBytes; + }; + routes = [ + { + routeConfig = { + Destination = "0.0.0.0/0"; + inherit Table; + # GatewayOnLink = true; + }; + } + { + routeConfig = { + Destination = "::/0"; + inherit Table; + # GatewayOnLink = true; + }; + } + ]; + routingPolicyRules = [ + { + routingPolicyRuleConfig = { + InvertRule = true; + inherit FirewallMark; + inherit Table; + }; + } + { + routingPolicyRuleConfig = { + SuppressPrefixLength = 0; + Table = "main"; + }; + } + ]; + }; + }; +} +# +## RESTORE +# +# systemctl stop wireguard-vpn_mvd +# ip route replace default via 10.50.0.1 +# unlink /etc/resolv.conf ; echo 'nameserver 1.1.1.1' > /etc/resolv.conf +# ping -c 1 8.8.8.8 +# dig google.de +# +## CHECKS +# ip address show vpn_mvd +# ip route show table 51820 +# ip route get 65.108.77.254 +# ip route get 10.50.0.4 +# ip rule show table main | grep suppress_prefixlength +# ip rule show table 51820 | grep fwmark +# sysctl net.ipv4.conf.all.src_valid_mark +# curl -s -4 https://checkip.srx.digital/ +# curl -s -6 https://checkip.srx.digital/ +# https://www.wireguard.com/netns/ +# +# ip route show table 51820 +# ip route get 65.108.77.254 +# ip route get 10.50.0.4 +# ip rule show table main | grep suppress_prefixlength +# ip rule show table 51820 | grep fwmark +# sysctl net.ipv4.conf.all.src_valid_mark +# curl -s -4 https://checkip.srx.digital/ +# curl -s -6 https://checkip.srx.digital/ +# 17: vpn_mvd: mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000 +# link/none +# inet 10.65.243.251/32 scope global vpn_mvd +# valid_lft forever preferred_lft forever +# inet6 fc00:bbbb:bbbb:bb01::2:f3fa/128 scope global +# valid_lft forever preferred_lft forever +# default dev vpn_mvd scope link +# 65.108.77.254 dev vpn_mvd table 51820 src 10.65.243.251 uid 0 +# cache +# 10.50.0.4 dev br_usr src 10.50.0.10 uid 0 +# cache +# 32764: from all lookup main suppress_prefixlength 0 +# 32765: not from all fwmark 0xca6c lookup 51820 +# 32765: not from all fwmark 0x2a lookup 51820 proto static +# net.ipv4.conf.all.src_valid_mark = 1 +# 193.32.249.133 +# 2a03:1b20:3:f011::e003 +# +# +# ip link add vpn_mvd type wireguard +# ip link set mtu 1420 up dev vpn_mvd +# +# ip -4 address add 10.65.243.251/32 dev vpn_mvd +# ip -4 route add 0.0.0.0/0 dev vpn_mvd table 51820 +# ip -4 rule add not fwmark 51820 table 51820 +# ip -4 rule add table main suppress_prefixlength 0 +# +# ip -6 address add fc00:bbbb:bbbb:bb01::2:f3fa/128 dev vpn_mvd +# ip -6 route add ::/0 dev vpn_mvd table 51820 +# ip -6 rule add not fwmark 51820 table 51820 +# ip -6 rule add table main suppress_prefixlength 0 +# +# sysctl -q net.ipv4.conf.all.src_valid_mark=1 +# +# wg set vpn_mvd fwmark 51820 +# wg setconf vpn_mvd /dev/fd/63 diff --git a/hosts/srxnas00/networking/wireguard/srx.nix b/hosts/srxnas00/networking/wireguard/srx.nix new file mode 100644 index 0000000..2feecb7 --- /dev/null +++ b/hosts/srxnas00/networking/wireguard/srx.nix @@ -0,0 +1,40 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.2/24" ]; + networkConfig = { + IPMasquerade = "ipv4"; + IPForward = true; + }; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; + +} diff --git a/hosts/srxnas00/networking/wireless.nix b/hosts/srxnas00/networking/wireless.nix new file mode 100644 index 0000000..5460077 --- /dev/null +++ b/hosts/srxnas00/networking/wireless.nix @@ -0,0 +1,19 @@ +{ config, ... }: { + age.secrets.wifi_client.file = ../wifi_client.age; + + networking = { + interfaces.wlp0s21f0u2.useDHCP = true; + + wireless = { + enable = true; + environmentFile = config.age.secrets.wifi_client.path; + + networks = { + "skynet".psk = "@PASS_SKYNET@"; + "FRITZ!Box Fon WLAN 7360".psk = "@PASS_WERK2@"; + }; + }; + }; + + services.telegraf.extraConfig.inputs.wireless = { }; +} diff --git a/hosts/srxnas00/services/apcupsd/default.nix b/hosts/srxnas00/services/apcupsd/default.nix new file mode 100644 index 0000000..e3a7dcc --- /dev/null +++ b/hosts/srxnas00/services/apcupsd/default.nix @@ -0,0 +1,16 @@ +{ + services = { + apcupsd = { + enable = true; + + configText = '' + UPSTYPE usb + NISIP 127.0.0.1 + BATTERYLEVEL 50 + MINUTES 5 + ''; + }; + + prometheus.exporters.apcupsd.enable = true; + }; +} diff --git a/hosts/srxnas00/services/home-assistant/auth.nix b/hosts/srxnas00/services/home-assistant/auth.nix new file mode 100644 index 0000000..ff19c09 --- /dev/null +++ b/hosts/srxnas00/services/home-assistant/auth.nix @@ -0,0 +1,10 @@ +{ + services.home-assistant.config.homeassistant.auth_providers = [ + { type = "homeassistant"; } + { + type = "trusted_networks"; + trusted_networks = [ "10.50.0.0/23" "192.168.178.0/24" ]; + allow_bypass_login = true; + } + ]; +} diff --git a/hosts/srxnas00/services/home-assistant/default.nix b/hosts/srxnas00/services/home-assistant/default.nix new file mode 100644 index 0000000..c654f6d --- /dev/null +++ b/hosts/srxnas00/services/home-assistant/default.nix @@ -0,0 +1,88 @@ +{ pkgs, config, lib, ... }: +{ + imports = [ + ./auth.nix + ./http.nix + ./zones.nix + ./lovelace + ]; + + users.users.hass = { + extraGroups = + [ "dialout" ] + ++ lib.optionals config.hardware.i2c.enable [ "i2c" ] + ++ lib.optionals config.hardware.bluetooth.enable [ "lp" ] + ++ lib.optionals config.sound.enable [ "audio" ]; + }; + + # age.secrets.homeAssistantSecrets.file = ./home-assistant-s2ecrets.age; + + services = { + home-assistant = { + enable = true; + package = + (pkgs.home-assistant.override { + # https://github.com/NixOS/nixpkgs/blob/master/pkgs/servers/home-assistant/component-packages.nix + extraComponents = [ + "auth" + "backup" + "esphome" + "lovelace" + "matrix" + "mqtt" + "network" + "zeroconf" + ]; + extraPackages = py: with py; [ psycopg2 pip ]; + }).overrideAttrs { doInstallCheck = false; }; + config = { + homeassistant = { + external_url = "https://home.srx.digital"; + internal_url = "https://home.vpn.srx.dev"; + }; + default_config = { }; + logger = { + default = "info"; + }; + mqtt = { + broker = "localhost"; + port = 1883; + discovery = true; + }; + backup = { }; + bluetooth = { }; + dhcp = { }; + discovery = { }; + esphome = { }; + frontend = { }; + history = { }; + prometheus = { }; + system_health = { }; + system_log = { }; + wake_on_lan = { }; + webhook = { }; + zeroconf = { }; + recorder = { + db_url = "postgresql://@/hass"; + purge_keep_days = 90; + }; + }; + }; + + postgresql = { + enable = true; + ensureDatabases = [ "hass" ]; + ensureUsers = [ + { + name = "hass"; + ensureDBOwnership = true; + } + ]; + }; + + postgresqlBackup = { + enable = true; + databases = [ "hass" ]; + }; + }; +} diff --git a/hosts/srxnas00/services/home-assistant/http.nix b/hosts/srxnas00/services/home-assistant/http.nix new file mode 100644 index 0000000..39912e1 --- /dev/null +++ b/hosts/srxnas00/services/home-assistant/http.nix @@ -0,0 +1,10 @@ +{ + # https://www.home-assistant.io/integrations/http + services.home-assistant.config.http = { + server_host = "0.0.0.0"; + # trusted_proxies = ["10.80.0.10"]; + use_x_forwarded_for = true; + ip_ban_enabled = true; + login_attempts_threshold = 5; + }; +} diff --git a/hosts/srxnas00/services/home-assistant/lovelace/default.nix b/hosts/srxnas00/services/home-assistant/lovelace/default.nix new file mode 100644 index 0000000..6de9d9b --- /dev/null +++ b/hosts/srxnas00/services/home-assistant/lovelace/default.nix @@ -0,0 +1,18 @@ +{ + services.home-assistant.lovelaceConfig = { + title = "SRX"; + views = [ + { + title = "Overview"; + cards = [ + { + type = "markdown"; + content = '' + https://srx.digital + ''; + } + ]; + } + ]; + }; +} diff --git a/hosts/srxnas00/services/home-assistant/zones.nix b/hosts/srxnas00/services/home-assistant/zones.nix new file mode 100644 index 0000000..b2bd9fa --- /dev/null +++ b/hosts/srxnas00/services/home-assistant/zones.nix @@ -0,0 +1,23 @@ +{ + services.home-assistant.config = { + homeassistant = { + name = "SRX"; + unit_system = "metric"; + time_zone = "Europe/Berlin"; + temperature_unit = "C"; + latitude = "53.5527778"; + longitude = "9.9611111"; + elevation = 13; + }; + + zone = [ + { + name = "Wohlwill"; + icon = "mdi:flower"; + latitude = "53.5527778"; + longitude = "9.9611111"; + radius = "200"; + } + ]; + }; +} diff --git a/hosts/srxnas00/services/jellyfin/default.nix b/hosts/srxnas00/services/jellyfin/default.nix new file mode 100644 index 0000000..a07a8fb --- /dev/null +++ b/hosts/srxnas00/services/jellyfin/default.nix @@ -0,0 +1,7 @@ +{ + services.jellyfin = { + enable = true; + openFirewall = true; + group = "users"; + }; +} diff --git a/hosts/srxnas00/services/minidlna/default.nix b/hosts/srxnas00/services/minidlna/default.nix new file mode 100644 index 0000000..a925b1a --- /dev/null +++ b/hosts/srxnas00/services/minidlna/default.nix @@ -0,0 +1,23 @@ +{ + users.users.minidlna.extraGroups = [ "users" ]; + + services.minidlna = { + enable = true; + openFirewall = true; + + settings = { + inotify = "yes"; + friendly_name = "srx"; + + media_dir = [ + "V,/srv/movies" + "A,/srv/music" + ]; + + extraConfig = '' + enable_tivo=no + max_connections=50 + ''; + }; + }; +} diff --git a/hosts/srxnas00/services/mosquitto/default.nix b/hosts/srxnas00/services/mosquitto/default.nix new file mode 100644 index 0000000..bb56532 --- /dev/null +++ b/hosts/srxnas00/services/mosquitto/default.nix @@ -0,0 +1,10 @@ +{ + services.mosquitto = { + enable = true; + listeners = [{ + port = 1883; + acl = [ "pattern readwrite #" ]; + settings = { allow_anonymous = true; }; + }]; + }; +} diff --git a/hosts/srxnas00/services/netboot/default.nix b/hosts/srxnas00/services/netboot/default.nix new file mode 100644 index 0000000..8a5031a --- /dev/null +++ b/hosts/srxnas00/services/netboot/default.nix @@ -0,0 +1,47 @@ +{ pkgs, ... }: +let + ipxeDerivation = pkgs.ipxe.overrideDerivation (_drv: { + additionalOptions = [ + "KEYBOARD_MAP" + "NET_PROTO_IPV6" + "DOWNLOAD_PROTO_NFS" + "DOWNLOAD_PROTO_FTP" + "DOWNLOAD_PROTO_FILE" + "DOWNLOAD_PROTO_HTTPS" + "CONSOLE_FRAMEBUFFER" + "CONSOLE_SERIAL" + "CONSOLE_SYSLOG" + "IMAGE_TRUST_CMD" + "IMAGE_ARCHIVE_CMD" + "IMAGE_ZLIB" + "IMAGE_GZIP" + "IMAGE_SCRIPT" + "IMAGE_PNG" + "CERT_CMD" + "CONSOLE_CMD" + "DIGEST_CMD" + "IMAGE_MEM_CMD" + "IPSTAT_CMD" + "NEIGHBOUR_CMD" + "NSLOOKUP_CMD" + "NTP_CMD" + "PARAM_CMD" + "PCI_CMD" + "POWEROFF_CMD" + "PXE_CMD" + "TIME_CMD" + "VLAN_CMD" + ]; + }); +in +{ + networking.firewall = { + allowedUDPPorts = [ 69 ]; + allowedTCPPorts = [ 69 ]; + }; + + services.atftpd = { + enable = true; + root = ipxeDerivation; + }; +} diff --git a/hosts/srxnas00/services/rtl-sdr/default.nix b/hosts/srxnas00/services/rtl-sdr/default.nix new file mode 100644 index 0000000..39b216a --- /dev/null +++ b/hosts/srxnas00/services/rtl-sdr/default.nix @@ -0,0 +1,26 @@ +{ pkgs, ... }: +{ + hardware = { + rtl-sdr.enable = true; + hackrf.enable = true; + }; + + environment.systemPackages = with pkgs; [ + rtl-sdr + rtl_433 + ]; + + services.prometheus.exporters.rtl_433 = { + enable = true; + channels = [{ + channel = 6543; + location = "Kitchen"; + name = "Acurite"; + }]; + ids = [{ + id = 1; + location = "universe"; + name = "Werk2"; + }]; + }; +} diff --git a/hosts/srxnas00/services/vault/default.nix b/hosts/srxnas00/services/vault/default.nix new file mode 100644 index 0000000..0d4b8a5 --- /dev/null +++ b/hosts/srxnas00/services/vault/default.nix @@ -0,0 +1,46 @@ +{ pkgs, config, ... }: +let + host = "vault.vpn.srx.dev"; + ip = "10.80.0.4"; + ports = { + api = 8200; + cluster = 8201; + stats = 8125; + }; + schema = "https"; +in +{ + environment = { + systemPackages = [ pkgs.vault ]; + variables.VAULT_ADDR = "${schema}://${host}:${toString ports.api}"; + }; + + services.vault = { + enable = true; + package = pkgs.vault-bin; + storageBackend = "raft"; + address = "${ip}:${toString ports.api}"; + tlsCertFile = "${config.security.acme.certs.${host}.directory}/fullchain.pem"; + tlsKeyFile = "${config.security.acme.certs.${host}.directory}/key.pem"; + listenerExtraConfig = '' + tls_min_version = "tls12" + ''; + extraConfig = '' + ui = true + api_addr = "${schema}://${host}:${toString ports.api}" + cluster_addr = "${schema}://${host}:${toString ports.cluster}" + ''; + # extraSettingsPaths = [ + # (pkgs.writeTextDir "nomad.hcl" (builtins.readFile ./policies/nomad.hcl)) + # ]; + # telemetryConfig = '' + # statsite_address = "${host}:${toString ports.stats}" + # ''; + }; + + security.acme.certs."${host}" = { + domain = "${host}"; + group = "vault"; + reloadServices = [ "vault.service" ]; + }; +} diff --git a/hosts/srxnas00/services/vdr/default.nix b/hosts/srxnas00/services/vdr/default.nix new file mode 100644 index 0000000..dbd4afd --- /dev/null +++ b/hosts/srxnas00/services/vdr/default.nix @@ -0,0 +1,26 @@ +{ pkgs, ... }: +{ + # services.vdr = { + # enable = true; + + # package = pkgs.wrapVdr.override { + # plugins = with pkgs.vdrPlugins; [ + # epgsearch + # femon + # markad + # streamdev + # vnsiserver + # ]; + # }; + # videoDir = "/srv/videos/vdr"; + # }; + + services.tvheadend.enable = true; + # services.antennas.enable = true; + + environment.systemPackages = with pkgs; [ + dtv-scan-tables + dvb-apps + w_scan2 + ]; +} diff --git a/hosts/srxnas00/services/zigbee2mqtt/default.nix b/hosts/srxnas00/services/zigbee2mqtt/default.nix new file mode 100644 index 0000000..1e117f5 --- /dev/null +++ b/hosts/srxnas00/services/zigbee2mqtt/default.nix @@ -0,0 +1,34 @@ +{ + users.users.zigbee2mqtt.extraGroups = [ "dialout" ]; + + services.zigbee2mqtt = { + enable = true; + + settings = { + serial.port = "/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0"; + + permit_join = true; + + homeassistant = { + discovery_topic = "homeassistant"; + status_topic = "homeassistant/status"; + }; + + availability = { + active.timeout = 10; + passive.timeout = 1500; + }; + + mqtt = { + server = "mqtt://localhost:1883"; + include_device_information = true; + keepalive = 60; + }; + + advanced = { + output = "json"; + log_level = "info"; + }; + }; + }; +} diff --git a/hosts/srxnas00/storage.nix b/hosts/srxnas00/storage.nix new file mode 100644 index 0000000..6f9a0ac --- /dev/null +++ b/hosts/srxnas00/storage.nix @@ -0,0 +1,187 @@ +{ lib, ... }: +let + disks = { + system = [ "/dev/disk/by-id/nvme-eui.00253855015004a5" ]; + data = [ + "/dev/disk/by-id/wwn-0x5000c50065b38b37" + "/dev/disk/by-id/wwn-0x5000c5007296fdf7" + "/dev/disk/by-id/wwn-0x5000c5007b7125de" + "/dev/disk/by-id/wwn-0x5000c5007b712c7e" + ]; + }; + compression = "zstd"; + rootFsOptions = { + acltype = "posixacl"; + dnodesize = "auto"; + normalization = "formD"; + xattr = "sa"; + relatime = "on"; + canmount = "off"; + mountpoint = "none"; + inherit compression; + "com.sun:auto-snapshot" = "false"; + }; + passwordFile = "/etc/hostname"; + system = lib.genAttrs disks.system + (device: + let + name = builtins.replaceStrings [ "_" ] [ "-" ] (lib.lists.last (builtins.split "/" device)); + in + { + type = "disk"; + inherit name device; + content = { + type = "gpt"; + partitions = { + esp = { + size = "1G"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + system = { + size = "100%"; + content = { + type = "luks"; + inherit name; + content = { + type = "zfs"; + pool = "system"; + }; + inherit passwordFile; + settings.allowDiscards = true; + }; + }; + }; + }; + }); + raid = lib.genAttrs disks.data + (device: + let + name = builtins.replaceStrings [ "_" ] [ "-" ] (lib.lists.last (builtins.split "/" device)); + in + { + type = "disk"; + inherit name device; + content = { + type = "gpt"; + partitions = { + raid = { + size = "100%"; + content = { + type = "luks"; + inherit name; + content = { + type = "zfs"; + pool = "raid"; + }; + inherit passwordFile; + settings.allowDiscards = true; + }; + }; + }; + }; + }); + default = mountpoint: { + type = "zfs_fs"; + options = { + inherit mountpoint; + }; + inherit mountpoint; + }; + auto_snapshot = mountpoint: { + type = "zfs_fs"; + options = { + inherit mountpoint; + "com.sun:auto-snapshot" = "true"; + }; + inherit mountpoint; + }; + can_not_mount = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + }; + mountpoint = null; + mountOptions = [ ]; + }; +in +{ + disko.devices = { + disk = system // raid; + zpool = { + system = { + type = "zpool"; + options = { + ashift = "12"; + autotrim = "on"; + }; + inherit rootFsOptions; + mountpoint = null; + datasets = { + "reserved" = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + refreservation = "10GiB"; + }; + mountpoint = null; + mountOptions = [ ]; + }; + "nixos" = can_not_mount; + "nixos/etc" = default "/etc"; + "nixos/nix" = default "/nix"; + "user" = can_not_mount; + "user/root" = default "/root"; + "user/home" = auto_snapshot "/home"; + "data" = can_not_mount; + "data/lib" = auto_snapshot "/var/lib"; + "data/log" = default "/var/log"; + "data/cache" = default "/var/cache"; + "data/backup" = default "/var/backup"; + }; + }; + raid = { + type = "zpool"; + mode = "raidz"; + options = { + ashift = "12"; + autotrim = "on"; + }; + inherit rootFsOptions; + mountpoint = null; + datasets = { + "data" = can_not_mount; + "data/backups" = default "/srv/backups"; + "data/home" = auto_snapshot "/srv/home"; + "data/documents" = auto_snapshot "/srv/documents"; + "data/movies" = default "/srv/movies"; + "data/music" = default "/srv/music"; + "data/pictures" = default "/srv/pictures"; + "data/videos" = default "/srv/videos"; + "data/public" = default "/srv/public"; + }; + }; + }; + nodev = { + "/" = { + fsType = "tmpfs"; + mountOptions = [ + "defaults" + "size=1G" + "mode=755" + "noatime" + ]; + }; + "/tmp" = { + fsType = "tmpfs"; + mountOptions = [ "size=1G" ]; + }; + }; + }; +} diff --git a/hosts/srxnas00/storage/nfs/default.nix b/hosts/srxnas00/storage/nfs/default.nix new file mode 100644 index 0000000..6d5cfc7 --- /dev/null +++ b/hosts/srxnas00/storage/nfs/default.nix @@ -0,0 +1,49 @@ +{ config, ... }: +{ + services.nfs.server = { + enable = true; + + statdPort = 4000; + lockdPort = 4001; + mountdPort = 4002; + + exports = '' + /export \ + 10.80.0.0/24(ro,fsid=0,no_subtree_check) \ + 10.50.0.0/23(ro,fsid=0,no_subtree_check) \ + 192.168.178.0/24(ro,fsid=0,no_subtree_check) + + /export/public \ + 10.80.0.0/24(ro,fsid=0,no_subtree_check) \ + 10.50.0.0/23(ro,nohide,insecure,no_subtree_check) \ + 192.168.178.0/24(ro,nohide,insecure,no_subtree_check) + ''; + }; + + networking.firewall = { + allowedTCPPorts = [ + 111 + 2049 + config.services.nfs.server.statdPort + config.services.nfs.server.lockdPort + config.services.nfs.server.mountdPort + ]; + allowedUDPPorts = [ + 111 + 2049 + config.services.nfs.server.statdPort + config.services.nfs.server.lockdPort + config.services.nfs.server.mountdPort + ]; + }; + + fileSystems = { + "/export/public" = { + device = "/srv/public"; + options = [ + "bind" + "X-mount.mkdir" + ]; + }; + }; +} diff --git a/hosts/srxnas00/vpn_mvd.age b/hosts/srxnas00/vpn_mvd.age new file mode 100644 index 0000000..e8c6445 --- /dev/null +++ b/hosts/srxnas00/vpn_mvd.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw EdgPWroD+DMAj0ToTcqIubkUWjLR2D+aFOO5zKmGdDo +0SHG1/7tBzIOaWw4F09jSRNJlLyJd/HEtZQqt3vAgkw +-> ssh-ed25519 JzjriQ V1P5BkpFEDGmIYljW1eZ9TtTCY/SPyFUDXU3a6nyaTU +SBkjuaMnEwxfhw/k9NKsQnzhkHvl2cEFOwnkxHm1U4k +-> ssh-rsa 6hPx7A +NhfmPvHC/IH4m2VPofNfRwDo9MZFgg2CG6Ms90z1pIQADFkdWaKRGsjrNXxijqQ6 +FJVdZFOIm9UDAvSwup1sgHDNzGESgZF6giou/wAUHwasLMGeq6w81ECAC+S2vrhM +oysVqqHau43mynqa/c3AVLsqf+BUJ/36gA7vs4azV8EX91v19KWj9Tw3B7EMsx9i +1xzUc6oA/KCosxSTAv8qbnMF7k5F07O18r5T7ybfJGRQNcJIyhTrcYWiDRfvmTI3 +c6JugKj+SYFbJ69v6Xhbc/XymLjG2DsvH2xlwoJoOfiTNyNnflFqWjtws13AJEyP +Kr1MRbfIoV6inGqFG57AB78TmkdOoHf/sGqr3xOuAOoG6z+DXbvDacfuoLR4/7Fl +NoOQSe9mvytBNEXpU34EUTKoYMGTpa26RD+TWRufjAg24uEBxctAnT4cX0Pz/ocs +4+w+jLP40Z2h7unEbak42v+LQaoFRwOH1bMGQxWsz579Mgt+SlQQoIENYASxEGgF +XaAMpPyRDISFrBeWG85ybYe4Uzp5vvIGoCLDzOguGxSPLtgAwnYzDCU6i3WBrdDp +pHkXyZeGXO53JBKSRPGxxTw8vIWDeQdo9GHngyu/Ni9CNB+yX7AANN/JDv1UfGeV +Io/9nDCYyGLtZazlZ5oMJvr4tT2EsAZi+M9TKYvlC+o +-> ssh-ed25519 ZeuIrQ FnZKjmd7OnN2m4Wp454VEmlMknUrnbDt3H3XiY2c3TI +fGBRRtiQJx14Fhjl5PG4p7dmbuWT0blx5UjjaYqgEt0 +--- r/IdYY+5f/9CBsS14j/COE9eMlqIjajRB3FdJx245sA +ÔQaKeش4J 1b3rfrーcȋˢrV>r \{!EF \ No newline at end of file diff --git a/hosts/srxnas00/vpn_srx.age b/hosts/srxnas00/vpn_srx.age new file mode 100644 index 0000000..fba0e07 --- /dev/null +++ b/hosts/srxnas00/vpn_srx.age @@ -0,0 +1,23 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw Tc1M7fljgqubhq6L4bVVNyzGTFsGUsbEX7iJInRRMCI +73ErEXZOZ5Mdk3TM50B/3bzChNS/Bw7kJCGBiS2qtB4 +-> ssh-ed25519 JzjriQ YxeQ0Irz6PcafUUcyBWNhUhkMrTKnerIp3xy1Ao3ZQs +ZHQn3i0z3MQ5TFGZICTV+ZIv90NMVKkorv+yiAqGGt8 +-> ssh-rsa 6hPx7A +yBuoRBC2/QunJQpwEXQcbPdRSXemOXx+wxOeObxqPn2+Q4W2NEhYV4FSUWe9tt5X +pIzErpqrBfeermbwZahURtmGsMeBayliR15wqn25Wt49stbFWRNvF4eWzec5/RwP +kPB5EZdE3IULOc95E4zrQkaeK59Q1GMP4fmiK9g/KQNiSGl5SkH1vKwEHyNE/1Ki +Ow9TjfXL8oeyCiXz7/IlGI8qSVzPEh+Ejz2n9BTpEOCnISuUT8XfyT01AG84RfgA +VvoQJVYWI1CovZea4wbGoIWDsbUBeRDn0my9MdLWIjq1Mv62Uax9YvmjzZSMWRIK +Z9AACWEs6F+TX69WBWiw1y/V8l6QHQ2IFfc2zWrGMivWAXP5ia4rGLaxS1Z0s+S8 +4JGxjwseQi8doUoOMIU+yxT0XnLAaOUqKjThFSVoFSiyV0udHZy8qZ9Oh3Kh6NSa +TVC2XTQSfcVchNRs+FeedR2t7BQiNmkABmA7lF6dK9gCOlzmpnzKgFLGpNCc9OqI +nE7Lz/FrZoFRZq+XfH0AX0yivDFeqfis4vroA4c8Ls4sWTUtThKhr9VQznkgFl+Q +lRKyDjRlm8pBj0N+kyejNG1hyQZcbEDF1YGAr+gFUK3DTCZ5qmNWVqOHgYLve4Qs +Yz6QPC0BdbV0KjVQBhtFWi3MiDbXmvZc83RKQCv7Zyk +-> ssh-ed25519 ZeuIrQ c8ZUf78mhgLNjzD3kPnyEy1j64gqCUQFJKK2ku8FEw0 +gmE6MS3XPzZc9/jWVjGNKMaPjQm/g5nN8xo+4wzIEKE +--- uD16fyRo5yikgO5E78EPD/h6nSUaMVCZ9JCtuJ+5tjk +2 4 +dV Vr+:j0À`FU Jf _\l5\2=lPJ2_ +n \ No newline at end of file diff --git a/hosts/srxnas01/clevis.age b/hosts/srxnas01/clevis.age new file mode 100644 index 0000000..b108f84 Binary files /dev/null and b/hosts/srxnas01/clevis.age differ diff --git a/hosts/srxnas01/default.nix b/hosts/srxnas01/default.nix new file mode 100644 index 0000000..900740d --- /dev/null +++ b/hosts/srxnas01/default.nix @@ -0,0 +1,46 @@ +{ self, ... }: +{ + imports = [ + self.nixosModules.roles-nas + self.nixosModules.services-security-tang + self.nixosModules.services-virtualisation-microvm + ./hardware.nix + ./storage.nix + ./network/wireguard + ./network/knsupdate + ./services/minidlna + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "srxnas01"; + domain = "srx.digital"; + hostId = "8656cb50"; + }; + + systemd.network = { + enable = true; + networks."10-uplink" = { + matchConfig.Name = "enp2s0"; + address = [ "10.50.0.10/23" ]; + routes = [ + { routeConfig.Gateway = "10.50.0.1"; } + { routeConfig.Gateway = "fe80::1"; } + ]; + }; + }; + + fileSystems."/mnt/cryptix" = { + device = "aufdie12.lan:/mnt/main/sort"; + fsType = "nfs"; + options = [ + "noauto" + "X-mount.mkdir" + "x-systemd.automount" + "x-systemd.device-timeout=5s" + "x-systemd.idle-timeout=60" + "x-systemd.mount-timeout=5s" + ]; + }; +} diff --git a/hosts/srxnas01/dns_update.age b/hosts/srxnas01/dns_update.age new file mode 100644 index 0000000..1d4631a --- /dev/null +++ b/hosts/srxnas01/dns_update.age @@ -0,0 +1,22 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw Yzqy7yM+713dnrLXcfjUhLFMjnQpl95wHJlzIjnQfSE +xIVphrMwhRQkwUXDv+pAkfqc8LIsQ1Ns22QTtKADG+Q +-> ssh-ed25519 JzjriQ k3JUDjOI5Qzelhc4fegecq9OWRdIJpZknIrwtXtQBWM +RsROE/3lcZlEbeBfzAMOyCMu4vChgNr5O1QJcdU9Tko +-> ssh-rsa 6hPx7A +udLGjSbutZOksoH/SwNDRn2tWkNHtnVvDK6V/EAJN4iyg4JkWA59lDt7cmeMHGw6 +hBIs0uqV7MsVCIqVxYpBM8fTnNb3I21JhsHQ0mHjynkc1ncD64UlIKfKslzp5yZL +2+/5I3bK6QO2lujwlnX45MqggU6K0l7C2Z/PmdCJ/nP90CjkIept9XPmdZBHWn+M +sTAsR9C4E0lopbbj2RVu1+Rep+8nATXgaWObh20hnO2By6PRywGBLFVLsscn94HG +TRWRmFAmxeEoqQaksxz12k+YZa82K+1isWAvj3869WmA9aHV74PZtlFhG4ZBEdvv +u9HX9y5ZxTI157m4q/EZGkcXbvPWTueuF9U0e/6zM2K7gJe6nHgArVcoemliDHzT +9w6n/5OKMinT+0XyQElvcqkZMyQtV3Fl8lBEIITuzxfZkBPRmgzAqGCdEJM4pQyI +XWDOGF8F9Ufg0ecDVR7fmBcSjUKYn+DSrlRxkX3TK5XUkVKm0H6yy7P7L9Cgzfr/ +6gPCW6bXa78QQYwfF20MUYlQ3EkpceDjj91NbPexu2YPr00J3bgmscus2r6QZJoc +CvTGQLpDP2bRfTDPFEyCEJQnUmjScmjwu/Nyg14uI8oVFyFG1+VwbQo0sLqAv/AD +NDYBiCybp2NdttMddPRqajN/aba2quWlZJNFDlOWM5g +-> ssh-ed25519 MrfLnw 47sMO7L4n9gmlB9IE4N3L6gcPb6/j/9VHmHDLw6W0iQ ++K+0xVmpm7SAQfkhW3VhbO6dNjSZ+gigbXCaJUKVsSU +--- mIAhV7mEGrObCXLHe+rfdIHOj7f1vM/mFf5KSBwPpuk +d$l +SIP2~g: D2FC9mݰM-c^z}oE.A +Ixw-mRBP<_:A2JۃYx81 \ No newline at end of file diff --git a/hosts/srxnas01/hardware.nix b/hosts/srxnas01/hardware.nix new file mode 100644 index 0000000..4274517 --- /dev/null +++ b/hosts/srxnas01/hardware.nix @@ -0,0 +1,54 @@ +{ inputs, config, modulesPath, ... }: +{ + imports = with inputs; [ + (modulesPath + "/installer/scan/not-detected.nix") + self.nixosModules.hardware + self.nixosModules.hardware-cpu-intel + self.nixosModules.hardware-security-secureboot + self.nixosModules.filesystems-zfs + ]; + + age.secrets.clevis.file = ./clevis.age; + + boot = { + initrd = { + systemd = { + enable = true; + inherit (config.systemd) network; + }; + network = { + enable = true; + ssh = { + enable = true; + authorizedKeys = config.users.users.root.openssh.authorizedKeys.keys; + port = 2222; + hostKeys = [ /etc/ssh/ssh_host_ed25519_key_initrd ]; + }; + }; + availableKernelModules = [ + "ahci" + "nvme" + "sd_mod" + "usb_storage" + "usbhid" + "xhci_pci" + "r8169" + ]; + kernelModules = [ ]; + clevis = { + enable = true; + useTang = true; + devices = { + "nvme-eui.0025385a81b4239b".secretFile = config.age.secrets.clevis.path; + "wwn-0x5000c500d6b1b870".secretFile = config.age.secrets.clevis.path; + }; + }; + }; + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + }; + + powerManagement.cpuFreqGovernor = "powersave"; +} diff --git a/hosts/srxnas01/network/knsupdate/default.nix b/hosts/srxnas01/network/knsupdate/default.nix new file mode 100644 index 0000000..0630e51 --- /dev/null +++ b/hosts/srxnas01/network/knsupdate/default.nix @@ -0,0 +1,16 @@ +{ config, ... }: +{ + age.secrets.knsupdate = { + file = ../../dns_update.age; + owner = config.srx.service.knsupdate.user; + }; + + srx.service.knsupdate = { + enable = true; + zone = "srx.digital"; + server = "dns.vpn.srx.dev"; + ttl = 120; + interval = "*:0/1"; + keyFile = config.age.secrets.knsupdate.path; + }; +} diff --git a/hosts/srxnas01/network/wireguard/default.nix b/hosts/srxnas01/network/wireguard/default.nix new file mode 100644 index 0000000..6a9512d --- /dev/null +++ b/hosts/srxnas01/network/wireguard/default.nix @@ -0,0 +1,36 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" "10.50.0.0/23" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.2/24" ]; + networkConfig.IPForward = true; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; +} diff --git a/hosts/srxnas01/services/minidlna/default.nix b/hosts/srxnas01/services/minidlna/default.nix new file mode 100644 index 0000000..a925b1a --- /dev/null +++ b/hosts/srxnas01/services/minidlna/default.nix @@ -0,0 +1,23 @@ +{ + users.users.minidlna.extraGroups = [ "users" ]; + + services.minidlna = { + enable = true; + openFirewall = true; + + settings = { + inotify = "yes"; + friendly_name = "srx"; + + media_dir = [ + "V,/srv/movies" + "A,/srv/music" + ]; + + extraConfig = '' + enable_tivo=no + max_connections=50 + ''; + }; + }; +} diff --git a/hosts/srxnas01/services/samba/default.nix b/hosts/srxnas01/services/samba/default.nix new file mode 100644 index 0000000..7129105 --- /dev/null +++ b/hosts/srxnas01/services/samba/default.nix @@ -0,0 +1,97 @@ +{ + services.samba = { + enable = true; + openFirewall = true; + securityType = "user"; + extraConfig = '' + server string = %h + workgroup = srx + netbios name = %h + + logging = systemd + log level = 1 + + load printers = no + + server min protocol = SMB3 + client min protocol = SMB3 + + aio read size = 16384 + aio write size = 16384 + + security = user + map to guest = bad user + guest account = nobody + invalid users = root + force group = users + create mask = 0660 + directory mask = 0770 + ''; + + shares = { + public = { + comment = "public exchange share"; + path = "/srv/public"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "yes"; + }; + + movies = { + comment = "privat movie share"; + path = "/srv/movies"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "yes"; + }; + + music = { + comment = "privat music share"; + path = "/srv/music"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "yes"; + }; + + home = { + comment = "privat home share"; + path = "/srv/home"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "no"; + }; + + documents = { + comment = "privat document share"; + path = "/srv/documents"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "no"; + }; + + pictures = { + comment = "privat picture share"; + path = "/srv/pictures"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "no"; + }; + + videos = { + comment = "privat video share"; + path = "/srv/videos"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "no"; + }; + + backups = { + comment = "privat samba share."; + path = "/srv/backups"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "no"; + }; + }; + }; +} diff --git a/hosts/srxnas01/storage.nix b/hosts/srxnas01/storage.nix new file mode 100644 index 0000000..2ad4491 --- /dev/null +++ b/hosts/srxnas01/storage.nix @@ -0,0 +1,177 @@ +{ lib, ... }: +let + disks = { + system = [ "/dev/disk/by-id/nvme-eui.0025385a81b4239b" ]; + data = [ "/dev/disk/by-id/wwn-0x5000c500d6b1b870" ]; + }; + compression = "zstd"; + rootFsOptions = { + acltype = "posixacl"; + dnodesize = "auto"; + normalization = "formD"; + xattr = "sa"; + relatime = "on"; + canmount = "off"; + mountpoint = "none"; + inherit compression; + "com.sun:auto-snapshot" = "false"; + }; + options = { + ashift = "12"; + autotrim = "on"; + }; + passwordFile = "/etc/hostname"; + system = lib.genAttrs disks.system + (device: + let + name = builtins.replaceStrings [ "_" ] [ "-" ] (lib.lists.last (builtins.split "/" device)); + in + { + type = "disk"; + inherit name device; + content = { + type = "gpt"; + partitions = { + esp = { + size = "1G"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + system = { + size = "100%"; + content = { + type = "luks"; + inherit name; + content = { + type = "zfs"; + pool = "system"; + }; + inherit passwordFile; + settings.allowDiscards = true; + }; + }; + }; + }; + }); + data = lib.genAttrs disks.data + (device: + let + name = builtins.replaceStrings [ "_" ] [ "-" ] (lib.lists.last (builtins.split "/" device)); + in + { + type = "disk"; + inherit name device; + content = { + type = "gpt"; + partitions = { + data = { + size = "100%"; + content = { + type = "luks"; + inherit name; + content = { + type = "zfs"; + pool = "data"; + }; + inherit passwordFile; + settings.allowDiscards = true; + }; + }; + }; + }; + }); + default = mountpoint: { + type = "zfs_fs"; + options = { + inherit mountpoint; + }; + inherit mountpoint; + }; + auto_snapshot = mountpoint: { + type = "zfs_fs"; + options = { + inherit mountpoint; + "com.sun:auto-snapshot" = "true"; + }; + inherit mountpoint; + }; + can_not_mount = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + }; + mountpoint = null; + mountOptions = [ ]; + }; +in +{ + disko.devices = { + disk = system // data; + zpool = { + system = { + type = "zpool"; + inherit options rootFsOptions; + mountpoint = null; + datasets = { + "reserved" = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + refreservation = "10GiB"; + }; + mountpoint = null; + mountOptions = [ ]; + }; + "nixos" = can_not_mount; + "nixos/etc" = default "/etc"; + "nixos/nix" = default "/nix"; + "user" = can_not_mount; + "user/root" = default "/root"; + "user/home" = auto_snapshot "/home"; + "var" = can_not_mount; + "var/lib" = auto_snapshot "/var/lib"; + "var/log" = default "/var/log"; + "var/cache" = default "/var/cache"; + "var/backup" = default "/var/backup"; + }; + }; + data = { + type = "zpool"; + inherit options rootFsOptions; + mountpoint = null; + datasets = { + "data" = can_not_mount; + "data/backups" = default "/srv/backups"; + "data/home" = auto_snapshot "/srv/home"; + "data/documents" = auto_snapshot "/srv/documents"; + "data/movies" = default "/srv/movies"; + "data/music" = default "/srv/music"; + "data/pictures" = default "/srv/pictures"; + "data/videos" = default "/srv/videos"; + "data/public" = default "/srv/public"; + }; + }; + }; + nodev = { + "/" = { + fsType = "tmpfs"; + mountOptions = [ + "defaults" + "size=1G" + "mode=755" + "noatime" + ]; + }; + "/tmp" = { + fsType = "tmpfs"; + mountOptions = [ "size=1G" ]; + }; + }; + }; +} diff --git a/hosts/srxnas01/vpn_srx.age b/hosts/srxnas01/vpn_srx.age new file mode 100644 index 0000000..6603d4d Binary files /dev/null and b/hosts/srxnas01/vpn_srx.age differ diff --git a/hosts/srxnb00/clevis.age b/hosts/srxnb00/clevis.age new file mode 100644 index 0000000..f48b20e Binary files /dev/null and b/hosts/srxnb00/clevis.age differ diff --git a/hosts/srxnb00/default.nix b/hosts/srxnb00/default.nix new file mode 100644 index 0000000..917aa46 --- /dev/null +++ b/hosts/srxnb00/default.nix @@ -0,0 +1,24 @@ +{ inputs, lib, ... }: +{ + imports = with inputs; [ + self.nixosModules.roles-workstation + self.nixosModules.services-storage-syncthing + ./hardware.nix + ./storage.nix + ./services/wireguard.nix + ./services/restic + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "srxnb00"; + domain = "srx.digital"; + hostId = "e7c5e58f"; + }; + + nix = { + gc.options = "--delete-older-than 30d"; + settings.cores = lib.mkForce 12; + }; +} diff --git a/hosts/srxnb00/hardware.nix b/hosts/srxnb00/hardware.nix new file mode 100644 index 0000000..ff15178 --- /dev/null +++ b/hosts/srxnb00/hardware.nix @@ -0,0 +1,49 @@ +{ inputs, config, modulesPath, ... }: +{ + imports = with inputs; [ + (modulesPath + "/installer/scan/not-detected.nix") + self.nixosModules.hardware + self.nixosModules.hardware-laptop + self.nixosModules.hardware-cpu-amd + self.nixosModules.hardware-gpu-amd + self.nixosModules.filesystems-zfs + self.nixosModules.hardware-security-secureboot + ]; + + age.secrets.clevis.file = ./clevis.age; + + boot = { + initrd = { + systemd = { + enable = true; + inherit (config.systemd) network; + }; + network = { + enable = true; + ssh = { + enable = true; + authorizedKeys = config.users.users.root.openssh.authorizedKeys.keys; + port = 2222; + hostKeys = [ /etc/ssh/ssh_host_ed25519_key_initrd ]; + }; + }; + availableKernelModules = [ + "nvme" + "xhci_pci" + "usb_storage" + "sd_mod" + "sdhci_pci" + "r8169" + ]; + kernelModules = [ ]; + clevis = { + enable = true; + devices."nvme-eui.002538ba11c0820c".secretFile = config.age.secrets.clevis.path; + }; + }; + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + }; +} diff --git a/hosts/srxnb00/services/restic/default.nix b/hosts/srxnb00/services/restic/default.nix new file mode 100644 index 0000000..f7f46ae --- /dev/null +++ b/hosts/srxnb00/services/restic/default.nix @@ -0,0 +1,69 @@ +{ config, pkgs, ... }: +{ + age.secrets = { + resticRepoKey = { + file = ./repo_key.age; + group = "crstl"; + mode = "0440"; + }; + + resticRepoSsh = { + file = ./repo_ssh.age; + group = "crstl"; + mode = "0440"; + }; + }; + + services.restic.backups.srxnb00_crstl = { + initialize = true; + repository = "sftp:automat@srxnas01.vpn.srx.dev:/srv/backups/restic/srxnb00_crstl"; + passwordFile = config.age.secrets.resticRepoKey.path; + extraOptions = [ + "sftp.command='ssh -i ${config.age.secrets.resticRepoSsh.path} automat@srxnas01.vpn.srx.dev -s sftp'" + ]; + paths = [ + "/etc" + "/home/crstl/.age" + "/home/crstl/.config" + "/home/crstl/.gnupg" + "/home/crstl/.mozilla" + "/home/crstl/.password-store" + "/home/crstl/.pki" + "/home/crstl/.ssh" + "/home/crstl/.thunderbird" + "/home/crstl/Development" + "/home/crstl/Documents" + "/home/crstl/Pictures" + ]; + exclude = [ + "/home/crstl/.cache" + "/home/crstl/.cargo" + "/home/crstl/.conda" + "/home/crstl/.kube/cache" + "/home/crstl/.local" + "/home/crstl/.npm" + "/home/crstl/.npm" + "/home/crstl/.npm-global" + "/home/crstl/.phoronix-test-suite" + "/home/crstl/.torrent" + "/home/crstl/Downloads" + "/home/crstl/Music" + "/home/crstl/Nextcloud" + "/home/crstl/Videos" + ]; + checkOpts = [ "--with-cache" ]; + timerConfig = { + Persistent = true; + OnCalendar = "daily"; + RandomizedDelaySec = "5h"; + }; + pruneOpts = [ + "--keep-daily 7" + "--keep-weekly 5" + "--keep-monthly 12" + "--keep-yearly 1" + ]; + }; + + environment.systemPackages = with pkgs; [ restic ]; +} diff --git a/hosts/srxnb00/services/restic/repo_key.age b/hosts/srxnb00/services/restic/repo_key.age new file mode 100644 index 0000000..8f8904c Binary files /dev/null and b/hosts/srxnb00/services/restic/repo_key.age differ diff --git a/hosts/srxnb00/services/restic/repo_ssh.age b/hosts/srxnb00/services/restic/repo_ssh.age new file mode 100644 index 0000000..3ed6583 Binary files /dev/null and b/hosts/srxnb00/services/restic/repo_ssh.age differ diff --git a/hosts/srxnb00/services/wireguard.nix b/hosts/srxnb00/services/wireguard.nix new file mode 100644 index 0000000..1f80738 --- /dev/null +++ b/hosts/srxnb00/services/wireguard.nix @@ -0,0 +1,67 @@ +{ config, ... }: +{ + age.secrets = { + vpnSrx = { + file = ../vpn_srx.age; + owner = "systemd-network"; + }; + vpnCcl = { + file = ../vpn_ccl.age; + owner = "systemd-network"; + }; + }; + + systemd.network = { + netdevs = { + "50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + "51-vpn_ccl" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_ccl"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnCcl.path; + ListenPort = 51821; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "0AJ9FTSIPIM1eQaxtCdLMZYDyHfdJBKRwlftMSFRWB8="; + AllowedIPs = [ "10.80.1.0/24" ]; + Endpoint = "116.202.240.209:51820"; + }; + }]; + }; + }; + + networks = { + "vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.100/24" ]; + }; + "vpn_ccl" = { + matchConfig.Name = "vpn_ccl"; + address = [ "10.80.1.100/24" ]; + }; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; +} diff --git a/hosts/srxnb00/storage.nix b/hosts/srxnb00/storage.nix new file mode 100644 index 0000000..bfe52ac --- /dev/null +++ b/hosts/srxnb00/storage.nix @@ -0,0 +1,144 @@ +{ lib, ... }: +let + disks = [ "/dev/disk/by-id/nvme-eui.002538ba11c0820c" ]; + compression = "zstd"; + rootFsOptions = { + acltype = "posixacl"; + dnodesize = "auto"; + normalization = "formD"; + xattr = "sa"; + relatime = "on"; + canmount = "off"; + mountpoint = "none"; + inherit compression; + "com.sun:auto-snapshot" = "false"; + }; + passwordFile = "/etc/hostname"; + system = lib.genAttrs disks + (device: + let + name = builtins.replaceStrings [ "_" ] [ "-" ] (lib.lists.last (builtins.split "/" device)); + in + { + type = "disk"; + inherit name device; + content = { + type = "gpt"; + partitions = { + boot = { + size = "1M"; + type = "EF02"; + }; + esp = { + size = "1G"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + swap = { + size = "8G"; + type = "8200"; + content = { + type = "swap"; + randomEncryption = true; + priority = 100; + }; + }; + system = { + size = "100%"; + content = { + type = "luks"; + inherit name; + content = { + type = "zfs"; + pool = "system"; + }; + inherit passwordFile; + settings.allowDiscards = true; + }; + }; + }; + }; + }); + default = mountpoint: { + type = "zfs_fs"; + options = { + inherit mountpoint; + }; + inherit mountpoint; + }; + auto_snapshot = mountpoint: { + type = "zfs_fs"; + options = { + inherit mountpoint; + "com.sun:auto-snapshot" = "true"; + }; + inherit mountpoint; + }; + can_not_mount = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + }; + mountpoint = null; + mountOptions = [ ]; + }; +in +{ + disko.devices = { + disk = system; + zpool = { + system = { + type = "zpool"; + options = { + ashift = "12"; + autotrim = "on"; + }; + inherit rootFsOptions; + mountpoint = null; + datasets = { + "reserved" = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + refreservation = "10GiB"; + }; + mountpoint = null; + mountOptions = [ ]; + }; + "nixos" = can_not_mount; + "nixos/etc" = default "/etc"; + "nixos/nix" = default "/nix"; + "user" = can_not_mount; + "user/root" = default "/root"; + "user/home" = auto_snapshot "/home"; + "data" = can_not_mount; + "data/lib" = auto_snapshot "/var/lib"; + "data/log" = default "/var/log"; + "data/cache" = default "/var/cache"; + "data/backup" = default "/var/backup"; + }; + }; + }; + nodev = { + "/" = { + fsType = "tmpfs"; + mountOptions = [ + "defaults" + "size=1G" + "mode=755" + "noatime" + ]; + }; + "/tmp" = { + fsType = "tmpfs"; + mountOptions = [ "size=1G" ]; + }; + }; + }; +} diff --git a/hosts/srxnb00/vpn_ccl.age b/hosts/srxnb00/vpn_ccl.age new file mode 100644 index 0000000..242d257 Binary files /dev/null and b/hosts/srxnb00/vpn_ccl.age differ diff --git a/hosts/srxnb00/vpn_srx.age b/hosts/srxnb00/vpn_srx.age new file mode 100644 index 0000000..c234462 Binary files /dev/null and b/hosts/srxnb00/vpn_srx.age differ diff --git a/hosts/srxtab00/default.nix b/hosts/srxtab00/default.nix new file mode 100644 index 0000000..35b792a --- /dev/null +++ b/hosts/srxtab00/default.nix @@ -0,0 +1,17 @@ +{ inputs, ... }: +{ + imports = with inputs; [ + self.nixosModules.roles-workstation + self.nixosModules.services-storage-syncthing + ./hardware.nix + ./services/wireguard.nix + ]; + + system.stateVersion = "23.11"; + + networking = { + hostName = "srxtab00"; + domain = "srx.digital"; + hostId = "81774791"; + }; +} diff --git a/hosts/srxtab00/hardware.nix b/hosts/srxtab00/hardware.nix new file mode 100644 index 0000000..a72a5b7 --- /dev/null +++ b/hosts/srxtab00/hardware.nix @@ -0,0 +1,95 @@ +{ inputs, lib, modulesPath, pkgs, ... }: +{ + imports = with inputs; [ + (modulesPath + "/installer/scan/not-detected.nix") + self.nixosModules.hardware + self.nixosModules.hardware-cpu-intel + self.nixosModules.hardware-gpu-intel + self.nixosModules.hardware-security-secureboot + nixos-hardware.nixosModules.microsoft-surface-go + ]; + + boot = { + initrd = { + availableKernelModules = [ + "nvme" + "rtsx_pci_sdmmc" + "usbhid" + "xhci_pci" + ]; + kernelModules = [ ]; + luks.devices.system = { + device = "/dev/disk/by-uuid/1f66cad5-a9ed-4ca1-b0c2-49436a762ee5"; + allowDiscards = true; + bypassWorkqueues = true; + }; + }; + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + + # use the mainline kernel, since wireplumber segfaults with the nixos-hardware version + kernelPackages = lib.mkForce pkgs.linuxPackages_latest; + }; + + fileSystems = { + "/" = { + device = "none"; + fsType = "tmpfs"; + options = [ + "noatime" + "size=20%" + "mode=755" + ]; + }; + + "/boot" = { + device = "/dev/disk/by-uuid/9A9A-B16F"; + fsType = "vfat"; + }; + + "/nix" = { + device = "/dev/disk/by-uuid/ac0096c0-3e16-4f29-8730-581cff1b0d91"; + fsType = "btrfs"; + options = [ + "noatime" + "discard=async" + "subvol=nix" + ]; + neededForBoot = true; + }; + + "/persist" = { + device = "/dev/disk/by-uuid/ac0096c0-3e16-4f29-8730-581cff1b0d91"; + fsType = "btrfs"; + options = [ + "noatime" + "discard=async" + "subvol=persist" + ]; + neededForBoot = true; + }; + }; + + age.identityPaths = [ "/persist/etc/ssh/ssh_host_ed25519_key" ]; + + environment.persistence."/persist" = { + files = [ + "/etc/machine-id" + "/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" + ]; + directories = [ + "/etc/secureboot" + "/home" + "/etc/NetworkManager" + "/var/log" + "/var/lib" + ]; + }; + + services.thermald.enable = lib.mkForce false; +} diff --git a/hosts/srxtab00/services/wireguard.nix b/hosts/srxtab00/services/wireguard.nix new file mode 100644 index 0000000..f42852c --- /dev/null +++ b/hosts/srxtab00/services/wireguard.nix @@ -0,0 +1,35 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.9/24" ]; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; +} diff --git a/hosts/srxtab00/vpn_srx.age b/hosts/srxtab00/vpn_srx.age new file mode 100644 index 0000000..57e1721 --- /dev/null +++ b/hosts/srxtab00/vpn_srx.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw lMiJgOtZjQmEA6uHZaj0hOm1c+nEzcluTDY+t0aGwlY +g33NxHReXUJnttwuvwgAssuwR96Qk0IYq0tWYUWbLnY +-> ssh-ed25519 JzjriQ PfLdV9B5wuV6H+vqmAWE73ZQC687izR+3Qx6uytCwTs +mpOYSzUpRlj7TJyKwldjl30xNfWMqDYdPuAyWPXkk5k +-> ssh-rsa 6hPx7A +E0WTEOxtajBGtbHWtfXJtASHvJ/jzP9SDzK6/wQuY18D8dhSwPBBYZW2umcIxHRf +tiZtUR6Xfea85pwvRbrVtG4OgD6VrX5RHDezCpooIUq124emGUuAXLnXsiaK2gU8 +VeENmZMruutCPA1AdjMrlv3Hu/WoCX32ddZdRUdnkbezb8j+wV00CJFcljEogXmq +O8vkHWxLPz+aPepg/VUhPrZ1bgxdxutPh/B5BodC1NAo2IpkTGyvVAPIbxgYPAWO +/JQZmJf1bqCcKyoCig/CggUwBXrK2nFk+ozbUYrJaBivnWIRJXMZDC9RAy+/dlsk +z/941Re6jW7sZdd93T16L1Wy8OnSo9yaaNB2FvxZC3lx0lU76S/Rf4Z4lRpLsPdX +pyvGQLBHAC5z39paTp7IdRBWePi7TU+ZD8EaBDZDK6WVsJf2CayXA0zm9Hbws7ha +1im2a9tLY5y/hm60ElKqT8J6Vd2Ord4XdFl/EBzaGXKVm4wpjq2nZFOXJpfiLs9L +hvwo9h4ixovAORNcos4HexlWYvUmMJt2jIfKQf3+5cOiK5+2dxGh2uDGDvBY6/G1 +tpx2VoZrkOarinUYx+aroAsNKZWQ74wNPzk5TFMKQQJ5n7BrfXpB4d84E19D+Ytg +WrJ3I/aGtkjd7N0OWaUnBDGKtIjwtQELvCBIVesxhZo +-> ssh-ed25519 xkaJLw pAC7AHHNlB6fESC3kXRvb/D+ZBXQrTLBpXsnX01xqzg +7Oe0RTbzF2WA5yQmbb8DfjPN4UVi8E2ZKmuzrXevZNM +--- tQ29HZq8ATniDoqMqoEznzo//PJdGeM5ra3JaW1nHRg +'S+\hqِ^<DnOz5@C Ҡ/6 Mq繊Զֿ\RLX \ No newline at end of file diff --git a/hosts/srxws00/default.nix b/hosts/srxws00/default.nix new file mode 100644 index 0000000..bd70866 --- /dev/null +++ b/hosts/srxws00/default.nix @@ -0,0 +1,25 @@ +{ inputs, ... }: +{ + imports = with inputs; [ + self.nixosModules.roles-workstation + self.nixosModules.filesystems-zfs + self.nixosModules.services-storage-syncthing + ./hardware.nix + ./storage.nix + ./services/wireguard.nix + ./services/nfs.nix + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "srxws00"; + domain = "srx.digital"; + hostId = "9222a8ae"; + + interfaces = { + eno1.wakeOnLan.enable = true; + eno2.wakeOnLan.enable = true; + }; + }; +} diff --git a/hosts/srxws00/hardware.nix b/hosts/srxws00/hardware.nix new file mode 100644 index 0000000..0dcb856 --- /dev/null +++ b/hosts/srxws00/hardware.nix @@ -0,0 +1,33 @@ +{ inputs, config, modulesPath, ... }: +{ + imports = with inputs; [ + (modulesPath + "/installer/scan/not-detected.nix") + self.nixosModules.hardware + self.nixosModules.hardware-cpu-intel + self.nixosModules.hardware-gpu-amd + self.nixosModules.hardware-security-secureboot + nixos-hardware.nixosModules.supermicro-x10sll-f + ]; + + boot = { + initrd = { + availableKernelModules = [ + "ahci" + "ehci_pci" + "nvme" + "usb_storage" + "usbhid" + "xhci_pci" + ]; + kernelModules = [ ]; + systemd = { + enable = true; + inherit (config.systemd) network; + }; + }; + loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + }; +} diff --git a/hosts/srxws00/services/nfs.nix b/hosts/srxws00/services/nfs.nix new file mode 100644 index 0000000..6b34594 --- /dev/null +++ b/hosts/srxws00/services/nfs.nix @@ -0,0 +1,69 @@ +{ + fileSystems = { + "/mnt/home" = { + device = "srxnas01.op.hq.hh.srx.dev:/export/mnt"; + fsType = "nfs"; + options = [ + "noauto" + "X-mount.mkdir" + "x-systemd.automount" + "x-systemd.idle-timeout=600" + ]; + }; + + "/mnt/backup" = { + device = "srxnas01.op.hq.hh.srx.dev:/export/backup"; + fsType = "nfs"; + options = [ + "noauto" + "X-mount.mkdir" + "x-systemd.automount" + "x-systemd.idle-timeout=600" + ]; + }; + + "/mnt/pictures" = { + device = "srxnas01.op.hq.hh.srx.dev:/export/pictures"; + fsType = "nfs"; + options = [ + "noauto" + "X-mount.mkdir" + "x-systemd.automount" + "x-systemd.idle-timeout=600" + ]; + }; + + "/mnt/music" = { + device = "srxnas01.op.hq.hh.srx.dev:/export/music"; + fsType = "nfs"; + options = [ + "noauto" + "X-mount.mkdir" + "x-systemd.automount" + "x-systemd.idle-timeout=600" + ]; + }; + + "/mnt/videos" = { + device = "srxnas01.op.hq.hh.srx.dev:/export/videos"; + fsType = "nfs"; + options = [ + "noauto" + "X-mount.mkdir" + "x-systemd.automount" + "x-systemd.idle-timeout=600" + ]; + }; + + "/mnt/movies" = { + device = "srxnas01.op.hq.hh.srx.dev:/export/movies"; + fsType = "nfs"; + options = [ + "noauto" + "X-mount.mkdir" + "x-systemd.automount" + "x-systemd.idle-timeout=600" + ]; + }; + }; +} diff --git a/hosts/srxws00/services/wireguard.nix b/hosts/srxws00/services/wireguard.nix new file mode 100644 index 0000000..0c8142a --- /dev/null +++ b/hosts/srxws00/services/wireguard.nix @@ -0,0 +1,35 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.3/24" ]; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; +} diff --git a/hosts/srxws00/storage.nix b/hosts/srxws00/storage.nix new file mode 100644 index 0000000..d5b2b08 --- /dev/null +++ b/hosts/srxws00/storage.nix @@ -0,0 +1,98 @@ +{ lib, ... }: +let + disks = [ "/dev/disk/by-id/nvme-SKHynix_HFS001TDE9X081N_ADA6N43261050645J" ]; +in +{ + disko.devices = { + disk = lib.genAttrs disks (device: { + name = lib.last (lib.splitString "/" device); + inherit device; + content = { + type = "gpt"; + partitions = { + ESP = { + label = "EFI"; + name = "ESP"; + type = "EF00"; + start = "1MiB"; + end = "512MiB"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + SYSTEM = { + size = "100%"; + content = { + type = "luks"; + name = "crypted"; + passwordFile = "/etc/hostname"; + settings.allowDiscards = true; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + subvolumes = { + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/var" = { + mountpoint = "/var"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/etc" = { + mountpoint = "/etc"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/root" = { + mountpoint = "/root"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + "/home" = { + mountpoint = "/home"; + mountOptions = [ + "compress=zstd" + "discard=async" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }; + }); + nodev = { + "/" = { + fsType = "tmpfs"; + mountOptions = [ + "size=1G" + "mode=755" + "noatime" + ]; + }; + "/tmp" = { + fsType = "tmpfs"; + mountOptions = [ "size=1G" ]; + }; + }; + }; +} diff --git a/hosts/srxws00/vpn_srx.age b/hosts/srxws00/vpn_srx.age new file mode 100644 index 0000000..9959a0a Binary files /dev/null and b/hosts/srxws00/vpn_srx.age differ diff --git a/hosts/srxws01/clevis.age b/hosts/srxws01/clevis.age new file mode 100644 index 0000000..8ef0ecb Binary files /dev/null and b/hosts/srxws01/clevis.age differ diff --git a/hosts/srxws01/default.nix b/hosts/srxws01/default.nix new file mode 100644 index 0000000..22ed0e7 --- /dev/null +++ b/hosts/srxws01/default.nix @@ -0,0 +1,36 @@ +{ inputs, ... }: +{ + imports = with inputs; [ + self.nixosModules.roles-workstation + self.nixosModules.filesystems-zfs + self.nixosModules.services-storage-syncthing + ./hardware.nix + ./storage.nix + ./services/wireguard.nix + ]; + + system.stateVersion = "24.05"; + + networking = { + hostName = "srxws01"; + domain = "srx.digital"; + hostId = "591d44f4"; + + interfaces = { + eno1.wakeOnLan.enable = true; + eno2.wakeOnLan.enable = true; + }; + }; + + systemd.network = { + enable = true; + networks."10-uplink" = { + matchConfig.Name = "eno1"; + address = [ "10.50.0.11/23" ]; + routes = [ + { routeConfig.Gateway = "10.50.0.1"; } + { routeConfig.Gateway = "fe80::1"; } + ]; + }; + }; +} diff --git a/hosts/srxws01/hardware.nix b/hosts/srxws01/hardware.nix new file mode 100644 index 0000000..49011dd --- /dev/null +++ b/hosts/srxws01/hardware.nix @@ -0,0 +1,52 @@ +{ inputs, modulesPath, config, ... }: +{ + imports = with inputs; [ + (modulesPath + "/installer/scan/not-detected.nix") + self.nixosModules.hardware + self.nixosModules.hardware-cpu-intel + self.nixosModules.hardware-gpu-amd + nixos-hardware.nixosModules.common-cpu-intel-sandy-bridge + ]; + + age.secrets.clevis.file = ./clevis.age; + + boot = { + initrd = { + systemd = { + enable = true; + inherit (config.systemd) network; + }; + availableKernelModules = [ + "ahci" + "ehci_pci" + "nvme" + "usb_storage" + "usbhid" + "xhci_pci" + "r8169" + ]; + kernelModules = [ ]; + network = { + enable = true; + ssh = { + enable = true; + authorizedKeys = config.users.users.root.openssh.authorizedKeys.keys; + port = 2222; + hostKeys = [ /etc/ssh/ssh_host_ed25519_key_initrd ]; + }; + }; + # clevis = { + # enable = true; + # useTang = true; + # devices."sda".secretFile = config.age.secrets.clevis.path; + # }; + }; + loader = { + grub = { + enable = true; + device = "/dev/disk/by-id/wwn-0x500253887015385a"; + }; + efi.canTouchEfiVariables = true; + }; + }; +} diff --git a/hosts/srxws01/services/wireguard.nix b/hosts/srxws01/services/wireguard.nix new file mode 100644 index 0000000..1ff455d --- /dev/null +++ b/hosts/srxws01/services/wireguard.nix @@ -0,0 +1,35 @@ +{ config, ... }: +{ + age.secrets.vpnSrx = { + file = ../vpn_srx.age; + owner = "systemd-network"; + }; + + systemd.network = { + netdevs."50-vpn_srx" = { + netdevConfig = { + Kind = "wireguard"; + Name = "vpn_srx"; + MTUBytes = "1300"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets.vpnSrx.path; + ListenPort = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig = { + PublicKey = "MPvns6jFwZPJvzZtxEDIMSIBBBtBQKBWQ8us3Wgj0mc="; + AllowedIPs = [ "10.80.0.0/24" ]; + Endpoint = "65.108.77.254:51820"; + }; + }]; + }; + + networks."vpn_srx" = { + matchConfig.Name = "vpn_srx"; + address = [ "10.80.0.8/24" ]; + }; + }; + + networking.firewall.trustedInterfaces = [ "vpn_srx" ]; +} diff --git a/hosts/srxws01/storage.nix b/hosts/srxws01/storage.nix new file mode 100644 index 0000000..2e89c7d --- /dev/null +++ b/hosts/srxws01/storage.nix @@ -0,0 +1,135 @@ +{ lib, ... }: +let + disks = [ "/dev/sda" ]; + compression = "zstd"; + rootFsOptions = { + acltype = "posixacl"; + dnodesize = "auto"; + normalization = "formD"; + xattr = "sa"; + relatime = "on"; + canmount = "off"; + mountpoint = "none"; + inherit compression; + "com.sun:auto-snapshot" = "false"; + }; + passwordFile = "/etc/hostname"; + system = lib.genAttrs disks + (device: + let + name = builtins.replaceStrings [ "_" ] [ "-" ] (lib.lists.last (builtins.split "/" device)); + in + { + type = "disk"; + inherit name device; + content = { + type = "gpt"; + partitions = { + boot = { + size = "1M"; + type = "EF02"; + }; + esp = { + size = "1G"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + system = { + size = "100%"; + content = { + type = "luks"; + inherit name; + content = { + type = "zfs"; + pool = "system"; + }; + inherit passwordFile; + settings.allowDiscards = true; + }; + }; + }; + }; + }); + default = mountpoint: { + type = "zfs_fs"; + options = { + inherit mountpoint; + }; + inherit mountpoint; + }; + auto_snapshot = mountpoint: { + type = "zfs_fs"; + options = { + inherit mountpoint; + "com.sun:auto-snapshot" = "true"; + }; + inherit mountpoint; + }; + can_not_mount = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + }; + mountpoint = null; + mountOptions = [ ]; + }; +in +{ + disko.devices = { + disk = system; + zpool = { + system = { + type = "zpool"; + options = { + ashift = "12"; + autotrim = "on"; + }; + inherit rootFsOptions; + mountpoint = null; + datasets = { + "reserved" = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + refreservation = "10GiB"; + }; + mountpoint = null; + mountOptions = [ ]; + }; + "nixos" = can_not_mount; + "nixos/etc" = default "/etc"; + "nixos/nix" = default "/nix"; + "user" = can_not_mount; + "user/root" = default "/root"; + "user/home" = auto_snapshot "/home"; + "data" = can_not_mount; + "data/lib" = auto_snapshot "/var/lib"; + "data/log" = default "/var/log"; + "data/cache" = default "/var/cache"; + "data/backup" = default "/var/backup"; + }; + }; + }; + nodev = { + "/" = { + fsType = "tmpfs"; + mountOptions = [ + "defaults" + "size=1G" + "mode=755" + "noatime" + ]; + }; + "/tmp" = { + fsType = "tmpfs"; + mountOptions = [ "size=1G" ]; + }; + }; + }; +} diff --git a/hosts/srxws01/vpn_srx.age b/hosts/srxws01/vpn_srx.age new file mode 100644 index 0000000..3a72ccb --- /dev/null +++ b/hosts/srxws01/vpn_srx.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw vj8zX+whDpCdCSVJgnSJZskUur3XRdyZezBXVfbnNW4 +zqAcqrop8ztrdvv9k41zcZpSfGwiKSOZZ/h55csKLLU +-> ssh-ed25519 JzjriQ 0fXTMwdHnjNEDN1QzBjqc2avm30r9nkcB5BkW+yiqk0 +tsEEmW0dtYlFUszS1/SYVg6Z2AUCxR7lglQQgkqCLUc +-> ssh-rsa 6hPx7A +M7mRYs2IU3IQpw5D5d59Vymjtx7BbUxG3ia5MS9Naxy0XvsvJuF+aWHaG6eofkwT +fMhYA11v3tAjmnMLg5Yeflp407iiYUE4IFS9tjJF6Vf9t48JDomlSSbmBaLdxFID +IznYr5TYnLX7cqg2k938pYQiwUkgXPlqXWfo0mZQl6eWgwicNJoV9RSAK+xeB0v5 +gh63v/lC45eJRax46ECZCUS1fiGjzrojzcgpFVfHwoXNxtp84Yo5LH9PjB2F5zUA +JrJo2l8oU5UfXr/ff4IRb9PFhJiuyrP2034kHYEFhC1y0QDMFVyYF8oLm9MCgaFK +IFSAHj5EeuQQ+gamUSmkdg5DIc2JtpMXAXQjHUsDmphKer4J1TmAl7QU0tVgswzQ +Fc/2a2j+xXGPIJv4Q8U/h4WDWi8O5RMxFsdbiVgTsYTlOWkGPbJY1+9mJCAE1IWB +wXiWQIjs+HRgjKkFvzlc+f9kr7ea/AkMj3Es1gpmNzYD2E65HkRIvWUOE2RAcLzD +xR+fNNB4rTnkByD51xqT+36uhDxB6dLmmvvHKh/4Cs32l3SvmnMvClI4JpteXdHY +mT90KDOPfgXK+yhXrnogOXIr0pkohBoP/zznfW5wOCbFvLEZgSPi+xnwN0uz+6gr +OVtsKoUh0JWuAcFI4wxRyW8nMTcW8N4T1fusEh/arSg +-> ssh-ed25519 Sk9VBA SzsxaOsMJnWoEYIL35fOjblvOdhQl6qvoZqfpnJyQTg +RX5DQpeJTviFFkZM6MT1OYCNRJqPZ+Hx44PBAMFUzQs +--- BVCT5FBu5kipw4jhqwiHsSMea+bO3tumrXBOnC2UWQM +XZD뇓ջ= XYG7)J7yo}p,P2) rϤR#%/dev/null 2>&1 || ${lib.getExe pkgs.vault} login -method=oidc + '' + else + ""; + in + { tofuCommand + , tufoConfig ? defaultTFConfig + , subdir ? defaultSubDir + , backend ? defaultBackend + , + }: + { + type = "app"; + program = toString (pkgs.writers.writeBash tofuCommand '' + pushd ${toString subdir} >/dev/null + ${vaultLogin} + if [[ -e config.tf.json ]]; then rm -f config.tf.json; fi + cp ${tufoConfig} config.tf.json \ + && ${lib.getExe opentofu} init ${if backend then "-upgrade" else "-backend=false"} \ + && ${lib.getExe opentofu} ${toString tofuCommand} $@ + popd >/dev/null + ''); + }; + + tf-validate = { + type = "app"; + program = toString (pkgs.writers.writeBash "tf-validate" '' + pushd ${toString subdir} >/dev/null + cp ${tufoConfig} config.tf.json \ + && ${lib.getExe opentofu} version \ + && ${lib.getExe opentofu} init -backend=false \ + && ${lib.getExe opentofu} validate \ + && ${lib.getExe opentofu} test \ + && ${pkgs.tfsec}/bin/tfsec --config-file ${tfsecConfig} \ + && ${pkgs.tflint}/bin/tflint + popd >/dev/null + ''); + }; + + tf2nix = { + type = "app"; + program = toString (pkgs.writers.writeBash "tf2nix" '' + HCL=$(realpath $@) + pushd ${toString subdir} >/dev/null + ${lib.getExe pkgs.hcl2json} $HCL > output.json + ${self.packages.${system}.json2nix}/bin/json2nix output.json + popd >/dev/null + ''); + }; + + tf-state = pkgs.runCommand "tf-state" { } '' + mkdir -p $out \ + && cp ${tufoConfig} config.tf.json \ + && cp ${tfsecConfig} tfsec.json \ + && ${lib.getExe opentofu} init -backend=false \ + && ${lib.getExe opentofu} version -json > terraform.json \ + && ${lib.getExe opentofu} validate \ + && ${pkgs.tfsec}/bin/tfsec --config-file ${tfsecConfig} \ + && ${pkgs.tflint}/bin/tflint \ + && cp tfsec.json terraform.json .terraform.lock.hcl $out + ''; + + mkApps = + commands: prefixMapper (genAttrs commands (tofuCommand: mkTofuApp { inherit tofuCommand; })); +} diff --git a/modules/custom/dns/knot/acls.nix b/modules/custom/dns/knot/acls.nix new file mode 100644 index 0000000..8420256 --- /dev/null +++ b/modules/custom/dns/knot/acls.nix @@ -0,0 +1,53 @@ +{ + services.knot.settings.acl = { + notify.action = "notify"; + + transfer = { + action = "transfer"; + address = [ + "10.80.0.5" # srxgp01 + "10.80.0.6" # srxgp02 + ]; + }; + + update = { + action = "update"; + address = [ + "10.80.0.0/24" + "127.0.0.1" + "::1/128" + ]; + key = "update"; + }; + + update_k8s = { + action = "update"; + address = [ + "10.80.0.0/24" + "127.0.0.1" + "::1/128" + ]; + key = "update_k8s"; + }; + + update_terraform_swendel = { + action = "update"; + address = [ + "10.80.0.0/24" + "127.0.0.1" + "::1/128" + ]; + key = "update_terraform_swendel"; + }; + + update_terraform_cicd = { + action = "update"; + address = [ + "10.80.0.0/24" + "127.0.0.1" + "::1/128" + ]; + key = "update_terraform_cicd"; + }; + }; +} diff --git a/modules/custom/dns/knot/default.nix b/modules/custom/dns/knot/default.nix new file mode 100644 index 0000000..3c2ce36 --- /dev/null +++ b/modules/custom/dns/knot/default.nix @@ -0,0 +1,15 @@ +{ self, ... }: +{ + imports = [ + self.nixosModules.services-dns-knot + self.nixosModules.custom-dns-zones + + ./secrets + ./acls.nix + ./policies.nix + ./remotes.nix + ./submission.nix + ./templates.nix + ./zones.nix + ]; +} diff --git a/modules/custom/dns/knot/policies.nix b/modules/custom/dns/knot/policies.nix new file mode 100644 index 0000000..3f9d567 --- /dev/null +++ b/modules/custom/dns/knot/policies.nix @@ -0,0 +1,23 @@ +{ + services.knot.settings.policy = { + denic_13 = { + keystore = "default"; + signing-threads = 4; + algorithm = "ecdsap256sha256"; + ksk-submission = "denic"; + ksk-lifetime = "365d"; + zsk-lifetime = "30d"; + propagation-delay = "1d"; + }; + + denic_13_test = { + keystore = "default"; + signing-threads = 4; + algorithm = "ecdsap256sha256"; + ksk-submission = "denic"; + ksk-lifetime = "14d"; + zsk-lifetime = "3d"; + propagation-delay = "1d"; + }; + }; +} diff --git a/modules/custom/dns/knot/remotes.nix b/modules/custom/dns/knot/remotes.nix new file mode 100644 index 0000000..9cd95e6 --- /dev/null +++ b/modules/custom/dns/knot/remotes.nix @@ -0,0 +1,73 @@ +{ + services.knot.settings.remote = { + srxgp00 = { + address = [ "10.80.0.1@853" ]; + cert-key = "EPap376f5O3gAIt36SaTceDgyE90GaANE9YCcjSRUbA="; + quic = true; + }; + + srxgp01 = { + address = [ "10.80.0.5@853" ]; + cert-key = "DFloXBI1hyI/aTGSEc+3ZjoeVz7a7Vi5AeP5ouKaByI="; + quic = true; + }; + + srxgp02 = { + address = [ "10.80.0.6@853" ]; + cert-key = "oq6Ig/gcTr7VCn7gQQjuMN2txkVZIJ58iSvrisxKE20="; + quic = true; + }; + + # denic + a_nic_de.address = [ + "194.0.0.53" + "2001:678:2::53" + ]; + f_nic_de.address = [ + "81.91.164.5" + "2a02:568:0:2::53" + ]; + l_de_net.address = [ + "77.67.63.105" + "2001:668:1f:11::105" + ]; + n_de_net.address = [ + "194.146.107.6" + "2001:67c:1011:1::53" + ]; + s_de_net.address = [ + "195.243.137.26" + "2003:8:14::53" + ]; + z_nic_de.address = [ + "194.246.96.1" + "2a02:568:fe02::de" + ]; + + # digital + v0n0_nic_digital.address = [ + "65.22.20.36" + "2a01:8840:16::36" + ]; + v0n1_nic_digital.address = [ + "65.22.21.36" + "2a01:8840:17::36" + ]; + v0n2_nic_digital.address = [ + "65.22.22.36" + "2a01:8840:18::36" + ]; + v0n3_nic_digital.address = [ + "161.232.10.36" + "2a01:8840:f4::36" + ]; + v2n0_nic_digital.address = [ + "65.22.23.36" + "2a01:8840:19::36" + ]; + v2n1_nic_digital.address = [ + "161.232.11.36" + "2a01:8840:f5::36" + ]; + }; +} diff --git a/modules/custom/dns/knot/secrets/default.nix b/modules/custom/dns/knot/secrets/default.nix new file mode 100644 index 0000000..89d238b --- /dev/null +++ b/modules/custom/dns/knot/secrets/default.nix @@ -0,0 +1,49 @@ +{ config, ... }: +{ + age.secrets = { + knot_key_xfr = { + file = ./tsig_xfr.age; + owner = "knot"; + }; + + knot_key_transfer = { + file = ./transfer.age; + owner = "knot"; + }; + + knot_key_notify = { + file = ./notify.age; + owner = "knot"; + }; + + knot_key_update = { + file = ./update.age; + owner = "knot"; + }; + + knot_key_update_k8s = { + file = ./update_k8s.age; + owner = "knot"; + }; + + knot_key_update_terraform_swendel = { + file = ./update_terraform_swendel.age; + owner = "knot"; + }; + + knot_key_update_terraform_cicd = { + file = ./update_terraform_cicd.age; + owner = "knot"; + }; + }; + + services.knot.keyFiles = [ + config.age.secrets.knot_key_xfr.path + config.age.secrets.knot_key_transfer.path + config.age.secrets.knot_key_notify.path + config.age.secrets.knot_key_update.path + config.age.secrets.knot_key_update_k8s.path + config.age.secrets.knot_key_update_terraform_swendel.path + config.age.secrets.knot_key_update_terraform_cicd.path + ]; +} diff --git a/modules/custom/dns/knot/secrets/notify.age b/modules/custom/dns/knot/secrets/notify.age new file mode 100644 index 0000000..9d05ac4 Binary files /dev/null and b/modules/custom/dns/knot/secrets/notify.age differ diff --git a/modules/custom/dns/knot/secrets/transfer.age b/modules/custom/dns/knot/secrets/transfer.age new file mode 100644 index 0000000..0082473 Binary files /dev/null and b/modules/custom/dns/knot/secrets/transfer.age differ diff --git a/modules/custom/dns/knot/secrets/tsig_xfr.age b/modules/custom/dns/knot/secrets/tsig_xfr.age new file mode 100644 index 0000000..bacf15a Binary files /dev/null and b/modules/custom/dns/knot/secrets/tsig_xfr.age differ diff --git a/modules/custom/dns/knot/secrets/update.age b/modules/custom/dns/knot/secrets/update.age new file mode 100644 index 0000000..b6e0e00 Binary files /dev/null and b/modules/custom/dns/knot/secrets/update.age differ diff --git a/modules/custom/dns/knot/secrets/update_k8s.age b/modules/custom/dns/knot/secrets/update_k8s.age new file mode 100644 index 0000000..0e8ec79 --- /dev/null +++ b/modules/custom/dns/knot/secrets/update_k8s.age @@ -0,0 +1,26 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw Q1229okMaQ7BBD8jW+trkE/531nZpPDm4gdEsi4HnnQ +f2V+08IAE4JCtdH7DZwuL0Qz3x6VyV/+NMYQbQrS4UA +-> ssh-ed25519 JzjriQ F44IX1AnOijWQvSIvNF+x31iKPRydUcGpN2+3WE4j1M +yZOfRden8DElpHIp/KQRlBe/M3SKti5E1k0chTpph9s +-> ssh-rsa 6hPx7A +rdClA1QsmF4XbN1c9riIOyXlQ+037DPk/NHUUsTKPmUUf79fsd7xy0ysAOgyMmFF +876OPD78ADNE0b0LHCs40WW+gzjMafRWZ4UOZJuPxf00VD4+Gpa7rzJ7DoEgub9C +lvbVbwgqU453q1qSheFdZudO06W1HccobEbHA5IbScDNQZUhGEcHpKs2+8J6VlO3 +gb6FyTU2cEU/oT+/fQxNjxqk1u7sVQp2jJ7f216zlcDWJ48yqdZwHi7w16mZyowy +dlWw5mdTqmZGgPEBDf8Bleewgh2MuDeodsLfzWPibwYKMJGd1AeidTzcUmIvQnW4 +dabhLXn3Hhy+GXV/ENrtly7oNgj50EdWWh3esRXJG8kZPBAZYvf9Aya+Uy/UyyfU +q5OSNBSJ6ML2Dor7vCWw1ZE0vLbXY/ikGuScGUVb26G2LhwjtT3d7Voc3Zda6iTs +2uraU5r9q0YFwvqIRDq3UYLM8uvxf1xBodf83JOpr2VNyLmIJuubKXGDm3mk4Vn4 +0Nu8X6/A01wTlsXUJeKPHL3Q9WM0NOOsPC1Ks5l57OIymLfob4Dq1uOCvCUdJFRm +iYj2a8mf9TnR32fAkV9LDPM9TIsFXIS/tpA0AIRe5FgQ07JhGhuRhAzi4Kf2Lswa +RBHQuZcrSMZ89zqMPSfE3FCQvBbysq0OikgmufJv3Bs +-> ssh-ed25519 Dfencg KDa5YlsXrSBJPs/hpGpsYfMr6sKhK4aZigUwDd/Wp3Y +IyWUtpbC1WUrfSgYUt+EMmScAsz9Z0jCl4oE9N/UCEc +-> ssh-ed25519 OWgoVA rUeWC6dgBvHQaMlk45u/0TyGi0JlQ+qZSDFfHZYSijE +Jc+YAfBn1xm2kAIzlb+u0Fta1G2T+F8VBlUjararGWU +-> ssh-ed25519 aP/BWw 4NIQEGBA05hGP8liXq3DP1XU50T0GUVvFlGQu4l7aD4 +7pgd/qKlWRw489to8Y9VdFp4pGpWQexrvadyEqhD7ms +--- IkR9E4EZw5kUePnJK2+xALsjdvfknKW4NTUoUqulewg +)mS5Z#[i rcct.C˒: cAAÃ.ʨ鳨&-v*R5Խ "kځq QB +,#&']qx276A}m@, QkW9 Sf҂` \ No newline at end of file diff --git a/modules/custom/dns/knot/secrets/update_terraform_cicd.age b/modules/custom/dns/knot/secrets/update_terraform_cicd.age new file mode 100644 index 0000000..4531674 --- /dev/null +++ b/modules/custom/dns/knot/secrets/update_terraform_cicd.age @@ -0,0 +1,26 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw MeB3IYguHb/KbEx1Tzli1uq2gOJVkrwCvrid6TUeWGA +x9PIk2zvGNwFm+DybuhFUo7ZRhF6geyASAd9Nxo/Miw +-> ssh-ed25519 JzjriQ MLV2mPDbStlt4YrNmv9UtSDtmK7L4wR7M2IuEakVLGU +fxh7dgU0Cu0ZTER8b24M0iv7wKeVdVE7CGqNF7Igobg +-> ssh-rsa 6hPx7A +Btd0qiGDyGyYX+UxXUfEd5voTplxZ/tqi/yfF2+Ss23DVeWWLk3TnNfiMR15eTUG +elAqDU5/MghPdqXEnTwzAoksb8w2yonzOHunSQu3hYUyvWaDvCMfGgJ9WP/zSsmv +Loe7jSwv8qcXEB4QvhvIBSjqU7s2Orms4Py0Xe9NihLsmwF+or65gOt6TBsn9t9W +Dzmc7ASFZj5Vb7ryNIgw9CCWyd7trRzCIRoE8znQqxdTJwY4kFbTFlKWyAXZ3KsP +dxmlClWS7eYM5Zd2a4b9V2CsDzY8pIM6QL827eHRVyqCg7xf3AoCJZvpo09iZyHR +pjlYE0sXM/i2suRk/aWliGih5/XJQhK1C0RNQpK305RicGj4vP5fkfXGMlpWV8UU +B/ozQMQFsgfsxPzgR2j3BfYWrvZC45WbB2pgUqNRDsqiSJEvSaI+7ezqZLYw9IGu +/G8AVbZLaAdm22OFlxOKwFcs6FtGure3gPGb39KW3IAqhesd0SpgV1GvnarSzXko +x4Qh7A1uKfIPY+IfZ0EgA1EpdWwrmUBtuTsJPrQymfAKUNcHgkFGfQPgpkHiacsY +9XG9FqaCWr+3qCWOy65nbVqB9h2ORCq2IXcfnfnRZFej9kAPDXpeuYFuipO4Gaay +iQS57uPezLRuoajhVplpshr95Zr5ZVcd/gFa2isTtXI +-> ssh-ed25519 Dfencg fRy4KqmTrjv7JifXnkKS5SHpXGHMhs27qd1iFnBmj2I +NeAZnwqOZKK571SNGXPSrdVAfTyoWn4BgZ/qUfXm1aQ +-> ssh-ed25519 OWgoVA XK0qU4kOq8kYcBXWJuLBH+K/X3B0Y2xklaYEBY1waFA +GgSmjDNW6OIE3kk4D6ooleQRywtqNED0Rm4Brnx5UZ0 +-> ssh-ed25519 aP/BWw AdbhT0YxEvb2yZ0tQxDbIHSfYFEGG83GOLtokjukV0c +BC/qk2xiXMcLb1oB3OqBcnhD6DP0yCtrqIfUvDzVWTI +--- ck1Jx0o4PwGn0bWgEy+9SfkHcHAlsz+6nPZsnKwwGNM +ՍV0{MZmҜ@U8`-_MPPW$/29L jp.w`kyi?`.zI +E%?"ڧ 2C@H4ssDC @~O9 SU/ee[JЮ  \ No newline at end of file diff --git a/modules/custom/dns/knot/secrets/update_terraform_swendel.age b/modules/custom/dns/knot/secrets/update_terraform_swendel.age new file mode 100644 index 0000000..a35ad19 Binary files /dev/null and b/modules/custom/dns/knot/secrets/update_terraform_swendel.age differ diff --git a/modules/custom/dns/knot/submission.nix b/modules/custom/dns/knot/submission.nix new file mode 100644 index 0000000..04d8b75 --- /dev/null +++ b/modules/custom/dns/knot/submission.nix @@ -0,0 +1,27 @@ +{ + services.knot.settings.submission = { + denic = { + parent = [ + "a_nic_de" + "f_nic_de" + "l_de_net" + "n_de_net" + "s_de_net" + "z_nic_de" + ]; + check-interval = "120s"; + }; + + digital = { + parent = [ + "v0n0_nic_digital" + "v0n1_nic_digital" + "v0n2_nic_digital" + "v0n3_nic_digital" + "v2n0_nic_digital" + "v2n1_nic_digital" + ]; + check-interval = "120s"; + }; + }; +} diff --git a/modules/custom/dns/knot/templates.nix b/modules/custom/dns/knot/templates.nix new file mode 100644 index 0000000..c267df1 --- /dev/null +++ b/modules/custom/dns/knot/templates.nix @@ -0,0 +1,34 @@ +{ + services.knot.settings.template = { + default = { + semantic-checks = true; + zonemd-generate = "zonemd-sha384"; + zonefile-load = "difference-no-serial"; + zonefile-sync = "-1"; + serial-policy = "unixtime"; + journal-content = "all"; + + notify = [ "srxgp01" "srxgp02" ]; + + acl = [ + "transfer" + "update" + "update_k8s" + "update_terraform_cicd" + "update_terraform_swendel" + ]; + + global-module = [ + "mod-stats/all" + "mod-cookies/default" + ]; + }; + + slave = { + acl = [ "notify" ]; + master = "srxgp00"; + zonefile-load = "none"; + storage = "/var/lib/knot/slave"; + }; + }; +} diff --git a/modules/custom/dns/knot/zones.nix b/modules/custom/dns/knot/zones.nix new file mode 100644 index 0000000..68b71d1 --- /dev/null +++ b/modules/custom/dns/knot/zones.nix @@ -0,0 +1,10 @@ +{ + services.knot.settings.zone = { + "whoami.srx.digital".module = "mod-whoami"; + "whoami6.srx.digital".module = "mod-whoami"; + "srx81.de" = { + dnssec-signing = true; + dnssec-policy = "denic_13_test"; + }; + }; +} diff --git a/modules/custom/dns/zones/curious.bio.nix b/modules/custom/dns/zones/curious.bio.nix new file mode 100644 index 0000000..135d2f5 --- /dev/null +++ b/modules/custom/dns/zones/curious.bio.nix @@ -0,0 +1,121 @@ +{ inputs, config, ... }: +with config.srx.service.dns; +with inputs.dns.lib.combinators; +{ + srx.service.dns.zones."curious.bio" = { + inherit (defaults) SOA NS TTL TXT DMARC; + + MX = [ (mx.mx 10 "mail.curious.bio.") ]; + + DKIM = [{ + selector = "mail"; + s = [ "email" ]; + p = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhbKGSt4MB4B0KBZNLb7Kz0/NJNhRceSRNlgeWe41jwB19uyks/q3Mk+7xFfs/yNIzDc0RuzGZoMAFuALpYsYiRAUV5f/PRgM/a2fCQ0f3aWWTAMT8ieZhHfOYPqnYV0cxCeYnbNbIgeT2Fic8GhRWpiPxDWqIC2zil09nmb2iTwIDAQAB"; + }]; + + A = [ "116.202.240.209" ]; + AAAA = [ "2a01:4f8:241:3e69::1" ]; + + SRV = [ + { + service = "caldavs"; + proto = "tcp"; + port = 443; + target = "cloud"; + } + { + service = "carddavs"; + proto = "tcp"; + port = 443; + target = "cloud"; + } + ]; + + subdomains = rec { + copepod = host "116.202.240.209" "2a01:4f8:241:3e69::1"; + + mail = copepod; + autoconfig = copepod; + + id = copepod; + track = copepod; + + www = copepod; + code = copepod; + wiki = copepod; + pad = copepod; + office = copepod; + survey = copepod; + paper = copepod; + + cloud = copepod; + onlyoffice = copepod; + collabora = copepod; + + meet = copepod; + "recordings.meet" = copepod; + + pretix = copepod; + ticket = copepod; + events = copepod; + + forum = copepod; + media = copepod; + social = copepod; + images = copepod; + + matrix = copepod; + matrix-admin = copepod; + chat = copepod; + turn = copepod; + + status = copepod; + + flow = copepod; + dashboard = copepod; + mqtt = copepod; + tsdb = copepod; + alarm = copepod; + + oh4k.CNAME = [ "oh4k.lupus-ddns.de." ]; + diatome.CNAME = [ "oh4k" ]; + + iot.subdomains = { + control = copepod; + flow = copepod; + net = copepod; + api = copepod; + mqtt = copepod; + }; + + vpn.subdomains = { + copepod = host "10.80.1.1" null; + diatome = host "10.80.1.50" null; + }; + + "usr.hq.hh".subdomains = { + cclap00.A = [ "10.10.0.4" ]; + cclfw00.A = [ "10.10.0.1" ]; + diatome.A = [ "10.10.0.2" ]; + ccllp00.A = [ "10.10.0.70" ]; + cclsw00.A = [ "10.10.0.3" ]; + cclws00_ipmi.A = [ "10.10.0.12" ]; + cclws00.A = [ "10.10.0.11" ]; + davis-gw.A = [ "10.10.0.87" ]; + fablab-gw.A = [ "10.10.0.82" ]; + homematic-gw.A = [ "10.10.0.5" ]; + janitza.A = [ "10.10.0.90" ]; + kimo-c310.A = [ "10.10.0.6" ]; + lupus-cam-entry.A = [ "10.10.0.86" ]; + lupus-cam-social.A = [ "10.10.0.83" ]; + lupus-cam-tor.A = [ "10.10.0.84" ]; + lupus-cam-ws.A = [ "10.10.0.85" ]; + lupus-gw.A = [ "10.10.0.81" ]; + }; + + "gh.hq.hh".subdomains = { + vermiloop.A = [ "10.10.60.11" ]; + }; + }; + }; +} diff --git a/modules/custom/dns/zones/default.nix b/modules/custom/dns/zones/default.nix new file mode 100644 index 0000000..2cc59b8 --- /dev/null +++ b/modules/custom/dns/zones/default.nix @@ -0,0 +1,41 @@ +{ inputs, lib, ... }: +with lib.lists; +with inputs.dns.lib.combinators; +{ + imports = with inputs; [ + srx-nixos-shadow.nixosModules.dns + + ./curious.bio.nix + ./nix-hamburg.de.nix + ./sourceindex.de.nix + ./srx.digital.nix + ./srx.dev.nix + ./vpn.srx.dev.nix + ]; + + srx.service.dns = rec { + defaults = { + SOA = { + nameServer = "${last (reverseList defaults.NS)}"; + adminEmail = "1egh0the@srx.digital"; + serial = 2024031918; + refresh = 6 * 60 * 60; + retry = 60 * 60; + }; + NS = [ "ns1.srx.dev." "ns2.srx.dev." "ns3.srx.dev." ]; + TTL = 3 * 60 * 60; + MX = [ (mx.mx 10 "mail.srx.digital.") ]; + TXT = [ (with spf; strict [ "mx" ]) ]; + DMARC = [{ p = "quarantine"; sp = "reject"; }]; + A = [ "65.108.77.254" ]; + AAAA = [ "2a01:4f9:6b:2573::1" ]; + }; + + zones = { + "srx81.de" = { inherit (defaults) SOA NS TXT; }; + "whoami.srx.digital" = { inherit (defaults) SOA NS A; }; + "whoami6.srx.digital" = { inherit (defaults) SOA NS AAAA; }; + "flowflexure.bio" = { inherit (defaults) SOA NS TXT MX DMARC A AAAA; }; + }; + }; +} diff --git a/modules/custom/dns/zones/nix-hamburg.de.nix b/modules/custom/dns/zones/nix-hamburg.de.nix new file mode 100644 index 0000000..5a52c3f --- /dev/null +++ b/modules/custom/dns/zones/nix-hamburg.de.nix @@ -0,0 +1,13 @@ +{ config, ... }: +with config.srx.service.dns; +{ + srx.service.dns.zones."nix-hamburg.de" = { + inherit (defaults) SOA NS TTL MX TXT DMARC A AAAA; + + DKIM = [{ + selector = "mail"; + s = [ "email" ]; + p = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIkR9v+74PC2RBXtHX7hyTIbQCbysHIwpcTg11ZmY3hl+Z3eKAHJqPHwczLk5O6QfhcoekxrvbM3PnaZBlR76In8Pe4QC8wVK8R171pOL31mqw3XS32yc9MUuoqvx9Q13uFgQwdQpSzqRSPNguNIdgF6cNkIaYP5S+AUE7CFCXjQIDAQAB"; + }]; + }; +} diff --git a/modules/custom/dns/zones/sourceindex.de.nix b/modules/custom/dns/zones/sourceindex.de.nix new file mode 100644 index 0000000..0d8dc1a --- /dev/null +++ b/modules/custom/dns/zones/sourceindex.de.nix @@ -0,0 +1,13 @@ +{ config, ... }: +with config.srx.service.dns; +{ + srx.service.dns.zones."sourceindex.de" = { + inherit (defaults) SOA NS TTL MX TXT DMARC A AAAA; + + DKIM = [{ + selector = "mail"; + s = [ "email" ]; + p = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM6qdnkgI0+PxDG63mON8gBjvN3GxW7HHkVMbjmG2rN72CFAuG5F3P9fAiocGWy1jN1mv9DhY3FNqdElE7ebxp3JnrLmKYHF4B5wmHSEmrTHeaVrc+Xnr/E2FWvcafTicOQXx1CRbDfHChH1As1RUFiL0HC0QQfXvXD0QTUzaq6QIDAQAB"; + }]; + }; +} diff --git a/modules/custom/dns/zones/srx.dev.nix b/modules/custom/dns/zones/srx.dev.nix new file mode 100644 index 0000000..971c603 --- /dev/null +++ b/modules/custom/dns/zones/srx.dev.nix @@ -0,0 +1,30 @@ +{ inputs, config, ... }: +with config.srx.service.dns; +with inputs.dns.lib.combinators; +{ + srx.service.dns.zones."srx.dev" = { + inherit (defaults) SOA NS TTL MX TXT DMARC A AAAA; + + DKIM = [{ + selector = "mail"; + s = [ "email" ]; + p = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMbarSAE2a5vfPEc/JeXtpZqD7xW2BBUmcNNuSyyHZ7IUmY52OjGFxIiSaj+Q0f8SJVtCq45fkvckreXj9yzx/h3WimDkFlPzElBiuuapulPBj1BSI3eM7O+FCU/4MdI+zEL1QMz2Lcq5o+xW3IwxEEWAygQyP3Z/ac/Rzt65NaQIDAQAB"; + }]; + + subdomains = rec { + srxgp00 = host "65.108.77.254" "2a01:4f9:6b:2573::1"; + srxgp01 = host "152.53.17.250" "2a0a:4cc0:1:131a::1"; + srxgp02 = host "212.132.77.48" "2a02:247a:275:9300::1"; + + ns1 = srxgp00; + ns2 = srxgp01; + ns3 = srxgp02; + + vpn = delegateTo [ + "ns1" + "ns2" + "ns3" + ]; + }; + }; +} diff --git a/modules/custom/dns/zones/srx.digital.nix b/modules/custom/dns/zones/srx.digital.nix new file mode 100644 index 0000000..aa2061a --- /dev/null +++ b/modules/custom/dns/zones/srx.digital.nix @@ -0,0 +1,103 @@ +{ inputs, config, ... }: +with config.srx.service.dns; +with inputs.dns.lib.combinators; +{ + srx.service.dns.zones."srx.digital" = { + inherit (defaults) SOA NS TTL MX TXT A AAAA; + + DKIM = [{ + selector = "mail"; + s = [ "email" ]; + p = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDbg881GUU/m6SGOkSbg4/USEP0TnN7xPqrv1tcALo1wnNRmUjBBIrQueidF0vwlEQr41iuuDH28ggKuSSUmlfxFVWvaYrgN2hdd54xCshfW47kUwsH+J8VzrLTAUU4p8PP2EMRVvF2cKPce4tdBWHjbw4YzfYlyTTo3vBS/aLE1QIDAQAB"; + }]; + + DMARC = [{ + p = "quarantine"; + sp = "reject"; + rua = [ "mailto:dmarc@srx.digital" ]; + ruf = [ "mailto:dmarc@srx.digital" ]; + }]; + + SRV = [ + { service = "https"; proto = "tcp"; port = 443; target = "autoconfig"; } + { service = "caldavs"; proto = "tcp"; port = 443; target = "cloud"; } + { service = "carddavs"; proto = "tcp"; port = 443; target = "cloud"; } + { service = "submissions"; proto = "tcp"; port = 465; target = "mail"; } + { service = "imaps"; proto = "tcp"; port = 993; target = "mail"; } + ]; + + subdomains = rec { + srxgp00 = host "65.108.77.254" "2a01:4f9:6b:2573::1"; + srxgp01 = host "152.53.17.250" "2a0a:4cc0:1:131a::1"; + srxgp02 = host "212.132.77.48" "2a02:247a:275:9300::1"; + srxk8s00 = host "78.46.220.70" "2a01:4f8:1c0c:5214::1"; + + whoami = delegateTo [ "ns1" "ns2" "ns3" ]; + whoami6 = delegateTo [ "ns1" "ns2" "ns3" ]; + + dns = srxgp00; + ns1 = srxgp00; + ns2 = srxgp01; + ns3 = srxgp02; + + mail = srxgp00; + autoconfig = srxgp00; + + ldap = srxgp00; + support = srxgp00; + checkip = srxgp00; + netboot = srxgp00; + tsdb = srxgp00; + id = srxgp00; + vault = srxgp00; + cloud = srxgp00; + code = srxgp00; + "live.code" = srxgp00; + pad = srxgp00; + analytics = srxgp00; + home = srxgp00; + auth = srxgp00; + media = srxgp00; + office = srxgp00; + paper = srxgp00; + meet = srxgp00; + survey = srxgp00; + metrics = srxgp00; + logs = srxgp00; + turn = srxgp00; + status = srxgp00; + "push.status" = srxgp00; + alerts = srxgp00; + push = srxgp00; + s3 = srxgp00; + "admin.s3" = srxgp00; + + nix.subdomains = { + cache = srxgp00; + build = srxgp00; + hydra = srxgp00; + }; + + matrix = { + CNAME = [ "srx.digital." ]; + subdomains = { + chat = srxgp00; + admin = srxgp00; + }; + }; + + "hq.op.hh".subdomains = rec { + srxfw01 = host "10.50.0.1" null; + srxsw01 = host "10.50.0.3" null; + srxap01 = host "10.50.0.4" null; + srxnas01 = host "10.50.0.10" null; + netboot = srxnas01; + nfs = srxnas01; + }; + + "hq.op.l".subdomains = { + srxnas00 = host "192.168.178.71" null; + }; + }; + }; +} diff --git a/modules/custom/dns/zones/vpn.srx.dev.nix b/modules/custom/dns/zones/vpn.srx.dev.nix new file mode 100644 index 0000000..7a55954 --- /dev/null +++ b/modules/custom/dns/zones/vpn.srx.dev.nix @@ -0,0 +1,56 @@ +{ inputs, config, ... }: +with config.srx.service.dns; +with inputs.dns.lib.combinators; +{ + srx.service.dns.zones."vpn.srx.dev" = { + inherit (defaults) SOA NS TTL; + + subdomains = rec { + srxgp00 = host "10.80.0.1" null; + srxgp01 = host "10.80.0.5" null; + srxgp02 = host "10.80.0.6" null; + + srxk8s00 = host "10.80.0.7" null; + + srxnb00 = host "10.80.0.100" null; + srxws00 = host "10.80.0.3" null; + srxws01 = host "10.80.0.8" null; + srxtab00 = host "10.80.0.9" null; + + srxnas00 = host "10.80.0.4" null; + srxnas01 = host "10.80.0.2" null; + srxfdm00 = host "10.80.0.13" null; + srxmc00 = host "10.80.0.14" null; + + copepod = host "10.80.0.10" null; + diatome = host "10.80.0.50" null; + genome = host "10.80.0.22" null; + opd00 = host "10.80.0.66" null; + + dns = srxgp00; + ns1 = srxgp00; + ns2 = srxgp01; + ns3 = srxgp02; + + ldap = srxgp00; + logs = srxgp00; + metrics = srxgp00; + mail = srxgp00; + s3 = srxgp00; + disco = srxgp00; + k8s = srxk8s00; + virt = srxk8s00; + mqtt = srxgp00; + vault = srxnas00; + nfs = srxnas00; + + netboot = srxnas01; + home = srxnas01; + + nix.subdomains = { + cache = srxgp00; + build = srxgp00; + }; + }; + }; +} diff --git a/modules/filesystems/zfs.nix b/modules/filesystems/zfs.nix new file mode 100644 index 0000000..68b7b12 --- /dev/null +++ b/modules/filesystems/zfs.nix @@ -0,0 +1,24 @@ +{ lib, config, ... }: +{ + boot = { + initrd.supportedFilesystems = lib.mkDefault [ "zfs" ]; + kernelPackages = lib.mkForce config.boot.zfs.package.latestCompatibleLinuxPackages; + supportedFilesystems = [ "zfs" ]; + }; + + services = { + zfs = { + autoScrub = { + enable = true; + interval = "weekly"; + }; + + trim = { + enable = true; + interval = "weekly"; + }; + }; + + telegraf.extraConfig.inputs.zfs = lib.mkIf config.services.telegraf.enable { }; + }; +} diff --git a/modules/hardware/bluetooth.nix b/modules/hardware/bluetooth.nix new file mode 100644 index 0000000..dbccc85 --- /dev/null +++ b/modules/hardware/bluetooth.nix @@ -0,0 +1,6 @@ +{ lib, config, ... }: +{ + hardware.bluetooth.enable = lib.mkDefault true; + + services.blueman.enable = lib.mkIf config.services.xserver.enable true; +} diff --git a/modules/hardware/cpu/amd.nix b/modules/hardware/cpu/amd.nix new file mode 100644 index 0000000..ee4bfef --- /dev/null +++ b/modules/hardware/cpu/amd.nix @@ -0,0 +1,12 @@ +{ inputs, ... }: +{ + imports = with inputs; [ + nixos-hardware.nixosModules.common-cpu-amd-pstate + ]; + + boot = { + kernelModules = [ "kvm-amd" ]; + extraModprobeConfig = "options kvm_amd nested=1"; + binfmt.emulatedSystems = [ "aarch64-linux" ]; + }; +} diff --git a/modules/hardware/cpu/intel.nix b/modules/hardware/cpu/intel.nix new file mode 100644 index 0000000..ee63463 --- /dev/null +++ b/modules/hardware/cpu/intel.nix @@ -0,0 +1,12 @@ +{ inputs, ... }: +{ + imports = with inputs; [ + nixos-hardware.nixosModules.common-cpu-intel + ]; + + boot = { + kernelModules = [ "kvm_intel" ]; + extraModprobeConfig = "options kvm_intel nested=1"; + binfmt.emulatedSystems = [ "aarch64-linux" ]; + }; +} diff --git a/modules/hardware/default.nix b/modules/hardware/default.nix new file mode 100644 index 0000000..c50cad4 --- /dev/null +++ b/modules/hardware/default.nix @@ -0,0 +1,38 @@ +{ self, pkgs, lib, ... }: +{ + imports = [ + self.nixosModules.hardware-disk + self.nixosModules.hardware-power + self.nixosModules.hardware-bluetooth + ]; + + hardware = { + ksm.enable = lib.mkDefault true; + i2c.enable = lib.mkDefault true; + enableRedistributableFirmware = lib.mkDefault true; + }; + + services = { + fwupd.enable = true; + thermald.enable = lib.mkIf (pkgs.hostPlatform.system == "x86_64-linux") true; + + telegraf.extraConfig.inputs = { + linux_cpu = { }; + sensors = { }; + temp = { }; + }; + }; + + programs.usbtop.enable = lib.mkDefault true; + + environment.systemPackages = with pkgs; [ + dmidecode + freeipmi + lm_sensors + lshw + pciutils + usbutils + ]; + + systemd.services.telegraf.path = with pkgs; [ lm_sensors ]; +} diff --git a/modules/hardware/disk.nix b/modules/hardware/disk.nix new file mode 100644 index 0000000..c1057d6 --- /dev/null +++ b/modules/hardware/disk.nix @@ -0,0 +1,42 @@ +{ inputs, config, pkgs, lib, ... }: +{ + imports = with inputs; [ + nixos-hardware.nixosModules.common-pc-ssd + ]; + + environment = { + etc."mdadm.conf".text = '' + MAILADDR root + ''; + + systemPackages = with pkgs; [ + hdparm + sdparm + nvme-cli + smartmontools + ]; + }; + + hardware.sensor.hddtemp = { + enable = lib.mkDefault true; + drives = [ "/dev/disk/by-path/*" ]; + }; + + services = { + smartd = { + enable = lib.mkDefault true; + notifications = { + mail.enable = lib.mkIf config.services.postfix.enable true; + x11.enable = lib.mkIf config.services.xserver.enable true; + }; + }; + + telegraf.extraConfig.inputs = lib.mkIf config.services.telegraf.enable { + hddtemp = { }; + smart = { + path_smartctl = lib.mkForce "${pkgs.smartmontools}/bin/smartctl"; + path_nvme = lib.mkForce "${pkgs.nvme-cli}/bin/nvme"; + }; + }; + }; +} diff --git a/modules/hardware/gpu/amd.nix b/modules/hardware/gpu/amd.nix new file mode 100644 index 0000000..731f149 --- /dev/null +++ b/modules/hardware/gpu/amd.nix @@ -0,0 +1,12 @@ +{ inputs, pkgs, ... }: +{ + imports = with inputs; [ + nixos-hardware.nixosModules.common-gpu-amd + ]; + + environment.systemPackages = with pkgs; [ + clinfo + radeontop + radeontools + ]; +} diff --git a/modules/hardware/gpu/intel.nix b/modules/hardware/gpu/intel.nix new file mode 100644 index 0000000..da0f30e --- /dev/null +++ b/modules/hardware/gpu/intel.nix @@ -0,0 +1,11 @@ +{ lib, pkgs, ... }: +{ + hardware = { + opengl = { + enable = lib.mkDefault true; + driSupport = lib.mkDefault true; + }; + }; + + environment.systemPackages = with pkgs; [ intel-gpu-tools ]; +} diff --git a/modules/hardware/gpu/nvidia.nix b/modules/hardware/gpu/nvidia.nix new file mode 100644 index 0000000..6291d54 --- /dev/null +++ b/modules/hardware/gpu/nvidia.nix @@ -0,0 +1,40 @@ +{ config, inputs, lib, ... }: +{ + imports = with inputs; [ + nixos-hardware.nixosModules.common-gpu-nvidia + ]; + + hardware = { + nvidia = { + modesetting.enable = lib.mkDefault true; + powerManagement.enable = lib.mkDefault true; + nvidiaPersistenced = lib.mkDefault true; + package = lib.mkForce config.boot.kernelPackages.nvidiaPackages.stable; + }; + + nvidia-container-toolkit.enable = lib.mkDefault true; + + opengl = { + enable = lib.mkDefault true; + driSupport = lib.mkDefault true; + driSupport32Bit = lib.mkDefault true; + }; + }; + + boot.blacklistedKernelModules = [ "nouveau" ]; + + # nixpkgs.config = { + # allowUnfree = lib.mkForce true; + # cudaSupport = lib.mkForce true; + # allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ "cudatoolkit" ]; + # }; + + services.xserver.videoDrivers = [ "nvidia" ]; + + virtualisation = { + docker.enableNvidia = lib.mkIf config.virtualisation.docker.enable true; + podman.enableNvidia = lib.mkIf config.virtualisation.podman.enable true; + }; + + #services.telegraf.extraConfig.inputs.nvidia_smi.bin_path = "${config.hardware.nvidia.package}/bin/nvidia-smi"; +} diff --git a/modules/hardware/laptop.nix b/modules/hardware/laptop.nix new file mode 100644 index 0000000..0057514 --- /dev/null +++ b/modules/hardware/laptop.nix @@ -0,0 +1,6 @@ +{ inputs, ... }: +{ + imports = with inputs; [ + nixos-hardware.nixosModules.common-pc-laptop-acpi_call + ]; +} diff --git a/modules/hardware/power.nix b/modules/hardware/power.nix new file mode 100644 index 0000000..de9b3f4 --- /dev/null +++ b/modules/hardware/power.nix @@ -0,0 +1,10 @@ +{ lib, pkgs, ... }: +{ + environment.systemPackages = with pkgs; [ + acpica-tools + powertop + ]; + + services.acpid.enable = lib.mkDefault true; + powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand"; +} diff --git a/modules/hardware/rpi4.nix b/modules/hardware/rpi4.nix new file mode 100644 index 0000000..386cfcc --- /dev/null +++ b/modules/hardware/rpi4.nix @@ -0,0 +1,37 @@ +{ lib, pkgs, ... }: +{ + boot = { + loader = { + grub.enable = lib.mkForce false; + generic-extlinux-compatible.enable = lib.mkForce true; + }; + initrd = { + availableKernelModules = [ + "genet" + "xhci_pci" + "usbhid" + "usb_storage" + ]; + kernelModules = [ ]; + }; + }; + + hardware = { + enableRedistributableFirmware = lib.mkForce false; + firmware = [ pkgs.raspberrypiWirelessFirmware ]; + }; + + environment.systemPackages = with pkgs; [ + libraspberrypi + raspberrypi-eeprom + rpiboot + ]; + + nix = { + extraOptions = '' + min-free = ${toString (100 * 1024 * 1024)} + max-free = ${toString (1024 * 1024 * 1024)} + ''; + settings.max-jobs = lib.mkDefault 4; + }; +} diff --git a/modules/hardware/security/nitrokey.nix b/modules/hardware/security/nitrokey.nix new file mode 100644 index 0000000..dce7be9 --- /dev/null +++ b/modules/hardware/security/nitrokey.nix @@ -0,0 +1,15 @@ +{ lib, pkgs, config, ... }: +{ + environment.systemPackages = with pkgs; lib.optionals config.services.xserver.enable [ + nitrokey-app2 + ]; + + hardware.nitrokey.enable = lib.mkDefault true; + + services = { + pcscd.enable = lib.mkDefault true; + udev.packages = with pkgs; [ + libu2f-host + ]; + }; +} diff --git a/modules/hardware/security/secureboot.nix b/modules/hardware/security/secureboot.nix new file mode 100644 index 0000000..bc0eb9d --- /dev/null +++ b/modules/hardware/security/secureboot.nix @@ -0,0 +1,21 @@ +{ lib, pkgs, inputs, ... }: +{ + imports = [ inputs.lanzaboote.nixosModules.lanzaboote ]; + + environment.systemPackages = with pkgs; [ sbctl ]; + + boot = { + bootspec = { + enable = lib.mkDefault true; + enableValidation = lib.mkDefault true; + }; + lanzaboote = { + enable = lib.mkDefault true; + pkiBundle = "/etc/secureboot"; + }; + loader = { + systemd-boot.enable = lib.mkForce false; + grub.enable = lib.mkForce false; + }; + }; +} diff --git a/modules/hardware/security/yubikey.nix b/modules/hardware/security/yubikey.nix new file mode 100644 index 0000000..b9d2903 --- /dev/null +++ b/modules/hardware/security/yubikey.nix @@ -0,0 +1,23 @@ +{ pkgs, config, lib, ... }: +{ + environment.systemPackages = with pkgs; [ + yubikey-personalization + ] ++ lib.optionals config.services.xserver.enable [ + yubikey-manager-qt + yubikey-personalization-gui + ]; + + security.pam.yubico = { + enable = lib.mkDefault true; + mode = "challenge-response"; + }; + + services = { + pcscd.enable = lib.mkDefault true; + yubikey-agent.enable = lib.mkDefault true; + udev.packages = with pkgs; [ + libu2f-host + yubikey-personalization + ]; + }; +} diff --git a/modules/hardware/sound/pipewire.nix b/modules/hardware/sound/pipewire.nix new file mode 100644 index 0000000..d7b2dda --- /dev/null +++ b/modules/hardware/sound/pipewire.nix @@ -0,0 +1,21 @@ +{ lib, pkgs, ... }: +{ + hardware.pulseaudio.enable = lib.mkForce false; + + environment.systemPackages = with pkgs; [ pulseaudio ]; + + security.rtkit.enable = lib.mkForce true; + + sound = { + enable = lib.mkForce true; + mediaKeys.enable = lib.mkForce true; + }; + + services.pipewire = { + enable = lib.mkForce true; + alsa.enable = lib.mkForce true; + alsa.support32Bit = lib.mkForce true; + pulse.enable = lib.mkForce true; + wireplumber.enable = lib.mkForce true; + }; +} diff --git a/modules/hardware/sound/pulseaudio.nix b/modules/hardware/sound/pulseaudio.nix new file mode 100644 index 0000000..9cc495c --- /dev/null +++ b/modules/hardware/sound/pulseaudio.nix @@ -0,0 +1,15 @@ +{ lib, pkgs, ... }: +{ + sound.enable = lib.mkForce true; + hardware.pulseaudio = { + enable = lib.mkForce true; + package = pkgs.pulseaudioFull; + extraConfig = '' + load-module module-bluetooth-discover + load-module module-bluetooth-policy + load-module module-switch-on-connect + load-module module-zeroconf-discover + load-module module-stream-restore + ''; + }; +} diff --git a/modules/roles/core/boot.nix b/modules/roles/core/boot.nix new file mode 100644 index 0000000..bafecb0 --- /dev/null +++ b/modules/roles/core/boot.nix @@ -0,0 +1,29 @@ +{ lib, pkgs, ... }: +{ + console.earlySetup = lib.mkForce true; + + boot = { + tmp = { + useTmpfs = lib.mkDefault true; + cleanOnBoot = lib.mkDefault true; + }; + + kernel.sysctl."vm.swappiness" = 10; + kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; + + initrd.systemd = { + initrdBin = with pkgs; [ + iproute2 + iputils + keyutils + tor + wpa_supplicant + ]; + + packages = with pkgs; [ + tor + wpa_supplicant + ]; + }; + }; +} diff --git a/modules/roles/core/commands.nix b/modules/roles/core/commands.nix new file mode 100644 index 0000000..f435b17 --- /dev/null +++ b/modules/roles/core/commands.nix @@ -0,0 +1,9 @@ +{ + programs = { + command-not-found.enable = false; + nix-index = { + enableBashIntegration = true; + enableZshIntegration = true; + }; + }; +} diff --git a/modules/roles/core/cve.nix b/modules/roles/core/cve.nix new file mode 100644 index 0000000..7b9e589 --- /dev/null +++ b/modules/roles/core/cve.nix @@ -0,0 +1,6 @@ +{ + # FIXME: review this if it's still necessary + # + # CVE-2024-6387 https://github.com/NixOS/nixpkgs/pull/323753 + services.openssh.settings.LoginGraceTime = 0; +} diff --git a/modules/roles/core/default.nix b/modules/roles/core/default.nix new file mode 100644 index 0000000..1e5ec3e --- /dev/null +++ b/modules/roles/core/default.nix @@ -0,0 +1,37 @@ +{ inputs, ... }: +{ + imports = with inputs; [ + srvos.nixosModules.common + srvos.nixosModules.mixins-terminfo + srvos.nixosModules.mixins-trusted-nix-caches + srvos.nixosModules.mixins-nix-experimental + disko.nixosModules.disko + home-manager.nixosModules.home-manager + agenix.nixosModules.age + impermanence.nixosModules.impermanence + nix-index-database.nixosModules.nix-index + vault-secrets.nixosModules.vault-secrets + self.nixosModules.services-dns + self.nixosModules.services-dns-knsupdate + + ./boot.nix + ./swap.nix + ./security.nix + ./cve.nix + ./users.nix + ./locale.nix + ./time.nix + ./nix.nix + ./fail2ban.nix + ./dns.nix + ./openssh.nix + ./motd.nix + ./pkgs.nix + ./home-manager.nix + ./tmux.nix + ./zsh.nix + ./editor.nix + ./commands.nix + ./vault.nix + ]; +} diff --git a/modules/roles/core/dns.nix b/modules/roles/core/dns.nix new file mode 100644 index 0000000..9640748 --- /dev/null +++ b/modules/roles/core/dns.nix @@ -0,0 +1,10 @@ +{ lib, ... }: +{ + networking.nameservers = lib.mkDefault [ + "1.1.1.1" + "9.9.9.9" + "2606:4700:4700::1111" + ]; + + services.resolved.enable = lib.mkDefault true; +} diff --git a/modules/roles/core/editor.nix b/modules/roles/core/editor.nix new file mode 100644 index 0000000..90ce331 --- /dev/null +++ b/modules/roles/core/editor.nix @@ -0,0 +1,6 @@ +{ + programs.neovim = { + viAlias = true; + vimAlias = true; + }; +} diff --git a/modules/roles/core/fail2ban.nix b/modules/roles/core/fail2ban.nix new file mode 100644 index 0000000..7202549 --- /dev/null +++ b/modules/roles/core/fail2ban.nix @@ -0,0 +1,29 @@ +{ + services = { + fail2ban = { + enable = true; + maxretry = 5; + + bantime-increment = { + enable = true; + multipliers = "1 2 4 8 16 32 64"; + maxtime = "168h"; + overalljails = true; + }; + + ignoreIP = [ + "10.0.0.0/8" + "192.168.0.0/16" + "116.202.144.14/28" + "116.202.240.209/26" + "65.108.77.254/26" + "2a01:4f8:241:3e69::/64" + "2a01:4f9:6b:2573::/64" + "srxgp00.srx.digital" + "srxgp01.srx.digital" + "srxgp02.srx.digital" + "srxk8s00.srx.digital" + ]; + }; + }; +} diff --git a/modules/roles/core/home-manager.nix b/modules/roles/core/home-manager.nix new file mode 100644 index 0000000..e7fadf6 --- /dev/null +++ b/modules/roles/core/home-manager.nix @@ -0,0 +1,11 @@ +{ inputs, ... }: +{ + home-manager = { + useGlobalPkgs = true; + useUserPackages = true; + backupFileExtension = "backup"; + extraSpecialArgs = { + inherit (inputs) stylix hostType impermanence; + }; + }; +} diff --git a/modules/roles/core/locale.nix b/modules/roles/core/locale.nix new file mode 100644 index 0000000..d442ba1 --- /dev/null +++ b/modules/roles/core/locale.nix @@ -0,0 +1,21 @@ +{ lib, ... }: +{ + console.keyMap = lib.mkDefault "de"; + + i18n = { + defaultLocale = lib.mkDefault "en_US.UTF-8"; + supportedLocales = lib.mkDefault [ + "en_US.UTF-8/UTF-8" + "de_DE.UTF-8/UTF-8" + ]; + extraLocaleSettings = lib.mkDefault { + LANG = "en_US.UTF-8"; + LC_ALL = "en_US.UTF-8"; + }; + }; + + services.xserver.xkb = { + layout = lib.mkDefault "de"; + options = lib.mkDefault "eurosign:e"; + }; +} diff --git a/modules/roles/core/motd.nix b/modules/roles/core/motd.nix new file mode 100644 index 0000000..2b4d197 --- /dev/null +++ b/modules/roles/core/motd.nix @@ -0,0 +1,38 @@ +{ lib, config, ... }: +{ + users.motd = lib.mkIf (!config.services.xserver.enable) '' + . . . . . + ............/_______________________|________________________|___________|:. + . /____ .____ _.___ ...| + /\ \ /\ \ /:| | :|. + /::\ \ /::\ \ /::| | .| + /::::\ \ /::::\ \ |::| | | + /::::::\ \ /::::::\ \ |::| | | + /:::/\:::\ \ /:::/\:::\ \ |::| | | + /:::/__\:::\ \ /:::/__\:::\ \ |::| | | + \:::\ \:::\ \ /::::\ \:::\ \ |::| | | + ___\:::\ \:::\ \ /::::::\ \:::\ \ |::| | | + /\ \:::\ \:::\ \ /:::/\:::\ \:::\____\ ______|::|___|_____ | + ./::\ \:::\ \:::\____\/:::/ \:::\ \:::| ||:::::::::::::::::::|.|. + \:::\ \:::\ \::/ /\::/ |::::\ /:::|____||:::::::::::::::::::| |:. + \:::\ \:::\ \/____/ \/____|:::::\/:::/ / ------|::|---|----- |. + \:::\ \:::\ \ |:::::::::/ / |::| | | + \:::\ \:::\____\ |::|\::::/ / |::| | | + \:::\ /:::/ / |::| \::/____/ |::| | | + \:::\/:::/ / |::| | |::| | | + \::::::/ / |::| | |::| | | + \::::/ / \::| | |::| | | + \::/ / \:| | \:| | |. + \/____/ \|___| \|___| ::| + . \ | | .| + :___________\_______________________:________________________|___________|:. + | /\::::/ : + | /::\::/ srx digital - Development & Operations . + | /::::\/ https://srx.digital + | /::::::\ ${config.networking.hostName} + | /::::::::\ NixOS ${config.system.nixos.release} (${config.system.nixos.codeName}) + | /::::::::::\ Linux Kernel ${config.boot.kernelPackages.kernel.version} + |_____/::::::::::::\_____________________________________________________:.. + . . . . + ''; +} diff --git a/modules/roles/core/nix.nix b/modules/roles/core/nix.nix new file mode 100644 index 0000000..fe889c5 --- /dev/null +++ b/modules/roles/core/nix.nix @@ -0,0 +1,60 @@ +{ lib, pkgs, hostType, ... }: +{ + nix = { + package = lib.mkForce pkgs.nixVersions.latest; + settings = { + accept-flake-config = true; + auto-optimise-store = hostType == "nixos"; + sandbox = hostType == "nixos"; + build-users-group = "nixbld"; + system-features = [ + "benchmark" + "big-parallel" + "recursive-nix" + "nixos-test" + "kvm" + ]; + allowed-users = [ "@wheel" ]; + trusted-users = [ + "root" + "@wheel" + ]; + experimental-features = [ + "flakes" + "auto-allocate-uids" + "nix-command" + ]; + substituters = [ + "https://nix-community.cachix.org" + "https://nix-config.cachix.org" + "https://arm.cachix.org/" + "https://cuda-maintainers.cachix.org" + "https://cache.nix.srx.digital" + ]; + trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "nix-config.cachix.org-1:Vd6raEuldeIZpttVQfrUbLvXJHzzzkS0pezXCVVjDG4=" + "arm.cachix.org-1:5BZ2kjoL1q6nWhlnrbAl+G7ThY7+HaBRD9PZzqZkbnM=" + "cuda-maintainers.cachix.org-1:0dq3bujKpuEPMCX6U4WylrUDZ9JyUG0VpVZa7CNfq5E=" + "cache.nix.srx.digital-1:+sJ/hAmjuhTpRakfhkCj7i2LoqNyBgm+YItJUSAWWlg=" + ]; + cores = 0; + max-jobs = "auto"; + connect-timeout = 5; + http-connections = 0; + flake-registry = "/etc/nix/registry.json"; + }; + distributedBuilds = true; + } + // lib.optionalAttrs (hostType == "nixos") { + channel.enable = false; + daemonCPUSchedPolicy = lib.mkDefault "batch"; + daemonIOSchedPriority = 5; + nixPath = [ "nixpkgs=/run/current-system/nixpkgs" ]; + optimise.automatic = true; + }; + + system.extraSystemBuilderCmds = '' + ln -sv ${pkgs.path} $out/nixpkgs + ''; +} diff --git a/modules/roles/core/openssh.nix b/modules/roles/core/openssh.nix new file mode 100644 index 0000000..c2e4a3c --- /dev/null +++ b/modules/roles/core/openssh.nix @@ -0,0 +1,7 @@ +{ lib, ... }: +{ + services.openssh = { + enable = true; + settings.PermitRootLogin = lib.mkDefault "no"; + }; +} diff --git a/modules/roles/core/pkgs.nix b/modules/roles/core/pkgs.nix new file mode 100644 index 0000000..5fed319 --- /dev/null +++ b/modules/roles/core/pkgs.nix @@ -0,0 +1,40 @@ +{ pkgs, ... }: +{ + environment.systemPackages = with pkgs; [ + clevis + curl + ddrescue + direnv + dnsutils + gotop + htop + httpie + iftop + inetutils + iotop + ipcalc + jq + killall + kitty + lsof + mc + molly-guard + mtr + ncdu + nfs-utils + pstree + ranger + reptyr + ripgrep + screen + sshfs + sysstat + tree + tshark + wakelan + wget + whois + wol + yq + ]; +} diff --git a/modules/roles/core/security.nix b/modules/roles/core/security.nix new file mode 100644 index 0000000..dd49546 --- /dev/null +++ b/modules/roles/core/security.nix @@ -0,0 +1,41 @@ +{ lib, pkgs, ... }: +{ + environment.systemPackages = with pkgs; [ + apparmor-parser + apparmor-profiles + ]; + + security = { + protectKernelImage = lib.mkDefault true; + + sudo = { + enable = true; + wheelNeedsPassword = lib.mkForce false; + }; + + apparmor = { + enable = true; + packages = with pkgs; [ + apparmor-utils + apparmor-profiles + ]; + }; + + pam = { + enableEcryptfs = lib.mkDefault true; + + loginLimits = [ + { domain = "*"; type = "-"; item = "memlock"; value = "unlimited"; } + { domain = "*"; type = "-"; item = "nofile"; value = "1048576"; } + { domain = "*"; type = "-"; item = "nproc"; value = "unlimited"; } + ]; + }; + + tpm2 = { + enable = true; + pkcs11.enable = true; + }; + + dhparams.enable = lib.mkForce true; + }; +} diff --git a/modules/roles/core/swap.nix b/modules/roles/core/swap.nix new file mode 100644 index 0000000..f8f9738 --- /dev/null +++ b/modules/roles/core/swap.nix @@ -0,0 +1,4 @@ +{ lib, ... }: +{ + zramSwap.enable = lib.mkDefault true; +} diff --git a/modules/roles/core/time.nix b/modules/roles/core/time.nix new file mode 100644 index 0000000..8a377ba --- /dev/null +++ b/modules/roles/core/time.nix @@ -0,0 +1,14 @@ +{ lib, ... }: +{ + time.timeZone = "Europe/Berlin"; + + services.timesyncd = { + enable = lib.mkDefault true; + servers = [ + "0.de.pool.ntp.org" + "1.de.pool.ntp.org" + "2.de.pool.ntp.org" + "3.de.pool.ntp.org" + ]; + }; +} diff --git a/modules/roles/core/tmux.nix b/modules/roles/core/tmux.nix new file mode 100644 index 0000000..9ea99ec --- /dev/null +++ b/modules/roles/core/tmux.nix @@ -0,0 +1,13 @@ +{ + programs.tmux = { + enable = true; + keyMode = "vi"; + aggressiveResize = true; + clock24 = true; + escapeTime = 0; + historyLimit = 10000; + newSession = false; + shortcut = "y"; + terminal = "tmux-256color"; + }; +} diff --git a/modules/roles/core/users.nix b/modules/roles/core/users.nix new file mode 100644 index 0000000..ce70fa0 --- /dev/null +++ b/modules/roles/core/users.nix @@ -0,0 +1,8 @@ +{ self, lib, ... }: +{ + imports = [ + self.nixosModules.users + ]; + + users.mutableUsers = lib.mkDefault false; +} diff --git a/modules/roles/core/vault.nix b/modules/roles/core/vault.nix new file mode 100644 index 0000000..fb85262 --- /dev/null +++ b/modules/roles/core/vault.nix @@ -0,0 +1,12 @@ +{ lib, pkgs, config, ... }: +{ + environment = { + systemPackages = [ pkgs.vault ]; + variables.VAULT_ADDR = lib.mkDefault "https://vault.vpn.srx.dev:5800"; + }; + + vault-secrets = { + vaultPrefix = "kv/system/${config.networking.hostName}"; + vaultAddress = config.environment.variables.VAULT_ADDR; + }; +} diff --git a/modules/roles/core/zsh.nix b/modules/roles/core/zsh.nix new file mode 100644 index 0000000..f078e23 --- /dev/null +++ b/modules/roles/core/zsh.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: +{ + programs.zsh = { + enable = true; + enableCompletion = true; + autosuggestions.enable = true; + interactiveShellInit = "source '${pkgs.grml-zsh-config}/etc/zsh/zshrc'"; + }; +} diff --git a/modules/roles/desktop/default.nix b/modules/roles/desktop/default.nix new file mode 100644 index 0000000..9fec713 --- /dev/null +++ b/modules/roles/desktop/default.nix @@ -0,0 +1,16 @@ +{ self, inputs, ... }: +{ + imports = with inputs; [ + self.nixosModules.hardware-sound-pipewire + self.nixosModules.roles-core + self.nixosModules.services-dns-avahi + srvos.nixosModules.desktop + nixos-hardware.nixosModules.common-hidpi + + ./system + ./display-manager + ./desktop-manager/gnome.nix + ./window-manager + ./office + ]; +} diff --git a/modules/roles/desktop/desktop-manager/default.nix b/modules/roles/desktop/desktop-manager/default.nix new file mode 100644 index 0000000..4e2d140 --- /dev/null +++ b/modules/roles/desktop/desktop-manager/default.nix @@ -0,0 +1,51 @@ +{ lib, pkgs, ... }: +{ + services = { + xserver = { + enable = lib.mkDefault true; + updateDbusEnvironment = lib.mkDefault true; + desktopManager.gnome.extraGSettingsOverridePackages = with pkgs; [ + gsettings-desktop-schemas + gnome.gnome-shell + gnome.dconf-editor + gnome.gnome-calculator + gnome.gnome-calendar + gnome.simple-scan + ]; + }; + + libinput.enable = lib.mkDefault true; + udev.packages = with pkgs; [ gnome.gnome-settings-daemon ]; + + gnome = { + at-spi2-core.enable = lib.mkDefault true; + core-os-services.enable = lib.mkDefault true; + core-utilities.enable = lib.mkDefault true; + glib-networking.enable = lib.mkDefault true; + gnome-browser-connector.enable = lib.mkDefault true; + gnome-keyring.enable = lib.mkDefault true; + gnome-online-accounts.enable = lib.mkDefault true; + gnome-remote-desktop.enable = lib.mkDefault true; + gnome-settings-daemon.enable = lib.mkDefault true; + gnome-user-share.enable = lib.mkDefault true; + rygel.enable = lib.mkDefault true; + sushi.enable = lib.mkDefault true; + + # disable defaults + games.enable = lib.mkForce false; + gnome-online-miners.enable = lib.mkForce false; + tracker-miners.enable = lib.mkForce false; + }; + }; + + xdg.portal.extraPortals = with pkgs; [ + xdg-desktop-portal-gnome + ]; + + programs = { + gnome-disks.enable = true; + gpaste.enable = true; + seahorse.enable = true; + nautilus-open-any-terminal.enable = true; + }; +} diff --git a/modules/roles/desktop/desktop-manager/gnome.nix b/modules/roles/desktop/desktop-manager/gnome.nix new file mode 100644 index 0000000..c970b89 --- /dev/null +++ b/modules/roles/desktop/desktop-manager/gnome.nix @@ -0,0 +1,5 @@ +{ lib, ... }: { + imports = [ ./default.nix ]; + + services.xserver.desktopManager.gnome.enable = lib.mkDefault true; +} diff --git a/modules/roles/desktop/display-manager/default.nix b/modules/roles/desktop/display-manager/default.nix new file mode 100644 index 0000000..390f73e --- /dev/null +++ b/modules/roles/desktop/display-manager/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./gdm.nix + ]; +} diff --git a/modules/roles/desktop/display-manager/gdm.nix b/modules/roles/desktop/display-manager/gdm.nix new file mode 100644 index 0000000..bbf7d5e --- /dev/null +++ b/modules/roles/desktop/display-manager/gdm.nix @@ -0,0 +1,7 @@ +{ lib, ... }: +{ + services.xserver.displayManager.gdm = { + enable = lib.mkDefault true; + wayland = lib.mkDefault true; + }; +} diff --git a/modules/roles/desktop/office/default.nix b/modules/roles/desktop/office/default.nix new file mode 100644 index 0000000..d3212cb --- /dev/null +++ b/modules/roles/desktop/office/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./evolution.nix + ./printer.nix + ./scanner.nix + ]; +} diff --git a/modules/roles/desktop/office/evolution.nix b/modules/roles/desktop/office/evolution.nix new file mode 100644 index 0000000..413b86f --- /dev/null +++ b/modules/roles/desktop/office/evolution.nix @@ -0,0 +1,11 @@ +{ lib, pkgs, ... }: +{ + programs.evolution = { + enable = lib.mkDefault true; + plugins = with pkgs; [ + evolution-ews + ]; + }; + + services.gnome.evolution-data-server.enable = lib.mkDefault true; +} diff --git a/modules/roles/desktop/office/printer.nix b/modules/roles/desktop/office/printer.nix new file mode 100644 index 0000000..0470266 --- /dev/null +++ b/modules/roles/desktop/office/printer.nix @@ -0,0 +1,15 @@ +{ lib, pkgs, ... }: +{ + services = { + system-config-printer.enable = lib.mkDefault true; + + printing = { + enable = lib.mkDefault true; + drivers = with pkgs; [ + gutenprint + gutenprintBin + hplip + ]; + }; + }; +} diff --git a/modules/roles/desktop/office/scanner.nix b/modules/roles/desktop/office/scanner.nix new file mode 100644 index 0000000..db3e424 --- /dev/null +++ b/modules/roles/desktop/office/scanner.nix @@ -0,0 +1,13 @@ +{ lib, pkgs, ... }: +{ + environment.systemPackages = with pkgs; [ + simple-scan + ]; + + hardware.sane = { + enable = lib.mkDefault true; + drivers = { + scanSnap.enable = lib.mkDefault true; + }; + }; +} diff --git a/modules/roles/desktop/system/default.nix b/modules/roles/desktop/system/default.nix new file mode 100644 index 0000000..77dfc91 --- /dev/null +++ b/modules/roles/desktop/system/default.nix @@ -0,0 +1,71 @@ +{ lib, pkgs, config, ... }: +{ + imports = [ + ./documentation.nix + ./fonts.nix + ./stylix.nix + ]; + + console.useXkbConfig = lib.mkDefault true; + + boot = { + consoleLogLevel = lib.mkDefault 0; + plymouth.enable = lib.mkDefault true; + kernelParams = lib.optionals config.boot.plymouth.enable [ "quiet" ]; + }; + + services = { + dbus = { + enable = lib.mkDefault true; + packages = with pkgs; [ gcr ]; + }; + + upower.enable = lib.mkDefault true; + libinput.enable = lib.mkDefault true; + automatic-timezoned.enable = lib.mkDefault true; + gvfs.enable = lib.mkDefault true; + flatpak.enable = lib.mkDefault true; + + # disable default services + geoclue2.enable = lib.mkForce false; + }; + + location = { + latitude = 53.0; + longitude = 10.0; + }; + + xdg = { + autostart.enable = lib.mkDefault true; + sounds.enable = lib.mkDefault true; + icons.enable = lib.mkDefault true; + menus.enable = lib.mkDefault true; + mime.enable = lib.mkDefault true; + + portal = { + enable = lib.mkDefault true; + wlr.enable = lib.mkDefault true; + extraPortals = with pkgs; [ + xdg-desktop-portal-wlr + ]; + }; + }; + + programs = { + nm-applet.enable = true; + light.enable = true; + }; + + networking = { + networkmanager.enable = lib.mkDefault true; + + # fix NetworkManager's Wireguard integration + firewall.checkReversePath = lib.mkDefault false; + }; + + environment.systemPackages = with pkgs; [ + wdisplays + pavucontrol + libcamera + ]; +} diff --git a/modules/roles/desktop/system/documentation.nix b/modules/roles/desktop/system/documentation.nix new file mode 100644 index 0000000..f1c1557 --- /dev/null +++ b/modules/roles/desktop/system/documentation.nix @@ -0,0 +1,10 @@ +{ lib, ... }: +{ + documentation = { + enable = lib.mkForce true; + nixos.enable = lib.mkForce true; + doc.enable = lib.mkForce true; + man.enable = lib.mkForce true; + info.enable = lib.mkForce true; + }; +} diff --git a/modules/roles/desktop/system/fonts.nix b/modules/roles/desktop/system/fonts.nix new file mode 100644 index 0000000..1daa354 --- /dev/null +++ b/modules/roles/desktop/system/fonts.nix @@ -0,0 +1,36 @@ +{ lib, pkgs, ... }: +{ + fonts = { + fontDir.enable = lib.mkDefault true; + fontconfig.enable = lib.mkForce true; + enableDefaultPackages = lib.mkDefault true; + + packages = with pkgs;[ + fira-code + fira-code-symbols + + material-design-icons + material-symbols + + noto-fonts + noto-fonts-cjk + noto-fonts-emoji + + roboto-mono + source-code-pro + + (nerdfonts.override { + fonts = [ + "FiraCode" + "Hack" + "Meslo" + ]; + }) + + # srx ci fonts + manrope + martian-mono + #literata + ]; + }; +} diff --git a/modules/roles/desktop/system/stylix.nix b/modules/roles/desktop/system/stylix.nix new file mode 100644 index 0000000..a065741 --- /dev/null +++ b/modules/roles/desktop/system/stylix.nix @@ -0,0 +1,47 @@ +{ lib, pkgs, inputs, ... }: +{ + imports = with inputs; [ + stylix.nixosModules.stylix + ]; + + stylix = { + enable = true; + + base16Scheme = "${inputs.base16-schemes}/material-palenight.yaml"; + + image = pkgs.fetchurl { + url = "https://media.githubusercontent.com/media/lovesegfault/nix-config/bda48ceaf8112a8b3a50da782bf2e65a2b5c4708/users/bemeurer/assets/walls/plants-00.jpg"; + hash = "sha256-n8EQgzKEOIG6Qq7og7CNqMMFliWM5vfi2zNILdpmUfI="; + }; + + autoEnable = true; + polarity = lib.mkDefault "dark"; + + cursor = { + name = "Numix-Cursor"; + package = pkgs.numix-cursor-theme; + }; + + fonts = lib.mkDefault { + serif = { + name = lib.mkDefault "DejaVu Serif"; + package = lib.mkDefault pkgs.dejavu_fonts; + }; + + sansSerif = { + name = lib.mkDefault "DejaVu Sans"; + package = lib.mkDefault pkgs.dejavu_fonts; + }; + + monospace = { + name = lib.mkDefault "DejaVu Sans Mono"; + package = lib.mkDefault pkgs.dejavu_fonts; + }; + + emoji = { + name = lib.mkDefault "Twitter Color Emoji"; + package = lib.mkDefault pkgs.twitter-color-emoji; + }; + }; + }; +} diff --git a/modules/roles/desktop/window-manager/default.nix b/modules/roles/desktop/window-manager/default.nix new file mode 100644 index 0000000..bd5d292 --- /dev/null +++ b/modules/roles/desktop/window-manager/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./sway + ]; +} diff --git a/modules/roles/desktop/window-manager/sway/default.nix b/modules/roles/desktop/window-manager/sway/default.nix new file mode 100644 index 0000000..fe39cd8 --- /dev/null +++ b/modules/roles/desktop/window-manager/sway/default.nix @@ -0,0 +1,34 @@ +{ pkgs, ... }: +{ + programs.sway = { + enable = true; + + wrapperFeatures = { + gtk = true; + base = true; + }; + + extraSessionCommands = '' + export XDG_SESSION_TYPE=wayland + export XDG_SESSION_DESKTOP=sway + export XDG_CURRENT_DESKTOP=sway + export SDL_VIDEODRIVER=wayland + export QT_QPA_PLATFORM=wayland-egl + export QT_WAYLAND_DISABLE_WINDOWDECORATION="1" + export _JAVA_AWT_WM_NONREPARENTING=1 + export MOZ_ENABLE_WAYLAND = "1"; + export NIXOS_OZONE_WL = "1"; + ''; + + extraPackages = with pkgs; [ + xwayland + swayidle + swaylock + swayws + swayr + slurp + wl-clipboard + wf-recorder + ]; + }; +} diff --git a/modules/roles/media-center/default.nix b/modules/roles/media-center/default.nix new file mode 100644 index 0000000..645c980 --- /dev/null +++ b/modules/roles/media-center/default.nix @@ -0,0 +1,52 @@ +{ pkgs, self, config, ... }: +{ + imports = [ + self.nixosModules.roles-desktop + ]; + + users.extraUsers.kodi.isNormalUser = true; + + services = { + xserver.desktopManager.kodi.enable = true; + + displayManager.autoLogin = { + enable = true; + user = "kodi"; + }; + + cage = { + enable = true; + user = "kodi"; + program = "${pkgs.kodi-wayland}/bin/kodi-standalone"; + }; + }; + + home-manager.users.kodi = { + home = { + username = config.users.users.kodi.name; + stateVersion = "24.05"; + }; + programs.kodi.enable = true; + }; + + environment.systemPackages = [ + (pkgs.kodi-wayland.withPackages (kodiPkgs: with kodiPkgs; [ + inputstream-adaptive + inputstream-ffmpegdirect + inputstream-rtmp + inputstreamhelper + pvr-hdhomerun + pvr-hts + pvr-iptvsimple + sendtokodi + websocket + + arteplussept + mediacccde + mediathekview + orftvthek + radioparadise + youtube + ])) + ]; +} diff --git a/modules/roles/nas/default.nix b/modules/roles/nas/default.nix new file mode 100644 index 0000000..91d23c1 --- /dev/null +++ b/modules/roles/nas/default.nix @@ -0,0 +1,9 @@ +{ self, ... }: +{ + imports = [ + self.nixosModules.roles-server + self.nixosModules.services-dns-avahi + self.nixosModules.services-storage-samba + self.nixosModules.services-storage-syncthing + ]; +} diff --git a/modules/roles/server/acme.age b/modules/roles/server/acme.age new file mode 100644 index 0000000..9305387 --- /dev/null +++ b/modules/roles/server/acme.age @@ -0,0 +1,47 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw X/76giRMWT5Bei/ene17F9o5ySZmnsJzp8VIEK3yymM +zEGfvQ5E1j39VFKbUzGSVaWdvM2ePTjAix+ZCoCWF3g +-> ssh-ed25519 JzjriQ fRVhe4wHUkDLQ/Fv9TEZEQoeuAUwalMgt7Xr5mCCg3Q +6DjFk13o/fjra2uFerEQJGqMDWp089V51015D9N08Po +-> ssh-rsa 6hPx7A +hbahzcyBc+7y7epHqhWHK+JEGaY52DBwMD0FBtb5F0PGSst1ulrTFpdra0UnKmEi +WJ7gWJQIchVDTByTb/VRRKe+Rk02AunpcUg2WJmpJ+xMns4fWVEd/2fYWoiWONgB +VNv00tvJsaAMBGmbmtGWv5jcI6OvlGFyNN47VnrJH6ya1cnEtsKiljCMm0W6+dfE +8O/aT5PVobVJCc4XEzweyrGH1znxvMWtyY1+EDZLwBaGQysO/hh+0ePP42qvYloD +6kRC/YYsMrbJyMqAnMC3hg8t7qKZM0nxIAtNGqMF7rxaNvMx1DgP9u9hoANKNZB3 +dGrgUVoYK2rsQmuGzwD/11M+ihJI/kK1apZW3UC3K5eDdmB7n98RlrhbVjhUZIDz +lYCPBqxOAtbA/zswnnIXvOmOwI+XE0LXY/jHBafpV8lXDAfzgHLbroBv8vokoidY +CtyNVphDH4v6eIEip20gtR9r2MDvNloL7V4PLxjyzt/+KV7hCpvPh/1GkciVYSms +STythFlFAQy5JI2RJUWuRQbDcrMYtVzodBA63f8Boj2kjkdZkMN0PTbYzSy/3LKw +b8ILMVC8L+W7d8tDAH5PPu0CBviSPY1RID9Jy9CsCNIXf+AKeJW3oxoWhv45wqy3 +fK1SgnMFUZKsIB9vbt8tMWqkBeSz2gvqLBPB/LVBFvA +-> ssh-ed25519 IK8+2Q pPqhFm0vVBIONpCZjuTNtWtZpFEwyA2SZh0MqzKPiFA +nDDGOFxW8jZ2Sd01kEN4SmFO7ie41aZR1uF70u8xPKQ +-> ssh-ed25519 SiDnLw CzYEihGdqLSzyE1a2XmnBrRwsvOxr1/DeJllPe7AXz4 +LIioBqrzVBw+viLjqdJx2JhG7wyFHoSw9sO1QR1lhHg +-> ssh-ed25519 Dfencg XsIvCMuZZ0kIds5nFrfFU/oN3C3Qj2+if2ETg+kkZFM +QZUECi7Ecn4GF4qTEw4SfAXTLdHUcMugIPZUFXl2zDQ +-> ssh-ed25519 OWgoVA SPC5dN82Skmlz/WGzHK7pG4jd9eJWHjEz+vuj9wZQHU +0Zv6QJov+R2EG1EOmN0m3c2QdaHqaFDE2YXOraPnZ5o +-> ssh-ed25519 aP/BWw t4xZomtfnEHuWNIkcTo7werR2TTuvfrbCSHXG0u5zmk +eZ5Tvvi6TKsg0UddHRhcoux9RlIjx9BVNdcz/6BLUhg +-> ssh-ed25519 v+/Ozg XyO362OVP+cIzJpcVNBExNZiV8V5rmkEj0Y4W2R6bXE +lYqrxXFF0mlXdTMReRYOoyef3Dr51vGTx8qBNWFDTIk +-> ssh-ed25519 5VC2zg mRUyKzgANYYz6gVQ8v/awn5PjkwJQP1qTRHlU8gmXDE +wmujtn+WijbXl8iu0uKHqqvRrkBRj5FnU1sZM+nd414 +-> ssh-ed25519 ZeuIrQ sApBrVKZ0yuILVwixKUNld4clCyLqUjVTNrg8Byb6G8 +CBgAMocNTvVqSRgBZ09yobavIsES9k8iLQ6NZeHuaNw +-> ssh-ed25519 MrfLnw bu2Lt/vS7vpNvAhSxDNErihHyFOSiV+zab/rDYtxjTs +DIhxoqCjIAo4eCcfhFwkCvWCophVs8fxZ0DSghStK5E +-> ssh-ed25519 TVW7ow nYGRe/cqWDQWwT1gGvu8PSXseT77WMcLI/VloHEAGzA +5SW+hiir3uWSbuBXbxdf5+SAFWGdhl/bYxcLcFpMjc8 +-> ssh-ed25519 xkaJLw Wz0a5l4oFX5tcxJiimdUcJfnZy7mj0znr5Jb9GOD8iE +OVEyjj8Ve9JrHWjQzJQ9d2IwWRR9qRF7ollbCmHQ5+Y +-> ssh-ed25519 al5mZw JOKOXNvEyxE/jG3LmjHIN4xYsJXr3xDoRhOb3A4bSk0 +43enBdIg0v4BJS75uZWTb7yH8WseW19CZDUa8wE/uNY +-> ssh-ed25519 Sk9VBA HvU0s8e/lNulRYMjW3nEiCuUk+whT4sFkQdKWXMrS3I +GYUAkwq7yL7zqcu3ekY/lw8WxB7ZiX2Y5vKkGZHZKsY +--- 0krOWry1XDLPkGSeWrS31d+kd8Z5u86bcQ2bs1vg8Zg +>8jCK&ۑZnt/aԚ;$xh.${>Q@#O*/,[&Ç)w*1V(HN,ZK +}M27VsBX7ڤ;k+aȀM*ˋ +ǠMA5(@ꗿ:CDhFv^Gs ](,E"zΉr( |h'~i \ No newline at end of file diff --git a/modules/roles/server/default.nix b/modules/roles/server/default.nix new file mode 100644 index 0000000..dc1fa81 --- /dev/null +++ b/modules/roles/server/default.nix @@ -0,0 +1,45 @@ +{ inputs, self, lib, hostType, config, ... }: +{ + imports = with inputs; [ + srvos.nixosModules.server + self.nixosModules.roles-core + self.nixosModules.services-monitoring + ]; + + age.secrets.acmeUpdate.file = ./acme.age; + + nix = lib.optionalAttrs (hostType == "nixos") { + optimise.dates = [ "05:30" ]; + }; + + programs.msmtp = { + enable = true; + setSendmail = lib.mkIf config.services.postfix.enable false; + defaults.aliases = "/etc/aliases"; + accounts = { + default = { + auth = false; + host = "mail.vpn.srx.dev"; + from = "no-reply@srx.digital"; + }; + }; + }; + + environment.etc.aliases = { + text = '' + root: hostmaster@srx.digital + ''; + mode = "0644"; + }; + + security.acme = { + acceptTerms = true; + defaults = { + keyType = "ec384"; + email = "echo8@srx.dev"; + dnsProvider = "rfc2136"; + credentialsFile = config.age.secrets.acmeUpdate.path; + webroot = null; + }; + }; +} diff --git a/modules/roles/workstation/default.nix b/modules/roles/workstation/default.nix new file mode 100644 index 0000000..2f13b01 --- /dev/null +++ b/modules/roles/workstation/default.nix @@ -0,0 +1,19 @@ +{ self, pkgs, ... }: +{ + imports = [ + self.nixosModules.roles-desktop + self.nixosModules.hardware-security-yubikey + # self.nixosModules.hardware-security-nitrokey + self.nixosModules.services-container-podman + self.nixosModules.services-virtualisation-libvirt + self.nixosModules.services-virtualisation-microvm + ]; + + programs = { + wireshark = { + enable = true; + package = pkgs.wireshark; + }; + kdeconnect.enable = true; + }; +} diff --git a/modules/services/container/default.nix b/modules/services/container/default.nix new file mode 100644 index 0000000..4ab6cf8 --- /dev/null +++ b/modules/services/container/default.nix @@ -0,0 +1,16 @@ +{ pkgs, ... }: +{ + virtualisation = { + containers = { + enable = true; + registries.search = [ + "docker.io" + "quay.io" + "code.srx.digital" + ]; + + ociSeccompBpfHook.enable = true; + containersConf.settings.engine.helper_binaries_dir = [ "${pkgs.netavark}/bin" ]; + }; + }; +} diff --git a/modules/services/container/docker.nix b/modules/services/container/docker.nix new file mode 100644 index 0000000..ef16da1 --- /dev/null +++ b/modules/services/container/docker.nix @@ -0,0 +1,20 @@ +{ lib, config, ... }: +{ + imports = [ ./default.nix ]; + + virtualisation = { + oci-containers.backend = "docker"; + + docker = { + enable = true; + storageDriver = config.virtualisation.containers.storage.settings.storage.driver; + autoPrune.enable = true; + }; + }; + + services.telegraf.extraConfig.inputs.docker = lib.mkIf config.services.telegraf.enable { }; + + users.users.telegraf = lib.mkIf config.services.telegraf.enable { + extraGroups = lib.optionals config.virtualisation.docker.enable [ "docker" ]; + }; +} diff --git a/modules/services/container/k3s/default.nix b/modules/services/container/k3s/default.nix new file mode 100644 index 0000000..2e26d5c --- /dev/null +++ b/modules/services/container/k3s/default.nix @@ -0,0 +1,123 @@ +{ lib, pkgs, config, inputs, ... }: +let + inherit (inputs) kubenix; + k3s-reset-node = pkgs.writeShellScriptBin "k3s-reset-node" '' + read -p "Are you sure? This will purge all k3s data: " -n 1 -r; echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + set +e + systemctl stop containerd.service k3s.service 2>/dev/null + systemctl kill containerd.service k3s.service 2>/dev/null + find /sys/fs/cgroup/systemd/system.slice/containerd.service* /sys/fs/cgroup/kubepods* -name cgroup.procs -print0 | xargs -0 -r cat | xargs -r kill -9 2>/dev/null + mount | awk '/\/var\/lib\/kubelet|\/run\/netns|\/run\/containerd/ {print $3}' | xargs -r umount 2>/dev/null + for ID in $(zfs list -r rpool/data/containerd | grep rpool/data/containerd/ | awk '{print $1}'); do zfs destroy -R $ID; done 2>/dev/null + rm -rf /run/containerd /etc/rancher /var/lib/cni /var/lib/containerd /var/lib/kubelet /var/lib/rancher 2>/dev/null + set -e + systemctl start containerd.service k3s.service + fi + ''; +in +{ + age.secrets = { + k8s_cluster_token.file = ./k8s_cluster_token.age; + k8s_environment.file = ./k8s_environment.age; + k8s_dns_update_rfc2136.file = ./k8s_dns_update_rfc2136.age; + k8s_traefik_dashboard.file = ./k8s_traefik_dashboard.age; + }; + + environment = { + systemPackages = with pkgs; [ + k3s + k3s-reset-node + ]; + + shellAliases = { + k = "${pkgs.k3s}/bin/k3s kubectl"; + kubectl = "${pkgs.k3s}/bin/k3s kubectl"; + }; + + etc."kubenix.yaml".source = + (kubenix.evalModules.${pkgs.hostPlatform.system} { + module = + { kubenix, ... }: + { + imports = [ kubenix.modules.k8s ]; + kubernetes = { + version = "1.26"; + resources = { + namespaces = { + "traefik" = { }; + "cert-manager" = { }; + "external-dns" = { }; + }; + secrets = { + traefik-dashboard-auth-secret = { + metadata.namespace = "traefik"; + data.users = "ref+file://${config.age.secrets.k8s_traefik_dashboard.path}"; + }; + dns-rfc2136-key-cert-manager = { + metadata.namespace = "cert-manager"; + stringData.password = "ref+file://${config.age.secrets.k8s_dns_update_rfc2136.path}"; + }; + dns-rfc2136-key-external-dns = { + metadata.namespace = "external-dns"; + stringData.password = "ref+file://${config.age.secrets.k8s_dns_update_rfc2136.path}"; + }; + }; + }; + }; + }; + }).config.kubernetes.resultYAML; + }; + + virtualisation.containerd = { + enable = lib.mkIf config.services.k3s.enable true; + settings = + let + fullCNIPlugins = pkgs.buildEnv { + name = "full-cni"; + paths = with pkgs; [ + cni-plugins + cni-plugin-flannel + ]; + }; + in + { + plugins."io.containerd.grpc.v1.cri".cni = { + bin_dir = "${fullCNIPlugins}/bin"; + conf_dir = "/var/lib/rancher/k3s/agent/etc/cni/net.d/"; + }; + }; + }; + + services.k3s = { + package = pkgs.k3s_1_29; + clusterInit = lib.mkIf (config.services.k3s.role == "server") true; + tokenFile = config.age.secrets.k8s_cluster_token.path; + environmentFile = config.age.secrets.k8s_environment.path; + }; + + systemd.services.k3s.path = with pkgs; [ + openiscsi + nfs-utils + ipset + ]; + + system.activationScripts.kubenix.text = '' + cat /etc/kubenix.yaml | ${pkgs.vals}/bin/vals eval > /var/lib/rancher/k3s/server/manifests/kubenix.yaml + ''; + + boot.kernel.sysctl = { + "net.core.rmem_max" = 2500000; + }; + + networking.firewall = { + allowedTCPPorts = [ + 80 + 443 + ]; + allowedUDPPorts = [ + 80 + 443 + ]; + }; +} diff --git a/modules/services/container/k3s/k8s_cluster_token.age b/modules/services/container/k3s/k8s_cluster_token.age new file mode 100644 index 0000000..bd2b84f --- /dev/null +++ b/modules/services/container/k3s/k8s_cluster_token.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw i0MtK0mAm0I6gig+7PsGsfe359YXhuKRoOnAn31W5Bs +9IcUM1N48YXgbYaPX6W48QfvmarUdjaOWynkUOmpIe4 +-> ssh-ed25519 JzjriQ +aZGSlPBlZJcMqc3lQZcEEmjOdcymOtkbDonEieGvnQ +hirQkN9Sj4YUpUahKOVkJ+cvb7mu85Hei4VBYQu3lMM +-> ssh-rsa 6hPx7A +Ryd3f+kT9TovF/EsM5PKfFJoSJAgSmt2zdYHkn+wMV7P6rlc26hsIcF5N2QnzuZl +YnMOZQBqX+r2Wr73l/Co08/2GxpKQVMo/1sJps1tBYMMEdViXXWIYpPpjJiSQkEK +4pa6+iahqtv0eOG4BAzw1iVRPLH030oLOBLHXFTuMa6Z4nbbokXMfH0WPVmyMNfx +B2NNd9BVr5IumWUdFo4/H7vbqVI3+9l5X5PEA4RQY3HStXzVzKN3byyCMymG4IJJ +u99DTSQLttWwMzQeaZpQTz5AaFdrOv7/ZxF3c5x9glhHIeuFHwDvEAT55Wj13uoy +F4lhEMwnHOh0nNClafOZvxUDn+T7/BQj8eHsZrDEVNOaBJ7+SxYS4BaGxLuDIwuR +DKoDYGq5cGYqo3kwKKX/JrYvVF/dS8J7fWAwYE4QeT9BNbPzhf4ikmMGnIOKEu4y +ZaQNu1MgfF4TkquS2cUDHr5GFJ1cUG9kh+fnluS0XA7UB2hJp1GJlDaGtNXtUeza +y2FRO28IS6HsNyXgU0/jUBck0iLK4SVlnHqbAkVFVe3ieMSfCs8ItvR4gHtACMlp +tfY/lM6ndoGuP3h5TeyHIzeLh2GAGEheagHKkWrq5Y9H5ey7DhUvM8hQLnSPoxfi +M2W82r+qr/MzBCVPZwESdBm/N+X5iRK7ARGkb7Tvx80 +-> ssh-ed25519 v+/Ozg Owz68lZizxg/Pwm8hJkP64A/w0PIcMV4GK73HTiVTRE +aK+CqTK4k6a9RPixSVRhvjxvlJX0lrJ8zySr8Bzbz8k +--- v9J7DptW6p5Je46ZYX7K44JsxcMB7BsEmhUi8E6gU4Y +f-T鼩!4iPZBeBܡ@D'J=w \ No newline at end of file diff --git a/modules/services/container/k3s/k8s_dns_update_rfc2136.age b/modules/services/container/k3s/k8s_dns_update_rfc2136.age new file mode 100644 index 0000000..fe099d6 Binary files /dev/null and b/modules/services/container/k3s/k8s_dns_update_rfc2136.age differ diff --git a/modules/services/container/k3s/k8s_environment.age b/modules/services/container/k3s/k8s_environment.age new file mode 100644 index 0000000..4a76062 Binary files /dev/null and b/modules/services/container/k3s/k8s_environment.age differ diff --git a/modules/services/container/k3s/k8s_traefik_dashboard.age b/modules/services/container/k3s/k8s_traefik_dashboard.age new file mode 100644 index 0000000..38fb69c Binary files /dev/null and b/modules/services/container/k3s/k8s_traefik_dashboard.age differ diff --git a/modules/services/container/podman.nix b/modules/services/container/podman.nix new file mode 100644 index 0000000..25af1b5 --- /dev/null +++ b/modules/services/container/podman.nix @@ -0,0 +1,20 @@ +{ pkgs, config, lib, ... }: +{ + imports = [ ./default.nix ]; + + virtualisation = { + oci-containers.backend = "podman"; + + podman = { + enable = true; + autoPrune.enable = true; + + dockerCompat = true; + dockerSocket.enable = true; + + extraPackages = with pkgs; [ zfs passt ]; + }; + }; + + users.users.telegraf = lib.mkIf config.services.telegraf.enable { extraGroups = [ "podman" ]; }; +} diff --git a/modules/services/database/mysql.nix b/modules/services/database/mysql.nix new file mode 100644 index 0000000..c1871c4 --- /dev/null +++ b/modules/services/database/mysql.nix @@ -0,0 +1,28 @@ +{ lib, config, ... }: +{ + services = { + mysql = { + enable = true; + settings = { + mysqld = { + plugin-load-add = [ + "server_audit" + "ed25519=auth_ed25519" + ]; + }; + + mysqldump = { + quick = true; + max_allowed_packet = "16M"; + }; + }; + }; + + mysqlBackup.enable = lib.mkIf config.services.mysql.enable true; + + telegraf.extraConfig.inputs.mysql = lib.mkIf config.services.telegraf.enable { + servers = [ "tcp(127.0.0.1:3306)/" ]; + metric_version = 2; + }; + }; +} diff --git a/modules/services/database/postgresql.nix b/modules/services/database/postgresql.nix new file mode 100644 index 0000000..23032d3 --- /dev/null +++ b/modules/services/database/postgresql.nix @@ -0,0 +1,37 @@ +{ lib, pkgs, config, ... }: +{ + services = { + postgresql = { + enable = true; + enableTCPIP = true; + package = pkgs.postgresql_14; + settings = { + logging_collector = true; + log_connections = true; + log_disconnections = true; + }; + }; + + postgresqlBackup = { + enable = true; + backupAll = true; + compression = "zstd"; + }; + + prometheus = { + exporters.postgres.enable = true; + scrapeConfigs = [ + { + job_name = "postgresql"; + static_configs = [ + { targets = [ "localhost:${toString config.services.prometheus.exporters.postgres.port}" ]; } + ]; + } + ]; + }; + + telegraf.extraConfig.inputs.postgresql = lib.mkIf config.services.telegraf.enable { }; + }; + + users.users.telegraf = lib.mkIf config.services.telegraf.enable { extraGroups = [ "postgres" ]; }; +} diff --git a/modules/services/dns/avahi.nix b/modules/services/dns/avahi.nix new file mode 100644 index 0000000..23bc370 --- /dev/null +++ b/modules/services/dns/avahi.nix @@ -0,0 +1,14 @@ +{ + services.avahi = { + enable = true; + ipv4 = true; + ipv6 = true; + nssmdns4 = true; + nssmdns6 = true; + publish = { + enable = true; + userServices = true; + workstation = true; + }; + }; +} diff --git a/modules/services/dns/default.nix b/modules/services/dns/default.nix new file mode 100644 index 0000000..7487948 --- /dev/null +++ b/modules/services/dns/default.nix @@ -0,0 +1,47 @@ +{ pkgs, lib, inputs, config, ... }: + +with lib; +with inputs; + +let + cfg = config.srx.service.dns; + + identity = "${config.services.knot.settings.server.identity}."; + primary = config.srx.service.dns.defaults.SOA.nameServer; + + writeZoneFile = zone: records: pkgs.writeText "${zone}.zone" ( + dns.lib.toString zone records + ); + + knotZones = lib.attrsets.mapAttrs + (zone: records: { + file = lib.mkIf (identity == primary) (writeZoneFile zone records); + template = lib.mkIf (identity != primary) "slave"; + }) + cfg.zones; +in +{ + options.srx.service.dns = { + zones = mkOption { + type = types.attrs; + default = { }; + description = ""; + }; + + defaults = mkOption { + type = types.attrs; + default = { }; + description = ""; + }; + + mergeHosts = mkOption { + type = types.bool; + default = true; + description = ""; + }; + }; + + config = { + services.knot.settings.zone = lib.mkIf config.services.knot.enable knotZones; + }; +} diff --git a/modules/services/dns/knot/default.nix b/modules/services/dns/knot/default.nix new file mode 100644 index 0000000..0f85469 --- /dev/null +++ b/modules/services/dns/knot/default.nix @@ -0,0 +1,30 @@ +{ + imports = [ + ./modules.nix + ./monitoring.nix + ./system.nix + ]; + + services.knot = { + enable = true; + + settings = { + server = { + listen = [ "0.0.0.0@53" "::@53" ]; + listen-quic = [ "0.0.0.0@853" ]; + tcp-reuseport = true; + tcp-fastopen = true; + }; + + log.syslog.any = "info"; + + database = { + journal-db = "/var/lib/knot/journal"; + kasp-db = "/var/lib/knot/kasp"; + timer-db = "/var/lib/knot/timer"; + }; + + keystore.default.backend = "pem"; + }; + }; +} diff --git a/modules/services/dns/knot/modules.nix b/modules/services/dns/knot/modules.nix new file mode 100644 index 0000000..df2a067 --- /dev/null +++ b/modules/services/dns/knot/modules.nix @@ -0,0 +1,29 @@ +{ + services.knot.settings = { + mod-rrl.default = { + rate-limit = 512; + slip = 2; + }; + + mod-cookies.default = { + secret-lifetime = "30h"; + badcookie-slip = 3; + }; + + mod-stats.all = { + server-operation = true; + edns-presence = true; + flag-presence = true; + query-size = true; + query-type = true; + request-protocol = true; + request-bytes = true; + request-edns-option = true; + reply-size = true; + reply-nodata = true; + response-code = true; + response-bytes = true; + response-edns-option = true; + }; + }; +} diff --git a/modules/services/dns/knot/monitoring.nix b/modules/services/dns/knot/monitoring.nix new file mode 100644 index 0000000..152ecd3 --- /dev/null +++ b/modules/services/dns/knot/monitoring.nix @@ -0,0 +1,38 @@ +{ lib, config, ... }: +{ + services.prometheus = { + exporters = { + knot.enable = true; + + dnssec = { + enable = true; + configuration.records = lib.attrsets.mapAttrsToList + (zone: _: { + inherit zone; + record = "@"; + type = "SOA"; + }) + config.srx.service.dns.zones; + }; + }; + + scrapeConfigs = [ + { + job_name = "knot"; + static_configs = [{ + targets = lib.lists.forEach config.srx.service.dns.defaults.NS ( + host: toString host + ":${toString config.services.prometheus.exporters.knot.port}" + ); + }]; + } + { + job_name = "dnssec"; + static_configs = [{ + targets = lib.lists.forEach config.srx.service.dns.defaults.NS ( + host: toString host + ":${toString config.services.prometheus.exporters.dnssec.port}" + ); + }]; + } + ]; + }; +} diff --git a/modules/services/dns/knot/secrets/notify.age b/modules/services/dns/knot/secrets/notify.age new file mode 100644 index 0000000..15a6f9b --- /dev/null +++ b/modules/services/dns/knot/secrets/notify.age @@ -0,0 +1,26 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw LalGl43X63KHU3u5YttzpM50W+OYCYUzKmlA0DcUYyw +2IEm+ynbpZUjtZn++6Pec1AujVvXZLmz3qv93buUV5M +-> ssh-ed25519 JzjriQ hmEu3Z8VFX7FMyRououBFcXb3hfIJTcI1bp0IcZKKUI +Sm6bx5GqMtL8FE4IyTUPEZJ/hD1yZtCzSSqVWN1RRSw +-> ssh-rsa 6hPx7A +rN5fraYhNXxCAw1k9LjrfS+GwCZxJLMVpGKb8WvXY2GcH8iqkifAcr9OLOHjA8SX +tJTuiiP++jpm4gnOLIKr7JF3Zf7KEaTMAzMPmlqmCMlhsetR2xsI4lX0CEmskqNd +Y/HyFLxA8/033QfSTMrMtwb2HnTDTui1hxyk78mMZK1WfmH7mBTW981dO0Eu3Xzw +Rp/Mr/Q6j6ALvv/RIAmAaS4XPFudzgRF3+LdQ7sIbolL4Qs4TmLs2pJZUgtbi9uj +hNyO+CMEsjGTimsk3P0XArNgTBwSsLoWe3kqrOEI6Qq1nTCaZrAZSdLHlyPIiKsJ +OFOw+PmdKPhJwZ7hdC8q7NLxQt9323nDG5s1HlzSNLYSLPJO8RBNW2tC0UJHLR0A +HaDmjJbrpGWnr2FZEHRTppzzAFHQRLNYufpauGLizfquyJ3JnvuBm0XMN0D7Dv4y +ozYf0r/ul8y7ce054j+B+9U2R9u1TGF2kYi3VtA+tKiamIrJZoyTYhKtp95JyDHq +RZcCeLAHxCWpkPoGFRZc2M3lc0rml4WgZQWvPm2sZt4aPZ2oxWselcBBvafwFJbV +bG6cfrqtrkAvfz05F6fJkNqYrlwzD4Sbs7smmq1PHAdVa3/sCqx1NWKQjsrxbL4U +DauI7+dBDCTU5Ti6jDxdKLU3ZeFy+0rS8qAbUt8v9i0 +-> ssh-ed25519 Dfencg lRmg947fjO2+6jQk7dfUnFCEmLQL8fpZk+NKyCK0vlw +H3+IQlxiC1qtvUdCZN7G3SMPKSeEveKOR6EEaAkgzYY +-> ssh-ed25519 OWgoVA 6EkpFgTdjTp8r4xkdRiDyL1IT3Xi71EFaQ+B/5eYumU +AiEzhEXzMRKG78stZxhvzw43JdHvVH0iez7RVWL5fi8 +-> ssh-ed25519 aP/BWw Jfgvos/ToJnlRXxrw1HJqVK96yFdul08m/urWIybzxY +IUFcGvwu+Haa3czjtA5bmn9JR4J7UH2zWCWJIeEuhV8 +--- IuNh2It+4aP21cuhFNy0u/Cr78ZkWzeSeGo5W2hLvi8 +0k5 QW vdRQG* ;.;3]:L\i.|ΤI/! +L$=X#J +;3m)44˕^#)Ƌ'X3HnTcvZ \ No newline at end of file diff --git a/modules/services/dns/knot/secrets/transfer.age b/modules/services/dns/knot/secrets/transfer.age new file mode 100644 index 0000000..7e84d9c --- /dev/null +++ b/modules/services/dns/knot/secrets/transfer.age @@ -0,0 +1,25 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw ZvaQoA2+Kx/Cmhh2v5X8HuZdDR8J+kl3RoxIUW5Ob3Y +5li2vxm7Bo9kAz8X+GGvkzfnG3LezaOQSIWkeP35mmM +-> ssh-ed25519 JzjriQ TXpjguPNNLkMNvoYLjmuBn2ebNi95y2p+ajXvE68BWY +TGRPfwMamNsdX8g0LMn8jDVQmH0faz5iaJwSBquV8So +-> ssh-rsa 6hPx7A +AEQfpzGm/5ehJgGLfG6W5d1ejyGG/+lPt3msIxPP8+nalIqxSXYDRroEt1yvVy9H +BqhHggbHSluOaFBwco+oSGwz5+WWOqkt8X7QpOgKr/e8Su4Uw977YsKbrpozY6Sv +OI3ae8Y1tIvRu4t7zGYGKPAximuMoJQZZU7BODox5JwXPrn8i9qxL7/04ZmChVdv +gXDwidVjCKBn8GhTLMeMDfeOxZmnT2ISVgwxQwCagZObZjJvoAaK5YKReJ9MXMYz +lKMc3x//mvh/zNOxMsAOgcgejGfXrZ5V4nQ0AYo93Auk+8wCl+o55w08bypD0g0n +8XbbGRBhMbqUliV6K+dECeEgedpwelI/sGuVRztihr48gUTaepHYskHjR5zmtFU+ +vDIqL+sagpXYHAA5jKQFOO06UoOI/564MAGg2RDqBy3oO2PhrIf5Wx7Bc55gRa/V +iuBTM0Z1CFk/xAQcyuCvT4l3PPwQw0nRhjdUVy5iPWk4acPZ8eypMXfpYApSTEo+ +FYnV97Oy6NCokg4ab4zOzGywP763fveoBDzim5d7mSypRMQCNvHghkt0B4DFj1++ ++WTIQCH81nm1uRaq3kLrGC3uweyFLLzAi/s4uzJ64OQIWz6l2CwZGLRpvSbOZOTR +fHU+3sLE5m8bdzpGmUU03sIVMT8I6DEWqO+hKY6WZ0g +-> ssh-ed25519 Dfencg h38X7a6k0ekakfrLqFnwPfsFR8OqhJiLZVyvmuLXGTw +3mWIWVV2Qn4sSlWoJY5P9K6KKS9DmdwTv5GJLQxIm9Q +-> ssh-ed25519 OWgoVA lbL/exL/ISUxxcyhRn+UYBecgCmYd0kacaYaqWaniUk +LEWaRQUrxaheMZ84+DaIT8+SSbRvvInG+uFgy6MHUMc +-> ssh-ed25519 aP/BWw T152dvP4OVYfpmBmL1fVp3qWSa6H+9H696CIFEh/zQI +EMek0YWld7Tt0Q7VJhCfGMZV4rj09hRQL1Ub1mnFpcI +--- 2A2PrD2AOi/L8xjLJ1aCSDn0IqP2XOuXe9h9n5jWC+I +.x?ˀC!Pcu$M o"zFb߆4@t;$L`8B@cgԡWbYz0Xcc^i^~$1%HJs4a-bX'G7v 0/)4o[?xȋ \ No newline at end of file diff --git a/modules/services/dns/knot/secrets/tsig_xfr.age b/modules/services/dns/knot/secrets/tsig_xfr.age new file mode 100644 index 0000000..907a923 Binary files /dev/null and b/modules/services/dns/knot/secrets/tsig_xfr.age differ diff --git a/modules/services/dns/knot/secrets/update.age b/modules/services/dns/knot/secrets/update.age new file mode 100644 index 0000000..c74aedf Binary files /dev/null and b/modules/services/dns/knot/secrets/update.age differ diff --git a/modules/services/dns/knot/secrets/update_k8s.age b/modules/services/dns/knot/secrets/update_k8s.age new file mode 100644 index 0000000..1c2e8f5 Binary files /dev/null and b/modules/services/dns/knot/secrets/update_k8s.age differ diff --git a/modules/services/dns/knot/secrets/update_terraform_cicd.age b/modules/services/dns/knot/secrets/update_terraform_cicd.age new file mode 100644 index 0000000..3a50cba Binary files /dev/null and b/modules/services/dns/knot/secrets/update_terraform_cicd.age differ diff --git a/modules/services/dns/knot/secrets/update_terraform_swendel.age b/modules/services/dns/knot/secrets/update_terraform_swendel.age new file mode 100644 index 0000000..a322afe Binary files /dev/null and b/modules/services/dns/knot/secrets/update_terraform_swendel.age differ diff --git a/modules/services/dns/knot/system.nix b/modules/services/dns/knot/system.nix new file mode 100644 index 0000000..e2843bf --- /dev/null +++ b/modules/services/dns/knot/system.nix @@ -0,0 +1,26 @@ +{ + networking.firewall = { + allowedTCPPorts = [ 53 853 ]; + allowedUDPPorts = [ 53 853 ]; + }; + + boot.kernel.sysctl = + let + socket_bufsize = 1048576; + busy_latency = 0; + backlog = 40000; + optmem_max = 20480; + in + { + "net.ipv4.tcp_fastopen" = 3; + "net.ipv4.tcp_tw_reuse" = 1; + "net.core.wmem_max" = socket_bufsize; + "net.core.wmem_default" = socket_bufsize; + "net.core.rmem_max" = socket_bufsize; + "net.core.rmem_default" = socket_bufsize; + "net.core.busy_read" = busy_latency; + "net.core.busy_poll" = busy_latency; + "net.core.netdev_max_backlog" = backlog; + "net.core.optmem_max" = optmem_max; + }; +} diff --git a/modules/services/dns/knot/zones/srx.digital.nix b/modules/services/dns/knot/zones/srx.digital.nix new file mode 100644 index 0000000..5ac3713 --- /dev/null +++ b/modules/services/dns/knot/zones/srx.digital.nix @@ -0,0 +1,139 @@ +{ dns, ... }: +with dns.lib.combinators; +{ + SOA = { + nameServer = "ns1.srx.dev."; + adminEmail = "hostmaster_ao5aeF@srx.digital"; + serial = 1981080812; + refresh = 6 * 60 * 60; + retry = 60 * 60; + }; + + NS = [ + "ns1.srx.dev." + "ns2.srx.dev." + "ns3.srx.dev." + ]; + + MX = [ (mx.mx 10 "mail") ]; + + TXT = [ (with spf; strict [ "mx" ]) ]; + + DMARC = [ + { + p = "quarantine"; + sp = "reject"; + rua = [ "mailto:dmarc@srx.digital" ]; + ruf = [ "mailto:dmarc@srx.digital" ]; + } + ]; + + DKIM = [ + { + selector = "mail"; + s = [ "email" ]; + p = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDbg881GUU/m6SGOkSbg4/USEP0TnN7xPqrv1tcALo1wnNRmUjBBIrQueidF0vwlEQr41iuuDH28ggKuSSUmlfxFVWvaYrgN2hdd54xCshfW47kUwsH+J8VzrLTAUU4p8PP2EMRVvF2cKPce4tdBWHjbw4YzfYlyTTo3vBS/aLE1QIDAQAB"; + } + ]; + + SRV = [ + { service = "https"; proto = "tcp"; port = 443; target = "autoconfig"; } + { service = "caldavs"; proto = "tcp"; port = 443; target = "cloud"; } + { service = "carddavs"; proto = "tcp"; port = 443; target = "cloud"; } + { service = "submissions"; proto = "tcp"; port = 465; target = "mail"; } + { service = "imaps"; proto = "tcp"; port = 993; target = "mail"; } + ]; + + A = [ "65.108.77.254" ]; + AAAA = [ "2a01:4f9:6b:2573::1" ]; + + subdomains = rec { + srxgp00 = host "65.108.77.254" "2a01:4f9:6b:2573::1"; + srxgp01 = host "152.53.17.250" "2a0a:4cc0:1:131a::1"; + srxgp02 = host "212.132.77.48" "2a02:247a:275:9300::1"; + srxk8s00 = host "78.46.220.70" "2a01:4f8:1c0c:5214::1"; + vpn = delegateTo [ "ns1" "ns2" "ns3" ]; + whoami = delegateTo [ "ns1" "ns2" "ns3" ]; + whoami6 = delegateTo [ "ns1" "ns2" "ns3" ]; + dns = srxgp00; + ns1 = srxgp00; + ns2 = srxgp01; + ns3 = srxgp02; + mail = srxgp00; + autoconfig = srxgp00; + ldap = srxgp00; + support = srxgp00; + checkip = srxgp00; + netboot = srxgp00; + tsdb = srxgp00; + id = srxgp00; + vault = srxgp00; + cloud = srxgp00; + code = srxgp00; + "live.code" = srxgp00; + pad = srxgp00; + analytics = srxgp00; + home = srxgp00; + media = srxgp00; + office = srxgp00; + paperless = srxgp00; + paper = srxgp00; + meet = srxgp00; + survey = srxgp00; + metrics = srxgp00; + logs = srxgp00; + turn = srxgp00; + status = srxgp00; + auth = srxgp00; + "push.status" = srxgp00; + alerts = srxgp00; + push = srxgp00; + s3 = srxgp00; + "admin.s3" = srxgp00; + geo.subdomains = { + de = srxgp00; + us = srxgp00; + uk = srxgp00; + nl = srxgp00; + }; + + ai.subdomains = { + image = srxgp00; + }; + + nix.subdomains = { + cache = srxgp00; + build = srxgp00; + hydra = srxgp00; + }; + + matrix = { + CNAME = [ "srx.digital." ]; + subdomains = { + chat = srxgp00; + admin = srxgp00; + }; + }; + + hh.subdomains = { + hq.subdomains = { + op.subdomains = rec { + srxfw01 = host "10.50.0.1" null; + srxsw01 = host "10.50.0.3" null; + srxap01 = host "10.50.0.4" null; + srxnas01 = host "10.50.0.10" null; + netboot = srxnas01; + nfs = srxnas01; + }; + }; + }; + + l.subdomains = { + hq.subdomains = { + op.subdomains = { + srxnas00 = host "192.168.178.71" null; + }; + }; + }; + }; +} diff --git a/modules/services/dns/knsupdate.nix b/modules/services/dns/knsupdate.nix new file mode 100644 index 0000000..284269a --- /dev/null +++ b/modules/services/dns/knsupdate.nix @@ -0,0 +1,170 @@ +{ lib, pkgs, config, ... }: +with lib; +let + cfg = config.srx.service.${name}; + name = "knsupdate"; + recordType = ipVersion: if ipVersion == 4 then "A" else "AAAA"; +in +{ + options.srx.service.${name} = { + enable = mkEnableOption '' + If enabled, ${name} will periodically update + the dns record. + ''; + + package = mkPackageOption pkgs "knot-dns" { }; + + zone = mkOption { + type = types.str; + default = config.networking.domain; + example = "example.com"; + description = '' + Specifies the zone of the dynamic update + message. + ''; + }; + + record = mkOption { + type = types.str; + default = config.networking.hostName; + example = "www"; + description = '' + Specifies the record of the dynamic update + message. + ''; + }; + + server = mkOption { + type = types.str; + default = null; + example = "ns1.example.com"; + description = '' + Specifies a receiving server of the dynamic + update message. + + The name parameter can be either a host name + or an IP address. + ''; + }; + + port = mkOption { + type = types.int; + default = 53; + description = '' + Specifies a receiving server port of the + dynamic update message. + ''; + }; + + ttl = mkOption { + type = types.int; + default = 60 * 60; + description = '' + Specifies the records TTL in seconds. + ''; + }; + + interval = mkOption { + type = types.str; + default = "02:15"; + example = "hourly"; + description = '' + Update the dns record at this interval. + Updates by default at 2:15 AM every day. + + The format is described in + {manpage}`systemd.time(7)`. + ''; + }; + + ipVersions = mkOption { + type = types.listOf (types.enum [ 4 6 ]); + default = [ 4 6 ]; + description = '' + Specifies the Internet Protocol Version + to use. + ''; + }; + + lockupService = mkOption { + type = types.str; + default = "https://checkip.srx.digital/"; + description = '' + The URL of the IP lookup service. This service returns + the current public IP address of the machine making + the request. It supports both IPv4 and IPv6 addresses. + ''; + }; + + keyFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/keys/${name}/keyFile"; + description = '' + Specifies the TSIG key file to authenticate the request. + + The format is described in + {manpage}`knot-dns.knsupdate(1)`. + ''; + }; + + user = mkOption { + type = types.str; + default = name; + description = "User under which ${name} runs."; + }; + + group = mkOption { + type = types.str; + default = name; + description = "Group under which ${name} runs."; + }; + }; + + config = lib.mkIf cfg.enable { + systemd = lib.foldl' + (acc: ipVersion: lib.recursiveUpdate acc { + services."${name}-IPv${toString ipVersion}" = { + description = "${name} updates DNS zones for dynamic IPv${toString ipVersion} records"; + path = [ pkgs.curl cfg.package ]; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + User = cfg.user; + Group = cfg.group; + LoadCredential = "tsig:${cfg.keyFile}"; + }; + script = '' + IP=$(${getExe pkgs.curl} -s -${toString ipVersion} ${cfg.lockupService}) + if [[ ! -z "$IP" ]]; then + ${cfg.package}/bin/knsupdate -k ''${CREDENTIALS_DIRECTORY}/tsig << EOT + server ${cfg.server} ${toString cfg.port} + zone ${cfg.zone} + del ${cfg.record}.${cfg.zone}. + add ${cfg.record}.${cfg.zone}. ${toString cfg.ttl} ${recordType ipVersion} $IP + send + EOT + fi + ''; + }; + + timers."${name}-IPv${toString ipVersion}" = { + enable = true; + timerConfig.OnCalendar = cfg.interval; + wantedBy = [ "timers.target" ]; + }; + }) + { } + cfg.ipVersions; + + users = optionalAttrs (cfg.user == name) { + users.${cfg.user} = { + group = cfg.user; + isSystemUser = true; + }; + + groups.${cfg.group}.gid = config.users.users.${cfg.user}.uid; + }; + }; +} diff --git a/modules/services/monitoring/default.nix b/modules/services/monitoring/default.nix new file mode 100644 index 0000000..47d3b1a --- /dev/null +++ b/modules/services/monitoring/default.nix @@ -0,0 +1,7 @@ +{ + imports = [ + ./prometheus.nix + ./telegraf.nix + ./promtail.nix + ]; +} diff --git a/modules/services/monitoring/loki.nix b/modules/services/monitoring/loki.nix new file mode 100644 index 0000000..be58be3 --- /dev/null +++ b/modules/services/monitoring/loki.nix @@ -0,0 +1,94 @@ +{ config, ... }: +{ + services = { + loki = { + enable = true; + configuration = rec { + server = { + http_listen_address = "0.0.0.0"; + http_listen_port = 3100; + }; + + auth_enabled = false; + + common = { + ring = { + instance_addr = server.http_listen_address; + kvstore.store = "inmemory"; + }; + replication_factor = 1; + }; + + ingester = { + lifecycler = { + address = server.http_listen_address; + final_sleep = "0s"; + }; + + chunk_idle_period = "1h"; + max_chunk_age = "1h"; + chunk_target_size = 1048576; + chunk_retain_period = "30s"; + }; + + schema_config.configs = [ + { + from = "2020-10-24"; + store = "boltdb-shipper"; + object_store = "filesystem"; + schema = "v13"; + index = { + prefix = "index_"; + period = "24h"; + }; + } + ]; + + storage_config = { + filesystem.directory = "${config.services.loki.dataDir}/chunks"; + boltdb_shipper = { + active_index_directory = "${config.services.loki.dataDir}/active_index"; + cache_location = "${config.services.loki.dataDir}/cache"; + cache_ttl = "24h"; + }; + }; + + limits_config = { + reject_old_samples = true; + reject_old_samples_max_age = "168h"; + allow_structured_metadata = false; + split_queries_by_interval = "24h"; + }; + + table_manager = { + retention_deletes_enabled = false; + retention_period = "0s"; + }; + + compactor.working_directory = "${config.services.loki.dataDir}/compactor"; + + query_range.cache_results = true; + + memberlist.join_members = [ "logs.vpn.srx.dev:${server.http_listen_address}" ]; + }; + }; + + prometheus.scrapeConfigs = [{ + job_name = "loki"; + static_configs = [{ + targets = [ + "${config.services.loki.configuration.server.http_listen_address}:${toString config.services.loki.configuration.server.http_listen_port}" + ]; + }]; + }]; + + grafana.provision.datasources.settings.datasources = [{ + name = "Loki"; + type = "loki"; + access = "proxy"; + url = "http://${config.services.loki.configuration.server.http_listen_address}:${toString config.services.loki.configuration.server.http_listen_port}"; + jsonData = { timeout = 60; maxLines = 1000; }; + }]; + }; +} + diff --git a/modules/services/monitoring/prometheus.nix b/modules/services/monitoring/prometheus.nix new file mode 100644 index 0000000..cc86f5e --- /dev/null +++ b/modules/services/monitoring/prometheus.nix @@ -0,0 +1,33 @@ +{ pkgs, lib, config, ... }: +{ + services.prometheus.exporters = { + systemd.enable = true; + smartctl.enable = lib.mkIf config.services.smartd.enable true; + node = { + enable = true; + enabledCollectors = [ + "systemd" + "processes" + "cgroups" + ]; + }; + blackbox = { + enable = true; + configFile = pkgs.writeText "blackbox-exporter.yaml" ( + builtins.toJSON { + modules.ssh_banner = { + prober = "tcp"; + timeout = "10s"; + tcp = { + preferred_ip_protocol = "ip4"; + query_response = [{ + expect = "^SSH-2.0-"; + send = "SSH-2.0-blackbox-ssh-check"; + }]; + }; + }; + } + ); + }; + }; +} diff --git a/modules/services/monitoring/promtail.nix b/modules/services/monitoring/promtail.nix new file mode 100644 index 0000000..c77a53a --- /dev/null +++ b/modules/services/monitoring/promtail.nix @@ -0,0 +1,48 @@ +{ config, ... }: +{ + services = { + promtail = { + enable = true; + configuration = { + server = { + http_listen_address = "0.0.0.0"; + http_listen_port = 9080; + grpc_listen_port = 0; + }; + clients = [{ url = "http://logs.vpn.srx.dev:3100/loki/api/v1/push"; }]; + scrape_configs = [{ + job_name = "journal"; + journal = { + json = true; + max_age = "12h"; + labels.job = "systemd-journal"; + }; + pipeline_stages = [ + { json.expressions = { transport = "_TRANSPORT"; unit = "_SYSTEMD_UNIT"; msg = "MESSAGE"; coredump_cgroup = "COREDUMP_CGROUP"; coredump_exe = "COREDUMP_EXE"; coredump_cmdline = "COREDUMP_CMDLINE"; coredump_uid = "COREDUMP_UID"; coredump_gid = "COREDUMP_GID"; }; } + { labels.coredump_unit = "coredump_unit"; } + { template = { source = "msg"; template = "{{if .coredump_exe}}{{.coredump_exe}} core dumped (user: {{.coredump_uid}}/{{.coredump_gid}}, command: {{.coredump_cmdline}}){{else}}{{.msg}}{{end}}"; }; } + { template = { source = "unit"; template = "{{if .unit}}{{.unit}}{{else}}{{.transport}}{{end}}"; }; } + { replace = { source = "unit"; expression = "^(session-\\d+.scope)$"; replace = "session.scope"; }; } + { regex = { expression = "(?P[^/]+)$"; source = "coredump_cgroup"; }; } + { labels.unit = "unit"; } + { output.source = "msg"; } + ]; + relabel_configs = [ + { source_labels = [ "__journal__systemd_unit" ]; target_label = "unit"; } + { source_labels = [ "__journal__transport" ]; target_label = "transport"; } + { source_labels = [ "__journal__hostname" ]; target_label = "host"; } + ]; + }]; + }; + }; + + prometheus.scrapeConfigs = [{ + job_name = "promtail"; + static_configs = [{ + targets = [ + "${config.services.promtail.configuration.server.http_listen_address}:${toString config.services.promtail.configuration.server.http_listen_port}" + ]; + }]; + }]; + }; +} diff --git a/modules/services/monitoring/telegraf.nix b/modules/services/monitoring/telegraf.nix new file mode 100644 index 0000000..394dc0f --- /dev/null +++ b/modules/services/monitoring/telegraf.nix @@ -0,0 +1,36 @@ +{ inputs, ... }: +{ + imports = with inputs; [ + srvos.nixosModules.mixins-telegraf + ]; + + services.telegraf = { + enable = true; + extraConfig = { + inputs = { + cpu = { }; + mem = { }; + swap = { }; + bond = { }; + disk = { }; + diskio = { }; + cgroup = { }; + system = { }; + conntrack = { }; + dns_query = { }; + filecount = { }; + hugepages = { }; + interrupts = { }; + iptables = { }; + kernel = { }; + netstat = { }; + nstat = { }; + processes = { }; + kernel_vmstat = { }; + systemd_units = { }; + internet_speed.interval = "60m"; + }; + outputs.prometheus_client.listen = ":9273"; + }; + }; +} diff --git a/modules/services/netboot/config.nix b/modules/services/netboot/config.nix new file mode 100644 index 0000000..f6ef327 --- /dev/null +++ b/modules/services/netboot/config.nix @@ -0,0 +1,36 @@ +{ lib, pkgs, config, ... }: +{ + imports = [ + ../../roles/core/fail2ban.nix + ../../roles/core/zsh.nix + ../../roles/core/editor.nix + ]; + + boot.supportedFilesystems = [ "zfs" "btrfs" ]; + + services = { + openssh.enable = true; + rpcbind.enable = true; + getty.autologinUser = lib.mkForce null; + }; + + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB6vk3k1p6YMsGLFQ/xABLYK/VJicywkf1MJawnN7oXU" + ]; + + environment.systemPackages = with pkgs; [ + ethtool + iotop + iperf + lsof + nvme-cli + pciutils + socat + sysstat + tcpdump + usbutils + vnstat + ]; + + system.stateVersion = config.system.nixos.release; +} diff --git a/modules/services/netboot/default.nix b/modules/services/netboot/default.nix new file mode 100644 index 0000000..33b700a --- /dev/null +++ b/modules/services/netboot/default.nix @@ -0,0 +1,88 @@ +{ pkgs, modulesPath, ... }: +let + nixosNetboot = + let + inherit ((import (pkgs.path + "/nixos/lib/eval-config.nix") { + system = "x86_64-linux"; + modules = [{ + imports = [ + (modulesPath + "/installer/netboot/netboot-base.nix") + ./config.nix + ]; + }]; + }).config.system) build; + in + pkgs.symlinkJoin { + name = "nixos-netboot"; + paths = with build; [ + kernel + netbootRamdisk + netbootIpxeScript + ]; + }; + + ipxeMenu = pkgs.writeTextDir "boot.php" '' + #!ipxe + + echo ip-address: ''${net0/ip} + echo ip-subnet-mask: ''${net0/netmask} + echo boot-file: ''${filename} + + :menu + menu iPXE boot menu + + item disk Boot Disk + item nixos-netboot Boot NixOS Netboot + item netboot-xyz Boot Netboot.xyz + item shell Start iPXE shell + item off Shutdown + item reset Reboot + + choose --default nixos-netboot --timeout 5000 res || goto menu + goto ''${res} + + :disk + exit + + :nixos-netboot + chain --autofree images/nixos-netboot/netboot.ipxe || goto menu + + :netboot-xyz + chain --autofree ipxe/netboot-xyz.ipxe || goto menu + + :shell + shell || goto menu + + :off + echo power off system + sleep 10 || goto menu + poweroff + + :reset + reboot + ''; + + ipxeNetbootXyz = pkgs.writeTextDir "netboot-xyz.ipxe" '' + #!ipxe + chain --autofree https://boot.netboot.xyz/ + ''; + + ipxeCollection = pkgs.symlinkJoin { + name = "ipxe"; + paths = [ ipxeNetbootXyz ]; + }; + + netbootWebRoot = pkgs.runCommand "webroot" { } '' + mkdir -pv $out/images + ln -s ${ipxeMenu}/boot.php $out/boot.php + ln -s ${nixosNetboot} $out/images/nixos-netboot + ln -s ${ipxeCollection} $out/ipxe + ''; +in +{ + services.nginx.virtualHosts."netboot.srx.digital" = { + forceSSL = true; + enableACME = true; + locations."/".root = netbootWebRoot; + }; +} diff --git a/modules/services/security/clamav/default.nix b/modules/services/security/clamav/default.nix new file mode 100644 index 0000000..6a51210 --- /dev/null +++ b/modules/services/security/clamav/default.nix @@ -0,0 +1,12 @@ +{ lib, ... }: +{ + services.clamav = { + scanner = { + enable = lib.mkDefault true; + interval = "daily"; + }; + updater.enable = lib.mkDefault true; + fangfrisch.enable = lib.mkDefault true; + daemon.enable = lib.mkDefault true; + }; +} diff --git a/modules/services/security/tang/default.nix b/modules/services/security/tang/default.nix new file mode 100644 index 0000000..3ceb0b0 --- /dev/null +++ b/modules/services/security/tang/default.nix @@ -0,0 +1,33 @@ +{ pkgs, ... }: +let + port = 7654; +in +{ + services.tang = { + enable = true; + listenStream = [ + "7654" + # "${host}" + ]; + ipAddressAllow = [ + "0.0.0.0/0" + # "10.80.0.0/24" + ]; + }; + + + environment.systemPackages = with pkgs; [ + cryptsetup + clevis + tang + jose + ]; + + networking.firewall.allowedTCPPorts = [ port ]; + + # services.nginx.virtualHosts.${host} = { + # forceSSL = true; + # enableACME = true; + # locations."/".proxyPass = "http://${bind}"; + # }; +} diff --git a/modules/services/storage/samba/default.nix b/modules/services/storage/samba/default.nix new file mode 100644 index 0000000..7129105 --- /dev/null +++ b/modules/services/storage/samba/default.nix @@ -0,0 +1,97 @@ +{ + services.samba = { + enable = true; + openFirewall = true; + securityType = "user"; + extraConfig = '' + server string = %h + workgroup = srx + netbios name = %h + + logging = systemd + log level = 1 + + load printers = no + + server min protocol = SMB3 + client min protocol = SMB3 + + aio read size = 16384 + aio write size = 16384 + + security = user + map to guest = bad user + guest account = nobody + invalid users = root + force group = users + create mask = 0660 + directory mask = 0770 + ''; + + shares = { + public = { + comment = "public exchange share"; + path = "/srv/public"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "yes"; + }; + + movies = { + comment = "privat movie share"; + path = "/srv/movies"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "yes"; + }; + + music = { + comment = "privat music share"; + path = "/srv/music"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "yes"; + }; + + home = { + comment = "privat home share"; + path = "/srv/home"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "no"; + }; + + documents = { + comment = "privat document share"; + path = "/srv/documents"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "no"; + }; + + pictures = { + comment = "privat picture share"; + path = "/srv/pictures"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "no"; + }; + + videos = { + comment = "privat video share"; + path = "/srv/videos"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "no"; + }; + + backups = { + comment = "privat samba share."; + path = "/srv/backups"; + browseable = "yes"; + writeable = "yes"; + "guest ok" = "no"; + }; + }; + }; +} diff --git a/modules/services/storage/syncthing/default.nix b/modules/services/storage/syncthing/default.nix new file mode 100644 index 0000000..32677d1 --- /dev/null +++ b/modules/services/storage/syncthing/default.nix @@ -0,0 +1,165 @@ +{ + home-manager.users.crstl.home.file = { + # https://docs.syncthing.net/users/ignoring.html + + ".ssh/.stignore".text = '' + config + ''; + + ".gnupg/.stignore".text = '' + scdaemon.conf + gpg-agent.conf + gpg.conf + ''; + + ".mozilla/firefox/.stignore".text = '' + profiles.ini + default/.keep + default/crashes + default/lock + default/user.js + default/saved-telemetry-pings + default/datareporting + Crash\ Reports + Pending\ Pings + ''; + + ".thunderbird/.stignore".text = '' + profiles.ini + default/.keep + default/crashes + default/lock + default/user.js + default/saved-telemetry-pings + default/datareporting + default/ImapMail + Crash\ Reports + Pending\ Pings + ''; + + ".config/FreeTube/.stignore".text = '' + Cache + Code\ Cache + Cookies + Cookies-journal + Crashpad + DawnCache + Dictionaries + GPUCache + history.db + hm_settings.db + Local\ Storage + Network\ Persistent\ State + player_cache + Preferences + Session\ Storage + Shared\ Dictionary + SharedStorage + SingletonCookie + SingletonLock + SingletonSocket + TransportSecurity + Trust\ Tokens + Trust\ Tokens-journal + ''; + }; + + services.syncthing = { + enable = true; + + user = "crstl"; + group = "crstl"; + dataDir = "/home/crstl"; + configDir = "/home/crstl/.config/syncthing"; + + settings = { + devices = { + "srxnb00".id = "4WUQOIU-ZOQ37TB-WY5MVXP-CETPYMW-FX6LY2R-QHLIDS4-EIGNF4G-BLYJNQX"; + "srxws00".id = "PBB2S4Q-ZDZJWA7-3PCEKWO-6AE6QQE-WRTUYFT-KE7PSBK-UXHS5JL-GUWFNQ3"; + "srxws01".id = "LNHCHTQ-HXH23YW-VPUNSTC-O27IIJO-4SH6XWC-EKK4ISR-3TCJ6VX-F2H3HQ7"; + "srxtab00".id = "7TKI7YR-7Y4FDOW-UJI3MB5-UK2XRIG-XOQWCCP-KPZSBQB-6C43AN7-LVQUPQE"; + "srxnas00".id = "6RDN34T-S3QZW3Z-V6TV5LB-EQFHAX4-FUZK6GX-A2IGKNT-6GMF4PE-DBNQPQD"; + "srxnas01".id = "QHM4QIS-KES6PGM-VC4MSQF-L35G7HD-GV6S7FM-JUNLSED-TEU65J4-266IXAC"; + }; + + folders = + let + ignorePerms = false; + devices = [ + "srxnas00" + "srxnas01" + "srxtab00" + "srxnb00" + "srxws00" + "srxws01" + ]; + in + { + downloads = { + path = "/home/crstl/Downloads"; + inherit devices ignorePerms; + }; + + music = { + path = "/home/crstl/Music"; + inherit devices ignorePerms; + }; + + videos = { + path = "/home/crstl/Videos"; + inherit devices ignorePerms; + }; + + documents = { + path = "/home/crstl/Documents"; + inherit devices ignorePerms; + }; + + firefox = { + path = "/home/crstl/.mozilla/firefox"; + inherit devices ignorePerms; + }; + + thunderbird = { + path = "/home/crstl/.thunderbird"; + inherit devices ignorePerms; + }; + + freetube = { + path = "/home/crstl/.config/FreeTube"; + inherit devices ignorePerms; + }; + + keyrings = { + path = "/home/crstl/.local/share/keyrings"; + inherit devices ignorePerms; + }; + + passwords = { + path = "/home/crstl/.password-store"; + inherit devices ignorePerms; + }; + + gpg = { + path = "/home/crstl/.gnupg"; + inherit devices ignorePerms; + }; + + ssh = { + path = "/home/crstl/.ssh"; + inherit devices ignorePerms; + }; + + goa = { + path = "/home/crstl/.config/goa-1.0"; + inherit devices ignorePerms; + }; + + evolution = { + path = "/home/crstl/.local/share/evolution"; + inherit devices ignorePerms; + }; + }; + }; + }; +} diff --git a/modules/services/virtualisation/libvirt.nix b/modules/services/virtualisation/libvirt.nix new file mode 100644 index 0000000..8555f41 --- /dev/null +++ b/modules/services/virtualisation/libvirt.nix @@ -0,0 +1,41 @@ +{ lib, pkgs, config, ... }: +{ + environment.systemPackages = + with pkgs; + [ + virt-top + ssh-askpass-fullscreen + swtpm + ] + ++ lib.optionals config.services.xserver.enable [ + virt-manager + spice-gtk + ]; + + networking.dhcpcd.denyInterfaces = [ "macvtap0@*" ]; + + virtualisation = { + libvirtd = { + enable = true; + + qemu = { + package = pkgs.qemu_kvm; + ovmf = { + enable = true; + packages = [ + (pkgs.OVMF.override { + secureBoot = true; + tpmSupport = true; + }).fd + ]; + }; + swtpm.enable = true; + }; + }; + spiceUSBRedirection.enable = true; + }; + + services.telegraf.extraConfig.inputs.libvirt = lib.mkIf config.services.telegraf.enable { }; + + users.users.telegraf = lib.mkIf config.services.telegraf.enable { extraGroups = [ "libvirtd" ]; }; +} diff --git a/modules/services/virtualisation/microvm.nix b/modules/services/virtualisation/microvm.nix new file mode 100644 index 0000000..e6cbb43 --- /dev/null +++ b/modules/services/virtualisation/microvm.nix @@ -0,0 +1,43 @@ +{ inputs, ... }: +let + inherit (inputs.nixpkgs) lib; +in +{ + imports = [ inputs.microvm.nixosModules.host ]; + + config = { + networking = { + useNetworkd = lib.mkDefault true; + + nat = { + enable = lib.mkDefault true; + enableIPv6 = lib.mkDefault true; + internalInterfaces = [ "microvm" ]; + }; + }; + + systemd.network = { + enable = true; + + netdevs."10-microvm".netdevConfig = { + Kind = "bridge"; + Name = "microvm"; + }; + + networks = { + "10-microvm" = { + matchConfig.Name = "microvm"; + networkConfig = { + DHCPServer = lib.mkDefault true; + IPv6SendRA = lib.mkDefault true; + }; + }; + + "11-microvm" = { + matchConfig.Name = "vm-*"; + networkConfig.Bridge = "microvm"; + }; + }; + }; + }; +} diff --git a/modules/services/web/nginx.nix b/modules/services/web/nginx.nix new file mode 100644 index 0000000..39526ad --- /dev/null +++ b/modules/services/web/nginx.nix @@ -0,0 +1,40 @@ +{ inputs, pkgs, config, lib, ... }: +{ + imports = with inputs; [ + srvos.nixosModules.mixins-nginx + ]; + + services = { + nginx = { + enable = true; + package = pkgs.nginxQuic; + statusPage = true; + clientMaxBodySize = "4096m"; + commonHttpConfig = '' + map $scheme $hsts_header { + https "max-age=31536000; includeSubdomains"; + } + + add_header Strict-Transport-Security $hsts_header; + + proxy_headers_hash_max_size 1024; + proxy_headers_hash_bucket_size 128; + ''; + }; + + prometheus.exporters.nginx.enable = true; + telegraf.extraConfig.inputs.nginx.urls = [ "http://localhost/nginx_status" ]; + }; + + systemd.services.nginx = { + requires = lib.optionals config.services.resolved.enable [ + "systemd-resolved.service" + ]; + after = lib.optionals config.services.resolved.enable [ + "network.target" + "systemd-resolved.service" + ]; + }; + + networking.firewall.allowedUDPPorts = [ 80 443 ]; +} diff --git a/modules/users/default.nix b/modules/users/default.nix new file mode 100644 index 0000000..2f9d4e5 --- /dev/null +++ b/modules/users/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./system/root + ./system/automat + ./system/service.nix + ./personal/crstl + ]; +} diff --git a/modules/users/personal/crstl/browser/chromium.nix b/modules/users/personal/crstl/browser/chromium.nix new file mode 100644 index 0000000..5ea46d4 --- /dev/null +++ b/modules/users/personal/crstl/browser/chromium.nix @@ -0,0 +1,17 @@ +{ pkgs, ... }: +{ + programs.chromium = { + enable = true; + package = pkgs.ungoogled-chromium; + commandLineArgs = [ + # https://github.com/ungoogled-software/ungoogled-chromium/blob/master/docs/flags.md + "--enable-logging=stderr" + "--no-service-autorun" + "--password-store=gnome" + ]; + dictionaries = with pkgs.hunspellDictsChromium; [ + en_US + de_DE + ]; + }; +} diff --git a/modules/users/personal/crstl/browser/firefox.nix b/modules/users/personal/crstl/browser/firefox.nix new file mode 100644 index 0000000..e06d0f0 --- /dev/null +++ b/modules/users/personal/crstl/browser/firefox.nix @@ -0,0 +1,242 @@ +{ lib, pkgs, ... }: +let + package = pkgs.firefox-wayland; +in +{ + programs.firefox = { + enable = true; + inherit package; + profiles = { + default = { + isDefault = true; + + settings = { + # https://kb.mozillazine.org/About:config_entries + "app.update.auto" = false; + "browser.newtab.url" = "about:blank"; + "browser.newtabpage.activity-stream.feeds.telemetry" = false; + "browser.newtabpage.activity-stream.section.highlights.includePocket" = false; + "browser.newtabpage.activity-stream.telemetry" = false; + "browser.newtabpage.pinned" = [ + { + title = "NixOS"; + url = "https://nixos.org"; + } + ]; + "browser.ping-centre.telemetry" = false; + "browser.search.isUS" = false; + "browser.search.region" = "DE"; + "browser.shell.checkDefaultBrowser" = false; + "browser.startup.homepage" = "about:blank"; + "browser.uidensity" = 0; + "distribution.searchplugins.defaultLocale" = "en-GB"; + "dom.security.https_only_mode_ever_enabled" = true; + "dom.security.https_only_mode" = true; + "experiments.activeExperiment" = false; + "experiments.enabled" = false; + "experiments.supported" = false; + "extensions.pocket.api" = ""; + "extensions.pocket.enabled" = false; + "extensions.pocket.oAuthConsumerKey" = ""; + "extensions.pocket.showHome" = false; + "extensions.pocket.site" = ""; + "general.smoothScroll" = true; + "general.useragent.locale" = "en-GB"; + "gnomeTheme.normalWidthTabs" = true; + "gnomeTheme.tabsAsHeaderbar" = true; + "network.allow-experiments" = false; + "policies.PasswordManagerEnabled" = true; + "privacy.donottrackheader.enabled" = true; + "privacy.partition.network_state.ocsp_cache" = true; + "privacy.resistFingerprinting" = false; + "privacy.trackingprotection.enabled" = true; + "privacy.trackingprotection.socialtracking.enabled" = true; + "signon.rememberSignons" = false; + "svg.content-properties.content.enabled" = true; + "svg.context-properties.content.enabled" = true; + "toolkit.legacyUserProfileCustomizations.stylesheets" = true; + "toolkit.telemetry.archive.enabled" = false; + "toolkit.telemetry.bhrPing.enabled" = false; + "toolkit.telemetry.enabled" = false; + "toolkit.telemetry.firstShutdownPing.enabled" = false; + "toolkit.telemetry.hybridContent.enabled" = false; + "toolkit.telemetry.newProfilePing.enabled" = false; + "toolkit.telemetry.reportingpolicy.firstRun" = false; + "toolkit.telemetry.shutdownPingSender.enabled" = false; + "toolkit.telemetry.unified" = false; + "toolkit.telemetry.updatePing.enabled" = false; + "webgl.disabled" = true; + }; + + extraConfig = '' + user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true); + user_pref("full-screen-api.ignore-widgets", true); + user_pref("media.ffmpeg.vaapi.enabled", true); + user_pref("media.rdd-vpx.enabled", true); + ''; + + search = { + force = true; + default = "Google"; + engines = { + "NixOS Options" = { + urls = [{ + template = "https://search.nixos.org/options"; + params = [ + { + name = "type"; + value = "options"; + } + { + name = "query"; + value = "{searchTerms}"; + } + ]; + }]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = [ "@no" ]; + }; + + "NixOS Wiki" = { + urls = [{ template = "https://nixos.wiki/index.php?search={searchTerms}"; }]; + iconUpdateURL = "https://nixos.wiki/favicon.png"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "@nw" ]; + }; + + "Nix Home Options" = { + urls = [{ + template = "https://mipmip.github.io/home-manager-option-search"; + params = [ + { + name = "type"; + value = "options"; + } + { + name = "query"; + value = "{searchTerms}"; + } + ]; + }]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = [ "@nh" ]; + }; + + "Nix Packages" = { + urls = [{ + template = "https://search.nixos.org/packages"; + params = [ + { + name = "type"; + value = "packages"; + } + { + name = "query"; + value = "{searchTerms}"; + } + ]; + }]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + definedAliases = [ "@np" ]; + }; + + "Nix Reference Manual" = { + urls = [{ template = "https://nixos.org/manual/nix/stable/?search={searchTerms}"; }]; + iconUpdateURL = "https://nixos.wiki/favicon.png"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "@nm" ]; + }; + + "OpenWRT Packages" = { + urls = [{ template = "https://openwrt.org/packages/pkgdata/{searchTerms}"; }]; + iconUpdateURL = "https://openwrt.org/_media/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "@ow" ]; + }; + + "OpenWRT Wiki" = { + urls = [{ template = "https://openwrt.org/de/start?do=search&q={searchTerms}"; }]; + iconUpdateURL = "https://openwrt.org/_media/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "@ow" ]; + }; + + "Zephyr Documentation" = { + urls = [{ template = "https://docs.zephyrproject.org/latest/search.html?q={searchTerms}"; }]; + iconUpdateURL = "https://zephyrproject.org/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "@zd" ]; + }; + + "Zephyr Config" = { + urls = [{ + template = "https://docs.zephyrproject.org/latest/kconfig.html?type=kconfig&query={searchTerms}"; + }]; + iconUpdateURL = "https://zephyrproject.org/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "@zc" ]; + }; + + "Docker Image" = { + urls = [{ template = "https://hub.docker.com/search?q={searchTerms}"; }]; + iconUpdateURL = "https://hub.docker.com/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "@di" ]; + }; + + "Python Package" = { + urls = [{ template = "https://pypi.org/search/?q={searchTerms}"; }]; + iconUpdateURL = "https://pypi.org/favicon.ico"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "@pip" ]; + }; + + "Rust Crates" = { + urls = [{ template = "https://crates.io/search?q={searchTerms}"; }]; + iconUpdateURL = "https://www.rust-lang.org/static/images/favicon-32x32.png"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "@rc" ]; + }; + + "Rust Book" = { + urls = [{ template = "https://doc.rust-lang.org/beta/book/index.html?search={searchTerms}"; }]; + iconUpdateURL = "https://www.rust-lang.org/static/images/favicon-32x32.png"; + updateInterval = 24 * 60 * 60 * 1000; + definedAliases = [ "@rb" ]; + }; + }; + }; + + # extensions = with firefox-addons.packages; [ + # block-origin + # bitwarden + # gopass-bridge + # react-devtools + # I-still-dont-care-about-cookies + # # dnssec + # # kde_connect + # ponsorblock + # arkreader + # ridactyl + # outube-shorts-block + # ]; + }; + }; + }; + + xdg.mimeApps = { + enable = true; + defaultApplications = { + "application/xhtml+xml" = "firefox.desktop"; + "text/html" = "firefox.desktop"; + "text/xml" = "firefox.desktop"; + "x-scheme-handler/ftp" = "firefox.desktop"; + "x-scheme-handler/http" = "firefox.desktop"; + "x-scheme-handler/https" = "firefox.desktop"; + "x-scheme-handler/about" = "firefox.desktop"; + "x-scheme-handler/unknown" = "firefox.desktop"; + }; + }; + + home.sessionVariables.BROWSER = "${lib.getExe package}"; +} diff --git a/modules/users/personal/crstl/cad/cadquery.nix b/modules/users/personal/crstl/cad/cadquery.nix new file mode 100644 index 0000000..5821b32 --- /dev/null +++ b/modules/users/personal/crstl/cad/cadquery.nix @@ -0,0 +1,4 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ cq-editor ]; +} diff --git a/modules/users/personal/crstl/cad/default.nix b/modules/users/personal/crstl/cad/default.nix new file mode 100644 index 0000000..de0f57a --- /dev/null +++ b/modules/users/personal/crstl/cad/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + # ./cadquery.nix + # ./kicad.nix + ./openscad.nix + ./slicer.nix + ]; +} diff --git a/modules/users/personal/crstl/cad/kicad.nix b/modules/users/personal/crstl/cad/kicad.nix new file mode 100644 index 0000000..52d633a --- /dev/null +++ b/modules/users/personal/crstl/cad/kicad.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ + kicad + # kikit + # kicadAddons.kikit + # kicadAddons.kikit-library + ]; +} diff --git a/modules/users/personal/crstl/cad/openscad.nix b/modules/users/personal/crstl/cad/openscad.nix new file mode 100644 index 0000000..c6ea9f9 --- /dev/null +++ b/modules/users/personal/crstl/cad/openscad.nix @@ -0,0 +1,12 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ + openscad + openscad-lsp + sca2d + ]; + + programs.vscode.extensions = with pkgs.vscode-extensions; [ + antyos.openscad + ]; +} diff --git a/modules/users/personal/crstl/cad/slicer.nix b/modules/users/personal/crstl/cad/slicer.nix new file mode 100644 index 0000000..d292706 --- /dev/null +++ b/modules/users/personal/crstl/cad/slicer.nix @@ -0,0 +1,7 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ + orca-slicer + super-slicer-latest + ]; +} diff --git a/modules/users/personal/crstl/chat/default.nix b/modules/users/personal/crstl/chat/default.nix new file mode 100644 index 0000000..7d83532 --- /dev/null +++ b/modules/users/personal/crstl/chat/default.nix @@ -0,0 +1,11 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ + jitsi-meet-electron + signal-desktop + element-desktop + telegram-desktop + nheko + slack + ]; +} diff --git a/modules/users/personal/crstl/default.nix b/modules/users/personal/crstl/default.nix new file mode 100644 index 0000000..f06c541 --- /dev/null +++ b/modules/users/personal/crstl/default.nix @@ -0,0 +1,111 @@ +{ lib, pkgs, config, ... }: +{ + age.secrets.crstlPassword.file = ./password.age; + + users = { + groups.crstl.gid = config.users.users.crstl.uid; + users.crstl = { + uid = 1000; + isNormalUser = true; + description = "Sebastian Wendel"; + createHome = true; + group = "crstl"; + extraGroups = + [ "users" "wheel" "dialout" ] + ++ lib.optionals config.hardware.i2c.enable [ "i2c" ] + ++ lib.optionals config.networking.networkmanager.enable [ "networkmanager" ] + ++ lib.optionals config.programs.sway.enable [ "input" "video" ] + ++ lib.optionals config.programs.wireshark.enable [ "wireshark" ] + ++ lib.optionals config.sound.enable [ "audio" ] + ++ lib.optionals config.services.unbound.enable [ "unbound" ] + ++ lib.optionals config.services.paperless.enable [ "paperless" ] + ++ lib.optionals config.virtualisation.libvirtd.enable [ "libvirtd" "qemu-libvirtd" ] + ++ lib.optionals config.virtualisation.docker.enable [ "docker" ] + ++ lib.optionals config.virtualisation.podman.enable [ "podman" ]; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKwyxpc0pVB46j1k5VCSabvI4TUADvAabnxlE5+D5o2l" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB6vk3k1p6YMsGLFQ/xABLYK/VJicywkf1MJawnN7oXU" + ]; + shell = lib.mkIf config.programs.zsh.enable pkgs.zsh; + hashedPasswordFile = config.age.secrets.crstlPassword.path; + }; + }; + + nix.settings.trusted-users = [ "crstl" ]; + + home-manager.users.crstl = { + imports = [ + ./terminal/ssh.nix + ./terminal/tmux.nix + ./terminal/kitty.nix + ./terminal/zsh.nix + ./terminal/htop.nix + ./terminal/nix-index.nix + ./terminal/dircolors.nix + ./terminal/bat.nix + ./terminal/starship.nix + ./terminal/lsd.nix + ./terminal/ripgrep.nix + ./editor/neovim.nix + ] ++ lib.optionals config.services.xserver.enable [ + ./gpg + ./terminal/git.nix + ./terminal/imv.nix + ./terminal/jq.nix + ./terminal/lf.nix + ./terminal/rbw.nix + ./terminal/thefuck.nix + ./terminal/yazi.nix + ./terminal/zoxide.nix + ./terminal/awscli.nix + ./system/home-manager.nix + ./system/gtk.nix + ./system/qt.nix + ./system/xdg.nix + ./system/gammastep.nix + ./system/kanshi.nix + ./system/stylix.nix + ./desktop-manager/dconf.nix + ./desktop-manager/blueman-applet.nix + ./desktop-manager/gnome-keyring.nix + ./desktop-manager/kdeconnect.nix + ./desktop-manager/nextcloud-client.nix + ./window-manager/dunst.nix + ./window-manager/rofi.nix + ./window-manager/sway.nix + ./window-manager/swayidle.nix + ./window-manager/waybar.nix + ./browser/firefox.nix + ./browser/chromium.nix + ./chat/default.nix + ./editor/emacs.nix + ./editor/helix.nix + ./editor/vscodium.nix + ./media/mpd.nix + ./media/mpv.nix + ./office/pass.nix + ./packages.nix + ./cad + ]; + + home = { + username = config.users.users.crstl.name; + stateVersion = "22.05"; + shellAliases = { + x = "${pkgs.yt-dlp}/bin/yt-dlp"; + vip = "${pkgs.curl}/bin/curl -s https://am.i.mullvad.net/json | jq"; + mip = "${pkgs.dnsutils}/bin/dig +short myip.opendns.com @208.67.222.222 2>&1"; + tp = "${pkgs.libressl}/bin/nc termbin.com 9999"; + }; + }; + + services.gammastep = { + inherit (config.location) latitude longitude; + }; + + programs = { + obs-studio.enable = lib.mkIf config.services.xserver.enable true; + freetube.enable = lib.mkIf config.services.xserver.enable true; + }; + }; +} diff --git a/modules/users/personal/crstl/desktop-manager/blueman-applet.nix b/modules/users/personal/crstl/desktop-manager/blueman-applet.nix new file mode 100644 index 0000000..061d1c4 --- /dev/null +++ b/modules/users/personal/crstl/desktop-manager/blueman-applet.nix @@ -0,0 +1 @@ +{ services.blueman-applet.enable = true; } diff --git a/modules/users/personal/crstl/desktop-manager/dconf.nix b/modules/users/personal/crstl/desktop-manager/dconf.nix new file mode 100644 index 0000000..2e6de02 --- /dev/null +++ b/modules/users/personal/crstl/desktop-manager/dconf.nix @@ -0,0 +1,103 @@ +{ + dconf.settings = { + "org/gnome/mutter" = { + attach-modal-dialogs = false; + dynamic-workspaces = true; + edge-tiling = false; + focus-change-on-pointer-rest = true; + workspaces-only-on-primary = false; + experimental-features = [ "scale-monitor-framebuffer" ]; + }; + + "org/gnome/desktop/interface" = { + clock-show-date = true; + clock-show-seconds = false; + clock-show-weekday = true; + enable-animations = true; + enable-hot-corners = true; + font-antialiasing = "grayscale"; + font-hinting = "slight"; + gtk-im-module = "ibus"; + locate-pointer = false; + show-battery-percentage = true; + toolkit-accessibility = false; + }; + + "org/gnome/desktop/search-providers" = { + disabled = [ "org.gnome.Eolie.desktop" ]; + enabled = [ "org.gnome.Weather.desktop" ]; + sort-order = [ + "org.gnome.Contacts.desktop" + "org.gnome.Documents.desktop" + "org.gnome.Nautilus.desktop" + ]; + }; + + "org/gnome/desktop/sound" = { + allow-volume-above-100-percent = false; + event-sounds = true; + }; + + "org/gnome/desktop/wm/preferences" = { + action-double-click-titlebar = "toggle-maximize"; + button-layout = "appmenu:close"; + workspace-names = [ + "Workspace 5" + "Workspace 2" + "Workspace 4" + "Workspace 1" + "Workspace 8" + "Workspace 8" + "Workspace 8" + "Workspace 8" + "Workspace 8" + ]; + }; + + "org/gnome/gnome-system-monitor" = { + network-total-in-bits = false; + show-dependencies = false; + show-whose-processes = "user"; + }; + + "org/gnome/settings-daemon/plugins/color" = { + night-light-enabled = true; + night-light-schedule-automatic = true; + night-light-schedule-to = 20.0; + night-light-temperature = "uint32 2883"; + }; + + "org/gnome/settings-daemon/plugins/power" = { + idle-dim = true; + power-button-action = "suspend"; + sleep-inactive-ac-type = "nothing"; + sleep-inactive-battery-timeout = 1200; + sleep-inactive-battery-type = "suspend"; + }; + + "org/gnome/shell/extensions/paperwm" = { + disable-scratch-in-overview = true; + override-hot-corner = false; + }; + + "org/gnome/shell/extensions/paperwm/keybindings" = { + close-window = [ "x" ]; + move-down-workspace = [ "m" ]; + move-up-workspace = [ "n" ]; + new-window = [ "Return" ]; + switch-down = [ "j" ]; + switch-down-workspace = [ "m" ]; + switch-left = [ "h" ]; + switch-right = [ "l" ]; + switch-up = [ "k" ]; + switch-up-workspace = [ "n" ]; + toggle-scratch = [ "Escape" ]; + toggle-scratch-layer = [ "Escape" ]; + toggle-scratch-window = [ ]; + }; + + "org/gnome/system/location" = { + enabled = true; + }; + }; +} diff --git a/modules/users/personal/crstl/desktop-manager/gnome-keyring.nix b/modules/users/personal/crstl/desktop-manager/gnome-keyring.nix new file mode 100644 index 0000000..c29c5f4 --- /dev/null +++ b/modules/users/personal/crstl/desktop-manager/gnome-keyring.nix @@ -0,0 +1,10 @@ +{ + services.gnome-keyring = { + enable = true; + components = [ + "pkcs11" + "secrets" + "ssh" + ]; + }; +} diff --git a/modules/users/personal/crstl/desktop-manager/kdeconnect.nix b/modules/users/personal/crstl/desktop-manager/kdeconnect.nix new file mode 100644 index 0000000..544c162 --- /dev/null +++ b/modules/users/personal/crstl/desktop-manager/kdeconnect.nix @@ -0,0 +1,6 @@ +{ + services.kdeconnect = { + enable = true; + indicator = true; + }; +} diff --git a/modules/users/personal/crstl/desktop-manager/nextcloud-client.nix b/modules/users/personal/crstl/desktop-manager/nextcloud-client.nix new file mode 100644 index 0000000..df49e98 --- /dev/null +++ b/modules/users/personal/crstl/desktop-manager/nextcloud-client.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ + libgnome-keyring + nextcloud-client + ]; + + services.nextcloud-client.enable = true; +} diff --git a/modules/users/personal/crstl/editor/emacs.nix b/modules/users/personal/crstl/editor/emacs.nix new file mode 100644 index 0000000..8619502 --- /dev/null +++ b/modules/users/personal/crstl/editor/emacs.nix @@ -0,0 +1,389 @@ +{ pkgs, config, ... }: +{ + services.emacs = { + enable = true; + package = pkgs.emacs29-nox; + # defaultEditor = true; + socketActivation.enable = true; + client.enable = true; + }; + + programs.emacs = { + enable = true; + inherit (config.services.emacs) package; + extraConfig = '' + (setq standard-indent 2) + (setq visible-bell t) + + ;; Initialize package sources + (require 'package) + (setq package-archives '(("melpa" . "https://melpa.org/packages/") + ("org" . "https://orgmode.org/elpa/") + ("elpa" . "https://elpa.gnu.org/packages/"))) + (package-initialize) + (unless package-archive-contents + (package-refresh-contents)) + + ;; Initialize use-package on non-Linux platforms + (unless (package-installed-p 'use-package) + (package-install 'use-package)) + + (require 'use-package) + (setq use-package-always-ensure t) + + (column-number-mode) + (global-display-line-numbers-mode t) + + (load-theme 'modus-vivendi t) + + (setq modus-themes-mode-line '(borderless accented)) + (setq modus-themes-region '(accented)) + + ;;(setq modus-themes-italic-constructs t + ;; modus-themes-bold-constructs nil + ;; modus-themes-mixed-fonts t + ;; modus-themes-variable-pitch-ui nil + ;; modus-themes-custom-auto-reload t + ;; modus-themes-disable-other-themes t + + ;; ;; Options for `modus-themes-prompts' are either nil (the + ;; ;; default), or a list of properties that may include any of those + ;; ;; symbols: `italic', `WEIGHT' + ;; modus-themes-prompts '(italic bold) + + ;; ;; The `modus-themes-completions' is an alist that reads two + ;; ;; keys: `matches', `selection'. Each accepts a nil value (or + ;; ;; empty list) or a list of properties that can include any of + ;; ;; the following (for WEIGHT read further below): + ;; ;; + ;; ;; `matches' :: `underline', `italic', `WEIGHT' + ;; ;; `selection' :: `underline', `italic', `WEIGHT' + ;; modus-themes-completions + ;; '((matches . (extrabold)) + ;; (selection . (semibold italic text-also))) + + ;; modus-themes-org-blocks 'gray-background ; {nil,'gray-background,'tinted-background} + + ;; ;; The `modus-themes-headings' is an alist: read the manual's + ;; ;; node about it or its doc string. Basically, it supports + ;; ;; per-level configurations for the optional use of + ;; ;; `variable-pitch' typography, a height value as a multiple of + ;; ;; the base font size (e.g. 1.5), and a `WEIGHT'. + ;; modus-themes-headings + ;; '((1 . (variable-pitch 1.5)) + ;; (2 . (1.3)) + ;; (agenda-date . (1.3)) + ;; (agenda-structure . (variable-pitch light 1.8)) + ;; (t . (1.1)))) + + (use-package doom-modeline + :init (doom-modeline-mode 1) + :custom ((doom-modeline-height 15))) + + (use-package rainbow-delimiters + :hook (prog-mode . rainbow-delimiters-mode)) + + (use-package which-key + :init (which-key-mode) + :diminish which-key-mode + :config + (setq which-key-idle-delay 1)) + + (use-package all-the-icons) + + (use-package nerd-icons) + + (use-package nix-mode + :mode "\\.nix\\'") + + (use-package org + :hook (org-mode . efs/org-mode-setup) + :config + (setq org-ellipsis " ▾") + (efs/org-font-setup)) + + (use-package lsp-mode + :init + (setq lsp-keymap-prefix "C-c l") + :hook ( + (python-mode . lsp) + (python-mode . dap-mode) + (python-mode . dap-ui-mode) + (lsp-mode . lsp-enable-which-key-integration)) + :commands lsp) + + (use-package helm-lsp :commands helm-lsp-workspace-symbol) + (use-package lsp-ivy :commands lsp-ivy-workspace-symbol) + (use-package lsp-treemacs :commands lsp-treemacs-errors-list) + + (use-package python-black + :demand t + :after python + :hook (python-mode . python-black-on-save-mode-enable-dwim)) + + (add-hook 'python-mode-hook 'python-isort-on-save-mode) + + (use-package python-pytest) + + (use-package dap-mode + :config + (dap-ui-mode 1) + (require 'dap-node)) + + (use-package docker) + + (use-package helm :config (require 'helm-autoloads)) + + (use-package treemacs + :ensure t + :defer t + :init + ;;(with-eval-after-load 'winum + ;; (define-key winum-keymap (kbd "M-0") #'treemacs-select-window)) + ;;:config + ;;(progn + ;; (setq treemacs-collapse-dirs (if treemacs-python-executable 3 0) + ;; treemacs-deferred-git-apply-delay 0.5 + ;; treemacs-directory-name-transformer #'identity + ;; treemacs-display-in-side-window t + ;; treemacs-eldoc-display 'simple + ;; treemacs-file-event-delay 2000 + ;; treemacs-file-extension-regex treemacs-last-period-regex-value + ;; treemacs-file-follow-delay 0.2 + ;; treemacs-file-name-transformer #'identity + ;; treemacs-follow-after-init t + ;; treemacs-expand-after-init t + ;; treemacs-find-workspace-method 'find-for-file-or-pick-first + ;; treemacs-git-command-pipe "" + ;; treemacs-goto-tag-strategy 'refetch-index + ;; treemacs-header-scroll-indicators '(nil . "^^^^^^") + ;; treemacs-hide-dot-git-directory t + ;; treemacs-indentation 2 + ;; treemacs-indentation-string " " + ;; treemacs-is-never-other-window nil + ;; treemacs-max-git-entries 5000 + ;; treemacs-missing-project-action 'ask + ;; treemacs-move-forward-on-expand nil + ;; treemacs-no-png-images nil + ;; treemacs-no-delete-other-windows t + ;; treemacs-project-follow-cleanup nil + ;; treemacs-persist-file (expand-file-name ".cache/treemacs-persist" user-emacs-directory) + ;; treemacs-position 'left + ;; treemacs-read-string-input 'from-child-frame + ;; treemacs-recenter-distance 0.1 + ;; treemacs-recenter-after-file-follow nil + ;; treemacs-recenter-after-tag-follow nil + ;; treemacs-recenter-after-project-jump 'always + ;; treemacs-recenter-after-project-expand 'on-distance + ;; treemacs-litter-directories '("/node_modules" "/.venv" "/.cask") + ;; treemacs-project-follow-into-home nil + ;; treemacs-show-cursor nil + ;; treemacs-show-hidden-files t + ;; treemacs-silent-filewatch nil + ;; treemacs-silent-refresh nil + ;; treemacs-sorting 'alphabetic-asc + ;; treemacs-select-when-already-in-treemacs 'move-back + ;; treemacs-space-between-root-nodes t + ;; treemacs-tag-follow-cleanup t + ;; treemacs-tag-follow-delay 1.5 + ;; treemacs-text-scale nil + ;; treemacs-user-mode-line-format nil + ;; treemacs-user-header-line-format nil + ;; treemacs-wide-toggle-width 70 + ;; treemacs-width 35 + ;; treemacs-width-increment 1 + ;; treemacs-width-is-initially-locked t + ;; treemacs-workspace-switch-cleanup nil) + + ;; ;;(treemacs-resize-icons 44) + ;; (treemacs-follow-mode t) + ;; (treemacs-filewatch-mode t) + ;; (treemacs-fringe-indicator-mode 'always) + ;; (when treemacs-python-executable + ;; (treemacs-git-commit-diff-mode t)) + ;; (pcase (cons (not (null (executable-find "git"))) + ;; (not (null treemacs-python-executable))) + ;; (`(t . t) + ;; (treemacs-git-mode 'deferred)) + ;; (`(t . _) + ;; (treemacs-git-mode 'simple))) + ;; (treemacs-hide-gitignored-files-mode nil)) + ;;:bind + ;;(:map global-map + ;; ("M-0" . treemacs-select-window) + ;; ("C-x t 1" . treemacs-delete-other-windows) + ;; ("C-x t t" . treemacs) + ;; ("C-x t d" . treemacs-select-directory) + ;; ("C-x t B" . treemacs-bookmark) + ;; ("C-x t C-t" . treemacs-find-file) + ;; ("C-x t M-t" . treemacs-find-tag))) + ) + + (use-package treemacs-evil + :after (treemacs evil) + :ensure t) + + (use-package treemacs-icons-dired + :hook (dired-mode . treemacs-icons-dired-enable-once) + :ensure t) + + (use-package treemacs-magit + :after (treemacs magit) + :ensure t) + + (use-package treemacs-persp + :after (treemacs persp-mode) + :ensure t + :config (treemacs-set-scope-type 'Perspectives)) + + (use-package treemacs-tab-bar ;;treemacs-tab-bar if you use tab-bar-mode + :after (treemacs) + :ensure t + :config (treemacs-set-scope-type 'Tabs)) + + (use-package ivy + :diminish + :config + (ivy-mode 1)) + + (setq ivy-use-virtual-buffers t) + (setq enable-recursive-minibuffers t) + + (global-set-key "\C-s" 'swiper) + (global-set-key (kbd "C-c C-r") 'ivy-resume) + (global-set-key (kbd "") 'ivy-resume) + (global-set-key (kbd "M-x") 'counsel-M-x) + (global-set-key (kbd "C-x C-f") 'counsel-find-file) + (global-set-key (kbd " f") 'counsel-describe-function) + (global-set-key (kbd " v") 'counsel-describe-variable) + (global-set-key (kbd " o") 'counsel-describe-symbol) + (global-set-key (kbd " l") 'counsel-find-library) + (global-set-key (kbd " i") 'counsel-info-lookup-symbol) + (global-set-key (kbd " u") 'counsel-unicode-char) + (global-set-key (kbd "C-c g") 'counsel-git) + (global-set-key (kbd "C-c j") 'counsel-git-grep) + (global-set-key (kbd "C-c k") 'counsel-ag) + (global-set-key (kbd "C-x l") 'counsel-locate) + (global-set-key (kbd "C-S-o") 'counsel-rhythmbox) + (define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history) + + ;;(use-package ivy-rich + ;; :init + ;; (ivy-rich-mode 1)) + + (use-package evil + :init + (setq evil-want-integration t) + (setq evil-want-keybinding nil) + (setq evil-want-C-u-scroll t) + (setq evil-want-C-i-jump nil) + :config + (evil-mode 1) + (define-key evil-insert-state-map (kbd "C-g") 'evil-normal-state) + (define-key evil-insert-state-map (kbd "C-h") 'evil-delete-backward-char-and-join) + + ;; Use visual line motions even outside of visual-line-mode buffers + (evil-global-set-key 'motion "j" 'evil-next-visual-line) + (evil-global-set-key 'motion "k" 'evil-previous-visual-line) + + (evil-set-initial-state 'messages-buffer-mode 'normal) + (evil-set-initial-state 'dashboard-mode 'normal)) + + (add-hook 'c-mode-hook 'helm-cscope-mode) + (add-hook 'c++-mode-hook 'helm-cscope-mode) + (eval-after-load "helm-cscope" + '(progn + (define-key helm-cscope-mode-map (kbd "M-t") 'helm-cscope-find-symbol) + (define-key helm-cscope-mode-map (kbd "M-r") 'helm-cscope-find-global-definition) + (define-key helm-cscope-mode-map (kbd "M-g M-c") 'helm-cscope-find-called-function) + (define-key helm-cscope-mode-map (kbd "M-g M-p") 'helm-cscope-find-calling-this-funtcion) + (define-key helm-cscope-mode-map (kbd "M-s") 'helm-cscope-select))) + + ;;(add-hook 'prog-mode-hook 'display-line-numbers-mode) + + (menu-bar-mode -1) + (lsp-treemacs-sync-mode 1) + + (global-tree-sitter-mode) + (global-set-key (kbd "") 'keyboard-escape-quit) + ''; + extraPackages = + epkgs: with epkgs; [ + all-the-icons + dap-mode + docker + docker-api + docker-cli + docker-compose-mode + doom-modeline + evil + helm + helm-codesearch + helm-dictionary + helm-directory + # helm-dired-history + helm-dired-recent-dirs + helm-firefox + helm-git + helm-git-grep + helm-gitignore + helm-google + helm-ispell + helm-ls-git + helm-lsp + helm-make + helm-nixos-options + helm-org + helm-pass + helm-proc + helm-pydoc + helm-shell-history + helm-systemd + helm-tree-sitter + helm-wikipedia + helm-xref + ivy + ivy-clipmenu + ivy-emoji + ivy-explorer + ivy-file-preview + ivy-fuz + ivy-historian + ivy-hydra + ivy-pass + ivy-rich + ivy-searcher + ivy-todo + ivy-xref + ivy-youtube + lsp-docker + lsp-ivy + lsp-mode + swiper + lsp-pyright + lsp-treemacs + nerd-icons + nix-mode + org + org-modern + python-black + python-isort + python-mode + python-pytest + rainbow-delimiters + treemacs + treemacs-all-the-icons + treemacs-evil + treemacs-icons-dired + treemacs-magit + treemacs-nerd-icons + treemacs-persp + treemacs-tab-bar + which-key + ]; + }; + home.packages = with pkgs; [ + emacs-all-the-icons-fonts + pyright + ]; +} diff --git a/modules/users/personal/crstl/editor/helix.nix b/modules/users/personal/crstl/editor/helix.nix new file mode 100644 index 0000000..c825ecd --- /dev/null +++ b/modules/users/personal/crstl/editor/helix.nix @@ -0,0 +1,289 @@ +{ lib, pkgs, ... }: +{ + programs.helix = { + enable = true; + defaultEditor = true; + + extraPackages = with pkgs; [ + ansible-language-server + clang-tools + delve + gitFull + go + gopls + jsonnet-language-server + lldb + lua-language-server + marksman + nil + nodePackages.bash-language-server + openscad-lsp + python3Packages.pylsp-mypy + python3Packages.pylsp-rope + python3Packages.python-lsp-server + taplo + terraform-ls + vscode-langservers-extracted + yaml-language-server + ]; + + settings = { + editor = { + shell = [ "zsh" "-c" ]; + line-number = "relative"; + rulers = [ 80 120 ]; + + gutters = [ + "diagnostics" + "line-numbers" + "spacer" + "diff" + ]; + + auto-format = true; + auto-info = true; + + completion-replace = true; + completion-trigger-len = 1; + + idle-timeout = 200; + true-color = true; + + bufferline = "always"; + color-modes = true; + + cursorline = true; + cursor-shape = { + normal = "block"; + insert = "bar"; + select = "underline"; + }; + + statusline = { + left = [ + "mode" + "selections" + "spinner" + "file-name" + "total-line-numbers" + ]; + center = [ ]; + right = [ + "diagnostics" + "file-encoding" + "file-line-ending" + "file-type" + "position-percentage" + "position" + ]; + mode = { + normal = "N "; + insert = " INS"; + select = "SELECT"; + }; + separator = ""; + }; + + lsp.display-messages = true; + }; + + keys.normal = { + space = { + space = "file_picker"; + w = ":w"; + q = ":q"; + }; + esc = [ + "collapse_selection" + "keep_primary_selection" + ]; + }; + }; + + languages = { + language = + let + nodeLsp = [ + { + name = "typescript"; + except-features = [ "format" ]; + } + { + name = "prettier"; + only-features = [ "format" ]; + } + "eslint" + ]; + in + [ + { + name = "bash"; + auto-format = true; + file-types = [ + "sh" + "bash" + ]; + formatter = { + command = "${pkgs.shfmt}/bin/shfmt"; + args = [ + "-i 4" # indent with 2 spaces + "-s" # simplify the code + "-ci" # indent switch cases + "-sr" # add space after redirection + ]; + }; + language-servers = [ "bash" ]; + } + { + name = "typescript"; + language-servers = nodeLsp; + } + { + name = "javascript"; + language-servers = nodeLsp; + } + { + name = "jsx"; + language-servers = nodeLsp; + } + { + name = "tsx"; + language-servers = nodeLsp; + } + { + name = "sql"; + formatter.command = "${pkgs.pgformatter}/bin/pg_format"; + } + { + name = "nix"; + auto-format = true; + formatter.command = "${pkgs.alejandra}/bin/alejandra"; + language-servers = [ "nil" ]; + } + { + name = "go"; + auto-format = true; + formatter.command = "${pkgs.go}/bin/gofmt"; + language-servers = [ "go" ]; + } + { + name = "rust"; + auto-format = true; + language-servers = [ "rust-analyzer" ]; + file-types = [ "rs" ]; + } + { + name = "xml"; + file-types = [ "xml" ]; + formatter = { + command = "${pkgs.yq-go}/bin/yq"; + args = [ + "--input-format" + "xml" + "--output-format" + "xml" + "--indent" + "2" + ]; + }; + } + ]; + + language-server = { + # check: hx --health [LANG] + + bash = with pkgs.nodePackages; { + command = "${bash-language-server}/bin/bash-language-server"; + args = [ "start" ]; + }; + + go = { + command = "${pkgs.gopls}/bin/gopls"; + }; + + nil = { + command = "${pkgs.nil}/bin/nil"; + config.nil = { + formatter.command = "${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt"; + nix.flake.autoEvalInputs = true; + }; + }; + + rust-analyzer = { + config.rust-analyzer = { + cargo.loadOutDirsFromCheck = true; + checkOnSave.command = "clippy"; + procMacro.enable = true; + + lens = { + references = true; + methodReferences = true; + }; + + completion.autoimport.enable = true; + experimental.procAttrMacros = true; + }; + }; + + typescript = with pkgs.nodePackages; { + command = "${typescript-language-server}/bin/typescript-language-server"; + args = [ + "--stdio" + "--tsserver-path=${typescript}/lib/node_modules/typescript/lib" + ]; + }; + + prettier = with pkgs; { + command = "${efm-langserver}/bin/efm-langserver"; + config = { + documentFormatting = true; + languages = + lib.genAttrs + [ + "typescript" + "javascript" + "typescriptreact" + "javascriptreact" + "vue" + "json" + "markdown" + ] + (_: [ + { + formatCommand = "${nodePackages.prettier}/bin/prettier --stdin-filepath \${INPUT}"; + formatStdin = true; + } + ]); + }; + }; + + eslint = with pkgs.nodePackages; { + command = "${eslint}/bin/eslint"; + args = [ "--stdio" ]; + config = { + validate = "on"; + packageManager = "yarn"; + useESLintClass = false; + codeActionOnSave.mode = "all"; + format = true; + quiet = false; + onIgnoredFiles = "off"; + rulesCustomizations = [ ]; + run = "onType"; + nodePath = ""; + workingDirectory.mode = "auto"; + experimental = { }; + problems.shortenToSingleLine = false; + codeAction = { + disableRuleComment = { + enable = true; + location = "separateLine"; + }; + showDocumentation.enable = true; + }; + }; + }; + }; + }; + }; +} diff --git a/modules/users/personal/crstl/editor/neovim.nix b/modules/users/personal/crstl/editor/neovim.nix new file mode 100644 index 0000000..13646e4 --- /dev/null +++ b/modules/users/personal/crstl/editor/neovim.nix @@ -0,0 +1,548 @@ +{ pkgs, config, ... }: +{ + programs.neovim = { + enable = true; + + viAlias = true; + vimAlias = true; + vimdiffAlias = true; + + # withNodeJs = lib.mkIf config.services.xserver.enable true; + # withPython3 = lib.mkIf config.services.xserver.enable true; + withRuby = false; + + extraPackages = [ + pkgs.git + pkgs.nil + # ] + # ++ lib.optionals config.services.xserver.enable + # [ + # tree-sitter + pkgs.bat + pkgs.clang + pkgs.delta + pkgs.elmPackages.elm-language-server + pkgs.fzf + pkgs.haskell-language-server + pkgs.luaPackages.lua-lsp + # pkgs.nodePackages.pyright + pkgs.nodePackages.typescript + pkgs.nodePackages.typescript-language-server + pkgs.ripgrep + pkgs.silver-searcher + # sumneko-lua-language-server + ]; + + # config = lib.mkIf cfg.enable { + # # Clear the /tmp directory when the system is rebooted + # boot.cleanTmpDir = lib.mkDefault true; + + # profiles.preferences.customizedVimPlugins = + # pkgs.vimPlugins + # // (with pkgs.vimPlugins; { + # # Code editing: Comment and uncomment + # vim-commentary = { + # plugin = vim-commentary; + # }; + + # # Programming language integrations: Language servers + # nvim-lspconfig = { + # plugin = nvim-lspconfig; + # type = "lua"; + # # plugin = nvim-lspconfig.overrideAttrs (oldAttrs: { + # # dependencies = (old.dependencies or [ ]) ++ [ + # # # lsp_extensions-nvim + # # # lsp_signature-nvim + # # # lua-dev-nvim + # # # SchemaStore-nvim + # # ]; + # # }); + # config = '' + # loadfile('${./neovim/plugins/lspconfig.lua}')() + # ''; + # }; + + # # Code editing: Auto-completion + # nvim-cmp = { + # plugin = nvim-cmp; + # type = "lua"; + # config = + # # Note caveats in the readme regarding native menu + # '' + # local cmp = require('cmp') + # cmp.setup({ + # snippet = { + # -- I don't use snippets but it appears to be required + # expand = function(args) + # require('luasnip').lsp_expand(args.body) + # end, + # }, + # mapping = cmp.mapping.preset.insert({ + # -- Accept the currently selected item + # [''] = cmp.mapping.confirm({ select = true }), + # -- Force auto-completion in insert mode without first typing something + # [''] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }), + # }), + # sources = cmp.config.sources({ + # -- Listed in order of preference + # { name = 'nvim_lua' }, + # { name = 'nvim_lsp' }, + # { name = 'luasnip' }, + # { name = 'buffer' }, + # }) + # }) + # vim.opt.completeopt = { + # -- Show the completion menu for a single match so that documentation will always appear + # "menuone", + # -- Don't pop open documentation unless you explicitly navigate the completion menu + # "noselect", + # } + # -- Suppress command-line noise related to completions + # vim.opt.shortmess:append "c" + # ''; + # }; + + # # Code editing: Auto-completion with current buffer contents + # cmp-buffer = { + # plugin = cmp-buffer; + # type = "lua"; + # config = '' + # -- Use buffer as a completion source for search via / + # require('cmp').setup.cmdline('/', { + # sources = { + # { name = 'buffer' } + # } + # }) + # ''; + # }; + + # # Code editing: Auto-completion with language servers + # cmp-nvim-lsp = { + # plugin = cmp-nvim-lsp; + # }; + + # # Code editing: Auto-completion with nvim's lua api + # cmp-nvim-lua = { + # plugin = cmp-nvim-lua; + # }; + + # # Git support + # vim-fugitive = { + # plugin = vim-fugitive; + # }; + + # # Git support: Show changed lines in gutter (replaces gitgutter) + # gitsigns-nvim = { + # plugin = gitsigns-nvim; + # type = "lua"; + # config = '' + # loadfile('${./neovim/plugins/gitsigns.lua}')() + # ''; + # }; + + # # Nix support + # vim-nix = { + # plugin = vim-nix; + # }; + + # # Navigation: Fuzzy finder + # telescope-nvim = { + # plugin = telescope-nvim; + # type = "lua"; + # config = '' + # -- Search file names that are tracked by git + # vim.keymap.set('n', 'o', function() return require('telescope.builtin').git_files() end, { desc = "Search tracked files" }) + # -- Search file names modified relative to HEAD + # vim.keymap.set('n', 'm', function() return require('telescope.builtin').git_status() end, { desc = "Search modified files" }) + # -- Search file names + # vim.keymap.set('n', 'O', function() return require('telescope.builtin').find_files() end, { desc = "Search files" }) + # -- Search file contents + # vim.keymap.set('n', '/', function() return require('telescope.builtin').live_grep() end, { desc = "Search files contents" }) + # -- Search buffer names + # vim.keymap.set('n', 'b', function() return require('telescope.builtin').buffers() end, { desc = "Search open buffers" }) + # -- Search diagnostics in all open buffers + # vim.keymap.set('n', 'D', function() return require('telescope.builtin').diagnostics() end, { desc = "Search workspace diagnostics" }) + # -- Search diagnostics + # vim.keymap.set('n', 'd', function() return require('telescope.builtin').diagnostics({ bufnr = 0 }) end, { desc = "Search diagnostics" }) + # -- Search vim help + # vim.keymap.set('n', 'hh', function() return require('telescope.builtin').help_tags() end, { desc = "Search vim help" }) + # -- Pressing esc twice to cancel is annoying, so map to directly close the popup in insert mode + # local actions = require('telescope.actions') + # require('telescope').setup({ + # defaults = { + # mappings = { + # i = { + # [""] = actions.close, + # }, + # }, + # }, + # }) + # ''; + # }; + # telescope-fzf-native-nvim = { + # # native fzf ostensibly improves performance + # plugin = telescope-fzf-native-nvim; + # type = "lua"; + # config = '' + # require('telescope').load_extension('fzf') + # ''; + # }; + + # # Navigation: File tree + # nvim-tree-lua = { + # plugin = nvim-tree-lua; + # type = "lua"; + # config = '' + # require('nvim-tree').setup({ + # }) + # ''; + # }; + + # # Navigation: Tabline + # bufferline-nvim = { + # plugin = bufferline-nvim; + # type = "lua"; + # config = '' + # require('bufferline').setup({ + # options = { + # -- Needed because vim buffers are different from vim tab pages. + # -- This is the same as setting vim.opt.showtabline = 2. + # always_show_bufferline = true, + # }, + # }) + # ''; + # }; + + # # Aesthetics: Color scheme + # gruvbox-nvim = { + # # faster than gruvbox and gruvbox-community + # plugin = gruvbox-nvim; + # type = "lua"; + # config = '' + # vim.cmd [[colorscheme gruvbox]] + # -- TODO: move to playground + # -- "Hide" the cursor line highlight past column 80 and 120 to hint at potential text wrap. + # vim.o.colorcolumn=vim.fn.join(vim.fn.range(81,121), ',') .. vim.fn.join(vim.fn.range(121,999), ',') + # vim.api.nvim_set_hl(0, 'ColorColumn', { link = 'Normal' }) + # ''; + # }; + + # # Aesthetics: icons + # nvim-web-devicons = { + # plugin = nvim-web-devicons; + # }; + + # # Aesthetics: status/tabline + # lualine-nvim = { + # plugin = lualine-nvim.overrideAttrs (oldAttrs: { + # dependencies = + # (oldAttrs.dependencies or []) + # ++ [ + # lualine-lsp-progress + # ]; + # }); + # type = "lua"; + # config = '' + # require('lualine').setup({ + # sections = { + # lualine_a = { { 'mode', upper = true } }, + # lualine_b = { { 'branch', icon = '' } }, + # lualine_c = { + # { 'filename', file_status = true, path = 1 }, + # { 'diagnostics', sources = { 'nvim_lsp' } }, + # { 'lsp_progress' }, + # }, + # lualine_x = { 'encoding', 'filetype' }, + # lualine_y = { 'progress' }, + # lualine_z = { 'location' }, + # }, + # }) + # -- Suppress mode prefixes like "-- INSERT --" in the command-line + # vim.opt.showmode = false + # ''; + # }; + + # # Vim: key binding feedback + # which-key-nvim = { + # plugin = which-key-nvim; + # type = "lua"; + # config = '' + # require('which-key').setup({ + # }) + # ''; + # }; + + # # Vim: benchmarking + # vim-startuptime = { + # # Run with vim --startuptime + # plugin = vim-startuptime; + # }; + # }); + + # plugins = with config.profiles.preferences.customizedVimPlugins; [ + # # Programming language integrations: Language servers + # nvim-lspconfig + + # # Code editing: Comment and uncomment + # vim-commentary + + # # Code editing: Auto-completion + # nvim-cmp + + # # Code editing: Auto-completion with language servers + # cmp-nvim-lsp + + # # Code editing: Auto-completion with current buffer contents + # cmp-buffer + + # # Code editing: Auto-completion with nvim's lua api + # cmp-nvim-lua + + # # Code editing: Auto-completion with current buffer contents + # cmp-buffer + + # # Git support + # vim-fugitive + + # # Git support: Show changed lines in gutter + # gitsigns-nvim + + # # Nix support + # vim-nix + + # # Navigation: Fuzzy finder + # telescope-nvim + # telescope-fzf-native-nvim + + # # Navigation: File tree + # nvim-tree-lua + + # # Navigation: Buffers + # bufferline-nvim + + # # Aesthetics: Color scheme + # gruvbox-nvim + + # # Aesthetics: icons + # nvim-web-devicons + + # # Aesthetics: Status/tabline + # lualine-lsp-progress + # lualine-nvim + + # # Vim: key binding feedback + # which-key-nvim + + # # Vim: benchmarking + # vim-startuptime + # ]; + + # extraConfig = '' + # let g:loaded_perl_provider = 0 + # :set relativenumber + # :set rnu + # ''; + + plugins = with pkgs; [ + vimPlugins.vim-nix + # ] + # ++ lib.optionals config.services.xserver.enable + # [ + vimPlugins.vim-clap + vimPlugins.fzf-vim + # vimPlugins.nvim-treesitter.withAllGrammars + vimPlugins.cmp-nvim-lsp + vimPlugins.cmp-snippy + vimPlugins.cmp-path + vimPlugins.cmp-cmdline + vimPlugins.cmp-buffer + vimPlugins.cmp-digraphs + vimPlugins.cmp-cmdline-history + vimPlugins.cmp-nvim-lsp-document-symbol + vimPlugins.cmp-nvim-lsp-signature-help + vimPlugins.cmp-git + vimPlugins.vim-airline-themes + { + plugin = vimPlugins.nvim-cmp; + config = '' + set completeopt=menu,menuone,noselect + + lua <'] = cmp.mapping.scroll_docs(-4), + [''] = cmp.mapping.scroll_docs(4), + [''] = cmp.mapping.complete(), + [''] = cmp.mapping.abort(), + [''] = cmp.mapping.confirm({ select = true }), + }), + sources = cmp.config.sources({ + { name = 'nvim_lsp' }, + { name = 'nvim_lsp_document_symbol' }, + { name = 'nvim_lsp_signature_help' }, + { name = 'cmdline_history' }, + { name = 'digraphs' }, + { name = 'path' }, + { name = 'buffer-lines' }, + { name = 'snippy' }, + { name = "git" }, + }, { + { name = 'buffer' }, + }) + }) + + cmp.setup.filetype('gitcommit', { + sources = cmp.config.sources({ + { name = 'cmp_git' }, + }, { + { name = 'buffer' }, + }) + }) + + cmp.setup.cmdline({ '/', '?' }, { + mapping = cmp.mapping.preset.cmdline(), + sources = { + { name = 'buffer' } + } + }) + + cmp.setup.cmdline(':', { + mapping = cmp.mapping.preset.cmdline(), + sources = cmp.config.sources({ + { name = 'path' } + }, { + { name = 'cmdline' } + }) + }) + + local capabilities = require('cmp_nvim_lsp').default_capabilities() + + require'lspconfig'.pyright.setup { + capabilities = capabilities, + } + require'lspconfig'.rnix.setup { + capabilities = capabilities, + } + require'lspconfig'.tsserver.setup { + capabilities = capabilities, + } + require'lspconfig'.clangd.setup { + capabilities = capabilities, + } + EOF + ''; + } + { + plugin = vimPlugins.nvim-snippy; + config = '' + lua << EOF + require('snippy').setup({ + mappings = { + is = { + [''] = 'expand_or_advance', + [''] = 'previous', + }, + nx = { + ['x'] = 'cut_text', + }, + }, + }) + EOF + ''; + } + { + plugin = vimPlugins.nvim-tree-lua; + config = '' + lua << EOF + vim.g.loaded_netrw = 1 + vim.g.loaded_netrwPlugin = 1 + vim.opt.termguicolors = true + require("nvim-tree").setup() + EOF + ''; + } + { + plugin = vimPlugins.vim-airline; + config = '' + let g:airline_powerline_fonts = 1 + let g:airline_theme='base16' + let g:airline#extensions#nvimlsp#enabled = 1 + ''; + } + { + plugin = vimPlugins.vim-which-key; + config = '' + lua << EOF + require("which-key").setup() + EOF + ''; + } + { + plugin = vimPlugins.nvim-autopairs; + config = '' + lua << EOF + require("nvim-autopairs").setup() + EOF + ''; + } + { + plugin = vimPlugins.nvim-lspconfig; + config = '' + lua << EOF + local opts = { noremap=true, silent=true } + vim.keymap.set('n', 'e', vim.diagnostic.open_float, opts) + vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts) + vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts) + vim.keymap.set('n', 'q', vim.diagnostic.setloclist, opts) + + local on_attach = function(client, bufnr) + vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') + local bufopts = { noremap=true, silent=true, buffer=bufnr } + vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, bufopts) + vim.keymap.set('n', 'gd', vim.lsp.buf.definition, bufopts) + vim.keymap.set('n', 'K', vim.lsp.buf.hover, bufopts) + vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, bufopts) + vim.keymap.set('n', '', vim.lsp.buf.signature_help, bufopts) + vim.keymap.set('n', 'wa', vim.lsp.buf.add_workspace_folder, bufopts) + vim.keymap.set('n', 'wr', vim.lsp.buf.remove_workspace_folder, bufopts) + vim.keymap.set('n', 'wl', function() + print(vim.inspect(vim.lsp.buf.list_workspace_folders())) + end, bufopts) + vim.keymap.set('n', 'D', vim.lsp.buf.type_definition, bufopts) + vim.keymap.set('n', 'rn', vim.lsp.buf.rename, bufopts) + vim.keymap.set('n', 'ca', vim.lsp.buf.code_action, bufopts) + vim.keymap.set('n', 'gr', vim.lsp.buf.references, bufopts) + vim.keymap.set('n', 'f', function() vim.lsp.buf.format { async = true } end, bufopts) + end + + local lsp_flags = { + debounce_text_changes = 150, + } + require('lspconfig')['pyright'].setup{ + on_attach = on_attach, + flags = lsp_flags, + } + require('lspconfig')['rnix'].setup{ + on_attach = on_attach, + flags = lsp_flags, + } + require('lspconfig')['tsserver'].setup{ + on_attach = on_attach, + flags = lsp_flags, + } + EOF + ''; + } + ]; + }; +} diff --git a/modules/users/personal/crstl/editor/vscodium.nix b/modules/users/personal/crstl/editor/vscodium.nix new file mode 100644 index 0000000..6e39654 --- /dev/null +++ b/modules/users/personal/crstl/editor/vscodium.nix @@ -0,0 +1,196 @@ +{ lib, pkgs, ... }: +{ + stylix.targets.vscode.enable = false; + + home = { + packages = with pkgs; [ + # git + gitFull + + # env + direnv + vscode-langservers-extracted + + # nix + nil + nixd + nixpkgs-fmt + nixfmt-rfc-style + deadnix + statix + + # golang + go + goperf + libcap + gcc + + # devops + opentofu + kubectl + kubernetes-helm + ]; + + sessionVariables.GOPATH = "/home/crstl/Development/golang"; + }; + + programs.vscode = { + enable = true; + package = pkgs.vscodium-fhs; + + mutableExtensionsDir = false; + enableUpdateCheck = false; + enableExtensionUpdateCheck = false; + + userSettings = { + telemetry.telemetryLevel = "off"; + gitlens.telemetry.enabled = false; + redhat.telemetry.enabled = false; + + window = { + zoomLevel = 1; + menuBarVisibility = "toggle"; + }; + + editor = { + inlineSuggest.enabled = true; + minimap.enabled = false; + autoIndent = "full"; + autoSurround = "brackets"; + }; + + workbench = { + iconTheme = "material-icon-theme"; + colorTheme = "Material Theme Palenight High Contrast"; + editor.enablePreview = false; + list.smoothScrolling = true; + startupEditor = "none"; + welcomePage.walkthroughs.openOnInstall = false; + }; + + update.showReleaseNotes = false; + + nix = { + enableLanguageServer = true; + serverPath = "${lib.getExe pkgs.nil}"; + serverSettings.nil = { + formatting.command = [ (lib.getExe pkgs.nixpkgs-fmt) ]; + nix = { + binary = lib.getExe pkgs.nix; + maxMemoryMB = 4096; + flake = { + autoArchive = true; + autoEvalInputs = true; + nixpkgsInputName = "nixpkgs"; + }; + }; + }; + }; + + "[jsonc]".editor.defaultFormatter = "vscode.json-language-features"; + "[nix]".editor.defaultFormatter = "jnoortheen.nix-ide"; + + github.copilot.chat.welcomeMessage = "never"; + + genieai = { + promptPrefix = { + explain = "gpt.explain"; + addComments = "gpt.comments"; + completeCode = "gpt.complete"; + optimize = "gpt.optimize"; + findProblems = "gpt.find"; + addTests = "gpt.test"; + }; + openai = { + model = "gpt-4"; + temperature = 0.7; + }; + response = { + showNotification = true; + }; + }; + }; + + extensions = with pkgs.vscode-extensions; [ + # themes & icons + equinusocio.vsc-material-theme + pkief.material-icon-theme + pkief.material-product-icons + + # visualize + ## kamikillerto.vscode-colorize + oderwat.indent-rainbow + + # formater + esbenp.prettier-vscode + formulahendry.auto-close-tag + formulahendry.auto-rename-tag + jkillian.custom-local-formatters + shardulm94.trailing-spaces + tyriar.sort-lines + + # lang + streetsidesoftware.code-spell-checker + + # file + redhat.vscode-yaml + + # env + editorconfig.editorconfig + irongeek.vscode-env + mikestead.dotenv + formulahendry.code-runner + + # git + codezombiech.gitignore + donjayamanne.githistory + mhutchie.git-graph + + # nix + arrterian.nix-env-selector + bbenoist.nix + brettm12345.nixfmt-vscode + jnoortheen.nix-ide + mkhl.direnv + + # golang + golang.go + + # web + astro-build.astro-vscode + bradlc.vscode-tailwindcss + ritwickdey.liveserver + + # markdown + bierner.markdown-mermaid + davidanson.vscode-markdownlint + unifiedjs.vscode-mdx + marp-team.marp-vscode + + # container + ms-kubernetes-tools.vscode-kubernetes-tools + ms-vscode-remote.remote-ssh + ms-vscode-remote.remote-containers + + # devops + hashicorp.hcl + hashicorp.terraform + github.vscode-github-actions + + # ai + github.copilot + github.copilot-chat + genieai.chatgpt-vscode + visualstudioexptteam.vscodeintellicode + visualstudioexptteam.intellicode-api-usage-examples + ]; + + globalSnippets = { + fixme = { + prefix = [ "fixme" ]; + description = "Insert a FIXME remark"; + body = [ "$LINE_COMMENT FIXME: $0" ]; + }; + }; + }; +} diff --git a/modules/users/personal/crstl/gpg/default.nix b/modules/users/personal/crstl/gpg/default.nix new file mode 100644 index 0000000..1a284be --- /dev/null +++ b/modules/users/personal/crstl/gpg/default.nix @@ -0,0 +1,21 @@ +{ pkgs, ... }: +{ + services.gpg-agent = { + enable = true; + enableScDaemon = true; + enableSshSupport = true; + enableExtraSocket = true; + defaultCacheTtl = 34560000; + maxCacheTtl = 34560000; + pinentryPackage = pkgs.pinentry-gnome3; + }; + + programs.gpg = { + enable = true; + settings = { + default-key = "EECAAE75129CF8D1DE4771F471D71CBBEA1E76AD"; + keyserver = "hkps://keys.openpgp.org"; + keyserver-options = "no-honor-keyserver-url"; + }; + }; +} diff --git a/modules/users/personal/crstl/gpg/keyserver.age b/modules/users/personal/crstl/gpg/keyserver.age new file mode 100644 index 0000000..bae0790 --- /dev/null +++ b/modules/users/personal/crstl/gpg/keyserver.age @@ -0,0 +1,44 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw 6ocHTAQUz4I4xpYL/v1oYf4AUScF9TsYzMPWC1xlanI +DUx7menhndw5iep3GksOZQ84JtmVt4Ikm3vaMayapRY +-> ssh-ed25519 JzjriQ gqI71D27jRUKt4dNSrGT4IFLosxyB1knb6SqXTP2wVc +BVSlTYiKoVBGzqMmbWv2K2Mh1iWWa7fJhVmrq6za6DQ +-> ssh-rsa 6hPx7A +Fg+Dk2NyPW7YOK+9KLPlfHYL/Z2/zoQxRTMl3qY7Qtjgp7LIviLKtXrUK91Cwz4u +R/2d0W7QtxMb3qDto1FVBVoWqqIDTjniJeA/32I8I94ewmhGD6RwgLt5bkjrVUqw +EBpCCvAXN3ZXCzTahTv+Y7IAXiZoqWXKKyqKbybcqGN4A0FW/aQYyYJju+Zb3xZU +XsOUTKPwqsDKxpXhViQ6gBYDzpSNX9jyvzQOBoCVL1XgIhOoTTTSFkgAhBtYXGRq +sQXc1/4wtCtxNRE9SI8GKDGsLqW421kYInQBhXmQsvoA+0LfBucmwYYqh2ZWKqay +4BukP4ZO5ldNnYAa8VhqVdhfzulBtWDCaQUHFYBOtn0HlhUj/IJ1YHQ2pTtx/wEt +dQ4f0QkoNRL+crTeypE+HFjDHjLlBzkmxu56cqImnyNOR64KoTw5f9wLFU7Xz0oq +VWjS1/z1l8lY7qc8Eh0mG0FRW1fZikW7173AfLdLOr1L3hw3k5nnqQYA84SKn0/n +jCJ52CsnfOTI9Q4oOs55FnV7gveoRiWaWme8Y4RgK/7cVWrRpTAAQEzT8uIGK/7R +LgdQpcloK0zfHBSkD+fnWmSpMK+hRetEt0H1GpCBDsjI8ylcesDNpO6th1nyfxyr +yTOM35sLya21kKiaRE5hReWGpnxN1yvVpamPOh1IPw0 +-> ssh-ed25519 SiDnLw 2F1Up/osFYuCWJJ7WSA/Ng39JbviF93v9cez6E9HsmM +9zRgy0Yjlh4UoBChzPl4ok9oQBC1Nx6AE+GGS7/ncHU +-> ssh-ed25519 Dfencg 1PJI0ReobErZPcsooAYES8Po+/vc6zozYazCox3iZBc +DB+JYu4FeGKtIFfkRGEchjiaYGy+OptF1BPVTTDhKeo +-> ssh-ed25519 OWgoVA zhndyZqQFzdaM3noqeI7L4Lvww5UbWycFeISo6nyiT4 +B7TKE3Qaz/D4YL0ecvYtyWm2dQ+XKbVSPZqLt2DgZQ8 +-> ssh-ed25519 aP/BWw sBdCAsDidUg9ZQiLxNFRcoW1y2s6e+vf98i2Fc+o2w0 +d3kQ9N70+HRTDSggWpOCcHqWAnWslWiiBY4r0r5wFlY +-> ssh-ed25519 v+/Ozg 1cpZqhjYBggF1FwDTMA7x3+dNSeIGhPcLTKq7KgvFws +Lohl1sDNzuioMlgzcUTyMj0dnFn2KrirBu1jco/o0Nk +-> ssh-ed25519 5VC2zg ZZNCrVED5tOYoJKshBo8e4uyaYl8U3M1KWfM2jZC0VE +Y7lrWbP9Fgo5ItSaU2c0GpJhx4ZMoFIzF4b5K4vGS1s +-> ssh-ed25519 ZeuIrQ CC3+rqvrw/QeW/wJtldrpxj2JqbPVcw2JkHbte9YEW4 +xadAuHXDVQJeQyMmfy12nbXKx1jiunbCfwh88Ix1rxA +-> ssh-ed25519 MrfLnw x0tdBoB2lbs5g1SwtUEj/xjSEkQ0onJ4gE+JUcDAYW8 +UpLeFyDM4Y7WXHJE9EItAXvyYdPioBnCRXHbnGz9xUk +-> ssh-ed25519 xkaJLw wtDFYitAVhBuEFusuX6HcRIajyjXlmnjAwd2Mh/rqxg +gIQiVMg8ZYQMh3k22lskpe1Jf7QuTggabqXjWxq9M5c +-> ssh-ed25519 al5mZw s5ITDTpae53n25VrO3L8SQxNr4ycRJWNQxIcUEIMrX0 +KNwG7WSaCIDfnNnAnl7lXeB5EWv4MmWdc9CCbaoYYFQ +-> ssh-ed25519 Sk9VBA rGfI3xSbon1V5inKsStk1h3cta8J2sLeYeq5Ky/iOjk +5SEDDnfoMMYaCwSVhLZBeAhuhOxArlsnb2mMky/eybc +--- cVx6mTAYi7EOPwkNdTMCwLdjSXY3FFcxv0HtATcDGWc +�r�s�����T��}��nF�l��hd �%�4���QZ-*�6뵻k��t' XJ��@0$E +��{�����������&X�ʚ[�!� +o���W3 +%X��X�#�x �L�f�%?��BR���F���EN� \ No newline at end of file diff --git a/modules/users/personal/crstl/media/mpd.nix b/modules/users/personal/crstl/media/mpd.nix new file mode 100644 index 0000000..6e394dd --- /dev/null +++ b/modules/users/personal/crstl/media/mpd.nix @@ -0,0 +1,14 @@ +{ pkgs, ... }: +{ + xdg.userDirs.enable = true; + + services.mpd.enable = true; + + home.packages = with pkgs; [ + cantata + mmtc + rofi-mpd + ]; + + programs.ncmpcpp.enable = true; +} diff --git a/modules/users/personal/crstl/media/mpv.nix b/modules/users/personal/crstl/media/mpv.nix new file mode 100644 index 0000000..b68b1bf --- /dev/null +++ b/modules/users/personal/crstl/media/mpv.nix @@ -0,0 +1,70 @@ +{ + programs.mpv = { + enable = true; + config = { + profile = "gpu-hq"; + gpu-context = "wayland"; + vo = "gpu"; + hwdec = "auto"; + }; + }; + + xdg.mimeApps.defaultApplications = { + "application/mxf" = "mpv.desktop"; + "application/sdp" = "mpv.desktop"; + "application/smil" = "mpv.desktop"; + "application/streamingmedia" = "mpv.desktop"; + "application/vnd.apple.mpegurl" = "mpv.desktop"; + "application/vnd.ms-asf" = "mpv.desktop"; + "application/vnd.rn-realmedia" = "mpv.desktop"; + "application/vnd.rn-realmedia-vbr" = "mpv.desktop"; + "application/x-cue" = "mpv.desktop"; + "application/x-extension-m4a" = "mpv.desktop"; + "application/x-extension-mp4" = "mpv.desktop"; + "application/x-matroska" = "mpv.desktop"; + "application/x-mpegurl" = "mpv.desktop"; + "application/x-ogm" = "mpv.desktop"; + "application/x-ogm-video" = "mpv.desktop"; + "application/x-shorten" = "mpv.desktop"; + "application/x-smil" = "mpv.desktop"; + "application/x-streamingmedia" = "mpv.desktop"; + "video/3gp" = "mpv.desktop"; + "video/3gpp" = "mpv.desktop"; + "video/3gpp2" = "mpv.desktop"; + "video/avi" = "mpv.desktop"; + "video/divx" = "mpv.desktop"; + "video/dv" = "mpv.desktop"; + "video/fli" = "mpv.desktop"; + "video/flv" = "mpv.desktop"; + "video/mkv" = "mpv.desktop"; + "video/mp2t" = "mpv.desktop"; + "video/mp4" = "mpv.desktop"; + "video/mp4v-es" = "mpv.desktop"; + "video/mpeg" = "mpv.desktop"; + "video/msvideo" = "mpv.desktop"; + "video/ogg" = "mpv.desktop"; + "video/quicktime" = "mpv.desktop"; + "video/vnd.divx" = "mpv.desktop"; + "video/vnd.mpegurl" = "mpv.desktop"; + "video/vnd.rn-realvideo" = "mpv.desktop"; + "video/webm" = "mpv.desktop"; + "video/x-avi" = "mpv.desktop"; + "video/x-flc" = "mpv.desktop"; + "video/x-flic" = "mpv.desktop"; + "video/x-flv" = "mpv.desktop"; + "video/x-m4v" = "mpv.desktop"; + "video/x-matroska" = "mpv.desktop"; + "video/x-mpeg2" = "mpv.desktop"; + "video/x-mpeg3" = "mpv.desktop"; + "video/x-ms-afs" = "mpv.desktop"; + "video/x-ms-asf" = "mpv.desktop"; + "video/x-ms-wmv" = "mpv.desktop"; + "video/x-ms-wmx" = "mpv.desktop"; + "video/x-ms-wvxvideo" = "mpv.desktop"; + "video/x-msvideo" = "mpv.desktop"; + "video/x-ogm" = "mpv.desktop"; + "video/x-ogm+ogg" = "mpv.desktop"; + "video/x-theora" = "mpv.desktop"; + "video/x-theora+ogg" = "mpv.desktop"; + }; +} diff --git a/modules/users/personal/crstl/office/pass.nix b/modules/users/personal/crstl/office/pass.nix new file mode 100644 index 0000000..d189ddf --- /dev/null +++ b/modules/users/personal/crstl/office/pass.nix @@ -0,0 +1,15 @@ +{ pkgs, ... }: +{ + # services.pass-secret-service.enable = true; + + programs.password-store = { + enable = true; + settings.PASSWORD_STORE_DIR = "$HOME/.password-store"; + }; + + home.packages = with pkgs; [ + gopass + gopass-jsonapi + qtpass + ]; +} diff --git a/modules/users/personal/crstl/packages.nix b/modules/users/personal/crstl/packages.nix new file mode 100644 index 0000000..ea33002 --- /dev/null +++ b/modules/users/personal/crstl/packages.nix @@ -0,0 +1,16 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ + appimage-run + filezilla + gimp + inkscape + libreoffice-fresh + meld + remmina + strawberry + transmission_4-gtk + transmission-rss + transmission-remote-gtk + ]; +} diff --git a/modules/users/personal/crstl/password.age b/modules/users/personal/crstl/password.age new file mode 100644 index 0000000..b1ebca1 --- /dev/null +++ b/modules/users/personal/crstl/password.age @@ -0,0 +1,45 @@ +age-encryption.org/v1 +-> ssh-ed25519 jDpDqw 6sZ74uKgsXI8RMtbAgo3ssmJJQRKLgtcD1S5VWYwkGs +r6WgWbM9uIfKT5k8VgAqr943utPfVjLjh5bx/IxADQ4 +-> ssh-ed25519 JzjriQ 0stdqyyMUutffKeFUAI9iXWP1UCpIQAGY/eLBGl1lDE +K66zAzoqkd8eXfD/gO6Ov5pbYrh4ebqsCMP0AaY+jDU +-> ssh-rsa 6hPx7A +GPFUJIGqxeys2GLE6nHy3vww9WPDTHSMnNFJl1S3xxiZjEYaPHDl1TBqU0gH7Och +6nQeu6K+kM3yCkLlPw/Rvr/tpVfac/PEp3TU/4tTitOECQjq2O5U/auEAWXOFYtx +q5ZO6JHZrhIgvqW9o9f7V0ioatpY10tKfXZmXJswFxjNiCAbtk/e5KmWFixVcDRY +38leCz67ES01kqundS7rqEWGLMAw3aemXCWgcRROGjjQs69A7MmcrRIEze0XH8dl +MTqahZHUFNvWVw8OihGYdzGjYht3qLLqjPGuKms1HNLn8nLCLGRDutFdp6GYjvML +OYOclQQx4FtkfFC0CpQscv8DCHuq0wuezXPmp079ktbQ9jaD0CJCpiKoWV2sxLt3 +bRsNKwsoeXlEfcGuvU76KGD3gElZcj0muN72gfOdqJUcn9RTHHZXBm/hbfYKsqvJ +/tzvJuPG9Dv9eozKYX8avFYgMFTg0TcPQJGjGk8BQJ3MVEcJq9fKyNMmg/dWg7YW +oy1CzGxFGdRaRP2bYr6dXrIs4+HiXzIUV0F/2T7pZWqr1W1zaHflK4Of8rLDtfQb +53AiqeAIdZLYLqekjblR5ke9WOovvnAMqrywplY7BgbyH8h9otVg6104EAxcY7Bk +F/x+6gL1tV0OhtWpUwrlxouNrI9rzmtS2dkz4Y5ZVpM +-> ssh-ed25519 IK8+2Q 3eZS/ctGuCI8hJXYzy17uXuIJynHuuJJrQ8qtJ9oOEo +4/M+rssfgYXEUip6PftdOi/4F3kGQccBSY6HktXsObc +-> ssh-ed25519 SiDnLw Ln+El0qOj+3wi4qrRIh3CVcaqZsdGH46V44mn6SS+CE +8NpVQbMkRsndtUYIQNcgYasMV/sC8fqzpQ4ipOQjmXg +-> ssh-ed25519 Dfencg VciwaDfyLsM4WGMAxN/Sab1SxaYwoB2954N/e78ag20 +WjBQn5OdX9eS0+cx5+Dk/Aye1h+BKjdE98elp/zDBB0 +-> ssh-ed25519 OWgoVA VAcwbXGDGCF5KJCrQlh1zefzYpVgSwwilea1y7RG9HE +RWPYnyc8dU2E8NJA3bVt59BctWHjLl7D5jfi0TyCRd4 +-> ssh-ed25519 aP/BWw J5nqEUmVXUTKSkDE9uUa8afy7yjeSyRQeHAxvWoSAxU +fxtKQO5zHnX4Si/Zkki4dunIYAiCtEaBO7awvKq4tqo +-> ssh-ed25519 v+/Ozg FI/PXe8lHiVHeNX0roW8GRx4nCjfVxMpHGdS1jzI8Eo +hdg/5dhzaJ+f1CRiF6RVmEqu3hKtlEVjF3ji7h9pzeA +-> ssh-ed25519 5VC2zg PT0cZntXNiNNFaN27W5F6znrwRNmyKTDKoA/tUTW0mk +UYX/wLXS67culSOHfeVygK80aBmTONxJXcBcf3YAg+s +-> ssh-ed25519 ZeuIrQ hZ0L1lIPmWi7ovl1Byl2pTt8LpmhD4wklPCQcUZSrWE +2W/6GBHGR58YIejZx521j/weWLv5SSwl80xmKnnR4ME +-> ssh-ed25519 MrfLnw zcfOpU8owgizGcBfxvFoi4VWPPUGIFQZQD9ver+smCs +LMdoH+qr32mRsNgHiWj4hi3WPldvywROJlVh4iBugwI +-> ssh-ed25519 TVW7ow IQFBhT+NFHeIfWTjS1JxYV2T5uFS+4lpSif8gRj+JHk +gO40UI4Pt+/ix2JtzsVXsJdW93kQFG67T9A5V8QUfYk +-> ssh-ed25519 xkaJLw D9AnOVBqmwS4g4MU3MlYOlpR+2T2mHIP6ykmhWgFyEE +SSMNkv7UtI3qdVsYSHHU5SRnhwaDQsB1Yq13Dzxk2hE +-> ssh-ed25519 al5mZw oJV7Cho7LLmrv/QJfXdqOxtjYat7bQNGeEwIjwTK8g4 +eQR8tTAhQQsAw4UjjH/b6mPxhEoygjqPuWEmrAoiVuE +-> ssh-ed25519 Sk9VBA EKqk5m4p4gkXOuJEVFw0s6FuEkWcGCuMXojsXx2M2QM +w/YSo95lCL7fxHgXJy7G5ad1/MgEaZRmAQGHDhW3x80 +--- sCbf+ug9guufIwu39hg3eIDsm6dsApmG/gV6zt+SESw +\)#?B&=c2Szދu"S̲EWɞhNGΧbLB^Lod6MUmp,E0H' O? [`|l[] 5w&x&ު#һ \ No newline at end of file diff --git a/modules/users/personal/crstl/system/gammastep.nix b/modules/users/personal/crstl/system/gammastep.nix new file mode 100644 index 0000000..8face6f --- /dev/null +++ b/modules/users/personal/crstl/system/gammastep.nix @@ -0,0 +1,7 @@ +{ + services.gammastep = { + enable = true; + tray = true; + provider = "manual"; + }; +} diff --git a/modules/users/personal/crstl/system/gtk.nix b/modules/users/personal/crstl/system/gtk.nix new file mode 100644 index 0000000..ded3b79 --- /dev/null +++ b/modules/users/personal/crstl/system/gtk.nix @@ -0,0 +1,14 @@ +{ lib, pkgs, ... }: +{ + gtk = { + enable = true; + theme = { + name = lib.mkForce "palenight"; + package = lib.mkForce pkgs.palenight-theme; + }; + iconTheme = { + name = lib.mkForce "Nordzy-purple-dark"; + package = lib.mkForce pkgs.nordzy-icon-theme; + }; + }; +} diff --git a/modules/users/personal/crstl/system/home-manager.nix b/modules/users/personal/crstl/system/home-manager.nix new file mode 100644 index 0000000..a7ef72e --- /dev/null +++ b/modules/users/personal/crstl/system/home-manager.nix @@ -0,0 +1,3 @@ +{ + programs.home-manager.enable = true; +} diff --git a/modules/users/personal/crstl/system/kanshi.nix b/modules/users/personal/crstl/system/kanshi.nix new file mode 100644 index 0000000..1f084fd --- /dev/null +++ b/modules/users/personal/crstl/system/kanshi.nix @@ -0,0 +1,67 @@ +{ + services.kanshi = { + enable = true; + settings = [ + { + profile = { + name = "srxtab00"; + outputs = [{ + criteria = "Sharp Corporation LQ100P1JX51 Unknown"; + scale = 1.1; + }]; + }; + } + { + profile = { + name = "srxws00"; + outputs = [ + { + criteria = "Dell Inc. DELL P3223QE 8HG75P3"; + status = "enable"; + mode = "3840x2160"; + position = "0,950"; + scale = 1.1; + } + { + criteria = "Dell Inc. DELL P3223QE 7HN7BP3"; + status = "enable"; + mode = "3840x2160"; + position = "3480,0"; + transform = "270"; + scale = 1.1; + } + ]; + }; + } + { + profile = { + name = "srxws01"; + outputs = [ + { + criteria = "Dell Inc. DELL U2415 7MT017CQ2NWU"; + status = "enable"; + mode = "1920x1200"; + position = "0,0"; + scale = 1.0; + } + { + criteria = "Dell Inc. DELL U2715H GH85D7920WHS"; + status = "enable"; + mode = "2560x1440"; + position = "1920,0"; + transform = "90"; + scale = 1.0; + } + { + criteria = "Dell Inc. DELL U2415 7MT016C80UAS"; + status = "enable"; + mode = "1920x1200"; + position = "3360,0"; + scale = 1.0; + } + ]; + }; + } + ]; + }; +} diff --git a/modules/users/personal/crstl/system/qt.nix b/modules/users/personal/crstl/system/qt.nix new file mode 100644 index 0000000..985c2b3 --- /dev/null +++ b/modules/users/personal/crstl/system/qt.nix @@ -0,0 +1,6 @@ +{ + qt = { + enable = true; + platformTheme.name = "gtk3"; + }; +} diff --git a/modules/users/personal/crstl/system/stylix.nix b/modules/users/personal/crstl/system/stylix.nix new file mode 100644 index 0000000..6b9e346 --- /dev/null +++ b/modules/users/personal/crstl/system/stylix.nix @@ -0,0 +1,29 @@ +{ + stylix = { + enable = true; + fonts = { + sizes = { + desktop = 12; + applications = 12; + terminal = 12; + popups = 12; + }; + }; + + opacity = { + terminal = 0.9; + applications = 0.9; + popups = 0.9; + desktop = 0.9; + }; + + targets = { + gnome.enable = true; + waybar = { + enableCenterBackColors = true; + enableRightBackColors = true; + enableLeftBackColors = true; + }; + }; + }; +} diff --git a/modules/users/personal/crstl/system/xdg.nix b/modules/users/personal/crstl/system/xdg.nix new file mode 100644 index 0000000..d7e2525 --- /dev/null +++ b/modules/users/personal/crstl/system/xdg.nix @@ -0,0 +1,6 @@ +{ + xdg.userDirs = { + enable = true; + createDirectories = true; + }; +} diff --git a/modules/users/personal/crstl/terminal/alacritty.nix b/modules/users/personal/crstl/terminal/alacritty.nix new file mode 100644 index 0000000..dfb00ea --- /dev/null +++ b/modules/users/personal/crstl/terminal/alacritty.nix @@ -0,0 +1,14 @@ +{ pkgs, ... }: +{ + programs.alacritty = { + enable = true; + settings = { + cursor.style = "Beam"; + dynamic_padding = true; + env.TERM = "xterm-256color"; + selection.save_to_clipboard = true; + url.launcher.program = "${pkgs.mimeo}/bin/mimeo"; + colors.draw_bold_text_with_bright_colors = true; + }; + }; +} diff --git a/modules/users/personal/crstl/terminal/awscli.nix b/modules/users/personal/crstl/terminal/awscli.nix new file mode 100644 index 0000000..f17e7d5 --- /dev/null +++ b/modules/users/personal/crstl/terminal/awscli.nix @@ -0,0 +1,9 @@ +{ + programs.awscli = { + enable = true; + settings.default = { + region = "eu-central-1"; + output = "json"; + }; + }; +} diff --git a/modules/users/personal/crstl/terminal/bat.nix b/modules/users/personal/crstl/terminal/bat.nix new file mode 100644 index 0000000..c253a6f --- /dev/null +++ b/modules/users/personal/crstl/terminal/bat.nix @@ -0,0 +1,27 @@ +{ pkgs, ... }: +{ + home.shellAliases = { + cat = "${pkgs.bat}/bin/bat --style=plain"; + less = "${pkgs.bat}/bin/bat --style=plain"; + }; + + programs.bat = { + enable = true; + config = { + color = "always"; + pager = "less -FR"; + style = "numbers,changes,header"; + map-syntax = [ + "*.hcl:Terraform" + "*.tf.json:Terraform" + "*.ino:C++" + ]; + }; + extraPackages = with pkgs.bat-extras; [ + batdiff + batgrep + batman + batwatch + ]; + }; +} diff --git a/modules/users/personal/crstl/terminal/dircolors.nix b/modules/users/personal/crstl/terminal/dircolors.nix new file mode 100644 index 0000000..b6186c2 --- /dev/null +++ b/modules/users/personal/crstl/terminal/dircolors.nix @@ -0,0 +1,5 @@ +{ + programs.dircolors = { + enable = true; + }; +} diff --git a/modules/users/personal/crstl/terminal/git.nix b/modules/users/personal/crstl/terminal/git.nix new file mode 100644 index 0000000..707f0ca --- /dev/null +++ b/modules/users/personal/crstl/terminal/git.nix @@ -0,0 +1,101 @@ +{ pkgs, lib, config, ... }: +{ + programs = { + git = { + enable = true; + package = pkgs.gitFull; + userName = "Sebastian Wendel"; + userEmail = "swendel@srx.digital"; + aliases = { + amend = "commit --amend -C HEAD"; + authors = + ''!"${pkgs.git}/bin/git log --pretty=format:%aN'' + + " | ${pkgs.coreutils}/bin/sort" + + " | ${pkgs.coreutils}/bin/uniq -c" + + " | ${pkgs.coreutils}/bin/sort -rn\""; + b = "branch --color -v"; + ca = "commit --amend"; + changes = "diff --name-status -r"; + clone = "clone --recursive"; + co = "checkout"; + cp = "cherry-pick"; + dc = "diff --cached"; + dh = "diff HEAD"; + ds = "diff --staged"; + from = "!${pkgs.git}/bin/git bisect start && ${pkgs.git}/bin/git bisect bad HEAD && ${pkgs.git}/bin/git bisect good"; + ls-ignored = "ls-files --exclude-standard --ignored --others"; + rc = "rebase --continue"; + rh = "reset --hard"; + ri = "rebase --interactive"; + rs = "rebase --skip"; + ru = "remote update --prune"; + snap = "!${pkgs.git}/bin/git stash" + " && ${pkgs.git}/bin/git stash apply"; + snaplog = + "!${pkgs.git}/bin/git log refs/snapshots/refs/heads/" + "$(${pkgs.git}/bin/git rev-parse HEAD)"; + spull = + "!${pkgs.git}/bin/git stash" + " && ${pkgs.git}/bin/git pull" + " && ${pkgs.git}/bin/git stash pop"; + su = "submodule update --init --recursive"; + undo = "reset --soft HEAD^"; + w = "status -sb"; + wdiff = "diff --color-words"; + l = + "log --graph --pretty=format:'%Cred%h%Creset" + + " —%Cblue%d%Creset %s %Cgreen(%cr)%Creset'" + + " --abbrev-commit --date=relative --show-notes=*"; + }; + + extraConfig = { + core = { + editr = "${lib.getExe pkgs.vscodium-fhs} --wait"; + pager = "${lib.getExe pkgs.bat}"; + trustctime = false; + logAllRefUpdates = true; + precomposeunicode = false; + whitespace = "trailing-space,space-before-tab"; + }; + branch.autosetupmerge = true; + credential.helper = "${pkgs.pass-git-helper}/bin/pass-git-helper"; + ghi.token = "!${pkgs.pass}/bin/pass show api.github.com | head -1"; + github.user = "SebastianWendel"; + hub.protocol = "${pkgs.openssh}/bin/ssh"; + init.defaultBranch = "main"; + mergetool.keepBackup = true; + pull.rebase = true; + rebase.autosquash = true; + rerere.enabled = true; + color = { + status = "auto"; + diff = "auto"; + branch = "auto"; + interactive = "auto"; + ui = "auto"; + sh = "auto"; + }; + }; + }; + + gitui.enable = true; + }; + + services.git-sync = { + enable = false; + repositories = { + "srx.digital.astro" = { + path = "${config.home.homeDirectory}/Development/web/srx.digital.astro"; + uri = "forgejo@code.srx.digital:srx/srx.infra.nix.history.git"; + }; + "srx.infra.nix" = { + path = "${config.home.homeDirectory}/Development/nix/srx.infra.nix"; + uri = "forgejo@code.srx.digital:srx/srx.infra.nix.history.git"; + }; + "srx.shadow.nix" = { + path = "${config.home.homeDirectory}/Development/nix/srx.shadow.nix"; + uri = "forgejo@code.srx.digital:srx/srx-nixos-shadow.git"; + }; + "nixpkgs" = { + path = "${config.home.homeDirectory}/Development/nix/nixpkgs"; + uri = "git@github.com:SebastianWendel/nixpkgs.git"; + }; + }; + }; +} diff --git a/modules/users/personal/crstl/terminal/htop.nix b/modules/users/personal/crstl/terminal/htop.nix new file mode 100644 index 0000000..bf05101 --- /dev/null +++ b/modules/users/personal/crstl/terminal/htop.nix @@ -0,0 +1,32 @@ +{ config, ... }: +{ + programs.htop = { + enable = true; + settings = + { + delay = 10; + show_program_path = false; + show_cpu_frequency = true; + show_cpu_temperature = true; + hide_kernel_threads = true; + } + // ( + with config.lib.htop; + leftMeters [ + (bar "AllCPUs2") + (bar "Memory") + (bar "Swap") + ] + ) + // ( + with config.lib.htop; + rightMeters [ + (text "Hostname") + (text "Tasks") + (text "LoadAverage") + (text "Uptime") + (text "Systemd") + ] + ); + }; +} diff --git a/modules/users/personal/crstl/terminal/imv.nix b/modules/users/personal/crstl/terminal/imv.nix new file mode 100644 index 0000000..f4e8c02 --- /dev/null +++ b/modules/users/personal/crstl/terminal/imv.nix @@ -0,0 +1,78 @@ +{ lib, ... }: +{ + programs.imv = { + enable = true; + settings = { + options.background = "ffffff"; + aliases.x = "close"; + }; + }; + + xdg.mimeApps.defaultApplications = { + "image/bmp" = lib.mkForce "imv.desktop"; + "image/gif" = lib.mkForce "imv.desktop"; + "image/jpeg" = lib.mkForce "imv.desktop"; + "image/jpg" = lib.mkForce "imv.desktop"; + "image/pjpeg" = lib.mkForce "imv.desktop"; + "image/png" = lib.mkForce "imv.desktop"; + "image/tiff" = lib.mkForce "imv.desktop"; + "image/webp" = lib.mkForce "imv.desktop"; + "image/x-3fr" = lib.mkForce "imv.desktop"; + "image/x-adobe-dng" = lib.mkForce "imv.desktop"; + "image/x-arw" = lib.mkForce "imv.desktop"; + "image/x-bay" = lib.mkForce "imv.desktop"; + "image/x-bmp" = lib.mkForce "imv.desktop"; + "image/x-canon-cr2" = lib.mkForce "imv.desktop"; + "image/x-canon-crw" = lib.mkForce "imv.desktop"; + "image/x-cap" = lib.mkForce "imv.desktop"; + "image/x-cr2" = lib.mkForce "imv.desktop"; + "image/x-crw" = lib.mkForce "imv.desktop"; + "image/x-dcr" = lib.mkForce "imv.desktop"; + "image/x-dcraw" = lib.mkForce "imv.desktop"; + "image/x-dcs" = lib.mkForce "imv.desktop"; + "image/x-dng" = lib.mkForce "imv.desktop"; + "image/x-drf" = lib.mkForce "imv.desktop"; + "image/x-eip" = lib.mkForce "imv.desktop"; + "image/x-erf" = lib.mkForce "imv.desktop"; + "image/x-fff" = lib.mkForce "imv.desktop"; + "image/x-fuji-raf" = lib.mkForce "imv.desktop"; + "image/x-iiq" = lib.mkForce "imv.desktop"; + "image/x-k25" = lib.mkForce "imv.desktop"; + "image/x-kdc" = lib.mkForce "imv.desktop"; + "image/x-mef" = lib.mkForce "imv.desktop"; + "image/x-minolta-mrw" = lib.mkForce "imv.desktop"; + "image/x-mos" = lib.mkForce "imv.desktop"; + "image/x-mrw" = lib.mkForce "imv.desktop"; + "image/x-nef" = lib.mkForce "imv.desktop"; + "image/x-nikon-nef" = lib.mkForce "imv.desktop"; + "image/x-nrw" = lib.mkForce "imv.desktop"; + "image/x-olympus-orf" = lib.mkForce "imv.desktop"; + "image/x-orf" = lib.mkForce "imv.desktop"; + "image/x-panasonic-raw" = lib.mkForce "imv.desktop"; + "image/x-pcx" = lib.mkForce "imv.desktop"; + "image/x-pef" = lib.mkForce "imv.desktop"; + "image/x-pentax-pef" = lib.mkForce "imv.desktop"; + "image/x-png" = lib.mkForce "imv.desktop"; + "image/x-portable-anymap" = lib.mkForce "imv.desktop"; + "image/x-portable-bitmap" = lib.mkForce "imv.desktop"; + "image/x-portable-graymap" = lib.mkForce "imv.desktop"; + "image/x-portable-pixmap" = lib.mkForce "imv.desktop"; + "image/x-ptx" = lib.mkForce "imv.desktop"; + "image/x-pxn" = lib.mkForce "imv.desktop"; + "image/x-r3d" = lib.mkForce "imv.desktop"; + "image/x-raf" = lib.mkForce "imv.desktop"; + "image/x-raw" = lib.mkForce "imv.desktop"; + "image/x-rw2" = lib.mkForce "imv.desktop"; + "image/x-rwl" = lib.mkForce "imv.desktop"; + "image/x-rwz" = lib.mkForce "imv.desktop"; + "image/x-sigma-x3f" = lib.mkForce "imv.desktop"; + "image/x-sony-arw" = lib.mkForce "imv.desktop"; + "image/x-sony-sr2" = lib.mkForce "imv.desktop"; + "image/x-sony-srf" = lib.mkForce "imv.desktop"; + "image/x-sr2" = lib.mkForce "imv.desktop"; + "image/x-srf" = lib.mkForce "imv.desktop"; + "image/x-tga" = lib.mkForce "imv.desktop"; + "image/x-x3f" = lib.mkForce "imv.desktop"; + "image/x-xbitmap" = lib.mkForce "imv.desktop"; + }; +} diff --git a/modules/users/personal/crstl/terminal/jq.nix b/modules/users/personal/crstl/terminal/jq.nix new file mode 100644 index 0000000..3c01c41 --- /dev/null +++ b/modules/users/personal/crstl/terminal/jq.nix @@ -0,0 +1 @@ +{ programs.jq.enable = true; } diff --git a/modules/users/personal/crstl/terminal/kitty.nix b/modules/users/personal/crstl/terminal/kitty.nix new file mode 100644 index 0000000..f2cbe5f --- /dev/null +++ b/modules/users/personal/crstl/terminal/kitty.nix @@ -0,0 +1,26 @@ +{ lib, ... }: +{ + programs.kitty = { + enable = true; + shellIntegration = { + enableBashIntegration = true; + enableZshIntegration = true; + }; + font = lib.mkForce { + size = 14; + name = ""; + }; + settings = { + copy_on_select = "clipboard"; + scrollback_lines = 10000; + update_check_interval = 0; + enable_audio_bell = false; + }; + keybindings = { + "ctrl+plus" = "change_font_size all +2.0"; + "ctrl+minus" = "change_font_size all -2.0"; + "ctrl+page_up" = "scroll_page_up"; + "ctrl+page_down" = "scroll_page_down"; + }; + }; +} diff --git a/modules/users/personal/crstl/terminal/lf.nix b/modules/users/personal/crstl/terminal/lf.nix new file mode 100644 index 0000000..d668f84 --- /dev/null +++ b/modules/users/personal/crstl/terminal/lf.nix @@ -0,0 +1,25 @@ +{ + programs.lf = { + enable = true; + + settings = { + number = true; + ratios = [ + 1 + 1 + 2 + ]; + tabstop = 4; + + preview = true; + hidden = true; + drawbox = true; + icons = true; + ignorecase = true; + }; + + commands = { + get-mime-type = ''%xdg-mime query filetype "$f"''; + }; + }; +} diff --git a/modules/users/personal/crstl/terminal/lsd.nix b/modules/users/personal/crstl/terminal/lsd.nix new file mode 100644 index 0000000..36f93a0 --- /dev/null +++ b/modules/users/personal/crstl/terminal/lsd.nix @@ -0,0 +1,11 @@ +{ + programs.lsd = { + enable = true; + enableAliases = true; + settings = { + layout = "grid"; + hyperlink = "auto"; + sorting.dir-grouping = "first"; + }; + }; +} diff --git a/modules/users/personal/crstl/terminal/mpd.nix b/modules/users/personal/crstl/terminal/mpd.nix new file mode 100644 index 0000000..6e394dd --- /dev/null +++ b/modules/users/personal/crstl/terminal/mpd.nix @@ -0,0 +1,14 @@ +{ pkgs, ... }: +{ + xdg.userDirs.enable = true; + + services.mpd.enable = true; + + home.packages = with pkgs; [ + cantata + mmtc + rofi-mpd + ]; + + programs.ncmpcpp.enable = true; +} diff --git a/modules/users/personal/crstl/terminal/nix-index.nix b/modules/users/personal/crstl/terminal/nix-index.nix new file mode 100644 index 0000000..562bbef --- /dev/null +++ b/modules/users/personal/crstl/terminal/nix-index.nix @@ -0,0 +1,5 @@ +{ + # programs.command-not-found.enable = true; + # programs.nix-index.enable = true; + programs.nix-index.enableZshIntegration = true; +} diff --git a/modules/users/personal/crstl/terminal/rbw.nix b/modules/users/personal/crstl/terminal/rbw.nix new file mode 100644 index 0000000..56e64e0 --- /dev/null +++ b/modules/users/personal/crstl/terminal/rbw.nix @@ -0,0 +1,13 @@ +{ pkgs, ... }: +{ + programs.rbw = { + enable = true; + settings = { + email = "swendel@srx.digital"; + base_url = "https://vault.srx.digital/"; + pinentry = pkgs.pinentry-gnome3; + sync_interval = 600; + lock_timeout = 21600; + }; + }; +} diff --git a/modules/users/personal/crstl/terminal/ripgrep.nix b/modules/users/personal/crstl/terminal/ripgrep.nix new file mode 100644 index 0000000..0b9550c --- /dev/null +++ b/modules/users/personal/crstl/terminal/ripgrep.nix @@ -0,0 +1,9 @@ +{ + programs.ripgrep = { + enable = true; + arguments = [ + "--max-columns-preview" + "--colors=line:style:bold" + ]; + }; +} diff --git a/modules/users/personal/crstl/terminal/ssh.nix b/modules/users/personal/crstl/terminal/ssh.nix new file mode 100644 index 0000000..699eff7 --- /dev/null +++ b/modules/users/personal/crstl/terminal/ssh.nix @@ -0,0 +1,6 @@ +{ + programs.ssh = { + enable = true; + forwardAgent = true; + }; +} diff --git a/modules/users/personal/crstl/terminal/starship.nix b/modules/users/personal/crstl/terminal/starship.nix new file mode 100644 index 0000000..5122eba --- /dev/null +++ b/modules/users/personal/crstl/terminal/starship.nix @@ -0,0 +1,63 @@ +{ lib, ... }: +{ + programs.starship = { + enable = true; + enableBashIntegration = true; + enableZshIntegration = true; + + settings = { + add_newline = true; + scan_timeout = 10; + + status = { + map_symbol = true; + pipestatus = true; + }; + + format = lib.concatStrings [ + "$all" + "$line_break" + "$character" + ]; + + character = { + success_symbol = " [λ](bold green)"; + error_symbol = " [λ](bold red)"; + }; + + nix_shell.symbol = "❄️ "; + aws.disabled = true; + + directory = { + style = "cyan"; + read_only = " 🔒"; + }; + + battery = { + charging_symbol = "⚡️"; + display = [ + { + threshold = 10; + style = "bold red"; + } + ]; + }; + + cmd_duration.show_notifications = true; + + git_metrics = { + format = "[+$added]($added_style)/[-$deleted]($deleted_style)"; + }; + + git_status = { + ahead = ''⇡''${count}''; + diverged = ''⇕⇡''${ahead_count}⇣''${behind_count}''; + behind = ''⇣''${count}''; + }; + + shlvl = { + symbol = "↕ "; + }; + }; + }; +} diff --git a/modules/users/personal/crstl/terminal/thefuck.nix b/modules/users/personal/crstl/terminal/thefuck.nix new file mode 100644 index 0000000..90f592d --- /dev/null +++ b/modules/users/personal/crstl/terminal/thefuck.nix @@ -0,0 +1,9 @@ +{ + programs.thefuck = { + enable = true; + enableBashIntegration = true; + enableFishIntegration = true; + enableZshIntegration = true; + enableInstantMode = true; + }; +} diff --git a/modules/users/personal/crstl/terminal/tmux.nix b/modules/users/personal/crstl/terminal/tmux.nix new file mode 100644 index 0000000..18bf255 --- /dev/null +++ b/modules/users/personal/crstl/terminal/tmux.nix @@ -0,0 +1,12 @@ +{ + programs.tmux = { + enable = true; + aggressiveResize = true; + clock24 = true; + escapeTime = 0; + historyLimit = 10000; + newSession = false; + secureSocket = false; + terminal = "tmux-256color"; + }; +} diff --git a/modules/users/personal/crstl/terminal/yazi.nix b/modules/users/personal/crstl/terminal/yazi.nix new file mode 100644 index 0000000..e015599 --- /dev/null +++ b/modules/users/personal/crstl/terminal/yazi.nix @@ -0,0 +1,12 @@ +{ + programs.yazi = { + enable = true; + enableZshIntegration = true; + settings = { + manager = { + show_hidden = false; + sort_dir_first = true; + }; + }; + }; +} diff --git a/modules/users/personal/crstl/terminal/zoxide.nix b/modules/users/personal/crstl/terminal/zoxide.nix new file mode 100644 index 0000000..439f676 --- /dev/null +++ b/modules/users/personal/crstl/terminal/zoxide.nix @@ -0,0 +1,7 @@ +{ + programs.zoxide = { + enable = true; + enableZshIntegration = true; + enableBashIntegration = true; + }; +} diff --git a/modules/users/personal/crstl/terminal/zsh.nix b/modules/users/personal/crstl/terminal/zsh.nix new file mode 100644 index 0000000..bc67e47 --- /dev/null +++ b/modules/users/personal/crstl/terminal/zsh.nix @@ -0,0 +1,68 @@ +{ pkgs, lib, ... }: +let + mkZshPlugin = + { pkg + , file ? "${pkg.pname}.plugin.zsh" + , + }: + { + name = pkg.pname; + inherit (pkg) src; + inherit file; + }; +in +{ + home.packages = with pkgs; [ thefuck ]; + + programs.zsh = { + enable = lib.mkForce true; + autocd = true; + + autosuggestion.enable = true; + enableCompletion = true; + syntaxHighlighting.enable = true; + enableVteIntegration = true; + + plugins = with pkgs; [ + (mkZshPlugin { pkg = zsh-z; }) + (mkZshPlugin { pkg = zsh-abbr; }) + (mkZshPlugin { pkg = zsh-fzf-tab; }) + (mkZshPlugin { pkg = zsh-autoenv; }) + (mkZshPlugin { pkg = zsh-autopair; }) + (mkZshPlugin { pkg = zsh-nix-shell; }) + (mkZshPlugin { pkg = zsh-completions; }) + (mkZshPlugin { pkg = zsh-you-should-use; }) + (mkZshPlugin { pkg = zsh-autosuggestions; }) + (mkZshPlugin { pkg = zsh-navigation-tools; }) + (mkZshPlugin { pkg = zsh-fzf-history-search; }) + (mkZshPlugin { pkg = zsh-fast-syntax-highlighting; }) + (mkZshPlugin { pkg = zsh-history-substring-search; }) + ]; + + oh-my-zsh = { + enable = true; + plugins = [ + "argocd" + "direnv" + "git" + "golang" + "helm" + "httpie" + "kubectl" + "nomad" + "pass" + "podman" + "ssh-agent" + "systemd" + "terraform" + "vault" + ]; + }; + + history = { + extended = true; + ignoreDups = true; + expireDuplicatesFirst = true; + }; + }; +} diff --git a/modules/users/personal/crstl/window-manager/dunst.nix b/modules/users/personal/crstl/window-manager/dunst.nix new file mode 100644 index 0000000..c745112 --- /dev/null +++ b/modules/users/personal/crstl/window-manager/dunst.nix @@ -0,0 +1,50 @@ +{ + services.dunst = { + enable = true; + settings = { + global = { + markup = "yes"; + plain_text = "no"; + sort = "yes"; + indicate_hidden = "yes"; + alignment = "left"; + bounce_freq = 0; + show_age_threshold = 1; + word_wrap = "yes"; + ignore_newline = "no"; + stack_duplicates = "yes"; + hide_duplicates_count = "no"; + shrink = "no"; + idle_threshold = 0; + transparency = 5; + monitor = "keyboard"; + follow = "mouse"; + sticky_history = "yes"; + history_length = 15; + show_indicators = "yes"; + line_height = 5; + separator_height = 1; + padding = 5; + horizontal_padding = 5; + startup_notification = true; + icon_position = "right"; + max_icon_size = 80; + frame_width = 3; + }; + shortcuts = { + close = "ctrl+space"; + close_all = "ctrl+shift+space"; + context = "mod4+u"; + }; + urgency_low = { + timeout = 3; + }; + urgency_normal = { + timeout = 5; + }; + urgency_critical = { + timeout = 10; + }; + }; + }; +} diff --git a/modules/users/personal/crstl/window-manager/rofi.nix b/modules/users/personal/crstl/window-manager/rofi.nix new file mode 100644 index 0000000..e98aee8 --- /dev/null +++ b/modules/users/personal/crstl/window-manager/rofi.nix @@ -0,0 +1,51 @@ +{ lib +, pkgs +, config +, ... +}: +let + # https://github.com/adi1090x/rofi + style = "4"; + type = "2"; + color = "onedark"; + + rofi-themes-adi1090x = pkgs.stdenv.mkDerivation { + name = "rofi-themes-adi1090x"; + src = pkgs.fetchFromGitHub { + owner = "adi1090x"; + repo = "rofi"; + rev = "ef71554d8b7097cbce1953f56d2d06f536a5826f"; + sha256 = "sha256-RePXizq3I7+u1aJMswOhotIqTVdPhaAGZQqn51lg2jY="; + }; + installPhase = "mkdir -p $out; cp -R * $out/"; + }; + theme = "adi1090x-${style}-${type}-${color}"; +in +{ + home.file = { + "${config.xdg.configHome}/rofi/themes/${theme}.rasi" = { + source = "${rofi-themes-adi1090x}/files/launchers/type-${type}/style-${style}.rasi"; + }; + "${config.xdg.configHome}/rofi/themes/shared/colors.rasi" = { + source = "${rofi-themes-adi1090x}/files/launchers/type-${type}/shared/colors.rasi"; + }; + "${config.xdg.configHome}/rofi/themes/shared/fonts.rasi" = { + source = "${rofi-themes-adi1090x}/files/launchers/type-${type}/shared/fonts.rasi"; + }; + "${config.xdg.configHome}/rofi/colors/${color}.rasi" = { + source = "${rofi-themes-adi1090x}/files/colors/${color}.rasi"; + }; + }; + + + programs.rofi = { + enable = true; + terminal = "${pkgs.alacritty}/bin/alacritty"; + theme = lib.mkForce theme; + extraConfig = { + monitor = -1; + # font = osConfig.stylix.fonts.monospace.name; + modi = "window,drun,run,ssh"; + }; + }; +} diff --git a/modules/users/personal/crstl/window-manager/sway.nix b/modules/users/personal/crstl/window-manager/sway.nix new file mode 100644 index 0000000..f770561 --- /dev/null +++ b/modules/users/personal/crstl/window-manager/sway.nix @@ -0,0 +1,355 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ + swayr # A window switcher (and more) for sway + + wdisplays # A graphical application for configuring displays in Wayland compositors + + bemenu # wayland clone of dmenu + mako # notification system developed by swaywm maintainer + #wpaperd # Minimal wallpaper daemon for Wayland + oguri # A very nice animated wallpaper daemon for Wayland compositors + + wl-clipboard # wl-copy and wl-paste for copy/paste from stdin / stdout + clipman # A simple clipboard manager for Wayland + xclip # Tool to access the X clipboard from a console application + xsel # Command-line program for getting and setting the contents of the X selection + + grim # screenshot functionality + slurp # screenshot functionality + + brightnessctl # This program allows you read and control device brightness + playerctl # ommand-line utility and library for controlling media players that implement MPRIS + + wev + ]; + + wayland.windowManager.sway = { + enable = true; + xwayland = true; + wrapperFeatures.gtk = true; + swaynag.enable = true; + + systemd = { + enable = true; + xdgAutostart = true; + }; + + config = rec { + bars = [ ]; + assigns = { }; + + keybindings = { + "${modifier}+1" = "workspace number 1"; + "${modifier}+2" = "workspace number 2"; + "${modifier}+3" = "workspace number 3"; + "${modifier}+4" = "workspace number 4"; + "${modifier}+5" = "workspace number 5"; + "${modifier}+6" = "workspace number 6"; + "${modifier}+7" = "workspace number 7"; + "${modifier}+8" = "workspace number 8"; + "${modifier}+9" = "workspace number 9"; + "${modifier}+a" = "focus parent"; + "${modifier}+d" = menu; + "${modifier}+e" = "exec ${pkgs.swaynag-battery}/bin/swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'"; + "${modifier}+f" = "fullscreen toggle"; + "${modifier}+l" = "exec ${pkgs.swaylock}/bin/swaylock"; + "${modifier}+r" = "mode resize"; + "${modifier}+y" = "floating disable"; + "${modifier}+x" = "floating enable"; + "${modifier}+s" = "layout stacking"; + "${modifier}+u" = "layout toggle split"; + "${modifier}+v" = "splitv"; + "${modifier}+h" = "splith"; + "${modifier}+w" = "layout tabbed"; + "${modifier}+Left" = "focus left"; + "${modifier}+Right" = "focus right"; + "${modifier}+Up" = "focus up"; + "${modifier}+Down" = "focus down"; + "${modifier}+minus" = "scratchpad show"; + "${modifier}+space" = "focus mode_toggle"; + "${modifier}+Return" = terminal; + "${modifier}+Print" = "exec ${pkgs.grim}/bin/grim ~/screenshot_$(date +%Y%m%d_%H%M%S).png"; + "${modifier}+Shift+1" = "move container to workspace number 1"; + "${modifier}+Shift+2" = "move container to workspace number 2"; + "${modifier}+Shift+3" = "move container to workspace number 3"; + "${modifier}+Shift+4" = "move container to workspace number 4"; + "${modifier}+Shift+5" = "move container to workspace number 5"; + "${modifier}+Shift+6" = "move container to workspace number 6"; + "${modifier}+Shift+7" = "move container to workspace number 7"; + "${modifier}+Shift+8" = "move container to workspace number 8"; + "${modifier}+Shift+9" = "move container to workspace number 9"; + "${modifier}+Shift+Left" = "move left"; + "${modifier}+Shift+Right" = "move right"; + "${modifier}+Shift+Up" = "move up"; + "${modifier}+Shift+Down" = "move down"; + "${modifier}+Shift+space" = "floating toggle"; + "${modifier}+Shift+minus" = "move scratchpad"; + "${modifier}+Shift+q" = "kill"; + "${modifier}+Shift+r" = "reload"; + "${modifier}+Shift+s" = "exec ${pkgs.systemd}/bin/systemctl suspend"; + + "Ctrl+${modifier}+Left " = "workspace prev"; + "Ctrl+${modifier}+Right" = "workspace next"; + + "XF86AudioLowerVolume" = "exec ${pkgs.pulseaudioFull}/bin/pactl set-sink-volume @DEFAULT_SINK@ -5%"; + "XF86AudioRaiseVolume" = "exec ${pkgs.pulseaudioFull}/bin/pactl set-sink-volume @DEFAULT_SINK@ +5%"; + "XF86AudioMute" = "exec ${pkgs.pulseaudioFull}/bin/pactl set-sink-mute @DEFAULT_SINK@ toggle"; + + "XF86AudioPlay" = "exec ${pkgs.playerctl}/bin/playerctl play-pause"; + "XF86AudioPause" = "exec ${pkgs.playerctl}/bin/playerctl play-pause"; + + "XF86AudioNext" = "exec ${pkgs.playerctl}/bin/playerctl next"; + "XF86AudioPrev" = "exec ${pkgs.playerctl}/bin/playerctl previous"; + + "XF86AudioMicMute" = "exec ${pkgs.ponymix}/bin/ponymix -t source toggle"; + + "XF86MonBrightnessDown" = "exec ${pkgs.brightnessctl}/bin/brightnessctl set 5%-"; + "XF86MonBrightnessUp" = "exec ${pkgs.brightnessctl}/bin/brightnessctl set 5%+"; + }; + + modifier = "Mod4"; + menu = "exec ${pkgs.rofi}/bin/rofi -show drun"; + terminal = "exec ${pkgs.kitty}/bin/kitty"; + keycodebindings = { }; + + up = "e"; + down = "n"; + left = "h"; + right = "i"; + + window = { + border = 5; + commands = [ + # swaymsg -t get_tree + { + criteria.app_id = "VirtualBox Machine"; + command = "floating enable"; + } + { + criteria.app_id = "io.elementary.calendar"; + command = "floating enable"; + } + { + criteria.app_id = "OpenSnitch*"; + command = "floating enable"; + } + { + criteria.app_id = "io.elementary.appcenter"; + command = "floating enable"; + } + { + criteria.app_id = "io.elementary.calculator"; + command = "floating enable"; + } + { + criteria.app_id = "io.elementary.files"; + command = "floating enable"; + } + { + criteria.app_id = "io.elementary.photos"; + command = "floating enable"; + } + { + criteria.app_id = "io.elementary.screenshot"; + command = "floating enable"; + } + { + criteria.app_id = "io.elementary.switchboard"; + command = "floating enable"; + } + { + criteria.app_id = "evince"; + command = "floating enable"; + } + { + criteria.app_id = "file-roller"; + command = "floating enable"; + } + { + criteria.app_id = ".blueman-manager-wrapped"; + command = "floating enable"; + } + { + criteria.app_id = "Alacritty"; + command = "opacity set 0.9"; + } + { + criteria.app_id = "Blueman-manager"; + command = "floating enable"; + } + { + criteria.app_id = "Bluetooth-wizard"; + command = "floating enable"; + } + { + criteria.app_id = "cantata"; + command = "floating enable"; + } + { + criteria.app_id = "com.nextcloud.desktopclient.nextcloud"; + command = "floating enable"; + } + { + criteria.app_id = "Element"; + command = "floating enable"; + } + { + criteria.app_id = "Evince"; + command = "floating enable"; + } + { + criteria.app_id = "Evolution-alarm-notify"; + command = "floating enable"; + } + { + criteria.app_id = "Evolution"; + command = "floating enable"; + } + { + criteria.app_id = "Fluffychat"; + command = "floating enable"; + } + { + criteria.app_id = "gnome-calculator"; + command = "floating enable"; + } + { + criteria.app_id = "Jitsi"; + command = "floating enable"; + } + { + criteria.app_id = "MPlayer"; + command = "floating enable"; + } + { + criteria.app_id = "Nautilus"; + command = "floating enable"; + } + { + criteria.app_id = "nm-connection-editor"; + command = "floating enable"; + } + { + criteria.app_id = "org.kde.kdeconnect.app"; + command = "floating enable"; + } + { + criteria.app_id = "org.kde.kdeconnect.sms"; + command = "floating enable"; + } + { + criteria.app_id = "org.kde.kdeconnect-indicator"; + command = "floating enable"; + } + { + criteria.app_id = "org.kde.kdeconnect.handler"; + command = "floating enable"; + } + { + criteria.app_id = "pavucontrol"; + command = "floating enable"; + } + { + criteria.app_id = "Pgadmin3"; + command = "floating enable"; + } + { + criteria.app_id = "Qemu-system-x86_64"; + command = "floating enable"; + } + { + criteria.app_id = "qtpass"; + command = "floating enable"; + } + { + criteria.app_id = "Shotwell"; + command = "floating enable"; + } + { + criteria.app_id = "Simple-scan"; + command = "floating enable"; + } + { + criteria.app_id = "Simplescreenrecorder"; + command = "floating enable"; + } + { + criteria.app_id = "telegramdesktop"; + command = "floating enable"; + } + { + criteria.app_id = "Thunar"; + command = "floating enable"; + } + { + criteria.app_id = "transmission-gtk"; + command = "floating enable"; + } + { + criteria.app_id = "virt-manager"; + command = "floating enable"; + } + { + criteria.app_id = "Wireshark"; + command = "floating enable"; + } + { + criteria.app_id = "X2GoAgent"; + command = "floating enable"; + } + { + criteria.app_id = "x2goclient"; + command = "floating enable"; + } + { + criteria.app_id = "org.gnome.Hamster.GUI"; + command = "floating enable"; + } + { + criteria.class = "Signal"; + command = "floating enable"; + } + { + criteria.app_id = "org.gnome.Calendar"; + command = "floating enable"; + } + { + criteria.app_id = "org.pipewire.Helvum"; + command = "floating enable"; + } + { + criteria.app_id = "org.gnome.Software"; + command = "floating enable"; + } + ]; + hideEdgeBorders = "none"; + titlebar = false; + }; + + workspaceLayout = "default"; + + output = { + "*" = { + # bg = "/home/crstl/Pictures/mems/JOM Optical Switches-920.jpg fill"; + }; + }; + + input = { + "type:keyboard" = { + xkb_layout = "de"; + }; + }; + }; + + # extraConfig = '' + # include /etc/sway/config.d/* + + # exec ${pkgs.swayidle}/bin/swayidle -w \ + # timeout 300 "swaylock -f" \ + # timeout 300 'swaymsg "output * dpms off"' \ + # resume 'swaymsg "output * dpms on"' \ + # before-sleep "swaylock -f" + # ''; + }; +} diff --git a/modules/users/personal/crstl/window-manager/swayidle.nix b/modules/users/personal/crstl/window-manager/swayidle.nix new file mode 100644 index 0000000..cd39894 --- /dev/null +++ b/modules/users/personal/crstl/window-manager/swayidle.nix @@ -0,0 +1,35 @@ +{ pkgs, ... }: +{ + services.swayidle = { + enable = true; + events = [ + { + event = "before-sleep"; + command = "${pkgs.swaylock}/bin/swaylock -efF"; + } + { + event = "after-resume"; + command = ''${pkgs.sway}/bin/swaymsg "output * dpms on"''; + } + { + event = "lock"; + command = "${pkgs.swaylock}/bin/swaylock -efF"; + } + ]; + timeouts = [ + { + timeout = 270; + command = ''${pkgs.libnotify}/bin/notify-send -t 30000 -- "Screen will lock in 30 seconds"''; + } + { + timeout = 300; + command = "${pkgs.swaylock}/bin/swaylock -efF"; + } + { + timeout = 600; + command = ''${pkgs.sway}/bin/swaymsg "output * dpms off"''; + resumeCommand = ''${pkgs.sway}/bin/swaymsg "output * dpms on"''; + } + ]; + }; +} diff --git a/modules/users/personal/crstl/window-manager/waybar.nix b/modules/users/personal/crstl/window-manager/waybar.nix new file mode 100644 index 0000000..70a0345 --- /dev/null +++ b/modules/users/personal/crstl/window-manager/waybar.nix @@ -0,0 +1,209 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ font-awesome ]; + + programs.waybar = { + enable = true; + + # package = pkgs.waybar.override {pulseSupport = true;}; + + systemd = { + enable = true; + target = "graphical-session.target"; + }; + + # font-family: "${osConfig.stylix.fonts.monospace.name}"; + style = '' + * { + font-size: 14px; + border: none; + border-radius: 0; + min-height: 0; + } + ''; + + settings = [ + { + gtk-layer-shell = true; + + layer = "top"; + height = 30; + + tray = { + icon-size = 20; + spacing = 10; + }; + + modules-left = [ + "sway/workspaces" + "sway/mode" + "sway/scratchpad" + "sway/window" + ]; + + modules-center = [ + "custom/launcher" + "clock" + "custom/lock" + "custom/power-menu" + "wireplumber" + ]; + + modules-right = [ + "mpd" + "network" + "battery" + "backlight" + "cpu" + "memory" + "disk" + "temperature" + "tray" + ]; + + "custom/launcher" = { + format = " ❄ "; + on-click = "${pkgs.rofi}/bin/rofi -show drun &"; + }; + + "custom/lock" = { + format = "  "; + on-click = "${pkgs.swaylock}/bin/swaylock"; + tooltip = false; + }; + + "custom/power-menu" = { + format = " ⏻ "; + on-click = "${pkgs.systemd}/bin/loginctl terminate-user $USER"; + }; + + clock = { + format = "{:%d.%m.%Y | %H:%M}"; + tooltip-format = "{calendar}"; + on-click = "${pkgs.gnome.gnome-calendar}/bin/gnome-calendar"; + }; + + battery = { + format = " {icon} {capacity} %"; + format-alt = "{icon} {time}"; + format-charging = " {capacity} %"; + format-discharging = "{icon} {capacity} %"; + format-plugged = " {capacity} %"; + format-icons = [ + "" + "" + "" + "" + "" + ]; + interval = 10; + states = { + good = 80; + warning = 20; + critical = 10; + }; + tooltip = true; + on-click = "${pkgs.gnome.gnome-power-manager}/bin/gnome-power-manager"; + }; + + cpu = { + format = " {usage} %"; + states = { + warning = 70; + critical = 90; + }; + tooltip = true; + interval = 1; + }; + + temperature = { + format = " {temperatureC} °C"; + }; + + memory = { + format = " {percentage} %"; + tooltip-format = "{percentage}% used of {total} GB"; + states = { + warning = 70; + critical = 90; + }; + tooltip = true; + interval = 1; + }; + + disk = { + format = "󰋊 {percentage_free} %"; + path = "/home"; + states = { + warning = 70; + critical = 90; + }; + interval = 1; + tooltip = true; + tooltip-format = "{percentage_free} % are {free} of {total} GB"; + on-click = "${pkgs.gnome.gnome-disk-utility}/bin/gnome.gnome-disk-utility"; + }; + + network = { + format-alt = "{ipaddr}/{cidr}"; + format-disconnected = "⚠ Disconnected"; + format-ethernet = " {ifname}: {ipaddr}/{cidr}"; + format-linked = " {ifname} (No IP)"; + format-wifi = " {essid} ({signalStrength} %)"; + on-click = "${pkgs.networkmanagerapplet}/bin/nm-connection-editor"; + tooltip = true; + interval = 1; + }; + + pulseaudio = { + format = " {icon} {volume} %"; + format-bluetooth = " {icon} {volume} %"; + format-bluetooth-muted = " {icon}"; + format-muted = " {icon}"; + format-source = " {volume} %"; + format-source-muted = " {icon}"; + on-click = "${pkgs.pavucontrol}/bin/pavucontrol"; + on-scroll-up = "${pkgs.ponymix}/bin/ponymix increase 1"; + on-scroll-down = "${pkgs.ponymix}/bin/ponymix decrease 1"; + }; + + wireplumber = { + format = " {icon} {volume} %"; + format-muted = " {icon}"; + format-source = " {volume} %"; + format-source-muted = " {icon}"; + on-click = "${pkgs.pavucontrol}/bin/pavucontrol"; + on-click-right = "${pkgs.helvum}/bin/helvum"; + on-scroll-up = "${pkgs.ponymix}/bin/ponymix increase 1"; + on-scroll-down = "${pkgs.ponymix}/bin/ponymix decrease 1"; + }; + + mpd = { + format-icons = [ "🎜" ]; + on-click = "${pkgs.cantata}/bin/cantata"; + }; + + backlight = { + format = "{icon} {percent} %"; + format-icons = [ + "" + "" + ]; + on-scroll-up = "${pkgs.brillo}/bin/brillo -e -A 0.5"; + on-scroll-down = "${pkgs.brillo}/bin/brillo -e -U 0.5"; + device = "intel_backlight"; + }; + + "wlr/workspaces" = { + all-outputs = true; + format = "{icon}"; + format-icons = { + active = " 󰮯"; + default = ""; + }; + on-click = "activate"; + }; + } + ]; + }; +} diff --git a/modules/users/system/automat/default.nix b/modules/users/system/automat/default.nix new file mode 100644 index 0000000..a4d3ac9 --- /dev/null +++ b/modules/users/system/automat/default.nix @@ -0,0 +1,45 @@ +{ config, pkgs, lib, ... }: +{ + age.secrets.sshPrivateAutomat = { + file = ./ssh-private.age; + owner = "${config.users.users.automat.group}"; + }; + + users = { + users.automat = { + uid = lib.mkForce 1080; + group = "automat"; + description = lib.mkForce "Automat build user"; + createHome = true; + home = "/var/lib/automat"; + extraGroups = + [ "users" ] + ++ lib.optionals config.virtualisation.libvirtd.enable [ "libvirtd" ] + ++ lib.optionals config.virtualisation.docker.enable [ "docker" ] + ++ lib.optionals config.virtualisation.podman.enable [ "podman" ]; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMm1kAmSNQBTBhhod951FNhPwXeIEz9It7NmHZ2d1LqJ" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPGG175tUqyZmN5a2ImRrEhZA5VtKdyxQMPJmymNCxGd" + ]; + isNormalUser = true; + shell = pkgs.bashInteractive; + }; + + groups.automat.gid = lib.mkForce config.users.users.automat.uid; + }; + + nix.settings.trusted-users = [ "automat" ]; + + services.displayManager.hiddenUsers = [ config.users.users.automat.name ]; + + home-manager = { + users.automat = { + home = { + username = config.users.users.automat.name; + stateVersion = "22.05"; + }; + + programs.home-manager.enable = true; + }; + }; +} diff --git a/modules/users/system/automat/ssh-private.age b/modules/users/system/automat/ssh-private.age new file mode 100644 index 0000000..16f6f48 Binary files /dev/null and b/modules/users/system/automat/ssh-private.age differ diff --git a/modules/users/system/root/default.nix b/modules/users/system/root/default.nix new file mode 100644 index 0000000..780d797 --- /dev/null +++ b/modules/users/system/root/default.nix @@ -0,0 +1,14 @@ +{ config, ... }: +{ + age.secrets.passwordRoot.file = ./password.age; + + users.users.root = { + openssh.authorizedKeys.keys = config.users.users.crstl.openssh.authorizedKeys.keys; + hashedPasswordFile = config.age.secrets.passwordRoot.path; + }; + + home-manager.users.root.home = { + username = config.users.users.root.name; + stateVersion = "23.11"; + }; +} diff --git a/modules/users/system/root/password.age b/modules/users/system/root/password.age new file mode 100644 index 0000000..b2f4e43 Binary files /dev/null and b/modules/users/system/root/password.age differ diff --git a/modules/users/system/service.nix b/modules/users/system/service.nix new file mode 100644 index 0000000..70686a7 --- /dev/null +++ b/modules/users/system/service.nix @@ -0,0 +1,30 @@ +{ config, pkgs, ... }: +{ + users = { + users.service = { + uid = 1010; + extraGroups = [ "wheel" ]; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIClhBg2rQEhXMkM97dRrWGAm94I1dnI553qsk5LD9nH4" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKwyxpc0pVB46j1k5VCSabvI4TUADvAabnxlE5+D5o2l" + ]; + shell = pkgs.bashInteractive; + isNormalUser = true; + }; + + groups.service.gid = config.users.users.service.uid; + }; + + home-manager = { + users.service = { + home = { + username = config.users.users.service.name; + stateVersion = "22.05"; + }; + + programs.home-manager.enable = true; + }; + }; + + services.displayManager.hiddenUsers = [ config.users.users.service.name ]; +} diff --git a/nix/deploy.nix b/nix/deploy.nix new file mode 100644 index 0000000..7ad80a0 --- /dev/null +++ b/nix/deploy.nix @@ -0,0 +1,27 @@ +{ inputs, ... }: +let + inherit (inputs) self deploy-rs nixpkgs; + inherit (nixpkgs) lib; + + genNode = + hostName: nixosCfg: + let + inherit (self.hosts.${hostName}) address hostPlatform remoteBuild; + inherit (deploy-rs.lib.${hostPlatform}) activate; + in + { + inherit remoteBuild; + hostname = address; + profiles.system.path = activate.nixos nixosCfg; + }; +in +{ + flake.deploy = { + # autoRollback = true; + # magicRollback = true; + autoRollback = false; + magicRollback = false; + user = "root"; + nodes = lib.mapAttrs genNode (self.nixosConfigurations or { }); + }; +} diff --git a/nix/devshell.nix b/nix/devshell.nix new file mode 100644 index 0000000..1be7473 --- /dev/null +++ b/nix/devshell.nix @@ -0,0 +1,291 @@ +{ self, lib, inputs, ... }: +{ + imports = with inputs; [ + git-hooks.flakeModule + treefmt-nix.flakeModule + devenv.flakeModule + devshell.flakeModule + flake-root.flakeModule + ]; + + perSystem = { self', inputs', pkgs, config, ... }: + { + formatter = config.treefmt.build.wrapper; + + pre-commit = { + inherit pkgs; + check.enable = true; + settings = { + hooks = { + treefmt.enable = true; + nil.enable = true; + statix.enable = true; + deadnix.enable = true; + shellcheck.enable = true; + }; + excludes = [ "flake.lock" ]; + }; + }; + + treefmt = { + projectRootFile = "flake.nix"; + programs = { + deadnix.enable = true; + deadnix.no-lambda-pattern-names = true; + nixpkgs-fmt.enable = true; + shellcheck.enable = true; + statix.enable = true; + }; + }; + + devShells = { + default = pkgs.mkShell { + name = "srx.nix.digital"; + inputsFrom = [ + config.flake-root.devShell + self'.devShells.commands + self'.devShells.nix + self'.devShells.k8s + self'.devShells.opentofu + ]; + packages = with pkgs; [ + gitFull + git-lfs + treefmt + act + actionlint + shellcheck + bind + knot-dns + wireguard-tools + ipcalc + minio-client + ]; + + shellHook = '' + ${config.pre-commit.installationScript} + ''; + }; + + nix = pkgs.mkShell { + packages = with pkgs; [ + (pkgs.vault-push-approle-envs self') + (pkgs.vault-push-approles self') + agenix + deadnix + nil + nix-fast-build + sops + statix + vault + ]; + }; + + k8s = pkgs.mkShell { + packages = with pkgs; [ + k3d + kubectl + kubernetes-helm + ]; + }; + }; + + devshells.commands = { + motd = '' + $(echo -e "\n") + {202}SRX Platform Development Environment{reset} + $(type -p menu &>/dev/null && menu) + ''; + + commands = [ + { + name = "reload"; + command = "direnv reload"; + help = "Reload the local environment."; + category = "development"; + } + { + name = "fmt"; + command = "nix fmt"; + help = "Run reformating with nix flake."; + category = "development"; + } + { + name = "generate"; + command = "${inputs'.nixos-generators.packages.nixos-generate}/bin/nixos-generate $@"; + help = "Generate NixOS configuration with nixos-generators."; + category = "development"; + } + { + name = "health"; + command = "${lib.getExe pkgs.nix-health}"; + help = "Checking the health of your Nix setup."; + category = "nix"; + } + { + name = "list"; + command = "nix flake show"; + help = "Run nix flake cheshow."; + category = "nix"; + } + { + name = "check"; + command = "nix flake check"; + help = "Run nix flake check."; + category = "nix"; + } + { + name = "build"; + command = "nix build"; + help = "Run nix flake build."; + category = "nix"; + } + { + name = "run"; + command = "nix run .\#run-qemu-vm -- $@"; + help = "Run host build in a qemu vm."; + category = "nix"; + } + { + name = "repl"; + command = "nix repl -f ."; + help = "Evaluate expressions interactive with Nix repl."; + category = "nix"; + } + { + name = "inspect"; + command = "${lib.getExe pkgs.nix-inspect}"; + help = "Inspect NixOS config and Nix expressions."; + category = "nix"; + } + { + name = "cve"; + command = "nix build && ${lib.getExe pkgs.vulnix} ./result"; + help = "Run NixOS security scanner with vulnix."; + category = "security"; + } + { + name = "secrets"; + command = "${pkgs.trivy}/bin/trivy fs ."; + help = "All-in-one security scanner with trivy."; + category = "security"; + } + { + name = "age"; + command = "${pkgs.agenix}/bin/agenix $@"; + help = "Manage NixOS secrets with agenix."; + category = "operations"; + } + { + name = "infect"; + command = "${inputs'.nixos-anywhere.packages.nixos-anywhere}/bin/nixos-anywhere $@"; + help = "Install NixOS everywhere via ssh."; + category = "operations"; + } + { + name = "deploy"; + command = "${pkgs.deploy-rs.deploy-rs}/bin/deploy $@"; + help = "Deploy NixOS remote machines with deploy-rs."; + category = "operations"; + } + { + name = "show"; + command = "terranix --pkgs /run/current-system/nixpkgs terranix/default.nix"; + help = "Show terranix state."; + category = "terraform"; + } + { + name = "validate"; + command = "nix run .\#tf-validate"; + help = "Run terraform validate."; + category = "terraform"; + } + { + name = "apply"; + command = "nix run .\#tf-apply"; + help = "Run terraform apply."; + category = "terraform"; + } + { + name = "destroy"; + command = "nix run .\#tf-destroy"; + help = "Run terraform destroy."; + category = "terraform"; + } + { + name = "state"; + command = "nix run .\#tf-state -- $@"; + help = "Manage terraform state."; + category = "terraform"; + } + ]; + }; + + apps = { + run-qemu-vm = { + type = "app"; + program = toString (pkgs.writers.writeBash "run-qemu-vm" '' + if [[ ! -z "$@" ]]; then + nixos-rebuild build-vm --flake .#$@ + export QEMU_NET_OPTS="hostfwd=tcp::2221-:22" + ./result/bin/run-$@-vm + else + echo "Usage: "$0" " + exit 1 + fi + ''); + }; + + nix-upgrades = { + type = "app"; + program = toString (pkgs.writers.writeBash "nix-upgrades" '' + set -eou pipefail + + NORMAL="\033[0m" + RED="\033[0;31m" + YELLOW="\033[0;33m" + GREEN="\033[0;32m" + SKULL="💀" + CHECK="✅" + WARNING="⚠️" + FIRE="🔥" + MAG="🔍" + + echo + echo -e "$YELLOW$MAG Scanning for upgradable hosts...$NORMAL" + echo + + ${lib.concatMapStringsSep "\n" (host: + let + inherit (self.hosts.${host}) address; + in lib.optionalString (address != null) '' + echo -n -e "${host}: $RED" + RUNNING=$(ssh "${address}" "readlink /run/current-system") + if [ $? = 0 ] && [ -n "$RUNNING" ]; then + CURRENT=$(nix eval --raw ".#nixosConfigurations.${host}.config.system.build.toplevel" 2>/dev/null) + RUNNING_VER=$(basename $RUNNING|rev|cut -d - -f 1|rev) + RUNNING_DATE=$(echo $RUNNING_VER|cut -d . -f 3) + CURRENT_VER=$(basename $CURRENT|rev|cut -d - -f 1|rev) + CURRENT_DATE=$(echo $CURRENT_VER|cut -d . -f 3) + + if [ "$RUNNING" = "$CURRENT" ]; then + echo -e "$GREEN$CHECK Current: $NORMAL $RUNNING_VER" + elif [ $RUNNING_DATE -gt $CURRENT_DATE ]; then + echo -e "$GREEN$FIRE Newer: $NORMAL $RUNNING_VER > $CURRENT_VER" + elif [ "$RUNNING_VER" = "$CURRENT_VER" ]; then + echo -e "$YELLOW$WARNING Modified: $NORMAL $RUNNING_VER" + elif [ -n "$RUNNING_VER" ]; then + echo -e "$RED$SKULL Outdated: $NORMAL $RUNNING_VER < $CURRENT_VER" + else + echo -e "$RED$SKULL Error: $NORMAL $RUNNING_VER" + fi + else + echo -e "$RED$SKULL SSH Connection Failed$NORMAL" + fi + echo -n -e "$NORMAL" + '') (builtins.attrNames self.nixosConfigurations)} + ''); + }; + }; + }; +} diff --git a/nix/home-manager.nix b/nix/home-manager.nix new file mode 100644 index 0000000..cba98b8 --- /dev/null +++ b/nix/home-manager.nix @@ -0,0 +1,49 @@ +{ withSystem, inputs, ... }: +let + inherit (inputs) self home-manager nixpkgs; + inherit (nixpkgs) lib; + + genModules = hostName: { homeDirectory, ... }: { config, ... }: { + imports = [ (../hosts + "/${hostName}") ]; + nix.registry = { + nixpkgs.flake = nixpkgs; + p.flake = nixpkgs; + }; + + home = { + inherit homeDirectory; + sessionVariables.NIX_PATH = lib.concatStringsSep ":" [ "nixpkgs=${config.xdg.dataHome}/nixpkgs" ]; + }; + + xdg = { + dataFile.nixpkgs.source = nixpkgs; + configFile."nix/nix.conf".text = '' + flake-registry = ${config.xdg.configHome}/nix/registry.json + ''; + }; + }; + + genConfiguration = hostName: { hostPlatform, type, ... }@attrs: + withSystem hostPlatform ( + { pkgs, ... }: + home-manager.lib.homeManagerConfiguration { + inherit pkgs; + modules = [ (genModules hostName attrs) ]; + extraSpecialArgs = { + hostType = type; + inherit inputs self; + }; + } + ); +in +{ + flake.homeConfigurations = lib.mapAttrs genConfiguration ( + lib.filterAttrs (_: host: host.type == "home-manager") self.hosts + ); + + perSystem = { lib, self', ... }: { + checks = lib.mapAttrs' + (name: config: lib.nameValuePair "home-manager-${name}" config.activation-script) + (self'.legacyPackages.homeConfigurations or { }); + }; +} diff --git a/nix/hosts.nix b/nix/hosts.nix new file mode 100644 index 0000000..66dd490 --- /dev/null +++ b/nix/hosts.nix @@ -0,0 +1,133 @@ +let + hosts = { + dev-vm = mkHost { + type = "nixos"; + address = "192.168.122.26"; + hostPlatform = "x86_64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEJg26fCklaaX7aakk8YKsBE1cvZmK7BbGRepnlljO0A"; + remoteBuild = false; + }; + srxgp00 = mkHost { + type = "nixos"; + address = "srxgp00.vpn.srx.dev"; + hostPlatform = "x86_64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKTMIY7REnKImy/UZ5SBcFLVywHjNtJB+TkwfnI8oqR3"; + remoteBuild = false; + }; + srxgp01 = mkHost { + type = "nixos"; + address = "srxgp01.vpn.srx.dev"; + hostPlatform = "aarch64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP4z3JIB0cwLTHpek2yXvFiUIzBkQf39Y0XE3tG8/02U"; + remoteBuild = false; + }; + srxgp02 = mkHost { + type = "nixos"; + address = "srxgp02.vpn.srx.dev"; + hostPlatform = "x86_64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILOatQqlVBjRGIK6Y95O73XOkvN6BOnn7xPTKA9olJYZ"; + remoteBuild = false; + }; + srxk8s00 = mkHost { + type = "nixos"; + address = "srxk8s00.vpn.srx.dev"; + hostPlatform = "aarch64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKnculMw+8hP3gix/K4OBqGqrx16Cs2ODxM0V52YXNrT"; + remoteBuild = false; + }; + srxnas00 = mkHost { + type = "nixos"; + address = "srxnas00.vpn.srx.dev"; + hostPlatform = "x86_64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHiUYwPlTez18gwbhWC3sB6LoYmDPz0suTF5n3zEGBhg"; + remoteBuild = false; + }; + srxnas01 = mkHost { + type = "nixos"; + address = "srxnas01.vpn.srx.dev"; + hostPlatform = "x86_64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDUTiU0WPTLF98yla0Mmit6eIfPpcrDKRemjM1VoHc9w"; + remoteBuild = false; + }; + srxws00 = mkHost { + type = "nixos"; + address = "srxws00.vpn.srx.dev"; + hostPlatform = "x86_64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFlG7m82O7W/Btp98ddipBiIvYkXAy1TP3kyRfYuL0aF"; + remoteBuild = false; + }; + srxnb00 = mkHost { + type = "nixos"; + address = "srxnb00.vpn.srx.dev"; + hostPlatform = "x86_64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII+ylR/an6nDQR1CBlWjPnUGf+2JJ9S3APaERFiZ6exT"; + remoteBuild = false; + }; + srxws01 = mkHost { + type = "nixos"; + address = "srxws01.vpn.srx.dev"; + hostPlatform = "x86_64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM54ABNX402t+q3hNKjJc1rhXLJckgCLlaDug4+7nfN2"; + remoteBuild = false; + }; + srxtab00 = mkHost { + type = "nixos"; + address = "srxtab00.vpn.srx.dev"; + hostPlatform = "x86_64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDJf8iY3QMWoJdYibBsTA9CZE+GQluhp/N+0Vxid7nSP"; + remoteBuild = false; + }; + srxmc00 = mkHost { + type = "nixos"; + address = "srxmc00.vpn.srx.dev"; + hostPlatform = "x86_64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGXv0QxmY2C44SvnV3HZd+wBhxc//ox8YhfDnh2L1k4f"; + remoteBuild = false; + }; + srxfdm00 = mkHost { + type = "nixos"; + address = "srxfdm00.vpn.srx.dev"; + hostPlatform = "aarch64-linux"; + pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2Z5iETExjTSn+F1QFwSnyrn5UdSnkn6C+rIM7Dssei"; + remoteBuild = false; + }; + }; + + hasSuffix = + suffix: content: + let + inherit (builtins) stringLength substring; + lenContent = stringLength content; + lenSuffix = stringLength suffix; + in + lenContent >= lenSuffix && substring (lenContent - lenSuffix) lenContent content == suffix; + + mkHost = + { type + , hostPlatform + , address ? null + , pubkey ? null + , homeDirectory ? null + , remoteBuild ? true + , large ? false + , + }: + if type == "nixos" then + assert address != null && pubkey != null; + assert (hasSuffix "linux" hostPlatform); + { inherit type hostPlatform address pubkey remoteBuild large; } + else if type == "darwin" then + assert pubkey != null; + assert (hasSuffix "darwin" hostPlatform); + { inherit type hostPlatform pubkey large; } + else if type == "home-manager" then + assert homeDirectory != null; + { inherit type hostPlatform homeDirectory large; } + else + throw "unknown host type '${type}'"; +in +{ + flake = { + inherit hosts; + }; +} diff --git a/nix/modules.nix b/nix/modules.nix new file mode 100644 index 0000000..a8d6546 --- /dev/null +++ b/nix/modules.nix @@ -0,0 +1,94 @@ +{ self, ... }: +let + inherit (builtins) listToAttrs replaceStrings stringLength substring; + + removeSuffix = suffix: str: + let + sufLen = stringLength suffix; + sLen = stringLength str; + in + if sufLen <= sLen && suffix == substring (sLen - sufLen) sufLen str then + substring 0 (sLen - sufLen) str + else + str; + + exposeModules = baseDir: paths: + let + prefix = stringLength (toString baseDir) + 1; + toPair = path: { + name = replaceStrings [ "/" ] [ "-" ] ( + removeSuffix ".nix" (substring prefix 100000000 (toString path)) + ); + value = path; + }; + in + listToAttrs (map toPair paths); +in +{ + flake = { + modules.nixos = exposeModules ../modules/. [ + ../modules/custom/dns/knot + ../modules/custom/dns/zones + ../modules/filesystems/zfs.nix + ../modules/hardware + ../modules/hardware/bluetooth.nix + ../modules/hardware/cpu/amd.nix + ../modules/hardware/cpu/intel.nix + ../modules/hardware/disk.nix + ../modules/hardware/gpu/amd.nix + ../modules/hardware/gpu/intel.nix + ../modules/hardware/gpu/nvidia.nix + ../modules/hardware/laptop.nix + ../modules/hardware/power.nix + ../modules/hardware/rpi4.nix + ../modules/hardware/security/nitrokey.nix + ../modules/hardware/security/secureboot.nix + ../modules/hardware/security/yubikey.nix + ../modules/hardware/sound/pipewire.nix + ../modules/hardware/sound/pulseaudio.nix + ../modules/roles/core + ../modules/roles/desktop + ../modules/roles/desktop/desktop-manager + ../modules/roles/desktop/desktop-manager/gnome.nix + ../modules/roles/desktop/display-manager + ../modules/roles/desktop/office + ../modules/roles/desktop/system + ../modules/roles/desktop/window-manager + ../modules/roles/media-center + ../modules/roles/nas + ../modules/roles/server + ../modules/roles/workstation + ../modules/services/container + ../modules/services/container/docker.nix + ../modules/services/container/k3s + ../modules/services/container/podman.nix + ../modules/services/database/mysql.nix + ../modules/services/database/postgresql.nix + ../modules/services/dns + ../modules/services/dns/avahi.nix + ../modules/services/dns/knot + ../modules/services/dns/knsupdate.nix + ../modules/services/monitoring + ../modules/services/monitoring/loki.nix + ../modules/services/monitoring/prometheus.nix + ../modules/services/monitoring/promtail.nix + ../modules/services/monitoring/telegraf.nix + ../modules/services/netboot + ../modules/services/netboot/config.nix + ../modules/services/security/clamav + ../modules/services/security/tang + ../modules/services/storage/samba + ../modules/services/storage/syncthing + ../modules/services/virtualisation/libvirt.nix + ../modules/services/virtualisation/microvm.nix + ../modules/services/web/nginx.nix + ../modules/users + ../modules/users/personal/crstl + ../modules/users/system/automat + ../modules/users/system/root + ../modules/users/system/service.nix + ]; + + nixosModules = self.modules.nixos; + }; +} diff --git a/nix/nixos.nix b/nix/nixos.nix new file mode 100644 index 0000000..12110b8 --- /dev/null +++ b/nix/nixos.nix @@ -0,0 +1,40 @@ +{ self, inputs, withSystem, ... }: +let + inherit (inputs) nixpkgs; + inherit (nixpkgs) lib; + + genConfiguration = hostname: { address, hostPlatform, type, ... }: + withSystem hostPlatform ( + { pkgs, ... }: + lib.nixosSystem { + modules = [ + (../hosts + "/${hostname}") + { + nixpkgs.pkgs = pkgs; + nix.registry = { + p.flake = nixpkgs; + nixpkgs.flake = nixpkgs; + }; + nixpkgs.hostPlatform = hostPlatform; + } + ]; + + specialArgs = { + hostType = type; + hostAddress = address; + inherit self inputs; + }; + } + ); +in +{ + flake.nixosConfigurations = lib.mapAttrs genConfiguration ( + lib.filterAttrs (_: host: host.type == "nixos") inputs.self.hosts + ); + + perSystem = { lib, pkgs, system, ... }: { + checks = lib.mapAttrs' + (name: config: lib.nameValuePair "nixos-${name}" config.config.system.build.toplevel) + ((lib.filterAttrs (_: config: config.pkgs.system == system)) self.nixosConfigurations); + }; +} diff --git a/nix/overlay.nix b/nix/overlay.nix new file mode 100644 index 0000000..a9bd412 --- /dev/null +++ b/nix/overlay.nix @@ -0,0 +1,36 @@ +{ inputs, lib, ... }: +let + importLocalOverlay = file: + lib.composeExtensions + (_: _: { __inputs = inputs; }) + (import (../overlays + "/${file}")); + + localOverlays = + lib.mapAttrs' + (f: _: lib.nameValuePair + (lib.removeSuffix ".nix" f) + (importLocalOverlay f) + ) + (builtins.readDir ../overlays); + +in +{ + flake.overlays = { + inherit localOverlays; + + default = lib.composeManyExtensions [ + inputs.agenix.overlays.default + inputs.deploy-rs.overlays.default + inputs.nixvim.overlays.default + inputs.nur.overlay + inputs.vault-secrets.overlays.default + + (final: _prev: { + inherit (inputs.nix-fast-build.packages.${final.stdenv.hostPlatform.system}) nix-fast-build; + inherit (inputs.srx-digital-website.packages.${final.stdenv.hostPlatform.system}) srx-digital; + inherit (inputs.nix-hamburg-website.packages.${final.stdenv.hostPlatform.system}) nix-hamburg; + inherit (inputs.cq-flake.packages.${final.stdenv.hostPlatform.system}) cq-editor; + }) + ]; + }; +} diff --git a/nix/packages.nix b/nix/packages.nix new file mode 100644 index 0000000..1e6900b --- /dev/null +++ b/nix/packages.nix @@ -0,0 +1,40 @@ +{ self, inputs, config, ... }: +{ + flake.hydraJobs = { + inherit (self) checks packages; + }; + + perSystem = { pkgs, self', system, ... }: + let + inherit (config) flake; + inherit (pkgs) lib linkFarm; + nixosDrvs = lib.mapAttrs (_: nixos: nixos.config.system.build.toplevel) flake.nixosConfigurations; + homeDrvs = lib.mapAttrs (_: home: home.activationPackage) flake.homeConfigurations; + hostDrvs = nixosDrvs // homeDrvs; + compatHosts = lib.filterAttrs (_: host: host.hostPlatform == system) flake.hosts; + compatHostDrvs = lib.mapAttrs (name: _: hostDrvs.${name}) compatHosts; + compatHostsFarm = linkFarm "hosts-${system}" (lib.mapAttrsToList (name: path: { inherit name path; }) compatHostDrvs); + packagesAdditional = { inherit (pkgs) nix-fast-build; }; + packagesBlacklist = [ ]; + packages = lib.mapAttrs' (name: lib.nameValuePair "package-${name}") ( + lib.filterAttrs (name: _v: !(builtins.elem name packagesBlacklist)) self'.packages); + in + { + _module.args = { + pkgs = import inputs.nixpkgs { + inherit system; + overlays = [ self.overlays.default ]; + config = { + allowUnfree = true; + allowAliases = true; + }; + }; + }; + + packages = ( + lib.optionalAttrs (compatHosts != { }) { default = compatHostsFarm; } + ) // compatHostDrvs // packagesAdditional; + + checks = packages; + }; +} diff --git a/nix/terranix.nix b/nix/terranix.nix new file mode 100644 index 0000000..8dd2116 --- /dev/null +++ b/nix/terranix.nix @@ -0,0 +1,63 @@ +{ self, lib, nixpkgs, inputs, ... }: +{ + flake.lib.terraform = import ../lib/terraform.nix { inherit self inputs lib nixpkgs; }; + + perSystem = { pkgs, system, inputs', self', ... }: + let + tofuLib = self.lib.terraform { inherit (self'.packages) opentofu; inherit pkgs tufoConfigAst; }; + tufoConfigAst = inputs.terranix.lib.terranixConfigurationAst { + inherit system pkgs; + modules = [ ../terranix ]; + }; + in + { + devShells.opentofu = pkgs.mkShell { + packages = [ + self'.packages.json2nix + self'.packages.opentofu + (inputs'.terranix.packages.terranix.override { nix = pkgs.nixVersions.latest; }) + ]; + }; + + apps = tofuLib.mkApps [ + "init" + "plan" + "apply" + "destroy" + "state" + "import" + ] // { inherit (tofuLib) tf-validate tf2nix; }; + + packages = { + inherit (tofuLib) tf-state; + + opentofu = pkgs.opentofu.withPlugins (tp: [ + tp.github + tp.grafana + tp.hcloud + tp.helm + tp.hydra + tp.keycloak + tp.minio + + (pkgs.opentofu.plugins.mkProvider { + owner = "go-gitea"; + repo = "terraform-provider-gitea"; + rev = "v0.3.0"; + vendorHash = "sha256-+jTenvGCfqI8I3//kc/kCa7kTIyzSGKjJXP6otKJBRA="; + spdx = "MIT"; + hash = "sha256-qUVF3JS3sOisAhgBHvpDsb6rEFXyQTU9Bga1WjetYL0="; + homepage = "https://registry.terraform.io/providers/go-gitea/gitea"; + provider-source-address = "registry.terraform.io/go-gitea/gitea"; + }) + ]); + + json2nix = pkgs.writeScriptBin "json2nix" '' + ${pkgs.python3}/bin/python ${pkgs.fetchurl { + url = "https://gist.githubusercontent.com/Scoder12/0538252ed4b82d65e59115075369d34d/raw/e86d1d64d1373a497118beb1259dab149cea951d/json2nix.py"; + hash = "sha256-ROUIrOrY9Mp1F3m+bVaT+m8ASh2Bgz8VrPyyrQf9UNQ="; + }} $@ + ''; + }; + }; +} diff --git a/overlays/cadquery.nix b/overlays/cadquery.nix new file mode 100644 index 0000000..3bbfcdc --- /dev/null +++ b/overlays/cadquery.nix @@ -0,0 +1,21 @@ +_final: prev: { + opencascade-occt = prev.opencascade-occt_0_17.override { + buildInputs = with prev; [ + tcl + tk + libGL + libGLU + libXext + libXmu + libXi + vtk + xorg.libXt + freetype + freeimage + fontconfig + tbb_2021_11 + rapidjson + glew + ] ++ vtk.buildInputs; + }; +} diff --git a/overlays/nix-latest.nix b/overlays/nix-latest.nix new file mode 100644 index 0000000..f528162 --- /dev/null +++ b/overlays/nix-latest.nix @@ -0,0 +1,18 @@ +final: prev: +let + useLatestNixFor = name: + { inherit name; value = prev.${name}.override { nix = final.nixVersions.latest; }; }; + useLatestNix = names: builtins.listToAttrs (map useLatestNixFor names); +in +(useLatestNix [ + "agenix" + "nix-direnv" + "nix-update" + "nixpkgs-review" +]) // { + # Workaround for electron depending on nix-prefetch-git at build-time via + # prefetch-yarn-deps + nix-prefetch-git = prev.nix-prefetch-git.override { nix = final.nixVersions.latest; }; + nix-prefetch-git-stable = prev.nix-prefetch-git; + prefetch-yarn-deps = prev.prefetch-yarn-deps.override { nix-prefetch-git = final.nix-prefetch-git-stable; }; +} diff --git a/secrets.nix b/secrets.nix new file mode 100644 index 0000000..bf7d263 --- /dev/null +++ b/secrets.nix @@ -0,0 +1,95 @@ +let + inherit (builtins) attrNames attrValues mapAttrs listToAttrs; + hosts = mapAttrs (_: v: v.pubkey) (import ./nix/hosts.nix).flake.hosts; + + srx_signing = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDcf3QwjRB29nYbFTHbtZjiYAwDlLB0tLz8Djo5x/HYg"; + srx_swendel = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB6vk3k1p6YMsGLFQ/xABLYK/VJicywkf1MJawnN7oXU"; + hydra_runner = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDjAHH3dWAxIi0ylYt3lEOnOd/Vx7u91F3ZIs+pIsUEC1BLUgULSiUvYgAI99FAPIbavcn2vSaDmHVFexlVltMY7V+I+F4Q/d96wfaTXq1t33PJUGOcbvBSRzspTJw5hRq6sGV7UPf0givVS0ZL8001S4SydziT/C+z+3EJXhk4RMJT2rkxw7KWFWWSRZYT4YsCcsMDjXyvV1GZXAZnTioIJ+JNi3zepUH0AWu/yhKO2k0drYJ3hzSSfbgehOLM9MXozPu90vHNiff7rw557LtzksJqRNNqIwPGZTcaNwuH/RQF7USe3juutf62fS7PCqoaaVIAhHVWq573VImCizwd42+qBqUgIjhaIJlyUAMQv7cQTnUDZoK8k7/gB3WN7a03bU6NcGpJvLR8HAM9RQCQXqCW2gQDLEnuHHOhHS4XsEovpvu3HigSi8FPLKrDtT/0b7ecmizYR/3IoRqiyE3RgUz+mpPGMKvYxKNQLXF5By0T7n4CWYPFdjVm7nM2APGrm3OHkbVyKKFi95YE0v/7P/8GRlVIKpLYU1DMnmDzEfjNOKokXG3JWTK/ZLkVUUNXuBbjNh8Q0cTUI/4NlgLgMecsNGhfxxr8TehDo/sZoxqhCFAPfyGRCJrIpnLSIxjEZmLRt2/wOxoZeaql4FsRQ7EqA579pGUUYTQCmpC1LQ=="; + + secrets = with hosts; { + "hosts/srxgp00/services/coturn/auth-secret.age" = [ srxgp00 ]; + "hosts/srxgp00/services/dendrite/environment.age" = [ srxgp00 ]; + "hosts/srxgp00/services/dendrite/private-key.age" = [ srxgp00 ]; + "hosts/srxgp00/services/forgejo/mailerPassword.age" = [ srxgp00 ]; + "hosts/srxgp00/services/forgejo/runnerToken.age" = [ srxgp00 ]; + "hosts/srxgp00/services/grafana/oidc-secret.age" = [ srxgp00 ]; + "hosts/srxgp00/services/hedgedoc/environment.age" = [ srxgp00 ]; + "hosts/srxgp00/services/hydra/private-key.age" = [ srxgp00 ]; + "hosts/srxgp00/services/hydra/secrets.age" = [ srxgp00 ]; + "hosts/srxgp00/services/keycloak/databasePassword.age" = [ srxgp00 ]; + "hosts/srxgp00/services/mailserver/mailbox-dmarc-client.age" = [ srxgp00 ]; + "hosts/srxgp00/services/mailserver/mailbox-dmarc.age" = [ srxgp00 ]; + "hosts/srxgp00/services/mailserver/mailbox-Ies6sh.age" = [ srxgp00 ]; + "hosts/srxgp00/services/mailserver/mailbox-Oom7oh.age" = [ srxgp00 ]; + "hosts/srxgp00/services/mailserver/mailbox-Osoo5u.age" = [ srxgp00 ]; + "hosts/srxgp00/services/mailserver/mailbox-ugai0U.age" = [ srxgp00 ]; + "hosts/srxgp00/services/mailserver/mailbox-xaev9B.age" = [ srxgp00 ]; + "hosts/srxgp00/services/minio/user_admin.age" = [ srxgp00 ]; + "hosts/srxgp00/services/minio/user_prometheus.age" = [ srxgp00 ]; + "hosts/srxgp00/services/nextcloud/adminpass.age" = [ srxgp00 ]; + "hosts/srxgp00/services/nextcloud/secrets.age" = [ srxgp00 ]; + "hosts/srxgp00/services/oauth2-proxy/secrets.age" = [ srxgp00 ]; + "hosts/srxgp00/services/openldap/ldap-bind-secret.age" = [ srxgp00 ]; + "hosts/srxgp00/services/openldap/ldap-config-secret.age" = [ srxgp00 ]; + "hosts/srxgp00/services/paperless/password.age" = [ srxgp00 ]; + "hosts/srxgp00/services/plausible/mail.age" = [ srxgp00 ]; + "hosts/srxgp00/services/plausible/password.age" = [ srxgp00 ]; + "hosts/srxgp00/services/plausible/secret.age" = [ srxgp00 ]; + "hosts/srxgp00/services/prometheus/alertmanager-env.age" = [ srxgp00 ]; + "hosts/srxgp00/services/restic/repo_key.age" = [ srxgp00 ]; + "hosts/srxgp00/services/restic/repo_ssh.age" = [ srxgp00 ]; + "hosts/srxgp00/services/vaultwarden/secrets.age" = [ srxgp00 ]; + "hosts/srxnb00/services/restic/repo_key.age" = [ srxnb00 ]; + "hosts/srxnb00/services/restic/repo_ssh.age" = [ srxnb00 ]; + "hosts/srxmc00/cifs_nas.age" = [ srxmc00 ]; + "modules/custom/dns/knot/secrets/notify.age" = [ srxgp00 srxgp01 srxgp02 ]; + "modules/custom/dns/knot/secrets/transfer.age" = [ srxgp00 srxgp01 srxgp02 ]; + "modules/custom/dns/knot/secrets/tsig_xfr.age" = [ srxgp00 srxgp01 srxgp02 ]; + "modules/custom/dns/knot/secrets/update_k8s.age" = [ srxgp00 srxgp01 srxgp02 ]; + "modules/custom/dns/knot/secrets/update_terraform_cicd.age" = [ srxgp00 srxgp01 srxgp02 ]; + "modules/custom/dns/knot/secrets/update_terraform_swendel.age" = [ srxgp00 srxgp01 srxgp02 ]; + "modules/custom/dns/knot/secrets/update.age" = [ srxgp00 srxgp01 srxgp02 ]; + "modules/services/container/k3s/k8s_cluster_token.age" = [ srxk8s00 ]; + "modules/services/container/k3s/k8s_dns_update_rfc2136.age" = [ srxk8s00 ]; + "modules/services/container/k3s/k8s_environment.age" = [ srxk8s00 ]; + "modules/services/container/k3s/k8s_traefik_dashboard.age" = [ srxk8s00 ]; + "modules/roles/server/acme.age" = attrValues hosts; + "modules/users/personal/crstl/password.age" = attrValues hosts; + "modules/users/system/automat/ssh-private.age" = attrValues hosts; + "modules/users/system/root/password.age" = attrValues hosts; + }; + + secrets' = mapAttrs + (_: v: { + publicKeys = [ + srx_signing + srx_swendel + hydra_runner + ] ++ v; + }) + secrets; + + allHostSecret = + secretName: + listToAttrs ( + map + (host: { + name = "hosts/${host}/${secretName}.age"; + value.publicKeys = [ + srx_signing + srx_swendel + hydra_runner + hosts.${host} + ]; + }) + (attrNames hosts) + ); +in +secrets' // +allHostSecret "initrd_hostkey" // +allHostSecret "dns_update" // +allHostSecret "vpn_srx" // +allHostSecret "vpn_ccl" // +allHostSecret "vpn_mvd" // +allHostSecret "wifi_client" // +allHostSecret "clevis" diff --git a/terranix/backend.nix b/terranix/backend.nix new file mode 100644 index 0000000..98c8e28 --- /dev/null +++ b/terranix/backend.nix @@ -0,0 +1,14 @@ +{ + terraform.backend.s3 = { + endpoints.s3 = "https://s3.srx.digital"; + bucket = "terraform-state"; + region = "eu-central-1"; + key = "srx.digital.tfstate"; + + skip_credentials_validation = true; + skip_requesting_account_id = true; + skip_metadata_api_check = true; + skip_region_validation = true; + use_path_style = true; + }; +} diff --git a/terranix/default.nix b/terranix/default.nix new file mode 100644 index 0000000..7483fa3 --- /dev/null +++ b/terranix/default.nix @@ -0,0 +1,16 @@ +{ + terraform.required_version = ">= 1.7"; + + imports = [ + ./backend.nix + ./variables.nix + + ./github + ./gitea + ./hcloud + ./hydra + ./minio + ./keycloak + ./grafana + ]; +} diff --git a/terranix/gitea/curious.bio.nix b/terranix/gitea/curious.bio.nix new file mode 100644 index 0000000..1efd189 --- /dev/null +++ b/terranix/gitea/curious.bio.nix @@ -0,0 +1,109 @@ +{ lib, ... }: +{ + variable.GITEA_MIRROR_TOKEN_CCL = { + type = "string"; + sensitive = true; + }; + + resource = { + gitea_org.gitea-org-curious-bio = { + name = "ccl"; + full_name = "Curious Community Labs e. V."; + location = "Hamburg, Germany"; + website = "https://curious.bio/"; + visibility = "public"; + }; + + gitea_repository = { + gitea-mirror-iot-backend = { + username = lib.tfRef "gitea_org.gitea-org-curious-bio.name"; + name = "iot-backend"; + description = "An Open-Source prototype for collecting, working with and displaying sensor data from MQTT enabled IoT devices. https://wiki.curious.bio/de/Projekte/IoT-Plattform"; + website = "https://code.curious.bio/curious.bio/iot-backend.git"; + migration_clone_address = "https://code.curious.bio/curious.bio/iot-backend.git"; + mirror = true; + has_issues = false; + has_wiki = false; + private = false; + depends_on = [ "gitea_org.gitea-org-curious-bio" ]; + }; + + gitea-mirror-infra-nix = { + username = lib.tfRef "gitea_org.gitea-org-curious-bio.name"; + name = "infra.nix"; + description = "CCL NixOS config"; + website = "https://code.curious.bio/curious.bio/infra.nix"; + migration_clone_address = "https://code.curious.bio/curious.bio/infra.nix"; + migration_service = "gitea"; + migration_service_auth_token = lib.tfRef "var.GITEA_MIRROR_TOKEN_CCL"; + mirror = true; + has_issues = false; + has_wiki = false; + private = true; + depends_on = [ "gitea_org.gitea-org-curious-bio" ]; + }; + + gitea-mirror-smart-energy-monitor = { + username = lib.tfRef "gitea_org.gitea-org-curious-bio.name"; + name = "smart-energy-monitor"; + description = "A smart energy monitor to measure the power consumption https://wiki.curious.bio/de/Projekte/IoT-Plattform"; + website = "https://code.curious.bio/curious.bio/smart-energy-monitor.git"; + migration_clone_address = "https://code.curious.bio/curious.bio/smart-energy-monitor.git"; + mirror = true; + has_issues = false; + has_wiki = false; + private = false; + depends_on = [ "gitea_org.gitea-org-curious-bio" ]; + }; + + + gitea-mirror-mushlab-iot = { + username = lib.tfRef "gitea_org.gitea-org-curious-bio.name"; + name = "mushlab-iot"; + website = "https://code.curious.bio/curious.bio/mushlab-iot.git"; + migration_clone_address = "https://code.curious.bio/curious.bio/mushlab-iot.git"; + mirror = true; + has_issues = false; + has_wiki = false; + private = false; + depends_on = [ "gitea_org.gitea-org-curious-bio" ]; + }; + + gitea-mirror-vermiloop = { + username = lib.tfRef "gitea_org.gitea-org-curious-bio.name"; + name = "vermiloop"; + website = "https://code.curious.bio/curious.bio/vermiloop.git"; + migration_clone_address = "https://code.curious.bio/curious.bio/vermiloop.git"; + mirror = true; + has_issues = false; + has_wiki = false; + private = false; + depends_on = [ "gitea_org.gitea-org-curious-bio" ]; + }; + + gitea-mirror-planktoscope = { + username = lib.tfRef "gitea_org.gitea-org-curious-bio.name"; + name = "planktoscope"; + website = "https://code.curious.bio/curious.bio/planktoscope.git"; + migration_clone_address = "https://code.curious.bio/curious.bio/planktoscope.git"; + mirror = true; + has_issues = false; + has_wiki = false; + private = false; + depends_on = [ "gitea_org.gitea-org-curious-bio" ]; + }; + + gitea-mirror-nix-cyanovision = { + username = lib.tfRef "gitea_org.gitea-org-curious-bio.name"; + name = "nix-cyanovision"; + website = "https://code.curious.bio/curious.bio/nix-cyanovision.git"; + migration_clone_address = "https://code.curious.bio/curious.bio/nix-cyanovision.git"; + mirror = true; + has_issues = false; + has_wiki = false; + private = false; + depends_on = [ "gitea_org.gitea-org-curious-bio" ]; + }; + }; + }; +} diff --git a/terranix/gitea/default.nix b/terranix/gitea/default.nix new file mode 100644 index 0000000..f4c0ae1 --- /dev/null +++ b/terranix/gitea/default.nix @@ -0,0 +1,14 @@ +{ + terraform.required_providers.gitea = { + source = "registry.terraform.io/go-gitea/gitea"; + version = ">= 0.3.0"; + }; + + imports = [ + ./swendel.nix + ./srx.digital.nix + ./nix-hamburg.de.nix + ./curious.bio.nix + ./octopot.de.nix + ]; +} diff --git a/terranix/gitea/nix-hamburg.de.nix b/terranix/gitea/nix-hamburg.de.nix new file mode 100644 index 0000000..267167f --- /dev/null +++ b/terranix/gitea/nix-hamburg.de.nix @@ -0,0 +1,9 @@ +{ + resource.gitea_org.gitea-org-nix-hamburg = { + name = "nix-hamburg"; + full_name = "Nix Hamburg User Group"; + location = "Hamburg, Germany"; + website = "https://nix-hamburg.de/"; + visibility = "public"; + }; +} diff --git a/terranix/gitea/octopot.de.nix b/terranix/gitea/octopot.de.nix new file mode 100644 index 0000000..3337a31 --- /dev/null +++ b/terranix/gitea/octopot.de.nix @@ -0,0 +1,9 @@ +{ + resource.gitea_org.gitea-org-octopod = { + name = "octopod"; + full_name = "octopod research & development GmbH"; + location = "Hamburg, Germany"; + website = "https://octopod.de"; + visibility = "private"; + }; +} diff --git a/terranix/gitea/srx.digital.nix b/terranix/gitea/srx.digital.nix new file mode 100644 index 0000000..5aca5ca --- /dev/null +++ b/terranix/gitea/srx.digital.nix @@ -0,0 +1,75 @@ +{ lib, ... }: +{ + resource = { + gitea_org.gitea-org-srx-digital = { + name = "srx"; + full_name = "srx development & operations"; + location = "Hamburg, Germany"; + website = "https://srx.digital"; + visibility = "public"; + }; + + gitea_repository = { + gitea-repo-srx-nixos-shadow = { + username = lib.tfRef "gitea_org.gitea-org-srx-digital.name"; + name = "srx-nixos-shadow"; + description = "The hidden part of the srx.digital NixOS platform"; + auto_init = false; + private = true; + }; + + srx-platform-nix = { + username = lib.tfRef "gitea_org.gitea-org-srx-digital.name"; + name = "srx-platform-nix"; + description = "Nix platform repository"; + migration_clone_address = "https://github.com/SebastianWendel/srx-platform-nix"; + migration_service_auth_token = lib.tfRef "var.GITHUB_TOKEN"; + migration_service = "github"; + has_issues = true; + has_wiki = true; + private = false; + mirror = true; + website = "https://srx.digital"; + depends_on = [ "gitea_org.gitea-org-srx-digital" ]; + }; + + gitea-mirror-fcos-drupal-cms-dev-kit = { + username = lib.tfRef "gitea_org.gitea-org-srx-digital.name"; + name = "fcos-drupal-cms-dev-kit"; + description = " FCOS Drupal CMS Development Kit"; + website = "https://gitlab.fabcity.hamburg/software/fcos-drupal-cms-dev-kit.git"; + has_issues = false; + has_wiki = false; + private = false; + mirror = true; + depends_on = [ "gitea_org.gitea-org-srx-digital" ]; + }; + + gitea-mirror-fab-city-os-core-chart = { + username = lib.tfRef "gitea_org.gitea-org-srx-digital.name"; + name = "fab-city-os-core-chart"; + description = "Fab City OS Core Helm Chart for Kubernetes"; + website = "https://gitlab.fabcity.hamburg/software/fab-city-os-core-chart.git"; + migration_clone_address = "https://gitlab.fabcity.hamburg/software/fab-city-os-core-chart.git"; + mirror = true; + has_issues = false; + has_wiki = false; + private = false; + depends_on = [ "gitea_org.gitea-org-srx-digital" ]; + }; + + gitea-mirror-fab-city-software-kit = { + username = lib.tfRef "gitea_org.gitea-org-srx-digital.name"; + name = "fab-city-software-kit"; + description = "Fab City Software Kit for Kubernetes"; + website = "https://gitlab.fabcity.hamburg/software/fab-city-software-kit.git"; + migration_clone_address = "https://gitlab.fabcity.hamburg/software/fab-city-software-kit.git"; + mirror = true; + has_issues = false; + has_wiki = false; + private = false; + depends_on = [ "gitea_org.gitea-org-srx-digital" ]; + }; + }; + }; +} diff --git a/terranix/gitea/swendel.nix b/terranix/gitea/swendel.nix new file mode 100644 index 0000000..9264b5c --- /dev/null +++ b/terranix/gitea/swendel.nix @@ -0,0 +1,64 @@ +{ lib, ... }: +{ + resource = { + gitea_repository = { + gitea-repo-gitHub-profile = { + username = "swendel"; + name = "SebastianWendel"; + description = "My personal GitHub profile."; + website = "https://srx.digital"; + migration_clone_address = "https://github.com/SebastianWendel/SebastianWendel.git"; + migration_service_auth_token = lib.tfRef "var.GITHUB_TOKEN"; + migration_service = "github"; + mirror = true; + has_issues = true; + has_wiki = false; + private = false; + }; + + gitea-mirror-nixpkgs = { + username = "swendel"; + name = "nixpkgs"; + description = "Mirror of nixpkgs"; + website = "https://github.com/SebastianWendel/nixpkgs.git"; + migration_clone_address = "https://github.com/SebastianWendel/nixpkgs.git"; + mirror = true; + has_issues = true; + has_wiki = true; + private = false; + }; + + gitea-mirror-bionet = { + username = "swendel"; + name = "bionet"; + description = "Image classification"; + website = "https://code.curious.bio/swendel/bionet.git"; + migration_clone_address = "https://code.curious.bio/swendel/bionet.git"; + migration_service = "gitea"; + migration_service_auth_token = lib.tfRef "var.GITEA_MIRROR_TOKEN_CCL"; + private = true; + }; + + gitea-mirror-birdnet-nix = { + username = "swendel"; + name = "birdnet-nix"; + description = "Nixified BirdNet"; + website = "https://code.curious.bio/swendel/birdnet-nix.git"; + migration_clone_address = "https://code.curious.bio/swendel/birdnet-nix.git"; + migration_service = "gitea"; + migration_service_auth_token = lib.tfRef "var.GITEA_MIRROR_TOKEN_CCL"; + private = true; + }; + + gitea-mirror-esphome-components = { + username = "swendel"; + name = "esphome-components"; + website = "https://code.curious.bio/swendel/esphome-components.git"; + migration_clone_address = "https://code.curious.bio/swendel/esphome-components.git"; + migration_service = "gitea"; + migration_service_auth_token = lib.tfRef "var.GITEA_MIRROR_TOKEN_CCL"; + private = true; + }; + }; + }; +} diff --git a/terranix/github/default.nix b/terranix/github/default.nix new file mode 100644 index 0000000..3488a19 --- /dev/null +++ b/terranix/github/default.nix @@ -0,0 +1,10 @@ +{ + terraform.required_providers.github = { + source = "registry.terraform.io/integrations/github"; + version = ">= 6.2.1"; + }; + + imports = [ + ./srx.digital.nix + ]; +} diff --git a/terranix/github/srx.digital.nix b/terranix/github/srx.digital.nix new file mode 100644 index 0000000..b7503e8 --- /dev/null +++ b/terranix/github/srx.digital.nix @@ -0,0 +1,28 @@ +{ + resource = { + github_user_ssh_key.swendel = { + title = "swendel"; + key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKwyxpc0pVB46j1k5VCSabvI4TUADvAabnxlE5+D5o2l"; + }; + + github_repository = { + github-repo-profile = { + name = "SebastianWendel"; + description = "My personal GitHub profile."; + homepage_url = "https://srx.digital"; + has_issues = false; + visibility = "public"; + vulnerability_alerts = false; + }; + + srx-platform-nix = { + name = "srx-platform-nix"; + description = "srx.digital - nix platform repository. Mirror of https://code.srx.digital/srx/srx-platform-nix/"; + homepage_url = "https://srx.digital"; + has_issues = false; + visibility = "public"; + vulnerability_alerts = false; + }; + }; + }; +} diff --git a/terranix/grafana/default.nix b/terranix/grafana/default.nix new file mode 100644 index 0000000..e671aeb --- /dev/null +++ b/terranix/grafana/default.nix @@ -0,0 +1,20 @@ +{ lib, ... }: { + terraform.required_providers.grafana = { + source = "registry.terraform.io/grafana/grafana"; + version = ">= 2.14.3"; + }; + + resource = { + grafana_organization.srx = { + name = "srx.digital - Development & Operations"; + admin_user = lib.tfRef "var.USERNAME_ADMIN"; + create_users = false; + }; + + grafana_organization_preferences.srx = { + timezone = "browser"; + week_start = "monday"; + depends_on = [ "grafana_organization.srx" ]; + }; + }; +} diff --git a/terranix/hcloud/default.nix b/terranix/hcloud/default.nix new file mode 100644 index 0000000..beb302c --- /dev/null +++ b/terranix/hcloud/default.nix @@ -0,0 +1,20 @@ +{ lib, ... }: { + terraform.required_providers.hcloud = { + source = "registry.terraform.io/hetznercloud/hcloud"; + version = ">= 1.45.0"; + }; + + resource.hcloud_server.srxk8s00 = { + name = "srxk8s00"; + server_type = "cax21"; + image = "debian-12"; + datacenter = "nbg1-dc3"; + public_net = { + ipv4_enabled = true; + ipv6_enabled = true; + }; + ssh_keys = lib.tfRef "data.hcloud_ssh_keys.all_keys.ssh_keys.*.name"; + }; + + data.hcloud_ssh_keys.all_keys = { }; +} diff --git a/terranix/hydra/default.nix b/terranix/hydra/default.nix new file mode 100644 index 0000000..aee21ec --- /dev/null +++ b/terranix/hydra/default.nix @@ -0,0 +1,12 @@ +{ + terraform.required_providers.hydra = { + source = "registry.terraform.io/DeterminateSystems/hydra"; + version = ">= 0.1.2"; + }; + + provider.hydra = { }; + + imports = [ + ./srx.digital.nix + ]; +} diff --git a/terranix/hydra/srx.digital.nix b/terranix/hydra/srx.digital.nix new file mode 100644 index 0000000..6b1ebb4 --- /dev/null +++ b/terranix/hydra/srx.digital.nix @@ -0,0 +1,63 @@ +{ lib, ... }: { + resource = { + hydra_project.srx = { + name = "srx"; + display_name = "srx.digital"; + description = "srx.digital NixOS Platform"; + homepage = "https://code.srx.digital/srx/"; + owner = lib.tfRef "var.USERNAME_PERSONAL"; + enabled = true; + visible = true; + }; + + hydra_jobset = { + srx-platform-nix = { + name = "srx-platform-nix"; + project = lib.tfRef "hydra_project.srx.name"; + type = "flake"; + flake_uri = "git+ssh://forgejo@code.srx.digital/srx/srx.infra.nix.history.git"; + description = "srx.digital NixOS Platform"; + state = "enabled"; + check_interval = 60; + scheduling_shares = 10000; + keep_evaluations = 5; + visible = true; + email_notifications = true; + email_override = lib.tfRef "var.EMAIL_PUBLIC"; + depends_on = [ "hydra_project.srx" ]; + }; + + srx-website-nix = { + name = "website"; + project = lib.tfRef "hydra_project.srx.name"; + type = "flake"; + flake_uri = "git+ssh://forgejo@code.srx.digital/srx/srx.astro.nix.git"; + description = "A Nix development environment of my portfolio page based on Astro"; + state = "enabled"; + check_interval = 60; + scheduling_shares = 1000; + keep_evaluations = 5; + visible = true; + email_notifications = true; + email_override = lib.tfRef "var.EMAIL_PUBLIC"; + depends_on = [ "hydra_project.srx" ]; + }; + + srx-shadow-nix = { + name = "nixos-shadow"; + project = lib.tfRef "hydra_project.srx.name"; + type = "flake"; + flake_uri = "git+ssh://forgejo@code.srx.digital/srx/srx-nixos-shadow.git"; + description = "The hidden part of the srx.digital NixOS platform"; + state = "enabled"; + check_interval = 60; + scheduling_shares = 1000; + keep_evaluations = 5; + visible = false; + email_notifications = true; + email_override = lib.tfRef "var.EMAIL_PUBLIC"; + depends_on = [ "hydra_project.srx" ]; + }; + }; + }; +} diff --git a/terranix/keycloak/default.nix b/terranix/keycloak/default.nix new file mode 100644 index 0000000..c1d609b --- /dev/null +++ b/terranix/keycloak/default.nix @@ -0,0 +1,12 @@ +{ + terraform.required_providers.keycloak = { + source = "registry.terraform.io/mrparkers/keycloak"; + version = ">= 4.4.0"; + }; + + provider.keycloak = { }; + + imports = [ + ./srx.digital.nix + ]; +} diff --git a/terranix/keycloak/srx.digital.nix b/terranix/keycloak/srx.digital.nix new file mode 100644 index 0000000..10ee194 --- /dev/null +++ b/terranix/keycloak/srx.digital.nix @@ -0,0 +1,114 @@ +{ lib, ... }: +{ + resource = { + keycloak_realm.srx-digital = { + enabled = true; + + realm = "srx-digital"; + display_name = "SRX Digital - Development & Operations"; + login_theme = "keycloak"; + access_code_lifespan = "1h"; + display_name_html = "SRX Digital - Development & Operations"; + + internationalization = [{ + default_locale = "en"; + supported_locales = [ "en" "de" ]; + }]; + + verify_email = true; + reset_password_allowed = true; + login_with_email_allowed = true; + password_policy = "length(20) and upperCase(2) and digits(2) and specialChars(2) and notUsername and passwordHistory(10) and forceExpiredPasswordChange(90)"; + ssl_required = "external"; + + smtp_server = [{ + host = lib.tfRef "var.EMAIL_HOST"; + port = lib.tfRef "var.EMAIL_PORT"; + from = lib.tfRef "var.EMAIL_NO_REPLY"; + from_display_name = lib.tfRef "var.COMPANY_HEADER"; + reply_to = lib.tfRef "var.EMAIL_BILLING"; + reply_to_display_name = lib.tfRef "var.COMPANY_HEADER"; + auth = { + username = lib.tfRef "var.EMAIL_NO_REPLY"; + password = lib.tfRef "var.EMAIL_PASSWORD"; + }; + ssl = true; + }]; + + security_defenses = [{ + headers = [{ + content_security_policy = "frame-src 'self'; frame-ancestors 'self'; object-src 'none';"; + content_security_policy_report_only = ""; + strict_transport_security = "max-age=31536000; includeSubDomains"; + x_content_type_options = "nosniff"; + x_frame_options = "DENY"; + x_robots_tag = "none"; + x_xss_protection = "1; mode=block"; + }]; + + brute_force_detection = [{ + failure_reset_time_seconds = 43200; + max_failure_wait_seconds = 900; + max_login_failures = 30; + minimum_quick_login_wait_seconds = 60; + permanent_lockout = false; + quick_login_check_milli_seconds = 1000; + wait_increment_seconds = 60; + }]; + }]; + }; + + keycloak_openid_client = { + openid_client = { + enabled = true; + client_id = "code"; + name = "SRX Code Base "; + access_type = "CONFIDENTIAL"; + standard_flow_enabled = true; + valid_redirect_uris = [ "https://code.srx.digital/*" ]; + realm_id = "\${keycloak_realm.srx-digital.id}"; + }; + }; + + keycloak_group.operator = { + name = "operator"; + realm_id = "\${keycloak_realm.srx-digital.id}"; + depends_on = [ + "keycloak_realm.srx-digital" + ]; + }; + + keycloak_user.swendel = { + enabled = true; + username = "swendel"; + first_name = "Sebastian"; + last_name = "Wendel"; + email = lib.tfRef "var.EMAIL_PERSONAL"; + + required_actions = [ + "Verify email" + "Update profile" + "Update password" + "Configure OTP" + ]; + + initial_password = { + value = lib.tfRef "var.EMAIL_PERSONAL"; + temporary = true; + }; + + realm_id = "\${keycloak_realm.srx-digital.id}"; + + depends_on = [ + "keycloak_realm.srx-digital" + "keycloak_group.operator" + ]; + }; + + keycloak_user_groups.operator = { + user_id = "\${keycloak_user.swendel.id}"; + group_ids = [ "\${keycloak_group.operator.id}" ]; + realm_id = "\${keycloak_realm.srx-digital.id}"; + }; + }; +} diff --git a/terranix/minio/admins.nix b/terranix/minio/admins.nix new file mode 100644 index 0000000..4cbea78 --- /dev/null +++ b/terranix/minio/admins.nix @@ -0,0 +1,33 @@ +{ + resource = { + minio_iam_user.swendel.name = "swendel"; + + minio_iam_service_account.swendel.target_user = "\${minio_iam_user.swendel.name}"; + + minio_iam_user_policy_attachment.swendel-policy-admin = { + user_name = "\${minio_iam_user.swendel.id}"; + policy_name = "consoleAdmin"; + }; + }; + + output = { + swendel-id.value = "\${minio_iam_user.swendel.id}"; + + swendel-secret = { + value = "\${minio_iam_user.swendel.secret}"; + sensitive = true; + }; + + swendel-status.value = "\${minio_iam_user.nix-hydra.status}"; + + swendel-access-key = { + value = "\${minio_iam_service_account.swendel.access_key}"; + sensitive = true; + }; + + swendel-secret-key = { + value = "\${minio_iam_service_account.swendel.secret_key}"; + sensitive = true; + }; + }; +} diff --git a/terranix/minio/default.nix b/terranix/minio/default.nix new file mode 100644 index 0000000..e7469c2 --- /dev/null +++ b/terranix/minio/default.nix @@ -0,0 +1,14 @@ +{ + terraform.required_providers.minio = { + source = "registry.terraform.io/aminueza/minio"; + version = ">= 2.2.0"; + }; + + provider.minio = { }; + + imports = [ + ./admins.nix + ./terraform.nix + ./hydra.nix + ]; +} diff --git a/terranix/minio/hydra.nix b/terranix/minio/hydra.nix new file mode 100644 index 0000000..b191ad8 --- /dev/null +++ b/terranix/minio/hydra.nix @@ -0,0 +1,65 @@ +{ + resource = { + minio_s3_bucket.nix-cache.bucket = "nix-cache"; + + minio_iam_user.nix-hydra.name = "nix-hydra"; + minio_iam_service_account.nix-hydra.target_user = "\${minio_iam_user.nix-hydra.name}"; + + minio_iam_policy = { + nix-cache-policy-hydra = { + name = "nix-cache-policy-hydra"; + policy = "\${data.minio_iam_policy_document.nix-cache-policy-hydra.json}"; + }; + nix-cache-policy-hydra-read = { + name = "nix-cache-policy-hydra-read"; + policy = "\${data.minio_iam_policy_document.nix-cache-policy-hydra-read.json}"; + }; + }; + minio_iam_user_policy_attachment.nix-cache-policy-hydra = { + user_name = "\${minio_iam_user.nix-hydra.id}"; + policy_name = "\${minio_iam_policy.nix-cache-policy-hydra.id}"; + }; + }; + + data = { + minio_iam_policy_document.nix-cache-policy-hydra-read.statement = { + sid = "AllowDirectReads"; + actions = [ + "s3:GetObject" + "s3:GetBucketLocation" + ]; + effect = "Allow"; + resources = [ + "\${minio_s3_bucket.nix-cache.arn}" + "\${minio_s3_bucket.nix-cache.arn}/*" + ]; + principal = "*"; + }; + + minio_iam_policy_document.nix-cache-policy-hydra.statement = { + sid = "AuthenticatedWrite"; + actions = [ "s3:*" ]; + effect = "Allow"; + resources = [ + "\${minio_s3_bucket.nix-cache.arn}" + "\${minio_s3_bucket.nix-cache.arn}/*" + ]; + principal = "*"; + }; + }; + + output = { + nix-hydra-id.value = "\${minio_iam_user.nix-hydra.id}"; + nix-hydra-secret = { + value = "\${minio_iam_user.nix-hydra.secret}"; + sensitive = true; + }; + nix-hydra-status.value = "\${minio_iam_user.nix-hydra.status}"; + nix-hydra-access-key.value = "\${minio_iam_service_account.nix-hydra.access_key}"; + nix-hydra-secret-key = { + value = "\${minio_iam_service_account.nix-hydra.secret_key}"; + sensitive = true; + }; + nix-cache-url.value = "\${minio_s3_bucket.nix-cache.bucket_domain_name}"; + }; +} diff --git a/terranix/minio/terraform.nix b/terranix/minio/terraform.nix new file mode 100644 index 0000000..62cdcef --- /dev/null +++ b/terranix/minio/terraform.nix @@ -0,0 +1,15 @@ +{ + resource = { + minio_s3_bucket.terraform-state.bucket = "terraform-state"; + + minio_s3_bucket_versioning.terraform-state = { + bucket = "terraform-state"; + versioning_configuration.status = "Enabled"; + depends_on = [ "minio_s3_bucket.terraform-state" ]; + }; + }; + + output = { + terraform-url.value = "\${minio_s3_bucket.terraform-state.bucket_domain_name}"; + }; +} diff --git a/terranix/tfsec.nix b/terranix/tfsec.nix new file mode 100644 index 0000000..f7c5d90 --- /dev/null +++ b/terranix/tfsec.nix @@ -0,0 +1,6 @@ +{ + exclude = [ + "github-repositories-private" + "github-repositories-enable_vulnerability_alerts" + ]; +} diff --git a/terranix/variables.nix b/terranix/variables.nix new file mode 100644 index 0000000..aabc6bd --- /dev/null +++ b/terranix/variables.nix @@ -0,0 +1,57 @@ +{ + variable = { + COMPANY_HEADER = { + type = "string"; + }; + + USERNAME_PERSONAL = { + type = "string"; + default = "guest"; + }; + + USERNAME_ADMIN = { + type = "string"; + default = "admin"; + }; + + EMAIL_HOST = { + type = "string"; + default = "mail.example.com"; + }; + + EMAIL_PORT = { + type = "number"; + default = 465; + }; + + EMAIL_PERSONAL = { + type = "string"; + default = "guest@example.com"; + }; + + EMAIL_PUBLIC = { + type = "string"; + default = "no-reply@example.com"; + }; + + EMAIL_BILLING = { + type = "string"; + default = "no-reply@example.com"; + }; + + EMAIL_NO_REPLY = { + type = "string"; + default = "no-reply@example.com"; + }; + + EMAIL_PASSWORD = { + type = "string"; + sensitive = true; + }; + + GITHUB_TOKEN = { + type = "string"; + sensitive = true; + }; + }; +}