Compare commits
	
		
			107 Commits
		
	
	
		
			731cfce080
			...
			fastback-s
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ab25c07f69 | |||
| aad8adf5da | |||
| 205a948486 | |||
| 39e7c703ba | |||
| d07ef96d28 | |||
| 1a29a7d589 | |||
| ca6fe534dc | |||
| e277cce3bc | |||
| c9ce57e2c5 | |||
| 04dfc89f07 | |||
| cfbbed8285 | |||
| 066c87d3d6 | |||
| e24ac05bb2 | |||
| a2b146e8ba | |||
| a03fdbdbdd | |||
| 5915f664cc | |||
| 42111c530e | |||
| a741e3eea2 | |||
| 7a4372dfe7 | |||
| 65917bad5c | |||
| 16c7fd7659 | |||
| 2fffefd22d | |||
| c14aebf4a3 | |||
| 677f3f26ab | |||
| c55600c5af | |||
| 64c3e2d720 | |||
| 20d5fa29ae | |||
| 046937de27 | |||
| bba87ef73b | |||
| 4e3ff0a466 | |||
| b1af3dbf18 | |||
| f58b71e8d3 | |||
| 0a86a649a6 | |||
| 85189e74f8 | |||
| e760569b3e | |||
| 0fe863844f | |||
| d44fdcfe6a | |||
| b48e7b1c33 | |||
| d0b155d786 | |||
| 01cb95de6d | |||
| 46df9b8aa8 | |||
| b2342c7a05 | |||
| a572be0708 | |||
| 68bf705e85 | |||
| 21136e98b2 | |||
| b537524e5a | |||
| 10769a4441 | |||
| 9b05e7cd8d | |||
| eda0cdbe0e | |||
| f321a039f3 | |||
| fc6c4f461f | |||
| 22bf75d0a0 | |||
| 318972a086 | |||
| 9fa8299b71 | |||
| 490413c24b | |||
| 9cec5051bf | |||
| 70f49c8438 | |||
| 8b0db3ac7f | |||
| cc07964fac | |||
| 4624480c8b | |||
| 3bc8befb7d | |||
| 1b853d405c | |||
| 82b24c3c55 | |||
| 2f2764a364 | |||
| 4b48d7e788 | |||
| 5686aa1a01 | |||
| 20a3873d25 | |||
| d9d7a714cd | |||
| 93892224b7 | |||
| 5e5f70501c | |||
| 33eded0626 | |||
| 9268256309 | |||
| 027cf2af6b | |||
| 54f628d3a5 | |||
| 56704821b8 | |||
| ca3547b27a | |||
| 88b6e00f93 | |||
| b4d0d9aff9 | |||
| 4ee66cdca7 | |||
| 1b72739000 | |||
| c28acb339b | |||
| 3d7a1b8e6c | |||
| 373fb45831 | |||
| c4e6896a0c | |||
| a1778e0f1e | |||
| 0cc35547f2 | |||
| 7404779c6d | |||
| 63f36fabbb | |||
| c8b65092be | |||
| d347234e82 | |||
| 0e115544e4 | |||
| e6ad150865 | |||
| afe124a726 | |||
| 655a44a28b | |||
| 7330b8f832 | |||
| aa18ebcb3b | |||
| 23db7e6c66 | |||
| dfca7fccaa | |||
| edb5767770 | |||
| a9a6409034 | |||
| 4d345f467f | |||
| 38e7251300 | |||
| 5766bdda99 | |||
| 4133ed48c5 | |||
| 01897ef0bb | |||
| 82eab34f4b | |||
| 241abd02ac | 
							
								
								
									
										2
									
								
								.envrc
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								.envrc
									
									
									
									
									
								
							@@ -1,2 +1,2 @@
 | 
				
			|||||||
nix_direnv_watch_file devshell/{default,commands,install,vm-tasks}.nix
 | 
					watch_file devshell/{default,commands,install,vm-tasks}.nix
 | 
				
			||||||
use flake
 | 
					use flake
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,12 +6,10 @@ on:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  check:
 | 
					  check:
 | 
				
			||||||
    name: Check Nix flake
 | 
					    name: Check, build and cache Nix flake
 | 
				
			||||||
    runs-on: ubuntu-22.04
 | 
					    runs-on: ubuntu-22.04
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v4
 | 
					      - uses: actions/checkout@v4
 | 
				
			||||||
      - name: Install jq
 | 
					 | 
				
			||||||
        run: apt-get update -y && apt-get install -y jq
 | 
					 | 
				
			||||||
      - uses: cachix/install-nix-action@v23
 | 
					      - uses: cachix/install-nix-action@v23
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          # Gitea will supply a token in GITHUB_TOKEN, which this action will
 | 
					          # Gitea will supply a token in GITHUB_TOKEN, which this action will
 | 
				
			||||||
@@ -20,17 +18,22 @@ jobs:
 | 
				
			|||||||
          extra_nix_config: |
 | 
					          extra_nix_config: |
 | 
				
			||||||
            # Make sure we're using sandbox
 | 
					            # Make sure we're using sandbox
 | 
				
			||||||
            sandbox-fallback = false
 | 
					            sandbox-fallback = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            extra-substituters = https://nix-cache.nul.ie/main
 | 
					            extra-substituters = https://nix-cache.nul.ie/main
 | 
				
			||||||
            extra-trusted-public-keys = main:a2CtSxCXCXKabLa6IYQWzy3rdYjOwg9Ccm4ayahFjDI=
 | 
					            extra-trusted-public-keys = main:mMChkG8LwXrFirVfudqjSHasK1jV31OVElYD3eImYl8=
 | 
				
			||||||
      - name: Set up attic
 | 
					      - name: Set up attic
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          nix run .#nixpkgs.mine.x86_64-linux.attic-client -- \
 | 
					          nix run .#nixpkgs.mine.x86_64-linux.attic-client -- \
 | 
				
			||||||
            login --set-default colony https://nix-cache.nul.ie "${{ secrets.NIX_CACHE_TOKEN }}"
 | 
					            login --set-default colony https://nix-cache.nul.ie "${{ secrets.NIX_CACHE_TOKEN }}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # - name: Check flake
 | 
					      - name: Check flake
 | 
				
			||||||
      #   run: nix flake check
 | 
					        run: nix flake check
 | 
				
			||||||
 | 
					      - name: Build the world
 | 
				
			||||||
 | 
					        id: build
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          path=$(nix build --no-link .#ci.x86_64-linux --json | jq -r .[0].outputs.out)
 | 
				
			||||||
 | 
					          echo "path=$path" >> "$GITHUB_OUTPUT"
 | 
				
			||||||
      - name: Push to cache
 | 
					      - name: Push to cache
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          path=$(nix build --no-link .#nixosConfigurations.middleman.config.system.build.toplevel --json | jq -r .[0].outputs.out)
 | 
					 | 
				
			||||||
          nix run .#nixpkgs.mine.x86_64-linux.attic-client -- \
 | 
					          nix run .#nixpkgs.mine.x86_64-linux.attic-client -- \
 | 
				
			||||||
            push main $path
 | 
					            push main ${{ steps.build.outputs.path }}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										50
									
								
								.gitea/workflows/installer.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								.gitea/workflows/installer.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					name: Installer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					on:
 | 
				
			||||||
 | 
					  push:
 | 
				
			||||||
 | 
					    tags: [installer]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					jobs:
 | 
				
			||||||
 | 
					  installer:
 | 
				
			||||||
 | 
					    name: Build installer
 | 
				
			||||||
 | 
					    runs-on: ubuntu-22.04
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - uses: actions/checkout@v4
 | 
				
			||||||
 | 
					      - name: Set up Go
 | 
				
			||||||
 | 
					        uses: https://github.com/actions/setup-go@v4
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          go-version: '>=1.20.1'
 | 
				
			||||||
 | 
					      - uses: cachix/install-nix-action@v23
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          github_access_token: ${{ secrets.GH_PULL_TOKEN }}
 | 
				
			||||||
 | 
					          extra_nix_config: |
 | 
				
			||||||
 | 
					            # Make sure we're using sandbox
 | 
				
			||||||
 | 
					            sandbox-fallback = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            extra-substituters = https://nix-cache.nul.ie/main
 | 
				
			||||||
 | 
					            extra-trusted-public-keys = main:mMChkG8LwXrFirVfudqjSHasK1jV31OVElYD3eImYl8=
 | 
				
			||||||
 | 
					      - name: Set up attic
 | 
				
			||||||
 | 
					        id: setup
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          nix run .#nixpkgs.mine.x86_64-linux.attic-client -- \
 | 
				
			||||||
 | 
					            login --set-default colony https://nix-cache.nul.ie "${{ secrets.NIX_CACHE_TOKEN }}"
 | 
				
			||||||
 | 
					          echo "short_rev=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Build installer ISO
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          nix build .#nixfiles.config.nixos.systems.installer.configuration.config.my.buildAs.iso
 | 
				
			||||||
 | 
					          ln -s "$(readlink result)"/iso/jackos-installer.iso \
 | 
				
			||||||
 | 
					            jackos-installer-${{ steps.setup.outputs.short_rev }}.iso
 | 
				
			||||||
 | 
					      - name: Build installer netboot archive
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          nix build .#nixfiles.config.nixos.systems.installer.configuration.config.my.buildAs.netbootArchive
 | 
				
			||||||
 | 
					          ln -s "$(readlink result)" \
 | 
				
			||||||
 | 
					            jackos-installer-netboot-${{ steps.setup.outputs.short_rev }}.tar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Create release
 | 
				
			||||||
 | 
					        uses: https://gitea.com/actions/release-action@main
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          title: Latest installer
 | 
				
			||||||
 | 
					          files: |
 | 
				
			||||||
 | 
					            jackos-installer-${{ steps.setup.outputs.short_rev }}.iso
 | 
				
			||||||
 | 
					            jackos-installer-netboot-${{ steps.setup.outputs.short_rev }}.tar
 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
age1ythn9runhsvwmszqfy69zetc422hug39ta4g236tue6f5qf65y0q4qg7xx
 | 
					 | 
				
			||||||
@@ -47,8 +47,8 @@ in
 | 
				
			|||||||
          (nodesFor homes)
 | 
					          (nodesFor homes)
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        autoRollback = true;
 | 
					        autoRollback = false;
 | 
				
			||||||
        magicRollback = true;
 | 
					        magicRollback = false;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # Filter out null values so deploy merges overriding options correctly
 | 
					      # Filter out null values so deploy merges overriding options correctly
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,6 +48,12 @@ in
 | 
				
			|||||||
      help = "Print the ed25519 pubkey for a host";
 | 
					      help = "Print the ed25519 pubkey for a host";
 | 
				
			||||||
      command = "${pkgs.openssh}/bin/ssh-keyscan -t ed25519 \"$1\" 2> /dev/null | awk '{ print $2 \" \" $3 }'";
 | 
					      command = "${pkgs.openssh}/bin/ssh-keyscan -t ed25519 \"$1\" 2> /dev/null | awk '{ print $2 \" \" $3 }'";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name = "json2nix";
 | 
				
			||||||
 | 
					      category = "utilities";
 | 
				
			||||||
 | 
					      help = "Convert JSON to formatted Nix";
 | 
				
			||||||
 | 
					      command = "nix eval --impure --expr 'builtins.fromJSON (builtins.readFile /dev/stdin)' | ${pkgs.nixfmt}/bin/nixfmt";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      name = "fmt";
 | 
					      name = "fmt";
 | 
				
			||||||
@@ -91,6 +97,18 @@ in
 | 
				
			|||||||
      help = "Build NixOS configuration into an ISO";
 | 
					      help = "Build NixOS configuration into an ISO";
 | 
				
			||||||
      command = ''nix build "''${@:2}" ".#nixfiles.config.nixos.systems.\"$1\".configuration.config.my.buildAs.iso"'';
 | 
					      command = ''nix build "''${@:2}" ".#nixfiles.config.nixos.systems.\"$1\".configuration.config.my.buildAs.iso"'';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name = "build-kexec";
 | 
				
			||||||
 | 
					      category = "tasks";
 | 
				
			||||||
 | 
					      help = "Build NixOS configuration as kexec tree";
 | 
				
			||||||
 | 
					      command = ''nix build "''${@:2}" ".#nixfiles.config.nixos.systems.\"$1\".configuration.config.my.buildAs.kexecTree"'';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name = "build-netboot";
 | 
				
			||||||
 | 
					      category = "tasks";
 | 
				
			||||||
 | 
					      help = "Build NixOS configuration as netboot archive";
 | 
				
			||||||
 | 
					      command = ''nix build "''${@:2}" ".#nixfiles.config.nixos.systems.\"$1\".configuration.config.my.buildAs.netbootArchive"'';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      name = "build-home";
 | 
					      name = "build-home";
 | 
				
			||||||
      category = "tasks";
 | 
					      category = "tasks";
 | 
				
			||||||
@@ -121,5 +139,11 @@ in
 | 
				
			|||||||
      help = "Update home-manager flake inputs";
 | 
					      help = "Update home-manager flake inputs";
 | 
				
			||||||
      command = ''update-inputs home-manager-{unstable,stable}'';
 | 
					      command = ''update-inputs home-manager-{unstable,stable}'';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name = "update-installer";
 | 
				
			||||||
 | 
					      category = "tasks";
 | 
				
			||||||
 | 
					      help = "Update installer tag (to trigger new release)";
 | 
				
			||||||
 | 
					      command = ''git tag -f installer && git push -f origin installer'';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,5 @@
 | 
				
			|||||||
{ lib, pkgs, ... }:
 | 
					{ lib, pkgs, ... }:
 | 
				
			||||||
let
 | 
					let
 | 
				
			||||||
  inherit (lib) concatStringsSep;
 | 
					 | 
				
			||||||
  inherit (lib.my) attrsToNVList;
 | 
					  inherit (lib.my) attrsToNVList;
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -13,9 +12,9 @@ in
 | 
				
			|||||||
    NIX_USER_CONF_FILES = toString (pkgs.writeText "nix.conf"
 | 
					    NIX_USER_CONF_FILES = toString (pkgs.writeText "nix.conf"
 | 
				
			||||||
      ''
 | 
					      ''
 | 
				
			||||||
        experimental-features = nix-command flakes ca-derivations repl-flake
 | 
					        experimental-features = nix-command flakes ca-derivations repl-flake
 | 
				
			||||||
        #substituters = https://nix-cache.nul.ie https://cache.nixos.org
 | 
					        connect-timeout = 5
 | 
				
			||||||
        substituters = https://cache.nixos.org
 | 
					        fallback = true
 | 
				
			||||||
        trusted-public-keys = ${concatStringsSep " " lib.my.c.nix.cacheKeys}
 | 
					        ${lib.my.c.nix.cache.conf}
 | 
				
			||||||
      '');
 | 
					      '');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    INSTALLER_SSH_OPTS = "-i .keys/deploy.key";
 | 
					    INSTALLER_SSH_OPTS = "-i .keys/deploy.key";
 | 
				
			||||||
@@ -25,7 +24,9 @@ in
 | 
				
			|||||||
    coreutils
 | 
					    coreutils
 | 
				
			||||||
    nixVersions.stable
 | 
					    nixVersions.stable
 | 
				
			||||||
    rage
 | 
					    rage
 | 
				
			||||||
    deploy-rs.deploy-rs
 | 
					    (pkgs.writeShellScriptBin "deploy" ''
 | 
				
			||||||
 | 
					      exec ${deploy-rs.deploy-rs}/bin/deploy --skip-checks "$@"
 | 
				
			||||||
 | 
					    '')
 | 
				
			||||||
    home-manager
 | 
					    home-manager
 | 
				
			||||||
    attic-client
 | 
					    attic-client
 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										158
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										158
									
								
								flake.lock
									
									
									
										generated
									
									
									
								
							@@ -35,11 +35,11 @@
 | 
				
			|||||||
        ]
 | 
					        ]
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1698258239,
 | 
					        "lastModified": 1702969472,
 | 
				
			||||||
        "narHash": "sha256-qnhoYYIJ0L/P7H/f56lQUEvpzNlXh4sxuHpRERV+B44=",
 | 
					        "narHash": "sha256-IJP9sC+/gLUdWhm6TsnWpw6A1zQWUfn53ym63KeLXvU=",
 | 
				
			||||||
        "owner": "zhaofengli",
 | 
					        "owner": "zhaofengli",
 | 
				
			||||||
        "repo": "attic",
 | 
					        "repo": "attic",
 | 
				
			||||||
        "rev": "e9918bc6be268da6fa97af6ced15193d8a0421c0",
 | 
					        "rev": "bdafd64910bb2b861cf90fa15f1fc93318b6fbf6",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -95,26 +95,17 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "crane": {
 | 
					    "crane": {
 | 
				
			||||||
      "inputs": {
 | 
					      "inputs": {
 | 
				
			||||||
        "flake-compat": [
 | 
					 | 
				
			||||||
          "attic",
 | 
					 | 
				
			||||||
          "flake-compat"
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "flake-utils": [
 | 
					 | 
				
			||||||
          "attic",
 | 
					 | 
				
			||||||
          "flake-utils"
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "nixpkgs": [
 | 
					        "nixpkgs": [
 | 
				
			||||||
          "attic",
 | 
					          "attic",
 | 
				
			||||||
          "nixpkgs"
 | 
					          "nixpkgs"
 | 
				
			||||||
        ],
 | 
					        ]
 | 
				
			||||||
        "rust-overlay": "rust-overlay"
 | 
					 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1677892403,
 | 
					        "lastModified": 1702918879,
 | 
				
			||||||
        "narHash": "sha256-/Wi0L1spSWLFj+UQxN3j0mPYMoc7ZoAujpUF/juFVII=",
 | 
					        "narHash": "sha256-tWJqzajIvYcaRWxn+cLUB9L9Pv4dQ3Bfit/YjU5ze3g=",
 | 
				
			||||||
        "owner": "ipetkov",
 | 
					        "owner": "ipetkov",
 | 
				
			||||||
        "repo": "crane",
 | 
					        "repo": "crane",
 | 
				
			||||||
        "rev": "105e27adb70a9890986b6d543a67761cbc1964a2",
 | 
					        "rev": "7195c00c272fdd92fc74e7d5a0a2844b9fadb2fb",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -185,11 +176,11 @@
 | 
				
			|||||||
        "utils": "utils"
 | 
					        "utils": "utils"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1695052866,
 | 
					        "lastModified": 1703087360,
 | 
				
			||||||
        "narHash": "sha256-agn7F9Oww4oU6nPiw+YiYI9Xb4vOOE73w8PAoBRP4AA=",
 | 
					        "narHash": "sha256-0VUbWBW8VyiDRuimMuLsEO4elGuUw/nc2WDeuO1eN1M=",
 | 
				
			||||||
        "owner": "serokell",
 | 
					        "owner": "serokell",
 | 
				
			||||||
        "repo": "deploy-rs",
 | 
					        "repo": "deploy-rs",
 | 
				
			||||||
        "rev": "e3f41832680801d0ee9e2ed33eb63af398b090e9",
 | 
					        "rev": "b709d63debafce9f5645a5ba550c9e0983b3d1f7",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -241,14 +232,14 @@
 | 
				
			|||||||
        "nixpkgs": [
 | 
					        "nixpkgs": [
 | 
				
			||||||
          "nixpkgs-unstable"
 | 
					          "nixpkgs-unstable"
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "systems": "systems_3"
 | 
					        "systems": "systems_4"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1698410321,
 | 
					        "lastModified": 1701787589,
 | 
				
			||||||
        "narHash": "sha256-MphuSlgpmKwtJncGMohryHiK55J1n6WzVQ/OAfmfoMc=",
 | 
					        "narHash": "sha256-ce+oQR4Zq9VOsLoh9bZT8Ip9PaMLcjjBUHVPzW5d7Cw=",
 | 
				
			||||||
        "owner": "numtide",
 | 
					        "owner": "numtide",
 | 
				
			||||||
        "repo": "devshell",
 | 
					        "repo": "devshell",
 | 
				
			||||||
        "rev": "1aed986e3c81a4f6698e85a7452cbfcc4b31a36e",
 | 
					        "rev": "44ddedcbcfc2d52a76b64fb6122f209881bd3e1e",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -276,11 +267,11 @@
 | 
				
			|||||||
    "flake-compat_2": {
 | 
					    "flake-compat_2": {
 | 
				
			||||||
      "flake": false,
 | 
					      "flake": false,
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1668681692,
 | 
					        "lastModified": 1696426674,
 | 
				
			||||||
        "narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
 | 
					        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
 | 
				
			||||||
        "owner": "edolstra",
 | 
					        "owner": "edolstra",
 | 
				
			||||||
        "repo": "flake-compat",
 | 
					        "repo": "flake-compat",
 | 
				
			||||||
        "rev": "009399224d5e398d03b22badca40a37ac85412a1",
 | 
					        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -418,14 +409,14 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "flake-utils_7": {
 | 
					    "flake-utils_7": {
 | 
				
			||||||
      "inputs": {
 | 
					      "inputs": {
 | 
				
			||||||
        "systems": "systems_4"
 | 
					        "systems": "systems_5"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1694529238,
 | 
					        "lastModified": 1701680307,
 | 
				
			||||||
        "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
 | 
					        "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
 | 
				
			||||||
        "owner": "numtide",
 | 
					        "owner": "numtide",
 | 
				
			||||||
        "repo": "flake-utils",
 | 
					        "repo": "flake-utils",
 | 
				
			||||||
        "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
 | 
					        "rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -451,7 +442,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "flake-utils_9": {
 | 
					    "flake-utils_9": {
 | 
				
			||||||
      "inputs": {
 | 
					      "inputs": {
 | 
				
			||||||
        "systems": "systems_5"
 | 
					        "systems": "systems_6"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1681202837,
 | 
					        "lastModified": 1681202837,
 | 
				
			||||||
@@ -474,16 +465,16 @@
 | 
				
			|||||||
        ]
 | 
					        ]
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1695108154,
 | 
					        "lastModified": 1703367386,
 | 
				
			||||||
        "narHash": "sha256-gSg7UTVtls2yO9lKtP0yb66XBHT1Fx5qZSZbGMpSn2c=",
 | 
					        "narHash": "sha256-FMbm48UGrBfOWGt8+opuS+uLBLQlRfhiYXhHNcYMS5k=",
 | 
				
			||||||
        "owner": "nix-community",
 | 
					        "owner": "nix-community",
 | 
				
			||||||
        "repo": "home-manager",
 | 
					        "repo": "home-manager",
 | 
				
			||||||
        "rev": "07682fff75d41f18327a871088d20af2710d4744",
 | 
					        "rev": "d5824a76bc6bb93d1dce9ebbbcb09a9b6abcc224",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
        "id": "home-manager",
 | 
					        "id": "home-manager",
 | 
				
			||||||
        "ref": "release-23.05",
 | 
					        "ref": "release-23.11",
 | 
				
			||||||
        "type": "indirect"
 | 
					        "type": "indirect"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@@ -494,11 +485,11 @@
 | 
				
			|||||||
        ]
 | 
					        ]
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1698670511,
 | 
					        "lastModified": 1703754036,
 | 
				
			||||||
        "narHash": "sha256-jQIu3UhBMPHXzVkHQO1O2gg8SVo5lqAVoC6mOaLQcLQ=",
 | 
					        "narHash": "sha256-JpJdcj9Tg4lMuYikXDpajA8wOp+rHyn9RD2rKBEM4cQ=",
 | 
				
			||||||
        "owner": "nix-community",
 | 
					        "owner": "nix-community",
 | 
				
			||||||
        "repo": "home-manager",
 | 
					        "repo": "home-manager",
 | 
				
			||||||
        "rev": "8e5416b478e465985eec274bc3a018024435c106",
 | 
					        "rev": "c24c298562fe41b39909f632c5a7151bbf6b4628",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -508,11 +499,11 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "impermanence": {
 | 
					    "impermanence": {
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1697303681,
 | 
					        "lastModified": 1703656108,
 | 
				
			||||||
        "narHash": "sha256-caJ0rXeagaih+xTgRduYtYKL1rZ9ylh06CIrt1w5B4g=",
 | 
					        "narHash": "sha256-hCSUqdFJKHHbER8Cenf5JRzjMlBjIdwdftGQsO0xoJs=",
 | 
				
			||||||
        "owner": "nix-community",
 | 
					        "owner": "nix-community",
 | 
				
			||||||
        "repo": "impermanence",
 | 
					        "repo": "impermanence",
 | 
				
			||||||
        "rev": "0f317c2e9e56550ce12323eb39302d251618f5b5",
 | 
					        "rev": "033643a45a4a920660ef91caa391fbffb14da466",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -531,13 +522,13 @@
 | 
				
			|||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1685908677,
 | 
					        "lastModified": 1685908677,
 | 
				
			||||||
        "narHash": "sha256-E4zUPEUFyVWjVm45zICaHRpfGepfkE9Z2OECV9HXfA4=",
 | 
					        "narHash": "sha256-E4zUPEUFyVWjVm45zICaHRpfGepfkE9Z2OECV9HXfA4=",
 | 
				
			||||||
        "owner": "guibou",
 | 
					        "owner": "nix-community",
 | 
				
			||||||
        "repo": "nixGL",
 | 
					        "repo": "nixGL",
 | 
				
			||||||
        "rev": "489d6b095ab9d289fe11af0219a9ff00fe87c7c5",
 | 
					        "rev": "489d6b095ab9d289fe11af0219a9ff00fe87c7c5",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
        "owner": "guibou",
 | 
					        "owner": "nix-community",
 | 
				
			||||||
        "repo": "nixGL",
 | 
					        "repo": "nixGL",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -560,11 +551,11 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "nixpkgs-mine": {
 | 
					    "nixpkgs-mine": {
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1698758299,
 | 
					        "lastModified": 1703756459,
 | 
				
			||||||
        "narHash": "sha256-J5Ljnna3fmtSRXvYOo0fm+65+lsP6FO1DXNp+fnSFA8=",
 | 
					        "narHash": "sha256-ztEMyPQZh3Pb+LOoWl5lbIK2LenP59sOUBC86CDmLio=",
 | 
				
			||||||
        "owner": "devplayer0",
 | 
					        "owner": "devplayer0",
 | 
				
			||||||
        "repo": "nixpkgs",
 | 
					        "repo": "nixpkgs",
 | 
				
			||||||
        "rev": "aebb3f35c0cb5270052dd4a1ac511cca5607a65e",
 | 
					        "rev": "e80160eb2ac3a7111d07cc43a15c16b9edca01ea",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -576,11 +567,11 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "nixpkgs-mine-stable": {
 | 
					    "nixpkgs-mine-stable": {
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1698758314,
 | 
					        "lastModified": 1703756491,
 | 
				
			||||||
        "narHash": "sha256-n5lkK0deuU/yHN6c+d1IeGFWW0DIOXDe2ZQK0OdMyY4=",
 | 
					        "narHash": "sha256-9VL34e0gzomwqRnryRn23V2ImYcaZIQdp7CsWg5TmlE=",
 | 
				
			||||||
        "owner": "devplayer0",
 | 
					        "owner": "devplayer0",
 | 
				
			||||||
        "repo": "nixpkgs",
 | 
					        "repo": "nixpkgs",
 | 
				
			||||||
        "rev": "2e412711696ca846a039eafcc7a23e80d85de1e3",
 | 
					        "rev": "36611f5f7cfd401f51ad4ca76fd6ee85a714bb74",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -592,26 +583,26 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "nixpkgs-stable": {
 | 
					    "nixpkgs-stable": {
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1698562188,
 | 
					        "lastModified": 1703467016,
 | 
				
			||||||
        "narHash": "sha256-9nkxGnA/T+jLhHAMFRW157Qi/zfbf5dF1q7HfKROl3o=",
 | 
					        "narHash": "sha256-/5A/dNPhbQx/Oa2d+Get174eNI3LERQ7u6WTWOlR1eQ=",
 | 
				
			||||||
        "owner": "NixOS",
 | 
					        "owner": "NixOS",
 | 
				
			||||||
        "repo": "nixpkgs",
 | 
					        "repo": "nixpkgs",
 | 
				
			||||||
        "rev": "3e10c80821dedb93592682379f476745f370a58e",
 | 
					        "rev": "d02d818f22c777aa4e854efc3242ec451e5d462a",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
        "id": "nixpkgs",
 | 
					        "id": "nixpkgs",
 | 
				
			||||||
        "ref": "nixos-23.05",
 | 
					        "ref": "nixos-23.11",
 | 
				
			||||||
        "type": "indirect"
 | 
					        "type": "indirect"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "nixpkgs-unstable": {
 | 
					    "nixpkgs-unstable": {
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1698611440,
 | 
					        "lastModified": 1703438236,
 | 
				
			||||||
        "narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=",
 | 
					        "narHash": "sha256-aqVBq1u09yFhL7bj1/xyUeJjzr92fXVvQSSEx6AdB1M=",
 | 
				
			||||||
        "owner": "NixOS",
 | 
					        "owner": "NixOS",
 | 
				
			||||||
        "repo": "nixpkgs",
 | 
					        "repo": "nixpkgs",
 | 
				
			||||||
        "rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735",
 | 
					        "rev": "5f64a12a728902226210bf01d25ec6cbb9d9265b",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
@@ -678,7 +669,7 @@
 | 
				
			|||||||
        "nixpkgs": [
 | 
					        "nixpkgs": [
 | 
				
			||||||
          "nixpkgs-unstable"
 | 
					          "nixpkgs-unstable"
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "rust-overlay": "rust-overlay_2"
 | 
					        "rust-overlay": "rust-overlay"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1682237245,
 | 
					        "lastModified": 1682237245,
 | 
				
			||||||
@@ -715,33 +706,6 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "rust-overlay": {
 | 
					    "rust-overlay": {
 | 
				
			||||||
      "inputs": {
 | 
					 | 
				
			||||||
        "flake-utils": [
 | 
					 | 
				
			||||||
          "attic",
 | 
					 | 
				
			||||||
          "crane",
 | 
					 | 
				
			||||||
          "flake-utils"
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "nixpkgs": [
 | 
					 | 
				
			||||||
          "attic",
 | 
					 | 
				
			||||||
          "crane",
 | 
					 | 
				
			||||||
          "nixpkgs"
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "locked": {
 | 
					 | 
				
			||||||
        "lastModified": 1675391458,
 | 
					 | 
				
			||||||
        "narHash": "sha256-ukDKZw922BnK5ohL9LhwtaDAdCsJL7L6ScNEyF1lO9w=",
 | 
					 | 
				
			||||||
        "owner": "oxalica",
 | 
					 | 
				
			||||||
        "repo": "rust-overlay",
 | 
					 | 
				
			||||||
        "rev": "383a4acfd11d778d5c2efcf28376cbd845eeaedf",
 | 
					 | 
				
			||||||
        "type": "github"
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      "original": {
 | 
					 | 
				
			||||||
        "owner": "oxalica",
 | 
					 | 
				
			||||||
        "repo": "rust-overlay",
 | 
					 | 
				
			||||||
        "type": "github"
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "rust-overlay_2": {
 | 
					 | 
				
			||||||
      "inputs": {
 | 
					      "inputs": {
 | 
				
			||||||
        "flake-utils": [
 | 
					        "flake-utils": [
 | 
				
			||||||
          "ragenix",
 | 
					          "ragenix",
 | 
				
			||||||
@@ -862,13 +826,31 @@
 | 
				
			|||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "utils": {
 | 
					    "systems_6": {
 | 
				
			||||||
      "locked": {
 | 
					      "locked": {
 | 
				
			||||||
        "lastModified": 1667395993,
 | 
					        "lastModified": 1681028828,
 | 
				
			||||||
        "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
 | 
					        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
 | 
				
			||||||
 | 
					        "owner": "nix-systems",
 | 
				
			||||||
 | 
					        "repo": "default",
 | 
				
			||||||
 | 
					        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "original": {
 | 
				
			||||||
 | 
					        "owner": "nix-systems",
 | 
				
			||||||
 | 
					        "repo": "default",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "utils": {
 | 
				
			||||||
 | 
					      "inputs": {
 | 
				
			||||||
 | 
					        "systems": "systems_3"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "locked": {
 | 
				
			||||||
 | 
					        "lastModified": 1701680307,
 | 
				
			||||||
 | 
					        "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
 | 
				
			||||||
        "owner": "numtide",
 | 
					        "owner": "numtide",
 | 
				
			||||||
        "repo": "flake-utils",
 | 
					        "repo": "flake-utils",
 | 
				
			||||||
        "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
 | 
					        "rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
 | 
				
			||||||
        "type": "github"
 | 
					        "type": "github"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "original": {
 | 
					      "original": {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								flake.nix
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								flake.nix
									
									
									
									
									
								
							@@ -7,13 +7,13 @@
 | 
				
			|||||||
    devshell.inputs.nixpkgs.follows = "nixpkgs-unstable";
 | 
					    devshell.inputs.nixpkgs.follows = "nixpkgs-unstable";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nixpkgs-unstable.url = "nixpkgs/nixos-unstable";
 | 
					    nixpkgs-unstable.url = "nixpkgs/nixos-unstable";
 | 
				
			||||||
    nixpkgs-stable.url = "nixpkgs/nixos-23.05";
 | 
					    nixpkgs-stable.url = "nixpkgs/nixos-23.11";
 | 
				
			||||||
    nixpkgs-mine.url = "github:devplayer0/nixpkgs/devplayer0";
 | 
					    nixpkgs-mine.url = "github:devplayer0/nixpkgs/devplayer0";
 | 
				
			||||||
    nixpkgs-mine-stable.url = "github:devplayer0/nixpkgs/devplayer0-stable";
 | 
					    nixpkgs-mine-stable.url = "github:devplayer0/nixpkgs/devplayer0-stable";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    home-manager-unstable.url = "home-manager";
 | 
					    home-manager-unstable.url = "home-manager";
 | 
				
			||||||
    home-manager-unstable.inputs.nixpkgs.follows = "nixpkgs-unstable";
 | 
					    home-manager-unstable.inputs.nixpkgs.follows = "nixpkgs-unstable";
 | 
				
			||||||
    home-manager-stable.url = "home-manager/release-23.05";
 | 
					    home-manager-stable.url = "home-manager/release-23.11";
 | 
				
			||||||
    home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable";
 | 
					    home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Stuff used by the flake for build / deployment
 | 
					    # Stuff used by the flake for build / deployment
 | 
				
			||||||
@@ -26,7 +26,7 @@
 | 
				
			|||||||
    impermanence.url = "github:nix-community/impermanence";
 | 
					    impermanence.url = "github:nix-community/impermanence";
 | 
				
			||||||
    boardie.url = "github:devplayer0/boardie";
 | 
					    boardie.url = "github:devplayer0/boardie";
 | 
				
			||||||
    boardie.inputs.nixpkgs.follows = "nixpkgs-unstable";
 | 
					    boardie.inputs.nixpkgs.follows = "nixpkgs-unstable";
 | 
				
			||||||
    nixGL.url = "github:guibou/nixGL";
 | 
					    nixGL.url = "github:nix-community/nixGL";
 | 
				
			||||||
    nixGL.inputs.nixpkgs.follows = "nixpkgs-unstable";
 | 
					    nixGL.inputs.nixpkgs.follows = "nixpkgs-unstable";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Packages not in nixpkgs
 | 
					    # Packages not in nixpkgs
 | 
				
			||||||
@@ -51,8 +51,8 @@
 | 
				
			|||||||
      ...
 | 
					      ...
 | 
				
			||||||
    }:
 | 
					    }:
 | 
				
			||||||
    let
 | 
					    let
 | 
				
			||||||
      inherit (builtins) mapAttrs;
 | 
					      inherit (builtins) mapAttrs replaceStrings;
 | 
				
			||||||
      inherit (lib) genAttrs recurseIntoAttrs evalModules;
 | 
					      inherit (lib) mapAttrs' filterAttrs nameValuePair recurseIntoAttrs evalModules;
 | 
				
			||||||
      inherit (lib.flake) flattenTree eachDefaultSystem;
 | 
					      inherit (lib.flake) flattenTree eachDefaultSystem;
 | 
				
			||||||
      inherit (lib.my) mkDefaultSystemsPkgs flakePackageOverlay;
 | 
					      inherit (lib.my) mkDefaultSystemsPkgs flakePackageOverlay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,7 +63,7 @@
 | 
				
			|||||||
        flake = flake-utils.lib;
 | 
					        flake = flake-utils.lib;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
      pkgsLibOverlay = final: prev: { lib = prev.lib.extend libOverlay; };
 | 
					      pkgsLibOverlay = final: prev: { lib = prev.lib.extend libOverlay; };
 | 
				
			||||||
      myPkgsOverlay = final: prev: import ./pkgs { lib = prev.lib; pkgs = prev; };
 | 
					      myPkgsOverlay = final: prev: import ./pkgs { lib = final.lib; pkgs = prev; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # Override the flake-level lib since we're going to use it for non-config specific stuff
 | 
					      # Override the flake-level lib since we're going to use it for non-config specific stuff
 | 
				
			||||||
      pkgsFlakes = mapAttrs (_: pkgsFlake: pkgsFlake // { lib = pkgsFlake.lib.extend libOverlay; }) {
 | 
					      pkgsFlakes = mapAttrs (_: pkgsFlake: pkgsFlake // { lib = pkgsFlake.lib.extend libOverlay; }) {
 | 
				
			||||||
@@ -116,18 +116,20 @@
 | 
				
			|||||||
        nixos/boxes/colony
 | 
					        nixos/boxes/colony
 | 
				
			||||||
        nixos/boxes/tower
 | 
					        nixos/boxes/tower
 | 
				
			||||||
        nixos/boxes/castle
 | 
					        nixos/boxes/castle
 | 
				
			||||||
 | 
					        nixos/boxes/home/stream.nix
 | 
				
			||||||
 | 
					        nixos/boxes/home/palace
 | 
				
			||||||
 | 
					        nixos/boxes/britway
 | 
				
			||||||
        nixos/boxes/kelder
 | 
					        nixos/boxes/kelder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Homes
 | 
					        # Homes
 | 
				
			||||||
        # home-manager/configs/castle.nix
 | 
					        # home-manager/configs/macsimum.nix
 | 
				
			||||||
        home-manager/configs/macsimum.nix
 | 
					 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      nixfiles = evalModules {
 | 
					      nixfiles = evalModules {
 | 
				
			||||||
        modules = [
 | 
					        modules = [
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            _module.args = {
 | 
					            _module.args = {
 | 
				
			||||||
              inherit lib pkgsFlakes hmFlakes inputs;
 | 
					              inherit lib pkgsFlakes hmFlakes self inputs;
 | 
				
			||||||
              pkgs' = configPkgs';
 | 
					              pkgs' = configPkgs';
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -164,18 +166,39 @@
 | 
				
			|||||||
      pkgs = pkgs'.mine.${system};
 | 
					      pkgs = pkgs'.mine.${system};
 | 
				
			||||||
      lib = pkgs.lib;
 | 
					      lib = pkgs.lib;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      filterSystem = filterAttrs (_: c: c.config.nixpkgs.system == system);
 | 
				
			||||||
 | 
					      homes =
 | 
				
			||||||
 | 
					        mapAttrs
 | 
				
			||||||
 | 
					          (_: h: h.activationPackage)
 | 
				
			||||||
 | 
					          (filterSystem self.homeConfigurations);
 | 
				
			||||||
 | 
					      systems =
 | 
				
			||||||
 | 
					        mapAttrs
 | 
				
			||||||
 | 
					          (_: h: h.config.system.build.toplevel)
 | 
				
			||||||
 | 
					          (filterSystem self.nixosConfigurations);
 | 
				
			||||||
      shell = pkgs.devshell.mkShell ./devshell;
 | 
					      shell = pkgs.devshell.mkShell ./devshell;
 | 
				
			||||||
    in
 | 
					    in
 | 
				
			||||||
    # Stuff for each platform
 | 
					    # Stuff for each platform
 | 
				
			||||||
    {
 | 
					    rec {
 | 
				
			||||||
      checks = flattenTree {
 | 
					      checks = flattenTree {
 | 
				
			||||||
        homeConfigurations = recurseIntoAttrs (mapAttrs (_: h: h.activationPackage)
 | 
					        homeConfigurations = recurseIntoAttrs homes;
 | 
				
			||||||
          (lib.filterAttrs (_: h: h.config.nixpkgs.system == system) self.homeConfigurations));
 | 
					 | 
				
			||||||
        deploy = recurseIntoAttrs (pkgs.deploy-rs.lib.deployChecks self.deploy);
 | 
					        deploy = recurseIntoAttrs (pkgs.deploy-rs.lib.deployChecks self.deploy);
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      packages = flattenTree (import ./pkgs { inherit lib pkgs; });
 | 
					      packages = flattenTree (import ./pkgs { inherit lib pkgs; });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      devShells.default = shell;
 | 
					      devShells.default = shell;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ci =
 | 
				
			||||||
 | 
					      let
 | 
				
			||||||
 | 
					        homes' =
 | 
				
			||||||
 | 
					          mapAttrs'
 | 
				
			||||||
 | 
					            (n: v: nameValuePair ''home-${replaceStrings ["@"] ["-at-"] n}'' v)
 | 
				
			||||||
 | 
					            homes;
 | 
				
			||||||
 | 
					        systems' = mapAttrs' (n: v: nameValuePair "system-${n}" v) systems;
 | 
				
			||||||
 | 
					        packages' = mapAttrs' (n: v: nameValuePair "package-${n}" v) packages;
 | 
				
			||||||
 | 
					      in
 | 
				
			||||||
 | 
					        pkgs.linkFarm "ci" (homes' // systems' // packages' // {
 | 
				
			||||||
 | 
					          inherit shell;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }));
 | 
					    }));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,9 +47,14 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      nix = {
 | 
					      nix = {
 | 
				
			||||||
        package = mkIf (!(versionAtLeast config.home.stateVersion "22.11")) pkgs.nix;
 | 
					        package = mkIf (!(versionAtLeast config.home.stateVersion "22.11")) pkgs.nix;
 | 
				
			||||||
        settings = {
 | 
					        settings = with lib.my.c.nix; {
 | 
				
			||||||
          experimental-features = [ "nix-command" "flakes" "ca-derivations" ];
 | 
					          experimental-features = [ "nix-command" "flakes" "ca-derivations" ];
 | 
				
			||||||
          max-jobs = mkDefault "auto";
 | 
					          max-jobs = mkDefault "auto";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          extra-substituters = cache.substituters;
 | 
				
			||||||
 | 
					          extra-trusted-public-keys = cache.keys;
 | 
				
			||||||
 | 
					          connect-timeout = 5;
 | 
				
			||||||
 | 
					          fallback = true;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,6 +80,7 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        tmux = {
 | 
					        tmux = {
 | 
				
			||||||
          enable = true;
 | 
					          enable = true;
 | 
				
			||||||
 | 
					          keyMode = "vi";
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bash = {
 | 
					        bash = {
 | 
				
			||||||
@@ -235,13 +241,6 @@ in
 | 
				
			|||||||
            exact = true;
 | 
					            exact = true;
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        settings = {
 | 
					 | 
				
			||||||
          substituters = [
 | 
					 | 
				
			||||||
            #"https://nix-cache.nul.ie"
 | 
					 | 
				
			||||||
            "https://cache.nixos.org"
 | 
					 | 
				
			||||||
          ];
 | 
					 | 
				
			||||||
          trusted-public-keys = lib.my.c.nix.cacheKeys;
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    (mkIf config.my.isStandalone {
 | 
					    (mkIf config.my.isStandalone {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,6 +61,7 @@ in
 | 
				
			|||||||
            settings = {
 | 
					            settings = {
 | 
				
			||||||
              background_opacity = "0.8";
 | 
					              background_opacity = "0.8";
 | 
				
			||||||
              tab_bar_edge = "top";
 | 
					              tab_bar_edge = "top";
 | 
				
			||||||
 | 
					              shell_integration = "no-sudo";
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,13 +70,17 @@ in
 | 
				
			|||||||
        "swaync/config.json" = mkIf (cfg.settings != { }) {
 | 
					        "swaync/config.json" = mkIf (cfg.settings != { }) {
 | 
				
			||||||
          source = configSource;
 | 
					          source = configSource;
 | 
				
			||||||
          onChange = ''
 | 
					          onChange = ''
 | 
				
			||||||
            ${cfg.package}/bin/swaync-client --reload-config
 | 
					            if ${pkgs.systemd}/bin/systemctl --user is-active --quiet swaync; then
 | 
				
			||||||
 | 
					              ${cfg.package}/bin/swaync-client --reload-config
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
          '';
 | 
					          '';
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        "swaync/style.css" = mkIf (cfg.style != null) {
 | 
					        "swaync/style.css" = mkIf (cfg.style != null) {
 | 
				
			||||||
          source = styleSource;
 | 
					          source = styleSource;
 | 
				
			||||||
          onChange = ''
 | 
					          onChange = ''
 | 
				
			||||||
            ${cfg.package}/bin/swaync-client --reload-css
 | 
					            if ${pkgs.systemd}/bin/systemctl --user is-active --quiet swaync; then
 | 
				
			||||||
 | 
					              ${cfg.package}/bin/swaync-client --reload-css
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
          '';
 | 
					          '';
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,19 +1,32 @@
 | 
				
			|||||||
{ lib }: rec {
 | 
					{ lib }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib) concatStringsSep;
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					rec {
 | 
				
			||||||
  # See https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/misc/ids.nix
 | 
					  # See https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/misc/ids.nix
 | 
				
			||||||
  ids = {
 | 
					  ids = {
 | 
				
			||||||
    uids = {
 | 
					    uids = {
 | 
				
			||||||
      matrix-syncv3 = 400;
 | 
					      matrix-syncv3 = 400;
 | 
				
			||||||
      gitea-runner = 401;
 | 
					      gitea-runner = 401;
 | 
				
			||||||
      jellyseerr = 402;
 | 
					      jellyseerr = 402;
 | 
				
			||||||
 | 
					      atticd = 403;
 | 
				
			||||||
 | 
					      kea = 404;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    gids = {
 | 
					    gids = {
 | 
				
			||||||
      matrix-syncv3 = 400;
 | 
					      matrix-syncv3 = 400;
 | 
				
			||||||
      gitea-runner = 401;
 | 
					      gitea-runner = 401;
 | 
				
			||||||
      jellyseerr = 402;
 | 
					      jellyseerr = 402;
 | 
				
			||||||
 | 
					      atticd = 403;
 | 
				
			||||||
 | 
					      kea = 404;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  nginx = {
 | 
					  kernel = {
 | 
				
			||||||
 | 
					    lts = pkgs: pkgs.linuxKernel.packages.linux_6_1;
 | 
				
			||||||
 | 
					    latest = pkgs: pkgs.linuxKernel.packages.linux_6_6;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  nginx = rec {
 | 
				
			||||||
    proxyHeaders = ''
 | 
					    proxyHeaders = ''
 | 
				
			||||||
      # Setting any proxy_header in a child (e.g. location) will nuke the parents...
 | 
					      # Setting any proxy_header in a child (e.g. location) will nuke the parents...
 | 
				
			||||||
      proxy_set_header X-Origin-URI $request_uri;
 | 
					      proxy_set_header X-Origin-URI $request_uri;
 | 
				
			||||||
@@ -27,18 +40,76 @@
 | 
				
			|||||||
      proxy_set_header X-Forwarded-Protocol $scheme;
 | 
					      proxy_set_header X-Forwarded-Protocol $scheme;
 | 
				
			||||||
      proxy_set_header X-Scheme $scheme;
 | 
					      proxy_set_header X-Scheme $scheme;
 | 
				
			||||||
    '';
 | 
					    '';
 | 
				
			||||||
 | 
					    baseHttpConfig = ''
 | 
				
			||||||
 | 
					      # NixOS provides a logrotate config that auto-compresses :)
 | 
				
			||||||
 | 
					      log_format main
 | 
				
			||||||
 | 
					        '$remote_addr - $remote_user [$time_local] $scheme "$host" "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
 | 
				
			||||||
 | 
					      access_log /var/log/nginx/access.log main;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # optimisation
 | 
				
			||||||
 | 
					      sendfile on;
 | 
				
			||||||
 | 
					      tcp_nopush on;
 | 
				
			||||||
 | 
					      tcp_nodelay on;
 | 
				
			||||||
 | 
					      keepalive_timeout 65;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # gzip
 | 
				
			||||||
 | 
					      gzip on;
 | 
				
			||||||
 | 
					      gzip_proxied any;
 | 
				
			||||||
 | 
					      gzip_comp_level 5;
 | 
				
			||||||
 | 
					      gzip_types
 | 
				
			||||||
 | 
					        application/atom+xml
 | 
				
			||||||
 | 
					        application/javascript
 | 
				
			||||||
 | 
					        application/json
 | 
				
			||||||
 | 
					        application/xml
 | 
				
			||||||
 | 
					        application/xml+rss
 | 
				
			||||||
 | 
					        image/svg+xml
 | 
				
			||||||
 | 
					        text/css
 | 
				
			||||||
 | 
					        text/javascript
 | 
				
			||||||
 | 
					        text/plain
 | 
				
			||||||
 | 
					        text/xml;
 | 
				
			||||||
 | 
					      gzip_vary on;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # proxying
 | 
				
			||||||
 | 
					      proxy_buffering off;
 | 
				
			||||||
 | 
					      proxy_redirect off;
 | 
				
			||||||
 | 
					      proxy_connect_timeout 60s;
 | 
				
			||||||
 | 
					      proxy_read_timeout 60s;
 | 
				
			||||||
 | 
					      proxy_send_timeout 60s;
 | 
				
			||||||
 | 
					      proxy_http_version 1.1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ${proxyHeaders}
 | 
				
			||||||
 | 
					    '';
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  networkd = {
 | 
				
			||||||
 | 
					    noL3 = {
 | 
				
			||||||
 | 
					      LinkLocalAddressing = "no";
 | 
				
			||||||
 | 
					      DHCP = "no";
 | 
				
			||||||
 | 
					      LLDP = false;
 | 
				
			||||||
 | 
					      EmitLLDP = false;
 | 
				
			||||||
 | 
					      IPv6AcceptRA = false;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  nix = {
 | 
					  nix = {
 | 
				
			||||||
    cacheKeys = [
 | 
					    cache = rec {
 | 
				
			||||||
      "nix-cache.nul.ie-1:XofkqdHQSGFoPjB6aRohQbCU2ILKFqhNjWfoOdQgF5Y="
 | 
					      substituters = [
 | 
				
			||||||
      "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
 | 
					        "https://nix-cache.${pubDomain}/main"
 | 
				
			||||||
    ];
 | 
					      ];
 | 
				
			||||||
 | 
					      keys = [
 | 
				
			||||||
 | 
					        "main:mMChkG8LwXrFirVfudqjSHasK1jV31OVElYD3eImYl8="
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					      conf = ''
 | 
				
			||||||
 | 
					        extra-substituters = ${concatStringsSep " " substituters}
 | 
				
			||||||
 | 
					        extra-trusted-public-keys = ${concatStringsSep " " keys}
 | 
				
			||||||
 | 
					      '';
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pubDomain = "nul.ie";
 | 
					  pubDomain = "nul.ie";
 | 
				
			||||||
  colony = {
 | 
					  colony = {
 | 
				
			||||||
    domain = "ams1.int.${pubDomain}";
 | 
					    domain = "ams1.int.${pubDomain}";
 | 
				
			||||||
 | 
					    pubV4 = "94.142.240.44";
 | 
				
			||||||
    prefixes = with lib.my.net.cidr; rec {
 | 
					    prefixes = with lib.my.net.cidr; rec {
 | 
				
			||||||
      all = {
 | 
					      all = {
 | 
				
			||||||
        v4 = "10.100.0.0/16";
 | 
					        v4 = "10.100.0.0/16";
 | 
				
			||||||
@@ -76,13 +147,179 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      vip1 = "94.142.241.224/30";
 | 
					      vip1 = "94.142.241.224/30";
 | 
				
			||||||
      vip2 = "94.142.242.254/31";
 | 
					      vip2 = "94.142.242.254/31";
 | 
				
			||||||
 | 
					      vip3 = "94.142.241.117/32";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      as211024 = {
 | 
				
			||||||
 | 
					        v4 = subnet 8 50 all.v4;
 | 
				
			||||||
 | 
					        v6 = "2a0e:97c0:4df::/64";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      home.v6 = "2a0e:97c0:4d0::/48";
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    firewallForwards = aa: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        port = "http";
 | 
				
			||||||
 | 
					        dst = aa.middleman.internal.ipv4.address;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        port = "https";
 | 
				
			||||||
 | 
					        dst = aa.middleman.internal.ipv4.address;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        port = 8448;
 | 
				
			||||||
 | 
					        dst = aa.middleman.internal.ipv4.address;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        port = 25565;
 | 
				
			||||||
 | 
					        dst = aa.simpcraft-oci.internal.ipv4.address;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        port = 25566;
 | 
				
			||||||
 | 
					        dst = aa.simpcraft-staging-oci.internal.ipv4.address;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        port = 25575;
 | 
				
			||||||
 | 
					        dst = aa.simpcraft-oci.internal.ipv4.address;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        port = 2456;
 | 
				
			||||||
 | 
					        dst = aa.valheim-oci.internal.ipv4.address;
 | 
				
			||||||
 | 
					        proto = "udp";
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        port = 2457;
 | 
				
			||||||
 | 
					        dst = aa.valheim-oci.internal.ipv4.address;
 | 
				
			||||||
 | 
					        proto = "udp";
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        port = 41641;
 | 
				
			||||||
 | 
					        dst = aa.waffletail.internal.ipv4.address;
 | 
				
			||||||
 | 
					        proto = "udp";
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        port = 25565;
 | 
				
			||||||
 | 
					        dst = aa.simpcraft-oci.internal.ipv4.address;
 | 
				
			||||||
 | 
					        proto = "udp";
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fstrimConfig = {
 | 
					    fstrimConfig = {
 | 
				
			||||||
      enable = true;
 | 
					      enable = true;
 | 
				
			||||||
      # backup happens at 05:00
 | 
					      # backup happens at 05:00
 | 
				
			||||||
      interval = "04:45";
 | 
					      interval = "04:45";
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  home = rec {
 | 
				
			||||||
 | 
					    domain = "h.${pubDomain}";
 | 
				
			||||||
 | 
					    vlans = {
 | 
				
			||||||
 | 
					      hi = 100;
 | 
				
			||||||
 | 
					      lo = 110;
 | 
				
			||||||
 | 
					      untrusted = 120;
 | 
				
			||||||
 | 
					      wan = 130;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    hiMTU = 9000;
 | 
				
			||||||
 | 
					    routers = [
 | 
				
			||||||
 | 
					      "river"
 | 
				
			||||||
 | 
					      "stream"
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    routersPubV4 = [
 | 
				
			||||||
 | 
					      "109.255.1.246"
 | 
				
			||||||
 | 
					      "109.255.252.63"
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    prefixes = with lib.my.net.cidr; rec {
 | 
				
			||||||
 | 
					      modem = {
 | 
				
			||||||
 | 
					        v4 = "192.168.0.0/24";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      all = {
 | 
				
			||||||
 | 
					        v4 = "192.168.64.0/18";
 | 
				
			||||||
 | 
					        v6 = "2a0e:97c0:4d0::/60";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      core = {
 | 
				
			||||||
 | 
					        v4 = subnet 6 0 all.v4;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      hi = {
 | 
				
			||||||
 | 
					        v4 = subnet 4 1 all.v4;
 | 
				
			||||||
 | 
					        v6 = subnet 4 1 all.v6;
 | 
				
			||||||
 | 
					        mtu = hiMTU;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      lo = {
 | 
				
			||||||
 | 
					        v4 = subnet 3 1 all.v4;
 | 
				
			||||||
 | 
					        v6 = subnet 4 2 all.v6;
 | 
				
			||||||
 | 
					        mtu = 1500;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      untrusted = {
 | 
				
			||||||
 | 
					        v4 = subnet 6 16 all.v4;
 | 
				
			||||||
 | 
					        v6 = subnet 4 3 all.v6;
 | 
				
			||||||
 | 
					        mtu = 1500;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      inherit (colony.prefixes) as211024;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    vips = with lib.my.net.cidr; {
 | 
				
			||||||
 | 
					      hi = {
 | 
				
			||||||
 | 
					        v4 = host (4*256-2) prefixes.hi.v4;
 | 
				
			||||||
 | 
					        v6 = host 65535 prefixes.hi.v6;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      lo = {
 | 
				
			||||||
 | 
					        v4 = host (8*256-2) prefixes.lo.v4;
 | 
				
			||||||
 | 
					        v6 = host 65535 prefixes.lo.v6;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      untrusted = {
 | 
				
			||||||
 | 
					        v4 = host 254 prefixes.untrusted.v4;
 | 
				
			||||||
 | 
					        v6 = host 65535 prefixes.untrusted.v6;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      as211024 = {
 | 
				
			||||||
 | 
					        v4 = host 4 prefixes.as211024.v4;
 | 
				
			||||||
 | 
					        v6 = host ((1*65536*65536*65536) + 65535) prefixes.as211024.v6;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  britway = {
 | 
				
			||||||
 | 
					    domain = "lon1.int.${pubDomain}";
 | 
				
			||||||
 | 
					    pubV4 = "45.76.141.188";
 | 
				
			||||||
 | 
					    prefixes = {
 | 
				
			||||||
 | 
					      vultr = {
 | 
				
			||||||
 | 
					        v6 = "2001:19f0:7402:128b::/64";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      inherit (colony.prefixes) as211024;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    # Need to use this IP as the source address for BGP
 | 
				
			||||||
 | 
					    assignedV6 = "2001:19f0:7402:128b:5400:04ff:feac:6e06";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  tailscale = {
 | 
				
			||||||
 | 
					    prefix = {
 | 
				
			||||||
 | 
					      v4 = "100.64.0.0/10";
 | 
				
			||||||
 | 
					      v6 = "fd7a:115c:a1e0::/48";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  as211024 = rec {
 | 
				
			||||||
 | 
					    trusted = {
 | 
				
			||||||
 | 
					      v4 = [
 | 
				
			||||||
 | 
					        colony.prefixes.as211024.v4
 | 
				
			||||||
 | 
					        colony.prefixes.all.v4
 | 
				
			||||||
 | 
					        home.prefixes.all.v4
 | 
				
			||||||
 | 
					        tailscale.prefix.v4
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					      v6 = [
 | 
				
			||||||
 | 
					        colony.prefixes.as211024.v6
 | 
				
			||||||
 | 
					        colony.prefixes.all.v6
 | 
				
			||||||
 | 
					        home.prefixes.all.v6
 | 
				
			||||||
 | 
					        tailscale.prefix.v6
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    nftTrust = ''
 | 
				
			||||||
 | 
					      iifname as211024 ip saddr { ${concatStringsSep ", " trusted.v4} } accept
 | 
				
			||||||
 | 
					      iifname as211024 ip6 saddr { ${concatStringsSep ", " trusted.v6} } accept
 | 
				
			||||||
 | 
					    '';
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  kelder = {
 | 
					  kelder = {
 | 
				
			||||||
    groups = {
 | 
					    groups = {
 | 
				
			||||||
      storage = 2000;
 | 
					      storage = 2000;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,26 @@
 | 
				
			|||||||
{ lib }:
 | 
					{ lib }:
 | 
				
			||||||
let
 | 
					let
 | 
				
			||||||
  inherit (builtins) length match elemAt filter;
 | 
					  inherit (builtins) length match elemAt filter replaceStrings substring;
 | 
				
			||||||
  inherit (lib)
 | 
					  inherit (lib)
 | 
				
			||||||
    genAttrs mapAttrsToList filterAttrsRecursive nameValuePair types
 | 
					    genAttrs mapAttrsToList filterAttrsRecursive nameValuePair types
 | 
				
			||||||
    mkOption mkOverride mkForce mkIf mergeEqualOption optional
 | 
					    mkOption mkOverride mkForce mkIf mergeEqualOption optional
 | 
				
			||||||
    showWarnings concatStringsSep flatten unique;
 | 
					    showWarnings concatStringsSep flatten unique optionalAttrs
 | 
				
			||||||
 | 
					    mkBefore;
 | 
				
			||||||
  inherit (lib.flake) defaultSystems;
 | 
					  inherit (lib.flake) defaultSystems;
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
rec {
 | 
					rec {
 | 
				
			||||||
 | 
					  pow =
 | 
				
			||||||
 | 
					    let
 | 
				
			||||||
 | 
					      pow' = base: exponent: value:
 | 
				
			||||||
 | 
					        # FIXME: It will silently overflow on values > 2**62 :(
 | 
				
			||||||
 | 
					        # The value will become negative or zero in this case
 | 
				
			||||||
 | 
					        if exponent == 0
 | 
				
			||||||
 | 
					        then 1
 | 
				
			||||||
 | 
					        else if exponent <= 1
 | 
				
			||||||
 | 
					        then value
 | 
				
			||||||
 | 
					        else (pow' base (exponent - 1) (value * base));
 | 
				
			||||||
 | 
					    in base: exponent: pow' base exponent base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  attrsToNVList = mapAttrsToList nameValuePair;
 | 
					  attrsToNVList = mapAttrsToList nameValuePair;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  inherit (import ./net.nix { inherit lib; }) net;
 | 
					  inherit (import ./net.nix { inherit lib; }) net;
 | 
				
			||||||
@@ -29,6 +42,8 @@ rec {
 | 
				
			|||||||
      ports = checked (elemAt m 1);
 | 
					      ports = checked (elemAt m 1);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  netBroadcast = net': net.cidr.host ((pow 2 (net.cidr.size net')) - 1) net';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mkDefaultSystemsPkgs = path: args': genAttrs defaultSystems (system: import path ((args' system) // { inherit system; }));
 | 
					  mkDefaultSystemsPkgs = path: args': genAttrs defaultSystems (system: import path ((args' system) // { inherit system; }));
 | 
				
			||||||
  mkApp = program: { type = "app"; inherit program; };
 | 
					  mkApp = program: { type = "app"; inherit program; };
 | 
				
			||||||
  mkShellApp = pkgs: name: text: mkApp (pkgs.writeShellScript name text).outPath;
 | 
					  mkShellApp = pkgs: name: text: mkApp (pkgs.writeShellScript name text).outPath;
 | 
				
			||||||
@@ -109,6 +124,21 @@ rec {
 | 
				
			|||||||
    home-manager = mkOpt' (enum [ "unstable" "stable" "mine" "mine-stable" ]) "unstable" "Branch of home-manager to use.";
 | 
					    home-manager = mkOpt' (enum [ "unstable" "stable" "mine" "mine-stable" ]) "unstable" "Branch of home-manager to use.";
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  nft = rec {
 | 
				
			||||||
 | 
					    ipEscape = replaceStrings ["." ":"] ["-" "-"];
 | 
				
			||||||
 | 
					    natFilterChain = ip: "filter-fwd-${ipEscape ip}";
 | 
				
			||||||
 | 
					    dnatChain = ip: "fwd-${ipEscape ip}";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mkVLAN = name: vid: {
 | 
				
			||||||
 | 
					    "25-${name}" = {
 | 
				
			||||||
 | 
					      netdevConfig = {
 | 
				
			||||||
 | 
					        Name = name;
 | 
				
			||||||
 | 
					        Kind = "vlan";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      vlanConfig.Id = vid;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
  networkdAssignment = iface: a: {
 | 
					  networkdAssignment = iface: a: {
 | 
				
			||||||
    matchConfig.Name = iface;
 | 
					    matchConfig.Name = iface;
 | 
				
			||||||
    address =
 | 
					    address =
 | 
				
			||||||
@@ -123,6 +153,9 @@ rec {
 | 
				
			|||||||
      LLDP = true;
 | 
					      LLDP = true;
 | 
				
			||||||
      EmitLLDP = "customer-bridge";
 | 
					      EmitLLDP = "customer-bridge";
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    linkConfig = optionalAttrs (a.mtu != null) {
 | 
				
			||||||
 | 
					      MTUBytes = toString a.mtu;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    ipv6AcceptRAConfig = {
 | 
					    ipv6AcceptRAConfig = {
 | 
				
			||||||
      Token = mkIf (a.ipv6.iid != null) "static:${a.ipv6.iid}";
 | 
					      Token = mkIf (a.ipv6.iid != null) "static:${a.ipv6.iid}";
 | 
				
			||||||
      UseDNS = true;
 | 
					      UseDNS = true;
 | 
				
			||||||
@@ -134,13 +167,32 @@ rec {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  systemdAwaitPostgres = pkg: host: {
 | 
					  systemdAwaitPostgres = pkg: host: {
 | 
				
			||||||
    after = [ "systemd-networkd-wait-online.service" ];
 | 
					    after = [ "systemd-networkd-wait-online.service" ];
 | 
				
			||||||
    preStart = ''
 | 
					    preStart = mkBefore ''
 | 
				
			||||||
      until ${pkg}/bin/pg_isready -h ${host}; do
 | 
					      until ${pkg}/bin/pg_isready -h ${host}; do
 | 
				
			||||||
        sleep 0.5
 | 
					        sleep 0.5
 | 
				
			||||||
      done
 | 
					      done
 | 
				
			||||||
    '';
 | 
					    '';
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  vm = rec {
 | 
				
			||||||
 | 
					    lvmDisk' = name: lv: {
 | 
				
			||||||
 | 
					      inherit name;
 | 
				
			||||||
 | 
					      backend = {
 | 
				
			||||||
 | 
					        driver = "host_device";
 | 
				
			||||||
 | 
					        filename = "/dev/main/${lv}";
 | 
				
			||||||
 | 
					        # It appears this needs to be set on the backend _and_ the format
 | 
				
			||||||
 | 
					        discard = "unmap";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      format = {
 | 
				
			||||||
 | 
					        driver = "raw";
 | 
				
			||||||
 | 
					        discard = "unmap";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      frontend = "virtio-blk";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    lvmDisk = lv: lvmDisk' lv lv;
 | 
				
			||||||
 | 
					    disk = vm: lv: lvmDisk' lv "vm-${vm}-${lv}";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deploy-rs =
 | 
					  deploy-rs =
 | 
				
			||||||
  with types;
 | 
					  with types;
 | 
				
			||||||
  let
 | 
					  let
 | 
				
			||||||
@@ -188,4 +240,18 @@ rec {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    filterOpts = filterAttrsRecursive (_: v: v != null);
 | 
					    filterOpts = filterAttrsRecursive (_: v: v != null);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  versionOverlay = { self, pkgsFlake }: final: prev:
 | 
				
			||||||
 | 
					  let
 | 
				
			||||||
 | 
					    date = substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101");
 | 
				
			||||||
 | 
					    revCode = flake: flake.shortRev or "dirty";
 | 
				
			||||||
 | 
					  in
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    trivial = prev.trivial // {
 | 
				
			||||||
 | 
					      release = "23.12:u-${prev.trivial.release}";
 | 
				
			||||||
 | 
					      codeName = "Amogus";
 | 
				
			||||||
 | 
					      revisionWithDefault = default: self.rev or default;
 | 
				
			||||||
 | 
					      versionSuffix = ".${date}.${revCode self}:u-${revCode pkgsFlake}";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										31
									
								
								lib/dns.nix
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								lib/dns.nix
									
									
									
									
									
								
							@@ -67,4 +67,35 @@ rec {
 | 
				
			|||||||
          (a.ipv6.address != null && a.ipv6.genPTR)
 | 
					          (a.ipv6.address != null && a.ipv6.genPTR)
 | 
				
			||||||
          ''@@PTR:${a.ipv6.address}:${toString ndots}@@ IN PTR ${a.name}.${domain}.'';
 | 
					          ''@@PTR:${a.ipv6.address}:${toString ndots}@@ IN PTR ${a.name}.${domain}.'';
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ifaceA = { pkgs, iface, skipBroadcasts ? [] }:
 | 
				
			||||||
 | 
					  let
 | 
				
			||||||
 | 
					    extraFilters = concatMapStringsSep " " (b: ''and .broadcast != \"${b}\"'') skipBroadcasts;
 | 
				
			||||||
 | 
					    script = pkgs.writeText "if-${iface}-a.lua" ''
 | 
				
			||||||
 | 
					      local proc = io.popen("${pkgs.iproute2}/bin/ip -j addr show dev ${iface} | ${pkgs.jq}/bin/jq -r '.[0].addr_info[] | select(.family == \"inet\" and .scope == \"global\" ${extraFilters}).local'", "r")
 | 
				
			||||||
 | 
					      assert(proc, "failed to popen")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      local addr_line = proc:read("*l")
 | 
				
			||||||
 | 
					      assert(proc:close(), "command failed")
 | 
				
			||||||
 | 
					      assert(addr_line, "no output from command")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return addr_line
 | 
				
			||||||
 | 
					    '';
 | 
				
			||||||
 | 
					  in
 | 
				
			||||||
 | 
					    ''A "dofile('${script}')"'';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  lookupIP = { pkgs, hostname, server, type ? "A" }:
 | 
				
			||||||
 | 
					  let
 | 
				
			||||||
 | 
					    script = pkgs.writeScript "drill-${hostname}-${server}.lua" ''
 | 
				
			||||||
 | 
					      local proc = io.popen("${pkgs.ldns}/bin/drill -Q @${server} ${hostname} ${type}", "r")
 | 
				
			||||||
 | 
					      assert(proc, "failed to popen")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      local addr_line = proc:read("*l")
 | 
				
			||||||
 | 
					      assert(proc:close(), "command failed")
 | 
				
			||||||
 | 
					      assert(addr_line, "no output from command")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return addr_line
 | 
				
			||||||
 | 
					    '';
 | 
				
			||||||
 | 
					  in
 | 
				
			||||||
 | 
					    ''${type} "dofile('${script}')"'';
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										197
									
								
								nixos/boxes/britway/bgp.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								nixos/boxes/britway/bgp.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,197 @@
 | 
				
			|||||||
 | 
					{ lib, pkgs, config, assignments, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib.my.c.britway) assignedV6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  securebitSpace = "2a0e:97c0:4d0::/44";
 | 
				
			||||||
 | 
					  intnet6 = "2a0e:97c0:4df::/48";
 | 
				
			||||||
 | 
					  amsnet6 = "2a0e:97c0:4d2::/48";
 | 
				
			||||||
 | 
					  homenet6 = "2a0e:97c0:4d0::/48";
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  config = {
 | 
				
			||||||
 | 
					    my = {
 | 
				
			||||||
 | 
					      secrets.files."britway/bgp-password-vultr.conf" = {
 | 
				
			||||||
 | 
					        owner = "bird2";
 | 
				
			||||||
 | 
					        group = "bird2";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    environment.etc."bird/vultr-password.conf".source = config.age.secrets."britway/bgp-password-vultr.conf".path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    systemd = {
 | 
				
			||||||
 | 
					      services.bird2.after = [ "systemd-networkd-wait-online@veth0.service" ];
 | 
				
			||||||
 | 
					      network = {
 | 
				
			||||||
 | 
					        config.networkConfig.ManageForeignRoutes = false;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    services = {
 | 
				
			||||||
 | 
					      bird2 = {
 | 
				
			||||||
 | 
					        enable = true;
 | 
				
			||||||
 | 
					        preCheckConfig = ''
 | 
				
			||||||
 | 
					          echo '"dummy"' > vultr-password.conf
 | 
				
			||||||
 | 
					        '';
 | 
				
			||||||
 | 
					        # TODO: Clean up and modularise
 | 
				
			||||||
 | 
					        config = ''
 | 
				
			||||||
 | 
					          define OWNAS = 211024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          define OWNIP4 = ${assignments.vultr.ipv4.address};
 | 
				
			||||||
 | 
					          define OWNNETSET4 = [ ${assignments.vultr.ipv4.address}/32 ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          define INTNET6 = ${intnet6};
 | 
				
			||||||
 | 
					          define AMSNET6 = ${amsnet6};
 | 
				
			||||||
 | 
					          define HOMENET6 = ${homenet6};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          define OWNIP6 = ${assignments.vultr.ipv6.address};
 | 
				
			||||||
 | 
					          define OWNNETSET6 = [ ${intnet6}, ${amsnet6}, ${homenet6} ];
 | 
				
			||||||
 | 
					          #define TRANSSET6 = [ ::1/128 ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          define DUB1IP6 = ${lib.my.c.home.vips.as211024.v6};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          define PREFIXP = 110;
 | 
				
			||||||
 | 
					          define PREFPEER = 120;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          filter bgp_import {
 | 
				
			||||||
 | 
					            if net !~ OWNNETSET4 && net !~ OWNNETSET6 then accept; else reject;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          filter bgp_export {
 | 
				
			||||||
 | 
					            if net ~ OWNNETSET4 || net ~ OWNNETSET6 then accept; else reject;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          router id from "veth0";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          protocol device {}
 | 
				
			||||||
 | 
					          protocol direct {
 | 
				
			||||||
 | 
					            interface "veth0";
 | 
				
			||||||
 | 
					            ipv4;
 | 
				
			||||||
 | 
					            ipv6;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          protocol static static4 {
 | 
				
			||||||
 | 
					            ipv4 {
 | 
				
			||||||
 | 
					              import all;
 | 
				
			||||||
 | 
					              export none;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          protocol static static6 {
 | 
				
			||||||
 | 
					            # Special case: We have to do the routing on behalf of this _internal_ next-hop
 | 
				
			||||||
 | 
					            route INTNET6 via "as211024";
 | 
				
			||||||
 | 
					            route HOMENET6 via DUB1IP6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ipv6 {
 | 
				
			||||||
 | 
					              import all;
 | 
				
			||||||
 | 
					              export none;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          protocol kernel kernel4 {
 | 
				
			||||||
 | 
					            ipv4 {
 | 
				
			||||||
 | 
					              import none;
 | 
				
			||||||
 | 
					              export none;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          protocol kernel kernel6 {
 | 
				
			||||||
 | 
					            ipv6 {
 | 
				
			||||||
 | 
					              import none;
 | 
				
			||||||
 | 
					              export filter {
 | 
				
			||||||
 | 
					                if net = HOMENET6 then accept;
 | 
				
			||||||
 | 
					                reject;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          protocol bgp bgptools {
 | 
				
			||||||
 | 
					            local as OWNAS;
 | 
				
			||||||
 | 
					            multihop;
 | 
				
			||||||
 | 
					            description "bgp.tools monitoring";
 | 
				
			||||||
 | 
					            neighbor 2a0c:2f07:9459::b11 as 212232;
 | 
				
			||||||
 | 
					            source address OWNIP6;
 | 
				
			||||||
 | 
					            ipv4 {
 | 
				
			||||||
 | 
					              import none;
 | 
				
			||||||
 | 
					              export all;
 | 
				
			||||||
 | 
					              add paths tx;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            ipv6 {
 | 
				
			||||||
 | 
					              import none;
 | 
				
			||||||
 | 
					              export all;
 | 
				
			||||||
 | 
					              add paths tx;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          template bgp base_bgp4 {
 | 
				
			||||||
 | 
					            local as OWNAS;
 | 
				
			||||||
 | 
					            direct;
 | 
				
			||||||
 | 
					            allow local as;
 | 
				
			||||||
 | 
					            ipv4 {
 | 
				
			||||||
 | 
					              import keep filtered;
 | 
				
			||||||
 | 
					              export none;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          template bgp upstream_bgp4 from base_bgp4 {
 | 
				
			||||||
 | 
					            ipv4 {
 | 
				
			||||||
 | 
					              #import none;
 | 
				
			||||||
 | 
					              import filter bgp_import;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          template bgp peer_bgp4 from base_bgp4 {
 | 
				
			||||||
 | 
					            ipv4 {
 | 
				
			||||||
 | 
					              import filter bgp_import;
 | 
				
			||||||
 | 
					              preference PREFPEER;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          template bgp ixp_bgp4 from base_bgp4 {
 | 
				
			||||||
 | 
					            ipv4 {
 | 
				
			||||||
 | 
					              import filter bgp_import;
 | 
				
			||||||
 | 
					              preference PREFIXP;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          template bgp base_bgp6 {
 | 
				
			||||||
 | 
					            local ${assignedV6} as OWNAS;
 | 
				
			||||||
 | 
					            direct;
 | 
				
			||||||
 | 
					            # So we can see routes we announce from other routers
 | 
				
			||||||
 | 
					            allow local as;
 | 
				
			||||||
 | 
					            ipv6 {
 | 
				
			||||||
 | 
					              import keep filtered;
 | 
				
			||||||
 | 
					              export filter bgp_export;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          template bgp upstream_bgp6 from base_bgp6 {
 | 
				
			||||||
 | 
					            ipv6 {
 | 
				
			||||||
 | 
					              #import none;
 | 
				
			||||||
 | 
					              import filter bgp_import;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          template bgp peer_bgp6 from base_bgp6 {
 | 
				
			||||||
 | 
					            ipv6 {
 | 
				
			||||||
 | 
					              import filter bgp_import;
 | 
				
			||||||
 | 
					              preference PREFPEER;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          template bgp ixp_bgp6 from base_bgp6 {
 | 
				
			||||||
 | 
					            ipv6 {
 | 
				
			||||||
 | 
					              import filter bgp_import;
 | 
				
			||||||
 | 
					              preference PREFIXP;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          protocol bgp upstream4_vultr from upstream_bgp4 {
 | 
				
			||||||
 | 
					            description "Vultr transit (IPv4)";
 | 
				
			||||||
 | 
					            neighbor 169.254.169.254 as 64515;
 | 
				
			||||||
 | 
					            multihop 2;
 | 
				
			||||||
 | 
					            password
 | 
				
			||||||
 | 
					            include "vultr-password.conf";;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          protocol bgp upstream6_vultr from upstream_bgp6 {
 | 
				
			||||||
 | 
					            description "Vultr transit (IPv6)";
 | 
				
			||||||
 | 
					            neighbor 2001:19f0:ffff::1 as 64515;
 | 
				
			||||||
 | 
					            multihop 2;
 | 
				
			||||||
 | 
					            password
 | 
				
			||||||
 | 
					            include "vultr-password.conf";;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        '';
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										174
									
								
								nixos/boxes/britway/default.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								nixos/boxes/britway/default.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,174 @@
 | 
				
			|||||||
 | 
					{ lib, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
 | 
					  inherit (lib.my.c) pubDomain;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.britway) prefixes domain pubV4 assignedV6;
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  nixos.systems.britway = {
 | 
				
			||||||
 | 
					    system = "x86_64-linux";
 | 
				
			||||||
 | 
					    nixpkgs = "mine";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assignments = {
 | 
				
			||||||
 | 
					      vultr = {
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = pubV4;
 | 
				
			||||||
 | 
					          mask = 23;
 | 
				
			||||||
 | 
					          gateway = "45.76.140.1";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6 = {
 | 
				
			||||||
 | 
					          iid = "::1";
 | 
				
			||||||
 | 
					          address = "2001:19f0:7402:128b::1";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      as211024 = {
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host 5 prefixes.as211024.v4;
 | 
				
			||||||
 | 
					          gateway = null;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6.address = net.cidr.host ((2*65536*65536*65536) + 1) prefixes.as211024.v6;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
 | 
				
			||||||
 | 
					      let
 | 
				
			||||||
 | 
					        inherit (lib) mkMerge mkForce;
 | 
				
			||||||
 | 
					        inherit (lib.my) networkdAssignment;
 | 
				
			||||||
 | 
					      in
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        imports = [
 | 
				
			||||||
 | 
					          "${modulesPath}/profiles/qemu-guest.nix"
 | 
				
			||||||
 | 
					          ./bgp.nix
 | 
				
			||||||
 | 
					          ./nginx.nix
 | 
				
			||||||
 | 
					          ./tailscale.nix
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config = mkMerge [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            boot = {
 | 
				
			||||||
 | 
					              initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "sr_mod" ];
 | 
				
			||||||
 | 
					              loader = {
 | 
				
			||||||
 | 
					                systemd-boot.enable = false;
 | 
				
			||||||
 | 
					                grub = {
 | 
				
			||||||
 | 
					                  enable = true;
 | 
				
			||||||
 | 
					                  device = "/dev/vda";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fileSystems = {
 | 
				
			||||||
 | 
					              "/boot" = {
 | 
				
			||||||
 | 
					                device = "/dev/disk/by-partuuid/c557ef12-da44-41d1-84f5-d32a711feefd";
 | 
				
			||||||
 | 
					                fsType = "ext4";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              "/nix" = {
 | 
				
			||||||
 | 
					                device = "/dev/disk/by-partuuid/d42d0853-b054-4104-8afd-6d36287c7ca3";
 | 
				
			||||||
 | 
					                fsType = "ext4";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              "/persist" = {
 | 
				
			||||||
 | 
					                device = "/dev/disk/by-partuuid/f14fbcf4-5242-456b-a4db-ef15d053d62e";
 | 
				
			||||||
 | 
					                fsType = "ext4";
 | 
				
			||||||
 | 
					                neededForBoot = true;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            services = {
 | 
				
			||||||
 | 
					              iperf3 = {
 | 
				
			||||||
 | 
					                enable = true;
 | 
				
			||||||
 | 
					                openFirewall = true;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            networking = { inherit domain; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            systemd.network = {
 | 
				
			||||||
 | 
					              config = {
 | 
				
			||||||
 | 
					                routeTables.ts-extra = 1337;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              links = {
 | 
				
			||||||
 | 
					                "10-veth0" = {
 | 
				
			||||||
 | 
					                  matchConfig.PermanentMACAddress = "56:00:04:ac:6e:06";
 | 
				
			||||||
 | 
					                  linkConfig.Name = "veth0";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              networks = {
 | 
				
			||||||
 | 
					                "20-veth0" = mkMerge [
 | 
				
			||||||
 | 
					                  (networkdAssignment "veth0" assignments.vultr)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    address = [ "${assignedV6}/64" ];
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					                "90-l2mesh-as211024" = mkMerge [
 | 
				
			||||||
 | 
					                  (networkdAssignment "as211024" assignments.as211024)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    matchConfig.Name = "as211024";
 | 
				
			||||||
 | 
					                    networkConfig.IPv6AcceptRA = mkForce false;
 | 
				
			||||||
 | 
					                    routes = map (r: { routeConfig = r; }) [
 | 
				
			||||||
 | 
					                      {
 | 
				
			||||||
 | 
					                        Destination = lib.my.c.colony.prefixes.all.v4;
 | 
				
			||||||
 | 
					                        Gateway = allAssignments.estuary.as211024.ipv4.address;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                      {
 | 
				
			||||||
 | 
					                        Destination = lib.my.c.home.prefixes.all.v4;
 | 
				
			||||||
 | 
					                        Gateway = lib.my.c.home.vips.as211024.v4;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                      {
 | 
				
			||||||
 | 
					                        # Just when routing traffic from Tailscale nodes, otherwise use WAN
 | 
				
			||||||
 | 
					                        Destination = lib.my.c.colony.prefixes.all.v6;
 | 
				
			||||||
 | 
					                        Gateway = allAssignments.estuary.as211024.ipv6.address;
 | 
				
			||||||
 | 
					                        Table = "ts-extra";
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                    ];
 | 
				
			||||||
 | 
					                    routingPolicyRules = map (r: { routingPolicyRuleConfig = r; }) [
 | 
				
			||||||
 | 
					                      {
 | 
				
			||||||
 | 
					                        IncomingInterface = "tailscale0";
 | 
				
			||||||
 | 
					                        To = lib.my.c.colony.prefixes.all.v6;
 | 
				
			||||||
 | 
					                        Table = "ts-extra";
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                    ];
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            my = {
 | 
				
			||||||
 | 
					              server.enable = true;
 | 
				
			||||||
 | 
					              secrets = {
 | 
				
			||||||
 | 
					                key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAmXC9egI46Qtaiifhq2I+rv2s1yPyzTlO4BHzUb+3Su";
 | 
				
			||||||
 | 
					                files = {
 | 
				
			||||||
 | 
					                  "l2mesh/as211024.key" = {};
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              vpns = {
 | 
				
			||||||
 | 
					                l2.pskFiles = {
 | 
				
			||||||
 | 
					                  as211024 = config.age.secrets."l2mesh/as211024.key".path;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              firewall = {
 | 
				
			||||||
 | 
					                trustedInterfaces = [ "tailscale0" ];
 | 
				
			||||||
 | 
					                extraRules = ''
 | 
				
			||||||
 | 
					                  table inet filter {
 | 
				
			||||||
 | 
					                    chain forward {
 | 
				
			||||||
 | 
					                      ${lib.my.c.as211024.nftTrust}
 | 
				
			||||||
 | 
					                      oifname as211024 accept
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  table inet nat {
 | 
				
			||||||
 | 
					                    chain postrouting {
 | 
				
			||||||
 | 
					                      iifname tailscale0 oifname veth0 snat ip to ${assignments.vultr.ipv4.address}
 | 
				
			||||||
 | 
					                      iifname tailscale0 oifname veth0 snat ip6 to ${assignments.as211024.ipv6.address}
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                '';
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										109
									
								
								nixos/boxes/britway/nginx.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								nixos/boxes/britway/nginx.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
				
			|||||||
 | 
					{ lib, pkgs, config, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (builtins) mapAttrs;
 | 
				
			||||||
 | 
					  inherit (lib) mkMerge mkDefault;
 | 
				
			||||||
 | 
					  inherit (lib.my.c) pubDomain;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.nginx) baseHttpConfig proxyHeaders;
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  config = {
 | 
				
			||||||
 | 
					    my = {
 | 
				
			||||||
 | 
					      secrets.files = {
 | 
				
			||||||
 | 
					        "dhparams.pem" = {
 | 
				
			||||||
 | 
					          owner = "acme";
 | 
				
			||||||
 | 
					          group = "acme";
 | 
				
			||||||
 | 
					          mode = "440";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        "britway/cloudflare-credentials.conf" = {
 | 
				
			||||||
 | 
					          owner = "acme";
 | 
				
			||||||
 | 
					          group = "acme";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      firewall = {
 | 
				
			||||||
 | 
					        tcp.allowed = [ "http" "https" ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    users = {
 | 
				
			||||||
 | 
					      users = {
 | 
				
			||||||
 | 
					        nginx.extraGroups = [ "acme" ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    security.acme = {
 | 
				
			||||||
 | 
					      acceptTerms = true;
 | 
				
			||||||
 | 
					      defaults = {
 | 
				
			||||||
 | 
					        email = "dev@nul.ie";
 | 
				
			||||||
 | 
					        server = "https://acme-v02.api.letsencrypt.org/directory";
 | 
				
			||||||
 | 
					        reloadServices = [ "nginx" ];
 | 
				
			||||||
 | 
					        dnsResolver = "8.8.8.8";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      certs = {
 | 
				
			||||||
 | 
					        "${pubDomain}" = {
 | 
				
			||||||
 | 
					          extraDomainNames = [
 | 
				
			||||||
 | 
					            "*.${pubDomain}"
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          dnsProvider = "cloudflare";
 | 
				
			||||||
 | 
					          credentialsFile = config.age.secrets."britway/cloudflare-credentials.conf".path;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    services = {
 | 
				
			||||||
 | 
					      nginx = {
 | 
				
			||||||
 | 
					        enable = true;
 | 
				
			||||||
 | 
					        enableReload = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        logError = "stderr info";
 | 
				
			||||||
 | 
					        recommendedTlsSettings = true;
 | 
				
			||||||
 | 
					        serverTokens = true;
 | 
				
			||||||
 | 
					        sslDhparam = config.age.secrets."dhparams.pem".path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Based on recommended*Settings, but probably better to be explicit about these
 | 
				
			||||||
 | 
					        appendHttpConfig = ''
 | 
				
			||||||
 | 
					          ${baseHttpConfig}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          # caching
 | 
				
			||||||
 | 
					          proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=512m;
 | 
				
			||||||
 | 
					        '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        virtualHosts =
 | 
				
			||||||
 | 
					        let
 | 
				
			||||||
 | 
					          hosts = {
 | 
				
			||||||
 | 
					            "_" = {
 | 
				
			||||||
 | 
					              default = true;
 | 
				
			||||||
 | 
					              forceSSL = true;
 | 
				
			||||||
 | 
					              onlySSL = false;
 | 
				
			||||||
 | 
					              locations = {
 | 
				
			||||||
 | 
					                "/".root = "${pkgs.nginx}/html";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "ts.${pubDomain}" = {
 | 
				
			||||||
 | 
					              locations."/" = {
 | 
				
			||||||
 | 
					                proxyPass = "http://localhost:${toString config.services.headscale.port}";
 | 
				
			||||||
 | 
					                proxyWebsockets = true;
 | 
				
			||||||
 | 
					                extraConfig = ''
 | 
				
			||||||
 | 
					                  proxy_buffering off;
 | 
				
			||||||
 | 
					                  add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
 | 
				
			||||||
 | 
					                '';
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          defaultsFor = mapAttrs (n: _: {
 | 
				
			||||||
 | 
					            onlySSL = mkDefault true;
 | 
				
			||||||
 | 
					            useACMEHost = mkDefault pubDomain;
 | 
				
			||||||
 | 
					            kTLS = mkDefault true;
 | 
				
			||||||
 | 
					            http2 = mkDefault true;
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        in
 | 
				
			||||||
 | 
					        mkMerge [
 | 
				
			||||||
 | 
					          hosts
 | 
				
			||||||
 | 
					          (defaultsFor hosts)
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										110
									
								
								nixos/boxes/britway/tailscale.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								nixos/boxes/britway/tailscale.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					{ lib, pkgs, config, assignments, allAssignments, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib) concatStringsSep;
 | 
				
			||||||
 | 
					  inherit (lib.my.c) pubDomain;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.britway) prefixes domain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Can't use overrideAttrs because we need to override `vendorHash` within `buildGoModule`
 | 
				
			||||||
 | 
					  headscale = pkgs.headscale.override {
 | 
				
			||||||
 | 
					    buildGoModule = args: pkgs.buildGoModule (args // rec {
 | 
				
			||||||
 | 
					      version = "0.23.0-alpha2";
 | 
				
			||||||
 | 
					      src = pkgs.fetchFromGitHub {
 | 
				
			||||||
 | 
					        owner = "juanfont";
 | 
				
			||||||
 | 
					        repo = "headscale";
 | 
				
			||||||
 | 
					        rev = "v${version}";
 | 
				
			||||||
 | 
					        hash = "sha256-sz+uQyyq/5YYDe5I44x5x2nvd48swAhNlInB8KZYvDo=";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      vendorHash = "sha256-u9AmJguQ5dnJpfhOeLN43apvMHuraOrJhvlEIp9RoIc=";
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  advRoutes = concatStringsSep "," [
 | 
				
			||||||
 | 
					    lib.my.c.home.prefixes.all.v4
 | 
				
			||||||
 | 
					    lib.my.c.home.prefixes.all.v6
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					  pubNameservers = [
 | 
				
			||||||
 | 
					    "1.1.1.1"
 | 
				
			||||||
 | 
					    "1.0.0.1"
 | 
				
			||||||
 | 
					    "2606:4700:4700::1111"
 | 
				
			||||||
 | 
					    "2606:4700:4700::1001"
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  config = {
 | 
				
			||||||
 | 
					    environment.systemPackages = [
 | 
				
			||||||
 | 
					      # For CLI
 | 
				
			||||||
 | 
					      config.services.headscale.package
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    services = {
 | 
				
			||||||
 | 
					      headscale = {
 | 
				
			||||||
 | 
					        enable = true;
 | 
				
			||||||
 | 
					        package = headscale;
 | 
				
			||||||
 | 
					        settings = {
 | 
				
			||||||
 | 
					          disable_check_updates = true;
 | 
				
			||||||
 | 
					          unix_socket_permission = "0770";
 | 
				
			||||||
 | 
					          server_url = "https://ts.${pubDomain}";
 | 
				
			||||||
 | 
					          db_type = "sqlite3";
 | 
				
			||||||
 | 
					          db_path = "/var/lib/headscale/db.sqlite3";
 | 
				
			||||||
 | 
					          noise.private_key_path = "/var/lib/headscale/noise_private.key";
 | 
				
			||||||
 | 
					          ip_prefixes = with lib.my.c.tailscale.prefix; [ v4 v6 ];
 | 
				
			||||||
 | 
					          dns_config = {
 | 
				
			||||||
 | 
					            # Use IPs that will route inside the VPN to prevent interception
 | 
				
			||||||
 | 
					            # (e.g. DNS rebinding filtering)
 | 
				
			||||||
 | 
					            restricted_nameservers = {
 | 
				
			||||||
 | 
					              "${domain}" = pubNameservers;
 | 
				
			||||||
 | 
					              "${lib.my.c.colony.domain}" = with allAssignments.estuary.base; [
 | 
				
			||||||
 | 
					                ipv4.address ipv6.address
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
 | 
					              "${lib.my.c.home.domain}" = with allAssignments; [
 | 
				
			||||||
 | 
					                river.hi.ipv4.address
 | 
				
			||||||
 | 
					                river.hi.ipv6.address
 | 
				
			||||||
 | 
					                stream.hi.ipv4.address
 | 
				
			||||||
 | 
					                stream.hi.ipv6.address
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            magic_dns = true;
 | 
				
			||||||
 | 
					            base_domain = "ts.${pubDomain}";
 | 
				
			||||||
 | 
					            override_local_dns = false;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          oidc = {
 | 
				
			||||||
 | 
					            only_start_if_oidc_is_available = true;
 | 
				
			||||||
 | 
					            issuer = "https://accounts.google.com";
 | 
				
			||||||
 | 
					            client_id = "545475967061-l45cln081mp8t4li2c34v7t7b8la6f4f.apps.googleusercontent.com";
 | 
				
			||||||
 | 
					            client_secret_path = config.age.secrets."britway/oidc-secret.txt".path;
 | 
				
			||||||
 | 
					            scope = [ "openid" "profile" "email" ];
 | 
				
			||||||
 | 
					            allowed_users = [ "jackos1998@gmail.com" ];
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      tailscale = {
 | 
				
			||||||
 | 
					        enable = true;
 | 
				
			||||||
 | 
					        authKeyFile = config.age.secrets."tailscale-auth.key".path;
 | 
				
			||||||
 | 
					        openFirewall = true;
 | 
				
			||||||
 | 
					        interfaceName = "tailscale0";
 | 
				
			||||||
 | 
					        extraUpFlags = [
 | 
				
			||||||
 | 
					          "--operator=${config.my.user.config.name}"
 | 
				
			||||||
 | 
					          "--login-server=https://ts.nul.ie"
 | 
				
			||||||
 | 
					          "--netfilter-mode=off"
 | 
				
			||||||
 | 
					          "--advertise-exit-node"
 | 
				
			||||||
 | 
					          "--advertise-routes=${advRoutes}"
 | 
				
			||||||
 | 
					          "--accept-routes=false"
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    my = {
 | 
				
			||||||
 | 
					      secrets = {
 | 
				
			||||||
 | 
					        files = {
 | 
				
			||||||
 | 
					          "britway/oidc-secret.txt" = {
 | 
				
			||||||
 | 
					            owner = "headscale";
 | 
				
			||||||
 | 
					            group = "headscale";
 | 
				
			||||||
 | 
					            mode = "440";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          "tailscale-auth.key" = {};
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,12 +1,33 @@
 | 
				
			|||||||
{ lib, ... }: {
 | 
					{ lib, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.home) domain vlans prefixes;
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
  nixos.systems.castle = {
 | 
					  nixos.systems.castle = {
 | 
				
			||||||
    system = "x86_64-linux";
 | 
					    system = "x86_64-linux";
 | 
				
			||||||
    nixpkgs = "mine";
 | 
					    nixpkgs = "mine";
 | 
				
			||||||
    home-manager = "mine";
 | 
					    home-manager = "mine";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assignments = {
 | 
				
			||||||
 | 
					      hi = {
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host 40 prefixes.hi.v4;
 | 
				
			||||||
 | 
					          mask = 22;
 | 
				
			||||||
 | 
					          gateway = null;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6 = {
 | 
				
			||||||
 | 
					          iid = "::3:1";
 | 
				
			||||||
 | 
					          address = net.cidr.host (65536*3+1) prefixes.hi.v6;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    configuration = { lib, pkgs, modulesPath, config, systems, assignments, allAssignments, ... }:
 | 
					    configuration = { lib, pkgs, modulesPath, config, systems, assignments, allAssignments, ... }:
 | 
				
			||||||
      let
 | 
					      let
 | 
				
			||||||
        inherit (lib) mkIf mkMerge mkForce;
 | 
					        inherit (lib) mkIf mkMerge mkForce;
 | 
				
			||||||
 | 
					        inherit (lib.my) mkVLAN networkdAssignment;
 | 
				
			||||||
      in
 | 
					      in
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        hardware = {
 | 
					        hardware = {
 | 
				
			||||||
@@ -25,7 +46,7 @@
 | 
				
			|||||||
            efi.canTouchEfiVariables = false;
 | 
					            efi.canTouchEfiVariables = false;
 | 
				
			||||||
            timeout = 10;
 | 
					            timeout = 10;
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
          kernelPackages = pkgs.linuxKernel.packages.linux_6_5;
 | 
					          kernelPackages = lib.my.c.kernel.latest pkgs;
 | 
				
			||||||
          kernelModules = [ "kvm-amd" ];
 | 
					          kernelModules = [ "kvm-amd" ];
 | 
				
			||||||
          kernelParams = [ "amd_iommu=on" "amd_pstate=passive" ];
 | 
					          kernelParams = [ "amd_iommu=on" "amd_pstate=passive" ];
 | 
				
			||||||
          kernelPatches = [
 | 
					          kernelPatches = [
 | 
				
			||||||
@@ -83,6 +104,15 @@
 | 
				
			|||||||
          blueman.enable = true;
 | 
					          blueman.enable = true;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        programs = {
 | 
				
			||||||
 | 
					          virt-manager.enable = true;
 | 
				
			||||||
 | 
					          wireshark = {
 | 
				
			||||||
 | 
					            enable = true;
 | 
				
			||||||
 | 
					            package = pkgs.wireshark-qt;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        virtualisation.libvirtd.enable = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        networking = {
 | 
					        networking = {
 | 
				
			||||||
          domain = "h.${lib.my.c.pubDomain}";
 | 
					          domain = "h.${lib.my.c.pubDomain}";
 | 
				
			||||||
          firewall.enable = false;
 | 
					          firewall.enable = false;
 | 
				
			||||||
@@ -117,6 +147,9 @@
 | 
				
			|||||||
        systemd = {
 | 
					        systemd = {
 | 
				
			||||||
          network = {
 | 
					          network = {
 | 
				
			||||||
            wait-online.enable = false;
 | 
					            wait-online.enable = false;
 | 
				
			||||||
 | 
					            netdevs = mkMerge [
 | 
				
			||||||
 | 
					              (mkVLAN "lan-hi" vlans.hi)
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
            links = {
 | 
					            links = {
 | 
				
			||||||
              "10-et2.5g" = {
 | 
					              "10-et2.5g" = {
 | 
				
			||||||
                matchConfig.MACAddress = "c8:7f:54:6e:17:0f";
 | 
					                matchConfig.MACAddress = "c8:7f:54:6e:17:0f";
 | 
				
			||||||
@@ -127,15 +160,33 @@
 | 
				
			|||||||
                linkConfig.Name = "et10g";
 | 
					                linkConfig.Name = "et10g";
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
              "12-et100g" = {
 | 
					              "12-et100g" = {
 | 
				
			||||||
                matchConfig.MACAddress = "24:8a:07:a8:fe:3a";
 | 
					                matchConfig.PermanentMACAddress = "24:8a:07:a8:fe:3a";
 | 
				
			||||||
                linkConfig.Name = "et100g";
 | 
					                linkConfig = {
 | 
				
			||||||
 | 
					                  Name = "et100g";
 | 
				
			||||||
 | 
					                  MTUBytes = "9000";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            networks = {
 | 
					            networks = {
 | 
				
			||||||
              "50-lan" = {
 | 
					              "50-lan" = {
 | 
				
			||||||
                matchConfig.Name = "et2.5g";
 | 
					                matchConfig.Name = "et2.5g";
 | 
				
			||||||
                DHCP = "yes";
 | 
					                DHCP = "no";
 | 
				
			||||||
 | 
					                address = [ "10.16.7.1/16" ];
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              "50-et100g" = {
 | 
				
			||||||
 | 
					                matchConfig.Name = "et100g";
 | 
				
			||||||
 | 
					                vlan = [ "lan-hi" ];
 | 
				
			||||||
 | 
					                networkConfig.IPv6AcceptRA = false;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              "60-lan-hi" = mkMerge [
 | 
				
			||||||
 | 
					                (networkdAssignment "lan-hi" assignments.hi)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  DHCP = "yes";
 | 
				
			||||||
 | 
					                  matchConfig.Name = "lan-hi";
 | 
				
			||||||
 | 
					                  linkConfig.MTUBytes = "9000";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -196,6 +247,7 @@
 | 
				
			|||||||
          secrets = {
 | 
					          secrets = {
 | 
				
			||||||
            key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMlVuTzKObeaUuPocCF41IO/8X+443lzUJLuCIclt2vr";
 | 
					            key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMlVuTzKObeaUuPocCF41IO/8X+443lzUJLuCIclt2vr";
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					          nvme.uuid = "2230b066-a674-4f45-a1dc-f7727b3a9e7b";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          firewall = {
 | 
					          firewall = {
 | 
				
			||||||
            enable = false;
 | 
					            enable = false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
{ lib, ... }:
 | 
					{ lib, ... }:
 | 
				
			||||||
let
 | 
					let
 | 
				
			||||||
  inherit (lib.my) net;
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
  inherit (lib.my.c.colony) domain prefixes;
 | 
					  inherit (lib.my.c.colony) domain prefixes firewallForwards;
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  imports = [ ./vms ];
 | 
					  imports = [ ./vms ];
 | 
				
			||||||
@@ -57,7 +57,7 @@ in
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        boot = {
 | 
					        boot = {
 | 
				
			||||||
          kernelPackages = pkgs.linuxKernel.packages.linux_6_1.extend (self: super: {
 | 
					          kernelPackages = (lib.my.c.kernel.lts pkgs).extend (self: super: {
 | 
				
			||||||
            kernel = super.kernel.override {
 | 
					            kernel = super.kernel.override {
 | 
				
			||||||
              structuredExtraConfig = with lib.kernel; {
 | 
					              structuredExtraConfig = with lib.kernel; {
 | 
				
			||||||
                #SOME_OPT = yes;
 | 
					                #SOME_OPT = yes;
 | 
				
			||||||
@@ -66,10 +66,21 @@ in
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
          kernelModules = [ "kvm-amd" ];
 | 
					          kernelModules = [ "kvm-amd" ];
 | 
				
			||||||
          kernelParams = [ "amd_iommu=on" "console=ttyS0,115200n8" "console=ttyS1,115200n8" "console=tty0" ];
 | 
					          kernelParams = [
 | 
				
			||||||
 | 
					            "amd_iommu=on"
 | 
				
			||||||
 | 
					            "console=ttyS0,115200n8" "console=ttyS1,115200n8" "console=tty0"
 | 
				
			||||||
 | 
					            "systemd.setenv=SYSTEMD_SULOGIN_FORCE=1"
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
          initrd = {
 | 
					          initrd = {
 | 
				
			||||||
            kernelModules = [ "dm-raid" ];
 | 
					            kernelModules = [ "dm-raid" ];
 | 
				
			||||||
            availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
 | 
					            availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
 | 
				
			||||||
 | 
					            systemd = {
 | 
				
			||||||
 | 
					              enable = true;
 | 
				
			||||||
 | 
					              # Onlu activate volumes needed for boot to prevent thin check from getting killed while switching root
 | 
				
			||||||
 | 
					              contents."/etc/lvm/lvm.conf".text = ''
 | 
				
			||||||
 | 
					                activation/auto_activation_volume_list = [ "main/colony-nix" "main/colony-persist" ]
 | 
				
			||||||
 | 
					              '';
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -137,6 +148,15 @@ in
 | 
				
			|||||||
          services = {
 | 
					          services = {
 | 
				
			||||||
            "serial-getty@ttyS0".enable = true;
 | 
					            "serial-getty@ttyS0".enable = true;
 | 
				
			||||||
            "serial-getty@ttyS1".enable = true;
 | 
					            "serial-getty@ttyS1".enable = true;
 | 
				
			||||||
 | 
					            lvm-activate-main = {
 | 
				
			||||||
 | 
					              description = "Activate remaining LVs";
 | 
				
			||||||
 | 
					              before = [ "local-fs-pre.target" ];
 | 
				
			||||||
 | 
					              serviceConfig = {
 | 
				
			||||||
 | 
					                Type = "oneshot";
 | 
				
			||||||
 | 
					                ExecStart = "${pkgs.lvm2.bin}/bin/vgchange -aay main";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              wantedBy = [ "sysinit.target" ];
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            rsync-lvm-meta = {
 | 
					            rsync-lvm-meta = {
 | 
				
			||||||
              description = "rsync lvm metadata backups / archives to rsync.net";
 | 
					              description = "rsync lvm metadata backups / archives to rsync.net";
 | 
				
			||||||
@@ -248,6 +268,14 @@ in
 | 
				
			|||||||
                      Destination = allAssignments.shill.internal.ipv4.address;
 | 
					                      Destination = allAssignments.shill.internal.ipv4.address;
 | 
				
			||||||
                      Gateway = allAssignments.shill.routing.ipv4.address;
 | 
					                      Gateway = allAssignments.shill.routing.ipv4.address;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      Destination = lib.my.c.tailscale.prefix.v4;
 | 
				
			||||||
 | 
					                      Gateway = allAssignments.shill.routing.ipv4.address;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      Destination = lib.my.c.tailscale.prefix.v6;
 | 
				
			||||||
 | 
					                      Gateway = allAssignments.shill.internal.ipv6.address;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                      Destination = prefixes.oci.v4;
 | 
					                      Destination = prefixes.oci.v4;
 | 
				
			||||||
@@ -261,6 +289,11 @@ in
 | 
				
			|||||||
                      Destination = allAssignments.whale2.internal.ipv4.address;
 | 
					                      Destination = allAssignments.whale2.internal.ipv4.address;
 | 
				
			||||||
                      Gateway = allAssignments.whale2.routing.ipv4.address;
 | 
					                      Gateway = allAssignments.whale2.routing.ipv4.address;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      Destination = allAssignments.git.internal.ipv4.address;
 | 
				
			||||||
 | 
					                      Gateway = allAssignments.git.routing.ipv4.address;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                  ];
 | 
					                  ];
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              ];
 | 
					              ];
 | 
				
			||||||
@@ -346,6 +379,7 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          firewall = {
 | 
					          firewall = {
 | 
				
			||||||
            trustedInterfaces = [ "vms" ];
 | 
					            trustedInterfaces = [ "vms" ];
 | 
				
			||||||
 | 
					            nat.forwardPorts."${allAssignments.estuary.internal.ipv4.address}" = firewallForwards allAssignments;
 | 
				
			||||||
            extraRules = ''
 | 
					            extraRules = ''
 | 
				
			||||||
              define cust = { vm-mail, vm-darts }
 | 
					              define cust = { vm-mail, vm-darts }
 | 
				
			||||||
              table inet filter {
 | 
					              table inet filter {
 | 
				
			||||||
@@ -372,6 +406,7 @@ in
 | 
				
			|||||||
                  "vm-estuary-persist"
 | 
					                  "vm-estuary-persist"
 | 
				
			||||||
                  "vm-whale2-persist"
 | 
					                  "vm-whale2-persist"
 | 
				
			||||||
                  "vm-mail-data"
 | 
					                  "vm-mail-data"
 | 
				
			||||||
 | 
					                  "vm-git-persist"
 | 
				
			||||||
                  "git"
 | 
					                  "git"
 | 
				
			||||||
                ];
 | 
					                ];
 | 
				
			||||||
                compression = "zstd,5";
 | 
					                compression = "zstd,5";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,37 +3,22 @@
 | 
				
			|||||||
    ./estuary
 | 
					    ./estuary
 | 
				
			||||||
    ./shill
 | 
					    ./shill
 | 
				
			||||||
    ./whale2
 | 
					    ./whale2
 | 
				
			||||||
 | 
					    ./git
 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  nixos.systems.colony.configuration = { lib, pkgs, config, systems, ... }:
 | 
					  nixos.systems.colony.configuration = { lib, pkgs, config, systems, ... }:
 | 
				
			||||||
  let
 | 
					  let
 | 
				
			||||||
    inherit (lib) mkIf mkMerge optionals;
 | 
					    inherit (lib) mkIf mkMerge optionals;
 | 
				
			||||||
 | 
					    inherit (lib.my) vm;
 | 
				
			||||||
    lvmDisk' = name: lv: {
 | 
					 | 
				
			||||||
      inherit name;
 | 
					 | 
				
			||||||
      backend = {
 | 
					 | 
				
			||||||
        driver = "host_device";
 | 
					 | 
				
			||||||
        filename = "/dev/main/${lv}";
 | 
					 | 
				
			||||||
        # It appears this needs to be set on the backend _and_ the format
 | 
					 | 
				
			||||||
        discard = "unmap";
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
      format = {
 | 
					 | 
				
			||||||
        driver = "raw";
 | 
					 | 
				
			||||||
        discard = "unmap";
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
      frontend = "virtio-blk";
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    lvmDisk = lv: lvmDisk' lv lv;
 | 
					 | 
				
			||||||
    vmLVM = vm: lv: lvmDisk' lv "vm-${vm}-${lv}";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    installerDisk = {
 | 
					    installerDisk = {
 | 
				
			||||||
      name = "installer";
 | 
					      name = "installer";
 | 
				
			||||||
      backend = {
 | 
					      backend = {
 | 
				
			||||||
        driver = "file";
 | 
					        driver = "file";
 | 
				
			||||||
        #filename = "${systems.installer.configuration.config.my.buildAs.iso}/iso/nixos-installer-devplayer0.iso";
 | 
					        #filename = "${systems.installer.configuration.config.my.buildAs.iso}/iso/nixos-installer-devplayer0.iso";
 | 
				
			||||||
        #filename = "/persist/home/dev/nixos-installer-devplayer0.iso";
 | 
					        filename = "/persist/home/dev/nixos-installer-devplayer0-b4d0d9a.iso";
 | 
				
			||||||
        #filename = "/persist/home/dev/debian-12.1.0-amd64-netinst.iso";
 | 
					        #filename = "/persist/home/dev/debian-12.1.0-amd64-netinst.iso";
 | 
				
			||||||
        filename = "/persist/home/dev/ubuntu-22.04.3-live-server-amd64.iso";
 | 
					        # filename = "/persist/home/dev/ubuntu-22.04.3-live-server-amd64.iso";
 | 
				
			||||||
        read-only = "on";
 | 
					        read-only = "on";
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
      format.driver = "raw";
 | 
					      format.driver = "raw";
 | 
				
			||||||
@@ -116,9 +101,9 @@
 | 
				
			|||||||
              };
 | 
					              };
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            drives = [ ] ++ (optionals (!config.my.build.isDevVM) [
 | 
					            drives = [ ] ++ (optionals (!config.my.build.isDevVM) [
 | 
				
			||||||
              (mkMerge [ (vmLVM "estuary" "esp") { frontendOpts.bootindex = 0; } ])
 | 
					              (mkMerge [ (vm.disk "estuary" "esp") { frontendOpts.bootindex = 0; } ])
 | 
				
			||||||
              (vmLVM "estuary" "nix")
 | 
					              (vm.disk "estuary" "nix")
 | 
				
			||||||
              (vmLVM "estuary" "persist")
 | 
					              (vm.disk "estuary" "persist")
 | 
				
			||||||
            ]);
 | 
					            ]);
 | 
				
			||||||
            hostDevices = {
 | 
					            hostDevices = {
 | 
				
			||||||
              net-wan0 = {
 | 
					              net-wan0 = {
 | 
				
			||||||
@@ -135,17 +120,17 @@
 | 
				
			|||||||
              cpus = 12;
 | 
					              cpus = 12;
 | 
				
			||||||
              threads = 2;
 | 
					              threads = 2;
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            memory = 65536;
 | 
					            memory = 40960;
 | 
				
			||||||
            networks.vms.mac = "52:54:00:27:3d:5c";
 | 
					            networks.vms.mac = "52:54:00:27:3d:5c";
 | 
				
			||||||
            cleanShutdown.timeout = 120;
 | 
					            cleanShutdown.timeout = 120;
 | 
				
			||||||
            drives = [ ] ++ (optionals (!config.my.build.isDevVM) [
 | 
					            drives = [ ] ++ (optionals (!config.my.build.isDevVM) [
 | 
				
			||||||
              (mkMerge [ (vmLVM "shill" "esp") { frontendOpts.bootindex = 0; } ])
 | 
					              (mkMerge [ (vm.disk "shill" "esp") { frontendOpts.bootindex = 0; } ])
 | 
				
			||||||
              (vmLVM "shill" "nix")
 | 
					              (vm.disk "shill" "nix")
 | 
				
			||||||
              (vmLVM "shill" "persist")
 | 
					              (vm.disk "shill" "persist")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              (lvmDisk "media")
 | 
					              (vm.lvmDisk "media")
 | 
				
			||||||
              (lvmDisk "minio")
 | 
					              (vm.lvmDisk "minio")
 | 
				
			||||||
              (lvmDisk "git")
 | 
					              (vm.lvmDisk "nix-atticd")
 | 
				
			||||||
            ]);
 | 
					            ]);
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -156,19 +141,39 @@
 | 
				
			|||||||
              cpus = 8;
 | 
					              cpus = 8;
 | 
				
			||||||
              threads = 2;
 | 
					              threads = 2;
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            memory = 32768;
 | 
					            memory = 16384;
 | 
				
			||||||
            networks.vms.mac = "52:54:00:d5:d9:c6";
 | 
					            networks.vms.mac = "52:54:00:d5:d9:c6";
 | 
				
			||||||
            cleanShutdown.timeout = 120;
 | 
					            cleanShutdown.timeout = 120;
 | 
				
			||||||
            drives = [ ] ++ (optionals (!config.my.build.isDevVM) [
 | 
					            drives = [ ] ++ (optionals (!config.my.build.isDevVM) [
 | 
				
			||||||
              (mkMerge [ (vmLVM "whale2" "esp") { frontendOpts.bootindex = 0; } ])
 | 
					              (mkMerge [ (vm.disk "whale2" "esp") { frontendOpts.bootindex = 0; } ])
 | 
				
			||||||
              (vmLVM "whale2" "nix")
 | 
					              (vm.disk "whale2" "nix")
 | 
				
			||||||
              (vmLVM "whale2" "persist")
 | 
					              (vm.disk "whale2" "persist")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              (lvmDisk "oci")
 | 
					              (vm.lvmDisk "oci")
 | 
				
			||||||
              (lvmDisk "gitea-actions-cache")
 | 
					 | 
				
			||||||
            ]);
 | 
					            ]);
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          git = {
 | 
				
			||||||
 | 
					            uuid = "c0659fdc-3356-4717-a6a1-5f289ef03c4a";
 | 
				
			||||||
 | 
					            cpu = "host,topoext";
 | 
				
			||||||
 | 
					            smp = {
 | 
				
			||||||
 | 
					              cpus = 12;
 | 
				
			||||||
 | 
					              threads = 2;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            memory = 40960;
 | 
				
			||||||
 | 
					            networks.vms.mac = "52:54:00:75:78:a8";
 | 
				
			||||||
 | 
					            cleanShutdown.timeout = 120;
 | 
				
			||||||
 | 
					            drives = [
 | 
				
			||||||
 | 
					              (mkMerge [ (vm.disk "git" "esp") { frontendOpts.bootindex = 0; } ])
 | 
				
			||||||
 | 
					              (vm.disk "git" "nix")
 | 
				
			||||||
 | 
					              (vm.disk "git" "persist")
 | 
				
			||||||
 | 
					              (vm.disk "git" "oci")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              (vm.lvmDisk "git")
 | 
				
			||||||
 | 
					              (vm.lvmDisk "gitea-actions-cache")
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          mail = {
 | 
					          mail = {
 | 
				
			||||||
            uuid = "fd95fe0f-c204-4dd5-b16f-2b808e14a43a";
 | 
					            uuid = "fd95fe0f-c204-4dd5-b16f-2b808e14a43a";
 | 
				
			||||||
            cpu = "host,topoext";
 | 
					            cpu = "host,topoext";
 | 
				
			||||||
@@ -176,15 +181,15 @@
 | 
				
			|||||||
              cpus = 3;
 | 
					              cpus = 3;
 | 
				
			||||||
              threads = 2;
 | 
					              threads = 2;
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            memory = 8192;
 | 
					            memory = 6144;
 | 
				
			||||||
            networks.public = {
 | 
					            networks.public = {
 | 
				
			||||||
              bridge = null;
 | 
					              bridge = null;
 | 
				
			||||||
              mac = "52:54:00:a8:d1:03";
 | 
					              mac = "52:54:00:a8:d1:03";
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            cleanShutdown.timeout = 120;
 | 
					            cleanShutdown.timeout = 120;
 | 
				
			||||||
            drives = [
 | 
					            drives = [
 | 
				
			||||||
              (mkMerge [ (vmLVM "mail" "root") { frontendOpts.bootindex = 0; } ])
 | 
					              (mkMerge [ (vm.disk "mail" "root") { frontendOpts.bootindex = 0; } ])
 | 
				
			||||||
              (vmLVM "mail" "data")
 | 
					              (vm.disk "mail" "data")
 | 
				
			||||||
            ];
 | 
					            ];
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -202,8 +207,8 @@
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
            cleanShutdown.timeout = 120;
 | 
					            cleanShutdown.timeout = 120;
 | 
				
			||||||
            drives = [
 | 
					            drives = [
 | 
				
			||||||
              (mkMerge [ (vmLVM "darts" "root") { frontendOpts.bootindex = 0; } ])
 | 
					              (mkMerge [ (vm.disk "darts" "root") { frontendOpts.bootindex = 0; } ])
 | 
				
			||||||
              (lvmDisk' "media" "darts-media")
 | 
					              (vm.lvmDisk' "media" "darts-media")
 | 
				
			||||||
            ];
 | 
					            ];
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,20 +16,23 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          define CCVIP1 = ${lib.my.c.colony.prefixes.vip1};
 | 
					          define CCVIP1 = ${lib.my.c.colony.prefixes.vip1};
 | 
				
			||||||
          define CCVIP2 = ${lib.my.c.colony.prefixes.vip2};
 | 
					          define CCVIP2 = ${lib.my.c.colony.prefixes.vip2};
 | 
				
			||||||
 | 
					          define CCVIP3 = ${lib.my.c.colony.prefixes.vip3};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          define OWNIP4 = ${assignments.internal.ipv4.address};
 | 
					          define OWNIP4 = ${assignments.internal.ipv4.address};
 | 
				
			||||||
          define OWNNETSET4 = [ ${assignments.internal.ipv4.address}/32 ];
 | 
					          define OWNNETSET4 = [ ${assignments.internal.ipv4.address}/32 ];
 | 
				
			||||||
          define CCNETSET4 = [ ${lib.my.c.colony.prefixes.vip1}, ${lib.my.c.colony.prefixes.vip2} ];
 | 
					          define CCNETSET4 = [ ${lib.my.c.colony.prefixes.vip1}, ${lib.my.c.colony.prefixes.vip2}, ${lib.my.c.colony.prefixes.vip3} ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          define INTNET6 = ${intnet6};
 | 
					          define INTNET6 = ${intnet6};
 | 
				
			||||||
          define AMSNET6 = ${amsnet6};
 | 
					          define AMSNET6 = ${amsnet6};
 | 
				
			||||||
          define HOMENET6 = ${homenet6};
 | 
					          define HOMENET6 = ${homenet6};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          define OWNIP6 = ${assignments.base.ipv6.address};
 | 
					          define OWNIP6 = ${assignments.base.ipv6.address};
 | 
				
			||||||
          define OWNNETSET6 = [ ${intnet6}, ${amsnet6}, ${homenet6} ];
 | 
					          # we have issues with sending ICMPv6 too big back on the wrong interface right now...
 | 
				
			||||||
 | 
					          define OWNNETSET6 = [ ${intnet6}, ${amsnet6} ];
 | 
				
			||||||
 | 
					          define CCNETSET6 = [ ];
 | 
				
			||||||
          #define TRANSSET6 = [ ::1/128 ];
 | 
					          #define TRANSSET6 = [ ::1/128 ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          define DUB1IP6 = 2a0e:97c0:4df:0:2::1;
 | 
					          define DUB1IP6 = ${lib.my.c.home.vips.as211024.v6};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          define PREFIXP = 110;
 | 
					          define PREFIXP = 110;
 | 
				
			||||||
          define PREFPEER = 120;
 | 
					          define PREFPEER = 120;
 | 
				
			||||||
@@ -41,7 +44,7 @@ in
 | 
				
			|||||||
            if net ~ OWNNETSET4 || net ~ OWNNETSET6 then accept; else reject;
 | 
					            if net ~ OWNNETSET4 || net ~ OWNNETSET6 then accept; else reject;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          filter bgp_export_cc {
 | 
					          filter bgp_export_cc {
 | 
				
			||||||
            if net ~ OWNNETSET4 || net ~ OWNNETSET6 || net ~ CCNETSET4 then accept; else reject;
 | 
					            if net ~ OWNNETSET4 || net ~ OWNNETSET6 || net ~ CCNETSET4 || net ~ CCNETSET6 then accept; else reject;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          router id from "wan";
 | 
					          router id from "wan";
 | 
				
			||||||
@@ -55,6 +58,7 @@ in
 | 
				
			|||||||
          protocol static static4 {
 | 
					          protocol static static4 {
 | 
				
			||||||
            route CCVIP1 via "base";
 | 
					            route CCVIP1 via "base";
 | 
				
			||||||
            route CCVIP2 via "base";
 | 
					            route CCVIP2 via "base";
 | 
				
			||||||
 | 
					            route CCVIP3 via "base";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ipv4 {
 | 
					            ipv4 {
 | 
				
			||||||
              import all;
 | 
					              import all;
 | 
				
			||||||
@@ -186,10 +190,12 @@ in
 | 
				
			|||||||
          protocol bgp upstream6_coloclue_eun2 from upstream_bgp6 {
 | 
					          protocol bgp upstream6_coloclue_eun2 from upstream_bgp6 {
 | 
				
			||||||
            description "ColoClue euNetworks 2 (IPv6)";
 | 
					            description "ColoClue euNetworks 2 (IPv6)";
 | 
				
			||||||
            neighbor 2a02:898:0:20::e2 as 8283;
 | 
					            neighbor 2a02:898:0:20::e2 as 8283;
 | 
				
			||||||
 | 
					            ipv6 { export filter bgp_export_cc; };
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          protocol bgp upstream6_coloclue_eun3 from upstream_bgp6 {
 | 
					          protocol bgp upstream6_coloclue_eun3 from upstream_bgp6 {
 | 
				
			||||||
            description "ColoClue euNetworks 3 (IPv6)";
 | 
					            description "ColoClue euNetworks 3 (IPv6)";
 | 
				
			||||||
            neighbor 2a02:898:0:20::e1 as 8283;
 | 
					            neighbor 2a02:898:0:20::e1 as 8283;
 | 
				
			||||||
 | 
					            ipv6 { export filter bgp_export_cc; };
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          protocol bgp upstream6_ifog from upstream_bgp6 {
 | 
					          protocol bgp upstream6_ifog from upstream_bgp6 {
 | 
				
			||||||
@@ -202,14 +208,15 @@ in
 | 
				
			|||||||
            neighbor 2001:7f8:10f::1b1b:154 as 6939;
 | 
					            neighbor 2001:7f8:10f::1b1b:154 as 6939;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          protocol bgp upstream4_fogixp_efero from upstream_bgp4 {
 | 
					          # Not working so well lately...
 | 
				
			||||||
            description "efero transit (on FogIXP, IPv4)";
 | 
					          # protocol bgp upstream4_fogixp_efero from upstream_bgp4 {
 | 
				
			||||||
            neighbor 185.1.147.107 as 208431;
 | 
					          #   description "efero transit (on FogIXP, IPv4)";
 | 
				
			||||||
          }
 | 
					          #   neighbor 185.1.147.107 as 208431;
 | 
				
			||||||
          protocol bgp upstream6_fogixp_efero from upstream_bgp6 {
 | 
					          # }
 | 
				
			||||||
            description "efero transit (on FogIXP, IPv6)";
 | 
					          # protocol bgp upstream6_fogixp_efero from upstream_bgp6 {
 | 
				
			||||||
            neighbor 2001:7f8:ca:1::107 as 208431;
 | 
					          #   description "efero transit (on FogIXP, IPv6)";
 | 
				
			||||||
          }
 | 
					          #   neighbor 2001:7f8:ca:1::107 as 208431;
 | 
				
			||||||
 | 
					          # }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          protocol bgp peer4_cc_luje from peer_bgp4 {
 | 
					          protocol bgp peer4_cc_luje from peer_bgp4 {
 | 
				
			||||||
            description "LUJE.net (on ColoClue, IPv4)";
 | 
					            description "LUJE.net (on ColoClue, IPv4)";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,8 @@
 | 
				
			|||||||
{ lib, ... }:
 | 
					{ lib, ... }:
 | 
				
			||||||
let
 | 
					let
 | 
				
			||||||
  inherit (lib.my) net;
 | 
					  inherit (builtins) elemAt;
 | 
				
			||||||
  inherit (lib.my.c.colony) domain prefixes;
 | 
					  inherit (lib.my) net mkVLAN;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.colony) pubV4 domain prefixes firewallForwards;
 | 
				
			||||||
  pubV4 = "94.142.240.44";
 | 
					 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  nixos = {
 | 
					  nixos = {
 | 
				
			||||||
@@ -11,9 +10,12 @@ in
 | 
				
			|||||||
      l2 = {
 | 
					      l2 = {
 | 
				
			||||||
        as211024 = {
 | 
					        as211024 = {
 | 
				
			||||||
          vni = 211024;
 | 
					          vni = 211024;
 | 
				
			||||||
 | 
					          security.enable = true;
 | 
				
			||||||
          peers = {
 | 
					          peers = {
 | 
				
			||||||
            estuary.addr = pubV4;
 | 
					            estuary.addr = pubV4;
 | 
				
			||||||
            home.addr = "188.141.75.2";
 | 
					            river.addr = elemAt lib.my.c.home.routersPubV4 0;
 | 
				
			||||||
 | 
					            stream.addr = elemAt lib.my.c.home.routersPubV4 1;
 | 
				
			||||||
 | 
					            britway.addr = lib.my.c.britway.pubV4;
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
@@ -53,10 +55,10 @@ in
 | 
				
			|||||||
      };
 | 
					      };
 | 
				
			||||||
      as211024 = {
 | 
					      as211024 = {
 | 
				
			||||||
        ipv4 = {
 | 
					        ipv4 = {
 | 
				
			||||||
          address = "10.255.3.1";
 | 
					          address = net.cidr.host 1 prefixes.as211024.v4;
 | 
				
			||||||
          gateway = null;
 | 
					          gateway = null;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        ipv6.address = "2a0e:97c0:4df:0:3::1";
 | 
					        ipv6.address = net.cidr.host 1 prefixes.as211024.v6;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,6 +66,7 @@ in
 | 
				
			|||||||
      let
 | 
					      let
 | 
				
			||||||
        inherit (lib) flatten mkIf mkMerge mkForce;
 | 
					        inherit (lib) flatten mkIf mkMerge mkForce;
 | 
				
			||||||
        inherit (lib.my) networkdAssignment;
 | 
					        inherit (lib.my) networkdAssignment;
 | 
				
			||||||
 | 
					        inherit (lib.my.c) networkd;
 | 
				
			||||||
      in
 | 
					      in
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        imports = [ "${modulesPath}/profiles/qemu-guest.nix" ./dns.nix ./bgp.nix ];
 | 
					        imports = [ "${modulesPath}/profiles/qemu-guest.nix" ./dns.nix ./bgp.nix ];
 | 
				
			||||||
@@ -90,6 +93,7 @@ in
 | 
				
			|||||||
            environment = {
 | 
					            environment = {
 | 
				
			||||||
              systemPackages = with pkgs; [
 | 
					              systemPackages = with pkgs; [
 | 
				
			||||||
                ethtool
 | 
					                ethtool
 | 
				
			||||||
 | 
					                conntrack-tools
 | 
				
			||||||
                wireguard-tools
 | 
					                wireguard-tools
 | 
				
			||||||
              ];
 | 
					              ];
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
@@ -114,34 +118,19 @@ in
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            systemd = {
 | 
					            systemd = {
 | 
				
			||||||
              services = {
 | 
					              services =
 | 
				
			||||||
                # Use this as a way to make sure the router always knows we're here (NDP seems kindy funky)
 | 
					              let
 | 
				
			||||||
                ipv6-neigh-keepalive =
 | 
					                waitOnline = "systemd-networkd-wait-online@wan.service";
 | 
				
			||||||
                let
 | 
					              in
 | 
				
			||||||
                  waitOnline = "systemd-networkd-wait-online@wan.service";
 | 
					              {
 | 
				
			||||||
                in
 | 
					                bird2 = {
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                  description = "Frequent ICMP6 neighbour solicitations";
 | 
					 | 
				
			||||||
                  enable = false;
 | 
					 | 
				
			||||||
                  requires = [ waitOnline ];
 | 
					 | 
				
			||||||
                  after = [ waitOnline ];
 | 
					 | 
				
			||||||
                  script = ''
 | 
					 | 
				
			||||||
                    while true; do
 | 
					 | 
				
			||||||
                      ${pkgs.ndisc6}/bin/ndisc6 ${assignments.internal.ipv6.gateway} wan
 | 
					 | 
				
			||||||
                      sleep 10
 | 
					 | 
				
			||||||
                    done
 | 
					 | 
				
			||||||
                  '';
 | 
					 | 
				
			||||||
                  wantedBy = [ "multi-user.target" ];
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                bird2 =
 | 
					 | 
				
			||||||
                let
 | 
					 | 
				
			||||||
                  waitOnline = "systemd-networkd-wait-online@wan.service";
 | 
					 | 
				
			||||||
                in
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                  after = [ waitOnline ];
 | 
					                  after = [ waitOnline ];
 | 
				
			||||||
                  # requires = [ waitOnline ];
 | 
					                  # requires = [ waitOnline ];
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					                ipsec = {
 | 
				
			||||||
 | 
					                  after = [ waitOnline ];
 | 
				
			||||||
 | 
					                  requires = [ waitOnline ];
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -154,19 +143,7 @@ in
 | 
				
			|||||||
                };
 | 
					                };
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              netdevs =
 | 
					              netdevs = mkMerge [
 | 
				
			||||||
              let
 | 
					 | 
				
			||||||
                mkVLAN = name: vid: {
 | 
					 | 
				
			||||||
                  "25-${name}" = {
 | 
					 | 
				
			||||||
                    netdevConfig = {
 | 
					 | 
				
			||||||
                      Name = name;
 | 
					 | 
				
			||||||
                      Kind = "vlan";
 | 
					 | 
				
			||||||
                    };
 | 
					 | 
				
			||||||
                    vlanConfig.Id = vid;
 | 
					 | 
				
			||||||
                  };
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
              in
 | 
					 | 
				
			||||||
              mkMerge [
 | 
					 | 
				
			||||||
                (mkVLAN "ifog" 409)
 | 
					                (mkVLAN "ifog" 409)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                (mkVLAN "frys-ix" 701)
 | 
					                (mkVLAN "frys-ix" 701)
 | 
				
			||||||
@@ -271,13 +248,7 @@ in
 | 
				
			|||||||
                    Kind = "vlan";
 | 
					                    Kind = "vlan";
 | 
				
			||||||
                  };
 | 
					                  };
 | 
				
			||||||
                  vlan = [ "frys-ix" "nl-ix" "fogixp" "ifog-transit" ];
 | 
					                  vlan = [ "frys-ix" "nl-ix" "fogixp" "ifog-transit" ];
 | 
				
			||||||
                  networkConfig = {
 | 
					                  networkConfig = networkd.noL3;
 | 
				
			||||||
                    LinkLocalAddressing = "no";
 | 
					 | 
				
			||||||
                    DHCP = "no";
 | 
					 | 
				
			||||||
                    LLDP = false;
 | 
					 | 
				
			||||||
                    EmitLLDP = false;
 | 
					 | 
				
			||||||
                    IPv6AcceptRA = false;
 | 
					 | 
				
			||||||
                  };
 | 
					 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                "85-ifog-transit" = {
 | 
					                "85-ifog-transit" = {
 | 
				
			||||||
                  matchConfig.Name = "ifog-transit";
 | 
					                  matchConfig.Name = "ifog-transit";
 | 
				
			||||||
@@ -315,6 +286,10 @@ in
 | 
				
			|||||||
                          Destination = prefixes.vip1;
 | 
					                          Destination = prefixes.vip1;
 | 
				
			||||||
                          Gateway = allAssignments.colony.routing.ipv4.address;
 | 
					                          Gateway = allAssignments.colony.routing.ipv4.address;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                          Destination = prefixes.vip3;
 | 
				
			||||||
 | 
					                          Gateway = allAssignments.colony.routing.ipv4.address;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                          Destination = prefixes.darts.v4;
 | 
					                          Destination = prefixes.darts.v4;
 | 
				
			||||||
                          Gateway = allAssignments.colony.routing.ipv4.address;
 | 
					                          Gateway = allAssignments.colony.routing.ipv4.address;
 | 
				
			||||||
@@ -323,6 +298,15 @@ in
 | 
				
			|||||||
                          Destination = prefixes.cust.v6;
 | 
					                          Destination = prefixes.cust.v6;
 | 
				
			||||||
                          Gateway = allAssignments.colony.internal.ipv6.address;
 | 
					                          Gateway = allAssignments.colony.internal.ipv6.address;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                          Destination = lib.my.c.tailscale.prefix.v4;
 | 
				
			||||||
 | 
					                          Gateway = allAssignments.colony.routing.ipv4.address;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                          Destination = lib.my.c.tailscale.prefix.v6;
 | 
				
			||||||
 | 
					                          Gateway = allAssignments.colony.internal.ipv6.address;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                      ] ++
 | 
					                      ] ++
 | 
				
			||||||
                      (map (pName: [
 | 
					                      (map (pName: [
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
@@ -337,14 +321,19 @@ in
 | 
				
			|||||||
                  }
 | 
					                  }
 | 
				
			||||||
                ];
 | 
					                ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                "90-l2mesh-as211024" = {
 | 
					                "90-l2mesh-as211024" = mkMerge [
 | 
				
			||||||
                  matchConfig.Name = "as211024";
 | 
					                  (networkdAssignment "as211024" assignments.as211024)
 | 
				
			||||||
                  address = with assignments.as211024; [
 | 
					                  {
 | 
				
			||||||
                    (with ipv4; "${address}/${toString mask}")
 | 
					                    matchConfig.Name = "as211024";
 | 
				
			||||||
                    (with ipv6; "${address}/${toString mask}")
 | 
					                    networkConfig.IPv6AcceptRA = mkForce false;
 | 
				
			||||||
                  ];
 | 
					                    routes = map (r: { routeConfig = r; }) [
 | 
				
			||||||
                  networkConfig.IPv6AcceptRA = false;
 | 
					                      {
 | 
				
			||||||
                };
 | 
					                        Destination = lib.my.c.home.prefixes.all.v4;
 | 
				
			||||||
 | 
					                        Gateway = lib.my.c.home.vips.as211024.v4;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                    ];
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
                "95-kelder" = {
 | 
					                "95-kelder" = {
 | 
				
			||||||
                  matchConfig.Name = "kelder";
 | 
					                  matchConfig.Name = "kelder";
 | 
				
			||||||
                  routes = [
 | 
					                  routes = [
 | 
				
			||||||
@@ -366,43 +355,23 @@ in
 | 
				
			|||||||
                  "estuary/kelder-wg.key" = {
 | 
					                  "estuary/kelder-wg.key" = {
 | 
				
			||||||
                    owner = "systemd-network";
 | 
					                    owner = "systemd-network";
 | 
				
			||||||
                  };
 | 
					                  };
 | 
				
			||||||
 | 
					                  "l2mesh/as211024.key" = {};
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
              server.enable = true;
 | 
					              server.enable = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              vpns = {
 | 
				
			||||||
 | 
					                l2.pskFiles = {
 | 
				
			||||||
 | 
					                  as211024 = config.age.secrets."l2mesh/as211024.key".path;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
              firewall = {
 | 
					              firewall = {
 | 
				
			||||||
                trustedInterfaces = [ "as211024" ];
 | 
					 | 
				
			||||||
                udp.allowed = [ 5353 lib.my.c.kelder.vpn.port ];
 | 
					                udp.allowed = [ 5353 lib.my.c.kelder.vpn.port ];
 | 
				
			||||||
                tcp.allowed = [ 5353 "bgp" ];
 | 
					                tcp.allowed = [ 5353 "bgp" ];
 | 
				
			||||||
                nat = {
 | 
					                nat = {
 | 
				
			||||||
                  enable = true;
 | 
					                  enable = true;
 | 
				
			||||||
                  externalInterface = "wan";
 | 
					                  externalInterface = "wan";
 | 
				
			||||||
                  externalIP = assignments.internal.ipv4.address;
 | 
					                  forwardPorts."${assignments.internal.ipv4.address}" = firewallForwards allAssignments;
 | 
				
			||||||
                  forwardPorts = [
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                      port = "http";
 | 
					 | 
				
			||||||
                      dst = allAssignments.middleman.internal.ipv4.address;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                      port = "https";
 | 
					 | 
				
			||||||
                      dst = allAssignments.middleman.internal.ipv4.address;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                      port = 8448;
 | 
					 | 
				
			||||||
                      dst = allAssignments.middleman.internal.ipv4.address;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                      port = 2456;
 | 
					 | 
				
			||||||
                      dst = allAssignments.valheim-oci.internal.ipv4.address;
 | 
					 | 
				
			||||||
                      proto = "udp";
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                      port = 2457;
 | 
					 | 
				
			||||||
                      dst = allAssignments.valheim-oci.internal.ipv4.address;
 | 
					 | 
				
			||||||
                      proto = "udp";
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                  ];
 | 
					 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                extraRules =
 | 
					                extraRules =
 | 
				
			||||||
                let
 | 
					                let
 | 
				
			||||||
@@ -424,12 +393,16 @@ in
 | 
				
			|||||||
                      # Safe enough to allow all SSH
 | 
					                      # Safe enough to allow all SSH
 | 
				
			||||||
                      tcp dport ssh accept
 | 
					                      tcp dport ssh accept
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                      ${matchInet "tcp dport { http, https, 8448 } accept" "middleman"}
 | 
					                      ip6 daddr ${aa.middleman.internal.ipv6.address} tcp dport { http, https, 8448 } accept
 | 
				
			||||||
                      ${matchInet "udp dport { 2456-2457 } accept" "valheim-oci"}
 | 
					                      ${matchInet "tcp dport { http, https } accept" "git"}
 | 
				
			||||||
 | 
					                      ip6 daddr ${aa.simpcraft-oci.internal.ipv6.address} tcp dport { 25565, 25575 } accept
 | 
				
			||||||
 | 
					                      ip6 daddr ${aa.simpcraft-staging-oci.internal.ipv6.address} tcp dport 25565 accept
 | 
				
			||||||
                      return
 | 
					                      return
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    chain routing-udp {
 | 
					                    chain routing-udp {
 | 
				
			||||||
 | 
					                      ip6 daddr ${aa.valheim-oci.internal.ipv6.address} udp dport { 2456-2457 } accept
 | 
				
			||||||
 | 
					                      ip6 daddr ${aa.waffletail.internal.ipv6.address} udp dport 41641 accept
 | 
				
			||||||
 | 
					                      ip6 daddr ${aa.simpcraft-oci.internal.ipv6.address} udp dport 25565 accept
 | 
				
			||||||
                      return
 | 
					                      return
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    chain filter-routing {
 | 
					                    chain filter-routing {
 | 
				
			||||||
@@ -446,9 +419,10 @@ in
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    chain forward {
 | 
					                    chain forward {
 | 
				
			||||||
                      iifname { wan, $ixps } oifname base jump filter-routing
 | 
					                      ${lib.my.c.as211024.nftTrust}
 | 
				
			||||||
 | 
					                      iifname { wan, as211024, $ixps } oifname base jump filter-routing
 | 
				
			||||||
                      oifname $ixps jump ixp
 | 
					                      oifname $ixps jump ixp
 | 
				
			||||||
                      iifname base oifname { wan, $ixps } accept
 | 
					                      iifname base oifname { base, wan, $ixps } accept
 | 
				
			||||||
                      oifname { as211024, kelder } accept
 | 
					                      oifname { as211024, kelder } accept
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    chain output {
 | 
					                    chain output {
 | 
				
			||||||
@@ -459,11 +433,9 @@ in
 | 
				
			|||||||
                  table inet nat {
 | 
					                  table inet nat {
 | 
				
			||||||
                    chain prerouting {
 | 
					                    chain prerouting {
 | 
				
			||||||
                      ${matchInet "meta l4proto { udp, tcp } th dport domain redirect to :5353" "estuary"}
 | 
					                      ${matchInet "meta l4proto { udp, tcp } th dport domain redirect to :5353" "estuary"}
 | 
				
			||||||
                      ip daddr ${allAssignments.shill.internal.ipv4.address} tcp dport { http, https } dnat to ${allAssignments.middleman.internal.ipv4.address}
 | 
					 | 
				
			||||||
                      ip6 daddr ${allAssignments.shill.internal.ipv6.address} tcp dport { http, https } dnat to ${allAssignments.middleman.internal.ipv6.address}
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    chain postrouting {
 | 
					                    chain postrouting {
 | 
				
			||||||
                      ip saddr ${prefixes.all.v4} snat to ${assignments.internal.ipv4.address}
 | 
					                      ip saddr ${prefixes.all.v4} oifname != as211024 snat to ${assignments.internal.ipv4.address}
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
                '';
 | 
					                '';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,7 @@ in
 | 
				
			|||||||
          allowFrom = [
 | 
					          allowFrom = [
 | 
				
			||||||
            "127.0.0.0/8" "::1/128"
 | 
					            "127.0.0.0/8" "::1/128"
 | 
				
			||||||
            prefixes.all.v4 prefixes.all.v6
 | 
					            prefixes.all.v4 prefixes.all.v6
 | 
				
			||||||
          ];
 | 
					          ] ++ (with lib.my.c.tailscale.prefix; [ v4 v6 ]);
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        settings = {
 | 
					        settings = {
 | 
				
			||||||
@@ -145,9 +145,14 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            http IN A ${assignments.internal.ipv4.address}
 | 
					            http IN A ${assignments.internal.ipv4.address}
 | 
				
			||||||
            http IN AAAA ${allAssignments.middleman.internal.ipv6.address}
 | 
					            http IN AAAA ${allAssignments.middleman.internal.ipv6.address}
 | 
				
			||||||
 | 
					            librespeed IN CNAME http.${config.networking.domain}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            valheim IN A ${assignments.internal.ipv4.address}
 | 
					            valheim IN A ${assignments.internal.ipv4.address}
 | 
				
			||||||
            valheim IN AAAA ${allAssignments.valheim-oci.internal.ipv6.address}
 | 
					            valheim IN AAAA ${allAssignments.valheim-oci.internal.ipv6.address}
 | 
				
			||||||
 | 
					            simpcraft IN A ${assignments.internal.ipv4.address}
 | 
				
			||||||
 | 
					            simpcraft IN AAAA ${allAssignments.simpcraft-oci.internal.ipv6.address}
 | 
				
			||||||
 | 
					            simpcraft-staging IN A ${assignments.internal.ipv4.address}
 | 
				
			||||||
 | 
					            simpcraft-staging IN AAAA ${allAssignments.simpcraft-staging-oci.internal.ipv6.address}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            mail-vm IN A ${net.cidr.host 0 prefixes.mail.v4}
 | 
					            mail-vm IN A ${net.cidr.host 0 prefixes.mail.v4}
 | 
				
			||||||
            mail-vm IN AAAA ${net.cidr.host 1 prefixes.mail.v6}
 | 
					            mail-vm IN AAAA ${net.cidr.host 1 prefixes.mail.v6}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										241
									
								
								nixos/boxes/colony/vms/git/default.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								nixos/boxes/colony/vms/git/default.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,241 @@
 | 
				
			|||||||
 | 
					{ lib, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (builtins) mapAttrs;
 | 
				
			||||||
 | 
					  inherit (lib) mkMerge mkDefault;
 | 
				
			||||||
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
 | 
					  inherit (lib.my.c) pubDomain;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.colony) domain prefixes;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.nginx) baseHttpConfig proxyHeaders;
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  nixos.systems.git = {
 | 
				
			||||||
 | 
					    system = "x86_64-linux";
 | 
				
			||||||
 | 
					    nixpkgs = "mine";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assignments = {
 | 
				
			||||||
 | 
					      routing = {
 | 
				
			||||||
 | 
					        name = "git-vm-routing";
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        ipv4.address = net.cidr.host 4 prefixes.vms.v4;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      internal = {
 | 
				
			||||||
 | 
					        name = "git-vm";
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host 0 prefixes.vip3;
 | 
				
			||||||
 | 
					          mask = 32;
 | 
				
			||||||
 | 
					          gateway = null;
 | 
				
			||||||
 | 
					          genPTR = false;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6 = {
 | 
				
			||||||
 | 
					          iid = "::4";
 | 
				
			||||||
 | 
					          address = net.cidr.host 4 prefixes.vms.v6;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
 | 
				
			||||||
 | 
					      let
 | 
				
			||||||
 | 
					        inherit (lib) mkMerge;
 | 
				
			||||||
 | 
					        inherit (lib.my) networkdAssignment;
 | 
				
			||||||
 | 
					      in
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        imports = [
 | 
				
			||||||
 | 
					          "${modulesPath}/profiles/qemu-guest.nix"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          ./gitea.nix
 | 
				
			||||||
 | 
					          ./gitea-actions.nix
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config = mkMerge [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            boot = {
 | 
				
			||||||
 | 
					              kernelParams = [ "console=ttyS0,115200n8" ];
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fileSystems = {
 | 
				
			||||||
 | 
					              "/boot" = {
 | 
				
			||||||
 | 
					                device = "/dev/disk/by-label/ESP";
 | 
				
			||||||
 | 
					                fsType = "vfat";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              "/nix" = {
 | 
				
			||||||
 | 
					                device = "/dev/disk/by-label/nix";
 | 
				
			||||||
 | 
					                fsType = "ext4";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              "/persist" = {
 | 
				
			||||||
 | 
					                device = "/dev/disk/by-label/persist";
 | 
				
			||||||
 | 
					                fsType = "ext4";
 | 
				
			||||||
 | 
					                neededForBoot = true;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              "/var/lib/containers" = {
 | 
				
			||||||
 | 
					                device = "/dev/disk/by-label/oci";
 | 
				
			||||||
 | 
					                fsType = "xfs";
 | 
				
			||||||
 | 
					                options = [ "pquota" ];
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            users = {
 | 
				
			||||||
 | 
					              users = {
 | 
				
			||||||
 | 
					                nginx.extraGroups = [ "acme" ];
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            security.acme = {
 | 
				
			||||||
 | 
					              acceptTerms = true;
 | 
				
			||||||
 | 
					              defaults = {
 | 
				
			||||||
 | 
					                email = "dev@nul.ie";
 | 
				
			||||||
 | 
					                server = "https://acme-v02.api.letsencrypt.org/directory";
 | 
				
			||||||
 | 
					                reloadServices = [ "nginx" ];
 | 
				
			||||||
 | 
					                dnsResolver = "8.8.8.8";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              certs = {
 | 
				
			||||||
 | 
					                "${pubDomain}" = {
 | 
				
			||||||
 | 
					                  extraDomainNames = [
 | 
				
			||||||
 | 
					                    "*.${pubDomain}"
 | 
				
			||||||
 | 
					                  ];
 | 
				
			||||||
 | 
					                  dnsProvider = "cloudflare";
 | 
				
			||||||
 | 
					                  credentialsFile = config.age.secrets."middleman/cloudflare-credentials.conf".path;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            services = {
 | 
				
			||||||
 | 
					              fstrim = lib.my.c.colony.fstrimConfig;
 | 
				
			||||||
 | 
					              # Hacks for Jsch (Minecraft FastBack) to work
 | 
				
			||||||
 | 
					              openssh = {
 | 
				
			||||||
 | 
					                hostKeys = [
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    bits = 4096;
 | 
				
			||||||
 | 
					                    path = "/etc/ssh/ssh_host_rsa_key";
 | 
				
			||||||
 | 
					                    type = "rsa";
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    path = "/etc/ssh/ssh_host_ed25519_key";
 | 
				
			||||||
 | 
					                    type = "ed25519";
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    type = "ecdsa-sha2-nistp256";
 | 
				
			||||||
 | 
					                    path = "/etc/ssh/ssh_host_ecdsa_key";
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					                settings = {
 | 
				
			||||||
 | 
					                  Macs = [
 | 
				
			||||||
 | 
					                    "hmac-sha2-512-etm@openssh.com"
 | 
				
			||||||
 | 
					                    "hmac-sha2-256-etm@openssh.com"
 | 
				
			||||||
 | 
					                    "umac-128-etm@openssh.com"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    "hmac-sha2-256"
 | 
				
			||||||
 | 
					                  ];
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              netdata.enable = true;
 | 
				
			||||||
 | 
					              nginx = {
 | 
				
			||||||
 | 
					                enable = true;
 | 
				
			||||||
 | 
					                enableReload = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                logError = "stderr info";
 | 
				
			||||||
 | 
					                recommendedTlsSettings = true;
 | 
				
			||||||
 | 
					                clientMaxBodySize = "0";
 | 
				
			||||||
 | 
					                serverTokens = true;
 | 
				
			||||||
 | 
					                sslDhparam = config.age.secrets."dhparams.pem".path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Based on recommended*Settings, but probably better to be explicit about these
 | 
				
			||||||
 | 
					                appendHttpConfig = ''
 | 
				
			||||||
 | 
					                  ${baseHttpConfig}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  # caching
 | 
				
			||||||
 | 
					                  proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=512m;
 | 
				
			||||||
 | 
					                '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                virtualHosts =
 | 
				
			||||||
 | 
					                let
 | 
				
			||||||
 | 
					                  hosts = {
 | 
				
			||||||
 | 
					                    "_" = {
 | 
				
			||||||
 | 
					                      default = true;
 | 
				
			||||||
 | 
					                      forceSSL = true;
 | 
				
			||||||
 | 
					                      onlySSL = false;
 | 
				
			||||||
 | 
					                      locations = {
 | 
				
			||||||
 | 
					                        "/".root = "${pkgs.nginx}/html";
 | 
				
			||||||
 | 
					                      };
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    "git.${pubDomain}" = {
 | 
				
			||||||
 | 
					                      locations."/".proxyPass = "http://localhost:3000";
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  defaultsFor = mapAttrs (n: _: {
 | 
				
			||||||
 | 
					                    onlySSL = mkDefault true;
 | 
				
			||||||
 | 
					                    useACMEHost = mkDefault pubDomain;
 | 
				
			||||||
 | 
					                    kTLS = mkDefault true;
 | 
				
			||||||
 | 
					                    http2 = mkDefault true;
 | 
				
			||||||
 | 
					                  });
 | 
				
			||||||
 | 
					                in
 | 
				
			||||||
 | 
					                mkMerge [
 | 
				
			||||||
 | 
					                  hosts
 | 
				
			||||||
 | 
					                  (defaultsFor hosts)
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            virtualisation = {
 | 
				
			||||||
 | 
					              podman = {
 | 
				
			||||||
 | 
					                enable = true;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              oci-containers = {
 | 
				
			||||||
 | 
					                backend = "podman";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              containers.containersConf.settings.network.default_subnet = "10.88.0.0/16";
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            systemd.network = {
 | 
				
			||||||
 | 
					              links = {
 | 
				
			||||||
 | 
					                "10-vms" = {
 | 
				
			||||||
 | 
					                  matchConfig.MACAddress = "52:54:00:75:78:a8";
 | 
				
			||||||
 | 
					                  linkConfig.Name = "vms";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              networks = {
 | 
				
			||||||
 | 
					                "80-vms" = mkMerge [
 | 
				
			||||||
 | 
					                  (networkdAssignment "vms" assignments.routing)
 | 
				
			||||||
 | 
					                  (networkdAssignment "vms" assignments.internal)
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            my = {
 | 
				
			||||||
 | 
					              secrets = {
 | 
				
			||||||
 | 
					                key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP+KINpHLMduBuW96JzfSRDLUzkI+XaCBghu5/wHiW5R";
 | 
				
			||||||
 | 
					                files = {
 | 
				
			||||||
 | 
					                  "dhparams.pem" = {
 | 
				
			||||||
 | 
					                    owner = "acme";
 | 
				
			||||||
 | 
					                    group = "acme";
 | 
				
			||||||
 | 
					                    mode = "440";
 | 
				
			||||||
 | 
					                  };
 | 
				
			||||||
 | 
					                  "middleman/cloudflare-credentials.conf" = {
 | 
				
			||||||
 | 
					                    owner = "acme";
 | 
				
			||||||
 | 
					                    group = "acme";
 | 
				
			||||||
 | 
					                  };
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              server.enable = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              firewall = {
 | 
				
			||||||
 | 
					                tcp.allowed = [ 19999 "http" "https" ];
 | 
				
			||||||
 | 
					                extraRules = ''
 | 
				
			||||||
 | 
					                  table inet filter {
 | 
				
			||||||
 | 
					                    chain forward {
 | 
				
			||||||
 | 
					                      ip saddr 10.88.0.0/16 accept
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                '';
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,7 +6,7 @@ let
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  cfgFile = pkgs.writeText "gitea-actions-runner.yaml" (toJSON {
 | 
					  cfgFile = pkgs.writeText "gitea-actions-runner.yaml" (toJSON {
 | 
				
			||||||
    container = {
 | 
					    container = {
 | 
				
			||||||
      network = "colony";
 | 
					      network = "podman";
 | 
				
			||||||
      privileged = true;
 | 
					      privileged = true;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    cache = {
 | 
					    cache = {
 | 
				
			||||||
@@ -30,6 +30,7 @@ in
 | 
				
			|||||||
          enable = true;
 | 
					          enable = true;
 | 
				
			||||||
          name = "main-docker";
 | 
					          name = "main-docker";
 | 
				
			||||||
          labels = [
 | 
					          labels = [
 | 
				
			||||||
 | 
					            "debian-node-bullseye:docker://node:18-bullseye"
 | 
				
			||||||
            "ubuntu-22.04:docker://git.nul.ie/dev/actions-ubuntu:22.04"
 | 
					            "ubuntu-22.04:docker://git.nul.ie/dev/actions-ubuntu:22.04"
 | 
				
			||||||
          ];
 | 
					          ];
 | 
				
			||||||
          url = "https://git.${pubDomain}";
 | 
					          url = "https://git.${pubDomain}";
 | 
				
			||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
{ lib, pkgs, config, assignments, allAssignments, ... }:
 | 
					{ lib, pkgs, config, assignments, allAssignments, ... }:
 | 
				
			||||||
let
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib) mkMerge;
 | 
				
			||||||
  inherit (lib.my.c) pubDomain;
 | 
					  inherit (lib.my.c) pubDomain;
 | 
				
			||||||
  inherit (lib.my.c.colony) prefixes;
 | 
					  inherit (lib.my.c.colony) prefixes;
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
@@ -25,20 +26,25 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    systemd = {
 | 
					    systemd = {
 | 
				
			||||||
      services = {
 | 
					      services = {
 | 
				
			||||||
        gitea.preStart =
 | 
					        gitea = mkMerge [
 | 
				
			||||||
        let
 | 
					          (lib.my.systemdAwaitPostgres pkgs.postgresql "colony-psql")
 | 
				
			||||||
          repSec = "${pkgs.replace-secret}/bin/replace-secret";
 | 
					          {
 | 
				
			||||||
          confPath = "${config.services.gitea.customDir}/conf/app.ini";
 | 
					            preStart =
 | 
				
			||||||
        in
 | 
					            let
 | 
				
			||||||
        ''
 | 
					              repSec = "${pkgs.replace-secret}/bin/replace-secret";
 | 
				
			||||||
          gitea_extra_setup() {
 | 
					              confPath = "${config.services.gitea.customDir}/conf/app.ini";
 | 
				
			||||||
            chmod u+w '${confPath}'
 | 
					            in
 | 
				
			||||||
            ${repSec} '#miniosecret#' '${config.age.secrets."gitea/minio.txt".path}' '${confPath}'
 | 
					            ''
 | 
				
			||||||
            chmod u-w '${confPath}'
 | 
					              gitea_extra_setup() {
 | 
				
			||||||
          }
 | 
					                chmod u+w '${confPath}'
 | 
				
			||||||
 | 
					                ${repSec} '#miniosecret#' '${config.age.secrets."gitea/minio.txt".path}' '${confPath}'
 | 
				
			||||||
 | 
					                chmod u-w '${confPath}'
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          (umask 027; gitea_extra_setup)
 | 
					              (umask 027; gitea_extra_setup)
 | 
				
			||||||
        '';
 | 
					            '';
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -123,21 +129,6 @@ in
 | 
				
			|||||||
          "gitea/minio.txt" = ownedByGit;
 | 
					          "gitea/minio.txt" = ownedByGit;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					 | 
				
			||||||
      firewall.extraRules = ''
 | 
					 | 
				
			||||||
        table inet filter {
 | 
					 | 
				
			||||||
          chain input {
 | 
					 | 
				
			||||||
            ip saddr ${prefixes.all.v4} tcp dport 3000 accept
 | 
					 | 
				
			||||||
            ip6 saddr ${prefixes.all.v6} tcp dport 3000 accept
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        table inet nat {
 | 
					 | 
				
			||||||
          chain prerouting {
 | 
					 | 
				
			||||||
            ip daddr ${assignments.internal.ipv4.address} tcp dport { http, https } dnat to ${allAssignments.middleman.internal.ipv4.address}
 | 
					 | 
				
			||||||
            ip6 daddr ${assignments.internal.ipv6.address} tcp dport { http, https } dnat to ${allAssignments.middleman.internal.ipv6.address}
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      '';
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -7,5 +7,6 @@
 | 
				
			|||||||
    ./jackflix
 | 
					    ./jackflix
 | 
				
			||||||
    ./object.nix
 | 
					    ./object.nix
 | 
				
			||||||
    ./toot.nix
 | 
					    ./toot.nix
 | 
				
			||||||
 | 
					    ./waffletail.nix
 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
let
 | 
					let
 | 
				
			||||||
  inherit (lib.my) net;
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
  inherit (lib.my.c) pubDomain;
 | 
					  inherit (lib.my.c) pubDomain;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.nginx) baseHttpConfig;
 | 
				
			||||||
  inherit (lib.my.c.colony) domain prefixes;
 | 
					  inherit (lib.my.c.colony) domain prefixes;
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -65,6 +66,7 @@ in
 | 
				
			|||||||
                  owner = "nginx";
 | 
					                  owner = "nginx";
 | 
				
			||||||
                  group = "nginx";
 | 
					                  group = "nginx";
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					                "librespeed.toml" = { };
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -121,6 +123,19 @@ in
 | 
				
			|||||||
                baseURL = "https://sso.${pubDomain}";
 | 
					                baseURL = "https://sso.${pubDomain}";
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            librespeed = {
 | 
				
			||||||
 | 
					              frontend.servers = [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  name = "Amsterdam, Netherlands";
 | 
				
			||||||
 | 
					                  server = "//librespeed.${domain}";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
 | 
					              backend = {
 | 
				
			||||||
 | 
					                enable = true;
 | 
				
			||||||
 | 
					                extraSettingsFile = config.age.secrets."librespeed.toml".path;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          users = {
 | 
					          users = {
 | 
				
			||||||
@@ -131,6 +146,10 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          systemd = {
 | 
					          systemd = {
 | 
				
			||||||
            network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal;
 | 
					            network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal;
 | 
				
			||||||
 | 
					            services = {
 | 
				
			||||||
 | 
					              # HACK: nginx seems to get stuck not being able to DNS early...
 | 
				
			||||||
 | 
					              nginx = lib.my.systemdAwaitPostgres pkgs.postgresql "colony-psql";
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          security = {
 | 
					          security = {
 | 
				
			||||||
@@ -231,43 +250,9 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
              # Based on recommended*Settings, but probably better to be explicit about these
 | 
					              # Based on recommended*Settings, but probably better to be explicit about these
 | 
				
			||||||
              appendHttpConfig = ''
 | 
					              appendHttpConfig = ''
 | 
				
			||||||
                # NixOS provides a logrotate config that auto-compresses :)
 | 
					                ${baseHttpConfig}
 | 
				
			||||||
                log_format main
 | 
					 | 
				
			||||||
                  '$remote_addr - $remote_user [$time_local] $scheme "$host" "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
 | 
					 | 
				
			||||||
                access_log /var/log/nginx/access.log main;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # optimisation
 | 
					                resolver_timeout 5s;
 | 
				
			||||||
                sendfile on;
 | 
					 | 
				
			||||||
                tcp_nopush on;
 | 
					 | 
				
			||||||
                tcp_nodelay on;
 | 
					 | 
				
			||||||
                keepalive_timeout 65;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                # gzip
 | 
					 | 
				
			||||||
                gzip on;
 | 
					 | 
				
			||||||
                gzip_proxied any;
 | 
					 | 
				
			||||||
                gzip_comp_level 5;
 | 
					 | 
				
			||||||
                gzip_types
 | 
					 | 
				
			||||||
                  application/atom+xml
 | 
					 | 
				
			||||||
                  application/javascript
 | 
					 | 
				
			||||||
                  application/json
 | 
					 | 
				
			||||||
                  application/xml
 | 
					 | 
				
			||||||
                  application/xml+rss
 | 
					 | 
				
			||||||
                  image/svg+xml
 | 
					 | 
				
			||||||
                  text/css
 | 
					 | 
				
			||||||
                  text/javascript
 | 
					 | 
				
			||||||
                  text/plain
 | 
					 | 
				
			||||||
                  text/xml;
 | 
					 | 
				
			||||||
                gzip_vary on;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                # proxying
 | 
					 | 
				
			||||||
                proxy_buffering off;
 | 
					 | 
				
			||||||
                proxy_redirect off;
 | 
					 | 
				
			||||||
                proxy_connect_timeout 60s;
 | 
					 | 
				
			||||||
                proxy_read_timeout 60s;
 | 
					 | 
				
			||||||
                proxy_send_timeout 60s;
 | 
					 | 
				
			||||||
                proxy_http_version 1.1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                ${lib.my.c.nginx.proxyHeaders}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                # caching
 | 
					                # caching
 | 
				
			||||||
                proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=4g;
 | 
					                proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=4g;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -318,59 +318,12 @@ in
 | 
				
			|||||||
        useACMEHost = pubDomain;
 | 
					        useACMEHost = pubDomain;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "toot.nul.ie" =
 | 
					      "toot.nul.ie" = {
 | 
				
			||||||
      let
 | 
					        locations."/" = {
 | 
				
			||||||
        mkAssetLoc = name: {
 | 
					          proxyPass = "http://toot-ctr.${domain}:80";
 | 
				
			||||||
          tryFiles = "$uri =404";
 | 
					          proxyWebsockets = true;
 | 
				
			||||||
          extraConfig = ''
 | 
					          extraConfig = proxyHeaders;
 | 
				
			||||||
            add_header Cache-Control "public, max-age=2419200, must-revalidate";
 | 
					 | 
				
			||||||
            add_header Strict-Transport-Security "max-age=63072000; includeSubpubDomains";
 | 
					 | 
				
			||||||
          '';
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
      in
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        root = "${pkgs.mastodon}/public";
 | 
					 | 
				
			||||||
        locations = mkMerge [
 | 
					 | 
				
			||||||
          (genAttrs [
 | 
					 | 
				
			||||||
            "= /sw.js"
 | 
					 | 
				
			||||||
            "~ ^/assets/"
 | 
					 | 
				
			||||||
            "~ ^/avatars/"
 | 
					 | 
				
			||||||
            "~ ^/emoji/"
 | 
					 | 
				
			||||||
            "~ ^/headers/"
 | 
					 | 
				
			||||||
            "~ ^/packs/"
 | 
					 | 
				
			||||||
            "~ ^/shortcuts/"
 | 
					 | 
				
			||||||
            "~ ^/sounds/"
 | 
					 | 
				
			||||||
          ] mkAssetLoc)
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            "/".tryFiles = "$uri @proxy";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            "^~ /api/v1/streaming" = {
 | 
					 | 
				
			||||||
              proxyPass = "http://toot-ctr.${domain}:55000";
 | 
					 | 
				
			||||||
              proxyWebsockets = true;
 | 
					 | 
				
			||||||
              extraConfig = ''
 | 
					 | 
				
			||||||
                ${proxyHeaders}
 | 
					 | 
				
			||||||
                proxy_set_header Proxy "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
 | 
					 | 
				
			||||||
              '';
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
            "@proxy" = {
 | 
					 | 
				
			||||||
              proxyPass = "http://toot-ctr.${domain}:55001";
 | 
					 | 
				
			||||||
              proxyWebsockets = true;
 | 
					 | 
				
			||||||
              extraConfig = ''
 | 
					 | 
				
			||||||
                ${proxyHeaders}
 | 
					 | 
				
			||||||
                proxy_set_header Proxy "";
 | 
					 | 
				
			||||||
                proxy_pass_header Server;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                proxy_cache CACHE;
 | 
					 | 
				
			||||||
                proxy_cache_valid 200 7d;
 | 
					 | 
				
			||||||
                proxy_cache_valid 410 24h;
 | 
					 | 
				
			||||||
                proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
 | 
					 | 
				
			||||||
                add_header X-Cached $upstream_cache_status;
 | 
					 | 
				
			||||||
              '';
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
        useACMEHost = pubDomain;
 | 
					        useACMEHost = pubDomain;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -394,9 +347,41 @@ in
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
        useACMEHost = pubDomain;
 | 
					        useACMEHost = pubDomain;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					      "public.${pubDomain}" = {
 | 
				
			||||||
 | 
					        serverAliases = [ "p.${pubDomain}" ];
 | 
				
			||||||
 | 
					        locations."/" = {
 | 
				
			||||||
 | 
					          root = "/mnt/media/public";
 | 
				
			||||||
 | 
					          extraConfig = ''
 | 
				
			||||||
 | 
					            fancyindex on;
 | 
				
			||||||
 | 
					            fancyindex_show_dotfiles on;
 | 
				
			||||||
 | 
					          '';
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        useACMEHost = pubDomain;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      "git.${pubDomain}" = {
 | 
					      "mc-map.${pubDomain}" = {
 | 
				
			||||||
        locations."/".proxyPass = "http://shill-vm.${domain}:3000";
 | 
					        locations."/".proxyPass = "http://simpcraft-oci.${domain}:8100";
 | 
				
			||||||
 | 
					        useACMEHost = pubDomain;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      "mc-rail.${pubDomain}" = {
 | 
				
			||||||
 | 
					        locations."/".proxyPass = "http://simpcraft-staging-oci.${domain}:3876";
 | 
				
			||||||
 | 
					        useACMEHost = pubDomain;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "librespeed.${domain}" = {
 | 
				
			||||||
 | 
					        locations."/".proxyPass = "http://localhost:8989";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      "speed.${pubDomain}" = {
 | 
				
			||||||
 | 
					        locations."/".proxyPass = "http://localhost:8989";
 | 
				
			||||||
 | 
					        useACMEHost = pubDomain;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "md.${pubDomain}" = {
 | 
				
			||||||
 | 
					        locations."/" = {
 | 
				
			||||||
 | 
					          proxyPass = "http://object-ctr.${domain}:3000";
 | 
				
			||||||
 | 
					          proxyWebsockets = true;
 | 
				
			||||||
 | 
					          extraConfig = proxyHeaders;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
        useACMEHost = pubDomain;
 | 
					        useACMEHost = pubDomain;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -412,7 +397,6 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      nixCacheableRegex = ''^\/(\S+\.narinfo|nar\/\S+\.nar\.\S+)$'';
 | 
					      nixCacheableRegex = ''^\/(\S+\.narinfo|nar\/\S+\.nar\.\S+)$'';
 | 
				
			||||||
      nixCacheHeaders = ''
 | 
					      nixCacheHeaders = ''
 | 
				
			||||||
        proxy_hide_header "X-Amz-Request-Id";
 | 
					 | 
				
			||||||
        add_header Cache-Control $nix_cache_control;
 | 
					        add_header Cache-Control $nix_cache_control;
 | 
				
			||||||
        add_header Expires $nix_expires;
 | 
					        add_header Expires $nix_expires;
 | 
				
			||||||
      '';
 | 
					      '';
 | 
				
			||||||
@@ -435,7 +419,22 @@ in
 | 
				
			|||||||
      "s3.${pubDomain}" = {
 | 
					      "s3.${pubDomain}" = {
 | 
				
			||||||
        serverAliases = [ "*.s3.${pubDomain}" ];
 | 
					        serverAliases = [ "*.s3.${pubDomain}" ];
 | 
				
			||||||
        inherit extraConfig;
 | 
					        inherit extraConfig;
 | 
				
			||||||
        locations."/".proxyPass = s3Upstream;
 | 
					        locations = {
 | 
				
			||||||
 | 
					          "/".proxyPass = s3Upstream;
 | 
				
			||||||
 | 
					          "/gitea/packages/" = {
 | 
				
			||||||
 | 
					            proxyPass = s3Upstream;
 | 
				
			||||||
 | 
					            # HACK: Docker images need the MIME type to be correct for the manifest but Gitea
 | 
				
			||||||
 | 
					            # doesn't tell S3... By hiding the header we can use add_header to set Content-Type
 | 
				
			||||||
 | 
					            # (normally can't be set directly)
 | 
				
			||||||
 | 
					            extraConfig = ''
 | 
				
			||||||
 | 
					              proxy_hide_header Content-Type;
 | 
				
			||||||
 | 
					              add_header Content-Type $upstream_http_content_type always;
 | 
				
			||||||
 | 
					              if ($args ~ "response-content-disposition=.+filename%3D%22manifest\.json%22") {
 | 
				
			||||||
 | 
					                add_header Content-Type "application/vnd.docker.distribution.manifest.v2+json";
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            '';
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
        useACMEHost = pubDomain;
 | 
					        useACMEHost = pubDomain;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -448,7 +447,6 @@ in
 | 
				
			|||||||
          };
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        useACMEHost = pubDomain;
 | 
					        useACMEHost = pubDomain;
 | 
				
			||||||
        onlySSL = false;
 | 
					 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,11 +48,17 @@ in
 | 
				
			|||||||
                  group = config.my.user.config.group;
 | 
					                  group = config.my.user.config.group;
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                "object/atticd.env" = {};
 | 
					                "object/atticd.env" = {};
 | 
				
			||||||
 | 
					                "object/hedgedoc.env" = {};
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            firewall = {
 | 
					            firewall = {
 | 
				
			||||||
              tcp.allowed = [ 9000 9001 config.services.sharry.config.bind.port 8069 ];
 | 
					              tcp.allowed = [
 | 
				
			||||||
 | 
					                9000 9001
 | 
				
			||||||
 | 
					                config.services.sharry.config.bind.port
 | 
				
			||||||
 | 
					                8069
 | 
				
			||||||
 | 
					                config.services.hedgedoc.settings.port
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            user.homeConfig = {
 | 
					            user.homeConfig = {
 | 
				
			||||||
@@ -60,9 +66,23 @@ in
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          users = with lib.my.c.ids; let inherit (config.services.atticd) user group; in {
 | 
				
			||||||
 | 
					            users."${user}" = {
 | 
				
			||||||
 | 
					              isSystemUser = true;
 | 
				
			||||||
 | 
					              uid = uids.atticd;
 | 
				
			||||||
 | 
					              group = group;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            groups."${user}".gid = gids.atticd;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          systemd = {
 | 
					          systemd = {
 | 
				
			||||||
            network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal;
 | 
					            network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal;
 | 
				
			||||||
            services = {
 | 
					
 | 
				
			||||||
 | 
					            services =
 | 
				
			||||||
 | 
					            let
 | 
				
			||||||
 | 
					              awaitPostgres = systemdAwaitPostgres pkgs.postgresql "colony-psql";
 | 
				
			||||||
 | 
					            in
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
              minio = {
 | 
					              minio = {
 | 
				
			||||||
                environment = {
 | 
					                environment = {
 | 
				
			||||||
                  MINIO_ROOT_USER = "minioadmin";
 | 
					                  MINIO_ROOT_USER = "minioadmin";
 | 
				
			||||||
@@ -71,7 +91,17 @@ in
 | 
				
			|||||||
                  MINIO_BROWSER_REDIRECT_URL = "https://minio.nul.ie";
 | 
					                  MINIO_BROWSER_REDIRECT_URL = "https://minio.nul.ie";
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
              sharry = systemdAwaitPostgres pkgs.postgresql "colony-psql";
 | 
					              sharry = awaitPostgres;
 | 
				
			||||||
 | 
					              atticd = mkMerge [
 | 
				
			||||||
 | 
					                awaitPostgres
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  serviceConfig = {
 | 
				
			||||||
 | 
					                    # Needs to be able to access its data
 | 
				
			||||||
 | 
					                    DynamicUser = mkForce false;
 | 
				
			||||||
 | 
					                    BindPaths = [ "/mnt/atticd:/var/lib/atticd/storage" ];
 | 
				
			||||||
 | 
					                  };
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -159,10 +189,8 @@ in
 | 
				
			|||||||
                api-endpoint = "https://nix-cache.${pubDomain}/";
 | 
					                api-endpoint = "https://nix-cache.${pubDomain}/";
 | 
				
			||||||
                database = mkForce {}; # blank to pull from env
 | 
					                database = mkForce {}; # blank to pull from env
 | 
				
			||||||
                storage = {
 | 
					                storage = {
 | 
				
			||||||
                  type = "s3";
 | 
					                  type = "local";
 | 
				
			||||||
                  region = "eu-central-1";
 | 
					                  path = "/var/lib/atticd/storage";
 | 
				
			||||||
                  bucket = "nix-attic";
 | 
					 | 
				
			||||||
                  endpoint = "http://localhost:9000";
 | 
					 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                chunking = {
 | 
					                chunking = {
 | 
				
			||||||
                  nar-size-threshold = 65536;
 | 
					                  nar-size-threshold = 65536;
 | 
				
			||||||
@@ -172,6 +200,26 @@ in
 | 
				
			|||||||
                };
 | 
					                };
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            hedgedoc = {
 | 
				
			||||||
 | 
					              enable = true;
 | 
				
			||||||
 | 
					              environmentFile = config.age.secrets."object/hedgedoc.env".path;
 | 
				
			||||||
 | 
					              settings = {
 | 
				
			||||||
 | 
					                domain = "md.${pubDomain}";
 | 
				
			||||||
 | 
					                protocolUseSSL = true;
 | 
				
			||||||
 | 
					                db = {
 | 
				
			||||||
 | 
					                  dialect = "postgresql";
 | 
				
			||||||
 | 
					                  username = "hedgedoc";
 | 
				
			||||||
 | 
					                  database = "hedgedoc";
 | 
				
			||||||
 | 
					                  host = "colony-psql";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                host = "::";
 | 
				
			||||||
 | 
					                allowAnonymous = false;
 | 
				
			||||||
 | 
					                allowAnonymousEdits = true;
 | 
				
			||||||
 | 
					                email = true;
 | 
				
			||||||
 | 
					                allowEmailRegister = false;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        (mkIf config.my.build.isDevVM {
 | 
					        (mkIf config.my.build.isDevVM {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
{ lib, ... }:
 | 
					{ lib, ... }:
 | 
				
			||||||
let
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib) mkForce;
 | 
				
			||||||
  inherit (lib.my) net;
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
  inherit (lib.my.c.colony) domain prefixes;
 | 
					  inherit (lib.my.c.colony) domain prefixes;
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
@@ -54,8 +55,7 @@ in
 | 
				
			|||||||
              tcp.allowed = [
 | 
					              tcp.allowed = [
 | 
				
			||||||
                19999
 | 
					                19999
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                config.services.mastodon.webPort
 | 
					                "http"
 | 
				
			||||||
                config.services.mastodon.streamingPort
 | 
					 | 
				
			||||||
              ];
 | 
					              ];
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
@@ -78,10 +78,13 @@ in
 | 
				
			|||||||
          services = {
 | 
					          services = {
 | 
				
			||||||
            netdata.enable = true;
 | 
					            netdata.enable = true;
 | 
				
			||||||
            mastodon = mkMerge [
 | 
					            mastodon = mkMerge [
 | 
				
			||||||
              {
 | 
					              rec {
 | 
				
			||||||
                enable = true;
 | 
					                enable = true;
 | 
				
			||||||
                localDomain = "nul.ie";
 | 
					                localDomain = extraConfig.WEB_DOMAIN; # for nginx config
 | 
				
			||||||
                extraConfig.WEB_DOMAIN = "toot.nul.ie";
 | 
					                extraConfig = {
 | 
				
			||||||
 | 
					                  LOCAL_DOMAIN = "nul.ie";
 | 
				
			||||||
 | 
					                  WEB_DOMAIN = "toot.nul.ie";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                secretKeyBaseFile = config.age.secrets."toot/secret-key.txt".path;
 | 
					                secretKeyBaseFile = config.age.secrets."toot/secret-key.txt".path;
 | 
				
			||||||
                otpSecretFile = config.age.secrets."toot/otp-secret.txt".path;
 | 
					                otpSecretFile = config.age.secrets."toot/otp-secret.txt".path;
 | 
				
			||||||
@@ -90,9 +93,8 @@ in
 | 
				
			|||||||
                  "vapid-pubkey.txt"
 | 
					                  "vapid-pubkey.txt"
 | 
				
			||||||
                  "BAyRyD2pnLQtMHr3J5AzjNMll_HDC6ra1ilOLAUmKyhkEdbm7_OwKZUgw1UefY4CHEcv4OOX9TnnN2DOYYuPZu8=");
 | 
					                  "BAyRyD2pnLQtMHr3J5AzjNMll_HDC6ra1ilOLAUmKyhkEdbm7_OwKZUgw1UefY4CHEcv4OOX9TnnN2DOYYuPZu8=");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                enableUnixSocket = false;
 | 
					                streamingProcesses = 4;
 | 
				
			||||||
                configureNginx = false;
 | 
					                configureNginx = true;
 | 
				
			||||||
                trustedProxy = allAssignments.middleman.internal.ipv6.address;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                database = {
 | 
					                database = {
 | 
				
			||||||
                  createLocally = false;
 | 
					                  createLocally = false;
 | 
				
			||||||
@@ -134,13 +136,31 @@ in
 | 
				
			|||||||
                };
 | 
					                };
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            ];
 | 
					            ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Override some stuff since we are proxying upstream
 | 
				
			||||||
 | 
					            nginx = {
 | 
				
			||||||
 | 
					              recommendedProxySettings = mkForce false;
 | 
				
			||||||
 | 
					              virtualHosts."${config.services.mastodon.localDomain}" =
 | 
				
			||||||
 | 
					              let
 | 
				
			||||||
 | 
					                extraConfig = ''
 | 
				
			||||||
 | 
					                  proxy_set_header Host $host;
 | 
				
			||||||
 | 
					                '';
 | 
				
			||||||
 | 
					              in
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                forceSSL = false;
 | 
				
			||||||
 | 
					                enableACME = false;
 | 
				
			||||||
 | 
					                locations = {
 | 
				
			||||||
 | 
					                  "@proxy" = { inherit extraConfig; };
 | 
				
			||||||
 | 
					                  "/api/v1/streaming/" = { inherit extraConfig; };
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        (mkIf config.my.build.isDevVM {
 | 
					        (mkIf config.my.build.isDevVM {
 | 
				
			||||||
          virtualisation = {
 | 
					          virtualisation = {
 | 
				
			||||||
            forwardPorts = with config.services.mastodon; [
 | 
					            forwardPorts = with config.services.mastodon; [
 | 
				
			||||||
              { from = "host"; guest.port = webPort; }
 | 
					              { from = "host"; guest.port = webPort; }
 | 
				
			||||||
              { from = "host"; guest.port = streamingPort; }
 | 
					 | 
				
			||||||
            ];
 | 
					            ];
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										100
									
								
								nixos/boxes/colony/vms/shill/containers/waffletail.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								nixos/boxes/colony/vms/shill/containers/waffletail.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
				
			|||||||
 | 
					{ lib, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.colony) domain prefixes;
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  nixos.systems.waffletail = { config, ... }: {
 | 
				
			||||||
 | 
					    system = "x86_64-linux";
 | 
				
			||||||
 | 
					    nixpkgs = "mine";
 | 
				
			||||||
 | 
					    rendered = config.configuration.config.my.asContainer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assignments = {
 | 
				
			||||||
 | 
					      internal = {
 | 
				
			||||||
 | 
					        name = "waffletail-ctr";
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        ipv4.address = net.cidr.host 9 prefixes.ctrs.v4;
 | 
				
			||||||
 | 
					        ipv6 = {
 | 
				
			||||||
 | 
					          iid = "::9";
 | 
				
			||||||
 | 
					          address = net.cidr.host 9 prefixes.ctrs.v6;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      tailscale = with lib.my.c.tailscale; {
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host 5 prefix.v4;
 | 
				
			||||||
 | 
					          mask = 32;
 | 
				
			||||||
 | 
					          gateway = null;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host 5 prefix.v6;
 | 
				
			||||||
 | 
					          mask = 128;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    configuration = { lib, config, assignments, ... }:
 | 
				
			||||||
 | 
					    let
 | 
				
			||||||
 | 
					      inherit (lib) concatStringsSep mkMerge mkIf mkForce;
 | 
				
			||||||
 | 
					      inherit (lib.my) networkdAssignment;
 | 
				
			||||||
 | 
					    in
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      config = {
 | 
				
			||||||
 | 
					        my = {
 | 
				
			||||||
 | 
					          deploy.enable = false;
 | 
				
			||||||
 | 
					          server.enable = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          secrets = {
 | 
				
			||||||
 | 
					            key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICZc88lcSQ9zzQzDITdE/T5ty++TxFQUAED7p9YfFBiR";
 | 
				
			||||||
 | 
					            files = {
 | 
				
			||||||
 | 
					              "tailscale-auth.key" = {};
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          firewall = {
 | 
				
			||||||
 | 
					            trustedInterfaces = [ "tailscale0" ];
 | 
				
			||||||
 | 
					            extraRules = ''
 | 
				
			||||||
 | 
					              table inet filter {
 | 
				
			||||||
 | 
					                chain forward {
 | 
				
			||||||
 | 
					                  iifname host0 oifname tailscale0 ip saddr ${prefixes.all.v4} accept
 | 
				
			||||||
 | 
					                  iifname host0 oifname tailscale0 ip6 saddr ${prefixes.all.v6} accept
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              table inet nat {
 | 
				
			||||||
 | 
					                chain postrouting {
 | 
				
			||||||
 | 
					                  iifname tailscale0 ip daddr != ${prefixes.all.v4} snat to ${assignments.internal.ipv4.address}
 | 
				
			||||||
 | 
					                  iifname tailscale0 ip6 daddr != ${prefixes.all.v6} snat ip6 to ${assignments.internal.ipv6.address}
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            '';
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        systemd = {
 | 
				
			||||||
 | 
					          network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        services = {
 | 
				
			||||||
 | 
					          tailscale =
 | 
				
			||||||
 | 
					          let
 | 
				
			||||||
 | 
					            advRoutes = concatStringsSep "," (with prefixes.all; [ v4 v6 ]);
 | 
				
			||||||
 | 
					          in
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            enable = true;
 | 
				
			||||||
 | 
					            authKeyFile = config.age.secrets."tailscale-auth.key".path;
 | 
				
			||||||
 | 
					            port = 41641;
 | 
				
			||||||
 | 
					            openFirewall = true;
 | 
				
			||||||
 | 
					            interfaceName = "tailscale0";
 | 
				
			||||||
 | 
					            extraUpFlags = [
 | 
				
			||||||
 | 
					              "--operator=${config.my.user.config.name}"
 | 
				
			||||||
 | 
					              "--login-server=https://ts.nul.ie"
 | 
				
			||||||
 | 
					              "--netfilter-mode=off"
 | 
				
			||||||
 | 
					              "--advertise-exit-node"
 | 
				
			||||||
 | 
					              "--advertise-routes=${advRoutes}"
 | 
				
			||||||
 | 
					              "--accept-routes=false"
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
{ lib, ... }:
 | 
					{ lib, ... }:
 | 
				
			||||||
let
 | 
					let
 | 
				
			||||||
  inherit (lib.my) net;
 | 
					  inherit (lib.my) net nft;
 | 
				
			||||||
  inherit (lib.my.c.colony) domain prefixes;
 | 
					  inherit (lib.my.c.colony) domain prefixes firewallForwards;
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  imports = [ ./containers ];
 | 
					  imports = [ ./containers ];
 | 
				
			||||||
@@ -49,7 +49,7 @@ in
 | 
				
			|||||||
        inherit (lib.my) networkdAssignment;
 | 
					        inherit (lib.my) networkdAssignment;
 | 
				
			||||||
      in
 | 
					      in
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        imports = [ "${modulesPath}/profiles/qemu-guest.nix" ./gitea.nix ];
 | 
					        imports = [ "${modulesPath}/profiles/qemu-guest.nix" ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        config = mkMerge [
 | 
					        config = mkMerge [
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
@@ -81,6 +81,7 @@ in
 | 
				
			|||||||
                fsType = "ext4";
 | 
					                fsType = "ext4";
 | 
				
			||||||
                neededForBoot = true;
 | 
					                neededForBoot = true;
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              "/mnt/media" = {
 | 
					              "/mnt/media" = {
 | 
				
			||||||
                device = "/dev/disk/by-label/media";
 | 
					                device = "/dev/disk/by-label/media";
 | 
				
			||||||
                fsType = "ext4";
 | 
					                fsType = "ext4";
 | 
				
			||||||
@@ -89,6 +90,10 @@ in
 | 
				
			|||||||
                device = "/dev/disk/by-label/minio";
 | 
					                device = "/dev/disk/by-label/minio";
 | 
				
			||||||
                fsType = "xfs";
 | 
					                fsType = "xfs";
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
 | 
					              "/mnt/atticd" = {
 | 
				
			||||||
 | 
					                device = "/dev/disk/by-label/atticd";
 | 
				
			||||||
 | 
					                fsType = "ext4";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            nix.settings = {
 | 
					            nix.settings = {
 | 
				
			||||||
@@ -134,6 +139,16 @@ in
 | 
				
			|||||||
                        ipv6PrefixConfig.Prefix = prefixes.ctrs.v6;
 | 
					                        ipv6PrefixConfig.Prefix = prefixes.ctrs.v6;
 | 
				
			||||||
                      }
 | 
					                      }
 | 
				
			||||||
                    ];
 | 
					                    ];
 | 
				
			||||||
 | 
					                    routes = map (r: { routeConfig = r; }) [
 | 
				
			||||||
 | 
					                      {
 | 
				
			||||||
 | 
					                        Destination = lib.my.c.tailscale.prefix.v4;
 | 
				
			||||||
 | 
					                        Gateway = allAssignments.waffletail.internal.ipv4.address;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                      {
 | 
				
			||||||
 | 
					                        Destination = lib.my.c.tailscale.prefix.v6;
 | 
				
			||||||
 | 
					                        Gateway = allAssignments.waffletail.internal.ipv6.address;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                    ];
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
                ];
 | 
					                ];
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
@@ -146,6 +161,7 @@ in
 | 
				
			|||||||
              firewall = {
 | 
					              firewall = {
 | 
				
			||||||
                tcp.allowed = [ 19999 ];
 | 
					                tcp.allowed = [ 19999 ];
 | 
				
			||||||
                trustedInterfaces = [ "ctrs" ];
 | 
					                trustedInterfaces = [ "ctrs" ];
 | 
				
			||||||
 | 
					                nat.forwardPorts."${allAssignments.estuary.internal.ipv4.address}" = firewallForwards allAssignments;
 | 
				
			||||||
                extraRules = ''
 | 
					                extraRules = ''
 | 
				
			||||||
                  table inet filter {
 | 
					                  table inet filter {
 | 
				
			||||||
                    chain forward {
 | 
					                    chain forward {
 | 
				
			||||||
@@ -153,6 +169,17 @@ in
 | 
				
			|||||||
                      iifname vms oifname ctrs accept
 | 
					                      iifname vms oifname ctrs accept
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                  }
 | 
					                  }
 | 
				
			||||||
 | 
					                  table inet nat {
 | 
				
			||||||
 | 
					                    # Hack to fix our NAT situation with internal routing
 | 
				
			||||||
 | 
					                    # We need to snat to our public IP, otherwise on the return path from e.g. middleman it will
 | 
				
			||||||
 | 
					                    # try to forward packet directly with its own IP, bypassing our carefully crafted DNAT...
 | 
				
			||||||
 | 
					                    chain ${nft.dnatChain allAssignments.estuary.internal.ipv4.address} {
 | 
				
			||||||
 | 
					                      ct mark set 0x1337
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    chain postrouting {
 | 
				
			||||||
 | 
					                      ct mark 0x1337 snat ip to ${assignments.internal.ipv4.address}
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
                '';
 | 
					                '';
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -175,9 +202,11 @@ in
 | 
				
			|||||||
                  object = {
 | 
					                  object = {
 | 
				
			||||||
                    bindMounts = {
 | 
					                    bindMounts = {
 | 
				
			||||||
                      "/mnt/minio".readOnly = false;
 | 
					                      "/mnt/minio".readOnly = false;
 | 
				
			||||||
 | 
					                      "/mnt/atticd".readOnly = false;
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
                  };
 | 
					                  };
 | 
				
			||||||
                  toot = {};
 | 
					                  toot = {};
 | 
				
			||||||
 | 
					                  waffletail = {};
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
              in
 | 
					              in
 | 
				
			||||||
              mkMerge [
 | 
					              mkMerge [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,6 +50,8 @@ in
 | 
				
			|||||||
      };
 | 
					      };
 | 
				
			||||||
    }) {
 | 
					    }) {
 | 
				
			||||||
      valheim-oci = 2;
 | 
					      valheim-oci = 2;
 | 
				
			||||||
 | 
					      simpcraft-oci = 3;
 | 
				
			||||||
 | 
					      simpcraft-staging-oci = 4;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
 | 
					    configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
 | 
				
			||||||
@@ -63,7 +65,7 @@ in
 | 
				
			|||||||
          "${modulesPath}/profiles/qemu-guest.nix"
 | 
					          "${modulesPath}/profiles/qemu-guest.nix"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          ./valheim.nix
 | 
					          ./valheim.nix
 | 
				
			||||||
          ./gitea-actions.nix
 | 
					          ./minecraft
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        config = mkMerge [
 | 
					        config = mkMerge [
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										121
									
								
								nixos/boxes/colony/vms/whale2/minecraft/default.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								nixos/boxes/colony/vms/whale2/minecraft/default.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					{ lib, pkgs, config, allAssignments, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib) concatStringsSep;
 | 
				
			||||||
 | 
					  inherit (lib.my) dockerNetAssignment;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # devplayer0
 | 
				
			||||||
 | 
					  op = "6d7d971b-ce10-435b-85c5-c99c0d8d288c";
 | 
				
			||||||
 | 
					  whitelist = concatStringsSep "," [
 | 
				
			||||||
 | 
					    op
 | 
				
			||||||
 | 
					    "dcd2ecb9-2b5e-49cb-9d4f-f5a76162df56" # Elderlypug
 | 
				
			||||||
 | 
					    "fcb26db2-c3ce-41aa-b588-efec79d37a8a" # Jesthral_
 | 
				
			||||||
 | 
					    "1d366062-12c0-4e29-aba7-6ab5d8c6bb05" # shr3kas0ras
 | 
				
			||||||
 | 
					    "703b378a-09f9-4c1d-9876-1c9305728c49" # OROURKEIRE
 | 
				
			||||||
 | 
					    "f105bbe6-eda6-4a13-a8cf-894e77cab77b" # Adzerq
 | 
				
			||||||
 | 
					    "1fc94979-41fb-497a-81e9-34ae24ca537a" # johnnyscrims
 | 
				
			||||||
 | 
					    "d53c91df-b6e6-4463-b106-e8427d7a8d01" # BossLonus
 | 
				
			||||||
 | 
					    "f439f64d-91c9-4c74-9ce5-df4d24cd8e05" # hynge_
 | 
				
			||||||
 | 
					    "d6ec4c91-5da2-44eb-b89d-71dc8fe017a0" # Eefah98
 | 
				
			||||||
 | 
					    "096a7348-fabe-4b2d-93fc-fd1fd5608fb0" # ToTheMoonStar
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fastback = {
 | 
				
			||||||
 | 
					    gitConfig = pkgs.writeText "git-config" ''
 | 
				
			||||||
 | 
					      [user]
 | 
				
			||||||
 | 
					      	email = "simpcraft@nul.ie"
 | 
				
			||||||
 | 
					      	name = "Simpcraft bot"
 | 
				
			||||||
 | 
					    '';
 | 
				
			||||||
 | 
					    knownHosts = pkgs.writeText "known_hosts" ''
 | 
				
			||||||
 | 
					      git.nul.ie ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBD023ECzYmLeXIpcGVaciPjq6UN/Sjmsys5HP/Nei5GkrUZqPa3OJ2uSXKLUSKGYdeNhxaFTPJe8Yx3TsZxMme8=
 | 
				
			||||||
 | 
					    '';
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  config = {
 | 
				
			||||||
 | 
					    virtualisation.oci-containers.containers = {
 | 
				
			||||||
 | 
					      simpcraft = {
 | 
				
			||||||
 | 
					        image = "ghcr.io/itzg/minecraft-server:2023.12.2-java17-alpine";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        environment = {
 | 
				
			||||||
 | 
					          TYPE = "MODRINTH";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          EULA = "true";
 | 
				
			||||||
 | 
					          ENABLE_QUERY = "true";
 | 
				
			||||||
 | 
					          MOTD = "§4§k----- §9S§ai§bm§cp§dc§er§fa§6f§5t §4§k-----";
 | 
				
			||||||
 | 
					          ICON = "/ext/icon.png";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          EXISTING_WHITELIST_FILE = "SYNCHRONIZE";
 | 
				
			||||||
 | 
					          WHITELIST = whitelist;
 | 
				
			||||||
 | 
					          EXISTING_OPS_FILE = "SYNCHRONIZE";
 | 
				
			||||||
 | 
					          OPS = op;
 | 
				
			||||||
 | 
					          DIFFICULTY = "normal";
 | 
				
			||||||
 | 
					          SPAWN_PROTECTION = "0";
 | 
				
			||||||
 | 
					          VIEW_DISTANCE = "20";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          MAX_MEMORY = "6G";
 | 
				
			||||||
 | 
					          MODRINTH_MODPACK = "https://cdn.modrinth.com/data/CIYf3Hk8/versions/cdj2bSKg/Simpcraft-0.1.2.mrpack";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          TZ = "Europe/Dublin";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        volumes = [
 | 
				
			||||||
 | 
					          "minecraft_data:/data"
 | 
				
			||||||
 | 
					          "${./icon.png}:/ext/icon.png:ro"
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        extraOptions = [
 | 
				
			||||||
 | 
					          ''--network=colony:${dockerNetAssignment allAssignments "simpcraft-oci"}''
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      simpcraft-staging = {
 | 
				
			||||||
 | 
					        image = "git.nul.ie/dev/craftblock:2024.1.0-java17-alpine";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        environment = {
 | 
				
			||||||
 | 
					          TYPE = "MODRINTH";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          EULA = "true";
 | 
				
			||||||
 | 
					          ENABLE_QUERY = "true";
 | 
				
			||||||
 | 
					          ENABLE_RCON = "true";
 | 
				
			||||||
 | 
					          MOTD = "§4§k----- §9S§ai§bm§cp§dc§er§fa§6f§5t [staging] §4§k-----";
 | 
				
			||||||
 | 
					          ICON = "/ext/icon.png";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          EXISTING_WHITELIST_FILE = "SYNCHRONIZE";
 | 
				
			||||||
 | 
					          WHITELIST = whitelist;
 | 
				
			||||||
 | 
					          EXISTING_OPS_FILE = "SYNCHRONIZE";
 | 
				
			||||||
 | 
					          OPS = op;
 | 
				
			||||||
 | 
					          DIFFICULTY = "normal";
 | 
				
			||||||
 | 
					          SPAWN_PROTECTION = "0";
 | 
				
			||||||
 | 
					          VIEW_DISTANCE = "20";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          MAX_MEMORY = "4G";
 | 
				
			||||||
 | 
					          MODRINTH_MODPACK = "https://cdn.modrinth.com/data/CIYf3Hk8/versions/Ym3sIi6H/Simpcraft-0.2.0.mrpack";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          TZ = "Europe/Dublin";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        environmentFiles = [ config.age.secrets."whale2/simpcraft.env".path ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        volumes = [
 | 
				
			||||||
 | 
					          "minecraft_staging_data:/data"
 | 
				
			||||||
 | 
					          "${./icon.png}:/ext/icon.png:ro"
 | 
				
			||||||
 | 
					          "${fastback.gitConfig}:/data/.config/git/config:ro"
 | 
				
			||||||
 | 
					          "${fastback.knownHosts}:/data/.ssh/known_hosts:ro"
 | 
				
			||||||
 | 
					          "${config.age.secrets."whale2/simpcraft-git.key".path}:/data/.ssh/id_rsa"
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        extraOptions = [
 | 
				
			||||||
 | 
					          ''--network=colony:${dockerNetAssignment allAssignments "simpcraft-staging-oci"}''
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    my = {
 | 
				
			||||||
 | 
					      secrets.files = {
 | 
				
			||||||
 | 
					        "whale2/simpcraft.env" = {};
 | 
				
			||||||
 | 
					        "whale2/simpcraft-git.key" = {
 | 
				
			||||||
 | 
					          owner = "1000";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								nixos/boxes/colony/vms/whale2/minecraft/icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								nixos/boxes/colony/vms/whale2/minecraft/icon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 5.4 KiB  | 
							
								
								
									
										220
									
								
								nixos/boxes/home/palace/default.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								nixos/boxes/home/palace/default.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,220 @@
 | 
				
			|||||||
 | 
					{ lib, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib.my) net mkVLAN;
 | 
				
			||||||
 | 
					  inherit (lib.my.c) pubDomain;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.home) domain vlans prefixes vips hiMTU;
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  imports = [ ./vms ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  nixos.systems.palace = {
 | 
				
			||||||
 | 
					    system = "x86_64-linux";
 | 
				
			||||||
 | 
					    nixpkgs = "mine-stable";
 | 
				
			||||||
 | 
					    home-manager = "mine-stable";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assignments = {
 | 
				
			||||||
 | 
					      hi = {
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        mtu = hiMTU;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host 22 prefixes.hi.v4;
 | 
				
			||||||
 | 
					          mask = 22;
 | 
				
			||||||
 | 
					          gateway = vips.hi.v4;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6 = {
 | 
				
			||||||
 | 
					          iid = "::2:1";
 | 
				
			||||||
 | 
					          address = net.cidr.host (65536*2+1) prefixes.hi.v6;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      core = {
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        name = "palace-core";
 | 
				
			||||||
 | 
					        mtu = 1500;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host 20 prefixes.core.v4;
 | 
				
			||||||
 | 
					          gateway = null;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    configuration = { lib, pkgs, modulesPath, config, systems, assignments, allAssignments, ... }:
 | 
				
			||||||
 | 
					      let
 | 
				
			||||||
 | 
					        inherit (lib) mkForce mkMerge;
 | 
				
			||||||
 | 
					        inherit (lib.my) networkdAssignment;
 | 
				
			||||||
 | 
					        inherit (lib.my.c) networkd;
 | 
				
			||||||
 | 
					      in
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        boot = {
 | 
				
			||||||
 | 
					          kernelPackages = (lib.my.c.kernel.lts pkgs).extend (self: super: {
 | 
				
			||||||
 | 
					            kernel = super.kernel.override {
 | 
				
			||||||
 | 
					              structuredExtraConfig = with lib.kernel; {
 | 
				
			||||||
 | 
					                ACPI_APEI_PCIEAER = yes;
 | 
				
			||||||
 | 
					                PCIEAER = yes;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          kernelModules = [ "kvm-amd" ];
 | 
				
			||||||
 | 
					          kernelParams = [ "amd_iommu=on" ];
 | 
				
			||||||
 | 
					          initrd = {
 | 
				
			||||||
 | 
					            availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hardware = {
 | 
				
			||||||
 | 
					          enableRedistributableFirmware = true;
 | 
				
			||||||
 | 
					          cpu = {
 | 
				
			||||||
 | 
					            amd.updateMicrocode = true;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fileSystems = {
 | 
				
			||||||
 | 
					          "/boot" = {
 | 
				
			||||||
 | 
					            device = "/dev/disk/by-partuuid/c06a8d24-2af9-4416-bf5e-cfe6defdbd47";
 | 
				
			||||||
 | 
					            fsType = "vfat";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          "/nix" = {
 | 
				
			||||||
 | 
					            device = "/dev/disk/by-uuid/450e1f72-238a-4160-98b8-b5e6d0d6fdf6";
 | 
				
			||||||
 | 
					            fsType = "ext4";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          "/persist" = {
 | 
				
			||||||
 | 
					            device = "/dev/disk/by-uuid/9d6d53a8-dff8-49e0-9bc3-fb5f7c6760d0";
 | 
				
			||||||
 | 
					            fsType = "ext4";
 | 
				
			||||||
 | 
					            neededForBoot = true;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        services = {
 | 
				
			||||||
 | 
					          lvm = {
 | 
				
			||||||
 | 
					            boot.thin.enable = true;
 | 
				
			||||||
 | 
					            dmeventd.enable = true;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          smartd = {
 | 
				
			||||||
 | 
					            enable = true;
 | 
				
			||||||
 | 
					            autodetect = true;
 | 
				
			||||||
 | 
					            extraOptions = [ "-A /var/log/smartd/" "--interval=600" ];
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          udev.extraRules = ''
 | 
				
			||||||
 | 
					            ACTION=="add", SUBSYSTEM=="net", ENV{ID_NET_DRIVER}=="mlx5_core", ENV{ID_PATH}=="pci-0000:44:00.0", ATTR{device/sriov_numvfs}="3"
 | 
				
			||||||
 | 
					          '';
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        environment.systemPackages = with pkgs; [
 | 
				
			||||||
 | 
					          pciutils
 | 
				
			||||||
 | 
					          usbutils
 | 
				
			||||||
 | 
					          partclone
 | 
				
			||||||
 | 
					          lm_sensors
 | 
				
			||||||
 | 
					          linuxPackages.cpupower
 | 
				
			||||||
 | 
					          smartmontools
 | 
				
			||||||
 | 
					          mstflint
 | 
				
			||||||
 | 
					          ethtool
 | 
				
			||||||
 | 
					          hwloc
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        networking = { inherit domain; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        systemd = {
 | 
				
			||||||
 | 
					          tmpfiles.rules = [
 | 
				
			||||||
 | 
					            "d /var/log/smartd 0755 root root"
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          network = {
 | 
				
			||||||
 | 
					            links = {
 | 
				
			||||||
 | 
					              "10-et1g0" = {
 | 
				
			||||||
 | 
					                matchConfig = {
 | 
				
			||||||
 | 
					                  PermanentMACAddress = "e0:d5:5e:68:0c:6e";
 | 
				
			||||||
 | 
					                  Driver = "igb";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                linkConfig.Name = "et1g0";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              "10-lan-core" = {
 | 
				
			||||||
 | 
					                matchConfig.PermanentMACAddress = "e0:d5:5e:68:0c:70";
 | 
				
			||||||
 | 
					                linkConfig.Name = "lan-core";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              "10-et100g" = {
 | 
				
			||||||
 | 
					                matchConfig = {
 | 
				
			||||||
 | 
					                  PermanentMACAddress = "24:8a:07:ac:59:c0";
 | 
				
			||||||
 | 
					                  Driver = "mlx5_core";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                linkConfig = {
 | 
				
			||||||
 | 
					                  Name = "et100g";
 | 
				
			||||||
 | 
					                  MTUBytes = toString hiMTU;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            netdevs = mkMerge [
 | 
				
			||||||
 | 
					              (mkVLAN "lan-hi" vlans.hi)
 | 
				
			||||||
 | 
					              (mkVLAN "lan-lo-phy" vlans.lo)
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "25-lan-lo".netdevConfig = {
 | 
				
			||||||
 | 
					                  Name = "lan-lo";
 | 
				
			||||||
 | 
					                  Kind = "bridge";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            networks = {
 | 
				
			||||||
 | 
					              "50-lan-core" = mkMerge [
 | 
				
			||||||
 | 
					                (networkdAssignment "lan-core" assignments.core)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  matchConfig.Name = "lan-core";
 | 
				
			||||||
 | 
					                  vlan = [ "lan-lo-phy" ];
 | 
				
			||||||
 | 
					                  networkConfig.IPv6AcceptRA = mkForce false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              "50-et100g" = {
 | 
				
			||||||
 | 
					                matchConfig.Name = "et100g";
 | 
				
			||||||
 | 
					                vlan = [ "lan-hi" ];
 | 
				
			||||||
 | 
					                networkConfig = networkd.noL3;
 | 
				
			||||||
 | 
					                linkConfig.RequiredForOnline = "no";
 | 
				
			||||||
 | 
					                extraConfig = ''
 | 
				
			||||||
 | 
					                  # cellar
 | 
				
			||||||
 | 
					                  [SR-IOV]
 | 
				
			||||||
 | 
					                  VirtualFunction=0
 | 
				
			||||||
 | 
					                  VLANId=${toString vlans.hi}
 | 
				
			||||||
 | 
					                  LinkState=yes
 | 
				
			||||||
 | 
					                  MACAddress=52:54:00:cc:3e:70
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  # river
 | 
				
			||||||
 | 
					                  [SR-IOV]
 | 
				
			||||||
 | 
					                  VirtualFunction=1
 | 
				
			||||||
 | 
					                  LinkState=yes
 | 
				
			||||||
 | 
					                  MACAddress=52:54:00:8a:8a:f2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  # sfh
 | 
				
			||||||
 | 
					                  [SR-IOV]
 | 
				
			||||||
 | 
					                  VirtualFunction=2
 | 
				
			||||||
 | 
					                  VLANId=${toString vlans.hi}
 | 
				
			||||||
 | 
					                  LinkState=yes
 | 
				
			||||||
 | 
					                  MACAddress=52:54:00:ac:15:a9
 | 
				
			||||||
 | 
					                '';
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              "60-lan-hi" = networkdAssignment "lan-hi" assignments.hi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              "50-lan-lo-phy" = {
 | 
				
			||||||
 | 
					                matchConfig.Name = "lan-lo-phy";
 | 
				
			||||||
 | 
					                networkConfig = {
 | 
				
			||||||
 | 
					                  Bridge = "lan-lo";
 | 
				
			||||||
 | 
					                } // networkd.noL3;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              "60-lan-lo" = {
 | 
				
			||||||
 | 
					                matchConfig.Name = "lan-lo";
 | 
				
			||||||
 | 
					                linkConfig.RequiredForOnline = "no";
 | 
				
			||||||
 | 
					                networkConfig = networkd.noL3;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        my = {
 | 
				
			||||||
 | 
					          secrets = {
 | 
				
			||||||
 | 
					            key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHzVJpoDz/AAYLJGzU8t6DgZ2sY3oehRqrlSO7C+GWiK";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          server.enable = true;
 | 
				
			||||||
 | 
					          deploy.node.hostname = "192.168.68.22";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										98
									
								
								nixos/boxes/home/palace/vms/cellar/default.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								nixos/boxes/home/palace/vms/cellar/default.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					{ lib, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
 | 
					  inherit (lib.my.c) pubDomain;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.home) domain prefixes vips hiMTU;
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  nixos.systems.cellar = {
 | 
				
			||||||
 | 
					    system = "x86_64-linux";
 | 
				
			||||||
 | 
					    nixpkgs = "mine";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assignments = {
 | 
				
			||||||
 | 
					      hi = {
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        mtu = hiMTU;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host 80 prefixes.hi.v4;
 | 
				
			||||||
 | 
					          mask = 22;
 | 
				
			||||||
 | 
					          gateway = vips.hi.v4;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6 = {
 | 
				
			||||||
 | 
					          iid = "::4:1";
 | 
				
			||||||
 | 
					          address = net.cidr.host (65536*4+1) prefixes.hi.v6;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
 | 
				
			||||||
 | 
					      let
 | 
				
			||||||
 | 
					        inherit (lib) mkMerge;
 | 
				
			||||||
 | 
					        inherit (lib.my) networkdAssignment;
 | 
				
			||||||
 | 
					      in
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        imports = [
 | 
				
			||||||
 | 
					          "${modulesPath}/profiles/qemu-guest.nix"
 | 
				
			||||||
 | 
					          ./spdk.nix
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config = mkMerge [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            boot = {
 | 
				
			||||||
 | 
					              kernelParams = [ "console=ttyS0,115200n8" "intel_iommu=on" ];
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fileSystems = {
 | 
				
			||||||
 | 
					              "/boot" = {
 | 
				
			||||||
 | 
					                device = "/dev/disk/by-partuuid/f7562ee6-34c1-4e94-8ae7-c6e71794d563";
 | 
				
			||||||
 | 
					                fsType = "vfat";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              "/nix" = {
 | 
				
			||||||
 | 
					                device = "/dev/disk/by-uuid/f31f6abd-0832-4014-a761-f3c3126d5739";
 | 
				
			||||||
 | 
					                fsType = "ext4";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              "/persist" = {
 | 
				
			||||||
 | 
					                device = "/dev/disk/by-uuid/620364e3-3a30-4704-be80-8593516e7482";
 | 
				
			||||||
 | 
					                fsType = "ext4";
 | 
				
			||||||
 | 
					                neededForBoot = true;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            networking = { inherit domain; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            environment.systemPackages = with pkgs; [
 | 
				
			||||||
 | 
					              pciutils
 | 
				
			||||||
 | 
					              partclone
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            services = {
 | 
				
			||||||
 | 
					              netdata.enable = true;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            systemd.network = {
 | 
				
			||||||
 | 
					              links = {
 | 
				
			||||||
 | 
					                "10-lan-hi" = {
 | 
				
			||||||
 | 
					                  matchConfig.PermanentMACAddress = "52:54:00:cc:3e:70";
 | 
				
			||||||
 | 
					                  linkConfig.Name = "lan-hi";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              networks = {
 | 
				
			||||||
 | 
					                "80-lan-hi" = networkdAssignment "lan-hi" assignments.hi;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            my = {
 | 
				
			||||||
 | 
					              secrets.key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDcklmJp8xVRddNDU1DruKV+Ipim3Jtl6nE1oCWmpmZH";
 | 
				
			||||||
 | 
					              server.enable = true;
 | 
				
			||||||
 | 
					              deploy.node.hostname = "192.168.68.80";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              firewall = {
 | 
				
			||||||
 | 
					                tcp.allowed = [ 19999 ];
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										137
									
								
								nixos/boxes/home/palace/vms/cellar/spdk.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								nixos/boxes/home/palace/vms/cellar/spdk.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
				
			|||||||
 | 
					{ lib, pkgs, config, assignments, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib) mapAttrsToList;
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  config = {
 | 
				
			||||||
 | 
					    boot.blacklistedKernelModules = [ "nvme" ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    systemd.services = {
 | 
				
			||||||
 | 
					      spdk-tgt.after = [ "systemd-networkd-wait-online@lan-hi.service" ];
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    my = {
 | 
				
			||||||
 | 
					      spdk = {
 | 
				
			||||||
 | 
					        enable = true;
 | 
				
			||||||
 | 
					        extraArgs = "--mem-channels 2 --cpumask 0xffff";
 | 
				
			||||||
 | 
					        debugCommands = ''
 | 
				
			||||||
 | 
					          spdk-rpc bdev_nvme_attach_controller -t pcie -a 02:00.0 -b NVMe0
 | 
				
			||||||
 | 
					          spdk-rpc bdev_nvme_attach_controller -t pcie -a 03:00.0 -b NVMe1
 | 
				
			||||||
 | 
					          spdk-rpc bdev_nvme_attach_controller -t pcie -a 04:00.0 -b NVMe2
 | 
				
			||||||
 | 
					          spdk-rpc bdev_raid_create -n NVMeRaid -z 64 -r 0 -b 'NVMe0n1 NVMe1n1 NVMe2n1'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          spdk-rpc ublk_create_target
 | 
				
			||||||
 | 
					          spdk-rpc ublk_start_disk NVMeRaid 1
 | 
				
			||||||
 | 
					        '';
 | 
				
			||||||
 | 
					        config.subsystems =
 | 
				
			||||||
 | 
					        let
 | 
				
			||||||
 | 
					          nvmeAttaches = mapAttrsToList (name: bdf: {
 | 
				
			||||||
 | 
					            method = "bdev_nvme_attach_controller";
 | 
				
			||||||
 | 
					            params = {
 | 
				
			||||||
 | 
					              hostnqn =
 | 
				
			||||||
 | 
					                "nqn.2014-08.org.nvmexpress:uuid:2b16606f-b82c-49f8-9b20-a589dac8b775";
 | 
				
			||||||
 | 
					              trtype = "PCIe";
 | 
				
			||||||
 | 
					              inherit name;
 | 
				
			||||||
 | 
					              traddr = bdf;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }) {
 | 
				
			||||||
 | 
					            "NVMe0" = "02:00.0";
 | 
				
			||||||
 | 
					            "NVMe1" = "03:00.0";
 | 
				
			||||||
 | 
					            "NVMe2" = "04:00.0";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          nvmfListener = nqn: {
 | 
				
			||||||
 | 
					            method = "nvmf_subsystem_add_listener";
 | 
				
			||||||
 | 
					            params = {
 | 
				
			||||||
 | 
					              inherit nqn;
 | 
				
			||||||
 | 
					              listen_address = {
 | 
				
			||||||
 | 
					                adrfam = "IPv4";
 | 
				
			||||||
 | 
					                traddr = assignments.hi.ipv4.address;
 | 
				
			||||||
 | 
					                trsvcid = "4420";
 | 
				
			||||||
 | 
					                trtype = "RDMA";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              secure_channel = false;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          nvmfBdev = { nqn, hostnqn, bdev, serial }: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              method = "nvmf_create_subsystem";
 | 
				
			||||||
 | 
					              params = {
 | 
				
			||||||
 | 
					                inherit nqn;
 | 
				
			||||||
 | 
					                serial_number = serial;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            (nvmfListener nqn)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              method = "nvmf_subsystem_add_host";
 | 
				
			||||||
 | 
					              params = {
 | 
				
			||||||
 | 
					                inherit nqn;
 | 
				
			||||||
 | 
					                host = hostnqn;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              method = "nvmf_subsystem_add_ns";
 | 
				
			||||||
 | 
					              params = {
 | 
				
			||||||
 | 
					                inherit nqn;
 | 
				
			||||||
 | 
					                namespace = {
 | 
				
			||||||
 | 
					                  bdev_name = bdev;
 | 
				
			||||||
 | 
					                  nsid = 1;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					        in
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          scheduler = [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              method = "framework_set_scheduler";
 | 
				
			||||||
 | 
					              params.name = "dynamic";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          bdev = [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              method = "bdev_set_options";
 | 
				
			||||||
 | 
					              params.bdev_auto_examine = false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ] ++ nvmeAttaches ++ [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              method = "bdev_raid_create";
 | 
				
			||||||
 | 
					              params = {
 | 
				
			||||||
 | 
					                base_bdevs = [ "NVMe0n1" "NVMe1n1" "NVMe2n1" ];
 | 
				
			||||||
 | 
					                name = "NVMeRaid";
 | 
				
			||||||
 | 
					                raid_level = "raid0";
 | 
				
			||||||
 | 
					                strip_size_kb = 64;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              method = "bdev_examine";
 | 
				
			||||||
 | 
					              params.name = "NVMeRaid";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            { method = "bdev_wait_for_examine"; }
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          nvmf = [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              method = "nvmf_create_transport";
 | 
				
			||||||
 | 
					              params.trtype = "RDMA";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            (nvmfListener "nqn.2014-08.org.nvmexpress.discovery")
 | 
				
			||||||
 | 
					          ] ++ (nvmfBdev {
 | 
				
			||||||
 | 
					            bdev = "NVMeRaidp1";
 | 
				
			||||||
 | 
					            nqn = "nqn.2016-06.io.spdk:river";
 | 
				
			||||||
 | 
					            hostnqn =
 | 
				
			||||||
 | 
					              "nqn.2014-08.org.nvmexpress:uuid:12b52d80-ccb6-418d-9b2e-2be34bff3cd9";
 | 
				
			||||||
 | 
					            serial = "SPDK00000000000001";
 | 
				
			||||||
 | 
					          }) ++ (nvmfBdev {
 | 
				
			||||||
 | 
					            bdev = "NVMeRaidp2";
 | 
				
			||||||
 | 
					            nqn = "nqn.2016-06.io.spdk:castle";
 | 
				
			||||||
 | 
					            hostnqn =
 | 
				
			||||||
 | 
					              "nqn.2014-08.org.nvmexpress:uuid:2230b066-a674-4f45-a1dc-f7727b3a9e7b";
 | 
				
			||||||
 | 
					            serial = "SPDK00000000000002";
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										191
									
								
								nixos/boxes/home/palace/vms/default.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								nixos/boxes/home/palace/vms/default.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  imports = [
 | 
				
			||||||
 | 
					    ./cellar
 | 
				
			||||||
 | 
					    ./river.nix
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  nixos.systems.palace.configuration = { lib, pkgs, config, systems, allAssignments, ... }:
 | 
				
			||||||
 | 
					  let
 | 
				
			||||||
 | 
					    inherit (lib) mkMerge;
 | 
				
			||||||
 | 
					    inherit (lib.my) vm;
 | 
				
			||||||
 | 
					    inherit (lib.my.c) networkd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    installerDisk = {
 | 
				
			||||||
 | 
					      name = "installer";
 | 
				
			||||||
 | 
					      backend = {
 | 
				
			||||||
 | 
					        driver = "file";
 | 
				
			||||||
 | 
					        filename = "/persist/home/dev/nixos-installer-devplayer0.iso";
 | 
				
			||||||
 | 
					        read-only = "on";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      format.driver = "raw";
 | 
				
			||||||
 | 
					      frontend = "ide-cd";
 | 
				
			||||||
 | 
					      frontendOpts = {
 | 
				
			||||||
 | 
					        bootindex = 1;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  in
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    systemd.network = {
 | 
				
			||||||
 | 
					      netdevs = {
 | 
				
			||||||
 | 
					        "25-vm-et1g0" = {
 | 
				
			||||||
 | 
					           netdevConfig = {
 | 
				
			||||||
 | 
					             Name = "vm-et1g0";
 | 
				
			||||||
 | 
					             Kind = "macvtap";
 | 
				
			||||||
 | 
					           };
 | 
				
			||||||
 | 
					           # TODO: Upstream this missing section
 | 
				
			||||||
 | 
					           extraConfig = ''
 | 
				
			||||||
 | 
					             [MACVTAP]
 | 
				
			||||||
 | 
					             Mode=passthru
 | 
				
			||||||
 | 
					           '';
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      networks = {
 | 
				
			||||||
 | 
					        "75-et1g0" = {
 | 
				
			||||||
 | 
					          matchConfig.Name = "et1g0";
 | 
				
			||||||
 | 
					          linkConfig.RequiredForOnline = "no";
 | 
				
			||||||
 | 
					          networkConfig = {
 | 
				
			||||||
 | 
					            MACVTAP = "vm-et1g0";
 | 
				
			||||||
 | 
					          } // networkd.noL3;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        "75-vm-et1g0" = {
 | 
				
			||||||
 | 
					          matchConfig.Name = "vm-et1g0";
 | 
				
			||||||
 | 
					          linkConfig.RequiredForOnline = "no";
 | 
				
			||||||
 | 
					          networkConfig = networkd.noL3;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    systemd.services =
 | 
				
			||||||
 | 
					    let
 | 
				
			||||||
 | 
					      awaitCellar = {
 | 
				
			||||||
 | 
					        after = [ "vm@cellar.service" ];
 | 
				
			||||||
 | 
					        bindsTo = [ "vm@cellar.service" ];
 | 
				
			||||||
 | 
					        preStart = ''
 | 
				
			||||||
 | 
					          until ${pkgs.netcat}/bin/nc -w1 -z ${allAssignments.cellar.hi.ipv4.address} 22; do
 | 
				
			||||||
 | 
					            sleep 1
 | 
				
			||||||
 | 
					          done
 | 
				
			||||||
 | 
					        '';
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    in
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "vm@cellar" = {
 | 
				
			||||||
 | 
					        serviceConfig = {
 | 
				
			||||||
 | 
					          CPUAffinity = "numa";
 | 
				
			||||||
 | 
					          NUMAPolicy = "bind";
 | 
				
			||||||
 | 
					          NUMAMask = "1";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      "vm@river" =
 | 
				
			||||||
 | 
					      let
 | 
				
			||||||
 | 
					        vtapUnit = "sys-subsystem-net-devices-vm\\x2det1g0.device";
 | 
				
			||||||
 | 
					      in
 | 
				
			||||||
 | 
					      mkMerge [
 | 
				
			||||||
 | 
					        awaitCellar
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          requires = [ vtapUnit ];
 | 
				
			||||||
 | 
					          after = [ vtapUnit ];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					      "vm@sfh" = awaitCellar;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    my = {
 | 
				
			||||||
 | 
					      vms = {
 | 
				
			||||||
 | 
					        instances = {
 | 
				
			||||||
 | 
					          cellar = {
 | 
				
			||||||
 | 
					            uuid = "b126d135-9fc1-415a-b675-aaf727bf2f38";
 | 
				
			||||||
 | 
					            cpu = "host,topoext";
 | 
				
			||||||
 | 
					            smp = {
 | 
				
			||||||
 | 
					              cpus = 8;
 | 
				
			||||||
 | 
					              threads = 2;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            memory = 16384;
 | 
				
			||||||
 | 
					            cleanShutdown.timeout = 120;
 | 
				
			||||||
 | 
					            drives = [
 | 
				
			||||||
 | 
					              (mkMerge [ (vm.disk "cellar" "esp") { frontendOpts.bootindex = 0; } ])
 | 
				
			||||||
 | 
					              (vm.disk "cellar" "nix")
 | 
				
			||||||
 | 
					              (vm.disk "cellar" "persist")
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					            hostDevices = {
 | 
				
			||||||
 | 
					              et100g0vf0 = {
 | 
				
			||||||
 | 
					                index = 0;
 | 
				
			||||||
 | 
					                hostBDF = "44:00.1";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              nvme0 = {
 | 
				
			||||||
 | 
					                index = 1;
 | 
				
			||||||
 | 
					                hostBDF = "41:00.0";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              nvme1 = {
 | 
				
			||||||
 | 
					                index = 2;
 | 
				
			||||||
 | 
					                hostBDF = "42:00.0";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              nvme2 = {
 | 
				
			||||||
 | 
					                index = 3;
 | 
				
			||||||
 | 
					                hostBDF = "43:00.0";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            qemuFlags = [
 | 
				
			||||||
 | 
					              "machine kernel-irqchip=split"
 | 
				
			||||||
 | 
					              "device intel-iommu,caching-mode=on,device-iotlb=on,intremap=on"
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          river = {
 | 
				
			||||||
 | 
					            uuid = "12b52d80-ccb6-418d-9b2e-2be34bff3cd9";
 | 
				
			||||||
 | 
					            cpu = "host,topoext";
 | 
				
			||||||
 | 
					            smp = {
 | 
				
			||||||
 | 
					              cpus = 3;
 | 
				
			||||||
 | 
					              threads = 2;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            memory = 4096;
 | 
				
			||||||
 | 
					            cleanShutdown.timeout = 60;
 | 
				
			||||||
 | 
					            networks = {
 | 
				
			||||||
 | 
					              et1g0 = {
 | 
				
			||||||
 | 
					                ifname = "vm-et1g0";
 | 
				
			||||||
 | 
					                bridge = null;
 | 
				
			||||||
 | 
					                tapFD = 100;
 | 
				
			||||||
 | 
					                # Real hardware MAC
 | 
				
			||||||
 | 
					                mac = "e0:d5:5e:68:0c:6e";
 | 
				
			||||||
 | 
					                waitOnline = false;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            drives = [
 | 
				
			||||||
 | 
					              installerDisk
 | 
				
			||||||
 | 
					              (mkMerge [ (vm.disk "river" "esp") { frontendOpts.bootindex = 0; } ])
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					            hostDevices = {
 | 
				
			||||||
 | 
					              et100g0vf1 = {
 | 
				
			||||||
 | 
					                index = 0;
 | 
				
			||||||
 | 
					                hostBDF = "44:00.2";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          sfh = {
 | 
				
			||||||
 | 
					            uuid = "82ec149d-577c-421a-93e2-a9307c756cd8";
 | 
				
			||||||
 | 
					            cpu = "host,topoext";
 | 
				
			||||||
 | 
					            smp = {
 | 
				
			||||||
 | 
					              cpus = 8;
 | 
				
			||||||
 | 
					              threads = 2;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            memory = 32768;
 | 
				
			||||||
 | 
					            cleanShutdown.timeout = 120;
 | 
				
			||||||
 | 
					            networks.netboot = {
 | 
				
			||||||
 | 
					              bridge = "lan-lo";
 | 
				
			||||||
 | 
					              waitOnline = "carrier";
 | 
				
			||||||
 | 
					              mac = "52:54:00:a5:7e:93";
 | 
				
			||||||
 | 
					              extraOptions.bootindex = 1;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            hostDevices = {
 | 
				
			||||||
 | 
					              et100g0vf2 = {
 | 
				
			||||||
 | 
					                index = 0;
 | 
				
			||||||
 | 
					                hostBDF = "44:00.3";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										142
									
								
								nixos/boxes/home/palace/vms/river.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								nixos/boxes/home/palace/vms/river.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,142 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  imports = [ (import ../../routing-common 0) ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  config.nixos.systems.river = {
 | 
				
			||||||
 | 
					    system = "x86_64-linux";
 | 
				
			||||||
 | 
					    nixpkgs = "mine";
 | 
				
			||||||
 | 
					    home-manager = "mine";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    configuration = { lib, modulesPath, pkgs, config, assignments, allAssignments, ... }:
 | 
				
			||||||
 | 
					    let
 | 
				
			||||||
 | 
					      inherit (lib.my) networkdAssignment mkVLAN;
 | 
				
			||||||
 | 
					      inherit (lib.my.c) networkd;
 | 
				
			||||||
 | 
					      inherit (lib.my.c.home) vlans;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      lanLink = {
 | 
				
			||||||
 | 
					        matchConfig = {
 | 
				
			||||||
 | 
					          Driver = "mlx5_core";
 | 
				
			||||||
 | 
					          PermanentMACAddress = "52:54:00:8a:8a:f2";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        linkConfig = {
 | 
				
			||||||
 | 
					          Name = "lan";
 | 
				
			||||||
 | 
					          MTUBytes = toString lib.my.c.home.hiMTU;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    in
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      imports = [
 | 
				
			||||||
 | 
					        "${modulesPath}/profiles/qemu-guest.nix"
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      config = {
 | 
				
			||||||
 | 
					        boot = {
 | 
				
			||||||
 | 
					          kernelModules = [ "kvm-intel" ];
 | 
				
			||||||
 | 
					          kernelParams = [ "console=ttyS0,115200n8" ];
 | 
				
			||||||
 | 
					          initrd = {
 | 
				
			||||||
 | 
					            availableKernelModules = [
 | 
				
			||||||
 | 
					              "virtio_pci" "ahci" "sr_mod" "virtio_blk"
 | 
				
			||||||
 | 
					              "ib_core" "ib_uverbs" "mlx5_core" "mlx5_ib" "8021q"
 | 
				
			||||||
 | 
					              "rdma_cm" "iw_cm" "ib_cm" "nvme_core" "nvme_rdma"
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					            kernelModules = [ "dm-snapshot" "nvme-fabrics" ];
 | 
				
			||||||
 | 
					            systemd = {
 | 
				
			||||||
 | 
					              extraBin = with pkgs; {
 | 
				
			||||||
 | 
					                dmesg = "${util-linux}/bin/dmesg";
 | 
				
			||||||
 | 
					                ip = "${iproute2}/bin/ip";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              extraConfig = ''
 | 
				
			||||||
 | 
					                DefaultTimeoutStartSec=50
 | 
				
			||||||
 | 
					                DefaultDeviceTimeoutSec=50
 | 
				
			||||||
 | 
					              '';
 | 
				
			||||||
 | 
					              network = {
 | 
				
			||||||
 | 
					                enable = true;
 | 
				
			||||||
 | 
					                wait-online.enable = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                links."10-lan" = lanLink;
 | 
				
			||||||
 | 
					                netdevs = mkVLAN "lan-hi" vlans.hi;
 | 
				
			||||||
 | 
					                networks = {
 | 
				
			||||||
 | 
					                  "20-lan" = {
 | 
				
			||||||
 | 
					                    matchConfig.Name = "lan";
 | 
				
			||||||
 | 
					                    vlan = [ "lan-hi" ];
 | 
				
			||||||
 | 
					                    linkConfig.RequiredForOnline = "no";
 | 
				
			||||||
 | 
					                    networkConfig = networkd.noL3;
 | 
				
			||||||
 | 
					                  };
 | 
				
			||||||
 | 
					                  "30-lan-hi" = networkdAssignment "lan-hi" assignments.hi;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hardware = {
 | 
				
			||||||
 | 
					          enableRedistributableFirmware = true;
 | 
				
			||||||
 | 
					          cpu = {
 | 
				
			||||||
 | 
					            intel.updateMicrocode = true;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fileSystems = {
 | 
				
			||||||
 | 
					          "/boot" = {
 | 
				
			||||||
 | 
					            device = "/dev/disk/by-partuuid/3ec6c49e-b485-40cb-8eff-315581ac6fe9";
 | 
				
			||||||
 | 
					            fsType = "vfat";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          "/nix" = {
 | 
				
			||||||
 | 
					            device = "/dev/main/nix";
 | 
				
			||||||
 | 
					            fsType = "ext4";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          "/persist" = {
 | 
				
			||||||
 | 
					            device = "/dev/main/persist";
 | 
				
			||||||
 | 
					            fsType = "ext4";
 | 
				
			||||||
 | 
					            neededForBoot = true;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        services = {
 | 
				
			||||||
 | 
					          lvm = {
 | 
				
			||||||
 | 
					            boot.thin.enable = true;
 | 
				
			||||||
 | 
					            dmeventd.enable = true;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        systemd.network = {
 | 
				
			||||||
 | 
					          links = {
 | 
				
			||||||
 | 
					            "10-wan" = {
 | 
				
			||||||
 | 
					              matchConfig = {
 | 
				
			||||||
 | 
					                # Matching against MAC address seems to break VLAN interfaces
 | 
				
			||||||
 | 
					                # (since they share the same MAC address)
 | 
				
			||||||
 | 
					                Driver = "virtio_net";
 | 
				
			||||||
 | 
					                PermanentMACAddress = "e0:d5:5e:68:0c:6e";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              linkConfig = {
 | 
				
			||||||
 | 
					                Name = "wan";
 | 
				
			||||||
 | 
					                RxBufferSize = 4096;
 | 
				
			||||||
 | 
					                TxBufferSize = 4096;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "10-lan" = lanLink;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          # So we don't drop the IP we use to connect to NVMe-oF!
 | 
				
			||||||
 | 
					          networks."60-lan-hi".networkConfig.KeepConfiguration = "static";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        my = {
 | 
				
			||||||
 | 
					          secrets = {
 | 
				
			||||||
 | 
					            key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP9uFa4z9WPuXRFVA+PClQSitQCSPckhKTxo1Hq585Oa";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          server.enable = true;
 | 
				
			||||||
 | 
					          nvme = {
 | 
				
			||||||
 | 
					            uuid = "12b52d80-ccb6-418d-9b2e-2be34bff3cd9";
 | 
				
			||||||
 | 
					            boot = {
 | 
				
			||||||
 | 
					              nqn = "nqn.2016-06.io.spdk:river";
 | 
				
			||||||
 | 
					              address = "192.168.68.80";
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          deploy.node.hostname = "192.168.68.1";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										384
									
								
								nixos/boxes/home/routing-common/default.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								nixos/boxes/home/routing-common/default.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,384 @@
 | 
				
			|||||||
 | 
					index: { lib, allAssignments, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (builtins) elemAt;
 | 
				
			||||||
 | 
					  inherit (lib.my) net mkVLAN;
 | 
				
			||||||
 | 
					  inherit (lib.my.c) pubDomain;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.home) domain vlans prefixes vips routers routersPubV4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  name = elemAt routers index;
 | 
				
			||||||
 | 
					  otherIndex = 1 - index;
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  nixos.systems."${name}" = {
 | 
				
			||||||
 | 
					    assignments = {
 | 
				
			||||||
 | 
					      modem = {
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host (254 - index) prefixes.modem.v4;
 | 
				
			||||||
 | 
					          gateway = null;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      core = {
 | 
				
			||||||
 | 
					        name = "${name}-core";
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        mtu = 1500;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host (index + 1) prefixes.core.v4;
 | 
				
			||||||
 | 
					          gateway = null;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      hi = {
 | 
				
			||||||
 | 
					        name = "${name}-hi";
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        mtu = 9000;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host (index + 1) prefixes.hi.v4;
 | 
				
			||||||
 | 
					          mask = 22;
 | 
				
			||||||
 | 
					          gateway = null;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6.address = net.cidr.host (index + 1) prefixes.hi.v6;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      lo = {
 | 
				
			||||||
 | 
					        name = "${name}-lo";
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        mtu = 1500;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host (index + 1) prefixes.lo.v4;
 | 
				
			||||||
 | 
					          mask = 21;
 | 
				
			||||||
 | 
					          gateway = null;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6.address = net.cidr.host (index + 1) prefixes.lo.v6;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      untrusted  = {
 | 
				
			||||||
 | 
					        name = "${name}-ut";
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        mtu = 1500;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host (index + 1) prefixes.untrusted.v4;
 | 
				
			||||||
 | 
					          mask = 24;
 | 
				
			||||||
 | 
					          gateway = null;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6.address = net.cidr.host (index + 1) prefixes.untrusted.v6;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      as211024 = {
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host (index + 2) prefixes.as211024.v4;
 | 
				
			||||||
 | 
					          gateway = null;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6 = {
 | 
				
			||||||
 | 
					          address = net.cidr.host ((1*65536*65536*65536) + index + 1) prefixes.as211024.v6;
 | 
				
			||||||
 | 
					          gateway = net.cidr.host ((2*65536*65536*65536) + 1) prefixes.as211024.v6;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    extraAssignments = {
 | 
				
			||||||
 | 
					      router-hi.hi = {
 | 
				
			||||||
 | 
					        name = "router-hi";
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = vips.hi.v4;
 | 
				
			||||||
 | 
					          mask = 22;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6.address = vips.hi.v6;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      router-lo.lo = {
 | 
				
			||||||
 | 
					        name = "router-lo";
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        ipv4 = {
 | 
				
			||||||
 | 
					          address = vips.lo.v4;
 | 
				
			||||||
 | 
					          mask = 21;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        ipv6.address = vips.lo.v6;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      router-ut.untrusted = {
 | 
				
			||||||
 | 
					        name = "router-ut";
 | 
				
			||||||
 | 
					        inherit domain;
 | 
				
			||||||
 | 
					        ipv4.address = vips.untrusted.v4;
 | 
				
			||||||
 | 
					        ipv6.address = vips.untrusted.v6;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    configuration = { lib, pkgs, config, assignments, allAssignments, ... }:
 | 
				
			||||||
 | 
					      let
 | 
				
			||||||
 | 
					        inherit (lib) mkIf mkMerge mkForce;
 | 
				
			||||||
 | 
					        inherit (lib.my) networkdAssignment;
 | 
				
			||||||
 | 
					        inherit (lib.my.c) networkd;
 | 
				
			||||||
 | 
					      in
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        imports = map (m: import m index) [
 | 
				
			||||||
 | 
					          ./keepalived.nix
 | 
				
			||||||
 | 
					          ./dns.nix
 | 
				
			||||||
 | 
					          ./radvd.nix
 | 
				
			||||||
 | 
					          ./kea.nix
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config = {
 | 
				
			||||||
 | 
					          environment = {
 | 
				
			||||||
 | 
					            systemPackages = with pkgs; [
 | 
				
			||||||
 | 
					              ethtool
 | 
				
			||||||
 | 
					              conntrack-tools
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          services = {
 | 
				
			||||||
 | 
					            resolved = {
 | 
				
			||||||
 | 
					              llmnr = "false";
 | 
				
			||||||
 | 
					              extraConfig = ''
 | 
				
			||||||
 | 
					                MulticastDNS=false
 | 
				
			||||||
 | 
					              '';
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            iperf3 = {
 | 
				
			||||||
 | 
					              enable = true;
 | 
				
			||||||
 | 
					              openFirewall = true;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            networkd-dispatcher = {
 | 
				
			||||||
 | 
					              enable = true;
 | 
				
			||||||
 | 
					              rules = {
 | 
				
			||||||
 | 
					                # tc filter hasn't been networkd-ified yet
 | 
				
			||||||
 | 
					                setup-wan-mirror = {
 | 
				
			||||||
 | 
					                  onState = [ "configured" ];
 | 
				
			||||||
 | 
					                  script = ''
 | 
				
			||||||
 | 
					                  #!${pkgs.runtimeShell}
 | 
				
			||||||
 | 
					                  if [ $IFACE = "wan-ifb" ]; then
 | 
				
			||||||
 | 
					                    ${pkgs.iproute2}/bin/tc filter add dev wan parent ffff: matchall action mirred egress redirect dev $IFACE
 | 
				
			||||||
 | 
					                  fi
 | 
				
			||||||
 | 
					                  '';
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          networking.domain = "h.${pubDomain}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          systemd.services = {
 | 
				
			||||||
 | 
					            ipsec =
 | 
				
			||||||
 | 
					            let
 | 
				
			||||||
 | 
					              waitOnline = "systemd-networkd-wait-online@wan.service";
 | 
				
			||||||
 | 
					            in
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              after = [ waitOnline ];
 | 
				
			||||||
 | 
					              requires = [ waitOnline ];
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          systemd.network = {
 | 
				
			||||||
 | 
					            wait-online.enable = false;
 | 
				
			||||||
 | 
					            config = {
 | 
				
			||||||
 | 
					              networkConfig = {
 | 
				
			||||||
 | 
					                ManageForeignRoutes = false;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            netdevs = mkMerge [
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "25-wan-ifb".netdevConfig = {
 | 
				
			||||||
 | 
					                  Name = "wan-ifb";
 | 
				
			||||||
 | 
					                  Kind = "ifb";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                "30-lan-core".netdevConfig = {
 | 
				
			||||||
 | 
					                  Name = "lan-core";
 | 
				
			||||||
 | 
					                  Kind = "macvlan";
 | 
				
			||||||
 | 
					                  MTUBytes = "1500";
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              (mkVLAN "lan-hi" vlans.hi)
 | 
				
			||||||
 | 
					              (mkVLAN "lan-lo" vlans.lo)
 | 
				
			||||||
 | 
					              (mkVLAN "lan-untrusted" vlans.untrusted)
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            networks =
 | 
				
			||||||
 | 
					            let
 | 
				
			||||||
 | 
					              mkVLANConfig = name:
 | 
				
			||||||
 | 
					              let
 | 
				
			||||||
 | 
					                iface = "lan-${name}";
 | 
				
			||||||
 | 
					              in
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "60-${iface}" = mkMerge [
 | 
				
			||||||
 | 
					                  (networkdAssignment iface assignments."${name}")
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    dns = [ "127.0.0.1" "::1" ];
 | 
				
			||||||
 | 
					                    domains = [ config.networking.domain ];
 | 
				
			||||||
 | 
					                    networkConfig.IPv6AcceptRA = mkForce false;
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            in
 | 
				
			||||||
 | 
					            mkMerge [
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "50-wan-ifb" = {
 | 
				
			||||||
 | 
					                  matchConfig.Name = "wan-ifb";
 | 
				
			||||||
 | 
					                  networkConfig = networkd.noL3;
 | 
				
			||||||
 | 
					                  extraConfig = ''
 | 
				
			||||||
 | 
					                    [CAKE]
 | 
				
			||||||
 | 
					                    Bandwidth=235M
 | 
				
			||||||
 | 
					                    RTTSec=10ms
 | 
				
			||||||
 | 
					                    PriorityQueueingPreset=besteffort
 | 
				
			||||||
 | 
					                    # DOCSIS preset
 | 
				
			||||||
 | 
					                    OverheadBytes=18
 | 
				
			||||||
 | 
					                    MPUBytes=64
 | 
				
			||||||
 | 
					                    CompensationMode=none
 | 
				
			||||||
 | 
					                  '';
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                "50-wan" = mkMerge [
 | 
				
			||||||
 | 
					                  (networkdAssignment "wan" assignments.modem)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    matchConfig.Name = "wan";
 | 
				
			||||||
 | 
					                    DHCP = "ipv4";
 | 
				
			||||||
 | 
					                    dns = [ "127.0.0.1" "::1" ];
 | 
				
			||||||
 | 
					                    dhcpV4Config.UseDNS = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    qdiscConfig = {
 | 
				
			||||||
 | 
					                      Parent = "ingress";
 | 
				
			||||||
 | 
					                      Handle = "0xffff";
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    extraConfig = ''
 | 
				
			||||||
 | 
					                      [CAKE]
 | 
				
			||||||
 | 
					                      Parent=root
 | 
				
			||||||
 | 
					                      Bandwidth=24M
 | 
				
			||||||
 | 
					                      RTTSec=1ms
 | 
				
			||||||
 | 
					                    '';
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                "55-lan" = {
 | 
				
			||||||
 | 
					                  matchConfig.Name = "lan";
 | 
				
			||||||
 | 
					                  vlan = [ "lan-hi" "lan-lo" "lan-untrusted" "wan-tunnel" ];
 | 
				
			||||||
 | 
					                  macvlan = [ "lan-core" ];
 | 
				
			||||||
 | 
					                  networkConfig = networkd.noL3;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                "60-lan-core" = mkMerge [
 | 
				
			||||||
 | 
					                  (networkdAssignment "lan-core" assignments.core)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    matchConfig.Name = "lan-core";
 | 
				
			||||||
 | 
					                    networkConfig.IPv6AcceptRA = mkForce false;
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                "90-l2mesh-as211024" = mkMerge [
 | 
				
			||||||
 | 
					                  (networkdAssignment "as211024" assignments.as211024)
 | 
				
			||||||
 | 
					                  {
 | 
				
			||||||
 | 
					                    matchConfig.Name = "as211024";
 | 
				
			||||||
 | 
					                    networkConfig.IPv6AcceptRA = mkForce false;
 | 
				
			||||||
 | 
					                    routes = map (r: { routeConfig = r; }) [
 | 
				
			||||||
 | 
					                      {
 | 
				
			||||||
 | 
					                        Destination = lib.my.c.colony.prefixes.all.v4;
 | 
				
			||||||
 | 
					                        Gateway = allAssignments.estuary.as211024.ipv4.address;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                      {
 | 
				
			||||||
 | 
					                        Destination = lib.my.c.tailscale.prefix.v4;
 | 
				
			||||||
 | 
					                        Gateway = allAssignments.britway.as211024.ipv4.address;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                      {
 | 
				
			||||||
 | 
					                        Destination = lib.my.c.tailscale.prefix.v6;
 | 
				
			||||||
 | 
					                        Gateway = allAssignments.britway.as211024.ipv6.address;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                    ];
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              (mkVLANConfig "hi")
 | 
				
			||||||
 | 
					              (mkVLANConfig "lo")
 | 
				
			||||||
 | 
					              (mkVLANConfig "untrusted")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                "60-lan-hi" = {
 | 
				
			||||||
 | 
					                  routes = map (r: { routeConfig = r; }) [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      Destination = elemAt routersPubV4 otherIndex;
 | 
				
			||||||
 | 
					                      Gateway = net.cidr.host (otherIndex + 1) prefixes.hi.v4;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  ];
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          my = {
 | 
				
			||||||
 | 
					            secrets = {
 | 
				
			||||||
 | 
					              files = {
 | 
				
			||||||
 | 
					                "l2mesh/as211024.key" = {};
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            vpns = {
 | 
				
			||||||
 | 
					              l2.pskFiles = {
 | 
				
			||||||
 | 
					                as211024 = config.age.secrets."l2mesh/as211024.key".path;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            firewall = {
 | 
				
			||||||
 | 
					              trustedInterfaces = [ "lan-hi" "lan-lo" ];
 | 
				
			||||||
 | 
					              udp.allowed = [ 5353 ];
 | 
				
			||||||
 | 
					              tcp.allowed = [ 5353 ];
 | 
				
			||||||
 | 
					              nat = {
 | 
				
			||||||
 | 
					                enable = true;
 | 
				
			||||||
 | 
					                externalInterface = "wan";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              extraRules =
 | 
				
			||||||
 | 
					              let
 | 
				
			||||||
 | 
					                aa = allAssignments;
 | 
				
			||||||
 | 
					              in
 | 
				
			||||||
 | 
					              ''
 | 
				
			||||||
 | 
					                table inet filter {
 | 
				
			||||||
 | 
					                  chain input {
 | 
				
			||||||
 | 
					                    ${lib.my.c.as211024.nftTrust}
 | 
				
			||||||
 | 
					                    iifname base meta l4proto { udp, tcp } th dport domain accept
 | 
				
			||||||
 | 
					                    iifname lan-core meta l4proto vrrp accept
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  chain routing-tcp {
 | 
				
			||||||
 | 
					                    ip daddr {
 | 
				
			||||||
 | 
					                      ${aa.castle.hi.ipv4.address},
 | 
				
			||||||
 | 
					                      ${aa.cellar.hi.ipv4.address},
 | 
				
			||||||
 | 
					                      ${aa.palace.hi.ipv4.address}
 | 
				
			||||||
 | 
					                    } tcp dport ssh accept
 | 
				
			||||||
 | 
					                    ip6 daddr {
 | 
				
			||||||
 | 
					                      ${aa.castle.hi.ipv6.address},
 | 
				
			||||||
 | 
					                      ${aa.cellar.hi.ipv6.address},
 | 
				
			||||||
 | 
					                      ${aa.palace.hi.ipv6.address}
 | 
				
			||||||
 | 
					                    } tcp dport ssh accept
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    return
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  chain routing-udp {
 | 
				
			||||||
 | 
					                    return
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  chain filter-routing {
 | 
				
			||||||
 | 
					                    tcp flags & (fin|syn|rst|ack) == syn ct state new jump routing-tcp
 | 
				
			||||||
 | 
					                    meta l4proto udp ct state new jump routing-udp
 | 
				
			||||||
 | 
					                    return
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  chain filter-untrusted {
 | 
				
			||||||
 | 
					                    ip daddr ${prefixes.modem.v4} reject
 | 
				
			||||||
 | 
					                    oifname wan accept
 | 
				
			||||||
 | 
					                    return
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  chain forward {
 | 
				
			||||||
 | 
					                    ${lib.my.c.as211024.nftTrust}
 | 
				
			||||||
 | 
					                    iifname lan-untrusted jump filter-untrusted
 | 
				
			||||||
 | 
					                    iifname { wan, as211024, lan-untrusted } oifname { lan-hi, lan-lo } jump filter-routing
 | 
				
			||||||
 | 
					                    oifname as211024 accept
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  chain output { }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                table inet nat {
 | 
				
			||||||
 | 
					                  chain prerouting {
 | 
				
			||||||
 | 
					                    ip daddr ${elemAt routersPubV4 index} meta l4proto { udp, tcp } th dport domain redirect to :5353
 | 
				
			||||||
 | 
					                    ip6 daddr ${assignments.as211024.ipv6.address} meta l4proto { udp, tcp } th dport domain redirect to :5353
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  chain postrouting {
 | 
				
			||||||
 | 
					                    oifname wan masquerade
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              '';
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										246
									
								
								nixos/boxes/home/routing-common/dns.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								nixos/boxes/home/routing-common/dns.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,246 @@
 | 
				
			|||||||
 | 
					index: { lib, pkgs, config, assignments, allAssignments, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (builtins) attrNames elemAt;
 | 
				
			||||||
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
 | 
					  inherit (lib.my.c) pubDomain;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.home) prefixes vips routers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  name = elemAt routers index;
 | 
				
			||||||
 | 
					  otherIndex = 1 - index;
 | 
				
			||||||
 | 
					  otherName = elemAt routers otherIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  authZones = attrNames config.my.pdns.auth.bind.zones;
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  config = {
 | 
				
			||||||
 | 
					    my = {
 | 
				
			||||||
 | 
					      secrets.files = {
 | 
				
			||||||
 | 
					        "home/pdns/auth.conf" = {
 | 
				
			||||||
 | 
					          owner = "pdns";
 | 
				
			||||||
 | 
					          group = "pdns";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        "home/pdns/recursor.conf" = {
 | 
				
			||||||
 | 
					          owner = "pdns-recursor";
 | 
				
			||||||
 | 
					          group = "pdns-recursor";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        "home/ddclient-cloudflare.key" = {};
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      pdns.recursor = {
 | 
				
			||||||
 | 
					        enable = true;
 | 
				
			||||||
 | 
					        extraSettingsFile = config.age.secrets."home/pdns/recursor.conf".path;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    services = {
 | 
				
			||||||
 | 
					      pdns-recursor = {
 | 
				
			||||||
 | 
					        dns = {
 | 
				
			||||||
 | 
					          address = [
 | 
				
			||||||
 | 
					            "127.0.0.1" "::1"
 | 
				
			||||||
 | 
					            assignments.hi.ipv4.address assignments.hi.ipv6.address
 | 
				
			||||||
 | 
					            assignments.lo.ipv4.address assignments.lo.ipv6.address
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          allowFrom = [
 | 
				
			||||||
 | 
					            "127.0.0.0/8" "::1/128"
 | 
				
			||||||
 | 
					            prefixes.hi.v4 prefixes.hi.v6
 | 
				
			||||||
 | 
					            prefixes.lo.v4 prefixes.lo.v6
 | 
				
			||||||
 | 
					          ] ++ (with lib.my.c.tailscale.prefix; [ v4 v6 ]);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        settings = {
 | 
				
			||||||
 | 
					          query-local-address = [
 | 
				
			||||||
 | 
					            "0.0.0.0"
 | 
				
			||||||
 | 
					            "::"
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          forward-zones = map (z: "${z}=127.0.0.1:5353") authZones;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          # DNS NOTIFY messages override TTL
 | 
				
			||||||
 | 
					          allow-notify-for = authZones;
 | 
				
			||||||
 | 
					          allow-notify-from = [ "127.0.0.0/8" "::1/128" ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          webserver = true;
 | 
				
			||||||
 | 
					          webserver-address = "::";
 | 
				
			||||||
 | 
					          webserver-allow-from = [ "127.0.0.1" "::1" ];
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    systemd = {
 | 
				
			||||||
 | 
					      services = {
 | 
				
			||||||
 | 
					        # Add AF_NETLINK to allow pulling IP from network interfaces
 | 
				
			||||||
 | 
					        pdns.serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
 | 
				
			||||||
 | 
					        ddns-update = {
 | 
				
			||||||
 | 
					          description = "DNS update script";
 | 
				
			||||||
 | 
					          after = [ "network.target" ];
 | 
				
			||||||
 | 
					          path = [
 | 
				
			||||||
 | 
					            (pkgs.python3.withPackages (ps: [ ps.cloudflare ]))
 | 
				
			||||||
 | 
					            pkgs.ldns
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          serviceConfig = {
 | 
				
			||||||
 | 
					            Type = "oneshot";
 | 
				
			||||||
 | 
					            ExecStart =
 | 
				
			||||||
 | 
					              ''${./dns_update.py} -k ${config.age.secrets."home/ddclient-cloudflare.key".path} '' +
 | 
				
			||||||
 | 
					              ''${pubDomain} ns${toString (index + 1)}.${config.networking.domain}'';
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          wantedBy = [ "multi-user.target" ];
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      timers = {
 | 
				
			||||||
 | 
					        ddns-update = {
 | 
				
			||||||
 | 
					          description = "Periodically update DNS";
 | 
				
			||||||
 | 
					          wantedBy = [ "timers.target" ];
 | 
				
			||||||
 | 
					          timerConfig = {
 | 
				
			||||||
 | 
					            OnBootSec = "5min";
 | 
				
			||||||
 | 
					            OnUnitInactiveSec = "5min";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    environment.systemPackages = with pkgs; [
 | 
				
			||||||
 | 
					      # For rec_control
 | 
				
			||||||
 | 
					      pdns-recursor
 | 
				
			||||||
 | 
					      sqlite
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    my.pdns.auth = {
 | 
				
			||||||
 | 
					      enable = true;
 | 
				
			||||||
 | 
					      extraSettingsFile = config.age.secrets."home/pdns/auth.conf".path;
 | 
				
			||||||
 | 
					      settings = {
 | 
				
			||||||
 | 
					        primary = true;
 | 
				
			||||||
 | 
					        resolver = "127.0.0.1";
 | 
				
			||||||
 | 
					        expand-alias = true;
 | 
				
			||||||
 | 
					        local-address = [
 | 
				
			||||||
 | 
					          "0.0.0.0:5353" "[::]:5353"
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					        also-notify = [ "127.0.0.1" ];
 | 
				
			||||||
 | 
					        enable-lua-records = true;
 | 
				
			||||||
 | 
					        # loglevel = 7;
 | 
				
			||||||
 | 
					        # log-dns-queries = true;
 | 
				
			||||||
 | 
					        # log-dns-details = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        api = true;
 | 
				
			||||||
 | 
					        webserver = true;
 | 
				
			||||||
 | 
					        webserver-address = "::";
 | 
				
			||||||
 | 
					        webserver-allow-from = [ "127.0.0.1" "::1" ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dnsupdate = true;
 | 
				
			||||||
 | 
					        launch = [ "gsqlite3" ];
 | 
				
			||||||
 | 
					        gsqlite3-database = "/var/lib/pdns/dynamic.sqlite3";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      bind.zones =
 | 
				
			||||||
 | 
					      let
 | 
				
			||||||
 | 
					        names = [ "core" "hi" "lo" "untrusted" ];
 | 
				
			||||||
 | 
					        i = toString (index + 1);
 | 
				
			||||||
 | 
					      in
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "${config.networking.domain}" = {
 | 
				
			||||||
 | 
					          type = "master";
 | 
				
			||||||
 | 
					          text = ''
 | 
				
			||||||
 | 
					            $TTL 60
 | 
				
			||||||
 | 
					            @ IN SOA ns${i}.${config.networking.domain}. dev.nul.ie. (
 | 
				
			||||||
 | 
					              @@SERIAL@@ ; serial
 | 
				
			||||||
 | 
					              3h ; refresh
 | 
				
			||||||
 | 
					              1h ; retry
 | 
				
			||||||
 | 
					              1w ; expire
 | 
				
			||||||
 | 
					              1h ; minimum
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ${name} IN LUA ${lib.my.dns.ifaceA {
 | 
				
			||||||
 | 
					              inherit pkgs;
 | 
				
			||||||
 | 
					              iface = "wan";
 | 
				
			||||||
 | 
					              skipBroadcasts = [ (lib.my.netBroadcast prefixes.modem.v4) ];
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					            ${otherName} IN LUA ${lib.my.dns.lookupIP {
 | 
				
			||||||
 | 
					              inherit pkgs;
 | 
				
			||||||
 | 
					              hostname = "${otherName}.${config.networking.domain}";
 | 
				
			||||||
 | 
					              server = net.cidr.host (otherIndex + 1) prefixes.hi.v4;
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					            ${elemAt routers 0} IN AAAA ${net.cidr.host 1 prefixes.hi.v6}
 | 
				
			||||||
 | 
					            ${elemAt routers 1} IN AAAA ${net.cidr.host 2 prefixes.hi.v6}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            @ IN NS ns1
 | 
				
			||||||
 | 
					            @ IN NS ns2
 | 
				
			||||||
 | 
					            ns1 IN ALIAS ${elemAt routers 0}.${config.networking.domain}.
 | 
				
			||||||
 | 
					            ns2 IN ALIAS ${elemAt routers 1}.${config.networking.domain}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dyn IN NS ns1.dyn.h.nul.ie.
 | 
				
			||||||
 | 
					            dyn IN NS ns2.dyn.h.nul.ie.
 | 
				
			||||||
 | 
					            ns1.dyn.h.nul.ie. IN ALIAS ${elemAt routers 0}.${config.networking.domain}.
 | 
				
			||||||
 | 
					            ns2.dyn.h.nul.ie. IN ALIAS ${elemAt routers 1}.${config.networking.domain}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            jim-core IN A ${net.cidr.host 10 prefixes.core.v4}
 | 
				
			||||||
 | 
					            jim IN A ${net.cidr.host 10 prefixes.hi.v4}
 | 
				
			||||||
 | 
					            jim IN AAAA ${net.cidr.host (65536+1) prefixes.hi.v6}
 | 
				
			||||||
 | 
					            jim-lo IN A ${net.cidr.host 10 prefixes.lo.v4}
 | 
				
			||||||
 | 
					            jim-lo IN AAAA ${net.cidr.host (65536+1) prefixes.lo.v6}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            dave-core IN A ${net.cidr.host 11 prefixes.core.v4}
 | 
				
			||||||
 | 
					            dave IN A ${net.cidr.host 11 prefixes.hi.v4}
 | 
				
			||||||
 | 
					            dave IN AAAA ${net.cidr.host (65536+2) prefixes.hi.v6}
 | 
				
			||||||
 | 
					            dave-lo IN A ${net.cidr.host 11 prefixes.lo.v4}
 | 
				
			||||||
 | 
					            dave-lo IN AAAA ${net.cidr.host (65536+2) prefixes.lo.v6}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ;ap0 IN A ${net.cidr.host 12 prefixes.hi.v4}
 | 
				
			||||||
 | 
					            ;ap0 IN AAAA ${net.cidr.host (65536+3) prefixes.hi.v6}
 | 
				
			||||||
 | 
					            vibe IN A ${net.cidr.host 13 prefixes.hi.v4}
 | 
				
			||||||
 | 
					            vibe IN AAAA ${net.cidr.host (65536+4) prefixes.hi.v6}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ups IN A ${net.cidr.host 20 prefixes.lo.v4}
 | 
				
			||||||
 | 
					            palace-kvm IN A ${net.cidr.host 21 prefixes.lo.v4}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ${lib.my.dns.fwdRecords {
 | 
				
			||||||
 | 
					              inherit allAssignments names;
 | 
				
			||||||
 | 
					              domain = config.networking.domain;
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          '';
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        "168.192.in-addr.arpa" = {
 | 
				
			||||||
 | 
					          type = "master";
 | 
				
			||||||
 | 
					          text = ''
 | 
				
			||||||
 | 
					            $TTL 60
 | 
				
			||||||
 | 
					            @ IN SOA ns${i}.${config.networking.domain}. dev.nul.ie. (
 | 
				
			||||||
 | 
					              @@SERIAL@@ ; serial
 | 
				
			||||||
 | 
					              3h ; refresh
 | 
				
			||||||
 | 
					              1h ; retry
 | 
				
			||||||
 | 
					              1w ; expire
 | 
				
			||||||
 | 
					              1h ; minimum
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            @ IN NS ns1.${config.networking.domain}.
 | 
				
			||||||
 | 
					            @ IN NS ns2.${config.networking.domain}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ${lib.my.dns.ptrRecords {
 | 
				
			||||||
 | 
					              inherit allAssignments names;
 | 
				
			||||||
 | 
					              domain = config.networking.domain;
 | 
				
			||||||
 | 
					              ndots = 2;
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          '';
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        "0.d.4.0.0.c.7.9.e.0.a.2.ip6.arpa" = {
 | 
				
			||||||
 | 
					          type = "master";
 | 
				
			||||||
 | 
					          text = ''
 | 
				
			||||||
 | 
					            $TTL 60
 | 
				
			||||||
 | 
					            @ IN SOA ns${i}.${config.networking.domain}. dev.nul.ie. (
 | 
				
			||||||
 | 
					              @@SERIAL@@ ; serial
 | 
				
			||||||
 | 
					              3h ; refresh
 | 
				
			||||||
 | 
					              1h ; retry
 | 
				
			||||||
 | 
					              1w ; expire
 | 
				
			||||||
 | 
					              1h ; minimum
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            @ IN NS ns1.${config.networking.domain}.
 | 
				
			||||||
 | 
					            @ IN NS ns2.${config.networking.domain}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ${lib.my.dns.ptr6Records {
 | 
				
			||||||
 | 
					              inherit allAssignments names;
 | 
				
			||||||
 | 
					              domain = config.networking.domain;
 | 
				
			||||||
 | 
					              ndots = 20;
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          '';
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								nixos/boxes/home/routing-common/dns_update.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										35
									
								
								nixos/boxes/home/routing-common/dns_update.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					import argparse
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import CloudFlare
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    parser = argparse.ArgumentParser(description='Cloudflare DNS update script')
 | 
				
			||||||
 | 
					    parser.add_argument('-k', '--api-token-file', help='Cloudflare API token file')
 | 
				
			||||||
 | 
					    parser.add_argument('zone', help='Cloudflare Zone')
 | 
				
			||||||
 | 
					    parser.add_argument('record', help='Cloudflare record name')
 | 
				
			||||||
 | 
					    args = parser.parse_args()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    address = subprocess.check_output(
 | 
				
			||||||
 | 
					        ['drill', '-Q', '-p5353', '@127.0.0.1', args.record, 'A'],
 | 
				
			||||||
 | 
					        encoding='utf8').strip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cf_token = None
 | 
				
			||||||
 | 
					    if args.api_token_file:
 | 
				
			||||||
 | 
					        with open(args.api_token_file) as f:
 | 
				
			||||||
 | 
					            cf_token = f.readline().strip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cf = CloudFlare.CloudFlare(token=cf_token)
 | 
				
			||||||
 | 
					    zones = cf.zones.get(params={'name': args.zone})
 | 
				
			||||||
 | 
					    assert zones, f'Zone {args.zone} not found'
 | 
				
			||||||
 | 
					    records = cf.zones.dns_records.get(zones[0]['id'], params={'name': args.record})
 | 
				
			||||||
 | 
					    assert records, f'Record {args.record} not found in zone {args.zone}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print(f'Updating {args.record} -> {address}')
 | 
				
			||||||
 | 
					    cf.zones.dns_records.patch(
 | 
				
			||||||
 | 
					        zones[0]['id'], records[0]['id'],
 | 
				
			||||||
 | 
					        data={'type': 'A', 'name': args.record, 'content': address})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										149
									
								
								nixos/boxes/home/routing-common/kea.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								nixos/boxes/home/routing-common/kea.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
				
			|||||||
 | 
					index: { lib, pkgs, assignments, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib) mkForce;
 | 
				
			||||||
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.home) domain prefixes vips hiMTU;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  dns-servers = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      ip-address = net.cidr.host 1 prefixes.core.v4;
 | 
				
			||||||
 | 
					      port = 5353;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      ip-address = net.cidr.host 2 prefixes.core.v4;
 | 
				
			||||||
 | 
					      port = 5353;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  users = with lib.my.c.ids; {
 | 
				
			||||||
 | 
					    users.kea= {
 | 
				
			||||||
 | 
					      isSystemUser = true;
 | 
				
			||||||
 | 
					      uid = uids.kea;
 | 
				
			||||||
 | 
					      group = "kea";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    groups.kea.gid = gids.kea;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  systemd.services = {
 | 
				
			||||||
 | 
					    kea-dhcp4-server.serviceConfig.DynamicUser = mkForce false;
 | 
				
			||||||
 | 
					    kea-dhcp-ddns-server.serviceConfig.DynamicUser = mkForce false;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  services = {
 | 
				
			||||||
 | 
					    kea = {
 | 
				
			||||||
 | 
					      dhcp4 = {
 | 
				
			||||||
 | 
					        enable = true;
 | 
				
			||||||
 | 
					        settings = {
 | 
				
			||||||
 | 
					          interfaces-config = {
 | 
				
			||||||
 | 
					            interfaces = [
 | 
				
			||||||
 | 
					              "lan-hi/${assignments.hi.ipv4.address}"
 | 
				
			||||||
 | 
					              "lan-lo/${assignments.lo.ipv4.address}"
 | 
				
			||||||
 | 
					              "lan-untrusted/${assignments.untrusted.ipv4.address}"
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          lease-database = {
 | 
				
			||||||
 | 
					            type = "memfile";
 | 
				
			||||||
 | 
					            persist = true;
 | 
				
			||||||
 | 
					            name = "/var/lib/kea/dhcp.leases";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          option-data = [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              name = "domain-name";
 | 
				
			||||||
 | 
					              data = domain;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              name = "domain-search";
 | 
				
			||||||
 | 
					              data = "${domain}, dyn.${domain}, ${lib.my.c.colony.domain}, ${lib.my.c.britway.domain}";
 | 
				
			||||||
 | 
					              always-send = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          subnet4 = [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              id = 1;
 | 
				
			||||||
 | 
					              subnet = prefixes.hi.v4;
 | 
				
			||||||
 | 
					              interface = "lan-hi";
 | 
				
			||||||
 | 
					              option-data = [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  name = "routers";
 | 
				
			||||||
 | 
					                  data = vips.hi.v4;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  name = "domain-name-servers";
 | 
				
			||||||
 | 
					                  data = "${net.cidr.host 1 prefixes.hi.v4}, ${net.cidr.host 2 prefixes.hi.v4}";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  name = "interface-mtu";
 | 
				
			||||||
 | 
					                  data = toString hiMTU;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
 | 
					              pools = [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  pool = if index == 0
 | 
				
			||||||
 | 
					                    then "192.168.68.120 - 192.168.69.255"
 | 
				
			||||||
 | 
					                    else "192.168.70.0 - 192.168.71.240";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
 | 
					              reservations = [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  # castle
 | 
				
			||||||
 | 
					                  hw-address = "24:8a:07:a8:fe:3a";
 | 
				
			||||||
 | 
					                  ip-address = net.cidr.host 40 prefixes.hi.v4;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              id = 2;
 | 
				
			||||||
 | 
					              subnet = prefixes.lo.v4;
 | 
				
			||||||
 | 
					              interface = "lan-lo";
 | 
				
			||||||
 | 
					              option-data = [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  name = "routers";
 | 
				
			||||||
 | 
					                  data = vips.lo.v4;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  name = "domain-name-servers";
 | 
				
			||||||
 | 
					                  data = "${net.cidr.host 1 prefixes.lo.v4}, ${net.cidr.host 2 prefixes.lo.v4}";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
 | 
					              pools = [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  pool = if index == 0
 | 
				
			||||||
 | 
					                    then "192.168.72.120 - 192.168.75.255"
 | 
				
			||||||
 | 
					                    else "192.168.76.0 - 192.168.79.240";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
 | 
					              reservations = [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  # castle
 | 
				
			||||||
 | 
					                  hw-address = "24:8a:07:a8:fe:3a";
 | 
				
			||||||
 | 
					                  ip-address = net.cidr.host 40 prefixes.lo.v4;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          ddns-send-updates = true;
 | 
				
			||||||
 | 
					          ddns-replace-client-name = "when-not-present";
 | 
				
			||||||
 | 
					          ddns-qualifying-suffix = "dyn.${domain}";
 | 
				
			||||||
 | 
					          ddns-generated-prefix = "ip";
 | 
				
			||||||
 | 
					          ddns-update-on-renew = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          dhcp-ddns.enable-updates = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      dhcp-ddns = {
 | 
				
			||||||
 | 
					        enable = true;
 | 
				
			||||||
 | 
					        settings = {
 | 
				
			||||||
 | 
					          forward-ddns.ddns-domains = [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              name = "dyn.${domain}.";
 | 
				
			||||||
 | 
					              inherit dns-servers;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										52
									
								
								nixos/boxes/home/routing-common/keepalived.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								nixos/boxes/home/routing-common/keepalived.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					index: { lib, pkgs, config, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (builtins) attrNames concatMap;
 | 
				
			||||||
 | 
					  inherit (lib) optional;
 | 
				
			||||||
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.home) prefixes vips;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  vlanIface = vlan: if vlan == "as211024" then vlan else "lan-${vlan}";
 | 
				
			||||||
 | 
					  vrrpIPs = family: concatMap (vlan: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      addr = "${vips.${vlan}.${family}}/${toString (net.cidr.length prefixes.${vlan}.${family})}";
 | 
				
			||||||
 | 
					      dev = vlanIface vlan;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ] ++ (optional (family == "v6") {
 | 
				
			||||||
 | 
					    addr = "fe80::1/64";
 | 
				
			||||||
 | 
					    dev = vlanIface vlan;
 | 
				
			||||||
 | 
					  })) (attrNames vips);
 | 
				
			||||||
 | 
					  mkVRRP = family: routerId: {
 | 
				
			||||||
 | 
					    state = if index == 0 then "MASTER" else "BACKUP";
 | 
				
			||||||
 | 
					    interface = "lan-core";
 | 
				
			||||||
 | 
					    priority = 255 - index;
 | 
				
			||||||
 | 
					    virtualRouterId = routerId;
 | 
				
			||||||
 | 
					    virtualIps = vrrpIPs family;
 | 
				
			||||||
 | 
					    extraConfig = ''
 | 
				
			||||||
 | 
					      notify_master "${config.systemd.package}/bin/systemctl start radvd.service"
 | 
				
			||||||
 | 
					      notify_backup "${config.systemd.package}/bin/systemctl stop radvd.service"
 | 
				
			||||||
 | 
					    '';
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  services = {
 | 
				
			||||||
 | 
					    keepalived = {
 | 
				
			||||||
 | 
					      enable = true;
 | 
				
			||||||
 | 
					      extraGlobalDefs = ''
 | 
				
			||||||
 | 
					        vrrp_version 3
 | 
				
			||||||
 | 
					        nftables keepalived
 | 
				
			||||||
 | 
					      '';
 | 
				
			||||||
 | 
					      vrrpInstances = {
 | 
				
			||||||
 | 
					        v4 = mkVRRP "v4" 51;
 | 
				
			||||||
 | 
					        v6 = mkVRRP "v6" 52;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      extraConfig = ''
 | 
				
			||||||
 | 
					        vrrp_sync_group main {
 | 
				
			||||||
 | 
					          group {
 | 
				
			||||||
 | 
					            v4
 | 
				
			||||||
 | 
					            v6
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      '';
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										53
									
								
								nixos/boxes/home/routing-common/mstpd.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								nixos/boxes/home/routing-common/mstpd.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					{ lib, pkgs, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  # TODO: Move into nixpkgs
 | 
				
			||||||
 | 
					  mstpd = pkgs.mstpd.overrideAttrs {
 | 
				
			||||||
 | 
					    patches = [ ./mstpd.patch ];
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  environment = {
 | 
				
			||||||
 | 
					    systemPackages = [
 | 
				
			||||||
 | 
					      mstpd
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    etc = {
 | 
				
			||||||
 | 
					      "bridge-stp.conf".text = ''
 | 
				
			||||||
 | 
					        MANAGE_MSTPD=n
 | 
				
			||||||
 | 
					        MSTP_BRIDGES=lan
 | 
				
			||||||
 | 
					      '';
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  services = {
 | 
				
			||||||
 | 
					    networkd-dispatcher.rules = {
 | 
				
			||||||
 | 
					      configure-mstpd = {
 | 
				
			||||||
 | 
					        onState = [ "routable" ];
 | 
				
			||||||
 | 
					        script = ''
 | 
				
			||||||
 | 
					          #!${pkgs.runtimeShell}
 | 
				
			||||||
 | 
					          if [ $IFACE = "lan" ]; then
 | 
				
			||||||
 | 
					            ${mstpd}/sbin/mstpctl setforcevers $IFACE rstp
 | 
				
			||||||
 | 
					          fi
 | 
				
			||||||
 | 
					        '';
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  systemd = {
 | 
				
			||||||
 | 
					    services = {
 | 
				
			||||||
 | 
					      mstpd = {
 | 
				
			||||||
 | 
					        description = "MSTP daemon";
 | 
				
			||||||
 | 
					        before = [ "network-pre.target" ];
 | 
				
			||||||
 | 
					        serviceConfig = {
 | 
				
			||||||
 | 
					          Type = "forking";
 | 
				
			||||||
 | 
					          ExecStart = "${mstpd}/sbin/bridge-stp restart";
 | 
				
			||||||
 | 
					          ExecReload = "${mstpd}/sbin/bridge-stp restart_config";
 | 
				
			||||||
 | 
					          PIDFile = "/run/mstpd.pid";
 | 
				
			||||||
 | 
					          Restart = "always";
 | 
				
			||||||
 | 
					          PrivateTmp = true;
 | 
				
			||||||
 | 
					          ProtectHome = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        wantedBy = [ "multi-user.target" ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								nixos/boxes/home/routing-common/mstpd.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								nixos/boxes/home/routing-common/mstpd.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					diff --git a/bridge-stp.in b/bridge-stp.in
 | 
				
			||||||
 | 
					index 3807873..9c73126 100755
 | 
				
			||||||
 | 
					--- a/bridge-stp.in
 | 
				
			||||||
 | 
					+++ b/bridge-stp.in
 | 
				
			||||||
 | 
					@@ -31,6 +31,10 @@
 | 
				
			||||||
 | 
					 # bridge or any associated kernel network interfaces in any code paths that are
 | 
				
			||||||
 | 
					 # used when this script is called by the kernel.
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					+# Ensure that we have a sane PATH.
 | 
				
			||||||
 | 
					+PATH='/run/current-system/sw/bin'
 | 
				
			||||||
 | 
					+export PATH
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					 # Parse arguments.
 | 
				
			||||||
 | 
					 CalledAs="$(basename "$0")"
 | 
				
			||||||
 | 
					 if [ "$CalledAs" = 'mstpctl_restart_config' ]; then
 | 
				
			||||||
 | 
					@@ -62,10 +66,6 @@ fi
 | 
				
			||||||
 | 
					 # Ensure that we have a sane umask.
 | 
				
			||||||
 | 
					 umask 022
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					-# Ensure that we have a sane PATH.
 | 
				
			||||||
 | 
					-PATH='/sbin:/usr/sbin:/bin:/usr/bin'
 | 
				
			||||||
 | 
					-export PATH
 | 
				
			||||||
 | 
					-
 | 
				
			||||||
 | 
					 # Define some relevant paths.
 | 
				
			||||||
 | 
					 mstpctl='@mstpctlfile@'
 | 
				
			||||||
 | 
					 mstpd='@mstpdfile@'
 | 
				
			||||||
							
								
								
									
										28
									
								
								nixos/boxes/home/routing-common/radvd.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								nixos/boxes/home/routing-common/radvd.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					index: { lib, pkgs, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib) mkForce concatMapStringsSep;
 | 
				
			||||||
 | 
					  inherit (lib.my) net;
 | 
				
			||||||
 | 
					  inherit (lib.my.c.home) domain prefixes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mkInterface = name: ''
 | 
				
			||||||
 | 
					    interface lan-${name} {
 | 
				
			||||||
 | 
					      AdvSendAdvert on;
 | 
				
			||||||
 | 
					      AdvRASrcAddress { fe80::1; };
 | 
				
			||||||
 | 
					      AdvLinkMTU ${toString prefixes."${name}".mtu};
 | 
				
			||||||
 | 
					      prefix ${prefixes."${name}".v6} {};
 | 
				
			||||||
 | 
					      RDNSS ${net.cidr.host 1 prefixes."${name}".v6} ${net.cidr.host 2 prefixes."${name}".v6} {};
 | 
				
			||||||
 | 
					      DNSSL ${domain} dyn.${domain} ${lib.my.c.colony.domain} ${lib.my.c.britway.domain} {};
 | 
				
			||||||
 | 
					     };
 | 
				
			||||||
 | 
					  '';
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  # To be started by keepalived
 | 
				
			||||||
 | 
					  systemd.services.radvd.wantedBy = mkForce [ ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  services = {
 | 
				
			||||||
 | 
					    radvd = {
 | 
				
			||||||
 | 
					      enable = true;
 | 
				
			||||||
 | 
					      config = concatMapStringsSep "\n" mkInterface [ "hi" "lo" "untrusted" ];
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										131
									
								
								nixos/boxes/home/stream.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								nixos/boxes/home/stream.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  imports = [ (import ./routing-common 1) ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  config.nixos.systems.stream = {
 | 
				
			||||||
 | 
					    system = "x86_64-linux";
 | 
				
			||||||
 | 
					    nixpkgs = "mine";
 | 
				
			||||||
 | 
					    home-manager = "mine";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    configuration = { lib, pkgs, config, ... }:
 | 
				
			||||||
 | 
					    let
 | 
				
			||||||
 | 
					      inherit (lib);
 | 
				
			||||||
 | 
					    in
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      imports = [ ./routing-common/mstpd.nix ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      config = {
 | 
				
			||||||
 | 
					        boot = {
 | 
				
			||||||
 | 
					          kernelModules = [ "kvm-intel" ];
 | 
				
			||||||
 | 
					          kernelParams = [ "intel_iommu=on" ];
 | 
				
			||||||
 | 
					          initrd.availableKernelModules = [ "xhci_pci" "usbhid" "usb_storage" "sd_mod" "sdhci_pci" ];
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        hardware = {
 | 
				
			||||||
 | 
					          enableRedistributableFirmware = true;
 | 
				
			||||||
 | 
					          cpu = {
 | 
				
			||||||
 | 
					            intel.updateMicrocode = true;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fileSystems = {
 | 
				
			||||||
 | 
					          "/boot" = {
 | 
				
			||||||
 | 
					            device = "/dev/disk/by-partuuid/fe081885-9157-46b5-be70-46ac6fcb4069";
 | 
				
			||||||
 | 
					            fsType = "vfat";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          "/nix" = {
 | 
				
			||||||
 | 
					            device = "/dev/disk/by-partuuid/a195e55e-397f-440d-a190-59ffa63cdb3f";
 | 
				
			||||||
 | 
					            fsType = "ext4";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          "/persist" = {
 | 
				
			||||||
 | 
					            device = "/dev/disk/by-partuuid/ad71fafd-2d26-49c8-b0cb-794a28e0beb7";
 | 
				
			||||||
 | 
					            fsType = "ext4";
 | 
				
			||||||
 | 
					            neededForBoot = true;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        systemd.network = {
 | 
				
			||||||
 | 
					          netdevs = {
 | 
				
			||||||
 | 
					            "25-lan" = {
 | 
				
			||||||
 | 
					              netdevConfig = {
 | 
				
			||||||
 | 
					                Name = "lan";
 | 
				
			||||||
 | 
					                Kind = "bridge";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              extraConfig = ''
 | 
				
			||||||
 | 
					                [Bridge]
 | 
				
			||||||
 | 
					                STP=true
 | 
				
			||||||
 | 
					              '';
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          links = {
 | 
				
			||||||
 | 
					            "10-wan" = {
 | 
				
			||||||
 | 
					              matchConfig = {
 | 
				
			||||||
 | 
					                # Matching against MAC address seems to break VLAN interfaces
 | 
				
			||||||
 | 
					                # (since they share the same MAC address)
 | 
				
			||||||
 | 
					                Driver = "igc";
 | 
				
			||||||
 | 
					                PermanentMACAddress = "00:f0:cb:ee:ca:dd";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              linkConfig = {
 | 
				
			||||||
 | 
					                Name = "wan";
 | 
				
			||||||
 | 
					                RxBufferSize = 4096;
 | 
				
			||||||
 | 
					                TxBufferSize = 4096;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            "10-lan-jim" = {
 | 
				
			||||||
 | 
					              matchConfig = {
 | 
				
			||||||
 | 
					                Driver = "igc";
 | 
				
			||||||
 | 
					                PermanentMACAddress = "00:f0:cb:ee:ca:de";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              linkConfig = {
 | 
				
			||||||
 | 
					                Name = "lan-jim";
 | 
				
			||||||
 | 
					                MTUBytes = toString lib.my.c.home.hiMTU;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            "10-et2" = {
 | 
				
			||||||
 | 
					              matchConfig = {
 | 
				
			||||||
 | 
					                Driver = "igc";
 | 
				
			||||||
 | 
					                PermanentMACAddress = "00:f0:cb:ee:ca:df";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              linkConfig.Name = "et2";
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            "10-lan-dave" = {
 | 
				
			||||||
 | 
					              matchConfig = {
 | 
				
			||||||
 | 
					                Driver = "mlx4_en";
 | 
				
			||||||
 | 
					                PermanentMACAddress = "00:02:c9:d5:b1:d6";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              linkConfig = {
 | 
				
			||||||
 | 
					                Name = "lan-dave";
 | 
				
			||||||
 | 
					                MTUBytes = toString lib.my.c.home.hiMTU;
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            "10-et5" = {
 | 
				
			||||||
 | 
					              matchConfig = {
 | 
				
			||||||
 | 
					                Driver = "mlx4_en";
 | 
				
			||||||
 | 
					                PermanentMACAddress = "00:02:c9:d5:b1:d7";
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					              linkConfig.Name = "et5";
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          networks = {
 | 
				
			||||||
 | 
					            "50-lan-jim" = {
 | 
				
			||||||
 | 
					              matchConfig.Name = "lan-jim";
 | 
				
			||||||
 | 
					              networkConfig.Bridge = "lan";
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            "50-lan-dave" = {
 | 
				
			||||||
 | 
					              matchConfig.Name = "lan-dave";
 | 
				
			||||||
 | 
					              networkConfig.Bridge = "lan";
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        my = {
 | 
				
			||||||
 | 
					          secrets = {
 | 
				
			||||||
 | 
					            key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPYTB4zeAqotrEJ8M+AiGm/s9PFsWlAodz3hYSROGuDb";
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          server.enable = true;
 | 
				
			||||||
 | 
					          deploy.node.hostname = "192.168.68.2";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -92,7 +92,7 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          nextcloud = {
 | 
					          nextcloud = {
 | 
				
			||||||
            enable = true;
 | 
					            enable = true;
 | 
				
			||||||
            package = pkgs.nextcloud27;
 | 
					            package = pkgs.nextcloud28;
 | 
				
			||||||
            datadir = "/mnt/storage/nextcloud";
 | 
					            datadir = "/mnt/storage/nextcloud";
 | 
				
			||||||
            hostName = "cloud.${domain}";
 | 
					            hostName = "cloud.${domain}";
 | 
				
			||||||
            https = true;
 | 
					            https = true;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
let
 | 
					let
 | 
				
			||||||
  inherit (builtins) mapAttrs;
 | 
					  inherit (builtins) mapAttrs;
 | 
				
			||||||
  inherit (lib) mkMerge mkIf mkDefault;
 | 
					  inherit (lib) mkMerge mkIf mkDefault;
 | 
				
			||||||
  inherit (lib.my.c.nginx) proxyHeaders;
 | 
					  inherit (lib.my.c.nginx) baseHttpConfig proxyHeaders;
 | 
				
			||||||
  inherit (lib.my.c.kelder) domain;
 | 
					  inherit (lib.my.c.kelder) domain;
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -39,43 +39,7 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # Based on recommended*Settings, but probably better to be explicit about these
 | 
					        # Based on recommended*Settings, but probably better to be explicit about these
 | 
				
			||||||
        appendHttpConfig = ''
 | 
					        appendHttpConfig = ''
 | 
				
			||||||
          # NixOS provides a logrotate config that auto-compresses :)
 | 
					          ${baseHttpConfig}
 | 
				
			||||||
          log_format main
 | 
					 | 
				
			||||||
            '$remote_addr - $remote_user [$time_local] $scheme "$host" "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
 | 
					 | 
				
			||||||
          access_log /var/log/nginx/access.log main;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          # optimisation
 | 
					 | 
				
			||||||
          sendfile on;
 | 
					 | 
				
			||||||
          tcp_nopush on;
 | 
					 | 
				
			||||||
          tcp_nodelay on;
 | 
					 | 
				
			||||||
          keepalive_timeout 65;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          # gzip
 | 
					 | 
				
			||||||
          gzip on;
 | 
					 | 
				
			||||||
          gzip_proxied any;
 | 
					 | 
				
			||||||
          gzip_comp_level 5;
 | 
					 | 
				
			||||||
          gzip_types
 | 
					 | 
				
			||||||
            application/atom+xml
 | 
					 | 
				
			||||||
            application/javascript
 | 
					 | 
				
			||||||
            application/json
 | 
					 | 
				
			||||||
            application/xml
 | 
					 | 
				
			||||||
            application/xml+rss
 | 
					 | 
				
			||||||
            image/svg+xml
 | 
					 | 
				
			||||||
            text/css
 | 
					 | 
				
			||||||
            text/javascript
 | 
					 | 
				
			||||||
            text/plain
 | 
					 | 
				
			||||||
            text/xml;
 | 
					 | 
				
			||||||
          gzip_vary on;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          # proxying
 | 
					 | 
				
			||||||
          proxy_buffering off;
 | 
					 | 
				
			||||||
          proxy_redirect off;
 | 
					 | 
				
			||||||
          proxy_connect_timeout 60s;
 | 
					 | 
				
			||||||
          proxy_read_timeout 60s;
 | 
					 | 
				
			||||||
          proxy_send_timeout 60s;
 | 
					 | 
				
			||||||
          proxy_http_version 1.1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          ${proxyHeaders}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          # caching
 | 
					          # caching
 | 
				
			||||||
          proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=4g;
 | 
					          proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=4g;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,7 @@ in
 | 
				
			|||||||
              efi.canTouchEfiVariables = true;
 | 
					              efi.canTouchEfiVariables = true;
 | 
				
			||||||
              timeout = 5;
 | 
					              timeout = 5;
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            kernelPackages = pkgs.linuxKernel.packages.linux_6_1;
 | 
					            kernelPackages = lib.my.c.kernel.lts pkgs;
 | 
				
			||||||
            kernelModules = [ "kvm-intel" ];
 | 
					            kernelModules = [ "kvm-intel" ];
 | 
				
			||||||
            kernelParams = [ "intel_iommu=on" ];
 | 
					            kernelParams = [ "intel_iommu=on" ];
 | 
				
			||||||
            initrd = {
 | 
					            initrd = {
 | 
				
			||||||
@@ -135,12 +135,14 @@ in
 | 
				
			|||||||
            samba-wsdd.enable = true;
 | 
					            samba-wsdd.enable = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            minecraft-server = {
 | 
					            minecraft-server = {
 | 
				
			||||||
              enable = true;
 | 
					              enable = false;
 | 
				
			||||||
              package = pkgs.minecraftServers.vanilla-1-19;
 | 
					              package = pkgs.minecraftServers.vanilla-1-20;
 | 
				
			||||||
              declarative = true;
 | 
					              declarative = true;
 | 
				
			||||||
              eula = true;
 | 
					              eula = true;
 | 
				
			||||||
              whitelist = {
 | 
					              whitelist = {
 | 
				
			||||||
                devplayer0 = "6d7d971b-ce10-435b-85c5-c99c0d8d288c";
 | 
					                devplayer0 = "6d7d971b-ce10-435b-85c5-c99c0d8d288c";
 | 
				
			||||||
 | 
					                Elderlypug = "dcd2ecb9-2b5e-49cb-9d4f-f5a76162df56";
 | 
				
			||||||
 | 
					                shr3kas0ras = "1d366062-12c0-4e29-aba7-6ab5d8c6bb05";
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
              serverProperties = {
 | 
					              serverProperties = {
 | 
				
			||||||
                motd = "Simpcraft";
 | 
					                motd = "Simpcraft";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,23 +25,20 @@
 | 
				
			|||||||
            efi.canTouchEfiVariables = true;
 | 
					            efi.canTouchEfiVariables = true;
 | 
				
			||||||
            timeout = 10;
 | 
					            timeout = 10;
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
          kernelPackages = pkgs.linuxKernel.packages.linux_6_5;
 | 
					          kernelPackages = lib.my.c.kernel.latest pkgs;
 | 
				
			||||||
          kernelModules = [ "kvm-intel" ];
 | 
					          kernelModules = [ "kvm-intel" ];
 | 
				
			||||||
          kernelParams = [ "intel_iommu=on" ];
 | 
					          kernelParams = [ "intel_iommu=on" ];
 | 
				
			||||||
          initrd = {
 | 
					          initrd = {
 | 
				
			||||||
            availableKernelModules = [ "nvme" "xhci_pci" "usb_storage" "usbhid" "thunderbolt" ];
 | 
					            availableKernelModules = [ "nvme" "xhci_pci" "usb_storage" "usbhid" "thunderbolt" ];
 | 
				
			||||||
            luks = {
 | 
					            luks = {
 | 
				
			||||||
              reusePassphrases = true;
 | 
					 | 
				
			||||||
              devices = {
 | 
					              devices = {
 | 
				
			||||||
                persist = {
 | 
					                persist = {
 | 
				
			||||||
                  device = "/dev/disk/by-uuid/27840c6f-445c-4b95-8c39-e69d07219f33";
 | 
					                  device = "/dev/disk/by-uuid/27840c6f-445c-4b95-8c39-e69d07219f33";
 | 
				
			||||||
                  allowDiscards = true;
 | 
					                  allowDiscards = true;
 | 
				
			||||||
                  preLVM = false;
 | 
					 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                home = {
 | 
					                home = {
 | 
				
			||||||
                  device = "/dev/disk/by-uuid/c16c5038-7883-42c3-960a-a085a99364eb";
 | 
					                  device = "/dev/disk/by-uuid/c16c5038-7883-42c3-960a-a085a99364eb";
 | 
				
			||||||
                  allowDiscards = true;
 | 
					                  allowDiscards = true;
 | 
				
			||||||
                  preLVM = false;
 | 
					 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
@@ -110,10 +107,19 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          fprintd.enable = true;
 | 
					          fprintd.enable = true;
 | 
				
			||||||
          blueman.enable = true;
 | 
					          blueman.enable = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          tailscale = {
 | 
				
			||||||
 | 
					            enable = true;
 | 
				
			||||||
 | 
					            openFirewall = true;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        programs = {
 | 
					        programs = {
 | 
				
			||||||
          steam.enable = true;
 | 
					          steam.enable = true;
 | 
				
			||||||
 | 
					          wireshark = {
 | 
				
			||||||
 | 
					            enable = true;
 | 
				
			||||||
 | 
					            package = pkgs.wireshark-qt;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        networking = {
 | 
					        networking = {
 | 
				
			||||||
@@ -169,6 +175,14 @@
 | 
				
			|||||||
                packages = with pkgs; [ ];
 | 
					                packages = with pkgs; [ ];
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              programs = {
 | 
				
			||||||
 | 
					                fish = {
 | 
				
			||||||
 | 
					                  shellAbbrs = {
 | 
				
			||||||
 | 
					                    tsup = "doas tailscale up --login-server=https://ts.nul.ie --accept-routes";
 | 
				
			||||||
 | 
					                  };
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              services = {
 | 
					              services = {
 | 
				
			||||||
                blueman-applet.enable = true;
 | 
					                blueman-applet.enable = true;
 | 
				
			||||||
              };
 | 
					              };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
{ lib, pkgsFlakes, hmFlakes, inputs, pkgs', config, ... }:
 | 
					{ self, lib, pkgsFlakes, hmFlakes, inputs, pkgs', config, ... }:
 | 
				
			||||||
let
 | 
					let
 | 
				
			||||||
  inherit (builtins) attrValues mapAttrs;
 | 
					  inherit (builtins) attrValues mapAttrs;
 | 
				
			||||||
  inherit (lib)
 | 
					  inherit (lib)
 | 
				
			||||||
@@ -25,10 +25,14 @@ let
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      modules' = [ hmFlakes.${config'.home-manager}.nixosModule ] ++ (attrValues cfg.modules);
 | 
					      modules' = [ hmFlakes.${config'.home-manager}.nixosModule ] ++ (attrValues cfg.modules);
 | 
				
			||||||
    in
 | 
					    in
 | 
				
			||||||
    pkgsFlake.lib.nixosSystem {
 | 
					    # Import eval-config ourselves since the flake now force-sets lib
 | 
				
			||||||
 | 
					    import "${pkgsFlake}/nixos/lib/eval-config.nix" {
 | 
				
			||||||
      # Gotta override lib here unforunately, eval-config.nix likes to import its own (unextended) lib. We explicitly
 | 
					      # Gotta override lib here unforunately, eval-config.nix likes to import its own (unextended) lib. We explicitly
 | 
				
			||||||
      # don't pass pkgs so that it'll be imported with modularly applied config and overlays.
 | 
					      # don't pass pkgs so that it'll be imported with modularly applied config and overlays.
 | 
				
			||||||
      lib = pkgs.lib;
 | 
					      lib = pkgs.lib.extend (lib.my.versionOverlay { inherit self pkgsFlake; });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Set to null since we pass modularly
 | 
				
			||||||
 | 
					      system = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # Put the inputs in specialArgs to avoid infinite recursion when modules try to do imports
 | 
					      # Put the inputs in specialArgs to avoid infinite recursion when modules try to do imports
 | 
				
			||||||
      specialArgs = { inherit inputs pkgsFlakes pkgsFlake allAssignments; inherit (cfg) systems; };
 | 
					      specialArgs = { inherit inputs pkgsFlakes pkgsFlake allAssignments; inherit (cfg) systems; };
 | 
				
			||||||
@@ -51,7 +55,7 @@ let
 | 
				
			|||||||
            pkgs' = allPkgs;
 | 
					            pkgs' = allPkgs;
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          system.name = name;
 | 
					          system = { inherit name; };
 | 
				
			||||||
          networking = {
 | 
					          networking = {
 | 
				
			||||||
            domain = let d = config'.assignments.internal.domain or null; in mkIf (d != null) (mkDefault' d);
 | 
					            domain = let d = config'.assignments.internal.domain or null; in mkIf (d != null) (mkDefault' d);
 | 
				
			||||||
            hostName = mkDefault (config'.assignments.internal.name or name);
 | 
					            hostName = mkDefault (config'.assignments.internal.name or name);
 | 
				
			||||||
@@ -86,6 +90,8 @@ let
 | 
				
			|||||||
                  pkgsPath = toString pkgsFlakes.${config'.hmNixpkgs};
 | 
					                  pkgsPath = toString pkgsFlakes.${config'.hmNixpkgs};
 | 
				
			||||||
                  pkgs' = allPkgs;
 | 
					                  pkgs' = allPkgs;
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                home.enableNixpkgsReleaseCheck = false;
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              (homeStateVersion config'.home-manager)
 | 
					              (homeStateVersion config'.home-manager)
 | 
				
			||||||
            ];
 | 
					            ];
 | 
				
			||||||
@@ -100,6 +106,7 @@ let
 | 
				
			|||||||
      altNames = mkOpt' (listOf str) [ ] "Extra names to assign.";
 | 
					      altNames = mkOpt' (listOf str) [ ] "Extra names to assign.";
 | 
				
			||||||
      visible = mkBoolOpt' true "Whether or not this assignment should be visible.";
 | 
					      visible = mkBoolOpt' true "Whether or not this assignment should be visible.";
 | 
				
			||||||
      domain = mkOpt' (nullOr str) null "Domain for this assignment.";
 | 
					      domain = mkOpt' (nullOr str) null "Domain for this assignment.";
 | 
				
			||||||
 | 
					      mtu = mkOpt' (nullOr ints.unsigned) null "Interface MTU.";
 | 
				
			||||||
      ipv4 = {
 | 
					      ipv4 = {
 | 
				
			||||||
        address = mkOpt' net.types.ipv4 null "IPv4 address.";
 | 
					        address = mkOpt' net.types.ipv4 null "IPv4 address.";
 | 
				
			||||||
        mask = mkOpt' ints.u8 24 "Network mask.";
 | 
					        mask = mkOpt' ints.u8 24 "Network mask.";
 | 
				
			||||||
@@ -125,6 +132,9 @@ let
 | 
				
			|||||||
  l2MeshOpts = with lib.types; { name, ... }: {
 | 
					  l2MeshOpts = with lib.types; { name, ... }: {
 | 
				
			||||||
    options = {
 | 
					    options = {
 | 
				
			||||||
      interface = mkOpt' str name "Name of VXLAN interface.";
 | 
					      interface = mkOpt' str name "Name of VXLAN interface.";
 | 
				
			||||||
 | 
					      ipv6 = mkBoolOpt' false "Whether this mesh's underlay operates over IPv6.";
 | 
				
			||||||
 | 
					      baseMTU = mkOpt' ints.unsigned 1500 "Base MTU to calculate VXLAN MTU with.";
 | 
				
			||||||
 | 
					      l3Overhead = mkOpt' ints.unsigned 40 "Overhead of L3 header (to calculate MTU).";
 | 
				
			||||||
      firewall = mkBoolOpt' true "Whether to generate firewall rules.";
 | 
					      firewall = mkBoolOpt' true "Whether to generate firewall rules.";
 | 
				
			||||||
      vni = mkOpt' ints.unsigned 1 "VXLAN VNI.";
 | 
					      vni = mkOpt' ints.unsigned 1 "VXLAN VNI.";
 | 
				
			||||||
      peers = mkOpt' (attrsOf (submodule l2PeerOpts)) { } "Peers.";
 | 
					      peers = mkOpt' (attrsOf (submodule l2PeerOpts)) { } "Peers.";
 | 
				
			||||||
@@ -181,6 +191,11 @@ in
 | 
				
			|||||||
      secretsPath = mkOpt' path null "Path to encrypted secret files.";
 | 
					      secretsPath = mkOpt' path null "Path to encrypted secret files.";
 | 
				
			||||||
      modules = mkOpt' (attrsOf commonOpts.moduleType) { } "NixOS modules to be exported by nixfiles.";
 | 
					      modules = mkOpt' (attrsOf commonOpts.moduleType) { } "NixOS modules to be exported by nixfiles.";
 | 
				
			||||||
      systems = mkOpt' (attrsOf (submodule systemOpts)) { } "NixOS systems to be exported by nixfiles.";
 | 
					      systems = mkOpt' (attrsOf (submodule systemOpts)) { } "NixOS systems to be exported by nixfiles.";
 | 
				
			||||||
 | 
					      allAssignments = mkOption {
 | 
				
			||||||
 | 
					        type = attrsOf (attrsOf (submodule assignmentOpts));
 | 
				
			||||||
 | 
					        description = "All network assignments.";
 | 
				
			||||||
 | 
					        readOnly = true;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
      vpns = {
 | 
					      vpns = {
 | 
				
			||||||
        l2 = mkOpt' (attrsOf (submodule l2MeshOpts)) { } "Layer 2 meshes.";
 | 
					        l2 = mkOpt' (attrsOf (submodule l2MeshOpts)) { } "Layer 2 meshes.";
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
@@ -206,5 +221,9 @@ in
 | 
				
			|||||||
        message = "Duplicate assignments: ${toString dupIPs}";
 | 
					        message = "Duplicate assignments: ${toString dupIPs}";
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nixos = {
 | 
				
			||||||
 | 
					      inherit allAssignments;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,8 @@
 | 
				
			|||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          isoImage = {
 | 
					          isoImage = {
 | 
				
			||||||
            isoBaseName = "nixos-installer-devplayer0";
 | 
					            isoBaseName = "jackos-installer";
 | 
				
			||||||
 | 
					            volumeID = "jackos-${config.system.nixos.release}-${pkgs.stdenv.hostPlatform.uname.processor}";
 | 
				
			||||||
            edition = "devplayer0";
 | 
					            edition = "devplayer0";
 | 
				
			||||||
            appendToMenuLabel = " /dev/player0 Installer";
 | 
					            appendToMenuLabel = " /dev/player0 Installer";
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,5 +17,8 @@
 | 
				
			|||||||
    gui = ./gui.nix;
 | 
					    gui = ./gui.nix;
 | 
				
			||||||
    l2mesh = ./l2mesh.nix;
 | 
					    l2mesh = ./l2mesh.nix;
 | 
				
			||||||
    borgthin = ./borgthin.nix;
 | 
					    borgthin = ./borgthin.nix;
 | 
				
			||||||
 | 
					    nvme = ./nvme;
 | 
				
			||||||
 | 
					    spdk = ./spdk.nix;
 | 
				
			||||||
 | 
					    librespeed = ./librespeed;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,9 @@ let
 | 
				
			|||||||
      "${modulesPath}/installer/cd-dvd/iso-image.nix"
 | 
					      "${modulesPath}/installer/cd-dvd/iso-image.nix"
 | 
				
			||||||
      allHardware
 | 
					      allHardware
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
 | 
					        # Doesn't work right now... (missing /dev/root)
 | 
				
			||||||
 | 
					        boot.initrd.systemd.enable = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        isoImage = {
 | 
					        isoImage = {
 | 
				
			||||||
          makeEfiBootable = true;
 | 
					          makeEfiBootable = true;
 | 
				
			||||||
          makeUsbBootable = true;
 | 
					          makeUsbBootable = true;
 | 
				
			||||||
@@ -40,6 +43,16 @@ let
 | 
				
			|||||||
    modules = flatten [
 | 
					    modules = flatten [
 | 
				
			||||||
      "${modulesPath}/installer/netboot/netboot.nix"
 | 
					      "${modulesPath}/installer/netboot/netboot.nix"
 | 
				
			||||||
      allHardware
 | 
					      allHardware
 | 
				
			||||||
 | 
					      ({ pkgs, config, ... }: {
 | 
				
			||||||
 | 
					        system.build.netbootArchive = pkgs.runCommand "netboot-${config.system.name}-archive.tar" { } ''
 | 
				
			||||||
 | 
					          ${pkgs.gnutar}/bin/tar -rvC "${config.system.build.kernel}" \
 | 
				
			||||||
 | 
					            -f "$out" "${config.system.boot.loader.kernelFile}"
 | 
				
			||||||
 | 
					          ${pkgs.gnutar}/bin/tar -rvC "${config.system.build.netbootRamdisk}" \
 | 
				
			||||||
 | 
					            -f "$out" initrd
 | 
				
			||||||
 | 
					          ${pkgs.gnutar}/bin/tar -rvC "${config.system.build.netbootIpxeScript}" \
 | 
				
			||||||
 | 
					            -f "$out" netboot.ipxe
 | 
				
			||||||
 | 
					        '';
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -79,6 +92,7 @@ in
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
    isoImage = {
 | 
					    isoImage = {
 | 
				
			||||||
      isoBaseName = dummyOption;
 | 
					      isoBaseName = dummyOption;
 | 
				
			||||||
 | 
					      volumeID = dummyOption;
 | 
				
			||||||
      edition = dummyOption;
 | 
					      edition = dummyOption;
 | 
				
			||||||
      appendToMenuLabel = dummyOption;
 | 
					      appendToMenuLabel = dummyOption;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -96,6 +110,7 @@ in
 | 
				
			|||||||
        iso = config.my.asISO.config.system.build.isoImage;
 | 
					        iso = config.my.asISO.config.system.build.isoImage;
 | 
				
			||||||
        container = config.my.asContainer.config.system.build.toplevel;
 | 
					        container = config.my.asContainer.config.system.build.toplevel;
 | 
				
			||||||
        kexecTree = config.my.asKexecTree.config.system.build.kexecTree;
 | 
					        kexecTree = config.my.asKexecTree.config.system.build.kexecTree;
 | 
				
			||||||
 | 
					        netbootArchive = config.my.asKexecTree.config.system.build.netbootArchive;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
{ lib, pkgs, pkgs', inputs, config, ... }:
 | 
					{ lib, pkgs, pkgs', inputs, config, ... }:
 | 
				
			||||||
let
 | 
					let
 | 
				
			||||||
  inherit (lib) mkIf mkDefault mkMerge;
 | 
					  inherit (lib) mkIf mkDefault mkMerge;
 | 
				
			||||||
  inherit (lib.my) mkBoolOpt' dummyOption;
 | 
					  inherit (lib.my) mkDefault';
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  options = with lib.types; {
 | 
					  options = with lib.types; {
 | 
				
			||||||
@@ -41,14 +41,13 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      nix = {
 | 
					      nix = {
 | 
				
			||||||
        package = pkgs'.mine.nix;
 | 
					        package = pkgs'.mine.nix;
 | 
				
			||||||
        settings = {
 | 
					        settings = with lib.my.c.nix; {
 | 
				
			||||||
          trusted-users = [ "@wheel" ];
 | 
					          trusted-users = [ "@wheel" ];
 | 
				
			||||||
          experimental-features = [ "nix-command" "flakes" "ca-derivations" ];
 | 
					          experimental-features = [ "nix-command" "flakes" "ca-derivations" ];
 | 
				
			||||||
          substituters = [
 | 
					          extra-substituters = cache.substituters;
 | 
				
			||||||
            #"https://nix-cache.nul.ie"
 | 
					          extra-trusted-public-keys = cache.keys;
 | 
				
			||||||
            "https://cache.nixos.org"
 | 
					          connect-timeout = 5;
 | 
				
			||||||
          ];
 | 
					          fallback = true;
 | 
				
			||||||
          trusted-public-keys = lib.my.c.nix.cacheKeys;
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        registry = {
 | 
					        registry = {
 | 
				
			||||||
          pkgs = {
 | 
					          pkgs = {
 | 
				
			||||||
@@ -89,12 +88,13 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      boot = {
 | 
					      boot = {
 | 
				
			||||||
        # Use latest LTS release by default
 | 
					        # Use latest LTS release by default
 | 
				
			||||||
        kernelPackages = mkDefault pkgs.linuxKernel.packages.linux_6_1;
 | 
					        kernelPackages = mkDefault (lib.my.c.kernel.lts pkgs);
 | 
				
			||||||
        kernel = {
 | 
					        kernel = {
 | 
				
			||||||
          sysctl = {
 | 
					          sysctl = {
 | 
				
			||||||
            "net.ipv6.route.max_size" = mkDefault 16384;
 | 
					            "net.ipv6.route.max_size" = mkDefault 16384;
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        loader = {
 | 
					        loader = {
 | 
				
			||||||
          efi = {
 | 
					          efi = {
 | 
				
			||||||
            efiSysMountPoint = mkDefault "/boot";
 | 
					            efiSysMountPoint = mkDefault "/boot";
 | 
				
			||||||
@@ -112,12 +112,24 @@ in
 | 
				
			|||||||
            memtest86.enable = mkDefault true;
 | 
					            memtest86.enable = mkDefault true;
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        initrd = {
 | 
				
			||||||
 | 
					          systemd = {
 | 
				
			||||||
 | 
					            enable = mkDefault true;
 | 
				
			||||||
 | 
					            emergencyAccess = mkDefault true;
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          services.lvm.enable = mkDefault true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      system = {
 | 
				
			||||||
 | 
					        nixos = {
 | 
				
			||||||
 | 
					          distroName = mkDefault' "JackOS";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      environment.systemPackages = with pkgs; mkMerge [
 | 
					      environment.systemPackages = with pkgs; mkMerge [
 | 
				
			||||||
        [
 | 
					        [
 | 
				
			||||||
          bash-completion
 | 
					          bash-completion
 | 
				
			||||||
          vim
 | 
					 | 
				
			||||||
          git
 | 
					          git
 | 
				
			||||||
          unzip
 | 
					          unzip
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
@@ -130,6 +142,7 @@ in
 | 
				
			|||||||
        fish.enable = mkDefault true;
 | 
					        fish.enable = mkDefault true;
 | 
				
			||||||
        # TODO: This is expecting to look up the channel for the database...
 | 
					        # TODO: This is expecting to look up the channel for the database...
 | 
				
			||||||
        command-not-found.enable = mkDefault false;
 | 
					        command-not-found.enable = mkDefault false;
 | 
				
			||||||
 | 
					        vim.defaultEditor = true;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      services = {
 | 
					      services = {
 | 
				
			||||||
@@ -143,6 +156,7 @@ in
 | 
				
			|||||||
              font-name=SauceCodePro Nerd Font Mono
 | 
					              font-name=SauceCodePro Nerd Font Mono
 | 
				
			||||||
            '';
 | 
					            '';
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					        getty.greetingLine = mkDefault' ''<<< Welcome to ${config.system.nixos.distroName} ${config.system.nixos.label} (\m) - \l >>>'';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        openssh = {
 | 
					        openssh = {
 | 
				
			||||||
          enable = mkDefault true;
 | 
					          enable = mkDefault true;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -208,7 +208,17 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            mkdir -p -m 0755 "$root"/sbin "$root"/etc
 | 
					            mkdir -p -m 0755 "$root"/sbin "$root"/etc
 | 
				
			||||||
            touch "$root"/etc/os-release
 | 
					            touch "$root"/etc/os-release
 | 
				
			||||||
            ln -sf "${containerSystem}"/init "$root"/sbin/init
 | 
					
 | 
				
			||||||
 | 
					            ${if system == sysProfile then ''
 | 
				
			||||||
 | 
					              if [ -e "${sysProfile}"/prepare-root ]; then
 | 
				
			||||||
 | 
					                initSource="${containerSystem}"/prepare-root
 | 
				
			||||||
 | 
					              else
 | 
				
			||||||
 | 
					                initSource="${containerSystem}"/init
 | 
				
			||||||
 | 
					              fi
 | 
				
			||||||
 | 
					              ln -sf "$initSource" "$root"/sbin/init
 | 
				
			||||||
 | 
					            '' else ''
 | 
				
			||||||
 | 
					              ln -sf "${containerSystem}/prepare-root" "$root"/sbin/init
 | 
				
			||||||
 | 
					            ''}
 | 
				
			||||||
          '';
 | 
					          '';
 | 
				
			||||||
          postStop =
 | 
					          postStop =
 | 
				
			||||||
          ''
 | 
					          ''
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,16 +15,20 @@ let
 | 
				
			|||||||
  # Based on https://github.com/serokell/deploy-rs/blob/master/flake.nix
 | 
					  # Based on https://github.com/serokell/deploy-rs/blob/master/flake.nix
 | 
				
			||||||
  nixosActivate = cfg': base: (pkgs.deploy-rs.lib.activate.custom // {
 | 
					  nixosActivate = cfg': base: (pkgs.deploy-rs.lib.activate.custom // {
 | 
				
			||||||
    dryActivate = "$PROFILE/bin/switch-to-configuration dry-activate";
 | 
					    dryActivate = "$PROFILE/bin/switch-to-configuration dry-activate";
 | 
				
			||||||
    boot = "$PROFILE/bin/switch-to-configuration boot";
 | 
					    boot = ''
 | 
				
			||||||
 | 
					      $PROFILE/bin/switch-to-configuration boot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ${keepGensSnippet "$PROFILE" cfg'.keepGenerations}
 | 
				
			||||||
 | 
					    '';
 | 
				
			||||||
  }) base.config.system.build.toplevel ''
 | 
					  }) base.config.system.build.toplevel ''
 | 
				
			||||||
    # work around https://github.com/NixOS/nixpkgs/issues/73404
 | 
					    # work around https://github.com/NixOS/nixpkgs/issues/73404
 | 
				
			||||||
    cd /tmp
 | 
					    cd /tmp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "$PROFILE"/bin/switch-to-configuration ${cfg'.mode}
 | 
					    "$PROFILE"/bin/switch-to-configuration switch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # https://github.com/serokell/deploy-rs/issues/31
 | 
					    # https://github.com/serokell/deploy-rs/issues/31
 | 
				
			||||||
    ${with base.config.boot.loader;
 | 
					    ${with base.config.boot.loader;
 | 
				
			||||||
    optionalString ((cfg'.mode == "switch" || cfg'.mode == "boot") && systemd-boot.enable)
 | 
					    optionalString systemd-boot.enable
 | 
				
			||||||
    "sed -i '/^default /d' ${efi.efiSysMountPoint}/loader/loader.conf"}
 | 
					    "sed -i '/^default /d' ${efi.efiSysMountPoint}/loader/loader.conf"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ${keepGensSnippet "$PROFILE" cfg'.keepGenerations}
 | 
					    ${keepGensSnippet "$PROFILE" cfg'.keepGenerations}
 | 
				
			||||||
@@ -59,7 +63,11 @@ let
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    name = "container-${n}";
 | 
					    name = "container-${n}";
 | 
				
			||||||
    value = {
 | 
					    value = {
 | 
				
			||||||
      path = pkgs.deploy-rs.lib.activate.custom ctrConfig.my.buildAs.container ''
 | 
					      path = (pkgs.deploy-rs.lib.activate.custom // {
 | 
				
			||||||
 | 
					        boot = ''
 | 
				
			||||||
 | 
					          echo "Next systemd-nspawn@${n}.service restart / reload will load config"
 | 
				
			||||||
 | 
					        '';
 | 
				
			||||||
 | 
					      }) ctrConfig.my.buildAs.container ''
 | 
				
			||||||
        source ${systemdUtil}/bin/systemd-util.sh
 | 
					        source ${systemdUtil}/bin/systemd-util.sh
 | 
				
			||||||
        ${if c.hotReload then ''
 | 
					        ${if c.hotReload then ''
 | 
				
			||||||
          if (! systemctl show -p ActiveState systemd-nspawn@${n} | grep -q "ActiveState=active") || \
 | 
					          if (! systemctl show -p ActiveState systemd-nspawn@${n} | grep -q "ActiveState=active") || \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,9 @@
 | 
				
			|||||||
{ lib, options, config, ... }:
 | 
					{ lib, options, config, ... }:
 | 
				
			||||||
let
 | 
					let
 | 
				
			||||||
  inherit (lib) optionalString concatStringsSep concatMapStringsSep optionalAttrs mkIf mkDefault mkMerge mkOverride;
 | 
					  inherit (builtins) typeOf attrNames;
 | 
				
			||||||
 | 
					  inherit (lib)
 | 
				
			||||||
 | 
					    optionalString concatStringsSep concatMapStringsSep mapAttrsToList optionalAttrs mkIf
 | 
				
			||||||
 | 
					    mkDefault mkMerge mkOverride;
 | 
				
			||||||
  inherit (lib.my) isIPv6 mkOpt' mkBoolOpt';
 | 
					  inherit (lib.my) isIPv6 mkOpt' mkBoolOpt';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  allowICMP = ''
 | 
					  allowICMP = ''
 | 
				
			||||||
@@ -63,8 +66,8 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    nat = with options.networking.nat; {
 | 
					    nat = with options.networking.nat; {
 | 
				
			||||||
      enable = mkBoolOpt' true "Whether to enable IP forwarding and NAT.";
 | 
					      enable = mkBoolOpt' true "Whether to enable IP forwarding and NAT.";
 | 
				
			||||||
      inherit externalInterface externalIP;
 | 
					      inherit externalInterface;
 | 
				
			||||||
      forwardPorts = mkOpt' (listOf (submodule forwardOpts)) [ ] "List of port forwards.";
 | 
					      forwardPorts = mkOpt' (either (listOf (submodule forwardOpts)) (attrsOf (listOf (submodule forwardOpts)))) [ ] "IPv4 port forwards";
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -131,9 +134,15 @@ in
 | 
				
			|||||||
                chain prerouting {
 | 
					                chain prerouting {
 | 
				
			||||||
                  type nat hook prerouting priority dstnat;
 | 
					                  type nat hook prerouting priority dstnat;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                chain output {
 | 
				
			||||||
 | 
					                  type nat hook output priority dstnat;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                chain postrouting {
 | 
					                chain postrouting {
 | 
				
			||||||
                  type nat hook postrouting priority srcnat;
 | 
					                  type nat hook postrouting priority srcnat;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                chain input {
 | 
				
			||||||
 | 
					                  type nat hook input priority srcnat;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              ${cfg.extraRules}
 | 
					              ${cfg.extraRules}
 | 
				
			||||||
@@ -141,11 +150,16 @@ in
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    (mkIf cfg.nat.enable {
 | 
					    (mkIf cfg.nat.enable (
 | 
				
			||||||
 | 
					    let
 | 
				
			||||||
 | 
					      iifForward = typeOf cfg.nat.forwardPorts == "list" && cfg.nat.forwardPorts != [ ];
 | 
				
			||||||
 | 
					      dipForward = typeOf cfg.nat.forwardPorts == "set" && cfg.nat.forwardPorts != { };
 | 
				
			||||||
 | 
					    in
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
      assertions = [
 | 
					      assertions = [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          assertion = with cfg.nat; (forwardPorts != [ ]) -> (externalInterface != null);
 | 
					          assertion = with cfg.nat; iifForward -> (externalInterface != null);
 | 
				
			||||||
          message = "my.firewall.nat.forwardPorts requires my.firewall.nat.external{Interface,IP}";
 | 
					          message = "my.firewall.nat.forwardPorts as list requires my.firewall.nat.externalInterface";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -168,43 +182,75 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      my.firewall.extraRules =
 | 
					      my.firewall.extraRules =
 | 
				
			||||||
        let
 | 
					        let
 | 
				
			||||||
 | 
					          inherit (lib.my.nft) natFilterChain dnatChain;
 | 
				
			||||||
 | 
					          ipK = ip: "ip${optionalString (isIPv6 ip) "6"}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          makeFilter = f:
 | 
					          makeFilter = f:
 | 
				
			||||||
          let
 | 
					            "${ipK f.dst} daddr ${f.dst} ${f.proto} dport ${toString f.dstPort} accept";
 | 
				
			||||||
            v6 = isIPv6 f.dst;
 | 
					 | 
				
			||||||
          in
 | 
					 | 
				
			||||||
            "ip${optionalString v6 "6"} daddr ${f.dst} ${f.proto} dport ${toString f.dstPort} accept";
 | 
					 | 
				
			||||||
          makeForward = f:
 | 
					          makeForward = f:
 | 
				
			||||||
            let
 | 
					            "${f.proto} dport ${toString f.port} dnat ${ipK f.dst} to ${f.dst}:${toString f.dstPort}";
 | 
				
			||||||
              v6 = isIPv6 f.dst;
 | 
					
 | 
				
			||||||
            in
 | 
					          dnatJumps = ''
 | 
				
			||||||
              "${f.proto} dport ${toString f.port} dnat ip${optionalString v6 "6"} to ${f.dst}:${toString f.dstPort}";
 | 
					            ${optionalString
 | 
				
			||||||
 | 
					              iifForward
 | 
				
			||||||
 | 
					              "iifname ${cfg.nat.externalInterface} jump iif-port-forward"}
 | 
				
			||||||
 | 
					            ${optionalString
 | 
				
			||||||
 | 
					              dipForward
 | 
				
			||||||
 | 
					              (concatMapStringsSep "\n    " (ip: "${ipK ip} daddr ${ip} jump ${dnatChain ip}") (attrNames cfg.nat.forwardPorts))}
 | 
				
			||||||
 | 
					          '';
 | 
				
			||||||
        in
 | 
					        in
 | 
				
			||||||
        ''
 | 
					        ''
 | 
				
			||||||
          table inet filter {
 | 
					          table inet filter {
 | 
				
			||||||
            chain filter-port-forwards {
 | 
					            ${optionalString iifForward ''
 | 
				
			||||||
              ${concatMapStringsSep "\n    " makeFilter cfg.nat.forwardPorts}
 | 
					              chain filter-iif-port-forwards {
 | 
				
			||||||
              return
 | 
					                ${concatMapStringsSep "\n    " makeFilter cfg.nat.forwardPorts}
 | 
				
			||||||
            }
 | 
					                return
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            ''}
 | 
				
			||||||
 | 
					            ${optionalString
 | 
				
			||||||
 | 
					              dipForward
 | 
				
			||||||
 | 
					              (concatStringsSep "\n" (mapAttrsToList (ip: fs: ''
 | 
				
			||||||
 | 
					                chain ${natFilterChain ip} {
 | 
				
			||||||
 | 
					                  ${concatMapStringsSep "\n    " makeFilter fs}
 | 
				
			||||||
 | 
					                  return
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              '') cfg.nat.forwardPorts))}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            chain forward {
 | 
					            chain forward {
 | 
				
			||||||
              ${optionalString
 | 
					              ${optionalString
 | 
				
			||||||
                (cfg.nat.externalInterface != null)
 | 
					                iifForward
 | 
				
			||||||
                "iifname ${cfg.nat.externalInterface} jump filter-port-forwards"}
 | 
					                "iifname ${cfg.nat.externalInterface} jump filter-iif-port-forwards"}
 | 
				
			||||||
 | 
					              ${optionalString
 | 
				
			||||||
 | 
					                dipForward
 | 
				
			||||||
 | 
					                (concatMapStringsSep "\n    " (ip: "jump ${natFilterChain ip}") (attrNames cfg.nat.forwardPorts))}
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          table inet nat {
 | 
					          table inet nat {
 | 
				
			||||||
            chain port-forward {
 | 
					            ${optionalString iifForward ''
 | 
				
			||||||
              ${concatMapStringsSep "\n    " makeForward cfg.nat.forwardPorts}
 | 
					              chain iif-port-forward {
 | 
				
			||||||
              return
 | 
					                ${concatMapStringsSep "\n    " makeForward cfg.nat.forwardPorts}
 | 
				
			||||||
            }
 | 
					                return
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            ''}
 | 
				
			||||||
 | 
					            ${optionalString
 | 
				
			||||||
 | 
					              dipForward
 | 
				
			||||||
 | 
					              (concatStringsSep "\n" (mapAttrsToList (ip: fs: ''
 | 
				
			||||||
 | 
					                chain ${dnatChain ip} {
 | 
				
			||||||
 | 
					                  ${concatMapStringsSep "\n    " makeForward fs}
 | 
				
			||||||
 | 
					                  return
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              '') cfg.nat.forwardPorts))}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            chain prerouting {
 | 
					            chain prerouting {
 | 
				
			||||||
              ${optionalString
 | 
					              ${dnatJumps}
 | 
				
			||||||
                (cfg.nat.externalInterface != null)
 | 
					            }
 | 
				
			||||||
                "${if (cfg.nat.externalIP != null) then "ip daddr ${cfg.nat.externalIP}" else "iifname ${cfg.nat.externalInterface}"} jump port-forward"}
 | 
					            chain output {
 | 
				
			||||||
 | 
					              ${dnatJumps}
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        '';
 | 
					        '';
 | 
				
			||||||
    })
 | 
					    }))
 | 
				
			||||||
  ]);
 | 
					  ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  meta.buildDocsInSandbox = false;
 | 
					  meta.buildDocsInSandbox = false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,7 +57,7 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    programs.dconf.enable = true;
 | 
					    programs.dconf.enable = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fonts.fonts = with pkgs; [
 | 
					    fonts.packages = with pkgs; [
 | 
				
			||||||
      dejavu_fonts
 | 
					      dejavu_fonts
 | 
				
			||||||
      freefont_ttf
 | 
					      freefont_ttf
 | 
				
			||||||
      gyre-fonts # TrueType substitutes for standard PostScript fonts
 | 
					      gyre-fonts # TrueType substitutes for standard PostScript fonts
 | 
				
			||||||
@@ -69,8 +69,19 @@ in
 | 
				
			|||||||
    xdg = {
 | 
					    xdg = {
 | 
				
			||||||
      portal = {
 | 
					      portal = {
 | 
				
			||||||
        enable = true;
 | 
					        enable = true;
 | 
				
			||||||
 | 
					        extraPortals = with pkgs; [
 | 
				
			||||||
 | 
					          xdg-desktop-portal-gtk
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
        # For sway
 | 
					        # For sway
 | 
				
			||||||
        wlr.enable = true;
 | 
					        wlr.enable = true;
 | 
				
			||||||
 | 
					        configPackages = [
 | 
				
			||||||
 | 
					          (pkgs.writeTextDir "share/xdg-desktop-portal/sway-portals.conf" ''
 | 
				
			||||||
 | 
					            [preferred]
 | 
				
			||||||
 | 
					            default=gtk
 | 
				
			||||||
 | 
					            org.freedesktop.impl.portal.Screenshot=wlr
 | 
				
			||||||
 | 
					            org.freedesktop.impl.portal.ScreenCast=wlr
 | 
				
			||||||
 | 
					          '')
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
{ lib, pkgs, config, vpns, ... }:
 | 
					{ lib, config, vpns, ... }:
 | 
				
			||||||
let
 | 
					let
 | 
				
			||||||
  inherit (lib) optionalString mapAttrsToList concatStringsSep filterAttrs mkIf mkMerge;
 | 
					  inherit (builtins) any attrValues;
 | 
				
			||||||
  inherit (lib.my) isIPv6;
 | 
					  inherit (lib) optionalString mapAttrsToList concatStringsSep concatMapStringsSep filterAttrs mkIf mkMerge;
 | 
				
			||||||
 | 
					  inherit (lib.my) isIPv6 mkOpt';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  vxlanPort = 4789;
 | 
					  vxlanPort = 4789;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,38 +25,34 @@ let
 | 
				
			|||||||
        Local = ownAddr;
 | 
					        Local = ownAddr;
 | 
				
			||||||
        MacLearning = true;
 | 
					        MacLearning = true;
 | 
				
			||||||
        DestinationPort = vxlanPort;
 | 
					        DestinationPort = vxlanPort;
 | 
				
			||||||
 | 
					        PortRange = "${toString vxlanPort}-${toString (vxlanPort + 1)}";
 | 
				
			||||||
        Independent = true;
 | 
					        Independent = true;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    links."20-l2mesh-${name}" = {
 | 
					 | 
				
			||||||
      matchConfig.Name = mesh.interface;
 | 
					 | 
				
			||||||
      # TODO: ipv6? ipsec?
 | 
					 | 
				
			||||||
      linkConfig.MTUBytes = "1450";
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    networks."90-l2mesh-${name}" = {
 | 
					    networks."90-l2mesh-${name}" = {
 | 
				
			||||||
      matchConfig.Name = mesh.interface;
 | 
					      matchConfig.Name = mesh.interface;
 | 
				
			||||||
      extraConfig = concatStringsSep "\n" (mapAttrsToList (n: peer: ''
 | 
					      linkConfig.MTUBytes =
 | 
				
			||||||
        [BridgeFDB]
 | 
					      let
 | 
				
			||||||
        MACAddress=00:00:00:00:00:00
 | 
					        espOverhead =
 | 
				
			||||||
        Destination=${peer.addr}
 | 
					          if (!mesh.security.enable) then 0
 | 
				
			||||||
      '') otherPeers);
 | 
					          else
 | 
				
			||||||
 | 
					            # SPI + seq + IV + pad / header + ICV
 | 
				
			||||||
 | 
					            4 + 4 + (if mesh.security.encrypt then 8 else 0) + 2 + 16;
 | 
				
			||||||
 | 
					        # UDP + VXLAN + Ethernet + L3 (IPv4/IPv6)
 | 
				
			||||||
 | 
					        overhead = espOverhead + 8 + 8 + 14 + mesh.l3Overhead;
 | 
				
			||||||
 | 
					      in
 | 
				
			||||||
 | 
					      toString (mesh.baseMTU - overhead);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      bridgeFDBs = mapAttrsToList (n: peer: {
 | 
				
			||||||
 | 
					        bridgeFDBConfig = {
 | 
				
			||||||
 | 
					          MACAddress = "00:00:00:00:00:00";
 | 
				
			||||||
 | 
					          Destination = peer.addr;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }) otherPeers;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mkLibreswanConfig = name: mesh: with info mesh; {
 | 
					  vxlanAllow = vni: "udp dport ${toString vxlanPort} @th,96,24 ${toString vni} accept";
 | 
				
			||||||
    enable = true;
 | 
					 | 
				
			||||||
    # TODO: finish this...
 | 
					 | 
				
			||||||
    connections."l2mesh-${name}" = ''
 | 
					 | 
				
			||||||
      keyexchange=ike
 | 
					 | 
				
			||||||
      type=transport
 | 
					 | 
				
			||||||
      left=${ownAddr}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      auto=start
 | 
					 | 
				
			||||||
      phase2=esp
 | 
					 | 
				
			||||||
      ikev2=yes
 | 
					 | 
				
			||||||
    '';
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  mkFirewallConfig = name: mesh: with info mesh;
 | 
					  mkFirewallConfig = name: mesh: with info mesh;
 | 
				
			||||||
  let
 | 
					  let
 | 
				
			||||||
    netProto = if (isIPv6 ownAddr) then "ip6" else "ip";
 | 
					    netProto = if (isIPv6 ownAddr) then "ip6" else "ip";
 | 
				
			||||||
@@ -63,8 +60,11 @@ let
 | 
				
			|||||||
  ''
 | 
					  ''
 | 
				
			||||||
    table inet filter {
 | 
					    table inet filter {
 | 
				
			||||||
      chain l2mesh-${name} {
 | 
					      chain l2mesh-${name} {
 | 
				
			||||||
        ${optionalString mesh.security.enable "meta l4proto esp accept"}
 | 
					        ${optionalString mesh.security.enable ''
 | 
				
			||||||
        udp dport ${toString vxlanPort} @th,96,24 ${toString mesh.vni} accept
 | 
					          udp dport isakmp accept
 | 
				
			||||||
 | 
					          meta l4proto esp accept
 | 
				
			||||||
 | 
					        ''}
 | 
				
			||||||
 | 
					        ${optionalString (!mesh.security.enable) (vxlanAllow mesh.vni)}
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chain input {
 | 
					      chain input {
 | 
				
			||||||
@@ -72,12 +72,63 @@ let
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  '';
 | 
					  '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mkLibreswanConfig = name: mesh: with info mesh; {
 | 
				
			||||||
 | 
					    enable = true;
 | 
				
			||||||
 | 
					    connections = mkMerge (mapAttrsToList
 | 
				
			||||||
 | 
					      (pName: peer: {
 | 
				
			||||||
 | 
					        "l2mesh-${name}-${pName}" = ''
 | 
				
			||||||
 | 
					          keyexchange=ike
 | 
				
			||||||
 | 
					          hostaddrfamily=ipv${if mesh.ipv6 then "6" else "4"}
 | 
				
			||||||
 | 
					          type=transport
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          left=${ownAddr}
 | 
				
			||||||
 | 
					          leftprotoport=udp/${toString vxlanPort}
 | 
				
			||||||
 | 
					          right=${peer.addr}
 | 
				
			||||||
 | 
					          rightprotoport=udp/${toString vxlanPort}
 | 
				
			||||||
 | 
					          rightupdown=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          auto=start
 | 
				
			||||||
 | 
					          authby=secret
 | 
				
			||||||
 | 
					          phase2=esp
 | 
				
			||||||
 | 
					          esp=${if mesh.security.encrypt then "aes_gcm256" else "null-sha256"}
 | 
				
			||||||
 | 
					          ikev2=yes
 | 
				
			||||||
 | 
					          modecfgpull=no
 | 
				
			||||||
 | 
					        '';
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    otherPeers);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  genSecrets = name: mesh: with info mesh; concatMapStringsSep "\n" (p: ''
 | 
				
			||||||
 | 
					    echo "${ownAddr} ${p.addr} : PSK \"$(< "${config.my.vpns.l2.pskFiles.${name}}")\"" >> /run/l2mesh.secrets
 | 
				
			||||||
 | 
					  '') (attrValues otherPeers);
 | 
				
			||||||
 | 
					  anySecurity = any (c: c.security.enable) (attrValues memberMeshes);
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  options = {
 | 
				
			||||||
 | 
					    my.vpns.l2 = with lib.types; {
 | 
				
			||||||
 | 
					      pskFiles = mkOpt' (attrsOf str) { } "PSK files for secured meshes.";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  config = {
 | 
					  config = {
 | 
				
			||||||
    systemd.network = mkMerge (mapAttrsToList mkNetConfig memberMeshes);
 | 
					    systemd.network = mkMerge (mapAttrsToList mkNetConfig memberMeshes);
 | 
				
			||||||
    # TODO: finish this...
 | 
					
 | 
				
			||||||
    #services.libreswan = mkMerge (mapAttrsToList mkLibreswanConfig (filterAttrs (_: c: c.security.enable) memberMeshes));
 | 
					    environment.etc."ipsec.d/l2mesh.secrets" = mkIf anySecurity {
 | 
				
			||||||
 | 
					      source = "/run/l2mesh.secrets";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    systemd.services.ipsec = mkIf anySecurity {
 | 
				
			||||||
 | 
					      preStart = ''
 | 
				
			||||||
 | 
					        oldUmask="$(umask)"
 | 
				
			||||||
 | 
					        umask 006
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        > /run/l2mesh.secrets
 | 
				
			||||||
 | 
					        ${concatStringsSep "\n" (mapAttrsToList genSecrets memberMeshes)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        umask "$oldUmask"
 | 
				
			||||||
 | 
					      '';
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    services.libreswan = mkMerge (mapAttrsToList mkLibreswanConfig (filterAttrs (_: c: c.security.enable) memberMeshes));
 | 
				
			||||||
    my.firewall.extraRules = concatStringsSep "\n" (mapAttrsToList mkFirewallConfig (filterAttrs (_: c: c.firewall) memberMeshes));
 | 
					    my.firewall.extraRules = concatStringsSep "\n" (mapAttrsToList mkFirewallConfig (filterAttrs (_: c: c.firewall) memberMeshes));
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										76
									
								
								nixos/modules/librespeed/default.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								nixos/modules/librespeed/default.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					{ lib, pkgs, config, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (builtins) toJSON;
 | 
				
			||||||
 | 
					  inherit (lib) mkOption mkMerge mkIf mkDefault;
 | 
				
			||||||
 | 
					  inherit (lib.my) mkOpt' mkBoolOpt';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cfg = config.my.librespeed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  serversConf = map (s: s // {
 | 
				
			||||||
 | 
					    dlURL = "backend/garbage";
 | 
				
			||||||
 | 
					    ulURL = "backend/empty";
 | 
				
			||||||
 | 
					    pingURL = "backend/empty";
 | 
				
			||||||
 | 
					    getIpURL = "backend/getIP";
 | 
				
			||||||
 | 
					  }) cfg.frontend.servers;
 | 
				
			||||||
 | 
					  frontendTree = pkgs.runCommand "librespeed-frontend" {
 | 
				
			||||||
 | 
					    speedtestServers = toJSON serversConf;
 | 
				
			||||||
 | 
					  } ''
 | 
				
			||||||
 | 
					    mkdir "$out"
 | 
				
			||||||
 | 
					    cp "${pkgs.librespeed-go}"/assets/* "$out"/
 | 
				
			||||||
 | 
					    substitute ${./index.html} "$out"/index.html --subst-var speedtestServers
 | 
				
			||||||
 | 
					  '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  backendConf = pkgs.writers.writeTOML "librespeed.toml" cfg.backend.settings;
 | 
				
			||||||
 | 
					  generateBackendSettings = base: dst: if (cfg.backend.extraSettingsFile != null) then ''
 | 
				
			||||||
 | 
					    oldUmask="$(umask)"
 | 
				
			||||||
 | 
					    umask 006
 | 
				
			||||||
 | 
					    cat "${base}" "${cfg.backend.extraSettingsFile}" > "${dst}"
 | 
				
			||||||
 | 
					    umask "$oldUmask"
 | 
				
			||||||
 | 
					  '' else ''
 | 
				
			||||||
 | 
					    cp "${base}" "${dst}"
 | 
				
			||||||
 | 
					  '';
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  options.my.librespeed = with lib.types; {
 | 
				
			||||||
 | 
					    frontend = {
 | 
				
			||||||
 | 
					      servers = mkOpt' (listOf (attrsOf unspecified)) { } "Server configs.";
 | 
				
			||||||
 | 
					      webroot = mkOption {
 | 
				
			||||||
 | 
					        description = "Frontend webroot.";
 | 
				
			||||||
 | 
					        type = package;
 | 
				
			||||||
 | 
					        readOnly = true;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    backend = {
 | 
				
			||||||
 | 
					      enable = mkBoolOpt' false "Whether to enable librespeed backend.";
 | 
				
			||||||
 | 
					      settings = mkOpt' (attrsOf unspecified) { } "Backend settings.";
 | 
				
			||||||
 | 
					      extraSettingsFile = mkOpt' (nullOr str) null "Extra settings file.";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  config = mkMerge [
 | 
				
			||||||
 | 
					    (mkIf (cfg.frontend.servers != { }) {
 | 
				
			||||||
 | 
					      my.librespeed.frontend.webroot = frontendTree;
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    (mkIf cfg.backend.enable {
 | 
				
			||||||
 | 
					      my.librespeed.backend.settings = {
 | 
				
			||||||
 | 
					        assets_path = frontendTree;
 | 
				
			||||||
 | 
					        database_type = mkDefault "bolt";
 | 
				
			||||||
 | 
					        database_file = mkDefault "/var/lib/librespeed-go/speedtest.db";
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      systemd.services.librespeed = {
 | 
				
			||||||
 | 
					        description = "LibreSpeed Go backend";
 | 
				
			||||||
 | 
					        wants = [ "network-online.target" ];
 | 
				
			||||||
 | 
					        after = [ "network-online.target" ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        preStart = generateBackendSettings backendConf "/run/librespeed-go/settings.toml";
 | 
				
			||||||
 | 
					        serviceConfig = {
 | 
				
			||||||
 | 
					          ExecStart = "${pkgs.librespeed-go}/bin/speedtest -c /run/librespeed-go/settings.toml";
 | 
				
			||||||
 | 
					          RuntimeDirectory = "librespeed-go";
 | 
				
			||||||
 | 
					          StateDirectory = "librespeed-go";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        wantedBy = [ "multi-user.target" ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										491
									
								
								nixos/modules/librespeed/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										491
									
								
								nixos/modules/librespeed/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,491 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					<link rel="shortcut icon" href="favicon.ico">
 | 
				
			||||||
 | 
					<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
 | 
				
			||||||
 | 
					<meta charset="UTF-8" />
 | 
				
			||||||
 | 
					<script type="text/javascript" src="speedtest.js"></script>
 | 
				
			||||||
 | 
					<script type="text/javascript">
 | 
				
			||||||
 | 
					function I(i){return document.getElementById(i);}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//LIST OF TEST SERVERS. See documentation for details if needed
 | 
				
			||||||
 | 
					var SPEEDTEST_SERVERS=@speedtestServers@;
 | 
				
			||||||
 | 
					// var SPEEDTEST_SERVERS=[
 | 
				
			||||||
 | 
					// 	{	//this server doesn't actually exist, remove it
 | 
				
			||||||
 | 
					// 		name:"Example Server 1", //user friendly name for the server
 | 
				
			||||||
 | 
					// 		server:"//test1.mydomain.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
 | 
				
			||||||
 | 
					// 		dlURL:"backend/garbage.php",  //path to download test on this server (garbage.php or replacement)
 | 
				
			||||||
 | 
					// 		ulURL:"backend/empty.php",  //path to upload test on this server (empty.php or replacement)
 | 
				
			||||||
 | 
					// 		pingURL:"backend/empty.php",  //path to ping/jitter test on this server (empty.php or replacement)
 | 
				
			||||||
 | 
					// 		getIpURL:"backend/getIP.php"  //path to getIP on this server (getIP.php or replacement)
 | 
				
			||||||
 | 
					// 	},
 | 
				
			||||||
 | 
					// 	{	//this server doesn't actually exist, remove it
 | 
				
			||||||
 | 
					// 		name:"Example Server 2", //user friendly name for the server
 | 
				
			||||||
 | 
					// 		server:"//test2.example.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
 | 
				
			||||||
 | 
					// 		dlURL:"garbage.php",  //path to download test on this server (garbage.php or replacement)
 | 
				
			||||||
 | 
					// 		ulURL:"empty.php",  //path to upload test on this server (empty.php or replacement)
 | 
				
			||||||
 | 
					// 		pingURL:"empty.php",  //path to ping/jitter test on this server (empty.php or replacement)
 | 
				
			||||||
 | 
					// 		getIpURL:"getIP.php"  //path to getIP on this server (getIP.php or replacement)
 | 
				
			||||||
 | 
					// 	}
 | 
				
			||||||
 | 
					// 	//add other servers here, comma separated
 | 
				
			||||||
 | 
					// ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//INITIALIZE SPEEDTEST
 | 
				
			||||||
 | 
					var s=new Speedtest(); //create speed test object
 | 
				
			||||||
 | 
					s.setParameter("telemetry_level","basic"); //enable telemetry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//SERVER AUTO SELECTION
 | 
				
			||||||
 | 
					function initServers(){
 | 
				
			||||||
 | 
					    var noServersAvailable=function(){
 | 
				
			||||||
 | 
					        I("message").innerHTML="No servers available";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var runServerSelect=function(){
 | 
				
			||||||
 | 
					        s.selectServer(function(server){
 | 
				
			||||||
 | 
					            if(server!=null){ //at least 1 server is available
 | 
				
			||||||
 | 
					                I("loading").className="hidden"; //hide loading message
 | 
				
			||||||
 | 
					                //populate server list for manual selection
 | 
				
			||||||
 | 
					                for(var i=0;i<SPEEDTEST_SERVERS.length;i++){
 | 
				
			||||||
 | 
					                    if(SPEEDTEST_SERVERS[i].pingT==-1) continue;
 | 
				
			||||||
 | 
					                    var option=document.createElement("option");
 | 
				
			||||||
 | 
					                    option.value=i;
 | 
				
			||||||
 | 
					                    option.textContent=SPEEDTEST_SERVERS[i].name;
 | 
				
			||||||
 | 
					                    if(SPEEDTEST_SERVERS[i]===server) option.selected=true;
 | 
				
			||||||
 | 
					                    I("server").appendChild(option);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                //show test UI
 | 
				
			||||||
 | 
					                I("testWrapper").className="visible";
 | 
				
			||||||
 | 
					                initUI();
 | 
				
			||||||
 | 
					            }else{ //no servers are available, the test cannot proceed
 | 
				
			||||||
 | 
					                noServersAvailable();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(typeof SPEEDTEST_SERVERS === "string"){
 | 
				
			||||||
 | 
					        //need to fetch list of servers from specified URL
 | 
				
			||||||
 | 
					        s.loadServerList(SPEEDTEST_SERVERS,function(servers){
 | 
				
			||||||
 | 
					            if(servers==null){ //failed to load server list
 | 
				
			||||||
 | 
					                noServersAvailable();
 | 
				
			||||||
 | 
					            }else{ //server list loaded
 | 
				
			||||||
 | 
					                SPEEDTEST_SERVERS=servers;
 | 
				
			||||||
 | 
					                runServerSelect();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }else{
 | 
				
			||||||
 | 
					        //hardcoded server list
 | 
				
			||||||
 | 
					        s.addTestPoints(SPEEDTEST_SERVERS);
 | 
				
			||||||
 | 
					        runServerSelect();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var meterBk=/Trident.*rv:(\d+\.\d+)/i.test(navigator.userAgent)?"#EAEAEA":"#80808040";
 | 
				
			||||||
 | 
					var dlColor="#6060AA",
 | 
				
			||||||
 | 
						ulColor="#616161";
 | 
				
			||||||
 | 
					var progColor=meterBk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//CODE FOR GAUGES
 | 
				
			||||||
 | 
					function drawMeter(c,amount,bk,fg,progress,prog){
 | 
				
			||||||
 | 
						var ctx=c.getContext("2d");
 | 
				
			||||||
 | 
						var dp=window.devicePixelRatio||1;
 | 
				
			||||||
 | 
						var cw=c.clientWidth*dp, ch=c.clientHeight*dp;
 | 
				
			||||||
 | 
						var sizScale=ch*0.0055;
 | 
				
			||||||
 | 
						if(c.width==cw&&c.height==ch){
 | 
				
			||||||
 | 
							ctx.clearRect(0,0,cw,ch);
 | 
				
			||||||
 | 
						}else{
 | 
				
			||||||
 | 
							c.width=cw;
 | 
				
			||||||
 | 
							c.height=ch;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx.beginPath();
 | 
				
			||||||
 | 
						ctx.strokeStyle=bk;
 | 
				
			||||||
 | 
						ctx.lineWidth=12*sizScale;
 | 
				
			||||||
 | 
						ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,Math.PI*0.1);
 | 
				
			||||||
 | 
						ctx.stroke();
 | 
				
			||||||
 | 
						ctx.beginPath();
 | 
				
			||||||
 | 
						ctx.strokeStyle=fg;
 | 
				
			||||||
 | 
						ctx.lineWidth=12*sizScale;
 | 
				
			||||||
 | 
						ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,amount*Math.PI*1.2-Math.PI*1.1);
 | 
				
			||||||
 | 
						ctx.stroke();
 | 
				
			||||||
 | 
						if(typeof progress !== "undefined"){
 | 
				
			||||||
 | 
							ctx.fillStyle=prog;
 | 
				
			||||||
 | 
							ctx.fillRect(c.width*0.3,c.height-16*sizScale,c.width*0.4*progress,4*sizScale);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function mbpsToAmount(s){
 | 
				
			||||||
 | 
						return 1-(1/(Math.pow(1.3,Math.sqrt(s))));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function format(d){
 | 
				
			||||||
 | 
					    d=Number(d);
 | 
				
			||||||
 | 
					    if(d<10) return d.toFixed(2);
 | 
				
			||||||
 | 
					    if(d<100) return d.toFixed(1);
 | 
				
			||||||
 | 
					    return d.toFixed(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//UI CODE
 | 
				
			||||||
 | 
					var uiData=null;
 | 
				
			||||||
 | 
					function startStop(){
 | 
				
			||||||
 | 
					    if(s.getState()==3){
 | 
				
			||||||
 | 
							//speed test is running, abort
 | 
				
			||||||
 | 
							s.abort();
 | 
				
			||||||
 | 
							data=null;
 | 
				
			||||||
 | 
							I("startStopBtn").className="";
 | 
				
			||||||
 | 
							I("server").disabled=false;
 | 
				
			||||||
 | 
							initUI();
 | 
				
			||||||
 | 
						}else{
 | 
				
			||||||
 | 
							//test is not running, begin
 | 
				
			||||||
 | 
							I("startStopBtn").className="running";
 | 
				
			||||||
 | 
							I("shareArea").style.display="none";
 | 
				
			||||||
 | 
							I("server").disabled=true;
 | 
				
			||||||
 | 
							s.onupdate=function(data){
 | 
				
			||||||
 | 
					            uiData=data;
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							s.onend=function(aborted){
 | 
				
			||||||
 | 
					            I("startStopBtn").className="";
 | 
				
			||||||
 | 
					            I("server").disabled=false;
 | 
				
			||||||
 | 
					            updateUI(true);
 | 
				
			||||||
 | 
					            if(!aborted){
 | 
				
			||||||
 | 
					                //if testId is present, show sharing panel, otherwise do nothing
 | 
				
			||||||
 | 
					                try{
 | 
				
			||||||
 | 
					                    var testId=uiData.testId;
 | 
				
			||||||
 | 
					                    if(testId!=null){
 | 
				
			||||||
 | 
					                        var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId;
 | 
				
			||||||
 | 
					                        I("resultsImg").src=shareURL;
 | 
				
			||||||
 | 
					                        I("resultsURL").value=shareURL;
 | 
				
			||||||
 | 
					                        I("testId").innerHTML=testId;
 | 
				
			||||||
 | 
					                        I("shareArea").style.display="";
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }catch(e){}
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							s.start();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					//this function reads the data sent back by the test and updates the UI
 | 
				
			||||||
 | 
					function updateUI(forced){
 | 
				
			||||||
 | 
						if(!forced&&s.getState()!=3) return;
 | 
				
			||||||
 | 
						if(uiData==null) return;
 | 
				
			||||||
 | 
						var status=uiData.testState;
 | 
				
			||||||
 | 
						I("ip").textContent=uiData.clientIp;
 | 
				
			||||||
 | 
						I("dlText").textContent=(status==1&&uiData.dlStatus==0)?"...":format(uiData.dlStatus);
 | 
				
			||||||
 | 
						drawMeter(I("dlMeter"),mbpsToAmount(Number(uiData.dlStatus*(status==1?oscillate():1))),meterBk,dlColor,Number(uiData.dlProgress),progColor);
 | 
				
			||||||
 | 
						I("ulText").textContent=(status==3&&uiData.ulStatus==0)?"...":format(uiData.ulStatus);
 | 
				
			||||||
 | 
						drawMeter(I("ulMeter"),mbpsToAmount(Number(uiData.ulStatus*(status==3?oscillate():1))),meterBk,ulColor,Number(uiData.ulProgress),progColor);
 | 
				
			||||||
 | 
						I("pingText").textContent=format(uiData.pingStatus);
 | 
				
			||||||
 | 
						I("jitText").textContent=format(uiData.jitterStatus);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					function oscillate(){
 | 
				
			||||||
 | 
						return 1+0.02*Math.sin(Date.now()/100);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					//update the UI every frame
 | 
				
			||||||
 | 
					window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||(function(callback,element){setTimeout(callback,1000/60);});
 | 
				
			||||||
 | 
					function frame(){
 | 
				
			||||||
 | 
						requestAnimationFrame(frame);
 | 
				
			||||||
 | 
						updateUI();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					frame(); //start frame loop
 | 
				
			||||||
 | 
					//function to (re)initialize UI
 | 
				
			||||||
 | 
					function initUI(){
 | 
				
			||||||
 | 
						drawMeter(I("dlMeter"),0,meterBk,dlColor,0);
 | 
				
			||||||
 | 
						drawMeter(I("ulMeter"),0,meterBk,ulColor,0);
 | 
				
			||||||
 | 
						I("dlText").textContent="";
 | 
				
			||||||
 | 
						I("ulText").textContent="";
 | 
				
			||||||
 | 
						I("pingText").textContent="";
 | 
				
			||||||
 | 
						I("jitText").textContent="";
 | 
				
			||||||
 | 
						I("ip").textContent="";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					<style type="text/css">
 | 
				
			||||||
 | 
						html,body{
 | 
				
			||||||
 | 
							border:none; padding:0; margin:0;
 | 
				
			||||||
 | 
							background:#FFFFFF;
 | 
				
			||||||
 | 
							color:#202020;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						body{
 | 
				
			||||||
 | 
							text-align:center;
 | 
				
			||||||
 | 
							font-family:"Roboto",sans-serif;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h1{
 | 
				
			||||||
 | 
							color:#404040;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#loading{
 | 
				
			||||||
 | 
							background-color:#FFFFFF;
 | 
				
			||||||
 | 
							color:#404040;
 | 
				
			||||||
 | 
							text-align:center;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						span.loadCircle{
 | 
				
			||||||
 | 
							display:inline-block;
 | 
				
			||||||
 | 
							width:2em;
 | 
				
			||||||
 | 
							height:2em;
 | 
				
			||||||
 | 
							vertical-align:middle;
 | 
				
			||||||
 | 
							background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAP1BMVEUAAAB2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZyFzwnAAAAFHRSTlMAEvRFvX406baecwbf0casimhSHyiwmqgAAADpSURBVHja7dbJbQMxAENRahnN5lkc//5rDRAkDeRgHszXgACJoKiIiIiIiIiIiIiIiIiIiIj4HHspsrpAVhdVVguzrA4OWc10WcEqpwKbnBo0OU1Q5NSpsoJFTgOecrrdEag85DRgktNqfoEdTjnd7hrEHMEJvmRUYJbTYk5Agy6nau6Abp5Cm7mDBtRdPi9gyKdU7w4p1fsLvyqs8hl4z9/w3n/Hmr9WoQ65lAU4d7lMYOz//QboRR5jBZibLMZdAR6O/Vfa1PlxNr3XdS3HzK/HVPRu/KnLs8iAOh993VpRRERERMT/fAN60wwWaVyWwAAAAABJRU5ErkJggg==');
 | 
				
			||||||
 | 
							background-size:2em 2em;
 | 
				
			||||||
 | 
							margin-right:0.5em;
 | 
				
			||||||
 | 
							animation: spin 0.6s linear infinite;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						@keyframes spin{
 | 
				
			||||||
 | 
							0%{transform:rotate(0deg);}
 | 
				
			||||||
 | 
							100%{transform:rotate(359deg);}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#startStopBtn{
 | 
				
			||||||
 | 
							display:inline-block;
 | 
				
			||||||
 | 
							margin:0 auto;
 | 
				
			||||||
 | 
							color:#6060AA;
 | 
				
			||||||
 | 
							background-color:rgba(0,0,0,0);
 | 
				
			||||||
 | 
							border:0.15em solid #6060FF;
 | 
				
			||||||
 | 
							border-radius:0.3em;
 | 
				
			||||||
 | 
							transition:all 0.3s;
 | 
				
			||||||
 | 
							box-sizing:border-box;
 | 
				
			||||||
 | 
							width:8em; height:3em;
 | 
				
			||||||
 | 
							line-height:2.7em;
 | 
				
			||||||
 | 
							cursor:pointer;
 | 
				
			||||||
 | 
							box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#startStopBtn:hover{
 | 
				
			||||||
 | 
							box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#startStopBtn.running{
 | 
				
			||||||
 | 
							background-color:#FF3030;
 | 
				
			||||||
 | 
							border-color:#FF6060;
 | 
				
			||||||
 | 
							color:#FFFFFF;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#startStopBtn:before{
 | 
				
			||||||
 | 
							content:"Start";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#startStopBtn.running:before{
 | 
				
			||||||
 | 
							content:"Abort";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#serverArea{
 | 
				
			||||||
 | 
							margin-top:1em;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#server{
 | 
				
			||||||
 | 
							font-size:1em;
 | 
				
			||||||
 | 
							padding:0.2em;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#test{
 | 
				
			||||||
 | 
							margin-top:2em;
 | 
				
			||||||
 | 
							margin-bottom:12em;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.testArea{
 | 
				
			||||||
 | 
							display:inline-block;
 | 
				
			||||||
 | 
							width:16em;
 | 
				
			||||||
 | 
							height:12.5em;
 | 
				
			||||||
 | 
							position:relative;
 | 
				
			||||||
 | 
							box-sizing:border-box;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.testArea2{
 | 
				
			||||||
 | 
							display:inline-block;
 | 
				
			||||||
 | 
							width:14em;
 | 
				
			||||||
 | 
							height:7em;
 | 
				
			||||||
 | 
							position:relative;
 | 
				
			||||||
 | 
							box-sizing:border-box;
 | 
				
			||||||
 | 
							text-align:center;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.testArea div.testName{
 | 
				
			||||||
 | 
							position:absolute;
 | 
				
			||||||
 | 
							top:0.1em; left:0;
 | 
				
			||||||
 | 
							width:100%;
 | 
				
			||||||
 | 
							font-size:1.4em;
 | 
				
			||||||
 | 
							z-index:9;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.testArea2 div.testName{
 | 
				
			||||||
 | 
					        display:block;
 | 
				
			||||||
 | 
					        text-align:center;
 | 
				
			||||||
 | 
					        font-size:1.4em;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.testArea div.meterText{
 | 
				
			||||||
 | 
							position:absolute;
 | 
				
			||||||
 | 
							bottom:1.55em; left:0;
 | 
				
			||||||
 | 
							width:100%;
 | 
				
			||||||
 | 
							font-size:2.5em;
 | 
				
			||||||
 | 
							z-index:9;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.testArea2 div.meterText{
 | 
				
			||||||
 | 
					        display:inline-block;
 | 
				
			||||||
 | 
					        font-size:2.5em;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.meterText:empty:before{
 | 
				
			||||||
 | 
							content:"0.00";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.testArea div.unit{
 | 
				
			||||||
 | 
							position:absolute;
 | 
				
			||||||
 | 
							bottom:2em; left:0;
 | 
				
			||||||
 | 
							width:100%;
 | 
				
			||||||
 | 
							z-index:9;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.testArea2 div.unit{
 | 
				
			||||||
 | 
							display:inline-block;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.testArea canvas{
 | 
				
			||||||
 | 
							position:absolute;
 | 
				
			||||||
 | 
							top:0; left:0; width:100%; height:100%;
 | 
				
			||||||
 | 
							z-index:1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.testGroup{
 | 
				
			||||||
 | 
							display:block;
 | 
				
			||||||
 | 
					        margin: 0 auto;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#shareArea{
 | 
				
			||||||
 | 
							width:95%;
 | 
				
			||||||
 | 
							max-width:40em;
 | 
				
			||||||
 | 
							margin:0 auto;
 | 
				
			||||||
 | 
							margin-top:2em;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#shareArea > *{
 | 
				
			||||||
 | 
							display:block;
 | 
				
			||||||
 | 
							width:100%;
 | 
				
			||||||
 | 
							height:auto;
 | 
				
			||||||
 | 
							margin: 0.25em 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#privacyPolicy{
 | 
				
			||||||
 | 
					        position:fixed;
 | 
				
			||||||
 | 
					        top:2em;
 | 
				
			||||||
 | 
					        bottom:2em;
 | 
				
			||||||
 | 
					        left:2em;
 | 
				
			||||||
 | 
					        right:2em;
 | 
				
			||||||
 | 
					        overflow-y:auto;
 | 
				
			||||||
 | 
					        width:auto;
 | 
				
			||||||
 | 
					        height:auto;
 | 
				
			||||||
 | 
					        box-shadow:0 0 3em 1em #000000;
 | 
				
			||||||
 | 
					        z-index:999999;
 | 
				
			||||||
 | 
					        text-align:left;
 | 
				
			||||||
 | 
					        background-color:#FFFFFF;
 | 
				
			||||||
 | 
					        padding:1em;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						a.privacy{
 | 
				
			||||||
 | 
					        text-align:center;
 | 
				
			||||||
 | 
					        font-size:0.8em;
 | 
				
			||||||
 | 
					        color:#808080;
 | 
				
			||||||
 | 
					        padding: 0 3em;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					    div.closePrivacyPolicy {
 | 
				
			||||||
 | 
					        width: 100%;
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    div.closePrivacyPolicy a.privacy {
 | 
				
			||||||
 | 
					        padding: 1em 3em;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
						@media all and (max-width:40em){
 | 
				
			||||||
 | 
							body{
 | 
				
			||||||
 | 
								font-size:0.8em;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.visible{
 | 
				
			||||||
 | 
							animation: fadeIn 0.4s;
 | 
				
			||||||
 | 
							display:block;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						div.hidden{
 | 
				
			||||||
 | 
							animation: fadeOut 0.4s;
 | 
				
			||||||
 | 
							display:none;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						@keyframes fadeIn{
 | 
				
			||||||
 | 
							0%{
 | 
				
			||||||
 | 
								opacity:0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							100%{
 | 
				
			||||||
 | 
								opacity:1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						@keyframes fadeOut{
 | 
				
			||||||
 | 
							0%{
 | 
				
			||||||
 | 
								display:block;
 | 
				
			||||||
 | 
								opacity:1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							100%{
 | 
				
			||||||
 | 
								display:block;
 | 
				
			||||||
 | 
								opacity:0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 | 
					<title>/dev/player0's speedtest</title>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body onload="initServers()">
 | 
				
			||||||
 | 
					<h1>/dev/player0's speedtest</h1>
 | 
				
			||||||
 | 
					<div id="loading" class="visible">
 | 
				
			||||||
 | 
						<p id="message"><span class="loadCircle"></span>Selecting a server...</p>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<div id="testWrapper" class="hidden">
 | 
				
			||||||
 | 
						<div id="startStopBtn" onclick="startStop()"></div><br/>
 | 
				
			||||||
 | 
						<a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a>
 | 
				
			||||||
 | 
						<div id="serverArea">
 | 
				
			||||||
 | 
							Server: <select id="server" onchange="s.setSelectedServer(SPEEDTEST_SERVERS[this.value])"></select>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
						<div id="test">
 | 
				
			||||||
 | 
							<div class="testGroup">
 | 
				
			||||||
 | 
					            <div class="testArea2">
 | 
				
			||||||
 | 
									<div class="testName">Ping</div>
 | 
				
			||||||
 | 
									<div id="pingText" class="meterText" style="color:#AA6060"></div>
 | 
				
			||||||
 | 
									<div class="unit">ms</div>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
								<div class="testArea2">
 | 
				
			||||||
 | 
									<div class="testName">Jitter</div>
 | 
				
			||||||
 | 
									<div id="jitText" class="meterText" style="color:#AA6060"></div>
 | 
				
			||||||
 | 
									<div class="unit">ms</div>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div class="testGroup">
 | 
				
			||||||
 | 
								<div class="testArea">
 | 
				
			||||||
 | 
									<div class="testName">Download</div>
 | 
				
			||||||
 | 
									<canvas id="dlMeter" class="meter"></canvas>
 | 
				
			||||||
 | 
									<div id="dlText" class="meterText"></div>
 | 
				
			||||||
 | 
									<div class="unit">Mbit/s</div>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
								<div class="testArea">
 | 
				
			||||||
 | 
									<div class="testName">Upload</div>
 | 
				
			||||||
 | 
									<canvas id="ulMeter" class="meter"></canvas>
 | 
				
			||||||
 | 
									<div id="ulText" class="meterText"></div>
 | 
				
			||||||
 | 
									<div class="unit">Mbit/s</div>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div id="ipArea">
 | 
				
			||||||
 | 
								<span id="ip"></span>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<div id="shareArea" style="display:none">
 | 
				
			||||||
 | 
								<h3>Share results</h3>
 | 
				
			||||||
 | 
								<p>Test ID: <span id="testId"></span></p>
 | 
				
			||||||
 | 
								<input type="text" value="" id="resultsURL" readonly="readonly" onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
 | 
				
			||||||
 | 
								<img src="" id="resultsImg" />
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
						<a href="https://github.com/librespeed/speedtest">Source code</a>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<div id="privacyPolicy" style="display:none">
 | 
				
			||||||
 | 
					    <h2>Privacy Policy</h2>
 | 
				
			||||||
 | 
					    <p>This HTML5 speed test server is configured with telemetry enabled.</p>
 | 
				
			||||||
 | 
					    <h4>What data we collect</h4>
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					        At the end of the test, the following data is collected and stored:
 | 
				
			||||||
 | 
					        <ul>
 | 
				
			||||||
 | 
					            <li>Test ID</li>
 | 
				
			||||||
 | 
					            <li>Time of testing</li>
 | 
				
			||||||
 | 
					            <li>Test results (download and upload speed, ping and jitter)</li>
 | 
				
			||||||
 | 
					            <li>IP address</li>
 | 
				
			||||||
 | 
					            <li>ISP information</li>
 | 
				
			||||||
 | 
					            <li>Approximate location (inferred from IP address, not GPS)</li>
 | 
				
			||||||
 | 
					            <li>User agent and browser locale</li>
 | 
				
			||||||
 | 
					            <li>Test log (contains no personal information)</li>
 | 
				
			||||||
 | 
					        </ul>
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					    <h4>How we use the data</h4>
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					        Data collected through this service is used to:
 | 
				
			||||||
 | 
					        <ul>
 | 
				
			||||||
 | 
					            <li>Allow sharing of test results (sharable image for forums, etc.)</li>
 | 
				
			||||||
 | 
					            <li>To improve the service offered to you (for instance, to detect problems on our side)</li>
 | 
				
			||||||
 | 
					        </ul>
 | 
				
			||||||
 | 
					        No personal information is disclosed to third parties.
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					    <h4>Your consent</h4>
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					        By starting the test, you consent to the terms of this privacy policy.
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					    <h4>Data removal</h4>
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					        If you want to have your information deleted, you need to provide either the ID of the test or your IP address. This is the only way to identify your data, without this information we won't be able to comply with your request.<br/><br/>
 | 
				
			||||||
 | 
					        Contact this email address for all deletion requests: <a href="mailto:dev@nul.ie">dev@nul.ie</a>.
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					    <br/><br/>
 | 
				
			||||||
 | 
					    <div class="closePrivacyPolicy">
 | 
				
			||||||
 | 
					        <a class="privacy" href="#" onclick="I('privacyPolicy').style.display='none'">Close</a>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <br/>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										58
									
								
								nixos/modules/nvme/default.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								nixos/modules/nvme/default.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					{ lib, pkgs, config, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (lib) mkIf;
 | 
				
			||||||
 | 
					  inherit (lib.my) mkOpt';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cfg = config.my.nvme;
 | 
				
			||||||
 | 
					  nvme-cli = pkgs.nvme-cli.override {
 | 
				
			||||||
 | 
					    libnvme = pkgs.libnvme.overrideAttrs (o: {
 | 
				
			||||||
 | 
					      patches = o.patches ++ [ ./libnvme-hostconf.patch ];
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hostNQN = "nqn.2014-08.org.nvmexpress:uuid:${cfg.uuid}";
 | 
				
			||||||
 | 
					  etc = prefix: {
 | 
				
			||||||
 | 
					    "${prefix}nvme/hostnqn".text = hostNQN;
 | 
				
			||||||
 | 
					    "${prefix}nvme/hostid".text = cfg.uuid;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  options.my.nvme = with lib.types; {
 | 
				
			||||||
 | 
					    uuid = mkOpt' (nullOr str) null "NVMe host ID";
 | 
				
			||||||
 | 
					    boot = {
 | 
				
			||||||
 | 
					      nqn = mkOpt' (nullOr str) null "NQN to connect to on boot";
 | 
				
			||||||
 | 
					      address = mkOpt' str null "Address of NVMe-oF target.";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  config = mkIf (cfg.uuid != null) {
 | 
				
			||||||
 | 
					    environment = {
 | 
				
			||||||
 | 
					      systemPackages = [
 | 
				
			||||||
 | 
					        nvme-cli
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					      etc = etc "";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    boot.initrd.systemd = mkIf (cfg.boot.nqn != null) {
 | 
				
			||||||
 | 
					      contents = etc "/etc/";
 | 
				
			||||||
 | 
					      extraBin.nvme = "${nvme-cli}/bin/nvme";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      services.connect-nvme = {
 | 
				
			||||||
 | 
					        description = "Connect NVMe-oF";
 | 
				
			||||||
 | 
					        before = [ "initrd-root-device.target" ];
 | 
				
			||||||
 | 
					        after = [ "systemd-networkd-wait-online.service" ];
 | 
				
			||||||
 | 
					        requires = [ "systemd-networkd-wait-online.service" ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        serviceConfig = {
 | 
				
			||||||
 | 
					          Type = "oneshot";
 | 
				
			||||||
 | 
					          ExecStart = "${nvme-cli}/bin/nvme connect -t rdma -a ${cfg.boot.address} -n ${cfg.boot.nqn}";
 | 
				
			||||||
 | 
					          Restart = "on-failure";
 | 
				
			||||||
 | 
					          RestartSec = 10;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wantedBy = [ "initrd-root-device.target" ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								nixos/modules/nvme/libnvme-hostconf.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								nixos/modules/nvme/libnvme-hostconf.patch
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					diff --git a/src/nvme/fabrics.c b/src/nvme/fabrics.c
 | 
				
			||||||
 | 
					index 21fb292..f9090d1 100644
 | 
				
			||||||
 | 
					--- a/src/nvme/fabrics.c
 | 
				
			||||||
 | 
					+++ b/src/nvme/fabrics.c
 | 
				
			||||||
 | 
					@@ -41,8 +41,8 @@
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 #define NVMF_HOSTID_SIZE	37
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					-#define NVMF_HOSTNQN_FILE	SYSCONFDIR "/nvme/hostnqn"
 | 
				
			||||||
 | 
					-#define NVMF_HOSTID_FILE	SYSCONFDIR "/nvme/hostid"
 | 
				
			||||||
 | 
					+#define NVMF_HOSTNQN_FILE	"/etc/nvme/hostnqn"
 | 
				
			||||||
 | 
					+#define NVMF_HOSTID_FILE	"/etc/nvme/hostid"
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 const char *nvmf_dev = "/dev/nvme-fabrics";
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
@@ -268,6 +268,9 @@ in
 | 
				
			|||||||
        # For pdns_control etc
 | 
					        # For pdns_control etc
 | 
				
			||||||
        systemPackages = with pkgs; [
 | 
					        systemPackages = with pkgs; [
 | 
				
			||||||
          pdns
 | 
					          pdns
 | 
				
			||||||
 | 
					          (pkgs.writeShellScriptBin "pu" ''
 | 
				
			||||||
 | 
					            ${pdns}/bin/pdnsutil --config-dir /run/pdns "$@"
 | 
				
			||||||
 | 
					          '')
 | 
				
			||||||
          pdns-file-record
 | 
					          pdns-file-record
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										94
									
								
								nixos/modules/spdk.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								nixos/modules/spdk.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					{ lib, pkgs, config, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  inherit (builtins) toJSON;
 | 
				
			||||||
 | 
					  inherit (lib) optional optionalAttrs mapAttrsToList mkIf withFeature;
 | 
				
			||||||
 | 
					  inherit (lib.my) mkOpt' mkBoolOpt';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rpcOpts = with lib.types; {
 | 
				
			||||||
 | 
					    options = {
 | 
				
			||||||
 | 
					      method = mkOpt' str null "RPC method name.";
 | 
				
			||||||
 | 
					      params = mkOpt' (attrsOf unspecified) { } "RPC params";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cfg = config.my.spdk;
 | 
				
			||||||
 | 
					  config' = {
 | 
				
			||||||
 | 
					    subsystems = mapAttrsToList (subsystem: c: {
 | 
				
			||||||
 | 
					      inherit subsystem;
 | 
				
			||||||
 | 
					      config = map (rpc: {
 | 
				
			||||||
 | 
					        inherit (rpc) method;
 | 
				
			||||||
 | 
					      } // (optionalAttrs (rpc.params != { }) { inherit (rpc) params; })) c;
 | 
				
			||||||
 | 
					    }) cfg.config.subsystems;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  configJSON = pkgs.writeText "spdk-config.json" (toJSON config');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  spdk = pkgs.spdk.overrideAttrs (o: {
 | 
				
			||||||
 | 
					    configureFlags = o.configureFlags ++ (map (withFeature true) [ "rdma" "ublk" ]);
 | 
				
			||||||
 | 
					    buildInputs = o.buildInputs ++ (with pkgs; [ liburing ]);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  spdk-rpc = (pkgs.writeShellScriptBin "spdk-rpc" ''
 | 
				
			||||||
 | 
					    exec ${pkgs.python3}/bin/python3 ${spdk.src}/scripts/rpc.py "$@"
 | 
				
			||||||
 | 
					  '');
 | 
				
			||||||
 | 
					  spdk-setup = (pkgs.writeShellScriptBin "spdk-setup" ''
 | 
				
			||||||
 | 
					    exec ${spdk.src}/scripts/setup.sh "$@"
 | 
				
			||||||
 | 
					  '');
 | 
				
			||||||
 | 
					  spdk-debug = pkgs.writeShellApplication {
 | 
				
			||||||
 | 
					    name = "spdk-debug";
 | 
				
			||||||
 | 
					    runtimeInputs = [ spdk ];
 | 
				
			||||||
 | 
					    text = ''
 | 
				
			||||||
 | 
					      set -m
 | 
				
			||||||
 | 
					      if [ "$(id -u)" -ne 0 ]; then
 | 
				
			||||||
 | 
					        echo "I need to be root!"
 | 
				
			||||||
 | 
					        exit 1
 | 
				
			||||||
 | 
					      fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      spdk_tgt ${cfg.extraArgs} --wait-for-rpc &
 | 
				
			||||||
 | 
					      until spdk-rpc spdk_get_version > /dev/null; do
 | 
				
			||||||
 | 
					        sleep 0.5
 | 
				
			||||||
 | 
					      done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      spdk-rpc bdev_set_options --disable-auto-examine
 | 
				
			||||||
 | 
					      spdk-rpc framework_start_init
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ${cfg.debugCommands}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      fg %1
 | 
				
			||||||
 | 
					    '';
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  options.my.spdk = with lib.types; {
 | 
				
			||||||
 | 
					    enable = mkBoolOpt' false "Whether to enable SPDK target.";
 | 
				
			||||||
 | 
					    extraArgs = mkOpt' str "" "Extra arguments to pass to spdk_tgt.";
 | 
				
			||||||
 | 
					    debugCommands = mkOpt' lines "" "Commands to run with the spdk-debug script.";
 | 
				
			||||||
 | 
					    config.subsystems = mkOpt' (attrsOf (listOf (submodule rpcOpts))) { } "Subsystem config / RPCs.";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  config = mkIf cfg.enable {
 | 
				
			||||||
 | 
					    boot.kernelModules = [ "ublk_drv" ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    environment.systemPackages = [
 | 
				
			||||||
 | 
					      spdk
 | 
				
			||||||
 | 
					      spdk-setup
 | 
				
			||||||
 | 
					      spdk-rpc
 | 
				
			||||||
 | 
					    ] ++ (optional (cfg.debugCommands != "") spdk-debug);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    systemd.services = {
 | 
				
			||||||
 | 
					      spdk-tgt = {
 | 
				
			||||||
 | 
					        description = "SPDK target";
 | 
				
			||||||
 | 
					        path = with pkgs; [
 | 
				
			||||||
 | 
					          bash
 | 
				
			||||||
 | 
					          python3
 | 
				
			||||||
 | 
					          kmod
 | 
				
			||||||
 | 
					          gawk
 | 
				
			||||||
 | 
					          util-linux
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					        serviceConfig = {
 | 
				
			||||||
 | 
					          ExecStartPre = "${spdk.src}/scripts/setup.sh";
 | 
				
			||||||
 | 
					          ExecStart = "${spdk}/bin/spdk_tgt ${cfg.extraArgs} -c ${configJSON}";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        wantedBy = [ "multi-user.target" ];
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -187,6 +187,9 @@ in
 | 
				
			|||||||
    (mkIf config.networking.resolvconf.enable {
 | 
					    (mkIf config.networking.resolvconf.enable {
 | 
				
			||||||
      my.tmproot.unsaved.ignore = [ "/etc/resolv.conf" ];
 | 
					      my.tmproot.unsaved.ignore = [ "/etc/resolv.conf" ];
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					    (mkIf config.networking.nftables.enable {
 | 
				
			||||||
 | 
					      my.tmproot.unsaved.ignore = [ "/var/lib/nftables/deletions.nft" ];
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
    (mkIf config.security.doas.enable {
 | 
					    (mkIf config.security.doas.enable {
 | 
				
			||||||
      my.tmproot.unsaved.ignore = [ "/etc/doas.conf" ];
 | 
					      my.tmproot.unsaved.ignore = [ "/etc/doas.conf" ];
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
@@ -221,8 +224,9 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # Catch non-existent source directories that are needed for boot (see `pathsNeededForBoot` in
 | 
					        # Catch non-existent source directories that are needed for boot (see `pathsNeededForBoot` in
 | 
				
			||||||
        # nixos/lib/util.nix). We do this by monkey-patching the `waitDevice` function that would otherwise hang.
 | 
					        # nixos/lib/util.nix). We do this by monkey-patching the `waitDevice` function that would otherwise hang.
 | 
				
			||||||
        boot.initrd.postDeviceCommands =
 | 
					        # Seems like systemd initrd doesn't care because it uses the systemd.mount units
 | 
				
			||||||
          ''
 | 
					        # ("If this mount is a bind mount and the specified path does not exist yet it is created as directory.")
 | 
				
			||||||
 | 
					        boot.initrd.postDeviceCommands = mkIf (!config.boot.initrd.systemd.enable) ''
 | 
				
			||||||
            ensurePersistSource() {
 | 
					            ensurePersistSource() {
 | 
				
			||||||
              [ -e "/mnt-root$1" ] && return
 | 
					              [ -e "/mnt-root$1" ] && return
 | 
				
			||||||
              echo "Persistent source directory $1 does not exist, creating..."
 | 
					              echo "Persistent source directory $1 does not exist, creating..."
 | 
				
			||||||
@@ -459,6 +463,35 @@ in
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
					      (mkIf config.virtualisation.libvirtd.enable {
 | 
				
			||||||
 | 
					        my.tmproot.persistence.config.directories = [ "/var/lib/libvirt" ];
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      (mkIf (with config.services.kea; (dhcp4.enable || dhcp6.enable || dhcp-ddns.enable)) {
 | 
				
			||||||
 | 
					        my.tmproot.persistence.config.directories = [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            directory = "/var/lib/kea";
 | 
				
			||||||
 | 
					            mode = "0750";
 | 
				
			||||||
 | 
					            user = "kea";
 | 
				
			||||||
 | 
					            group = "kea";
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      (persistSimpleSvc "headscale")
 | 
				
			||||||
 | 
					      (mkIf config.services.tailscale.enable {
 | 
				
			||||||
 | 
					        my.tmproot.persistence.config.directories = [ "/var/lib/tailscale" ];
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      (mkIf config.my.librespeed.backend.enable {
 | 
				
			||||||
 | 
					        my.tmproot.persistence.config.directories = [ "/var/lib/librespeed-go" ];
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      (mkIf config.services.hedgedoc.enable {
 | 
				
			||||||
 | 
					        my.tmproot.persistence.config.directories = [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            directory = "/var/lib/hedgedoc";
 | 
				
			||||||
 | 
					            user = "hedgedoc";
 | 
				
			||||||
 | 
					            group = "hedgedoc";
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
    ]))
 | 
					    ]))
 | 
				
			||||||
  ]);
 | 
					  ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,8 +35,11 @@ in
 | 
				
			|||||||
            isNormalUser = true;
 | 
					            isNormalUser = true;
 | 
				
			||||||
            uid = mkDefault 1000;
 | 
					            uid = mkDefault 1000;
 | 
				
			||||||
            extraGroups =
 | 
					            extraGroups =
 | 
				
			||||||
              [ "wheel" "kvm" ] ++
 | 
					              [ "wheel" "kvm" "dialout" ] ++
 | 
				
			||||||
              (optional config.networking.networkmanager.enable "networkmanager");
 | 
					              (optional config.networking.networkmanager.enable "networkmanager") ++
 | 
				
			||||||
 | 
					              (optional config.virtualisation.libvirtd.enable "libvirtd") ++
 | 
				
			||||||
 | 
					              (optional config.programs.wireshark.enable "wireshark") ++
 | 
				
			||||||
 | 
					              (with config.services.headscale; (optional enable group));
 | 
				
			||||||
            password = mkIf (cfg.passwordSecret == null) (mkDefault "hunter2");
 | 
					            password = mkIf (cfg.passwordSecret == null) (mkDefault "hunter2");
 | 
				
			||||||
            shell =
 | 
					            shell =
 | 
				
			||||||
              let shell = cfg.homeConfig.my.shell;
 | 
					              let shell = cfg.homeConfig.my.shell;
 | 
				
			||||||
@@ -57,33 +60,17 @@ in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            "/home/${user'.name}/.config/fish/fish_variables"
 | 
					            "/home/${user'.name}/.config/fish/fish_variables"
 | 
				
			||||||
          ];
 | 
					          ];
 | 
				
			||||||
          persistence.config =
 | 
					          persistence.config.users."${user'.name}" = {
 | 
				
			||||||
          let
 | 
					            files = [
 | 
				
			||||||
            perms = {
 | 
					              ".bash_history"
 | 
				
			||||||
              mode = "0700";
 | 
					              ".lesshst"
 | 
				
			||||||
              user = user.name;
 | 
					 | 
				
			||||||
              group = user.group;
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
          in
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            files = (map (file: {
 | 
					 | 
				
			||||||
              inherit file;
 | 
					 | 
				
			||||||
              parentDirectory = perms;
 | 
					 | 
				
			||||||
            }) [
 | 
					 | 
				
			||||||
              "/home/${user'.name}/.bash_history"
 | 
					 | 
				
			||||||
              "/home/${user'.name}/.lesshst"
 | 
					 | 
				
			||||||
            ]) ++ [
 | 
					 | 
				
			||||||
              # Just to make sure we get correct default perms
 | 
					 | 
				
			||||||
              "/home/.tmproot.dummy"
 | 
					 | 
				
			||||||
            ];
 | 
					            ];
 | 
				
			||||||
            directories = map (directory: {
 | 
					            directories = [
 | 
				
			||||||
              inherit directory;
 | 
					 | 
				
			||||||
            } // perms) [
 | 
					 | 
				
			||||||
              # Persist all of fish; it's not easy to persist just the history fish won't let you move it to a different
 | 
					              # Persist all of fish; it's not easy to persist just the history fish won't let you move it to a different
 | 
				
			||||||
              # directory. Also it does some funny stuff and can't really be a symlink it seems.
 | 
					              # directory. Also it does some funny stuff and can't really be a symlink it seems.
 | 
				
			||||||
              "/home/${user'.name}/.local/share/fish"
 | 
					              ".local/share/fish"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              "/home/${user'.name}/.cache/nix"
 | 
					              ".cache/nix"
 | 
				
			||||||
            ];
 | 
					            ];
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -99,7 +86,7 @@ in
 | 
				
			|||||||
    (mkIf (cfg.passwordSecret != null) {
 | 
					    (mkIf (cfg.passwordSecret != null) {
 | 
				
			||||||
      my = {
 | 
					      my = {
 | 
				
			||||||
        secrets.files."${cfg.passwordSecret}" = {};
 | 
					        secrets.files."${cfg.passwordSecret}" = {};
 | 
				
			||||||
        user.config.passwordFile = config.age.secrets."${cfg.passwordSecret}".path;
 | 
					        user.config.hashedPasswordFile = config.age.secrets."${cfg.passwordSecret}".path;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  ]);
 | 
					  ]);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,29 +48,6 @@ let
 | 
				
			|||||||
      asyncio.run(main())
 | 
					      asyncio.run(main())
 | 
				
			||||||
    '';
 | 
					    '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # TODO: Upstream or something...
 | 
					 | 
				
			||||||
  vfio-pci-bind = pkgs.stdenv.mkDerivation rec {
 | 
					 | 
				
			||||||
    pname = "vfio-pci-bind";
 | 
					 | 
				
			||||||
    version = "b41e4545b21de434fc51a34a9bf1d72e3ac66cc8";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    src = fetchGit {
 | 
					 | 
				
			||||||
      url = "https://github.com/andre-richter/vfio-pci-bind";
 | 
					 | 
				
			||||||
      rev = version;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    prePatch = ''
 | 
					 | 
				
			||||||
      substituteInPlace vfio-pci-bind.sh \
 | 
					 | 
				
			||||||
        --replace modprobe ${pkgs.kmod}/bin/modprobe
 | 
					 | 
				
			||||||
      substituteInPlace 25-vfio-pci-bind.rules \
 | 
					 | 
				
			||||||
        --replace vfio-pci-bind.sh "$out"/bin/vfio-pci-bind.sh
 | 
					 | 
				
			||||||
    '';
 | 
					 | 
				
			||||||
    installPhase = ''
 | 
					 | 
				
			||||||
      mkdir -p "$out"/bin/ "$out"/lib/udev/rules.d
 | 
					 | 
				
			||||||
      cp vfio-pci-bind.sh "$out"/bin/
 | 
					 | 
				
			||||||
      cp 25-vfio-pci-bind.rules "$out"/lib/udev/rules.d/
 | 
					 | 
				
			||||||
    '';
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  cfg = config.my.vms;
 | 
					  cfg = config.my.vms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  netOpts = with lib.types; { name, iName, ... }: {
 | 
					  netOpts = with lib.types; { name, iName, ... }: {
 | 
				
			||||||
@@ -139,7 +116,7 @@ let
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
        default = { };
 | 
					        default = { };
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
      drives = mkOpt' (listOf (submodule driveOpts)) { } "Drives to attach to VM.";
 | 
					      drives = mkOpt' (listOf (submodule driveOpts)) [ ] "Drives to attach to VM.";
 | 
				
			||||||
      hostDevices = mkOpt' (attrsOf (submodule hostDevOpts)) { } "Host PCI devices to pass to the VM.";
 | 
					      hostDevices = mkOpt' (attrsOf (submodule hostDevOpts)) { } "Host PCI devices to pass to the VM.";
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@@ -149,6 +126,8 @@ let
 | 
				
			|||||||
      (map
 | 
					      (map
 | 
				
			||||||
        (i: mapAttrsToList (name: c: c // { inherit name; }) i.hostDevices)
 | 
					        (i: mapAttrsToList (name: c: c // { inherit name; }) i.hostDevices)
 | 
				
			||||||
        (attrValues cfg.instances));
 | 
					        (attrValues cfg.instances));
 | 
				
			||||||
 | 
					  anyVfioDevs = any (d: d.bindVFIO);
 | 
				
			||||||
 | 
					  vfioHostDevs = filter (d: d.bindVFIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mkQemuScript = n: i:
 | 
					  mkQemuScript = n: i:
 | 
				
			||||||
  let
 | 
					  let
 | 
				
			||||||
@@ -184,6 +163,7 @@ let
 | 
				
			|||||||
            else "ifname=${c.ifname},script=no,downscript=no"))
 | 
					            else "ifname=${c.ifname},script=no,downscript=no"))
 | 
				
			||||||
        ("device ${c.model},netdev=${nn},mac=${c.mac}" + (extraQEMUOpts c.extraOptions))
 | 
					        ("device ${c.model},netdev=${nn},mac=${c.mac}" + (extraQEMUOpts c.extraOptions))
 | 
				
			||||||
      ]) i.networks)) ++
 | 
					      ]) i.networks)) ++
 | 
				
			||||||
 | 
					      (optional (i.networks == { }) "nic none") ++
 | 
				
			||||||
      (flatten (map (d: [
 | 
					      (flatten (map (d: [
 | 
				
			||||||
        "blockdev node-name=${d.name}-backend,${d.backend}"
 | 
					        "blockdev node-name=${d.name}-backend,${d.backend}"
 | 
				
			||||||
        "blockdev node-name=${d.name}-format,${d.formatBackendProp}=${d.name}-backend,${d.format}"
 | 
					        "blockdev node-name=${d.name}-format,${d.formatBackendProp}=${d.name}-backend,${d.format}"
 | 
				
			||||||
@@ -224,15 +204,15 @@ in
 | 
				
			|||||||
    services.udev = {
 | 
					    services.udev = {
 | 
				
			||||||
      packages =
 | 
					      packages =
 | 
				
			||||||
        optionals
 | 
					        optionals
 | 
				
			||||||
          (any (d: d.bindVFIO) allHostDevs)
 | 
					          (anyVfioDevs allHostDevs)
 | 
				
			||||||
          [
 | 
					          [
 | 
				
			||||||
            vfio-pci-bind
 | 
					            pkgs.vfio-pci-bind
 | 
				
			||||||
            (pkgs.writeTextDir
 | 
					            (pkgs.writeTextDir
 | 
				
			||||||
              "etc/udev/rules.d/20-vfio-tags.rules"
 | 
					              "etc/udev/rules.d/20-vfio-tags.rules"
 | 
				
			||||||
              (concatMapStringsSep
 | 
					              (concatMapStringsSep
 | 
				
			||||||
                "\n"
 | 
					                "\n"
 | 
				
			||||||
                (d: ''ACTION=="add", SUBSYSTEM=="pci", KERNEL=="0000:${d.hostBDF}", TAG="vfio-pci-bind"'')
 | 
					                (d: ''ACTION=="add", SUBSYSTEM=="pci", KERNEL=="0000:${d.hostBDF}", TAG="vfio-pci-bind"'')
 | 
				
			||||||
                (filter (d: d.bindVFIO) allHostDevs)))
 | 
					                (vfioHostDevs allHostDevs)))
 | 
				
			||||||
          ];
 | 
					          ];
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -281,10 +261,30 @@ in
 | 
				
			|||||||
          };
 | 
					          };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          preStart =
 | 
					          preStart =
 | 
				
			||||||
 | 
					          let
 | 
				
			||||||
 | 
					            hostDevs = attrValues i.hostDevices;
 | 
				
			||||||
 | 
					          in
 | 
				
			||||||
            ''
 | 
					            ''
 | 
				
			||||||
              if [ ! -e "$STATE_DIRECTORY"/ovmf_vars.bin ]; then
 | 
					              if [ ! -e "$STATE_DIRECTORY"/ovmf_vars.bin ]; then
 | 
				
			||||||
                cp "${cfg.ovmfPackage.fd}"/FV/OVMF_VARS.fd "$STATE_DIRECTORY"/ovmf_vars.bin
 | 
					                cp "${cfg.ovmfPackage.fd}"/FV/OVMF_VARS.fd "$STATE_DIRECTORY"/ovmf_vars.bin
 | 
				
			||||||
              fi
 | 
					              fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              ${optionalString (anyVfioDevs hostDevs) ''
 | 
				
			||||||
 | 
					                iommu_group() {
 | 
				
			||||||
 | 
					                  g=/sys/bus/pci/devices/0000:$1/iommu_group
 | 
				
			||||||
 | 
					                  until [ -e $g ]; do
 | 
				
			||||||
 | 
					                    sleep 0.1
 | 
				
			||||||
 | 
					                  done
 | 
				
			||||||
 | 
					                  basename $(readlink $g)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                wait_vfio() {
 | 
				
			||||||
 | 
					                  until [ -e /dev/vfio/$(iommu_group $1) ]; do
 | 
				
			||||||
 | 
					                    sleep 0.1
 | 
				
			||||||
 | 
					                  done
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ${concatMapStringsSep "\n" (d: "wait_vfio ${d.hostBDF}") (vfioHostDevs hostDevs) }
 | 
				
			||||||
 | 
					              ''}
 | 
				
			||||||
            '';
 | 
					            '';
 | 
				
			||||||
          script = mkQemuScript n i;
 | 
					          script = mkQemuScript n i;
 | 
				
			||||||
          postStart =
 | 
					          postStart =
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,4 +5,7 @@ in
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  # yeah turns out this is in nixpkgs now... we'll leave it as a sample i guess lol
 | 
					  # yeah turns out this is in nixpkgs now... we'll leave it as a sample i guess lol
 | 
				
			||||||
  monocraft' = callPackage ./monocraft.nix { };
 | 
					  monocraft' = callPackage ./monocraft.nix { };
 | 
				
			||||||
 | 
					  vfio-pci-bind = callPackage ./vfio-pci-bind.nix { };
 | 
				
			||||||
 | 
					  librespeed-go = callPackage ./librespeed-go.nix { };
 | 
				
			||||||
 | 
					  modrinth-app = callPackage ./modrinth-app { };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								pkgs/librespeed-go.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								pkgs/librespeed-go.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					{ lib, fetchFromGitHub, buildGoModule, ... }:
 | 
				
			||||||
 | 
					let
 | 
				
			||||||
 | 
					  webSrc = fetchFromGitHub {
 | 
				
			||||||
 | 
					    owner = "librespeed";
 | 
				
			||||||
 | 
					    repo = "speedtest";
 | 
				
			||||||
 | 
					    rev = "5.3.0";
 | 
				
			||||||
 | 
					    hash = "sha256-OgKGLQcfWX/sBLzaHI6TcJHxX1Wol6K7obLf0+CHrC8=";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					in
 | 
				
			||||||
 | 
					buildGoModule rec {
 | 
				
			||||||
 | 
					  pname = "librespeed-go";
 | 
				
			||||||
 | 
					  version = "1.1.5";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  src = fetchFromGitHub {
 | 
				
			||||||
 | 
					    owner = "librespeed";
 | 
				
			||||||
 | 
					    repo = "speedtest-go";
 | 
				
			||||||
 | 
					    rev = "v${version}";
 | 
				
			||||||
 | 
					    hash = "sha256-ywGrodl/mj/WB25F0TKVvaV0PV4lgc+KEj0x/ix9HT8=";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  vendorHash = "sha256-ev5TEv8u+tx7xIvNaK8b5iq2XXF6I37Fnrr8mb+N2WM=";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  postInstall = ''
 | 
				
			||||||
 | 
					    mkdir -p "$out"/assets
 | 
				
			||||||
 | 
					    cp "${webSrc}"/{speedtest.js,speedtest_worker.js,favicon.ico} "$out"/assets/
 | 
				
			||||||
 | 
					  '';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6239
									
								
								pkgs/modrinth-app/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6239
									
								
								pkgs/modrinth-app/Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										97
									
								
								pkgs/modrinth-app/default.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								pkgs/modrinth-app/default.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
				
			|||||||
 | 
					{ lib
 | 
				
			||||||
 | 
					, fetchFromGitHub
 | 
				
			||||||
 | 
					, rustPlatform
 | 
				
			||||||
 | 
					, pkg-config
 | 
				
			||||||
 | 
					, openssl
 | 
				
			||||||
 | 
					, libsoup
 | 
				
			||||||
 | 
					, dbus
 | 
				
			||||||
 | 
					, glib
 | 
				
			||||||
 | 
					, glib-networking
 | 
				
			||||||
 | 
					, gtk3
 | 
				
			||||||
 | 
					, webkitgtk
 | 
				
			||||||
 | 
					, libayatana-appindicator
 | 
				
			||||||
 | 
					, librsvg
 | 
				
			||||||
 | 
					, wrapGAppsHook
 | 
				
			||||||
 | 
					, stdenvNoCC
 | 
				
			||||||
 | 
					, jq
 | 
				
			||||||
 | 
					, moreutils
 | 
				
			||||||
 | 
					, nodePackages
 | 
				
			||||||
 | 
					, cacert
 | 
				
			||||||
 | 
					}:
 | 
				
			||||||
 | 
					rustPlatform.buildRustPackage rec {
 | 
				
			||||||
 | 
					  pname = "modrinth-app";
 | 
				
			||||||
 | 
					  version = "0.6.3";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  src = fetchFromGitHub {
 | 
				
			||||||
 | 
					    owner = "modrinth";
 | 
				
			||||||
 | 
					    repo = "theseus";
 | 
				
			||||||
 | 
					    rev = "v${version}";
 | 
				
			||||||
 | 
					    hash = "sha256-gFQXcTqHgSKfne6+v837ENXYYiEYu/Yks9TpnfBCPnA=";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cargoLock = {
 | 
				
			||||||
 | 
					    lockFile = ./Cargo.lock;
 | 
				
			||||||
 | 
					    outputHashes = {
 | 
				
			||||||
 | 
					      "tauri-plugin-single-instance-0.0.0" = "sha256-G4h2OXKPpZMmradutdUWxGG5axL9XMz2ACAe8AQ40eg=";
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  nativeBuildInputs = [
 | 
				
			||||||
 | 
					    pkg-config
 | 
				
			||||||
 | 
					    nodePackages.pnpm
 | 
				
			||||||
 | 
					    wrapGAppsHook
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					  buildInputs = [
 | 
				
			||||||
 | 
					    openssl
 | 
				
			||||||
 | 
					    libsoup
 | 
				
			||||||
 | 
					    dbus
 | 
				
			||||||
 | 
					    glib
 | 
				
			||||||
 | 
					    glib-networking
 | 
				
			||||||
 | 
					    gtk3
 | 
				
			||||||
 | 
					    webkitgtk
 | 
				
			||||||
 | 
					    libayatana-appindicator
 | 
				
			||||||
 | 
					    librsvg
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  pnpm-deps = stdenvNoCC.mkDerivation {
 | 
				
			||||||
 | 
					    pname = "${pname}-pnpm-deps";
 | 
				
			||||||
 | 
					    inherit src version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sourceRoot = "${src.name}/theseus_gui";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nativeBuildInputs = [
 | 
				
			||||||
 | 
					      jq
 | 
				
			||||||
 | 
					      moreutils
 | 
				
			||||||
 | 
					      nodePackages.pnpm
 | 
				
			||||||
 | 
					      cacert
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    installPhase = ''
 | 
				
			||||||
 | 
					      export HOME=$(mktemp -d)
 | 
				
			||||||
 | 
					      pnpm config set store-dir $out
 | 
				
			||||||
 | 
					      pnpm install --ignore-scripts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Remove timestamp and sort the json files
 | 
				
			||||||
 | 
					      rm -rf $out/v3/tmp
 | 
				
			||||||
 | 
					      for f in $(find $out -name "*.json"); do
 | 
				
			||||||
 | 
					        sed -i -E -e 's/"checkedAt":[0-9]+,//g' $f
 | 
				
			||||||
 | 
					        jq --sort-keys . $f | sponge $f
 | 
				
			||||||
 | 
					      done
 | 
				
			||||||
 | 
					    '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dontFixup = true;
 | 
				
			||||||
 | 
					    outputHashMode = "recursive";
 | 
				
			||||||
 | 
					    outputHash = "sha256-9HtTdIotG3sNIlWhd76v7Ia6P69ufp/FFqZfINXSkVc=";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  preBuild = ''
 | 
				
			||||||
 | 
					    cd theseus_gui
 | 
				
			||||||
 | 
					    export HOME=$(mktemp -d)
 | 
				
			||||||
 | 
					    pnpm config set store-dir ${pnpm-deps}
 | 
				
			||||||
 | 
					    pnpm install --ignore-scripts --offline
 | 
				
			||||||
 | 
					    chmod -R +w node_modules
 | 
				
			||||||
 | 
					    pnpm rebuild
 | 
				
			||||||
 | 
					    pnpm build
 | 
				
			||||||
 | 
					    cd ..
 | 
				
			||||||
 | 
					  '';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								pkgs/vfio-pci-bind.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								pkgs/vfio-pci-bind.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					{ stdenv, kmod, ... }:
 | 
				
			||||||
 | 
					stdenv.mkDerivation rec {
 | 
				
			||||||
 | 
					  pname = "vfio-pci-bind";
 | 
				
			||||||
 | 
					  version = "b41e4545b21de434fc51a34a9bf1d72e3ac66cc8";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  src = fetchGit {
 | 
				
			||||||
 | 
					    url = "https://github.com/andre-richter/vfio-pci-bind";
 | 
				
			||||||
 | 
					    rev = version;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  prePatch = ''
 | 
				
			||||||
 | 
					    substituteInPlace vfio-pci-bind.sh \
 | 
				
			||||||
 | 
					      --replace modprobe ${kmod}/bin/modprobe
 | 
				
			||||||
 | 
					    substituteInPlace 25-vfio-pci-bind.rules \
 | 
				
			||||||
 | 
					      --replace vfio-pci-bind.sh "$out"/bin/vfio-pci-bind.sh
 | 
				
			||||||
 | 
					  '';
 | 
				
			||||||
 | 
					  installPhase = ''
 | 
				
			||||||
 | 
					    mkdir -p "$out"/bin/ "$out"/lib/udev/rules.d
 | 
				
			||||||
 | 
					    cp vfio-pci-bind.sh "$out"/bin/
 | 
				
			||||||
 | 
					    cp 25-vfio-pci-bind.rules "$out"/lib/udev/rules.d/
 | 
				
			||||||
 | 
					  '';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -9,7 +9,6 @@ let
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  defaultKeys = [
 | 
					  defaultKeys = [
 | 
				
			||||||
    (fileContents .keys/dev.pub)
 | 
					    (fileContents .keys/dev.pub)
 | 
				
			||||||
    (fileContents .keys/ci.pub)
 | 
					 | 
				
			||||||
  ];
 | 
					  ];
 | 
				
			||||||
  secretKeys =
 | 
					  secretKeys =
 | 
				
			||||||
    zipAttrsWith
 | 
					    zipAttrsWith
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								secrets/britway/bgp-password-vultr.conf.age
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								secrets/britway/bgp-password-vultr.conf.age
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyBJYzdr
 | 
				
			||||||
 | 
					b1d2aEtVd3lVb3NBamRwVFpTaTRjZFlCczk4MVIwQUoxWklwN0NrCmFFekpPYUlO
 | 
				
			||||||
 | 
					YlgvVlQ2WDR6amZDN0ZSY0Q3WWtTME5pUmhQeks1c3dGOVUKLT4gWDI1NTE5IHVK
 | 
				
			||||||
 | 
					bUZvUVAvL0NmQzFkY3BuYm1wMjcwbFpLRUNpZjJCaW15SEVDUDV0REkKRXFMQ2d1
 | 
				
			||||||
 | 
					NlFBejBvTlJrcUtCYWZxSDBkbmxIdExBNTU0aC8zRW5OVWllVQotPiBDLWdyZWFz
 | 
				
			||||||
 | 
					ZSBkeC4oTFUgO0FtJG9+RyB2IF1QXGhxVwpJS213MXBRMWY1cXlHZwotLS0gRUF2
 | 
				
			||||||
 | 
					ZkswNlhvcDhTc2tybCs1dldwa2l6SDZZVmNkNUNjNGlkV1ZVa09pOAp88dxHGxVU
 | 
				
			||||||
 | 
					vuFQO6JcroY9MF5Te/YV+wMc3hVxksibMnH1TWGh207prwcOWNOEz2iEkZY=
 | 
				
			||||||
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
							
								
								
									
										15
									
								
								secrets/britway/cloudflare-credentials.conf.age
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								secrets/britway/cloudflare-credentials.conf.age
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyBLVlg2
 | 
				
			||||||
 | 
					ZUdtUlFUQXBLT3B5YmkycWJnMXJyKzltbyt6K2dJK1RBUm5ydWwwCmRUdjJFSEYz
 | 
				
			||||||
 | 
					Wnp4cGtzTXZwc0s0SUJQUjRlOUJlQUoyQ3BETXZmY0ppWG8KLT4gWDI1NTE5IGR5
 | 
				
			||||||
 | 
					QUJzeG1DQTRLUmRwNnNSRUJRSFFtUDl5VjB0clVLYUp3R1g4TEVKaTgKb09tVlhF
 | 
				
			||||||
 | 
					R0tmcmIxMHVHcG80RGxRTEhBcngvT3MrdnNPbmpCTlRyZW5xQQotPiA6RzEtZ3Jl
 | 
				
			||||||
 | 
					YXNlCldSUlN2ejB0MGpyUHYzNS9OQmJTK3MvcXRDakdBVlhuUEt6SFE4QmhnWVN0
 | 
				
			||||||
 | 
					V1JMOE1oaEp5QQotLS0gYW1OMTcxNWJrUndmR2h0ZmRDWk5CYnJjc29pSERUMnNk
 | 
				
			||||||
 | 
					d2VhTGdpOW4yUQrEeH2E9m0YycuW60QrdlRetO1kNU5FaKXRQt46iA9lACIWD4rC
 | 
				
			||||||
 | 
					Cx6WxhCBgz3hvm9x6iuYiiQxZzgJNK7qXcV2MBeQdivazeEbC7blAKVPhwD/dl+b
 | 
				
			||||||
 | 
					PzBDXRXG3c3jMjeZFT69fIBGJfZrrLGKpTALVE4dTVXmQmVVQDTp19IC+jUXHBti
 | 
				
			||||||
 | 
					Pj6Dpc7452s8zPkzZyRbasO9b4PYTwq8IHT6X7ITwbzZZm8gexDYe2SzRZ5VcPz3
 | 
				
			||||||
 | 
					El+yoULZ92WbXPSQIP/Slx4BEZjmsQS+sm0N8AnBRNZkWVbHPF9IZRg3VjDAn2i8
 | 
				
			||||||
 | 
					F3un5js=
 | 
				
			||||||
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
							
								
								
									
										13
									
								
								secrets/britway/oidc-secret.txt.age
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								secrets/britway/oidc-secret.txt.age
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyAyMWox
 | 
				
			||||||
 | 
					cEFDWWUrVzJSM1o2azJqei9HV2xFY25oQXV5SzM3akxEaUJiN1J3CjkrQVhjWHY5
 | 
				
			||||||
 | 
					Uk01eGp5Q0RKNVREVXJVZytndTM0SXNZSGIvUVp1TnRiNXMKLT4gWDI1NTE5IFZn
 | 
				
			||||||
 | 
					WjAyR1RMajEyMnFSYnNGT2EyekROVWNoakFJQVZxaFc0YThOMHVyanMKWldrdlAv
 | 
				
			||||||
 | 
					cVg0OTFHL2loeGJ3RHA0MnlnckN3czF4RUgyc1NjYXVOSXF5cwotPiBvTFQtZ3Jl
 | 
				
			||||||
 | 
					YXNlIDRsSDp6eikgT1ojIGEzOFZMIFc3MUZGCkttZ3ZLNGxucnlJc01kRXFZTGpC
 | 
				
			||||||
 | 
					eCsvRzl5WnFUMUIyTWNVWGk4SjQyN3V0bXQ4VzFuM1RjSzVMcDJkaW1JYXMKQkE4
 | 
				
			||||||
 | 
					YWI1Mmg3MkpjdVpVYWJkczJQMnM1SVMvNkZhOXBDVEZPCi0tLSB3SVIyU3M5RHBE
 | 
				
			||||||
 | 
					VFRtMFU4OUFLbkNjbkJmVmhlc2VsYzdsd0pFaFkrUmkwCs+h2KlXoyZ8U++A9wmV
 | 
				
			||||||
 | 
					kh4N2YyI/a84yPGDNoFdSlXaU8jxUzolnadImXSXyB4CroqQLvGEbkZZlWqPLVfh
 | 
				
			||||||
 | 
					Iav7Ja8=
 | 
				
			||||||
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
@@ -1,13 +1,13 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USAwUDl0
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USB2WFY2
 | 
				
			||||||
WENqQ09VdkJSbDgzdjNFSDZhM0I1MlN4NGJ3MDBhUHVYUWhHZkJvCkRMaDBoNDN6
 | 
					MzFnVFYvb0wzc3grRDBrUi9teW1tNmx5dVBIRVc5OUdlcjdvTDJFCmpJL2tlYXND
 | 
				
			||||||
eGk0NFZpTjdXSm1DNTF6bzVOdTNTcTdJYUtRdVVzQWUvZGcKLT4gWDI1NTE5IDJF
 | 
					bVJKbzd2S3JkSFVMdG40MS84V0lPTVJSNHVBQlNXSkN1eTAKLT4gWDI1NTE5IFBM
 | 
				
			||||||
dWkzMExMKy92ODAvZnYwTkRnYk92RjFObTZORVI0amtaZG5lZXRjRzAKSmQ1Zloz
 | 
					ZGo3L2VlNUZqOEE1UHBuMHdqc1pyYlQ3R29ucE9pajU0bHMzamlXRDAKcG1Qdmw2
 | 
				
			||||||
ME5Ca1ZiNkxsU3BLYlNuU3RSaHBWWnZRRTBFc2V1K1hkQUZRSQotPiBWSldTemtM
 | 
					cUlncDFWNXBOWnpIeDNZSFA3d1E1bjNaVVpKU3lMRjRaSHNtMAotPiB2XUh8eF4t
 | 
				
			||||||
Uy1ncmVhc2UKSEtXOGVCRC9EZGVTVjYzaDhQdVJTS0dHUHRiN1cybVlLK3JOaGMw
 | 
					Z3JlYXNlICUrO0cxIH4gaTRoIF81SEpTN0Q5CnpWdEZpb1hZa2t5YkE5RnJFMHVZ
 | 
				
			||||||
TUJyUE5CdnN1OFY3Nm9wbnRMeDV3TXQ5aApvRXdEOTRzT3NYbVRSVkpKT2lpbEFo
 | 
					WkhkQ2o0eWtyOE9ueDJkeGd2aUhmLzRUUGs1aUc1NURIOTYxczZhOEVmT0EKd2xk
 | 
				
			||||||
RGdXbjhvYnl3Ci0tLSBlSmliMk5TMWU5aWwwYkdwd2NDQnNWUXJJclFHKzB3M2Zs
 | 
					TXFHN051d25PQmtNUVZkVEFGUVliZjdmZDF3RWFkaEhNTzd3ZVd5N3dlNzQKLS0t
 | 
				
			||||||
YlAyWHREQitZCrcVpAY1+uNiY1rOKCLzWaFJLdKZ1/iwN+BhD7AoMo65Tb0g65SV
 | 
					IGZDR1Mxd24zOW05bitzQnN5WWVOOGtCNEc5aXIraEF4eXFUQm5CZUdCV2MKd44C
 | 
				
			||||||
kfHePz8prE4OCGU57Mi3A/4Uwo4NCqwDGoqHDDgxOy1cA33Urp8Mlor8XFxI1/mt
 | 
					/Trgg0OEZ89/jqbj56z/Hia1Ka3ZsEv6bXPI/kcRvFDBFTgtvG3KWCgMBtTUHXzY
 | 
				
			||||||
hwzY8F4=
 | 
					TKBPoQqrUf7plH7a/mTx3KR+4Y+yF+1i86s7TzYjD8d1xfFH3BsVtg==
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,29 +1,30 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USBMdEVY
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USBuQjBY
 | 
				
			||||||
L0JXSU56czhLUE5kNVRJbmNKZVBZcnpvai9NcCtSRHJlT1VYTzFjCkdvL0syRE8v
 | 
					K1ZTUzR0SmFoYUZLdzUzNUt2M1B4RFdPZzFkcW8rMWJLUjVHOUN3Cjd3ZHdMSzdp
 | 
				
			||||||
Z0NoTTc5eGhBWE9RcnZob3Q4aFZTV2MyL1QxOFNKNEZSWGMKLT4gWDI1NTE5IFIx
 | 
					OWswditVWUhYNjZCdjV6M1d6U3pNak5hUlZjTHNqSkZPSk0KLT4gWDI1NTE5IGNG
 | 
				
			||||||
ZnlaZUlPWGdwcUkzNFlFbnR2YUtsU3VHbGtMcStkSkIxU0EveWVmRFUKY2ltTDNE
 | 
					ZytHazJQWTExMjNkZWV2aDUwcnZjUGcwcXRkZWl0M0F2R2JpUVlJekUKWTFlbkEz
 | 
				
			||||||
UDFxK2ZRRXBUMXFMUlA1dHlwcndWbG1CZDNjdS9Vc2NVNWxRbwotPiBOIy84Ry1n
 | 
					YlN6dkgrMmFFcmlZMjQ0b2oySjlEMC85cUF5QlA4NGF3blBKRQotPiA8M1hbWS1n
 | 
				
			||||||
cmVhc2UgSSpdIFN+ICkvcyFrVVomIDZNIQpRTVZtWVAvVzB6RkdSQzNpaG5zNnJ4
 | 
					cmVhc2UgOmlZJFYmJgo3UExzUHhSVi9lbVRjNW4xTnVaUTVGSGVDNzRUNlJ2TnVu
 | 
				
			||||||
dWN5YStTdTAyWUNucnc2OU0vU0prdFM4cjVKNnlSN09KM0Fjc2hGa3lxClh6L2xM
 | 
					U0wrWU5kd3dyR2phcUNVUHJCYjdzeWhjNVFOV011CmZMOVN0WDk5eUg3ajhwbStQ
 | 
				
			||||||
VFEKLS0tIEw5blBQRnJ0c2tJc3Eza2tDV2lSbXdlSHRiWlBBWFdqMUY5eUZJZGZy
 | 
					aHExT0EwblpreTBXVHh6Zk1HRkhzcmFQNnoyVUlaeStMUkgKLS0tIG1aY3Zadko3
 | 
				
			||||||
ZjQKLKV5zGtMXse0TUJG94Q3pnxpYHa9zM9Vc4MwRR0blmvJmeNMc6UFlvy8VZuR
 | 
					V3pDMGswSDZCeit4SVhSRCsrZVRVZVkvQkNsQWN1MXFMUGcKcK74YULWqWw9VvkI
 | 
				
			||||||
3ymLJm8i9kquJHiqgvocFWInxOgeTaGX96cXzm4sDu/SUK8Pmsd6V+PmH2rWc9hh
 | 
					NH38VHfDPW5ueSiyHHKn8MI9YosPr/TmkwgKd/DOIMVB74ahPalo1QUeg+eaBVnq
 | 
				
			||||||
GeS23VhcfQfzgUIyxhTR2x3QsJM8Gdw6vTm92GHY9xv1BfogZnluWRNwvHEXmUnu
 | 
					Uncsbx5ecW3JswthkAhiktWHcdHmioGD6hCcgbWtfA3VvbAYc2gtAF2plfDVH6BD
 | 
				
			||||||
02sMSYy4af2bDY/oJDlYILJzBf26SRYX6S3oDW8pvFSX9R+nc9qXqSOFRaVxsLyd
 | 
					c8veai3B15ZmDmq3b62sgVA9JUgbFaB1eRqcaPXmNgQJR4c8J+CZWXGQ/TKMqtAg
 | 
				
			||||||
ma4WtOBQgsY6u9bdxEPDzHRtcUoMAwldj7tEgHBjui+FfwGu6EqKinOm2FYUzvYW
 | 
					chCDuczjLX8IxhMPF1gdCggSt5GtMhY47fpZJRbBUw01l8koqjm63KvEeg2ejFGU
 | 
				
			||||||
+Gjs+Mxv1/lj5YukN8notOmZTIwklQRlOY9SstnzjpssnhGorWqNRSryEf0bK5az
 | 
					+tXonI4jm2JUxlDTqmNSrVpmAgtPoEPszHc+GsnyNjAz4IXMm5UrQAZyDPgxtwQW
 | 
				
			||||||
iRdbITn3ow+BlnudX5ARruTy8FRywW5MCTouYTOvzNcuLmA6pfRKeIsAlnwqs15G
 | 
					ZAn0IdOB8rSL/AnRGUpPrecuauINQjONe8CapijjJPQK7g1AHscfxr+OJD1j2eV3
 | 
				
			||||||
itha60bScbFLDUuT2B87LHjEbbgMxNll+4oqBNTarvlCUD5IoMN/qU2iOcO9/vF+
 | 
					O6TNlz8vKW4t/V7CUf46ykxxExhA0mKJ53ksaXy2+HWoro2+c4nao/bEld5gt08U
 | 
				
			||||||
47dhWS7dIHnR5Jea60G03FGRXLmwBLrE2N9EasqwuiqwhmSWOfOV/6Zj6ky+jvLm
 | 
					uCpJtjPKB64X6vdzbY21/l87VRDyxbb3poENfrXlawqS0Z7i2gAbHN5EuiMv+35o
 | 
				
			||||||
VnB/41gq4WGoC3ZvQgVg6bifvVgtBe/tzY5MQM916Fpd56Zves3DdyTHiKQ3iVyb
 | 
					sBaR0BfcbTn6VagC3i8HEEOO964FrW65pkqmGJcJMgUdcZSl+Y7gHMjWyodqGPOY
 | 
				
			||||||
6WyqRvXvwanOttCHQgoJwARKoTkpRwEEcOAuD3sO6fjXythcie5BpqXadfExI5jc
 | 
					evT6xj4iyeM49vXynV2vrJRu5rr02hOS/8rPphV9c9q9ju5n8xbhS6IiybAelPwt
 | 
				
			||||||
78ILy4gVZYLifDi+bc8j/QyvPGreOvErwNAsIPRCqQ9r/y/uBA8425rM9FMQnXzj
 | 
					sa+xM+w0n+fxVksiXeFj7qD1LDN4+kwqhYP9SlzbA4fT3AkYYrxthTww4IFAweyQ
 | 
				
			||||||
8eAr3FHL6wMvOMOt3woi7MpUQn9elO1heCwUGEOfVfsIL7FPlK5U/SCzC+lk3sVx
 | 
					IJkpVL0/IZEIEfRzpr0lWLprAaoyPc64pecl0z/gBJDgz1kSG6iEh6K4qx7ahGde
 | 
				
			||||||
nwe2q4pExw+WtZ+mtBSfjgbftZZQ7t4yOCdXVm3REbpUSTiT4f+sKfZSIYaNPqKY
 | 
					kBBpS2I2ZsdBkvmQxDSM7tYYBzPxcUNZlSFOIeUy3Xl+OGPlKgtMofbnjV8AFqUf
 | 
				
			||||||
elB5nrxYsyumEsFzjAqjT93XNaQGashpmTg7eiiT2GzL9oWO5a/oliqUxx98G7lA
 | 
					tOpgKpLUEkTgXbGUKBxHLj+8pbw7zOFp4sJ00i48ZzLP5D9jom+jS19wGshRc7cH
 | 
				
			||||||
4lYpzz5MUmUe5DEyZXObXVBrRG6svuG2DJ5FXgOpRbFzqTDP6ihgmeuueEPWtVGP
 | 
					dK92CctvrfndQ85yO0vqlyOdMTqjh/z3P2KmhL5SW6P51q5mseTvj7FNM7331DTs
 | 
				
			||||||
SPv7655KDhJu3xcyTIpUE5C/sDTs0HoLx31eg8o0FOGVNDAw5PmKED5ldAxLHNOB
 | 
					rq7XWaBLE61eWWQ/dZKnqh5YbkSlU1+08Rl6H/vCU5hTC8fht3KTQSWPofkrP+5f
 | 
				
			||||||
VNf1ZwE3j3D/8t3mUyDWixCBBk+oOfj5JCmnNFTc0XKAz2gsZmPot4mvdA5NDvjy
 | 
					We/Pe62LyhV/MbLRA0nmU7Sf4IAnpHfa4kLtlYeB3xiqKd0McM//qzjuk5NoIgE4
 | 
				
			||||||
XyhPftapSzjSWz/UunsNplC6Op3htri68nI=
 | 
					nL0T8YXdGt8K01w+nt+j5bo5gFoRz5+1/ZZ9BgN2DOo4SClYnJWQ/x80X061yJ33
 | 
				
			||||||
 | 
					0SGv4eAC3vFi6xE=
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,16 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USBYUTlr
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpCM2U2USA3MEFh
 | 
				
			||||||
Mm1ubFFPTHhhb3NERHJPaXoxamt5bUtqQmRkUTFGZCsvaUtyZGdrCmVNUEtrSTVQ
 | 
					YURySHY5RjVQa1c0QmMvTkZtZElNd1BIeDFpR1U1YXZ5dndnclUwClA2M0ZYMk90
 | 
				
			||||||
MkdHWnd1OTNSN3lOaFdrdWsxUHM2S0VZVlNRWGt4R0FyZ0UKLT4gWDI1NTE5IFNZ
 | 
					RmlCZHVISkxZQTZXeEhZVUROSVRGRVg4TmZKZytSL05FcTgKLT4gWDI1NTE5IFY2
 | 
				
			||||||
QUhpVU04WWpEZThEaE82WDJvT3NVVWxNRVFEZjluVW8rbGhOQ0Rua0kKOWlZYlFh
 | 
					V2k3S0VQdGlQZ0hkU2ZoSWdOUG9rQ0p5Ukg3ZHU3MXVvNHlWYVN5VVUKcWtoWDJh
 | 
				
			||||||
RjduNDAwS0NJa0lPNmx6dmIvdmFtcXJyaG5FQ2hVU01qby9sTQotPiBVJjEhLWdy
 | 
					LzRwcktWUGQ1bnJvRzVBVlpHU3NhdzYwUDBPTmx3MFNrdWNQYwotPiBKQil6Km0t
 | 
				
			||||||
ZWFzZSBOYyllZE4KV0lYMmErd3RvUWp1UVRvdlpKTUZWWlJHK1laN2FoZGh2aVlM
 | 
					Z3JlYXNlIFdlRTlUU2cgVlxLIzUgJlVyQiJ8Cng3NzF2b3d6MnlEdURQWHgrSFJv
 | 
				
			||||||
dTdLbWZsVkozVTBwb2JyeGpFMy9FcjR0eDhxQQpUL05uT2ZSUytNV01wMjFYRWZL
 | 
					Y1BMUkZyelJSdDJvUUUwY1k5R3ZBMnJaa1R4NWxlUll2azNseW5MQlpvVWUKYUdN
 | 
				
			||||||
NTRkSmlkcUl4LzJYTDQwMm43cVJVeTdkY0dxdkI1ZjA3Z2NoU3NBCi0tLSB4Y3lV
 | 
					d1ZscXVxd1dxSGpzMjBYeWhhYyt5ZlNkSjhmV1ZTTDBTCi0tLSBBTG45VUJOSXZv
 | 
				
			||||||
UVphTEtIWFhVQ1h4MUZzNDYzSEhDUFpMcE1ZdFNtd1A2Rk5lMUhRCp/F11nGICQA
 | 
					N3lYNVlyZldMVkpZdUMvS21NdSswVmU3VThZK2M2eis4CjwfWWJVR9Ty5dBXEr5s
 | 
				
			||||||
L5uInKKk8jVGzpG93U4Kz3zut6jGF/is4cVuvkRHZLKiUVC4kILirdinnbxlJY2Y
 | 
					U+QrifXvyMJJvqOKEfMYYomFLpt/VtbDAUwNlqLnFIk1VZ2xPUBisXPtReiCK3gq
 | 
				
			||||||
Gkpef0zthmNhfFhsgjj5Tmxyiu1L+6GkY0z2GlKR8uRUG4bXsDQzDkZQm8Wcmrrt
 | 
					P+i6bUONSmPYvmF82VgiuKDuz/kmWqVGg2iSBPIXAGLNIEojndQwmhnrsN9ex4Xy
 | 
				
			||||||
9lG04SI0Dj7Gc2HJEwjl7ZPBi9qnFU49on+/Y5DIpzTllgE7luduFLjLM2Q+kNGK
 | 
					lBHkvVsN8EamUJwZ+FEZe4+PjA5yEnANWpeTELOt2gA92/jwwnNIsr07eVTlkh8X
 | 
				
			||||||
cU8cF+gvrpyAFytiUZ3jhATtXsqC0dzsugjj8pmT1WQzZd6iqVJ84G2pMg+boVyn
 | 
					UmQ2owGwktXP7it6//NV3C7sAdazs2bX65WSnog2E8WPNAorKWI8RCYs33CshVFt
 | 
				
			||||||
aVLGrcn3qOnIIJLKrYEjyxSYMGs=
 | 
					zzclZ4hRmlAmqMHYqFY=
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,11 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGo2N0ZYUSBmOURS
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGo2N0ZYUSBoYlRq
 | 
				
			||||||
dzkyWWlrU0FoOHlmNzZzQUk0cWNueEJQY1c3aDdZMDltbXcvU21ZCkhrb2VkQUxK
 | 
					ckk2c21uMVZSR05SdlJpck5MT0FZeUpLTmpTRVN2WDkxWWxmVTBvCjlHZWtEQ2Jh
 | 
				
			||||||
U1hwdkcxSGhNUFNITmZRM0NsQ0hEVjJGRXcrOXpVMEp3ZTgKLT4gWDI1NTE5IFNK
 | 
					YUdybjJLWkNsZkxabTVIR0JnMno5YlMvVmhodDU1bktrSzgKLT4gWDI1NTE5IFZT
 | 
				
			||||||
Vzh3VnZsbGFJVjVZQTd0b1VLM3RpSUF2QlMzY3pLTExReXVDb3IySGcKbXdhNVcr
 | 
					Um9lWXhqRFFLTWdNaTR3Sm1acmY4N0l6WE1FSW54ZEtQcEE5RHBRRHcKcE5KYmp1
 | 
				
			||||||
LzVPc1hmOUQ0eDdRVWJzTUFLZXZVT1NzRnNpS05GQ1hidnI3cwotPiBlO1BHIzst
 | 
					WVdCVk0wMHZ2SCtUR0xKWU10N0xETXlXZmgxcmZZOFBXYWtBawotPiBlRm1gKGxU
 | 
				
			||||||
Z3JlYXNlIGtoLjRXUTZGCllYeUs5QQotLS0gbTlsWXIycFFyWXNWQmpxejVYb0dr
 | 
					LWdyZWFzZSAqXF8gOkU8Tm96IGA4IC1TCjY3NUgKLS0tIDhjaTNrbG1iQ05iTWRS
 | 
				
			||||||
SU1iTnl2dU01UXRJYXJFb2RCZW9sSQoyxOoyPMiWLvMelIOLcxb3I6g2kf1dp2X9
 | 
					UzIvNzA5TmVGS2ozZmYrYjlBY3J4Z1RRUGRNeWcKUTIEhWqr0fOODu86MDll7k3U
 | 
				
			||||||
UeZBTWke9NkQgC3YscKbhpl4bq74SLzN1qThnyLoWN6yRipSu/ttO1i7VTMFTz0T
 | 
					ThgmS9nlcUY3fMgXzZLtpHIJ/4ZSI+miu8RmLMaeC61qv6xNThGdx+MvU4tMBWKA
 | 
				
			||||||
Ho8+JqExIMCtmGRzMXfEqMepY6WizsK+
 | 
					Hv3XGi2MYL1jdHh2KYg5PgdqchYuHrFuBPS7c/tQow==
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,82 +1,82 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGo2N0ZYUSB2em85
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGo2N0ZYUSBZVkFh
 | 
				
			||||||
Qk1UN3VxWXJCV2xVRnpxSEhDTmttQXljMStlZlhmQ2t1Qi9VbEh3CmpXU05vNVVr
 | 
					RDNNZCtySlNQTTZFbzJvZmF2TEZKVUM5VjFjQWNSeHlNc1JNZ2hNClVac2pEdWdw
 | 
				
			||||||
a1NxV28vYlRKczRSQVBSSmwyWFpLRW5xMndVTkF0UnprY2sKLT4gWDI1NTE5IDdK
 | 
					OVpOTmhWWklVRDA3UzZWWk9QVG1ySUFmTzRSVlFReVdFVFEKLT4gWDI1NTE5IDVD
 | 
				
			||||||
V21PeXRQODE1UWYxYmI2VmN2aGlOWVMzSWY3aEtkdlNtSkphVEdBMWMKQ0V0N2Vn
 | 
					eWN2S29aWVNVTTdldXFxZG1vWUNYK2RrajI0OGNGaklzdFByTzlPUkUKTmsvdTE3
 | 
				
			||||||
WEU5cnRuNFRjNVYxYWNzTjlZUmx0ci9VdTBERHVRSlErTjY5dwotPiA+fGZXKnxC
 | 
					ZFBvalZsdENxR0VnV3FVSnFxTitBRlFWR1BzcjJWd1h0U3hpYwotPiAyOkUlJC1n
 | 
				
			||||||
LS1ncmVhc2UgOnZeIGRnSytTMn4yIDh9PGR+TlswCm9xODRucm1RYTlEZklkcEdO
 | 
					cmVhc2UgIWFOMiogVDc8IFZETk9BSDVTIHEKQ01rc1ZoNXQxUDdtWGRQUlRCV3k1
 | 
				
			||||||
RmR0L1BwTzdCSG9NR0sxcUV2Wm5uT3lia2FuTXA5M2VhQVZRaTF3NEZXckFiWTUK
 | 
					djNZeEtOaUl6Tkl5TDA1S2ZXWTFQZEFiV2pWMDJpZ2dkYXdBOGhSTVA2ego4UnBz
 | 
				
			||||||
dXlXNWtHWUY4THN0K3lRUmR4YkxwMHJhb1RZCi0tLSBBc1VRQWo2SjRFV3YvZ0NL
 | 
					ZGhXcklMd0NVWlhsc0Voem1wUzMyREViUllCRAotLS0gMU5GQjdJaVdlUFJGMG82
 | 
				
			||||||
eUNEeUQ5YzNlWU1LMUlOeWh1UHJVS3JBMFdjCruYC0f782So3smThuTgVCo7eZ4h
 | 
					YnZCUm05ak9qcmVyUVJSS0tHaWRRTld3ZkNPMArRgojrBQvlyjMhChn8jgUNDysj
 | 
				
			||||||
LsHM6Ak+TWwLmyYiTvyGBopAYcQsoXogrV0lfHFDOJw4/PbsDzLsl5bUmmk5+YbT
 | 
					9Nh3BVqf44fiUNMKARTrFTz3wVMlioo6MmKRzJ/yj0fWkZ2h80X68Nq3rQvy+0UK
 | 
				
			||||||
dJoNBFoxVxrQJGmwxNm6d8Dsd6dWP+sq9ETWD3aEh+erxfZiFoYEL88NuIRWy61t
 | 
					4PNPRbwY5ib0nf7n3itFKjehrYr8HnOjreQps4it52bT5re2TWIC9ogZhNKBLRvB
 | 
				
			||||||
3VNyOsg2QduTpIsEtZnkrOMk3ZH5GF/EtTqyKaGlJCGBU9t1gsfrik4JReM01VqS
 | 
					qv14HjcF5bGnia8TgSU/8nUZJuIaLwHvS5sc9GOtmV4lDwiSTEJQEtGh716Jzuvs
 | 
				
			||||||
BSV0b8+abrSc2oQIIxXQaq5+UFDXo7Cu6+hI7nuqCuHW+ckPVivHi4fqZI+ZWu5I
 | 
					XxQLPEVVufAjZUKLp+jWUhXGkvUEeY5bxE2aOLuB8kLfHPC/5p2rl/n2sW3oEDFn
 | 
				
			||||||
HxQxUfH0B2tsllzdOkbw4TBv+uRFwS9HOiXpKx2dsITiSOtfD98ZFeb+lsnc0rpH
 | 
					Fw+XcNnCHWBzk3DlzKZFXwIaZL6Ocqrt+p8CBpWoNhbssuKyOtEbWQOmJxX3UPMt
 | 
				
			||||||
sErWwwR/GxrRtRZ2U4cRB9lKMkXrd/6n2o4UqfropxC29C2pdPiZElNT3e91+0Zl
 | 
					sBFNdKSKFhoBQ4ukqkKDhgcm0i+8wG4eBbNIMIDwzPBxK0QiVriwlPQHl7RS2M/J
 | 
				
			||||||
MoPBF8eHBM0K1i7uhtZ2a3TJcqM7LOjWmeQDI11ZWcGPUqKyRDM5KjMX2UnCeqkb
 | 
					LgGeS7qrKC3SgmLu57CdUVUlnogJ4oOg7FPh6x+jQBIIv7gtYCzJb040TUZWZWvi
 | 
				
			||||||
cJ35gPpkLeamTGmFjROlnYyqvQtnFu6J2gq8rus4btxI0P9lZ+vRr1jCFm5ZAi7o
 | 
					cfKWBBwLqLa+7Y6kEhcosLUgw2c9Et5P4rvNjU598q7qrZq7uK6Mr+PMwD3Pd66O
 | 
				
			||||||
AFFj9wvg8oDxIPVKQ2HQRFH9BDYJ3pjQiXYf3TKDlaJD2BD6rrmGP+HzRPw1bgzu
 | 
					SQyT4nYhhXBnaIsLXZfima2nRzPocaBmfsuXQwlnLJC8JB6yzqEViK0xYKfl0fIi
 | 
				
			||||||
JS17pMY9rgMMnEOm9FadnYOBE2fESUktnd5wD9qcF4Szv86sl03kkte3bypgy/RN
 | 
					jxuYBw/8Y+MWQhIkF1pP8z+Kw51QdK4CIV33mlLBJnGjlizewsjj04EIgpzQ0+3I
 | 
				
			||||||
9X6+a/xEUAUzjlUZkZYIpGnO4tX+Q09xDhAU0POJUQ/bpI9nnEsdxGKxr+nA1r4C
 | 
					ZRyee/SzFmGBBk/pMGN0DizA8LS9yZ9DRGrc13rYVUTN6G5xT5AT1eEtFbQ6DH/n
 | 
				
			||||||
eTeg4M2epxEGWcOmUAHku2rWg5ou3U2kPdiNfl8XkiCMX2dVCcMF+VPLsaBj4V1T
 | 
					q13Tur4QJ8AqJmwv1cnX+faH61dXahfbinveXWqB5S95/HE3OGnZfAiS5bs1jW4U
 | 
				
			||||||
JEfXN9bACRhanm3q7xiWQiYtNrv8rCcJ3XZR+TZtTN0oIjdhpB8vCYc28f9upZ04
 | 
					D3BLaBiFMYD+ccPedg5MLXRgEryVaOWlQ5wuXxqmaCG0KS6YLxl8o0bRR3lKXNZP
 | 
				
			||||||
W3Ki7D5M/B00RTT1klpYCwp2d+TrpCURJtAWOgW2LSINE1PlcdhmTFbMkPNsKJR8
 | 
					B7Ye0Px69aYtOs58dTOq0Peu039Fi5iNC0beocdKOjig4tZ6p41uz0jPGMUoDebZ
 | 
				
			||||||
8NjYPGt6xkyKJUUaJ6/joQ3kXm5+eiKXY5ornpdgvk0Yjb8QVB5bAWPYHTjqMGRV
 | 
					MYHax+a7Qpi5M6ZVGVpF1ieW2hqnm0lfb18cEYHuXjoI/YlgVhFPCGSzHJpuNiDU
 | 
				
			||||||
8wZqlmUUB8yVxUTWOTCB8ngT8ys/YXElcdGGnjdmZRjN2CvAoJWLbw48SZdr+nuh
 | 
					qJSfOuD8HUB2iXFeEgAi+V3EKTsyjlS+R1zWxkr2awqAk7Uf3svLGWZNINHNoJRe
 | 
				
			||||||
f6CKctNPDM8Gfb4ULHApapd21L7wXqZC1yd0fsQ98jZdVUjNkrKVv1oVlAOjuMRr
 | 
					CPPANHzTSHlNPSelQ1CyOhl0W/eMCEJuJ9/6kZsmUC3zvzxEMGofG+Ub9RRBW/+/
 | 
				
			||||||
MTgiRE26MDdXlKVseMxDv/wEocmRxgOz1tBrw6FHnFCrFuvIuJ2UKO/0guTbMD+z
 | 
					TkrVvMrQv7/Va/4dxMPCqrdOQ+3/LkVzGX7qg6tQR76Su0q7aqh38Ki9qWY47bTm
 | 
				
			||||||
iW+CeT81DlLik3NVgyfOz8j5AhEilxoRanF8Hacr+4RoLQCLZQYFGvzgtNIxMeRb
 | 
					lq5I2EcQApt/O1cGQJTFowdXVJXx/qQv436p/jL1mymQ8241iQ6XX3DUjbnqdI33
 | 
				
			||||||
2FAwDBk7mVcumiEqYWXBFGM/FGqxNXuKLird7x/R9PbBptBhF50E89L1yyOb4klo
 | 
					4XcPa/B7naRkgSG1Z55Vv+IIBOzcjzUMzeQVP/WM3SFRNYT79mJnV0SsKvUFtUOM
 | 
				
			||||||
CIuEopydCtRD+WlmzxOYkCFph+oZpJmJb55Kq+i/Xmcjt7326055U5EhSo8wvT7b
 | 
					1OxMGEx+ZxfNIZqdp+qo0+uIU00ciokldh4URo9u8EIHjFVcV3Eyb7EbbCxzDiU9
 | 
				
			||||||
iIWC+qzSHDR3PSipe5XaivfavGULiFY6yz1i72FIncCR2g/KmrQP/BIkI9Nldoqa
 | 
					iwoAAaJjwBlyaRQFWYsKhY2J3NEay142WAyAiHmnNBNhZM9TKkCpjton4ehxeRUC
 | 
				
			||||||
vsUGi+EhST28VG+HXa09O4R/JK/sgdQfolohG1XCRBIPn8GTJfPFDZ1CgK2RIRbl
 | 
					hoXpzh4J2lMhdcmXXZ675C3MYiLDpajgLS1dwRp+mAUXwjvQG5rmJd7UWdgpbdpJ
 | 
				
			||||||
n9Az1u5HPc2t+Pz+UsyBDVb2Vmlmvbs3lX4EtzdGWOmBPtD735rmLre9Fu7jn/A6
 | 
					K6wABNkl601XgKv3/nV9touE0KQjHg1fzo9vzmf8zVEViTgXxH3NECZHctObwgoo
 | 
				
			||||||
KwXyknlvV5OLh3nNTUUCHrGDREw51fhnOlD//YNY+copvfxtOXN8NvRabbD+d4hn
 | 
					SlbUOW8vihCi2HU9G3tqH7dwkUsgB2a22JFovgwwW8ePKJQpdvwAV/jyFMLL6jyj
 | 
				
			||||||
K9jlqbxHBTKW+SxxAI1l+z8Eujd/nB2ISmiM8Nf7/U2L5TavMLJ3BFGL7i8ktFFm
 | 
					6Tf0Gsc/Iut6Mh5TYiTWJdCzvEBjcybOVnppj2zR32/A/vAXUrJQaq0kwKkCwG+e
 | 
				
			||||||
a9JNPjxWDtIJLK7TrjLpFM/Kw6jFdsP70oZ+elN892NPsCZF712D56KbvW4ga+Zy
 | 
					TL0hAQuA2Su27qTR9Xy2QKpQ5NppRH7V9YxCpjGfcLbcCh7XH7AEZaYfrrX8NoP5
 | 
				
			||||||
uwxk/FoY7mOYZFMbNXuPg1gcVBxT/TklPrMK1Nd9qkuMIcg1rnmr/HsuoqaPfsxq
 | 
					zPalFA+7E1IuDRtT29wFNRVb3lAet9t5q0LUHf3x+Qk23dQ7Mdq2JIf9RIo5xZ6X
 | 
				
			||||||
zG+86LDx1jwFNtllpUqf6Cyr6akxlvOofSi0HHut1qcsHWqBxzkC/TdO3rc2nt9T
 | 
					nsKa9eBQ0O5OAv1VGWVvbrVCMpmyiklYV2rcIT+dbrhrgiTu/BvODSvtmeANIkhC
 | 
				
			||||||
hodHQrOg3XXuNaNtrmmAxMJmr0qbtftMxUxSjA406QfoOaTe41YYlRLWcrR4UM2S
 | 
					uF112/+QW1UNPCENioYq9OWPcEwby+s9JkQf5nTub2o/0lTFKJxNgXa1QBcKKVyC
 | 
				
			||||||
APTQEBiqCzlItGbXVBjFfJMdMRue/yDXbz6ggCTRlOMjuGLP6+lLuois+nY/BSNi
 | 
					9aTCRhcxXsfuR7YzbCXRcK2hUW203iS8+UgAfZBVe5GhskOd0ZR0WSkse+jGzPqI
 | 
				
			||||||
zhTD6iEdCmLZ/AlQZBs2ZoLicFPsArqP7TXjKlY6GcHFyoWJGfdINlYniGgX4zk4
 | 
					tnH5F0yQgLn9emebpL6dNFUVvssjpiMlvkijXFJv1tWSKLb3TxJd2BE/w5Zj7Haz
 | 
				
			||||||
UO9pgNtkI1PIMRIDTIVMkFp0FAdbcnY6NMTyJBZR1fxS7WPiWcLEhd4u3XWlCt3c
 | 
					iv7Wz6o5+bY4v2YL2Ev7hGzfSaef+ip7/BYZ9TGuzSoZEHMYa7dNT8kRR18IhfXv
 | 
				
			||||||
i2G7D5hnVC4ZnJWj671dnQgKdWAS+Y1UcjrmhvfYzi1k/qrN0HICxk7Nde4QJxUZ
 | 
					Y3wa2xlOhB+WE3AjtYy1oTi2c6Vmd9UKASZy/Eb++j1MSPtxZQLNaj+svCmqqfvO
 | 
				
			||||||
NgO6CATuSzUXa1kq1IK1S73FBWrxhbV540N76ws512fWHK2vISHGi1TK546FXtZD
 | 
					/gElVfGlgkomYwc2EfJvR1lt9u9YGepxKrafPsgvjR6bYPwLF7eHKkKyEiqGCYnW
 | 
				
			||||||
lpkbjr564pjqL01Y8HwehW2Q8y80YQ8T64/VTwSzVi4dQKTI0ZnqPRHGH7wg3Shw
 | 
					mcNJz/B0egxhFjoGd0U17tNuZcYRD/Tsj9ugGF+4/q+IaEV2YzZTdGzupI3lW17o
 | 
				
			||||||
v1O6LOqO3r5XELziHxpFJSreEeEB5c4rqxPQjl1WeOYBoChZS3JHwEMeT2UAzXVv
 | 
					Q4H+EksxkWYDr0WRlYKn7VT1gTThuggEz77JskjNP4jK29EOIEO9IqGMh39tXsud
 | 
				
			||||||
L0Y+qoa0pB0lwDZm4LR2h4UWLWaJSEj2BqBihVBmGH0s/umou+LztWkVA+vYVyDF
 | 
					mhL2Z6XMX6sgxSjSkYxLpFnS1mRZ6uQnSptxHTfnG6jYhq//MTjGX7xmYBj5EoTC
 | 
				
			||||||
rU9bIXpdYm1zTYuyB3DHJVXkDQJwsjfQhpe4Kcd79pdPH9pudnMQliVQMuzoD8R3
 | 
					duHuaCqjRXc3yHWoNm8jepkpbe1PPbwEbL6RDK16G3g0WVREjZopj+66C2xlY8Bq
 | 
				
			||||||
dAzP/SU/5i5t8aQPOkStzJXE0nZe1bHrY+/9Cmq//n7zIRall8GVMJ5LBwbg3qex
 | 
					ZCmHhud22QHs+5r1LLSIynsUlGIOvq30DZ0F2/f9Gm7uayIYbp8gA4z7M7RjmHoZ
 | 
				
			||||||
OHViAM/+VI6UOwB3FjGbCJTP3wX0y08bxM9klvVOi0gVQkEF058A6Ir18Tfo9Vho
 | 
					+XHYSPc4kH4a3T9MucQQGzJMl1k/bifBAWLbu9uPcDUe7Cglfz0wHnPemOu8HZXY
 | 
				
			||||||
fcjJEaYHacB+oVE7/Gwz35mTOvDzkTRlfHVjbcxzLQ0UJJzY7hZl0tXviK1cphiP
 | 
					6qS1n6PAHyyGlqX/pNWxR2vQrHJRksdTCvjl4g6256PhaMDop3QAHuQj9meYKIqP
 | 
				
			||||||
rSQqwaaxp0uZCrOiQkMrwS1X3RZ5MqIJ2B34y/rSnwU6kJyx5uD0rIslZgohmNx0
 | 
					MiZexiuOW3KjPJ30Gx1Q7PnUc+w3SjjsKaZEvRgeWKa37rvj1ICTnBQUPq2HV6y8
 | 
				
			||||||
oOCDQgfh13O2SVMNYDMrpIeFQtksMN9TEmRu5bzZwo/lmf/9DjZmDe3aDqlf4wuI
 | 
					zaGnJcfd0ENAmFnRaCIbdU6TRonnIAAuSfE2gtLni/PJbmUpznuq82W//kxvH1tR
 | 
				
			||||||
PO7Qt2vmPHcgC7aQ5fqQYzFtYko86FrRLc/ih1Jto+tfnqt/mD1kCLi/w2dhqKu3
 | 
					oPx6LuM2+hRncMoyXUTWSUVO1DAUPXgZA+j7fkkwmosi14d/5xe3wO4U3dGZ6wAY
 | 
				
			||||||
E1FWKmc1jzL6/K5sPxHHSaYjmJB4YqQ5VzmhV23uzyydarySDO+atM8UkaC/FIvX
 | 
					D+zlzhq4d/4vIvLIL0NoBcp8yM+xWxPTtvj7HUJ7BOVV06ICnilUlv2wjR+dZLZK
 | 
				
			||||||
uV/LrLBDxXAmuuV5493ga4Lo+EWraqeuCWcA+kofqrN7ChH4hQnGQF9IAwhqaOzQ
 | 
					DyjWhMoqk8r2TDZbAQr8MNX+sSlp1JxQEgBijpqBvRdF/ulqraF/GFDFRLcEi7D+
 | 
				
			||||||
DSCrnL6Ame3W1nhJrQmzm7ACtowyFmTL6BVtnPNnHTEeirrKZzrtpEk9tm9GsMxT
 | 
					AkHPg4TrmaNB5ixsj72j0xruFJxgQJGj8fwQtemJGu8QcuJbCvJ74TI3vu0Pac/C
 | 
				
			||||||
DxmUqWk7A0s6nBiQ+Z9oCFyCAsLaXUPIIxfyhirp+S5yyhKrkgy2rBGeKIXi+jmp
 | 
					MRov1TAVJB7+iVvVNEgCMlzimJCSCUYh1Zgk5Ci2CDFMFRAEcGoHywIW6v5V8j5o
 | 
				
			||||||
WSARJVaFCqkaRYqJdnm4mB8haXSNyHLqFSYxwijr+1uAuD7GkXhbFztv6bvKC0yN
 | 
					v30mJKZCVFc4Yibivjj1aGhQVO72vgiog4L++i7CeXHIu6Fe1Jmlve5iuxrQA2aM
 | 
				
			||||||
mbCTQJT+tn0ixOTUb6w+EYftekpg3sLuxrIlfBBUBBUde2ZqZtqZ8hCUBoYDgovk
 | 
					9vjCbFJIi8k5vQTVcKPRcsto7/qbyxvWvahKBBbHl53XnSb0WtLUyTEaXJ+0l5gy
 | 
				
			||||||
Ka4eXTfFwxhy0efC3DAjXwlvCXjRH5dF5Opw5PdQjt7sPD1qHYb0g+YcspNNOOMm
 | 
					Epxfl6ZRNkt+YBYBqCZL9aK6TNpCR+zTC7OhrKcZntqFYCeRB25YEfc1z0lTH4SE
 | 
				
			||||||
cK0mBD2atI/TRA+JAHzTD7yL8t3XP6QA/ELvDpdtRkmVRhJk2vfDMF4NVwfjYWqc
 | 
					TPymGSMOeUX8YEIr+XNYG0H/I7ZtEdNGBEXaUrC4YUNrvojpq3PS9bhfLhAf5D11
 | 
				
			||||||
RBBFozGx1yffVoRn4ZZfvdITelxotwidMBpZ2ene+Q9Qj47szfKm147EqFqZq5ZZ
 | 
					wmI2tS9cqxAuS2zkaBr9Qo5xNEVsyGNFd1K0q0JJosiMnVZDzOA4wJTYhOw5gwcW
 | 
				
			||||||
5b7asWfCd3K9M4mYGy3lqtckbNEEFWRHXxiCObIRC3GRJ3rGWRWx5BRclGAeFHqd
 | 
					T1Kh/LDvK4RE0CV0jRqN81YO8V6Jq+/c2kgtwTLzrx1GCcdHRsY2kPhCEWOTLKb8
 | 
				
			||||||
eFANicRCHuTvgRI8JtGk8wH6VJC1oHAL0f2GnqNY0ve206+pKMuqcpxqP5VPI2EW
 | 
					Jn5nyyvOOjMIkAEYYqoRRxl05UbNWNS9SuO2g9HF6JpNJmw0cmzT8erIIjVvaUs5
 | 
				
			||||||
eIlqiGL3zDuJFsyjOEVpt8adEo0Ks2IV4Wc7zn3dtVMRn5VBuXlLF5/8/bYJZEOM
 | 
					dd0Bd5EgkkLq3RMPNTiidQCyIy8QtoElmxYfM11mbf+JMgxsB3sDcRGN4lauUhho
 | 
				
			||||||
YgW6l2O5ABaY0Hrog0UqqdluvrPl7/qwmMFK8rHkv07n1N0EWRpBAdOXpgv28T2E
 | 
					JlayuFUfrQEwtHFwyULiJwUC55faVqOQzyvcQ8C9AJezDXS7//ku1kvEgbzK0nFm
 | 
				
			||||||
r/5CWA5PIoX86WIOrFAklEg0pfwc/nMl4G22z4hVKeRcrXcSTJ/hpicjajEVre36
 | 
					3bCCiuog7pG9XlldSReYvlJtnqTmp6E5+m9YaP+yB2E+swKBORHkbCfBu1CuX6R+
 | 
				
			||||||
VMYOyc+/4CXoJ9rL/kdSJ87zlOnejM+SBld1nTikRI3icG5ahX+WKOiEOEKkw0V0
 | 
					aryBYIDeLaIiJs5GWJN//37TT0hVUCipY9QISfTiZ5tIy0aNKRu9syjWphcoTJuv
 | 
				
			||||||
PQX/9W5l3v3g8O+4fbrjIpsnHfdaQE+X1Rfju+EQ//IdWj3Uiaph+OXgCX6tr4r1
 | 
					YBaRxKNdZs81ppFTa3sXB824+QXwzRJJPjBndXOtyX/a2U68NK3dqau/A5190VAn
 | 
				
			||||||
c5DhsAl4tRhzgHQHeHXPqb89B6mf5FuCDiKmUNYl92vxn8+AUHiCah/n3Jf97Ny7
 | 
					bn7jnJ68rhcL9ewwydQRm72qwyxBbRHFXnEXpkJhzYRw6fosglqbOJMxFiy36HWD
 | 
				
			||||||
2lliV8bKL3XoioKrC92+942TP25l0ufbbxekYfKnmXMmSf6aLx1vY4cj4OjkJU4T
 | 
					RkVluvTInw8Em/DhhWgn+UrxLlQN6JnVdpkT9hwrlFWooiM56UKAPO2a1FM2XKXe
 | 
				
			||||||
UZVWnh4w7P5LzoEMZCoLHBzBIEa/puUaAL5vCPefaXekBKEiAnl+LQh6//kTAFRK
 | 
					TqsolY07uWnA+ouiljqIpsaFlVDBcz/sGZWqy4aKKPBTcZlreW88PMsS0c9nixVi
 | 
				
			||||||
XKgoU3BAIy6D8exVdkniva6kVbQ+0mMROywSJ3P2QrCNr/Kid0js/46m5qUpgJKp
 | 
					nKnmI00HuzeL85zVHGo0IKYfktVVjuZNPzJ6+w18XpKIi8TxHpxELC9M2kVOCnuy
 | 
				
			||||||
m+SnkdmALU6vIPEORnqSEa/Ku2s/kOdUwm9vJPdD21chLCXVwDPmyj1ZNmIiQB9Y
 | 
					uwuntJlRty+GpXVvx2VLi1wBKyLpXUxhyg1tSi2sZyjIdVt4yEOKfajZYOp73JZx
 | 
				
			||||||
EULpw6z1Sg24awXuiTKkhIpJhm6CalOhTNkeLrU1W1Q3zaq1oVWkCLCsukhZk4xk
 | 
					IcInD7Cby9olkMsa25YhloljY8YELfW8EWutF13m8tsjGP9c6aOuMIXhrrpwLgYy
 | 
				
			||||||
jugqrDYRPPv6qQj9dr6sF0SKe/2hfIXCve9yeHU6jhp8PaBNp73EErsjdkbt/FOm
 | 
					E27iFh9tHq0mjCMibwQnHld7Ccd4OqO4AKfPofHDxWoY9+ivArOBAXjsCxhxWWWp
 | 
				
			||||||
fbr85mqB7ZvXf0My9joxZLKp7ajarwsFxSggthekLdYwlLm8gSGqYRk2AkvYa5E0
 | 
					aLqLJz+JH+idcsVDlw8jJzFW6pQFbM3VxXObvCg9ou5+P+Pc5XYyALJzIlmoOrN+
 | 
				
			||||||
WGZsi+DM1FvsA+St3m3znaHyQKKRxMlcNwaMWP0TJCuWUj0DTIWHvjjLKr6dJshM
 | 
					ns5Z+U/2XKGyySQASUyFXUNml6csSrTd+ejz1QvEX9POU1nLmvS1+aojgnptgdpn
 | 
				
			||||||
nrVMBlK1X7TO5QQh1+r10gcMy2o1
 | 
					sAtksQHMt1Njo1oRug3+/0iC6XWEig==
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,28 +1,35 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGdTeFAwUSBncWNO
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyB3QTU1
 | 
				
			||||||
M2Rzc0xVZ0hvQWxtZTJJd2dZWUZ5MkVUckZ5MU9lcFJlN0xQS3owCmdvZTBZNXIy
 | 
					TEdvbFNaUmE4U1lCNzI1dlloVDBTNXdURjZ2akRMV0R6dm5ST0FNCk9YclRSakhT
 | 
				
			||||||
dTIxdytiVzJGeXFwTjZHY1hoWWlVVDhOZnRmRWJZcS9CY1UKLT4gc3NoLWVkMjU1
 | 
					NlV2UVJwak9Fa3dQNTNBK0xKWGlkNXdwZTBEMm4xZzc3azQKLT4gc3NoLWVkMjU1
 | 
				
			||||||
MTkgVkZjdzVnIHRLRisyQ0ExSkUzR2R6Z0xocmZ4SXV6YUlsMnZESm5oc0NOdEFK
 | 
					MTkgakk4UkFnIGNBMHNrdG84cUQxd1lqQmJIczlScU1jNk52Y3BtR2tXeDNWdWRX
 | 
				
			||||||
WW9TUjgKclVCbmZLNjBNUjErcVZ4aklHTU1KRVd2SXpCQzlPcTBtUkgrT3QvY1pG
 | 
					cEFCR0UKVU5vem5MZUFPbGhoQzJTYnF4OTd3OW9jYTRkazdocVJkZ0pRRGNLek93
 | 
				
			||||||
ZwotPiBYMjU1MTkgSUZwWE5pOGNMeHZOU1RhVlBIckZ1UmlZT3JXNUlTYXdmYUo0
 | 
					cwotPiBzc2gtZWQyNTUxOSBnU3hQMFEgQ2RUaEUyV1ZGbGRtZnlIUEtTQXk5MUZF
 | 
				
			||||||
UU5KQU9Edwp2STJ0VE9jZDJ4aWhaVFFuajRHR3E2UzVsZDNHbHVTNW9aVlB4UGRu
 | 
					djYxZ0hBUThlV2tXTHNvdXpVSQpMdiswMy9QNUtCb1hkbGRqR0Nia3FXTzE1ajZL
 | 
				
			||||||
UU1VCi0+ICVBLi1ncmVhc2UgbGBiZ0MnelUgK0ogcyU4dTIgVGQKNkJ3MgotLS0g
 | 
					UXljSTZqM2YvbzVuWUFzCi0+IHNzaC1lZDI1NTE5IFZGY3c1ZyBYL1NrRjRaRnFn
 | 
				
			||||||
Tlg5TmJpVkV2dkJUZDI1YjR1MitSTW05dHdpTFdGOFlQemwvQ2p6dVpCQQrcRVSM
 | 
					RlNLdWJ3cThteDM3WmNaY210d3RmZzhCYmNpVXBwVGlVCjBkM0IzZC9zNjhmTTZV
 | 
				
			||||||
EaN+F8T+cF6tMjJC3BOF1wYm+iJ1EVesnuFa85J4T50sRQgb+ePlJIwR87NYRrNn
 | 
					R25ySkVoQWxQQ252WWFlWWZFMlc5dWtUN3VvVTgKLT4gWDI1NTE5IE8yUU1pWGFr
 | 
				
			||||||
9wpiDSgv+7dS33yfqVo8M6/Bvt/wanBK2uteEfoJyB0a6UZ4cbRqAr8msFCriyPY
 | 
					NzUvZVpwalB6aklkWmJGWUQzTnJiRjNzdzY2MUp6MkY5M1UKR1VIWDVyTFpxem5F
 | 
				
			||||||
GrGZpinA/h9jxr+GlQdS+WYce3xbzc4b1tKzHY3NiUY9aXWokhXjzjTzHrqefBLW
 | 
					TmRNWE9zZStLanRTdlU5d0NOSEJKdWhDUjBCdy9vOAotPiBTJCd2NyFYey1ncmVh
 | 
				
			||||||
wa0EvYFUxuazoVX5mjhG+pET/WEYRPGZoIfLUTRvV1Xx7W+/7SIsqLYLKqqb+GLk
 | 
					c2UgfE4mYSBXfms0TC5FPiBiYmx8IGRFV35mciNoCjVZdHRiVUtMMWxEMlJ4b1F1
 | 
				
			||||||
ec6P1104mIjhBY9TUbbeMUMTMBoskd8nr387QQAtU9c89FgvlZ4am3X0L7iUv9lP
 | 
					TGgxY01XTlZpTEtndkg0T0hRVjlqVUJGMUpSaE5tVlZWR3VGenpkUXY2eXJtbmkK
 | 
				
			||||||
hxTOgK86HwrGK/eKzO62gSjIfrRWBOMDWl2iCZ/4t6pCGnUxky6IA4iN/slnKBEg
 | 
					ZCtqRVN4dnZENXdoYkpjNHRWYXkvN2laY1p4YjV0WQotLS0gOHlEVTVOSmlNemNQ
 | 
				
			||||||
Y+V/8YQ5iQN7F9UpRSVkaD6IGEaY8gu2A9FDfh+i/KkfgBsAtLGhf8XavKOLCjYR
 | 
					TW5ISk1DeDlEM1RoQ2JtUFlyTXRKQjdnT0hiend2VQqrUFvr+76sKn0ldBmZMlEW
 | 
				
			||||||
1csUFlyJMn+Va0iPr8YLlLmxn+JU8usX/Fysun5qYHLoeTJAUWV0yIIrCgk0XvgT
 | 
					U2k85DLo2KU+/+GtbkZwVXxxIZHMLpoJgghHk9ptdalUgLGcl0X15x9jVaw8aeta
 | 
				
			||||||
P9Rj12ShAKeln+nNX8hTA9WgEoqsASxUvJyAP+m09fOczr2xLcROU6YZfXLxb03R
 | 
					hbeOHotRHY7bC3z0S74riTk3xDMR1eT0QGhDMWHjfo8SkCftOYBlFfhTftevdep3
 | 
				
			||||||
GCBJtPf5pYWRW+562rjg2gnnkvsi4VhpG6lnaPitZDXEE5VAoErFTEo2NEKfdaJv
 | 
					pKMZsuQMwH9JzxgUfcxIcWE975cZzrEJ85nfWMGvdSjcg51KNxP/UUPRxDlcbCEf
 | 
				
			||||||
SwTYt8cb8Y2GR4Zl5qJEZnlC9GbJo2Xy4fAEfCo0Ox9uuJrvchXIl/tIu5W2o5ie
 | 
					9XX5apSzNsTI3ibGD1n6Qwq8bdVYDMHmy5pAhw4l8L+SdoU1tGdw7JOA16sMCJbx
 | 
				
			||||||
i9FnaU0ZwGBWn8gayOPgos9nNsxqj5s5XL11IyWvcxapP1eomf6ud0nY0RiQNVmN
 | 
					T4bV0ky/PGRonjJuCyDBj8oe9vMe1ZI1O/ITtktekS+wocxBs6QXlY7pIZMlGUn2
 | 
				
			||||||
tj/oFRGFBUkva7amacWrYmUUD/JSc6s2aJSI3kuiuFkaBAXF3UPRLtg7Gw4B+OL3
 | 
					6m59ZEEaf7R4/MdnmBDNDkQuyXaKc7SaTc6h5sKWzXdYScGUKvgUQ7U/WJ2ItUTC
 | 
				
			||||||
VkJiBpNP4KJUvmMBAbHDoIIVwNW854BFSI6R4kLGC1FvsEbx+aPu6dPFNnzO9Yom
 | 
					N/Xq07GkZZMt5MYBlyEr+/mKWlcy+ylJPGb7EswvQWaHoeM1QF0XLZ1v+W/Xsso0
 | 
				
			||||||
fWH0Q2FHBU7OLKJygm+X6jqQishe6mcaVQl5vaP7EHuylKwmA+dFCoHkTY4/gpT8
 | 
					seIoz+geSu9a02kwfsa8WvWXdIAT5X2pNGPClVNzjQ23pfQfQuW8ZQrGmIFR4g5A
 | 
				
			||||||
ikSOzoIguvIITXEJdRi8+K08QfJ1h6F4Hrzj1BOZj6aWTwHdrBcAFzRniRVtPoaN
 | 
					58T1K+vGLdShqqVGyJFMVrSuOzqX5FVmZalu7/++1IQfiRGUlrHKoPlKWnCfFEOu
 | 
				
			||||||
Z5fwht5nryfb5wuGH8Smvycqx2EXgu0TURtmd3k=
 | 
					AYjaPeEFX2ByxcqfMK1YVPvUufdISUQeaQOO7mXGE3FqB0oUqmRIUiWZATwhq3Pw
 | 
				
			||||||
 | 
					p5QdcySTnmMpD/w05hvwski77kCdmYuHlMlLZez/kfhTnIGXris+Vwi/V19bsZ8G
 | 
				
			||||||
 | 
					zwaZ/Xr6WNC+df5JqSfTGREnXZPFRDkaTt3ri5/eEm6BqliuYjGbuiKsDECi4+JX
 | 
				
			||||||
 | 
					bHpH6LBBoKQ6ms7jCAn0Ls4cUKF37PcjGAOuWnzCSBU+REht1EDfHzx4C7hNiP8X
 | 
				
			||||||
 | 
					87NjEqJbwE9lORho0hQJRTn8uriQcidlVoB3se2SYKbMy8UA4NNnxN9PTj0TuQjL
 | 
				
			||||||
 | 
					OD3LtqHBElqNPbGNyyEAAJmMBmmkUvPPXlGQ0D99b1+jIdHzYSRtOLshBFykqWYQ
 | 
				
			||||||
 | 
					LJD61duhGqcQqcLx4+JdQ+oVcfAI2nG7YINnHB0OmS2DOZvvwqQ7ASScSujUWIjA
 | 
				
			||||||
 | 
					LNQxu3ruMz+bw/G0tYZBBiE=
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,11 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyAwekMw
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBEcDNm
 | 
				
			||||||
WG9LeUliQWhKQkpPbFljb3JpaWpJajlEL1htK1hVbDFibHRTNXg4Cng1RG9SMFhX
 | 
					ajc3a0gwYmVSdkowak1aakJ3VWZ1Rk50S1JIS0ExVktVSW9OVWljCjJqbUEySlNK
 | 
				
			||||||
RXZoWHp4MFNaQ2FFeUpmV2lFOW04bzNRRGNnYWZ0NUROemMKLT4gWDI1NTE5IEg5
 | 
					a0xyT3NPK1BBMjZzN0RrLzhwVitvS0pzQ25iSnJSc3FmM0EKLT4gWDI1NTE5IHk0
 | 
				
			||||||
UUlKdGNRam5IMUp5aVQvUTI4eE9kWXV5cXR0blZnYTVFTTVaRlVqZ0kKQXRMbG5T
 | 
					M2pkWHgyMHR1WHc5bE4xWTFDTndKdkhRdTg5bzZIWEU2cm02UDZBQjgKUUY3dS9p
 | 
				
			||||||
ZXgvVGpybTBlbjh0RDRnVm5wcXQxZk0yY0FCbW9UR1dTZ0pKVQotPiAuYy1ncmVh
 | 
					U3h1L1ZvTkFPdURLZ2tSYXJXOGNZZ21KVGdIbXdhSUJrd2puYwotPiAoL0RtO0lH
 | 
				
			||||||
c2UKZjFEV1RVRE1TVVUyLzNCZHp4VzlHRmNKZCt1bDIyT2lnWDNuTVN6ZHNpSjJX
 | 
					OS1ncmVhc2UKVGthN0ZSU0ZFTTg5YW9UOXMwa3RnSzFlMjE2VTN3Ci0tLSBwMEMx
 | 
				
			||||||
UTVuY0gvYlcrdm40ZUYxem55QgpXSFdFaG5hMUdIakRpaHIzQ280eEJUdkRkRTBm
 | 
					Q0tQckd3SzBwUUE4SndMV01kUjVrOTdDWmxlcWs2Zy9TZk5yMzhvCrBXyLBZGuSD
 | 
				
			||||||
czdxNnZxUlh1dwotLS0gclFJQTd2OXQxZUJIdFhJcXBtR2lJT1J6RVR5dnluV0hM
 | 
					dJodNI13obTM3UvX6hSgQ8Su+J3fOKr5NibkhQ0Auvlr2tUXhhDm2WOUlHjqVTq+
 | 
				
			||||||
VUdqMjVqMnNQUQqejqBp4AOrEgmQHT6loz9TYgmUK6iohAAcxKPRWKpSHFSPb6jH
 | 
					jWLSyhioDlIEyBgk8Zrl7KGeDzBi
 | 
				
			||||||
nJSMdNXr9jo5iwETMANiRTCVOLTkuO/RqD6XwNoD+0wFkI/BD3Itlw==
 | 
					 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,15 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBYc04x
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBzaEo5
 | 
				
			||||||
SC9kR1Y3anNQUGZSclBSMVIrMDFqZDFlZVhNWWVSb0JZc1FqYjM0Cm5nUWJzWllO
 | 
					RzNndHBLMUl3Z2txdVZoOVJBbWsrTVJwY01WeHQ0VTBaSm5VclY0CnJLYStYNEI5
 | 
				
			||||||
NE16amkvWFZ6Wms3ZzdLTjdpRUZOdndyeXNqMWZOSlJtZkkKLT4gWDI1NTE5IFV0
 | 
					VTN3dEQ0ZjBKaU1PZSt3d0lldkE5VC9wNHdWazNWV2F6WWMKLT4gWDI1NTE5IEJ5
 | 
				
			||||||
bVN0U3kxZENOU1RuaHVseUI0cGhtRXQyWHgrM0ZYNmpvLytucUUva1EKNS9QbU1l
 | 
					amlzTDhCOFF0TllPd2RsME5Cb1lRQUZPTGNvOEZnL1J2Wlpnb29GblUKT2t1NFZy
 | 
				
			||||||
NFovRXFnTnF1RnRkK3V6KzhBeDZMQ3ZPdGpva29zM0ZzcXdVNAotPiBZXzBzSF8t
 | 
					blNZSHdxZjlHTlZmaTFYT0laQ1IwOCtDZ21vTjhxM0owdTAvawotPiBLYS1ncmVh
 | 
				
			||||||
Z3JlYXNlIGRKKTpgWyZXCitVTUg1VnRKU0dhUmZBY0F4VnNqNlprRE1YNWRveWw0
 | 
					c2UgRX0nVGtpSCUgNVNDWCVwIDBuPjM3MwplK2cwc2htQ2RLcFhUZ0RSc21uQlFV
 | 
				
			||||||
NTRDZUNNbm9MdGhlclMwcTZaS1BOMDgzRlp1N1k4eFgKVkcwRAotLS0gMS9tcDJL
 | 
					Y1QwSStOK3lKYmVVQ0J5RXA3Zytaa0JoMWtlWU9qMHBLNktFZWxtbFpDCnJyS0JJ
 | 
				
			||||||
c0JKSjdIQ1Jpelk0U1lCOHhBTjg1bGxuc3lsV3FzRkl2NnRnWQqapBTPnK0EVrvY
 | 
					WEcwbndYbERreFhLZlRyQ3E0czB5NkREancxZk5BTGdWRkR6N2NrZmFrbnhSYlZZ
 | 
				
			||||||
ycL8K7wHa/Wx6icU46t/F9rlwAdSTc+hrptogpPbEb0HxC9jjVacJOiMQI8cW7Qd
 | 
					NElHNEEKLS0tIGVLdXAxU0ZaZVkxaHV4dEZNNUVuc2J4N3VRMzZzTktSMDY3bDVB
 | 
				
			||||||
NpBXk3wdNtroDHbl3ZD4APcXohOf6fKVnuA4l5C3o2q9tA1grmcQAMwu+GjX+QAN
 | 
					bWtmUVkKigIZ3J0s23vNzmbzJGjSMGBXK6o6xnsA9HXeQZ13VgKv5Qv+UHu+Z0g2
 | 
				
			||||||
S3jIH3AUjjzIQLccetH+SZDIy0p9F1m/5mxTF2hEUBBH1MxHWMZWJ9kg
 | 
					TeKdQSrHbDB3ydIxaiXsi2ivULdrIMCyd96rEJFxrkVuVqSZE0ehG5j+o8lKk4OU
 | 
				
			||||||
 | 
					PDe70slbZrVYDSu+OOUOCVRSopZreCURlYn2Pc4rjvrMAn5r1r+/AxjZMdkmmQZ0
 | 
				
			||||||
 | 
					l0wMBTus5zZzKg==
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,15 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyB4Q0Qw
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBoZUI4
 | 
				
			||||||
UWNSRmJ0V3c3NlppdXpueUlFdUJSWmpmWlU2OWN5MjNYVFJpa0NzCmVHbnhxSS9t
 | 
					bEdWSW1pcDdMYVRJLzdQOWhsdTlZMmlyZjRVeEFwU3Z3NzVFa3lBCkxRZ1FYeU9D
 | 
				
			||||||
bGZCSmpzMGtNalBKZGVhV0h0SWc3azV4bmU5U2UwaU5Jc28KLT4gWDI1NTE5ICtu
 | 
					L2dramp4WFFlREZ3NTFnWUs3clVEcnBhLzExclVac1M2SG8KLT4gWDI1NTE5IHVZ
 | 
				
			||||||
d29NM0JORm5iZGFzUm52ZkFIYkFwci85TWRqL092WXozdUM0aXNYVm8KMEhtUE1j
 | 
					bk9QYy94Tk50c1dVanNvNzhpYWNqeFMzVVR0eTQ5OXozMmp2VFlad2cKaEdvUnR5
 | 
				
			||||||
S29raExJM01tNENMcTk2UzFTaDZrRmdkUm02OTdiZ1k1Y0VjcwotPiB7aU42LWdy
 | 
					ZjhsQ1FRaittQXFkbnRZei85MmtWb3pXRVFsc0RzNzBPMXFMWQotPiAzSXJZb0RE
 | 
				
			||||||
ZWFzZSBzIEM/MCA3KiROIC1QSkwKSWQvSkhUUVd4TzEwbTI1VTViWWlqY2QzTFhj
 | 
					LWdyZWFzZSBudCBGIDklTWIjVnwgM3YvCjRVYUd2TForc0gycnRBR05MbU90QmNu
 | 
				
			||||||
TVYvcHYKLS0tIHk5YkZ2M3FPY0lJVldvVTJKd3NTSHhOeEpyOERVa0c5LzlBU2Nt
 | 
					dXlmQVB2bnZyME5heXlyMUdGTmR6SVd5SHcrTThrZEJYRlpnUmdmWnkKU1lyNjQ3
 | 
				
			||||||
SHE1VTgKVVe4VNvZral5pLuXVu1padzWA2w+xWhQgTtMVRbbO3fBvzzHzhbbmojV
 | 
					T0J6b3NPQ1FYZnhxTjFrYmN1UUJzMjEwcDBwSTJkTnlmeHl3WmFFTXB4eUVMWm9i
 | 
				
			||||||
/RAKf8roFkc89xJ9W+QGvhuHqoCEam7RYqc+Zt5AKOYVVxqDCUEb7bEAAXU5yp98
 | 
					NExUZzM2SHlLLwpiZjQKLS0tIHdqakpMSUNOdnlBcVA4RGJHR2d5QnJNT2dVclZN
 | 
				
			||||||
t0kTX0AxriBfgrjPSMcnN6MsYs1VPn4YhDKdOy1Kg01S1x2UKd2b+JkBh4dJJQ80
 | 
					djd4WXBLSUhORktzZ2sKzMjxqL3UPrtGmXDijdfu0AwxLJooK7ZKauYvXWSuZUrR
 | 
				
			||||||
PBHPrCFbbbldQg==
 | 
					vl5i1QPMEEBYEl+NaZIFgxAFqWpAXHQ1VxSijMWxNjKUd1Chq0tbLrpbh9wXJflK
 | 
				
			||||||
 | 
					SW19Wyqc9eTb8BnFoOSYWpDvAs2Lbyr2kJkOj2TNrwMv8nDJdOB8XIPlV5drCj1q
 | 
				
			||||||
 | 
					Dx/1zWqm6NMYxsep6eZkv4AzxA==
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,13 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBnaWFz
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBrd0pM
 | 
				
			||||||
ZVlRd3pPTVpCM3dkakJXbnJid3NWYlFRZmJFREpJb1hHMGJucFFVCk0rRHh1bFBG
 | 
					TGw1anJNaGoyQ3lMUis1cHVtRWFPcFFNZk9Cdm9TMEh1QTdKc25ZCm9VNzVQcUxE
 | 
				
			||||||
UnYrdm9xUUFLNVpyd2xRTnRFQ01mUGpOb2lieUh5ZDJTMTgKLT4gWDI1NTE5IEky
 | 
					Njh2Wi80RWszSU5NczRNcHpVYXpRMzJNcDRsdGxyWVZsUDgKLT4gWDI1NTE5IFpT
 | 
				
			||||||
R0kzYTZQZnh0TGFXSzhaUUp4enNlZTZXQTUrZEYrbWE3ZkRPcitkbGMKa1dVbUVj
 | 
					MEJVUkcycVFJaVFOUURoL29VT3R0MVJCWW04NXVRVEpKY3hlY1lWRkEKcENya1Jx
 | 
				
			||||||
WUZGMUZpUXVCOXBnMnlXRVgxVzUvZjlyNFdFMjlzVWIvS3FUMAotPiAxcFJRdC1n
 | 
					VnBCMVBrZkc4VDkvMnZoTllCL09vQ0VOZytuMnRvYVQxL2FldwotPiAzLWdyZWFz
 | 
				
			||||||
cmVhc2UgWHZ2Yk97W1wgK0RPClJWSmczZy8vK25iYVVIWVdmSjZMZ09zb0s5SStz
 | 
					ZSBCNX0gIiB7InIsfCAkOT9uM2UKUWpSYTZ1dUo3SHNaUlFibTl0UDhTaFh5Mk1n
 | 
				
			||||||
OCtrcGxVbTh4ZFhNU0lya2VML3VOWVgxWDAKLS0tIGR5MjhyOU1naGJyenVBYWZ6
 | 
					bFp2cjM5RGhqU0s0Qm50Zk1pUVZmT0R6ZjBoUG1EUGlKbHFzVwozQ2t1cWVDVVAv
 | 
				
			||||||
ZUxRNmgwMVVON2pMWlZybHN0dXI4SS9HMXcKZTI6JjBiTsBbdv8Mr8REAxlVIG0q
 | 
					Q21QTjF3NW5UdTBZRldnL0RmSlV3QndHcDB0d0lvZ1RHTTByS1ZwNkNVQnU3WmVn
 | 
				
			||||||
Cl4PrX/rgiOAJbtrUsvBuIABgeWxPordi1yMXL8XQDZDs++O40nXAtW95zjd7pAH
 | 
					ZwotLS0gb0Fxb2FsYzgwRjJwSUF3ei9hZVR2Vk1ORDlIMWoyZ2RTd09hUmtvMWpD
 | 
				
			||||||
nwlFdNyq
 | 
					cwrEjdaYfoGZ9i/S97xL9QvA/yii+sJLeuUzzv7a3DE661eQ5ezurV8Qz1tIhxWG
 | 
				
			||||||
 | 
					RsOppaaj1podFx3U1x7QQbLO6zQbJA458RMjYgc=
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,13 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBpTXRa
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBHNWg0
 | 
				
			||||||
MFNiNmVGT1FXTTlrcW5iTVhIOVpaZ2xSUHJLUm5kOXd4ZUlPbEdJClQ1RjBvWFN4
 | 
					WGRGZnlTdEhsRm96T0ZMOWx4UUxkTitJa3hMWDE1dVkreEtEa0RVClpvR2I5NGpz
 | 
				
			||||||
aWk4VWNYM3k1QmxqMndBNzI4ZEYzd01KUlloTzExNnMvWXcKLT4gWDI1NTE5IGZ0
 | 
					aUF0N1VZU05oWXUzTEI1TVBLYlVVang3Zzgwbi9teDVlQlEKLT4gWDI1NTE5IG4v
 | 
				
			||||||
elpiN0F5T0twV215U2N4NVlTTVlGWnNaYnYveWJNTjJBc3hhNWJuWHcKeFF6UnlE
 | 
					OXRIbzhaZEdXc1pjTnRRWHVxc2ZTcmozSlJkY3lyOGtvd1BVeGprVUkKdUNqSW94
 | 
				
			||||||
TFdrSldQUmRNZlZkdHJub3NFc3IzVTVQZXFMeGVjUVgwYTZpRQotPiBGLWdyZWFz
 | 
					SUIyOWtsNU83cnVOTUxNR1BvWHJPczdzUWc4aGp1MjlpZm5ESQotPiA2KSV2PVx5
 | 
				
			||||||
ZQo4VFRXbVF6S0g1T1dyT280N3JKck4za3lQMk9IdVN4a3dWRmMKLS0tIHcyNU8y
 | 
					LWdyZWFzZSBqezVxOHc9biA+aD4tP20mXwpwRCtMUDhmcVhGNXpCZlFmSllpdDVp
 | 
				
			||||||
S1ExZ2VBNHJRcGk0NTNTUVJWYjJGdlpkbjlITExUM2ZMNHFFUzAKpcjYGp5hpP48
 | 
					SmFZelNhZnJlR25DS2l2MlQ3ZGFtdGxkZEdEWVNrRlk1VEZBRm9GMHBFCkVlQ1hp
 | 
				
			||||||
d9o+H2zQplmAmMau78pnvPqsEoYSxvaQ/6oO5+vm81VqFkYEqUBMqVNZ9viJGRsq
 | 
					WnhOTGl2R2s5RDRKN0p5TmF6Y0cyN3ZlR2pDZlhMVjQ1c0FJN3hCbFEKLS0tIEFT
 | 
				
			||||||
UA5l70tl+qgDc3EKxecQ0wAH
 | 
					bjFiRStXMmJueHdsRm1nU084dDRpS0tBT21ENzZFclJXbE11NWJETm8KyMHU+tZY
 | 
				
			||||||
 | 
					QELtZCbXKWnP8QC6V84JIFAxoRslACwsIJZpogcZO/IFIV2RGunGjCJk6QBmhOPV
 | 
				
			||||||
 | 
					kJXRcGO/ndYjWfuU0U3+9HtPocnO
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,11 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IC9FSlh2ZyBYL09w
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyBOZ1RV
 | 
				
			||||||
aWtCSnR1SlF5dGl3ME14cEVXNXRCTlVJc2EzQ2h0aWcrTjZMSlh3CkZVV1p0ekFk
 | 
					VVpOZ0Jhd2x4YklMOHdkNkd0MEM4ekZiYXFKMjRIdXlZVDFkOTFZCkRreDZlK3Bo
 | 
				
			||||||
cGdweS9uOVNKTFZtK2xFRmRYUDU5cjhYeGxsUi90QTJFWUEKLT4gWDI1NTE5IGVP
 | 
					WmJ1MDBxSU5UYzRuUDMvdnpVc0prNFF4MjM0M1FaZmg4V1EKLT4gWDI1NTE5IEkz
 | 
				
			||||||
TUczWU84V3Znb2UzMnowTkdheDFNYjcwNWNiRENVSnZaL1dnSFV0d1UKT2pwdmJX
 | 
					THNsVDVCbU9KYWpXL010OVRmNjBVVmVyVzhRZW5McVFJcnA3ZWJvZzQKOE1lQnVX
 | 
				
			||||||
aHF5aGRiT3c2bGtObFZtRTErQzEyYnh0SjliMGRTcXpYbjJDbwotPiBYMjU1MTkg
 | 
					Nk1rWVAvS1lpbDEzb2ViUUE4RlB5NnJOZmNoUGdUMGNuMk1iMAotPiBuYVwtZ3Jl
 | 
				
			||||||
azY4Vk5IdEhoVkhuRFdDOWVnV2poQ1JxTlFPSVlmK3lNei81Q3RwL2xoVQp2Tnk0
 | 
					YXNlIHdYXzh3MSB0TyREIGpdTjheeQpJZ2pYUyt6UC9vVmRNZU1uaDdvR2ZUNG0K
 | 
				
			||||||
dkxObzdSL3pseFBHRzliaDJwZXpiTmtNUFBCcFhCYmVIcjFLSE9ZCi0+IFUsdy1n
 | 
					LS0tIHNCRno2V21tZU9XV1UwR2IvZDdkWEMzZDI4V25Yb0lvdmJadXNEZFV6TEEK
 | 
				
			||||||
cmVhc2Uga3daakI1IC0yK2IrYiBHdisnRW8KdlNXbmc1Q0hmS3dIVDJGbG9pankx
 | 
					81uT8S3QJNe+mVadi/VpXSPEP0Ygzm0/+1pB5qqYlSQEWTHqS55gCyFCwu+sjaDq
 | 
				
			||||||
L3UyTTBrMHY3emlvd3pEdUFVb0poOEVlWDE4eE5OYmxXSWcwajRsUk9ZZApMeHY5
 | 
					DpYTSm1JAk5ql9NRj4fJvCS53lJZ4zo+5c0iJKmuRg==
 | 
				
			||||||
NTRlZitnCi0tLSBjczV1M2ppNzVwS1VjeTdjVkt6Zngva3RvUFBhS3FvanVyUHVy
 | 
					 | 
				
			||||||
NkgyZnE4Cj/vbg5W+u2Ycmw31K590IF6tlnrMgn02tFTpGSGBzeay7LrzNWa2MIP
 | 
					 | 
				
			||||||
SoaaCI1YLl0uTR89UuHjuXaLuFCVNuX7wMHpiRlJLBi/FLPiRLA=
 | 
					 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,11 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEJhUWxSZyBRK3Zp
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyBBOVJi
 | 
				
			||||||
OTVnQ2lZRzloWE1hYmxMYWZERDdXL0pTdFVGYUN3Vk0wbkhBWTFBCkg1YkVidmwy
 | 
					SXdGVDlXWmVGZUM0OTJPUWFYem5qZzAwZWxhNzhpT2t1VjdZU0ZrCjYxWUE2VW5o
 | 
				
			||||||
ZVhDSWJOTXB6Qmw5OXNVU0RVUlFyQkE4MVE2eUp6ZXZBOHMKLT4gWDI1NTE5IG9u
 | 
					cGFLZ3g3Y3BpUWlWOUtUYTg4MGZXVHZvdVV3eU9iZW0ybE0KLT4gWDI1NTE5IDIw
 | 
				
			||||||
YUMxZkhHc0RVZkQ3UEEvazArRnl5NGpvTkJPRWdFbm9qYzdjZjNZZ28KRU1FdmMz
 | 
					QmxaWTY0WjJFZUd6TUxqaHhRelpRQ1hGZVBEcm43d3JYUVhpTWp4aGcKVzhJdFFu
 | 
				
			||||||
cVlzbHRFWUZqbkw2Ry9QVXppTFdNRTIwWnJBYzc0NUxieUMvRQotPiAxbn4nYSxC
 | 
					SEhUUUZVNVk1N2tzekpzUS9RazRCcFBhb2xxbkhRNEwzVys5cwotPiBkeE19PHEm
 | 
				
			||||||
LWdyZWFzZSBNRyAxO0EgVDoKQklPUS93Ci0tLSBoTXhqZ2VjNTlOVzdBN25CeUdD
 | 
					LWdyZWFzZQpwR0xsb05JVlFXQTZZQkJSWHY0akNRdjh1eXFnbmFDWUlCM0xLWXBi
 | 
				
			||||||
VFJtT2pDWi9taXh1SHpNTG9oeHJsbE9jCgGD+69tbzN5f1FlBBSMb/2GgJW2cmXI
 | 
					QkVuanloRQotLS0gZTkrT212MXdsZy9Kb1AwMkFHU3VsTElweGNlYkZ2UWVXRzkr
 | 
				
			||||||
97MXqA888ugf0vppdqy5yu+D4GdjoIvkKv0=
 | 
					dnB0SHRnYwrveLSY6SdUDO+QH7WGniLIOPcECTQ7CiTj9lwD5Hm0rYLdvizolb33
 | 
				
			||||||
 | 
					CsGX/kSEI2bD
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,12 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEJhUWxSZyBGekxK
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyBrTW1E
 | 
				
			||||||
ZFVBQkpTeGtzcHJuektzS0hPUFBIelg5UzQvVzg3SXJmSE9NbG5nCjFMbDBMcmFw
 | 
					ZDFSRXIwbXZXUlNJbHZCVjFzMzRxTmdtbDQ5eWVOWWp3SEdSUERrClVMeFRLOGUx
 | 
				
			||||||
dG9xaHpGV2RvZDg3WjRueTZtUGR3TnUyZE8yM1Rhdi83MGcKLT4gWDI1NTE5IGRu
 | 
					U0dmT2ZUUXlCSGhJdE5ibkZLMmZ2VmZFWU9PQXpGZFRPQkkKLT4gWDI1NTE5IDIw
 | 
				
			||||||
Ry9ZNVIyWEYvcWhCOWx0eEVVcnFaYm5IK3Fhc1Z1Ykg0VDFEbE0wU28KcnFGN3Rs
 | 
					VXd5N2EwTVdhdkRYeVF3c201SnV3TmxnUGpOZWY5bFJaQWRWMWxQVmMKR2RNc2pE
 | 
				
			||||||
bEtUazc3dkFCMEN2V2hTNFhlK2Z0OWQyNjNjaW5kbVU2OVozQQotPiAlfj84LWdy
 | 
					aUs4ZW1XSGU1RzM4bHZYQks2cHZWUkhZN1hob2d1QnM3cCtlMAotPiB0XENxMSct
 | 
				
			||||||
ZWFzZSBNLzc9fUcgNi5nKCBdRk50dSB1ClJkdmx0VjVUK0o3cmxrY1JycktXVkFS
 | 
					Z3JlYXNlIC5LIEIoJ1w6Ci93eE5lMUxDQjE3dWI4a05wUE5sV2dWN21ZN2lFRThv
 | 
				
			||||||
Yk10a3plZmsKLS0tIEVzUEhoUEE5TkZFK01BckxpZ0tKV2hZRERRbnFQUnlXRjQx
 | 
					YVJGNXNWaEtmbjVMaXhnemVuTXhOMXFtNkQvbGNuS3oKalZ6bEtGdHcxYnZNb0Zy
 | 
				
			||||||
RExPb1B3dHMKUaxZI1wEt10kHnWMgn3Na0UVpn/bhGpwXpToyH0Gzdjy5mQiPvcl
 | 
					YnlGTDdoVVdyeTJpYjJjZkc3alUyV2ZGa0taeEFIYTdiRnZmYmRjR3BzNUp2Ci0t
 | 
				
			||||||
X8RKm1wpkrLhXA==
 | 
					LSBROCtSMzFNR3hTK1p5NVhGcFpqM0U0L0MwbWpzNUNTUWUyNEVXbzFFMGpjCnot
 | 
				
			||||||
 | 
					A6mYbp+jhpoyjZidXQfzLVcu6y34WqAfJZsfT6l5SJONVfSvSw+iP7XXW2T5OnE=
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,12 @@
 | 
				
			|||||||
-----BEGIN AGE ENCRYPTED FILE-----
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IEJhUWxSZyBxbXBS
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyA3dDEx
 | 
				
			||||||
L0lhYVlEM0ZjdW9ESEFnSy9haDBDYk13SVU2VkF4c2VuclNwUkJrClRSei9aNVVU
 | 
					SUw4QVh5T3QySHFFemo2N1JWTjNCSGRiS1lmRTkxVEQ3S1NKR2dNClZNM1Vwc3dF
 | 
				
			||||||
V21CVi9wNWVDa1A0VUJVa3lkTmFGRktjTVQwTjFSUXNpb0EKLT4gWDI1NTE5IFZm
 | 
					elB0Unk1OWpUb1RQMVpSTUpJUDNrZzFMWkhKK0l1dXVBYlkKLT4gWDI1NTE5IGRF
 | 
				
			||||||
SmplRjRsSmx0WHNVRk1mZXdDa3BWSnFGckJab053N2x1MmsrZC9qd3MKUHdSY3lp
 | 
					TTZlMjdaamlwTUJzYlVkcVIxbmtybkFwakVtK2craXVBNVZraGZ1VlEKN2VvaU5r
 | 
				
			||||||
YVBqcGFvamF4ajFjeHpFMVN6U2FBTElVNlRlV2pBV2FSMTh1WQotPiAxKXl+PFIt
 | 
					VjNRS2I5WE9kVDhES2dWTUV2cEVJaXZxNzRUcFo5blhGTDBaawotPiAxXCJQemxa
 | 
				
			||||||
Z3JlYXNlIDdJTjYrICE4NnVIKD1jCjl3UjhGV1UyMUxxbVNXMXlmZXBNQlhXRlFh
 | 
					dS1ncmVhc2UgcDphKHFVTGUgIUonYydBPgowQnc2Wk5yS0E1bVBCWmpOc25MWWs2
 | 
				
			||||||
R0lpQXFlSEUxUjdiNThUYVFpNU5zCi0tLSBjeVhQVnJHS0Fsb2drSHJGZWhsankv
 | 
					UTR1dVlJbnNXYUVJSkx5bWFIcmtpT1lPSVE3b2Zpd0JaTGZWcEtjelFDCitQcy83
 | 
				
			||||||
MkJOY3g1WnBzS0doa2ZEbFRyaDU4CtUkWHxzTHEczny17RbpuuZphcdRdBjl+xHU
 | 
					bEVvM3FNTEhyWVVFS21tS0VQWG5OOHFza28KLS0tIEZZeUZwVGxUdEdtQTZuYk5K
 | 
				
			||||||
ysTSxxajA7yJ0u1l440nc3WC9Aikw3w=
 | 
					SHJaUDhHZ0JqbGNFSjJCaVlQTVo0OStkMWcKz/w0SnoHxnw71gr5DbXgMl59Kgjy
 | 
				
			||||||
 | 
					SW4tzNGeRcX2j4YdRjr77TP5UAzpQE30tEcrtw==
 | 
				
			||||||
-----END AGE ENCRYPTED FILE-----
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								secrets/home/ddclient-cloudflare.key.age
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								secrets/home/ddclient-cloudflare.key.age
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					-----BEGIN AGE ENCRYPTED FILE-----
 | 
				
			||||||
 | 
					YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpOcUlvZyBNalB5
 | 
				
			||||||
 | 
					RUZRNE1CTUJsbW1kSkxBSWVIcG1RUnBKd1gvcnRQVkZCUXFOQmhvClJUN2ltbnNk
 | 
				
			||||||
 | 
					T1grdVJSTzIyNTBTTGVEckVGQXdYNHdwOU5NbW1md3lGM0kKLT4gc3NoLWVkMjU1
 | 
				
			||||||
 | 
					MTkgcytxUmZnIHZ4bFZSS0huWFBDbUhNcTd2MFhvV0lOY1l3d3ZXNU4vT3dwMmlI
 | 
				
			||||||
 | 
					emhoV0kKcDF4M0FPK0JpclI5Q3Q5WGxpZWVYbHVWbkNWdTArclZsN09XK3VJSXc1
 | 
				
			||||||
 | 
					awotPiBYMjU1MTkgRjRCNVZmcXVnQnJ4KzZoM1ZkdWxYUkJTM1JuK3ZlRWJYdkFR
 | 
				
			||||||
 | 
					WXpFSmR4NApTbU5qR3ZuN0ZmbzIvMTFsMkdNSGJXSVlrVmZPdnZvcHFiZW45SW9I
 | 
				
			||||||
 | 
					endJCi0+IDEoIjlcJi1ncmVhc2UgJUE4IWl5ODkgfGVdLihEfT4gWCAreSduPS4K
 | 
				
			||||||
 | 
					bkI2Wm9LRGJXdW11aDl2VgotLS0gTENqYjZEUUZaWVZEcWQvWW5yTzJEdHRLeDJm
 | 
				
			||||||
 | 
					QUl5aytXdDE5QVMwVHZVSQo+aDbaGNOrz+hTSUQ4IAjDC9EfNwrlXDZtBqw8HkRv
 | 
				
			||||||
 | 
					1/Rr737scjrM7Bgt9zuKn6CB0zdeHTW5u685V2hCW/3aTy1eppWMWj3r
 | 
				
			||||||
 | 
					-----END AGE ENCRYPTED FILE-----
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user