Compare commits

..

1 Commits

Author SHA1 Message Date
88ad6cd610 be.lt: show battery level in tmux
All checks were successful
flake / flake (push) Successful in 1m13s
2024-07-17 16:45:46 +01:00
137 changed files with 992 additions and 3187 deletions

View File

@ -11,9 +11,12 @@ jobs:
flake: flake:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: DeterminateSystems/nix-installer-action@b92f66560d6f97d6576405a7bae901ab57e72b6a # v15 - name: Prepare for Nix installation
- uses: DeterminateSystems/magic-nix-cache-action@87b14cf437d03d37989d87f0fa5ce4f5dc1a330b # v8 run: |
apt-get update
apt-get install -y sudo
- uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
- name: lint - name: lint
run: | run: |
nix fmt nix fmt

View File

@ -1,27 +0,0 @@
{ config, pkgs, ... }:
{
config = {
system.stateVersion = 4;
networking.hostName = "jakehillion-mba-m2-15";
nix = {
useDaemon = true;
};
programs.zsh.enable = true;
security.pam.enableSudoTouchIdAuth = true;
environment.systemPackages = with pkgs; [
fd
htop
mosh
neovim
nix
ripgrep
sapling
];
};
}

View File

@ -2,9 +2,7 @@
"nodes": { "nodes": {
"agenix": { "agenix": {
"inputs": { "inputs": {
"darwin": [ "darwin": "darwin",
"darwin"
],
"home-manager": [ "home-manager": [
"home-manager" "home-manager"
], ],
@ -14,11 +12,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1723293904, "lastModified": 1720546205,
"narHash": "sha256-b+uqzj+Wa6xgMS9aNbX4I+sXeb5biPDi39VgvSFqFvU=", "narHash": "sha256-boCXsjYVxDviyzoEyAk624600f3ZBo/DKtUdvMTpbGY=",
"owner": "ryantm", "owner": "ryantm",
"repo": "agenix", "repo": "agenix",
"rev": "f6291c5935fdc4e0bef208cfc0dcab7e3f7a1c41", "rev": "de96bd907d5fbc3b14fc33ad37d1b9a3cb15edc6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -30,53 +28,35 @@
"darwin": { "darwin": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"agenix",
"nixpkgs" "nixpkgs"
] ]
}, },
"locked": { "locked": {
"lastModified": 1731153869, "lastModified": 1700795494,
"narHash": "sha256-3Ftf9oqOypcEyyrWJ0baVkRpvQqroK/SVBFLvU3nPuc=", "narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=",
"owner": "lnl7", "owner": "lnl7",
"repo": "nix-darwin", "repo": "nix-darwin",
"rev": "5c74ab862c8070cbf6400128a1b56abb213656da", "rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "lnl7", "owner": "lnl7",
"ref": "master",
"repo": "nix-darwin", "repo": "nix-darwin",
"type": "github" "type": "github"
} }
}, },
"disko": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1731060864,
"narHash": "sha256-aYE7oAYZ+gPU1mPNhM0JwLAQNgjf0/JK1BF1ln2KBgk=",
"owner": "nix-community",
"repo": "disko",
"rev": "5e40e02978e3bd63c2a6a9fa6fa8ba0e310e747f",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "disko",
"type": "github"
}
},
"flake-utils": { "flake-utils": {
"inputs": { "inputs": {
"systems": "systems_2" "systems": "systems_2"
}, },
"locked": { "locked": {
"lastModified": 1726560853, "lastModified": 1710146030,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -92,11 +72,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1726989464, "lastModified": 1720042825,
"narHash": "sha256-Vl+WVTJwutXkimwGprnEtXc/s/s8sMuXzqXaspIGlwM=", "narHash": "sha256-A0vrUB6x82/jvf17qPCpxaM+ulJnD8YZwH9Ci0BsAzE=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "2f23fa308a7c067e52dfcc30a0758f47043ec176", "rev": "e1391fb22e18a36f57e6999c7a9f966dc80ac073",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -113,11 +93,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1730837930, "lastModified": 1721135958,
"narHash": "sha256-0kZL4m+bKBJUBQse0HanewWO0g8hDdCvBhudzxgehqc=", "narHash": "sha256-H548rpPMsn25LDKn1PCFmPxmWlClJJGnvdzImHkqjuY=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "2f607e07f3ac7e53541120536708e824acccfaa8", "rev": "afd2021bedff2de92dfce0e257a3d03ae65c603d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -128,11 +108,11 @@
}, },
"impermanence": { "impermanence": {
"locked": { "locked": {
"lastModified": 1730403150, "lastModified": 1719091691,
"narHash": "sha256-W1FH5aJ/GpRCOA7DXT/sJHFpa5r8sq2qAUncWwRZ3Gg=", "narHash": "sha256-AxaLX5cBEcGtE02PeGsfscSb/fWMnyS7zMWBXQWDKbE=",
"owner": "nix-community", "owner": "nix-community",
"repo": "impermanence", "repo": "impermanence",
"rev": "0d09341beeaa2367bac5d718df1404bf2ce45e6f", "rev": "23c1f06316b67cb5dabdfe2973da3785cfe9c34a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -144,11 +124,11 @@
}, },
"nixos-hardware": { "nixos-hardware": {
"locked": { "locked": {
"lastModified": 1730919458, "lastModified": 1720737798,
"narHash": "sha256-yMO0T0QJlmT/x4HEyvrCyigGrdYfIXX3e5gWqB64wLg=", "narHash": "sha256-G/OtEAts7ZUvW5lrGMXSb8HqRp2Jr9I7reBuvCOL54w=",
"owner": "nixos", "owner": "nixos",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "e1cc1f6483393634aee94514186d21a4871e78d7", "rev": "c5013aa7ce2c7ec90acee5d965d950c8348db751",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -159,11 +139,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1730963269, "lastModified": 1720954236,
"narHash": "sha256-rz30HrFYCHiWEBCKHMffHbMdWJ35hEkcRVU0h7ms3x0=", "narHash": "sha256-1mEKHp4m9brvfQ0rjCca8P1WHpymK3TOr3v34ydv9bs=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "83fb6c028368e465cd19bb127b86f971a5e41ebc", "rev": "53e81e790209e41f0c1efa9ff26ff2fd7ab35e27",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -175,22 +155,23 @@
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1730867498, "lastModified": 1720957393,
"narHash": "sha256-Ce3a1w7Qf+UEPjVJcXxeSiWyPMngqf1M2EIsmqiluQw=", "narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=",
"rev": "9240e11a83307a6e8cf2254340782cba4aa782fd", "owner": "nixos",
"type": "tarball", "repo": "nixpkgs",
"url": "https://gitea.hillion.co.uk/api/v1/repos/JakeHillion/nixpkgs/archive/9240e11a83307a6e8cf2254340782cba4aa782fd.tar.gz" "rev": "693bc46d169f5af9c992095736e82c3488bf7dbb",
"type": "github"
}, },
"original": { "original": {
"type": "tarball", "owner": "nixos",
"url": "https://gitea.hillion.co.uk/JakeHillion/nixpkgs/archive/nixos-unstable.tar.gz" "ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
} }
}, },
"root": { "root": {
"inputs": { "inputs": {
"agenix": "agenix", "agenix": "agenix",
"darwin": "darwin",
"disko": "disko",
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"home-manager": "home-manager", "home-manager": "home-manager",
"home-manager-unstable": "home-manager-unstable", "home-manager-unstable": "home-manager-unstable",

124
flake.nix
View File

@ -1,18 +1,14 @@
{ {
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05"; nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05";
nixpkgs-unstable.url = "https://gitea.hillion.co.uk/JakeHillion/nixpkgs/archive/nixos-unstable.tar.gz"; nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
nixos-hardware.url = "github:nixos/nixos-hardware"; nixos-hardware.url = "github:nixos/nixos-hardware";
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
darwin.url = "github:lnl7/nix-darwin";
darwin.inputs.nixpkgs.follows = "nixpkgs";
agenix.url = "github:ryantm/agenix"; agenix.url = "github:ryantm/agenix";
agenix.inputs.nixpkgs.follows = "nixpkgs"; agenix.inputs.nixpkgs.follows = "nixpkgs";
agenix.inputs.darwin.follows = "darwin";
agenix.inputs.home-manager.follows = "home-manager"; agenix.inputs.home-manager.follows = "home-manager";
home-manager.url = "github:nix-community/home-manager/release-24.05"; home-manager.url = "github:nix-community/home-manager/release-24.05";
@ -21,89 +17,51 @@
home-manager-unstable.inputs.nixpkgs.follows = "nixpkgs-unstable"; home-manager-unstable.inputs.nixpkgs.follows = "nixpkgs-unstable";
impermanence.url = "github:nix-community/impermanence/master"; impermanence.url = "github:nix-community/impermanence/master";
disko.url = "github:nix-community/disko";
disko.inputs.nixpkgs.follows = "nixpkgs";
}; };
description = "Hillion Nix flake"; description = "Hillion Nix flake";
outputs = outputs = { self, nixpkgs, nixpkgs-unstable, nixos-hardware, flake-utils, agenix, home-manager, home-manager-unstable, impermanence, ... }@inputs: {
{ self nixosConfigurations =
, agenix let
, darwin fqdns = builtins.attrNames (builtins.readDir ./hosts);
, disko getSystemOverlays = system: nixpkgsConfig: [
, flake-utils (final: prev: {
, home-manager "storj" = final.callPackage ./pkgs/storj.nix { };
, home-manager-unstable })
, impermanence ];
, nixos-hardware mkHost = fqdn:
, nixpkgs let
, nixpkgs-unstable system = builtins.readFile ./hosts/${fqdn}/system;
, ... func = if builtins.pathExists ./hosts/${fqdn}/unstable then nixpkgs-unstable.lib.nixosSystem else nixpkgs.lib.nixosSystem;
}@inputs: home-manager-pick = if builtins.pathExists ./hosts/${fqdn}/unstable then home-manager-unstable else home-manager;
let in
getSystemOverlays = system: nixpkgsConfig: [ func {
(final: prev: { inherit system;
unstable = nixpkgs-unstable.legacyPackages.${prev.system}; specialArgs = inputs;
modules = [
./hosts/${fqdn}/default.nix
./modules/default.nix
"storj" = final.callPackage ./pkgs/storj.nix { }; agenix.nixosModules.default
}) impermanence.nixosModules.impermanence
];
in
{
nixosConfigurations =
let
fqdns = builtins.attrNames (builtins.readDir ./hosts);
mkHost = fqdn:
let
system = builtins.readFile ./hosts/${fqdn}/system;
func = if builtins.pathExists ./hosts/${fqdn}/unstable then nixpkgs-unstable.lib.nixosSystem else nixpkgs.lib.nixosSystem;
home-manager-pick = if builtins.pathExists ./hosts/${fqdn}/unstable then home-manager-unstable else home-manager;
in
func {
inherit system;
specialArgs = inputs;
modules = [
./hosts/${fqdn}/default.nix
./modules/default.nix
agenix.nixosModules.default home-manager-pick.nixosModules.default
impermanence.nixosModules.impermanence {
disko.nixosModules.disko home-manager.sharedModules = [
impermanence.nixosModules.home-manager.impermanence
];
}
home-manager-pick.nixosModules.default ({ config, ... }: {
{ system.configurationRevision = nixpkgs.lib.mkIf (self ? rev) self.rev;
home-manager.sharedModules = [ nixpkgs.overlays = getSystemOverlays config.nixpkgs.hostPlatform.system config.nixpkgs.config;
impermanence.nixosModules.home-manager.impermanence })
]; ];
} };
in
({ config, ... }: { nixpkgs.lib.genAttrs fqdns mkHost;
system.configurationRevision = nixpkgs.lib.mkIf (self ? rev) self.rev; } // flake-utils.lib.eachDefaultSystem (system: {
nixpkgs.overlays = getSystemOverlays config.nixpkgs.hostPlatform.system config.nixpkgs.config; formatter = nixpkgs.legacyPackages.${system}.nixpkgs-fmt;
}) });
];
};
in
nixpkgs.lib.genAttrs fqdns mkHost;
darwinConfigurations = {
jakehillion-mba-m2-15 = darwin.lib.darwinSystem {
system = "aarch64-darwin";
specialArgs = inputs;
modules = [
./darwin/jakehillion-mba-m2-15/configuration.nix
({ config, ... }: {
nixpkgs.overlays = getSystemOverlays "aarch64-darwin" config.nixpkgs.config;
})
];
};
};
} // flake-utils.lib.eachDefaultSystem (system: {
formatter = nixpkgs.legacyPackages.${system}.nixpkgs-fmt;
});
} }

View File

@ -15,6 +15,7 @@
boot.loader.efi.canTouchEfiVariables = true; boot.loader.efi.canTouchEfiVariables = true;
custom.defaults = true; custom.defaults = true;
custom.laptop = true;
## Impermanence ## Impermanence
custom.impermanence = { custom.impermanence = {
@ -24,17 +25,6 @@
]; ];
}; };
## WiFi
age.secrets."wifi/be.lt.ts.hillion.co.uk".file = ../../secrets/wifi/be.lt.ts.hillion.co.uk.age;
networking.wireless = {
enable = true;
environmentFile = config.age.secrets."wifi/be.lt.ts.hillion.co.uk".path;
networks = {
"Hillion WPA3 Network".psk = "@HILLION_WPA3_NETWORK_PSK@";
};
};
## Desktop ## Desktop
custom.users.jake.password = true; custom.users.jake.password = true;
custom.desktop.awesome.enable = true; custom.desktop.awesome.enable = true;

View File

@ -34,27 +34,14 @@
### Explicitly use the latest kernel at time of writing because the LTS ### Explicitly use the latest kernel at time of writing because the LTS
### kernels available in NixOS do not seem to support this server's very ### kernels available in NixOS do not seem to support this server's very
### modern hardware. ### modern hardware.
### custom.sched_ext.enable implies >=6.12, if this is removed the kernel may need to be pinned again. >=6.10 seems good. boot.kernelPackages = pkgs.linuxPackages_6_9;
custom.sched_ext.enable = true;
## Enable btrfs compression ## Enable btrfs compression
fileSystems."/data".options = [ "compress=zstd" ]; fileSystems."/data".options = [ "compress=zstd" ];
fileSystems."/nix".options = [ "compress=zstd" ]; fileSystems."/nix".options = [ "compress=zstd" ];
## Impermanence ## Impermanence
custom.impermanence = { custom.impermanence.enable = true;
enable = true;
cache.enable = true;
userExtraFiles.jake = [
".ssh/id_ecdsa"
".ssh/id_rsa"
];
};
boot.initrd.postDeviceCommands = lib.mkAfter ''
btrfs subvolume delete /cache/system
btrfs subvolume snapshot /cache/empty_snapshot /cache/system
'';
## Custom Services ## Custom Services
custom = { custom = {
@ -88,42 +75,6 @@
fileSystems = [ "/data" ]; fileSystems = [ "/data" ];
}; };
## Resilio
custom.resilio = {
enable = true;
folders =
let
folderNames = [
"dad"
"joseph"
"projects"
"resources"
"sync"
];
mkFolder = name: {
name = name;
secret = {
name = "resilio/plain/${name}";
file = ../../secrets/resilio/plain/${name}.age;
};
};
in
builtins.map (mkFolder) folderNames;
};
services.resilio.directoryRoot = "/data/sync";
## General usability
### Make podman available for dev tools such as act
virtualisation = {
containers.enable = true;
podman = {
enable = true;
dockerCompat = true;
dockerSocket.enable = true;
};
};
users.users.jake.extraGroups = [ "podman" ];
## Networking ## Networking
boot.kernel.sysctl = { boot.kernel.sysctl = {
"net.ipv4.ip_forward" = true; "net.ipv4.ip_forward" = true;

View File

@ -18,7 +18,7 @@
{ {
device = "tmpfs"; device = "tmpfs";
fsType = "tmpfs"; fsType = "tmpfs";
options = [ "mode=0755" "size=100%" ]; options = [ "mode=0755" ];
}; };
fileSystems."/boot" = fileSystems."/boot" =
@ -35,13 +35,6 @@
options = [ "subvol=data" ]; options = [ "subvol=data" ];
}; };
fileSystems."/cache" =
{
device = "/dev/disk/by-uuid/9aebe351-156a-4aa0-9a97-f09b01ac23ad";
fsType = "btrfs";
options = [ "subvol=cache" ];
};
fileSystems."/nix" = fileSystems."/nix" =
{ {
device = "/dev/disk/by-uuid/9aebe351-156a-4aa0-9a97-f09b01ac23ad"; device = "/dev/disk/by-uuid/9aebe351-156a-4aa0-9a97-f09b01ac23ad";

View File

@ -1,7 +0,0 @@
# gendry.jakehillion-terminals.ts.hillion.co.uk
Additional installation step for Clevis/Tang:
$ echo -n $DISK_ENCRYPTION_PASSWORD | clevis encrypt sss "$(cat /etc/nixos/hosts/gendry.jakehillion-terminals.ts.hillion.co.uk/clevis_config.json)" >/mnt/data/disk_encryption.jwe
$ sudo chown root:root /mnt/data/disk_encryption.jwe
$ sudo chmod 0400 /mnt/data/disk_encryption.jwe

View File

@ -15,24 +15,8 @@
boot.loader.systemd-boot.enable = true; boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true; boot.loader.efi.canTouchEfiVariables = true;
boot.kernelParams = [
"ip=dhcp"
];
boot.initrd = {
availableKernelModules = [ "r8169" ];
network.enable = true;
clevis = {
enable = true;
useTang = true;
devices."root".secretFile = "/data/disk_encryption.jwe";
};
};
custom.defaults = true; custom.defaults = true;
## Custom scheduler
custom.sched_ext.enable = true;
## Impermanence ## Impermanence
custom.impermanence = { custom.impermanence = {
enable = true; enable = true;
@ -45,13 +29,6 @@
]; ];
}; };
## Enable ZRAM swap to help with root on tmpfs
zramSwap = {
enable = true;
memoryPercent = 200;
algorithm = "zstd";
};
## Desktop ## Desktop
custom.users.jake.password = true; custom.users.jake.password = true;
custom.desktop.awesome.enable = true; custom.desktop.awesome.enable = true;
@ -59,7 +36,9 @@
## Resilio ## Resilio
custom.resilio.enable = true; custom.resilio.enable = true;
services.resilio.deviceName = "gendry.jakehillion-terminals";
services.resilio.directoryRoot = "/data/sync"; services.resilio.directoryRoot = "/data/sync";
services.resilio.storagePath = "/data/sync/.sync";
custom.resilio.folders = custom.resilio.folders =
let let

View File

@ -1,75 +0,0 @@
{ config, pkgs, lib, ... }:
{
imports = [
./disko.nix
./hardware-configuration.nix
];
config = {
system.stateVersion = "24.05";
networking.hostName = "merlin";
networking.domain = "rig.ts.hillion.co.uk";
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.kernelParams = [
"ip=dhcp"
# zswap
"zswap.enabled=1"
"zswap.compressor=zstd"
"zswap.max_pool_percent=20"
];
boot.initrd = {
availableKernelModules = [ "igc" ];
network.enable = true;
clevis = {
enable = true;
useTang = true;
devices = {
"disk0-crypt".secretFile = "/data/disk_encryption.jwe";
};
};
};
boot.kernelPackages = pkgs.linuxPackages_latest;
custom.defaults = true;
custom.locations.autoServe = true;
custom.impermanence.enable = true;
custom.users.jake.password = true;
security.sudo.wheelNeedsPassword = lib.mkForce true;
# Networking
networking = {
interfaces.enp171s0.name = "eth0";
interfaces.enp172s0.name = "eth1";
};
networking.nameservers = lib.mkForce [ ]; # Trust the DHCP nameservers
networking.firewall = {
trustedInterfaces = [ "tailscale0" ];
allowedTCPPorts = lib.mkForce [
22 # SSH
];
allowedUDPPorts = lib.mkForce [ ];
interfaces = {
eth0 = {
allowedTCPPorts = lib.mkForce [ ];
allowedUDPPorts = lib.mkForce [ ];
};
};
};
## Tailscale
age.secrets."tailscale/merlin.rig.ts.hillion.co.uk".file = ../../secrets/tailscale/merlin.rig.ts.hillion.co.uk.age;
services.tailscale = {
enable = true;
authKeyFile = config.age.secrets."tailscale/merlin.rig.ts.hillion.co.uk".path;
};
};
}

View File

@ -1,70 +0,0 @@
{
disko.devices = {
disk = {
disk0 = {
type = "disk";
device = "/dev/nvme0n1";
content = {
type = "gpt";
partitions = {
ESP = {
size = "1G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
disk0-crypt = {
size = "100%";
content = {
type = "luks";
name = "disk0-crypt";
settings = {
allowDiscards = true;
};
content = {
type = "btrfs";
subvolumes = {
"/data" = {
mountpoint = "/data";
mountOptions = [ "compress=zstd" "ssd" ];
};
"/nix" = {
mountpoint = "/nix";
mountOptions = [ "compress=zstd" "ssd" ];
};
};
};
};
};
swap = {
size = "64G";
content = {
type = "swap";
randomEncryption = true;
discardPolicy = "both";
};
};
};
};
};
};
nodev = {
"/" = {
fsType = "tmpfs";
mountOptions = [
"mode=755"
"size=100%"
];
};
};
};
}

View File

@ -1,28 +0,0 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usbhid" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp171s0.useDHCP = lib.mkDefault true;
# networking.interfaces.enp172s0.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp173s0f0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View File

@ -23,6 +23,12 @@
services.tailscale = { services.tailscale = {
enable = true; enable = true;
authKeyFile = config.age.secrets."tailscale/microserver.home.ts.hillion.co.uk".path; authKeyFile = config.age.secrets."tailscale/microserver.home.ts.hillion.co.uk".path;
useRoutingFeatures = "server";
extraUpFlags = [
"--advertise-routes"
"10.64.50.0/24,10.239.19.0/24"
"--advertise-exit-node"
];
}; };
## Enable IoT VLAN ## Enable IoT VLAN
@ -37,6 +43,11 @@
bluetooth.enable = true; bluetooth.enable = true;
}; };
## Enable IP forwarding for Tailscale
boot.kernel.sysctl = {
"net.ipv4.ip_forward" = true;
};
## Run a persistent iperf3 server ## Run a persistent iperf3 server
services.iperf3.enable = true; services.iperf3.enable = true;
services.iperf3.openFirewall = true; services.iperf3.openFirewall = true;
@ -45,9 +56,11 @@
networking.firewall.interfaces = { networking.firewall.interfaces = {
"eth0" = { "eth0" = {
allowedUDPPorts = [ allowedUDPPorts = [
5353 # HomeKit
]; ];
allowedTCPPorts = [ allowedTCPPorts = [
7654 # Tang 7654 # Tang
21063 # HomeKit
]; ];
}; };
}; };

View File

@ -1,7 +0,0 @@
# phoenix.st.ts.hillion.co.uk
Additional installation step for Clevis/Tang:
$ echo -n $DISK_ENCRYPTION_PASSWORD | clevis encrypt sss "$(cat /etc/nixos/hosts/phoenix.st.ts.hillion.co.uk/clevis_config.json)" >/mnt/data/disk_encryption.jwe
$ sudo chown root:root /mnt/data/disk_encryption.jwe
$ sudo chmod 0400 /mnt/data/disk_encryption.jwe

View File

@ -1,14 +0,0 @@
{
"t": 1,
"pins": {
"tang": [
{
"url": "http://10.64.50.21:7654"
},
{
"url": "http://10.64.50.25:7654"
}
]
}
}

View File

@ -1,168 +0,0 @@
{ config, pkgs, lib, ... }:
let
zpool_name = "practical-defiant-coffee";
in
{
imports = [
./disko.nix
./hardware-configuration.nix
];
config = {
system.stateVersion = "24.05";
networking.hostName = "phoenix";
networking.domain = "st.ts.hillion.co.uk";
networking.hostId = "4d7241e9";
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.kernelParams = [
"ip=dhcp"
"zfs.zfs_arc_max=34359738368"
# zswap
"zswap.enabled=1"
"zswap.compressor=zstd"
"zswap.max_pool_percent=20"
];
boot.initrd = {
availableKernelModules = [ "igc" ];
network.enable = true;
clevis = {
enable = true;
useTang = true;
devices = {
"disk0-crypt".secretFile = "/data/disk_encryption.jwe";
"disk1-crypt".secretFile = "/data/disk_encryption.jwe";
};
};
};
custom.defaults = true;
custom.locations.autoServe = true;
custom.impermanence.enable = true;
custom.users.jake.password = true; # TODO: remove me once booting has stabilised
## Filesystems
boot.supportedFilesystems = [ "zfs" ];
boot.zfs = {
forceImportRoot = false;
extraPools = [ zpool_name ];
};
services.btrfs.autoScrub = {
enable = true;
interval = "Tue, 02:00";
# All filesystems includes the BTRFS parts of all the hard drives. This
# would take forever and is redundant as they get fully read regularly.
fileSystems = [ "/data" ];
};
services.zfs.autoScrub = {
enable = true;
interval = "Wed, 02:00";
};
## Resilio
custom.resilio = {
enable = true;
backups.enable = true;
folders =
let
folderNames = [
"dad"
"joseph"
"projects"
"resources"
"sync"
];
mkFolder = name: {
name = name;
secret = {
name = "resilio/plain/${name}";
file = ../../secrets/resilio/plain/${name}.age;
};
};
in
builtins.map (mkFolder) folderNames;
};
services.resilio.directoryRoot = "/${zpool_name}/sync";
## Chia
age.secrets."chia/farmer.key" = {
file = ../../secrets/chia/farmer.key.age;
owner = "chia";
group = "chia";
};
custom.chia = {
enable = true;
keyFile = config.age.secrets."chia/farmer.key".path;
plotDirectories = builtins.genList (i: "/mnt/d${toString i}/plots/contract-k32") 8;
};
## Restic
custom.services.restic.path = "/${zpool_name}/backups/restic";
## Backups
### Git
custom.backups.git = {
enable = true;
extraRepos = [ "https://gitea.hillion.co.uk/JakeHillion/nixos.git" ];
};
## Downloads
custom.services.downloads = {
metadataPath = "/${zpool_name}/downloads/metadata";
downloadCachePath = "/${zpool_name}/downloads/torrents";
filmsPath = "/${zpool_name}/media/films";
tvPath = "/${zpool_name}/media/tv";
};
## Plex
users.users.plex.extraGroups = [ "mediaaccess" ];
services.plex.enable = true;
## Networking
networking = {
interfaces.enp4s0.name = "eth0";
interfaces.enp5s0.name = "eth1";
interfaces.enp6s0.name = "eth2";
interfaces.enp8s0.name = "eth3";
vlans = {
cameras = {
id = 3;
interface = "eth0";
};
};
};
networking.nameservers = lib.mkForce [ ]; # Trust the DHCP nameservers
networking.firewall = {
trustedInterfaces = [ "tailscale0" ];
allowedTCPPorts = lib.mkForce [
22 # SSH
];
allowedUDPPorts = lib.mkForce [ ];
interfaces = {
eth0 = {
allowedTCPPorts = lib.mkForce [
32400 # Plex
];
allowedUDPPorts = lib.mkForce [ ];
};
};
};
## Tailscale
age.secrets."tailscale/phoenix.st.ts.hillion.co.uk".file = ../../secrets/tailscale/phoenix.st.ts.hillion.co.uk.age;
services.tailscale = {
enable = true;
authKeyFile = config.age.secrets."tailscale/phoenix.st.ts.hillion.co.uk".path;
};
};
}

View File

@ -1,103 +0,0 @@
{
disko.devices = {
disk = {
disk0 = {
type = "disk";
device = "/dev/nvme0n1";
content = {
type = "gpt";
partitions = {
ESP = {
size = "1G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
disk0-crypt = {
size = "100%";
content = {
type = "luks";
name = "disk0-crypt";
settings = {
allowDiscards = true;
};
};
};
swap = {
size = "64G";
content = {
type = "swap";
randomEncryption = true;
discardPolicy = "both";
};
};
};
};
};
disk1 = {
type = "disk";
device = "/dev/nvme1n1";
content = {
type = "gpt";
partitions = {
disk1-crypt = {
size = "100%";
content = {
type = "luks";
name = "disk1-crypt";
settings = {
allowDiscards = true;
};
content = {
type = "btrfs";
extraArgs = [
"-d raid1"
"/dev/mapper/disk0-crypt"
];
subvolumes = {
"/data" = {
mountpoint = "/data";
mountOptions = [ "compress=zstd" "ssd" ];
};
"/nix" = {
mountpoint = "/nix";
mountOptions = [ "compress=zstd" "ssd" ];
};
};
};
};
};
swap = {
size = "64G";
content = {
type = "swap";
randomEncryption = true;
discardPolicy = "both";
};
};
};
};
};
};
nodev = {
"/" = {
fsType = "tmpfs";
mountOptions = [
"mode=755"
"size=100%"
];
};
};
};
}

View File

@ -1 +0,0 @@
x86_64-linux

View File

@ -32,14 +32,6 @@
nat.enable = lib.mkForce false; nat.enable = lib.mkForce false;
useDHCP = false; useDHCP = false;
vlans = {
cameras = {
id = 3;
interface = "eth2";
};
};
interfaces = { interfaces = {
enp1s0 = { enp1s0 = {
name = "eth0"; name = "eth0";
@ -64,14 +56,6 @@
} }
]; ];
}; };
cameras /* cameras@eth2 */ = {
ipv4.addresses = [
{
address = "10.133.145.1";
prefixLength = 24;
}
];
};
enp4s0 = { name = "eth3"; }; enp4s0 = { name = "eth3"; };
enp5s0 = { name = "eth4"; }; enp5s0 = { name = "eth4"; };
enp6s0 = { name = "eth5"; }; enp6s0 = { name = "eth5"; };
@ -98,10 +82,8 @@
ip protocol icmp counter accept comment "accept all ICMP types" ip protocol icmp counter accept comment "accept all ICMP types"
iifname "eth0" tcp dport 22 counter accept comment "SSH" iifname "eth0" ct state { established, related } counter accept
iifname "eth0" drop
iifname { "eth0", "cameras" } ct state { established, related } counter accept
iifname { "eth0", "cameras" } drop
} }
chain forward { chain forward {
@ -110,7 +92,6 @@
iifname { iifname {
"eth1", "eth1",
"eth2", "eth2",
"tailscale0",
} oifname { } oifname {
"eth0", "eth0",
} counter accept comment "Allow trusted LAN to WAN" } counter accept comment "Allow trusted LAN to WAN"
@ -120,13 +101,12 @@
} oifname { } oifname {
"eth1", "eth1",
"eth2", "eth2",
"tailscale0", } ct state established,related counter accept comment "Allow established back to LANs"
} ct state { established,related } counter accept comment "Allow established back to LANs"
iifname "tailscale0" oifname { "eth1", "eth2" } counter accept comment "Allow LAN access from Tailscale" ip daddr 10.64.50.20 tcp dport 32400 counter accept comment "Plex"
iifname { "eth1", "eth2" } oifname "tailscale0" ct state { established,related } counter accept comment "Allow established back to Tailscale"
ip daddr 10.64.50.20 tcp dport 8444 counter accept comment "Chia"
ip daddr 10.64.50.27 tcp dport 32400 counter accept comment "Plex"
ip daddr 10.64.50.21 tcp dport 7654 counter accept comment "Tang" ip daddr 10.64.50.21 tcp dport 7654 counter accept comment "Tang"
} }
} }
@ -135,17 +115,16 @@
chain prerouting { chain prerouting {
type nat hook prerouting priority filter; policy accept; type nat hook prerouting priority filter; policy accept;
iifname eth0 tcp dport 32400 counter dnat to 10.64.50.27 iifname eth0 tcp dport 32400 counter dnat to 10.64.50.20
iifname eth0 tcp dport 8444 counter dnat to 10.64.50.20
iifname eth0 tcp dport 7654 counter dnat to 10.64.50.21 iifname eth0 tcp dport 7654 counter dnat to 10.64.50.21
} }
chain postrouting { chain postrouting {
type nat hook postrouting priority filter; policy accept; type nat hook postrouting priority filter; policy accept;
oifname "eth0" masquerade oifname "eth0" masquerade
iifname tailscale0 oifname eth1 snat to 10.64.50.1
iifname tailscale0 oifname eth2 snat to 10.239.19.1
} }
} }
''; '';
@ -159,7 +138,7 @@
settings = { settings = {
interfaces-config = { interfaces-config = {
interfaces = [ "eth1" "eth2" "cameras" ]; interfaces = [ "eth1" "eth2" ];
}; };
lease-database = { lease-database = {
type = "memfile"; type = "memfile";
@ -216,22 +195,18 @@
data = "10.64.50.1, 1.1.1.1, 8.8.8.8"; data = "10.64.50.1, 1.1.1.1, 8.8.8.8";
} }
]; ];
reservations = lib.lists.remove null (lib.lists.imap0 reservations = lib.lists.imap0
(i: el: if el == null then null else { (i: el: {
ip-address = "10.64.50.${toString (20 + i)}"; ip-address = "10.64.50.${toString (20 + i)}";
inherit (el) hw-address hostname; inherit (el) hw-address hostname;
}) [ }) [
null { hostname = "tywin"; hw-address = "c8:7f:54:6d:e1:03"; }
{ hostname = "microserver"; hw-address = "e4:5f:01:b4:58:95"; } { hostname = "microserver"; hw-address = "e4:5f:01:b4:58:95"; }
{ hostname = "theon"; hw-address = "00:1e:06:49:06:1e"; } { hostname = "theon"; hw-address = "00:1e:06:49:06:1e"; }
{ hostname = "server-switch"; hw-address = "84:d8:1b:9d:0d:85"; } { hostname = "server-switch"; hw-address = "84:d8:1b:9d:0d:85"; }
{ hostname = "apc-ap7921"; hw-address = "00:c0:b7:6b:f4:34"; } { hostname = "apc-ap7921"; hw-address = "00:c0:b7:6b:f4:34"; }
{ hostname = "sodium"; hw-address = "d8:3a:dd:c3:d6:2b"; } { hostname = "sodium"; hw-address = "d8:3a:dd:c3:d6:2b"; }
{ hostname = "gendry"; hw-address = "18:c0:4d:35:60:1e"; } ];
{ hostname = "phoenix"; hw-address = "a8:b8:e0:04:17:a5"; }
{ hostname = "merlin"; hw-address = "b0:41:6f:13:20:14"; }
{ hostname = "stinger"; hw-address = "7c:83:34:be:30:dd"; }
]);
} }
{ {
subnet = "10.239.19.0/24"; subnet = "10.239.19.0/24";
@ -255,58 +230,17 @@
]; ];
reservations = [ reservations = [
{ {
# bedroom-everything-presence-one
hw-address = "40:22:d8:e0:1d:50"; hw-address = "40:22:d8:e0:1d:50";
ip-address = "10.239.19.2"; ip-address = "10.239.19.2";
hostname = "bedroom-everything-presence-one"; hostname = "bedroom-everything-presence-one";
} }
{ {
# living-room-everything-presence-one
hw-address = "40:22:d8:e0:0f:78"; hw-address = "40:22:d8:e0:0f:78";
ip-address = "10.239.19.3"; ip-address = "10.239.19.3";
hostname = "living-room-everything-presence-one"; hostname = "living-room-everything-presence-one";
} }
{
hw-address = "a0:7d:9c:b0:f0:14";
ip-address = "10.239.19.4";
hostname = "hallway-wall-tablet";
}
{
hw-address = "d8:3a:dd:c3:d6:2b";
ip-address = "10.239.19.5";
hostname = "sodium";
}
{
hw-address = "48:da:35:6f:f2:4b";
ip-address = "10.239.19.6";
hostname = "hammer";
}
{
hw-address = "48:da:35:6f:83:b8";
ip-address = "10.239.19.7";
hostname = "charlie";
}
];
}
{
subnet = "10.133.145.0/24";
interface = "cameras";
pools = [{
pool = "10.133.145.64 - 10.133.145.254";
}];
option-data = [
{
name = "routers";
data = "10.133.145.1";
}
{
name = "broadcast-address";
data = "10.133.145.255";
}
{
name = "domain-name-servers";
data = "1.1.1.1, 8.8.8.8";
}
];
reservations = [
]; ];
} }
]; ];
@ -350,13 +284,6 @@
services.tailscale = { services.tailscale = {
enable = true; enable = true;
authKeyFile = config.age.secrets."tailscale/router.home.ts.hillion.co.uk".path; authKeyFile = config.age.secrets."tailscale/router.home.ts.hillion.co.uk".path;
useRoutingFeatures = "server";
extraSetFlags = [
"--advertise-routes"
"10.64.50.0/24,10.239.19.0/24,10.133.145.0/24"
"--advertise-exit-node"
"--netfilter-mode=off"
];
}; };
## Enable btrfs compression ## Enable btrfs compression
@ -380,34 +307,9 @@
}; };
services.caddy = { services.caddy = {
enable = true; enable = true;
virtualHosts = { virtualHosts."http://graphs.router.home.ts.hillion.co.uk" = {
"graphs.router.home.ts.hillion.co.uk" = { listenAddresses = [ config.custom.dns.tailscale.ipv4 config.custom.dns.tailscale.ipv6 ];
listenAddresses = [ config.custom.dns.tailscale.ipv4 config.custom.dns.tailscale.ipv6 ]; extraConfig = "reverse_proxy unix///run/netdata/netdata.sock";
extraConfig = ''
tls {
ca https://ca.ts.hillion.co.uk:8443/acme/acme/directory
}
reverse_proxy unix///run/netdata/netdata.sock
'';
};
"hammer.kvm.ts.hillion.co.uk" = {
listenAddresses = [ config.custom.dns.tailscale.ipv4 config.custom.dns.tailscale.ipv6 ];
extraConfig = ''
tls {
ca https://ca.ts.hillion.co.uk:8443/acme/acme/directory
}
reverse_proxy http://10.239.19.6
'';
};
"charlie.kvm.ts.hillion.co.uk" = {
listenAddresses = [ config.custom.dns.tailscale.ipv4 config.custom.dns.tailscale.ipv6 ];
extraConfig = ''
tls {
ca https://ca.ts.hillion.co.uk:8443/acme/acme/directory
}
reverse_proxy http://10.239.19.7
'';
};
}; };
}; };
users.users.caddy.extraGroups = [ "netdata" ]; users.users.caddy.extraGroups = [ "netdata" ];

View File

@ -1,4 +1,4 @@
{ config, pkgs, lib, nixos-hardware, ... }: { config, pkgs, nixpkgs-unstable, lib, nixos-hardware, ... }:
{ {
imports = [ imports = [
@ -22,19 +22,14 @@
fileSystems."/nix".options = [ "compress=zstd" ]; fileSystems."/nix".options = [ "compress=zstd" ];
## Impermanence ## Impermanence
custom.impermanence = { custom.impermanence.enable = true;
enable = true;
cache.enable = true;
};
boot.initrd.postDeviceCommands = lib.mkAfter '' boot.initrd.postDeviceCommands = lib.mkAfter ''
btrfs subvolume delete /cache/tmp btrfs subvolume delete /cache/tmp
btrfs subvolume snapshot /cache/empty_snapshot /cache/tmp btrfs subvolume snapshot /cache/empty_snapshot /cache/tmp
chmod 1777 /cache/tmp chmod 0777 /cache/tmp
chmod +t /cache/tmp
''; '';
## CA server
custom.ca.service.enable = true;
### nix only supports build-dir from 2.22. bind mount /tmp to something persistent instead. ### nix only supports build-dir from 2.22. bind mount /tmp to something persistent instead.
fileSystems."/tmp" = { fileSystems."/tmp" = {
device = "/cache/tmp"; device = "/cache/tmp";
@ -48,17 +43,14 @@
## Custom Services ## Custom Services
custom.locations.autoServe = true; custom.locations.autoServe = true;
custom.www.home.enable = true;
custom.www.iot.enable = true;
custom.services.isponsorblocktv.enable = true;
# Networking # Networking
networking = { networking = {
interfaces.end0.name = "eth0"; useDHCP = false;
vlans = { interfaces = {
iot = { end0 = {
id = 2; name = "eth0";
interface = "eth0"; useDHCP = true;
}; };
}; };
}; };
@ -67,27 +59,14 @@
networking.firewall = { networking.firewall = {
trustedInterfaces = [ "tailscale0" ]; trustedInterfaces = [ "tailscale0" ];
allowedTCPPorts = lib.mkForce [ allowedTCPPorts = lib.mkForce [
22 # SSH
]; ];
allowedUDPPorts = lib.mkForce [ ]; allowedUDPPorts = lib.mkForce [ ];
interfaces = { interfaces = {
eth0 = { eth0 = {
allowedTCPPorts = lib.mkForce [ allowedTCPPorts = lib.mkForce [
80 # HTTP 1-2
443 # HTTPS 1-2
7654 # Tang 7654 # Tang
]; ];
allowedUDPPorts = lib.mkForce [ allowedUDPPorts = lib.mkForce [
443 # HTTP 3
];
};
iot = {
allowedTCPPorts = lib.mkForce [
80 # HTTP 1-2
443 # HTTPS 1-2
];
allowedUDPPorts = lib.mkForce [
443 # HTTP 3
]; ];
}; };
}; };

View File

@ -1,84 +0,0 @@
{ config, pkgs, lib, ... }:
{
imports = [
./disko.nix
./hardware-configuration.nix
];
config = {
system.stateVersion = "24.05";
networking.hostName = "stinger";
networking.domain = "pop.ts.hillion.co.uk";
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.kernelParams = [
"ip=dhcp"
# zswap
"zswap.enabled=1"
"zswap.compressor=zstd"
"zswap.max_pool_percent=20"
];
boot.initrd = {
availableKernelModules = [ "r8169" ];
network.enable = true;
clevis = {
enable = true;
useTang = true;
devices = {
"disk0-crypt".secretFile = "/data/disk_encryption.jwe";
};
};
};
custom.defaults = true;
custom.locations.autoServe = true;
custom.impermanence.enable = true;
hardware = {
bluetooth.enable = true;
};
# Networking
networking = {
interfaces.enp1s0.name = "eth0";
vlans = {
iot = {
id = 2;
interface = "eth0";
};
};
};
networking.nameservers = lib.mkForce [ ]; # Trust the DHCP nameservers
networking.firewall = {
trustedInterfaces = [ "tailscale0" ];
allowedTCPPorts = lib.mkForce [
22 # SSH
];
allowedUDPPorts = lib.mkForce [ ];
interfaces = {
eth0 = {
allowedTCPPorts = lib.mkForce [
1400 # HA Sonos
21063 # HomeKit
];
allowedUDPPorts = lib.mkForce [
5353 # HomeKit
];
};
};
};
## Tailscale
age.secrets."tailscale/stinger.pop.ts.hillion.co.uk".file = ../../secrets/tailscale/stinger.pop.ts.hillion.co.uk.age;
services.tailscale = {
enable = true;
authKeyFile = config.age.secrets."tailscale/stinger.pop.ts.hillion.co.uk".path;
};
};
}

View File

@ -1,70 +0,0 @@
{
disko.devices = {
disk = {
disk0 = {
type = "disk";
device = "/dev/nvme0n1";
content = {
type = "gpt";
partitions = {
ESP = {
size = "1G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
disk0-crypt = {
size = "100%";
content = {
type = "luks";
name = "disk0-crypt";
settings = {
allowDiscards = true;
};
content = {
type = "btrfs";
subvolumes = {
"/data" = {
mountpoint = "/data";
mountOptions = [ "compress=zstd" "ssd" ];
};
"/nix" = {
mountpoint = "/nix";
mountOptions = [ "compress=zstd" "ssd" ];
};
};
};
};
};
swap = {
size = "64G";
content = {
type = "swap";
randomEncryption = true;
discardPolicy = "both";
};
};
};
};
};
};
nodev = {
"/" = {
fsType = "tmpfs";
mountOptions = [
"mode=755"
"size=100%"
];
};
};
};
}

View File

@ -1,28 +0,0 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp0s20f0u2.useDHCP = lib.mkDefault true;
# networking.interfaces.enp1s0.useDHCP = lib.mkDefault true;
# networking.interfaces.wlo1.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View File

@ -1 +0,0 @@
x86_64-linux

View File

@ -0,0 +1,7 @@
# tywin.storage.ts.hillion.co.uk
Additional installation step for Clevis/Tang:
$ echo -n $DISK_ENCRYPTION_PASSWORD | clevis encrypt sss "$(cat /etc/nixos/hosts/tywin.storage.ts.hillion.co.uk/clevis_config.json)" >/mnt/disk_encryption.jwe
$ sudo chown root:root /mnt/disk_encryption.jwe
$ sudo chmod 0400 /mnt/disk_encryption.jwe

View File

@ -0,0 +1,245 @@
{ config, pkgs, lib, ... }:
{
imports = [
./hardware-configuration.nix
];
config = {
system.stateVersion = "22.11";
networking.hostName = "tywin";
networking.domain = "storage.ts.hillion.co.uk";
networking.hostId = "2a9b6df5";
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.kernelParams = [
"ip=dhcp"
"zfs.zfs_arc_max=25769803776"
];
boot.initrd = {
availableKernelModules = [ "r8169" ];
network.enable = true;
clevis = {
enable = true;
useTang = true;
devices."root".secretFile = "/disk_encryption.jwe";
};
};
custom.locations.autoServe = true;
custom.defaults = true;
# zram swap: used in the hope it will give the ZFS ARC more room to back off
zramSwap = {
enable = true;
memoryPercent = 200;
algorithm = "zstd";
};
## Tailscale
age.secrets."tailscale/tywin.storage.ts.hillion.co.uk".file = ../../secrets/tailscale/tywin.storage.ts.hillion.co.uk.age;
services.tailscale = {
enable = true;
authKeyFile = config.age.secrets."tailscale/tywin.storage.ts.hillion.co.uk".path;
};
## Filesystems
fileSystems."/".options = [ "compress=zstd" ];
boot.supportedFilesystems = [ "zfs" ];
boot.zfs = {
forceImportRoot = false;
extraPools = [ "data" ];
};
services.btrfs.autoScrub = {
enable = true;
interval = "Tue, 02:00";
# All filesystems includes the BTRFS parts of all the hard drives. This
# would take forever and is redundant as they get fully read regularly.
fileSystems = [ "/" ];
};
services.zfs.autoScrub = {
enable = true;
interval = "Wed, 02:00";
};
## Backups
### Git
age.secrets."git/git_backups_ecdsa".file = ../../secrets/git/git_backups_ecdsa.age;
age.secrets."git/git_backups_remotes".file = ../../secrets/git/git_backups_remotes.age;
custom.backups.git = {
enable = true;
sshKey = config.age.secrets."git/git_backups_ecdsa".path;
reposFile = config.age.secrets."git/git_backups_remotes".path;
repos = [ "https://gitea.hillion.co.uk/JakeHillion/nixos.git" ];
};
## Resilio
custom.resilio.enable = true;
services.resilio.deviceName = "tywin.storage";
services.resilio.directoryRoot = "/data/users/jake/sync";
services.resilio.storagePath = "/data/users/jake/sync/.sync";
custom.resilio.folders =
let
folderNames = [
"dad"
"joseph"
"projects"
"resources"
"sync"
];
mkFolder = name: {
name = name;
secret = {
name = "resilio/plain/${name}";
file = ../../secrets/resilio/plain/${name}.age;
};
};
in
builtins.map (mkFolder) folderNames;
age.secrets."resilio/restic/128G.key" = {
file = ../../secrets/restic/128G.age;
owner = "rslsync";
group = "rslsync";
};
services.restic.backups."sync" = {
repository = "rest:http://restic.tywin.storage.ts.hillion.co.uk/128G";
user = "rslsync";
passwordFile = config.age.secrets."resilio/restic/128G.key".path;
timerConfig = {
Persistent = true;
OnUnitInactiveSec = "15m";
RandomizedDelaySec = "5m";
};
paths = [ "/data/users/jake/sync" ];
exclude = [
"/data/users/jake/sync/.sync"
"/data/users/jake/sync/*/.sync"
"/data/users/jake/sync/resources/media/films"
"/data/users/jake/sync/resources/media/iso"
"/data/users/jake/sync/resources/media/tv"
"/data/users/jake/sync/dad/media"
];
};
## Restic
age.secrets."restic/128G.key" = {
file = ../../secrets/restic/128G.age;
owner = "restic";
group = "restic";
};
age.secrets."restic/1.6T.key" = {
file = ../../secrets/restic/1.6T.age;
owner = "restic";
group = "restic";
};
services.restic.server = {
enable = true;
appendOnly = true;
extraFlags = [ "--no-auth" ];
dataDir = "/data/backups/restic";
listenAddress = "127.0.0.1:8000"; # TODO: can this be a Unix socket?
};
services.caddy = {
enable = true;
virtualHosts."http://restic.tywin.storage.ts.hillion.co.uk".extraConfig = ''
bind ${config.custom.dns.tailscale.ipv4} ${config.custom.dns.tailscale.ipv6}
reverse_proxy http://localhost:8000
'';
};
### HACK: Allow Caddy to restart if it fails. This happens because Tailscale
### is too late at starting. Upstream nixos caddy does restart on failure
### but it's prevented on exit code 1. Set the exit code to 0 (non-failure)
### to override this.
systemd.services.caddy = {
requires = [ "tailscaled.service" ];
after = [ "tailscaled.service" ];
serviceConfig = {
RestartPreventExitStatus = lib.mkForce 0;
};
};
services.restic.backups."prune-128G" = {
repository = "/data/backups/restic/128G";
user = "restic";
passwordFile = config.age.secrets."restic/128G.key".path;
timerConfig = {
Persistent = true;
OnCalendar = "02:30";
RandomizedDelaySec = "1h";
};
pruneOpts = [
"--keep-last 48"
"--keep-within-hourly 7d"
"--keep-within-daily 1m"
"--keep-within-weekly 6m"
"--keep-within-monthly 24m"
];
};
services.restic.backups."prune-1.6T" = {
repository = "/data/backups/restic/1.6T";
user = "restic";
passwordFile = config.age.secrets."restic/1.6T.key".path;
timerConfig = {
Persistent = true;
OnCalendar = "Wed, 02:30";
RandomizedDelaySec = "4h";
};
pruneOpts = [
"--keep-within-daily 14d"
"--keep-within-weekly 2m"
"--keep-within-monthly 18m"
];
};
## Chia
age.secrets."chia/farmer.key" = {
file = ../../secrets/chia/farmer.key.age;
owner = "chia";
group = "chia";
};
custom.chia = {
enable = true;
openFirewall = true;
keyFile = config.age.secrets."chia/farmer.key".path;
plotDirectories = builtins.genList (i: "/mnt/d${toString i}/plots/contract-k32") 7;
};
## Downloads
custom.services.downloads = {
metadataPath = "/data/downloads/metadata";
downloadCachePath = "/data/downloads/torrents";
filmsPath = "/data/media/films";
tvPath = "/data/media/tv";
};
## Plex
users.users.plex.extraGroups = [ "mediaaccess" ];
services.plex = {
enable = true;
openFirewall = true;
};
## Networking
networking.nameservers = lib.mkForce [ ]; # Trust the DHCP nameservers
networking.firewall.interfaces."tailscale0".allowedTCPPorts = [
80 # Caddy (restic.tywin.storage.ts.)
];
};
}

View File

@ -9,11 +9,28 @@
(modulesPath + "/installer/scan/not-detected.nix") (modulesPath + "/installer/scan/not-detected.nix")
]; ];
boot.initrd.availableKernelModules = [ "nvme" "ahci" "xhci_pci" "thunderbolt" "usbhid" "usb_storage" "sd_mod" ]; boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ];
boot.initrd.kernelModules = [ ]; boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-amd" ]; boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ]; boot.extraModulePackages = [ ];
fileSystems."/" =
{
device = "/dev/disk/by-uuid/cb48d4ed-d268-490c-9977-2b5d31ce2c1b";
fsType = "btrfs";
};
boot.initrd.luks.devices."root" = {
device = "/dev/disk/by-uuid/32837730-5e15-4917-9939-cbb58bb0aabf";
allowDiscards = true;
};
fileSystems."/boot" =
{
device = "/dev/disk/by-uuid/BC57-0AF6";
fsType = "vfat";
};
fileSystems."/mnt/d0" = fileSystems."/mnt/d0" =
{ {
device = "/dev/disk/by-uuid/9136434d-d883-4118-bd01-903f720e5ce1"; device = "/dev/disk/by-uuid/9136434d-d883-4118-bd01-903f720e5ce1";
@ -50,28 +67,14 @@
fsType = "btrfs"; fsType = "btrfs";
}; };
fileSystems."/mnt/d6" = swapDevices = [ ];
{
device = "/dev/disk/by-uuid/b461e07d-39ab-46b4-b1d1-14c2e0791915";
fsType = "btrfs";
};
fileSystems."/mnt/d7" =
{
device = "/dev/disk/by-uuid/eb8d32d0-e506-449b-8dbc-585ba05c4252";
fsType = "btrfs";
};
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's # (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction # still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`. # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true; networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp4s0.useDHCP = lib.mkDefault true; # networking.interfaces.enp7s0.useDHCP = lib.mkDefault true;
# networking.interfaces.enp5s0.useDHCP = lib.mkDefault true;
# networking.interfaces.enp6s0.useDHCP = lib.mkDefault true;
# networking.interfaces.enp8s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
} }

View File

@ -2,7 +2,7 @@
{ {
imports = [ imports = [
./git/default.nix ./git.nix
./homeassistant.nix ./homeassistant.nix
./matrix.nix ./matrix.nix
]; ];

View File

@ -7,17 +7,25 @@ in
options.custom.backups.git = { options.custom.backups.git = {
enable = lib.mkEnableOption "git"; enable = lib.mkEnableOption "git";
extraRepos = lib.mkOption { repos = lib.mkOption {
description = "A list of remotes to clone."; description = "A list of remotes to clone.";
type = with lib.types; listOf str; type = with lib.types; listOf str;
default = [ ]; default = [ ];
}; };
reposFile = lib.mkOption {
description = "A file containing the remotes to clone, one per line.";
type = with lib.types; nullOr str;
default = null;
};
sshKey = lib.mkOption {
description = "SSH private key to use when cloning repositories over SSH.";
type = with lib.types; nullOr str;
default = null;
};
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
age.secrets."git/git_backups_ecdsa".file = ../../../secrets/git/git_backups_ecdsa.age; age.secrets."git-backups/restic/128G".file = ../../secrets/restic/128G.age;
age.secrets."git/git_backups_remotes".file = ../../../secrets/git/git_backups_remotes.age;
age.secrets."git-backups/restic/128G".file = ../../../secrets/restic/128G.age;
systemd.services.backup-git = { systemd.services.backup-git = {
description = "Git repo backup service."; description = "Git repo backup service.";
@ -29,10 +37,9 @@ in
WorkingDirectory = "%C/backup-git"; WorkingDirectory = "%C/backup-git";
LoadCredential = [ LoadCredential = [
"id_ecdsa:${config.age.secrets."git/git_backups_ecdsa".path}"
"repos_file:${config.age.secrets."git/git_backups_remotes".path}"
"restic_password:${config.age.secrets."git-backups/restic/128G".path}" "restic_password:${config.age.secrets."git-backups/restic/128G".path}"
]; ] ++ (if cfg.sshKey == null then [ ] else [ "id_ecdsa:${cfg.sshKey}" ])
++ (if cfg.reposFile == null then [ ] else [ "repos_file:${cfg.reposFile}" ]);
}; };
environment = { environment = {
@ -41,12 +48,11 @@ in
}; };
script = '' script = ''
set -x
shopt -s nullglob shopt -s nullglob
# Read and deduplicate repos # Read and deduplicate repos
readarray -t raw_repos < $CREDENTIALS_DIRECTORY/repos_file ${if cfg.reposFile == null then "" else "readarray -t raw_repos < $CREDENTIALS_DIRECTORY/repos_file"}
declare -A repos=(${builtins.concatStringsSep " " (builtins.map (x : "[${x}]=1") cfg.extraRepos)}) declare -A repos=(${builtins.concatStringsSep " " (builtins.map (x : "[${x}]=1") cfg.repos)})
for repo in ''${raw_repos[@]}; do repos[$repo]=1; done for repo in ''${raw_repos[@]}; do repos[$repo]=1; done
# Clean up existing repos # Clean up existing repos
@ -73,7 +79,7 @@ in
# Backup to Restic # Backup to Restic
${pkgs.restic}/bin/restic \ ${pkgs.restic}/bin/restic \
-r rest:https://restic.ts.hillion.co.uk/128G \ -r rest:http://restic.tywin.storage.ts.hillion.co.uk/128G \
--cache-dir .restic --exclude .restic \ --cache-dir .restic --exclude .restic \
backup . backup .
@ -87,9 +93,9 @@ in
wantedBy = [ "timers.target" ]; wantedBy = [ "timers.target" ];
timerConfig = { timerConfig = {
Persistent = true; Persistent = true;
OnBootSec = "10m";
OnUnitInactiveSec = "15m"; OnUnitInactiveSec = "15m";
RandomizedDelaySec = "5m"; RandomizedDelaySec = "5m";
Unit = "backup-git.service";
}; };
}; };
}; };

View File

@ -1 +0,0 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIc3WVROMCifYtqHRWf5gZAOQFdpbcSYOC0JckKzUVM5sGdXtw3VXNiVqY3npdMizS4e1V8Hh77UecD3q9CLkMA= backups-git@nixos

View File

@ -14,44 +14,19 @@ in
owner = "hass"; owner = "hass";
group = "hass"; group = "hass";
}; };
age.secrets."backups/homeassistant/restic/1.6T" = {
file = ../../secrets/restic/1.6T.age;
owner = "postgres";
group = "postgres";
};
services = { services = {
postgresqlBackup = { restic.backups."homeassistant" = {
enable = true; user = "hass";
compression = "none"; # for better diffing timerConfig = {
databases = [ "homeassistant" ]; OnCalendar = "03:00";
}; RandomizedDelaySec = "60m";
restic.backups = {
"homeassistant-config" = {
user = "hass";
timerConfig = {
OnCalendar = "03:00";
RandomizedDelaySec = "60m";
};
repository = "rest:https://restic.ts.hillion.co.uk/128G";
passwordFile = config.age.secrets."backups/homeassistant/restic/128G".path;
paths = [
config.services.home-assistant.configDir
];
};
"homeassistant-database" = {
user = "postgres";
timerConfig = {
OnCalendar = "03:00";
RandomizedDelaySec = "60m";
};
repository = "rest:https://restic.ts.hillion.co.uk/1.6T";
passwordFile = config.age.secrets."backups/homeassistant/restic/1.6T".path;
paths = [
"${config.services.postgresqlBackup.location}/homeassistant.sql"
];
}; };
repository = "rest:http://restic.tywin.storage.ts.hillion.co.uk/128G";
passwordFile = config.age.secrets."backups/homeassistant/restic/128G".path;
paths = [
config.services.home-assistant.configDir
];
}; };
}; };
}; };

View File

@ -24,7 +24,7 @@ in
OnCalendar = "03:00"; OnCalendar = "03:00";
RandomizedDelaySec = "60m"; RandomizedDelaySec = "60m";
}; };
repository = "rest:https://restic.ts.hillion.co.uk/128G"; repository = "rest:http://restic.tywin.storage.ts.hillion.co.uk/128G";
passwordFile = config.age.secrets."backups/matrix/restic/128G".path; passwordFile = config.age.secrets."backups/matrix/restic/128G".path;
paths = [ paths = [
"${config.services.postgresqlBackup.location}/matrix-synapse.sql" "${config.services.postgresqlBackup.location}/matrix-synapse.sql"

View File

@ -1,11 +0,0 @@
# ca
Getting the certificates in the right place is a manual process (for now, at least). This is to keep the most control over the root certificate's key and allow manual cycling. The manual commands should be run on a trusted machine.
Creating a 10 year root certificate:
nix run nixpkgs#step-cli -- certificate create 'Hillion ACME' cert.pem key.pem --kty=EC --curve=P-521 --profile=root-ca --not-after=87600h
Creating the intermediate key:
nix run nixpkgs#step-cli -- certificate create 'Hillion ACME (sodium.pop.ts.hillion.co.uk)' intermediate_cert.pem intermediate_key.pem --kty=EC --curve=P-521 --profile=intermediate-ca --not-after=8760h --ca=$NIXOS_ROOT/modules/ca/cert.pem --ca-key=DOWNLOADED_KEY.pem

View File

@ -1,13 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIB+TCCAVqgAwIBAgIQIZdaIUsuJdjnu7DQP1N8oTAKBggqhkjOPQQDBDAXMRUw
EwYDVQQDEwxIaWxsaW9uIEFDTUUwHhcNMjQwODAxMjIyMjEwWhcNMzQwNzMwMjIy
MjEwWjAXMRUwEwYDVQQDEwxIaWxsaW9uIEFDTUUwgZswEAYHKoZIzj0CAQYFK4EE
ACMDgYYABAAJI3z1PrV97EFc1xaENcr6ML1z6xdXTy+ReHtf42nWsw+c3WDKzJ45
+xHJ/p2BTOR5+NQ7RGQQ68zmFJnEYTYDogAw6U9YzxxDGlG1HlgnZ9PPmXoF+PFl
Zy2WZCiDPx5KDJcjTPzLV3ITt4fl3PMA12BREVeonvrvRLcpVrMfS2b7wKNFMEMw
DgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFFBT
fMT0uUbS+lVUbGKK8/SZHPISMAoGCCqGSM49BAMEA4GMADCBiAJCAPNIwrQztPrN
MaHB3J0lNVODIGwQWblt99vnjqIWOKJhgckBxaElyInsyt8dlnmTCpOCJdY4BA+K
Nr87AfwIWdAaAkIBV5i4zXPXVKblGKnmM0FomFSbq2cYE3pmi5BO1StakH1kEHlf
vbkdwFgkw2MlARp0Ka3zbWivBG9zjPoZtsL/8tk=
-----END CERTIFICATE-----

View File

@ -1,14 +0,0 @@
{ config, pkgs, lib, ... }:
let
cfg = config.custom.ca.consumer;
in
{
options.custom.ca.consumer = {
enable = lib.mkEnableOption "ca.service";
};
config = lib.mkIf cfg.enable {
security.pki.certificates = [ (builtins.readFile ./cert.pem) ];
};
}

View File

@ -1,8 +0,0 @@
{ ... }:
{
imports = [
./consumer.nix
./service.nix
];
}

View File

@ -1,48 +0,0 @@
{ config, pkgs, lib, ... }:
let
cfg = config.custom.ca.service;
in
{
options.custom.ca.service = {
enable = lib.mkEnableOption "ca.service";
};
config = lib.mkIf cfg.enable {
users.users.step-ca.uid = config.ids.uids.step-ca;
users.groups.step-ca.gid = config.ids.gids.step-ca;
services.step-ca = {
enable = true;
address = config.custom.dns.tailscale.ipv4;
port = 8443;
intermediatePasswordFile = "/data/system/ca/intermediate.psk";
settings = {
root = ./cert.pem;
crt = "/data/system/ca/intermediate.crt";
key = "/data/system/ca/intermediate.pem";
dnsNames = [ "ca.ts.hillion.co.uk" ];
logger = { format = "text"; };
db = {
type = "badgerv2";
dataSource = "/var/lib/step-ca/db";
};
authority = {
provisioners = [
{
type = "ACME";
name = "acme";
}
];
};
};
};
};
}

View File

@ -22,8 +22,8 @@ in
default = null; default = null;
}; };
plotDirectories = lib.mkOption { plotDirectories = lib.mkOption {
type = with lib.types; listOf str; type = with lib.types; nullOr (listOf str);
default = [ ]; default = null;
}; };
openFirewall = lib.mkOption { openFirewall = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
@ -46,7 +46,7 @@ in
}; };
virtualisation.oci-containers.containers.chia = { virtualisation.oci-containers.containers.chia = {
image = "ghcr.io/chia-network/chia:2.4.3"; image = "ghcr.io/chia-network/chia:2.4.1";
ports = [ "8444" ]; ports = [ "8444" ];
extraOptions = [ extraOptions = [
"--uidmap=0:${toString config.users.users.chia.uid}:1" "--uidmap=0:${toString config.users.users.chia.uid}:1"
@ -62,11 +62,6 @@ in
}; };
}; };
systemd.tmpfiles.rules = [
"d ${cfg.path} 0700 chia chia - -"
"d ${cfg.path}/.chia 0700 chia chia - -"
];
networking.firewall = lib.mkIf cfg.openFirewall { networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ 8444 ]; allowedTCPPorts = [ 8444 ];
}; };

View File

@ -3,7 +3,6 @@
{ {
imports = [ imports = [
./backups/default.nix ./backups/default.nix
./ca/default.nix
./chia.nix ./chia.nix
./defaults.nix ./defaults.nix
./desktop/awesome/default.nix ./desktop/awesome/default.nix
@ -12,16 +11,16 @@
./hostinfo.nix ./hostinfo.nix
./ids.nix ./ids.nix
./impermanence.nix ./impermanence.nix
./laptop.nix
./locations.nix ./locations.nix
./prometheus/default.nix
./resilio.nix ./resilio.nix
./sched_ext.nix
./services/default.nix ./services/default.nix
./shell/default.nix ./shell/default.nix
./ssh/default.nix ./ssh/default.nix
./storj.nix ./storj.nix
./users.nix ./users.nix
./www/default.nix ./www/global.nix
./www/www-repo.nix
]; ];
options.custom = { options.custom = {

View File

@ -1,10 +1,9 @@
{ pkgs, nixpkgs-unstable, lib, config, agenix, ... }: { pkgs, lib, config, agenix, ... }:
{ {
options.custom.defaults = lib.mkEnableOption "defaults"; options.custom.defaults = lib.mkEnableOption "defaults";
config = lib.mkIf config.custom.defaults { config = lib.mkIf config.custom.defaults {
hardware.enableAllFirmware = true;
nix = { nix = {
settings.experimental-features = [ "nix-command" "flakes" ]; settings.experimental-features = [ "nix-command" "flakes" ];
settings = { settings = {
@ -39,6 +38,7 @@
git git
htop htop
nix nix
sapling
vim vim
]; ];
variables.EDITOR = "vim"; variables.EDITOR = "vim";
@ -53,17 +53,10 @@
}; };
networking.firewall.enable = true; networking.firewall.enable = true;
nix.registry.nixpkgs-unstable.to = {
type = "path";
path = nixpkgs-unstable;
};
# Delegation # Delegation
custom.ca.consumer.enable = true;
custom.dns.enable = true; custom.dns.enable = true;
custom.home.defaults = true; custom.home.defaults = true;
custom.hostinfo.enable = true; custom.hostinfo.enable = true;
custom.prometheus.client.enable = true;
custom.shell.enable = true; custom.shell.enable = true;
custom.ssh.enable = true; custom.ssh.enable = true;
}; };

View File

@ -50,16 +50,10 @@ in
pop = { pop = {
li = "100.106.87.35"; li = "100.106.87.35";
sodium = "100.87.188.4"; sodium = "100.87.188.4";
stinger = "100.117.89.126";
};
rig = {
merlin = "100.69.181.56";
};
st = {
phoenix = "100.92.37.106";
}; };
storage = { storage = {
theon = "100.104.142.22"; theon = "100.104.142.22";
tywin = "100.115.31.91";
}; };
}; };
}; };
@ -83,16 +77,10 @@ in
pop = { pop = {
li = "fd7a:115c:a1e0::e701:5723"; li = "fd7a:115c:a1e0::e701:5723";
sodium = "fd7a:115c:a1e0::3701:bc04"; sodium = "fd7a:115c:a1e0::3701:bc04";
stinger = "fd7a:115c:a1e0::8401:597e";
};
rig = {
merlin = "fd7a:115c:a1e0::8d01:b538";
};
st = {
phoenix = "fd7a:115c:a1e0::6901:256a";
}; };
storage = { storage = {
theon = "fd7a:115c:a1e0::4aa8:8e16"; theon = "fd7a:115c:a1e0::4aa8:8e16";
tywin = "fd7a:115c:a1e0:ab12:4843:cd96:6273:1f5b";
}; };
}; };
}; };

View File

@ -3,47 +3,30 @@
{ {
imports = [ imports = [
./git.nix ./git.nix
./neovim.nix
./tmux/default.nix ./tmux/default.nix
]; ];
options.custom.home.defaults = lib.mkEnableOption "home"; options.custom.home.defaults = lib.mkEnableOption "home";
config = lib.mkIf config.custom.home.defaults { config = lib.mkIf config.custom.home.defaults {
home-manager = home-manager = {
let users.root.home = {
stateVersion = if (builtins.compareVersions config.system.stateVersion "24.05") > 0 then config.system.stateVersion else "22.11"; stateVersion = "22.11";
in
{
users.root.home = {
inherit stateVersion;
## Set an empty ZSH config and defer to the global one ## Set an empty ZSH config and defer to the global one
file.".zshrc".text = ""; file.".zshrc".text = "";
};
users."${config.custom.user}" = {
home = {
inherit stateVersion;
};
services = {
ssh-agent.enable = true;
};
programs = {
zoxide = {
enable = true;
options = [ "--cmd cd" ];
};
zsh.enable = true;
};
};
}; };
users."${config.custom.user}".home = {
stateVersion = "22.11";
## Set an empty ZSH config and defer to the global one
file.".zshrc".text = "";
};
};
# Delegation # Delegation
custom.home.git.enable = true; custom.home.git.enable = true;
custom.home.neovim.enable = true;
custom.home.tmux.enable = true; custom.home.tmux.enable = true;
}; };
} }

View File

@ -9,34 +9,21 @@ in
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home-manager.users.jake.programs = { home-manager.users.jake.programs.git = lib.mkIf (config.custom.user == "jake") {
sapling = lib.mkIf (config.custom.user == "jake") { enable = true;
enable = true; extraConfig = {
userName = "Jake Hillion"; user = {
userEmail = "jake@hillion.co.uk"; email = "jake@hillion.co.uk";
name = "Jake Hillion";
extraConfig = {
ui = {
"merge:interactive" = ":merge3";
};
}; };
}; pull = {
rebase = true;
git = lib.mkIf (config.custom.user == "jake") { };
enable = true; merge = {
userName = "Jake Hillion"; conflictstyle = "diff3";
userEmail = "jake@hillion.co.uk"; };
init = {
extraConfig = { defaultBranch = "main";
pull = {
rebase = true;
};
merge = {
conflictstyle = "diff3";
};
init = {
defaultBranch = "main";
};
}; };
}; };
}; };

View File

@ -1,82 +0,0 @@
{ pkgs, lib, config, ... }:
let
cfg = config.custom.home.neovim;
in
{
options.custom.home.neovim = {
enable = lib.mkEnableOption "neovim";
};
config = lib.mkIf config.custom.home.neovim.enable {
home-manager.users."${config.custom.user}".programs.neovim = {
enable = true;
viAlias = true;
vimAlias = true;
plugins = with pkgs.vimPlugins; [
a-vim
dracula-nvim
telescope-nvim
];
extraLuaConfig = ''
-- Logical options
vim.opt.splitright = true
vim.opt.splitbelow = true
vim.opt.ignorecase = true
vim.opt.smartcase = true
vim.opt.expandtab = true
vim.opt.tabstop = 2
vim.opt.shiftwidth = 2
-- Appearance
vim.cmd[[colorscheme dracula-soft]]
vim.opt.number = true
vim.opt.relativenumber = true
-- Telescope
require('telescope').setup({
pickers = {
find_files = {
find_command = {
"${pkgs.fd}/bin/fd",
"--type=f",
"--strip-cwd-prefix",
"--no-require-git",
"--hidden",
"--exclude=.sl",
},
},
},
defaults = {
vimgrep_arguments = {
"${pkgs.ripgrep}/bin/rg",
"--color=never",
"--no-heading",
"--with-filename",
"--line-number",
"--column",
"--smart-case",
"--no-require-git",
"--hidden",
"--glob=!.sl",
},
},
})
-- Key bindings
vim.g.mapleader = ","
--- Key bindings: Telescope
local telescope_builtin = require('telescope.builtin')
vim.keymap.set('n', '<leader>ff', telescope_builtin.find_files, {})
vim.keymap.set('n', '<leader>fg', telescope_builtin.live_grep, {})
vim.keymap.set('n', '<leader>fb', telescope_builtin.buffers, {})
vim.keymap.set('n', '<leader>fh', telescope_builtin.help_tags, {})
'';
};
};
}

View File

@ -1,16 +1,9 @@
setw -g mouse on setw -g mouse on
# Large history
set -g history-limit 500000
# Bindings # Bindings
bind C-Y set-window-option synchronize-panes bind C-Y set-window-option synchronize-panes
bind -n C-k clear-history bind -n C-k clear-history
# Status pane
set -g status-right-length 100
set -g status-right "#(uname -r) • #(hostname -f | sed 's/\.ts\.hillion\.co\.uk//g') • %d-%b-%y %H:%M"
# New panes in the same directory # New panes in the same directory
bind '"' split-window -c "#{pane_current_path}" bind '"' split-window -c "#{pane_current_path}"
bind % split-window -h -c "#{pane_current_path}" bind % split-window -h -c "#{pane_current_path}"

View File

@ -11,7 +11,14 @@ in
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
home-manager.users.jake.programs.tmux = { home-manager.users.jake.programs.tmux = {
enable = true; enable = true;
extraConfig = lib.readFile ./.tmux.conf;
extraConfig = lib.strings.concatLines [
(lib.readFile ./.tmux.conf)
''set -g status-right "${lib.strings.optionalString config.custom.laptop "#{battery_icon} #{battery_percentage} #{battery_remain} | "}\"#{=21:pane_title}\" %H:%M %d-%b-%y"''
];
plugins = with pkgs; lib.lists.optional config.custom.laptop tmuxPlugins.battery;
}; };
}; };
} }

View File

@ -7,10 +7,6 @@
unifi = 183; unifi = 183;
chia = 185; chia = 185;
gitea = 186; gitea = 186;
node-exporter = 188;
step-ca = 198;
isponsorblocktv = 199;
frigate = 200;
## Consistent People ## Consistent People
jake = 1000; jake = 1000;
@ -21,10 +17,6 @@
unifi = 183; unifi = 183;
chia = 185; chia = 185;
gitea = 186; gitea = 186;
node-exporter = 188;
step-ca = 198;
isponsorblocktv = 199;
frigate = 200;
## Consistent Groups ## Consistent Groups
mediaaccess = 1200; mediaaccess = 1200;

View File

@ -2,6 +2,7 @@
let let
cfg = config.custom.impermanence; cfg = config.custom.impermanence;
listIf = (enable: x: if enable then x else [ ]);
in in
{ {
options.custom.impermanence = { options.custom.impermanence = {
@ -11,13 +12,6 @@ in
type = lib.types.str; type = lib.types.str;
default = "/data"; default = "/data";
}; };
cache = {
enable = lib.mkEnableOption "impermanence.cache";
path = lib.mkOption {
type = lib.types.str;
default = "/cache";
};
};
users = lib.mkOption { users = lib.mkOption {
type = with lib.types; listOf str; type = with lib.types; listOf str;
@ -39,94 +33,53 @@ in
services = { services = {
openssh.hostKeys = [ openssh.hostKeys = [
{ path = "${cfg.base}/system/etc/ssh/ssh_host_ed25519_key"; type = "ed25519"; } { path = "/data/system/etc/ssh/ssh_host_ed25519_key"; type = "ed25519"; }
{ path = "${cfg.base}/system/etc/ssh/ssh_host_rsa_key"; type = "rsa"; bits = 4096; } { path = "/data/system/etc/ssh/ssh_host_rsa_key"; type = "rsa"; bits = 4096; }
]; ];
matrix-synapse.dataDir = "${cfg.base}/system/var/lib/matrix-synapse"; matrix-synapse.dataDir = "${cfg.base}/system/var/lib/matrix-synapse";
gitea.stateDir = "${cfg.base}/system/var/lib/gitea"; gitea.stateDir = "${cfg.base}/system/var/lib/gitea";
}; };
custom.chia = lib.mkIf config.custom.chia.enable { environment.persistence."${cfg.base}/system" = {
path = lib.mkOverride 999 "${cfg.base}/chia"; hideMounts = true;
directories = [
"/etc/nixos"
] ++ (listIf config.services.tailscale.enable [ "/var/lib/tailscale" ]) ++
(listIf config.services.zigbee2mqtt.enable [ config.services.zigbee2mqtt.dataDir ]) ++
(listIf config.services.postgresql.enable [ config.services.postgresql.dataDir ]) ++
(listIf config.hardware.bluetooth.enable [ "/var/lib/bluetooth" ]) ++
(listIf config.custom.services.unifi.enable [ "/var/lib/unifi" ]) ++
(listIf (config.virtualisation.oci-containers.containers != { }) [ "/var/lib/containers" ]) ++
(listIf config.services.tang.enable [ "/var/lib/private/tang" ]);
}; };
custom.services.frigate = lib.mkIf config.custom.services.frigate.enable {
dataPath = lib.mkOverride 999 "${cfg.base}/frigate";
};
services.resilio = lib.mkIf config.services.resilio.enable {
directoryRoot = lib.mkOverride 999 "${cfg.base}/sync";
};
services.plex = lib.mkIf config.services.plex.enable {
dataDir = lib.mkOverride 999 "${cfg.base}/plex";
};
services.home-assistant = lib.mkIf config.services.home-assistant.enable {
configDir = lib.mkOverride 999 "/data/home-assistant";
};
environment.persistence = lib.mkMerge [
{
"${cfg.base}/system" = {
hideMounts = true;
directories = [
"/etc/nixos"
] ++ (lib.lists.optional config.services.tailscale.enable "/var/lib/tailscale") ++
(lib.lists.optional config.services.zigbee2mqtt.enable config.services.zigbee2mqtt.dataDir) ++
(lib.lists.optional config.services.postgresql.enable config.services.postgresql.dataDir) ++
(lib.lists.optional config.hardware.bluetooth.enable "/var/lib/bluetooth") ++
(lib.lists.optional config.custom.services.unifi.enable "/var/lib/unifi") ++
(lib.lists.optional (config.virtualisation.oci-containers.containers != { }) "/var/lib/containers") ++
(lib.lists.optional config.services.tang.enable "/var/lib/private/tang") ++
(lib.lists.optional config.services.caddy.enable "/var/lib/caddy") ++
(lib.lists.optional config.services.prometheus.enable "/var/lib/${config.services.prometheus.stateDir}") ++
(lib.lists.optional config.custom.services.isponsorblocktv.enable "${config.custom.services.isponsorblocktv.dataDir}") ++
(lib.lists.optional config.services.step-ca.enable "/var/lib/step-ca/db");
};
}
(lib.mkIf cfg.cache.enable {
"${cfg.cache.path}/system" = {
hideMounts = true;
directories = (lib.lists.optional config.services.postgresqlBackup.enable config.services.postgresqlBackup.location);
};
})
];
home-manager.users = home-manager.users =
let let
mkUser = (x: mkUser = (x: {
let name = x;
homeCfg = config.home-manager.users."${x}"; value = {
in home = {
{ persistence."/data/users/${x}" = {
name = x; allowOther = false;
value = {
home = {
persistence."${cfg.base}/users/${x}" = {
allowOther = false;
files = cfg.userExtraFiles.${x} or [ ]; files = cfg.userExtraFiles.${x} or [ ];
directories = cfg.userExtraDirs.${x} or [ ]; directories = cfg.userExtraDirs.${x} or [ ];
};
sessionVariables = lib.attrsets.optionalAttrs homeCfg.programs.zoxide.enable { _ZO_DATA_DIR = "${cfg.base}/users/${x}/.local/share/zoxide"; };
};
programs = {
zsh.history.path = lib.mkOverride 999 "${cfg.base}/users/${x}/.zsh_history";
}; };
file.".zshrc".text = lib.mkForce ''
HISTFILE=/data/users/${x}/.zsh_history
'';
}; };
}); };
});
in in
builtins.listToAttrs (builtins.map mkUser cfg.users); builtins.listToAttrs (builtins.map mkUser cfg.users);
systemd.tmpfiles.rules = lib.lists.flatten (builtins.map systemd.tmpfiles.rules = lib.lists.flatten (builtins.map
(user: (user:
let details = config.users.users.${user}; in [ let details = config.users.users.${user}; in [
"d ${cfg.base}/users/${user} 0700 ${user} ${details.group} - -" "d /data/users/${user} 0700 ${user} ${details.group} - -"
"L ${details.home}/local - ${user} ${details.group} - ${cfg.base}/users/${user}" "L ${details.home}/local - ${user} ${details.group} - /data/users/${user}"
]) ])
cfg.users); cfg.users);
}; };

5
modules/laptop.nix Normal file
View File

@ -0,0 +1,5 @@
{ pkgs, lib, config, ... }:
{
options.custom.laptop = lib.mkEnableOption "laptop";
}

View File

@ -20,14 +20,11 @@ in
custom.locations.locations = { custom.locations.locations = {
services = { services = {
authoritative_dns = [ "boron.cx.ts.hillion.co.uk" ]; authoritative_dns = [ "boron.cx.ts.hillion.co.uk" ];
downloads = "phoenix.st.ts.hillion.co.uk"; downloads = "tywin.storage.ts.hillion.co.uk";
frigate = "phoenix.st.ts.hillion.co.uk";
gitea = "boron.cx.ts.hillion.co.uk"; gitea = "boron.cx.ts.hillion.co.uk";
homeassistant = "stinger.pop.ts.hillion.co.uk"; homeassistant = "microserver.home.ts.hillion.co.uk";
mastodon = ""; mastodon = "";
matrix = "boron.cx.ts.hillion.co.uk"; matrix = "boron.cx.ts.hillion.co.uk";
prometheus = "boron.cx.ts.hillion.co.uk";
restic = "phoenix.st.ts.hillion.co.uk";
tang = [ tang = [
"li.pop.ts.hillion.co.uk" "li.pop.ts.hillion.co.uk"
"microserver.home.ts.hillion.co.uk" "microserver.home.ts.hillion.co.uk"

View File

@ -1,24 +0,0 @@
{ pkgs, lib, config, ... }:
let
cfg = config.custom.prometheus.client;
in
{
options.custom.prometheus.client = {
enable = lib.mkEnableOption "prometheus-client";
};
config = lib.mkIf cfg.enable {
users.users.node-exporter.uid = config.ids.uids.node-exporter;
users.groups.node-exporter.gid = config.ids.gids.node-exporter;
services.prometheus.exporters.node = {
enable = true;
port = 9000;
enabledCollectors = [
"systemd"
];
};
};
}

View File

@ -1,8 +0,0 @@
{ ... }:
{
imports = [
./client.nix
./service.nix
];
}

View File

@ -1,67 +0,0 @@
{ pkgs, lib, config, ... }:
let
cfg = config.custom.services.prometheus;
in
{
options.custom.services.prometheus = {
enable = lib.mkEnableOption "prometheus-client";
};
config = lib.mkIf cfg.enable {
services.prometheus = {
enable = true;
globalConfig = {
scrape_interval = "15s";
};
retentionTime = "1y";
scrapeConfigs = [{
job_name = "node";
static_configs = [{
targets = builtins.map (x: "${x}:9000") (builtins.attrNames (builtins.readDir ../../hosts));
}];
}];
rules = [
''
groups:
- name: service alerting
rules:
- alert: ResilioSyncDown
expr: node_systemd_unit_state{ name = 'resilio.service', state != 'active' } > 0
for: 10m
annotations:
summary: "Resilio Sync systemd service is down"
description: "The Resilio Sync systemd service is not active on instance {{ $labels.instance }}."
''
];
};
services.caddy = {
enable = true;
virtualHosts."prometheus.ts.hillion.co.uk" = {
listenAddresses = [ config.custom.dns.tailscale.ipv4 config.custom.dns.tailscale.ipv6 ];
extraConfig = ''
reverse_proxy http://localhost:9090
tls {
ca https://ca.ts.hillion.co.uk:8443/acme/acme/directory
}
'';
};
};
### HACK: Allow Caddy to restart if it fails. This happens because Tailscale
### is too late at starting. Upstream nixos caddy does restart on failure
### but it's prevented on exit code 1. Set the exit code to 0 (non-failure)
### to override this.
systemd.services.caddy = {
requires = [ "tailscaled.service" ];
after = [ "tailscaled.service" ];
serviceConfig = {
RestartPreventExitStatus = lib.mkForce 0;
};
};
};
}

View File

@ -4,9 +4,6 @@ let
cfg = config.custom.resilio; cfg = config.custom.resilio;
in in
{ {
imports = [ "${nixpkgs-unstable}/nixos/modules/services/networking/resilio.nix" ];
disabledModules = [ "services/networking/resilio.nix" ];
options.custom.resilio = { options.custom.resilio = {
enable = lib.mkEnableOption "resilio"; enable = lib.mkEnableOption "resilio";
@ -19,93 +16,50 @@ in
type = with lib.types; uniq (listOf attrs); type = with lib.types; uniq (listOf attrs);
default = [ ]; default = [ ];
}; };
backups = {
enable = lib.mkEnableOption "resilio.backups";
};
}; };
config = lib.mkIf cfg.enable (lib.mkMerge [ config = lib.mkIf cfg.enable {
{ users.users =
users.users = let
let mkUser =
mkUser = (user: {
(user: { name = user;
name = user;
value = {
extraGroups = [ "rslsync" ];
};
});
in
builtins.listToAttrs (builtins.map mkUser cfg.extraUsers);
age.secrets =
let
mkSecret = (secret: {
name = secret.name;
value = { value = {
file = secret.file; extraGroups = [ "rslsync" ];
owner = "rslsync";
group = "rslsync";
}; };
}); });
in
builtins.listToAttrs (builtins.map mkUser cfg.extraUsers);
age.secrets =
let
mkSecret = (secret: {
name = secret.name;
value = {
file = secret.file;
owner = "rslsync";
group = "rslsync";
};
});
in
builtins.listToAttrs (builtins.map (folder: mkSecret folder.secret) cfg.folders);
services.resilio = {
enable = true;
sharedFolders =
let
mkFolder = name: secret: {
directory = "${config.services.resilio.directoryRoot}/${name}";
secretFile = "${config.age.secrets."${secret.name}".path}";
knownHosts = [ ];
searchLAN = true;
useDHT = true;
useRelayServer = true;
useSyncTrash = false;
useTracker = true;
};
in in
builtins.listToAttrs (builtins.map (folder: mkSecret folder.secret) cfg.folders); builtins.map (folder: mkFolder folder.name folder.secret) cfg.folders;
};
services.resilio = { };
enable = true;
deviceName = lib.mkOverride 999 (lib.strings.concatStringsSep "." (lib.lists.take 2 (lib.strings.splitString "." config.networking.fqdnOrHostName)));
storagePath = lib.mkOverride 999 "${config.services.resilio.directoryRoot}/.sync";
sharedFolders =
let
mkFolder = name: secret: {
directory = "${config.services.resilio.directoryRoot}/${name}";
secretFile = "${config.age.secrets."${secret.name}".path}";
knownHosts = [ ];
searchLAN = true;
useDHT = true;
useRelayServer = true;
useSyncTrash = false;
useTracker = true;
};
in
builtins.map (folder: mkFolder folder.name folder.secret) cfg.folders;
};
systemd.services.resilio.unitConfig.RequiresMountsFor = builtins.map (folder: "${config.services.resilio.directoryRoot}/${folder.name}") cfg.folders;
}
(lib.mkIf cfg.backups.enable {
age.secrets."resilio/restic/128G.key" = {
file = ../secrets/restic/128G.age;
owner = "rslsync";
group = "rslsync";
};
services.restic.backups."resilio" = {
repository = "rest:https://restic.ts.hillion.co.uk/128G";
user = "rslsync";
passwordFile = config.age.secrets."resilio/restic/128G.key".path;
timerConfig = {
OnBootSec = "10m";
OnUnitInactiveSec = "15m";
RandomizedDelaySec = "5m";
};
paths = [ config.services.resilio.directoryRoot ];
exclude = [
"${config.services.resilio.directoryRoot}/.sync"
"${config.services.resilio.directoryRoot}/*/.sync"
"${config.services.resilio.directoryRoot}/resources/media/films"
"${config.services.resilio.directoryRoot}/resources/media/iso"
"${config.services.resilio.directoryRoot}/resources/media/tv"
"${config.services.resilio.directoryRoot}/dad/media"
];
};
})
]);
} }

View File

@ -1,22 +0,0 @@
{ config, pkgs, lib, ... }:
let
cfg = config.custom.sched_ext;
in
{
options.custom.sched_ext = {
enable = lib.mkEnableOption "sched_ext";
};
config = lib.mkIf cfg.enable {
assertions = [{
assertion = config.boot.kernelPackages.kernelAtLeast "6.12";
message = "sched_ext requires a kernel >=6.12";
}];
boot.kernelPackages = if pkgs.linuxPackages.kernelAtLeast "6.12" then pkgs.linuxPackages else (if pkgs.linuxPackages_latest.kernelAtLeast "6.12" then pkgs.linuxPackages_latest else pkgs.unstable.linuxPackages_testing);
environment.systemPackages = with pkgs; [ unstable.scx.layered unstable.scx.lavd ];
};
}

View File

@ -32,22 +32,14 @@ in
86400 NS ns1.hillion.co.uk. 86400 NS ns1.hillion.co.uk.
ca 21600 CNAME sodium.pop.ts.hillion.co.uk. deluge.downloads 21600 CNAME tywin.storage.ts.hillion.co.uk.
frigate 21600 CNAME ${config.custom.locations.locations.services.frigate}.
prometheus 21600 CNAME ${config.custom.locations.locations.services.prometheus}.
restic 21600 CNAME ${config.custom.locations.locations.services.restic}.
deluge.downloads 21600 CNAME ${config.custom.locations.locations.services.downloads}.
prowlarr.downloads 21600 CNAME ${config.custom.locations.locations.services.downloads}.
radarr.downloads 21600 CNAME ${config.custom.locations.locations.services.downloads}.
sonarr.downloads 21600 CNAME ${config.custom.locations.locations.services.downloads}.
graphs.router.home 21600 CNAME router.home.ts.hillion.co.uk. graphs.router.home 21600 CNAME router.home.ts.hillion.co.uk.
prowlarr.downloads 21600 CNAME tywin.storage.ts.hillion.co.uk.
radarr.downloads 21600 CNAME tywin.storage.ts.hillion.co.uk.
restic.tywin.storage 21600 CNAME tywin.storage.ts.hillion.co.uk.
sonarr.downloads 21600 CNAME tywin.storage.ts.hillion.co.uk.
zigbee2mqtt.home 21600 CNAME router.home.ts.hillion.co.uk. zigbee2mqtt.home 21600 CNAME router.home.ts.hillion.co.uk.
charlie.kvm 21600 CNAME router.home.ts.hillion.co.uk.
hammer.kvm 21600 CNAME router.home.ts.hillion.co.uk.
'' + (makeRecords "A" config.custom.dns.authoritative.ipv4.uk.co.hillion.ts) + "\n\n" + (makeRecords "AAAA" config.custom.dns.authoritative.ipv6.uk.co.hillion.ts); '' + (makeRecords "A" config.custom.dns.authoritative.ipv4.uk.co.hillion.ts) + "\n\n" + (makeRecords "AAAA" config.custom.dns.authoritative.ipv6.uk.co.hillion.ts);
}; };
}; };

View File

@ -4,13 +4,10 @@
imports = [ imports = [
./authoritative_dns.nix ./authoritative_dns.nix
./downloads.nix ./downloads.nix
./frigate.nix
./gitea/default.nix ./gitea/default.nix
./homeassistant.nix ./homeassistant.nix
./isponsorblocktv.nix
./mastodon/default.nix ./mastodon/default.nix
./matrix.nix ./matrix.nix
./restic.nix
./tang.nix ./tang.nix
./unifi.nix ./unifi.nix
./version_tracker.nix ./version_tracker.nix

View File

@ -24,33 +24,27 @@ in
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
age.secrets."wireguard/downloads".file = ../../secrets/wireguard/downloads.age;
age.secrets."deluge/auth" = {
file = ../../secrets/deluge/auth.age;
owner = "deluge";
};
services.caddy = { services.caddy = {
enable = true; enable = true;
virtualHosts = builtins.listToAttrs (builtins.map virtualHosts = builtins.listToAttrs (builtins.map
(x: { (x: {
name = "${x}.downloads.ts.hillion.co.uk"; name = "http://${x}.downloads.ts.hillion.co.uk";
value = { value = {
listenAddresses = [ config.custom.dns.tailscale.ipv4 config.custom.dns.tailscale.ipv6 ]; listenAddresses = [ config.custom.dns.tailscale.ipv4 config.custom.dns.tailscale.ipv6 ];
extraConfig = '' extraConfig = "reverse_proxy unix//${cfg.metadataPath}/caddy/caddy.sock";
reverse_proxy unix//${cfg.metadataPath}/caddy/caddy.sock
tls {
ca https://ca.ts.hillion.co.uk:8443/acme/acme/directory
}
'';
}; };
}) [ "prowlarr" "sonarr" "radarr" "deluge" ]); }) [ "prowlarr" "sonarr" "radarr" "deluge" ]);
}; };
## Wireguard ## Wireguard
age.secrets."wireguard/downloads".file = ../../secrets/wireguard/downloads.age;
age.secrets."deluge/auth" = {
file = ../../secrets/deluge/auth.age;
owner = "deluge";
};
networking.wireguard.interfaces."downloads" = { networking.wireguard.interfaces."downloads" = {
privateKeyFile = config.age.secrets."wireguard/downloads".path; privateKeyFile = config.age.secrets."wireguard/downloads".path;
ips = [ "10.2.0.2/32" ]; ips = [ "10.2.0.2/32" ];

View File

@ -1,126 +0,0 @@
{ config, pkgs, lib, ... }:
let
cfg = config.custom.services.frigate;
in
{
options.custom.services.frigate = {
enable = lib.mkEnableOption "frigate";
dataPath = lib.mkOption {
type = lib.types.str;
default = "/var/lib/frigate";
};
recordingsPath = lib.mkOption {
type = lib.types.str;
default = "/practical-defiant-coffee/cctv";
};
};
config = lib.mkIf cfg.enable {
age.secrets."frigate/secrets.env".file = ../../secrets/frigate/secrets.env.age;
services.caddy = {
enable = true;
virtualHosts."frigate.ts.hillion.co.uk" = {
listenAddresses = [ config.custom.dns.tailscale.ipv4 config.custom.dns.tailscale.ipv6 ];
extraConfig = ''
reverse_proxy unix///run/nginx-frigate/nginx.sock
tls {
ca https://ca.ts.hillion.co.uk:8443/acme/acme/directory
}
'';
};
};
users.users.frigate = {
group = "frigate";
home = cfg.dataPath;
createHome = true;
uid = config.ids.uids.frigate;
};
users.groups.frigate.gid = config.ids.gids.frigate;
users.users.nginx = {
group = "nginx";
uid = config.ids.uids.nginx;
};
users.groups.nginx.gid = config.ids.gids.nginx;
systemd.tmpfiles.rules = [
"d /run/nginx-frigate 0750 nginx caddy - -"
];
containers."frigate" = {
autoStart = true;
ephemeral = true;
additionalCapabilities = [ "CAP_NET_ADMIN" ];
macvlans = [ "cameras" ];
bindMounts = {
"/run/agenix/frigate/secrets.env".hostPath = config.age.secrets."frigate/secrets.env".path;
"/run/nginx-frigate" = { hostPath = "/run/nginx-frigate"; isReadOnly = false; };
"/var/lib/frigate" = { hostPath = cfg.dataPath; isReadOnly = false; };
"/media/frigate/recordings" = { hostPath = cfg.recordingsPath; isReadOnly = false; };
};
config = (hostConfig: { config, pkgs, ... }: {
config = {
system.stateVersion = "24.05";
systemd.network = {
enable = true;
networks."10-cameras" = {
matchConfig.Name = "mv-cameras";
networkConfig.DHCP = "ipv4";
dhcpV4Config.ClientIdentifier = "mac";
linkConfig.MACAddress = "00:b7:43:f3:81:a0";
};
};
services.resolved.enable = false;
users.users.frigate.uid = hostConfig.ids.uids.frigate;
users.groups.frigate.gid = hostConfig.ids.gids.frigate;
services.nginx.virtualHosts."frigate.ts.hillion.co.uk".listen = lib.mkForce [
{ addr = "unix:/run/nginx-frigate/nginx.sock"; }
];
services.frigate = {
enable = true;
package = pkgs.frigate;
hostname = "frigate.ts.hillion.co.uk";
settings = {
record = {
enabled = true;
retain.mode = "motion";
};
cameras = {
living_room = {
enabled = true;
ffmpeg.inputs = [
{
path = "rtsp://admin:{FRIGATE_RTSP_PASSWORD}@10.133.145.2:554/h264Preview_01_sub";
roles = [ "detect" ];
}
{
path = "rtsp://admin:{FRIGATE_RTSP_PASSWORD}@10.133.145.2:554/h264Preview_01_main";
roles = [ "record" ];
}
];
};
};
};
};
systemd.services.frigate.serviceConfig.EnvironmentFile = "/run/agenix/frigate/secrets.env";
};
}) config;
};
};
}

View File

@ -63,11 +63,6 @@ in
runner = { runner = {
capacity = 3; capacity = 3;
}; };
cache = {
enabled = true;
host = "10.108.27.2";
port = 41919;
};
}; };
}; };
@ -81,8 +76,6 @@ in
chain output { chain output {
type filter hook output priority 100; policy accept; type filter hook output priority 100; policy accept;
ct state { established, related } counter accept
ip daddr 10.0.0.0/8 drop ip daddr 10.0.0.0/8 drop
ip daddr 100.64.0.0/10 drop ip daddr 100.64.0.0/10 drop
ip daddr 172.16.0.0/12 drop ip daddr 172.16.0.0/12 drop

View File

@ -1,4 +1,4 @@
{ config, pkgs, lib, ... }: { config, pkgs, lib, nixpkgs-unstable, ... }:
let let
cfg = config.custom.services.gitea; cfg = config.custom.services.gitea;
@ -55,7 +55,7 @@ in
services.gitea = { services.gitea = {
enable = true; enable = true;
package = pkgs.unstable.gitea; package = nixpkgs-unstable.legacyPackages.x86_64-linux.gitea;
mailerPasswordFile = config.age.secrets."gitea/mailer_password".path; mailerPasswordFile = config.age.secrets."gitea/mailer_password".path;
appName = "Hillion Gitea"; appName = "Hillion Gitea";

View File

@ -44,40 +44,20 @@ in
"bluetooth" "bluetooth"
"default_config" "default_config"
"esphome" "esphome"
"fully_kiosk" "flux"
"google_assistant" "google_assistant"
"homekit" "homekit"
"met" "met"
"mobile_app" "mobile_app"
"mqtt" "mqtt"
"otp" "otp"
"smartthings"
"sonos"
"sun" "sun"
"switchbot" "switchbot"
"waze_travel_time"
];
customComponents = with pkgs.home-assistant-custom-components; [
adaptive_lighting
]; ];
config = { config = {
default_config = { }; default_config = { };
homeassistant = {
auth_providers = [
{ type = "homeassistant"; }
{
type = "trusted_networks";
trusted_networks = [ "10.239.19.4/32" ];
trusted_users = {
"10.239.19.4" = "fb4979873ecb480d9e3bb336250fa344";
};
allow_bypass_login = true;
}
];
};
recorder = { recorder = {
db_url = "postgresql://@/homeassistant"; db_url = "postgresql://@/homeassistant";
}; };
@ -87,8 +67,6 @@ in
trusted_proxies = with config.custom.dns.authoritative; [ trusted_proxies = with config.custom.dns.authoritative; [
ipv4.uk.co.hillion.ts.cx.boron ipv4.uk.co.hillion.ts.cx.boron
ipv6.uk.co.hillion.ts.cx.boron ipv6.uk.co.hillion.ts.cx.boron
ipv4.uk.co.hillion.ts.pop.sodium
ipv6.uk.co.hillion.ts.pop.sodium
]; ];
}; };
@ -101,9 +79,6 @@ in
report_state = true; report_state = true;
expose_by_default = true; expose_by_default = true;
exposed_domains = [ "light" ]; exposed_domains = [ "light" ];
entity_config = {
"input_boolean.sleep_mode" = { };
};
}; };
homekit = [{ homekit = [{
filter = { filter = {
@ -113,19 +88,25 @@ in
bluetooth = { }; bluetooth = { };
adaptive_lighting = { switch = [
lights = [ {
"light.bedroom_lamp" platform = "flux";
"light.bedroom_light" start_time = "07:00";
"light.cubby_light" stop_time = "23:59";
"light.desk_lamp" mode = "mired";
"light.hallway_light" disable_brightness_adjust = true;
"light.living_room_lamp" lights = [
"light.living_room_light" "light.bedroom_lamp"
"light.wardrobe_light" "light.bedroom_light"
]; "light.cubby_light"
min_sunset_time = "21:00"; "light.desk_lamp"
}; "light.hallway_light"
"light.living_room_lamp"
"light.living_room_light"
"light.wardrobe_light"
];
}
];
light = [ light = [
{ {
@ -133,7 +114,7 @@ in
lights = { lights = {
bathroom_light = { bathroom_light = {
unique_id = "87a4cbb5-e5a7-44fd-9f28-fec2d6a62538"; unique_id = "87a4cbb5-e5a7-44fd-9f28-fec2d6a62538";
value_template = "{{ false if state_attr('script.bathroom_light_switch_if_on', 'last_triggered') > states.sensor.bathroom_motion_sensor_illuminance_lux.last_reported else states('sensor.bathroom_motion_sensor_illuminance_lux') | int > 500 }}"; value_template = "{{ states('sensor.bathroom_motion_sensor_illuminance_lux') | int > 500 }}";
turn_on = { service = "script.noop"; }; turn_on = { service = "script.noop"; };
turn_off = { service = "script.bathroom_light_switch_if_on"; }; turn_off = { service = "script.bathroom_light_switch_if_on"; };
}; };
@ -164,13 +145,6 @@ in
} }
]; ];
input_boolean = {
sleep_mode = {
name = "Set house to sleep mode";
icon = "mdi:sleep";
};
};
# UI managed expansions # UI managed expansions
automation = "!include automations.yaml"; automation = "!include automations.yaml";
script = "!include scripts.yaml"; script = "!include scripts.yaml";

View File

@ -1,62 +0,0 @@
{ config, pkgs, lib, ... }:
let
cfg = config.custom.services.isponsorblocktv;
ver = "v2.2.1";
ctl = pkgs.writeScriptBin "isponsorblocktv-config" ''
#! ${pkgs.runtimeShell}
set -e
sudo systemctl stop podman-isponsorblocktv
sudo ${pkgs.podman}/bin/podman run \
--rm -it \
--uidmap=0:${toString config.users.users.isponsorblocktv.uid}:1 \
--gidmap=0:${toString config.users.groups.isponsorblocktv.gid}:1 \
-v ${cfg.dataDir}:/app/data \
ghcr.io/dmunozv04/isponsorblocktv:${ver} \
--setup-cli
sudo systemctl start podman-isponsorblocktv
'';
in
{
options.custom.services.isponsorblocktv = {
enable = lib.mkEnableOption "isponsorblocktv";
dataDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/isponsorblocktv";
};
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [ ctl ];
users.groups.isponsorblocktv = {
gid = config.ids.gids.isponsorblocktv;
};
users.users.isponsorblocktv = {
home = cfg.dataDir;
createHome = true;
isSystemUser = true;
group = "isponsorblocktv";
uid = config.ids.uids.isponsorblocktv;
};
virtualisation.oci-containers.containers.isponsorblocktv = {
image = "ghcr.io/dmunozv04/isponsorblocktv:${ver}";
extraOptions = [
"--uidmap=0:${toString config.users.users.isponsorblocktv.uid}:1"
"--gidmap=0:${toString config.users.groups.isponsorblocktv.gid}:1"
];
volumes = [ "${cfg.dataDir}:/app/data" ];
};
systemd.tmpfiles.rules = [
"d ${cfg.dataDir} 0700 isponsorblocktv isponsorblocktv - -"
];
};
}

View File

@ -1,306 +0,0 @@
{ config, pkgs, lib, ... }:
let
cfg = config.custom.services.restic;
in
{
options.custom.services.restic = {
enable = lib.mkEnableOption "restic http server";
path = lib.mkOption {
type = lib.types.path;
default = "/var/lib/restic";
};
repos = lib.mkOption {
readOnly = true;
type = with lib.types; attrsOf (submodule {
options = {
path = lib.mkOption {
default = null;
type = nullOr str;
};
passwordFile = lib.mkOption {
default = null;
type = nullOr str;
};
environmentFile = lib.mkOption {
default = null;
type = nullOr str;
};
forgetConfig = lib.mkOption {
default = null;
type = nullOr (submodule {
options = {
timerConfig = lib.mkOption {
type = attrs;
};
opts = lib.mkOption {
type = listOf str;
};
};
});
};
clones = lib.mkOption {
default = [ ];
type = listOf (submodule {
options = {
timerConfig = lib.mkOption {
type = attrs;
};
repo = lib.mkOption {
type = str;
};
};
});
};
};
});
default = {
"128G" = {
path = "${cfg.path}/128G";
passwordFile = config.age.secrets."restic/128G.key".path;
forgetConfig = {
timerConfig = {
OnCalendar = "02:30";
RandomizedDelaySec = "1h";
};
opts = [
"--keep-last 48"
"--keep-within-hourly 7d"
"--keep-within-daily 1m"
"--keep-within-weekly 6m"
"--keep-within-monthly 24m"
];
};
clones = [
{
repo = "128G-wasabi";
timerConfig = {
OnBootSec = "30m";
OnUnitInactiveSec = "60m";
RandomizedDelaySec = "20m";
};
}
{
repo = "128G-backblaze";
timerConfig = {
OnBootSec = "30m";
OnUnitInactiveSec = "60m";
RandomizedDelaySec = "20m";
};
}
];
};
"1.6T" = {
path = "${cfg.path}/1.6T";
passwordFile = config.age.secrets."restic/1.6T.key".path;
forgetConfig = {
timerConfig = {
OnCalendar = "Wed, 02:30";
RandomizedDelaySec = "4h";
};
opts = [
"--keep-within-daily 14d"
"--keep-within-weekly 2m"
"--keep-within-monthly 18m"
];
};
clones = [
{
repo = "1.6T-wasabi";
timerConfig = {
OnBootSec = "30m";
OnUnitInactiveSec = "60m";
RandomizedDelaySec = "20m";
};
}
{
repo = "1.6T-backblaze";
timerConfig = {
OnBootSec = "30m";
OnUnitInactiveSec = "60m";
RandomizedDelaySec = "20m";
};
}
];
};
"128G-wasabi" = {
environmentFile = config.age.secrets."restic/128G-wasabi.env".path;
};
"1.6T-wasabi" = {
environmentFile = config.age.secrets."restic/1.6T-wasabi.env".path;
};
"128G-backblaze" = {
environmentFile = config.age.secrets."restic/128G-backblaze.env".path;
};
"1.6T-backblaze" = {
environmentFile = config.age.secrets."restic/1.6T-backblaze.env".path;
};
};
};
};
config = lib.mkIf cfg.enable {
age.secrets = {
"restic/128G.key" = {
file = ../../secrets/restic/128G.age;
owner = "restic";
group = "restic";
};
"restic/128G-wasabi.env".file = ../../secrets/restic/128G-wasabi.env.age;
"restic/128G-backblaze.env".file = ../../secrets/restic/128G-backblaze.env.age;
"restic/1.6T.key" = {
file = ../../secrets/restic/1.6T.age;
owner = "restic";
group = "restic";
};
"restic/1.6T-wasabi.env".file = ../../secrets/restic/1.6T-wasabi.env.age;
"restic/1.6T-backblaze.env".file = ../../secrets/restic/1.6T-backblaze.env.age;
};
services.restic.server = {
enable = true;
appendOnly = true;
extraFlags = [ "--no-auth" ];
dataDir = cfg.path;
listenAddress = "127.0.0.1:8000"; # TODO: can this be a Unix socket?
};
services.caddy = {
enable = true;
virtualHosts."restic.ts.hillion.co.uk".extraConfig = ''
bind ${config.custom.dns.tailscale.ipv4} ${config.custom.dns.tailscale.ipv6}
tls {
ca https://ca.ts.hillion.co.uk:8443/acme/acme/directory
}
reverse_proxy http://localhost:8000
'';
};
systemd =
let
mkRepoInfo = repo_cfg: (if (repo_cfg.passwordFile != null) then {
serviceConfig.LoadCredential = [
"password_file:${repo_cfg.passwordFile}"
];
environment = {
RESTIC_REPOSITORY = repo_cfg.path;
RESTIC_PASSWORD_FILE = "%d/password_file";
};
} else {
serviceConfig.EnvironmentFile = repo_cfg.environmentFile;
});
mkForgetService = name: repo_cfg:
if (repo_cfg.forgetConfig != null) then
({
description = "Restic forget service for ${name}";
serviceConfig = {
User = "restic";
Group = "restic";
};
script = ''
set -xe
${pkgs.restic}/bin/restic forget ${lib.strings.concatStringsSep " " repo_cfg.forgetConfig.opts} \
--prune \
--retry-lock 30m
'';
} // (mkRepoInfo repo_cfg)) else { };
mkForgetTimer = repo_cfg:
if (repo_cfg.forgetConfig != null) then {
wantedBy = [ "timers.target" ];
timerConfig = repo_cfg.forgetConfig.timerConfig;
} else { };
mkCloneService = from_repo: clone_cfg: to_repo: {
name = "restic-clone-${from_repo.name}-${to_repo.name}";
value = lib.mkMerge [
{
description = "Restic copy from ${from_repo.name} to ${to_repo.name}";
serviceConfig = {
User = "restic";
Group = "restic";
LoadCredential = [
"from_password_file:${from_repo.cfg.passwordFile}"
];
};
environment = {
RESTIC_FROM_PASSWORD_FILE = "%d/from_password_file";
};
script = ''
set -xe
${pkgs.restic}/bin/restic copy \
--from-repo ${from_repo.cfg.path} \
--retry-lock 30m
'';
}
(mkRepoInfo to_repo.cfg)
];
};
mkCloneTimer = from_repo: clone_cfg: to_repo: {
name = "restic-clone-${from_repo.name}-${to_repo.name}";
value = {
wantedBy = [ "timers.target" ];
timerConfig = clone_cfg.timerConfig;
};
};
mapClones = fn: builtins.listToAttrs (lib.lists.flatten (lib.mapAttrsToList
(
from_repo_name: from_repo_cfg: (builtins.map
(
clone_cfg: (fn
{ name = from_repo_name; cfg = from_repo_cfg; }
clone_cfg
{ name = clone_cfg.repo; cfg = cfg.repos."${clone_cfg.repo}"; }
)
)
from_repo_cfg.clones)
)
cfg.repos));
in
{
services = {
caddy = {
### HACK: Allow Caddy to restart if it fails. This happens because Tailscale
### is too late at starting. Upstream nixos caddy does restart on failure
### but it's prevented on exit code 1. Set the exit code to 0 (non-failure)
### to override this.
requires = [ "tailscaled.service" ];
after = [ "tailscaled.service" ];
serviceConfig = {
RestartPreventExitStatus = lib.mkForce 0;
};
};
}
// lib.mapAttrs' (name: value: lib.attrsets.nameValuePair ("restic-forget-" + name) (mkForgetService name value)) cfg.repos
// mapClones mkCloneService;
timers = lib.mapAttrs' (name: value: lib.attrsets.nameValuePair ("restic-forget-" + name) (mkForgetTimer value)) cfg.repos
// mapClones mkCloneTimer;
};
};
}

View File

@ -13,10 +13,7 @@ in
enable = true; enable = true;
ipAddressAllow = [ ipAddressAllow = [
"138.201.252.214/32" "138.201.252.214/32"
"10.64.50.26/32" "10.64.50.20/32"
"10.64.50.27/32"
"10.64.50.28/32"
"10.64.50.29/32"
]; ];
}; };
}; };

View File

@ -10,14 +10,20 @@ in
dataDir = lib.mkOption { dataDir = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = "/var/lib/unifi"; default = "/var/lib/unifi";
readOnly = true; # NixOS module only supports this directory
}; };
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
# Fix dynamically allocated user and group ids users.users.unifi = {
users.users.unifi.uid = config.ids.uids.unifi; uid = config.ids.uids.unifi;
users.groups.unifi.gid = config.ids.gids.unifi; isSystemUser = true;
group = "unifi";
description = "UniFi controller daemon user";
home = "${cfg.dataDir}";
};
users.groups.unifi = {
gid = config.ids.gids.unifi;
};
services.caddy = { services.caddy = {
enable = true; enable = true;
@ -32,9 +38,21 @@ in
}; };
}; };
services.unifi = { virtualisation.oci-containers.containers = {
enable = true; "unifi" = {
unifiPackage = pkgs.unifi8; image = "lscr.io/linuxserver/unifi-controller:8.0.24-ls221";
environment = {
PUID = toString config.ids.uids.unifi;
PGID = toString config.ids.gids.unifi;
TZ = "Etc/UTC";
};
volumes = [ "${cfg.dataDir}:/config" ];
ports = [
"8080:8080"
"8443:8443"
"3478:3478/udp"
];
};
}; };
}; };
} }

View File

@ -75,7 +75,7 @@ in
}; };
services.restic.backups."zigbee2mqtt" = lib.mkIf cfg.backup { services.restic.backups."zigbee2mqtt" = lib.mkIf cfg.backup {
repository = "rest:https://restic.ts.hillion.co.uk/1.6T"; repository = "rest:http://restic.tywin.storage.ts.hillion.co.uk/1.6T";
user = "zigbee2mqtt"; user = "zigbee2mqtt";
passwordFile = config.age.secrets."resilio/zigbee2mqtt/1.6T.key".path; passwordFile = config.age.secrets."resilio/zigbee2mqtt/1.6T.key".path;

View File

@ -14,8 +14,6 @@ in
"jake".openssh.authorizedKeys.keys = [ "jake".openssh.authorizedKeys.keys = [
"sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBBwJH4udKNvi9TjOBgkxpBBy7hzWqmP0lT5zE9neusCpQLIiDhr6KXYMPXWXdZDc18wH1OLi2+639dXOvp8V/wgAAAAEc3NoOg== jake@beryllium-keys" "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBBwJH4udKNvi9TjOBgkxpBBy7hzWqmP0lT5zE9neusCpQLIiDhr6KXYMPXWXdZDc18wH1OLi2+639dXOvp8V/wgAAAAEc3NoOg== jake@beryllium-keys"
"sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBPPJtW19jOaUsjmxc0+QibaLJ3J3yxPXSXZXwKT0Ean6VeaH5G8zG+zjt1Y6sg2d52lHgrRfeVl1xrG/UGX8qWoAAAAEc3NoOg== jakehillion@jakehillion-mbp"
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOt74U+rL+BMtAEjfu/Optg1D7Ly7U+TupRxd5u9kfN7oJnW4dJA25WRSr4dgQNq7MiMveoduBY/ky2s0c9gvIA= jake@jake-gentoo" "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOt74U+rL+BMtAEjfu/Optg1D7Ly7U+TupRxd5u9kfN7oJnW4dJA25WRSr4dgQNq7MiMveoduBY/ky2s0c9gvIA= jake@jake-gentoo"
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC0uKIvvvkzrOcS7AcamsQRFId+bqPwUC9IiUIsiH5oWX1ReiITOuEo+TL9YMII5RyyfJFeu2ZP9moNuZYlE7Bs= jake@jake-mbp" "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC0uKIvvvkzrOcS7AcamsQRFId+bqPwUC9IiUIsiH5oWX1ReiITOuEo+TL9YMII5RyyfJFeu2ZP9moNuZYlE7Bs= jake@jake-mbp"
@ -50,6 +48,7 @@ in
"router.home.ts.hillion.co.uk".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAlCj/i2xprN6h0Ik2tthOJQy6Qwq3Ony73+yfbHYTFu"; "router.home.ts.hillion.co.uk".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAlCj/i2xprN6h0Ik2tthOJQy6Qwq3Ony73+yfbHYTFu";
"sodium.pop.ts.hillion.co.uk".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDQmG7v/XrinPmkTU2eIoISuU3+hoV4h60Bmbwd+xDjr"; "sodium.pop.ts.hillion.co.uk".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDQmG7v/XrinPmkTU2eIoISuU3+hoV4h60Bmbwd+xDjr";
"theon.storage.ts.hillion.co.uk".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN59psLVu3/sQORA4x3p8H3ei8MCQlcwX5T+k3kBeBMf"; "theon.storage.ts.hillion.co.uk".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN59psLVu3/sQORA4x3p8H3ei8MCQlcwX5T+k3kBeBMf";
"tywin.storage.ts.hillion.co.uk".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGATsjWO0qZNFp2BhfgDuWi+e/ScMkFxp79N2OZoed1k";
}; };
programs.ssh.knownHostsFiles = [ ./github_known_hosts ]; programs.ssh.knownHostsFiles = [ ./github_known_hosts ];
}; };

View File

@ -1,10 +0,0 @@
{ config, lib, ... }:
{
imports = [
./global.nix
./home.nix
./iot.nix
./www-repo.nix
];
}

View File

@ -33,11 +33,6 @@ in
services.caddy = { services.caddy = {
enable = true; enable = true;
package = pkgs.unstable.caddy;
globalConfig = ''
email acme@hillion.co.uk
'';
virtualHosts = { virtualHosts = {
"hillion.co.uk".extraConfig = '' "hillion.co.uk".extraConfig = ''

View File

@ -1,27 +0,0 @@
{ pkgs, lib, config, ... }:
let
cfg = config.custom.www.home;
locations = config.custom.locations.locations;
in
{
options.custom.www.home = {
enable = lib.mkEnableOption "home";
};
config = lib.mkIf cfg.enable {
services.caddy = {
enable = true;
virtualHosts = {
"homeassistant.home.hillion.co.uk".extraConfig = ''
bind 10.64.50.25
tls {
ca https://ca.ts.hillion.co.uk:8443/acme/acme/directory
}
reverse_proxy http://${locations.services.homeassistant}:8123
'';
};
};
};
}

View File

@ -1,32 +0,0 @@
{ pkgs, lib, config, ... }:
let
cfg = config.custom.www.iot;
locations = config.custom.locations.locations;
in
{
options.custom.www.iot = {
enable = lib.mkEnableOption "iot";
};
config = lib.mkIf cfg.enable {
services.caddy = {
enable = true;
package = pkgs.unstable.caddy;
virtualHosts = {
"homeassistant.iot.hillion.co.uk".extraConfig = ''
bind 10.239.19.5
tls {
ca https://ca.ts.hillion.co.uk:8443/acme/acme/directory
}
@blocked not remote_ip 10.239.19.4
respond @blocked "<h1>Access Denied</h1>" 403
reverse_proxy http://${locations.services.homeassistant}:8123
'';
};
};
};
}

View File

@ -57,7 +57,7 @@ in
${pkgs.git}/bin/git clone ${cfg.remote} ${cfg.location} ${pkgs.git}/bin/git clone ${cfg.remote} ${cfg.location}
else else
cd ${cfg.location} cd ${cfg.location}
${pkgs.git}/bin/git remote set-url origin ${cfg.remote} ${pkgs.git} remote set-url origin ${cfg.remote}
${pkgs.git}/bin/git fetch ${pkgs.git}/bin/git fetch
${pkgs.git}/bin/git reset --hard origin/${cfg.branch} ${pkgs.git}/bin/git reset --hard origin/${cfg.branch}
fi fi

View File

@ -1,15 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p restic rsync
set -e
HOST="restic.ts.hillion.co.uk"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
cd "$DIR"
rsync -ar --no-perms --delete-after --rsync-path='sudo -u restic rsync' --progress $HOST:/practical-defiant-coffee/backups/restic/128G/ restic/128G
echo 'checking 128G'
restic -r restic/128G check --read-data-subset=25%
touch last_synced

View File

@ -2,12 +2,12 @@
#!nix-shell -i bash -p restic rsync #!nix-shell -i bash -p restic rsync
set -e set -e
HOST="restic.ts.hillion.co.uk" HOST="tywin.storage.ts.hillion.co.uk"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
cd "$DIR" cd "$DIR"
rsync -ar --no-perms --delete-after --rsync-path='sudo -u restic rsync' --progress $HOST:/practical-defiant-coffee/backups/restic/ restic rsync -ar --no-perms --delete-after --rsync-path='sudo -u restic rsync' --progress $HOST:/data/backups/restic/ restic
echo 'checking 128G' echo 'checking 128G'
restic -r restic/128G check --read-data restic -r restic/128G check --read-data
@ -15,3 +15,4 @@ echo 'checking 1.6T'
restic -r restic/1.6T check --read-data restic -r restic/1.6T check --read-data
touch last_synced touch last_synced

Binary file not shown.

Binary file not shown.

View File

@ -1,31 +1,23 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-rsa JSzstA
AiswwF+XOeVnSZ7QbCIG+4D+o5JxVYlw6d4R1GDj3orsEGPy8a83QtjiUiNDUwFO
/3GD3I6Hv5/H16s5kLVjxachAKKequNMtZ3R9y8pJaCa3i2Ypf0itlryoPT5MywA
vlgLzPHmc/eYdyOGWJ+Lfe5ZYq8cGSyWn7E2g5KzWxj3+Pn4onNwTCQBClPtebrw
E3mvTywpIvWQ5QyrJHIkFQERoKO1kprL9G5ikvgvGqC87SLPsOhvCX/5a83znKPo
8HMEUDIUbcyjaTusdXpXdRtFEtjDoXR2lDsbJB73LG7u9mBFwJNDPeI5ulWL/7kl
whb9xs87Z6JaEJFZOB1jwfsIUGQKVSoHAWNWfM6WT9tNkYfh+mulQOuE99rEwGVn
+/Mo5nYMfmb0hUeQEEVAdfko4w4NvWvUIq0keZ4M9IjfggOdDPM7wG41xKcqXJkz
d92e4Qj7fl8ldMcha7EJkXKTuP48zBeEmnWwMRY0UAbnHsIb0ko03Wi5fO8tKiHj
sl/asjk074jextEkhlzGQrDtJm2rK9GXuZVvtuIy+wKRWNs0sS7NqArlZj5jlUbB
sPYf5JeWBC3pEcdN73T+O4CIssOT5k7D7k8P2h8zw5Se2iMAjB50sFnCOe6Iiyfq
RHL/686aDDCJVqQ2tk0N25oT4h1Xk7dJZSNFaFh47zs
-> ssh-rsa GxPFJQ -> ssh-rsa GxPFJQ
in/cSQ8GJaS5GpEdJFXBC8no9M3BRcB+F98R1Xm+MSlyS153MVuNcGUAfEQ9RbOd F1+/Im3cdSzHDBn2W5LAV+ezO23nrjzaeVLQ0pFNYMt6v8XTA/WHHTPsImg/Nebi
8nKFnJ0ZjvgWnE342cJPnOZJ9yrMi7pcRy8RXslMIIBXLnt5Tv32kJJSdWYfOyHc noLNcxgjPu3fSnubXJuhsL5kQ6qHWvjQlQ0cRVSnMvV4UvrrPyp0066q1iMBL3PA
aT3ZYQN3j+rqokLb2Axe95pWCXKj/wUyoBCYgC5evb8/ek6XRVA647bnET5DsD0J rh4hQ7sF4sHz3pm9jtxfdnWamGxqsowE793AjtNEvSU/i9/ZkFrKRj0LLAhHeIHJ
HCTXanw3Nm6l6Uy/AJ87FM3tBaIzA/EIktZiS1ujY7yKOU5R0VPvmwZEFC8Y4dSE dWdYpnlZIrRjXFo6y+jdYpK0gyGQopy4SwoRwvDmQ/5paBRhpiXYUPtwRckiz/KE
k3FbG6aUcz9JP+BSA2bO3p3z89fyun7MFgPZt0xW7EVN+YQaamqdQOFtXZZAdDzq iHA0WJhDO9a5OHLN9WPnKVRIutH/YHviy4twyPDjhHCDeJBQE02Lykd6wvJg9cWT
jDVgoCbFm/g8bJzvFAFq+w BkCeYhVdGp7VpWZEbLCtnw
-> ssh-rsa K9mW1w -> ssh-rsa K9mW1w
sSMw9YdkrWxDctoj4jEEd7d3Pzaar13X/AlYmaUjl4JFG5en372xl1TUvqX8GN0k Pm7esUbyDOoLdzxxrRkOXYxodhfKdK+X41nAT2AOR0bBcNHqGt8BSvL+HOK1vbOW
ZwtLyUdSZCubpu+2Hd17hMK06KYz0jyV8qobsepgifgEvsFCeGq356pd6wDWaoog AquzA7+S91aNF7noV3JPIDrWZxDquqBp4z89YYyWNjpH9EIOYa2Sbp5xNFdgyAJw
hARFKOgHgHV6ElHlwkeWjIeFkz5BunTUn3NTZGlbDFnhKnEw1dexy98ZRmrZ7vlO C0uS3B/XKJcQi2np39szNzuR2h7uTKkKW5wMan+YUK1ODxmTJVibo0c0JUybMjXA
6+55q81hL1eRsBuenq8/hF+5zsnJK6pNnfL34NlPU8uQ5EmHZoDxpsk0AhJAOijK VS31BrkDb0LKRgvp/kNfn9aEaI7d78oca+6X0BDHk2zYRPwL1Q/MGw4tkx3pqI+x
Jh18WlnsHdLganJpa7vx8fn/rPUJq+M5ieNCu+BFvta08UA7vmlW/OYkaFIn4weS i6frCSHlo715tHaYvxRQyimWthmUft/1etMasFINhLidx4ufdawLR6sbR09sCrMj
OfzizypwKK4Y1HV+PMdtKg 5NMeB1wc1XrGxwMumNDWyg
-> ssh-ed25519 RR/L5A iVk2PxSSxsqJ6TKq2kXOATgdBf3WXVikjuXTonkXnwQ -> ssh-ed25519 nWv9MA CxCjLfbIfEn1voAr3jX+dRGnHmdAyylNuPn/2QfuphM
cbeSnGk8CAwz20mJUa2tkaJMNCbcU2tvzH+aRdJ1aPE PS2cpu13uyPlo9PJIT+dybq4P2juNpiZY61sJq7DepQ
--- CaEXrA9MPkvFWguILIVe2FhmFbgeHMNTHXgvDBf3Hbk -> )ei-grease ,jk Bw
Baüm'm™£ÏAOðOU!ýzÊ(ÿü#Ô°¾ÿ_?!g÷q" ù§žŽZƒ<5A>è|æ·šî÷aOó|HªüÐûSq&ÆÆn+w<>$áZ^ù Gg|à(HR,<06>àm1VÁÈÄû<C384>3]ÁE~püÃ/¥e÷² IucfaHwBWhzdMcTDXxOUyTy1kCUnSlsfAwVw8YKimsxHyvJS+wkyPXUzepHMZYId
SvebFA
--- q53LwYLjQ6p0yHStpDma4DYMpfFTpv7+MAzaHjM7Kaw
¹§—?0šîÕº9S>íƒÊìhàÛ(Æ Qå>8;þÓz°Øø¿L‰úPYhJÞsÛ@¥dÕÒœC׌<C397>9Ú¿{r|­±t¶¡aNv3'o•
ôÖ±¹d= í¦àZ<C3A0>`T62(€÷$ÓH°ŸZ:œQhµú<C2B5>

View File

@ -1,31 +0,0 @@
age-encryption.org/v1
-> ssh-rsa JSzstA
UxtA9OeecK4nVLsDq1BVy1NnWzf4ITfGqQdd31u1iTDhKhPmg8bvu4TuiVn+hD7/
B2Ar0GOHXH/JB882Q8o2D2DlkVYfwkGmtSxnw/p/um05+l59JGi6zAkw3uSAGrMF
rdte3EdlRrxCImxJVp6AvXEH3kXjT1BtDVBwARpLBGAONc++rwDIFeP56ras4hIa
H2JReFBethNMMZCOa0jH1nUDoRVohdt2wD2KO4LuOxTK0qkRxky4Pwt/+MP26X4j
Uo2FRLrgBb4DlqeNz9EQEnJeRS1Pz6GbzfqZi7f1LUoa5ifKuBobPe2sDBDvE0RR
jFAHZp1Nir/FXEkfjPw2uOfdCUZRLQ2OQ5JLlb0BKo5hV202eGCTY3Fhf34JYkE2
n++1I5oX2dX1qY9KDpj+LMASKWHtC7ayei9Mcr4Ee7m/dGq9y7Ipjw5aliFJd74n
23idt0MgZbM6GPcqig/Mbz1EQTGwu99HN5wAp8jxusjAkMfmmqosLtkUii4hvKCa
7YnbOJT/6AofZucuylfrJpD3uzkEyaKVlNeZUU82ROSKZK6VdILLB8WfWAMPAsH9
bLXHtcUo3nF/eQ4P8DZhJM/8tUdg0at4LW4Rb/wQX72xMB2l0F6sqS741f5jjqN3
gL0tSpYQXtB3ni1mBbj2jKq8+UUP6NpDwOU5p5pfK+I
-> ssh-rsa GxPFJQ
cNBRc51b5Pw2KQq+EHQ4tCGSQQu+JMZHpJjoSAPx5sLd1DgGhE1x1F9h9CuSRFZh
J6fh5xtr9l0rzae/IgSQgfaaq4KVgIC/TIiyLX1VN1MSgbrisMAFA1fu0N/mTJGJ
XEiZI3RebiBxnfS3yJpBAdsFvZDw6o0xD2d1rSzN2dKFKNr9XGPNX1wUqERnWVQF
B5fRpNiWygGPdBaXYDc5OC49vlCAkldaU2EvA1wEuesdTDDn9nisqAlgBBYXEDWq
EBGgiITNyz+wI7ncSVW6JWr5TFfDNEtqGo1JS8nYnpVNHTgU4PbTpqq5fvlAy+hI
gyIR51YZaJZNQhrQ/N4KYw
-> ssh-rsa K9mW1w
c9vvvWH+MrbfNifQYOsfhiw1Ie6npjBVCMrx8YZJwtVmRy3RYjXYn6zcFH+xzSGr
tC0WPwyQ1dqgUNTUdvxaGrSayo5WF2CNosjc66eMrqyG72pcpJwAqlNbWbDNHbm9
nE3c6XBv0WnEq7G+nkRx0luD96twkor4LVzDa37MUtljNqJo1Puv2AcEylEqXCUX
bKN78TlUOhCpec93ZIxQoE71+26qqpGNnwyTQkHII/RzMKZGQjtmdRtQiUPzVmxT
/3WjnQm4vbeKjOeBjjIdV1Wc7dykBRE7rq/Oe8AGl/7FAnbe6c2Bav50OOL5/Tbo
Fe5TZbOwFDc1ob3IezRI5Q
-> ssh-ed25519 RR/L5A Mvv5Y3bd2IqR1cffLQbJ3WuJCoGMpJaqf/TvV0kcYQs
jRBAHCUuW6hBsuv0VjR+uSKmmqK5rsU4vUIuNHQyAiE
--- /Xx07JneqPgZUC0LrtSMMHAt9eSoB0KUHxQ+j8mkr6c
).<2E><><EFBFBD>*<2A><><EFBFBD>?$M<15><>e1<65><31>"v84<38><34><EFBFBD><EFBFBD><EFBFBD> <<3C>ގJ+<2B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۃ<EFBFBD>Q<EFBFBD>"ӵz<D3B5>"<22><>ǠB,<2C><><EFBFBD><EFBFBD><01><>^k<><6B>I<EFBFBD>,<2C>B

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,31 +1,19 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-rsa JSzstA
uM89I2iF5jhpx3ndhtroIDxXWMSZew8mSLLBiSisYM+CfjtGKOVCDvmOFNSgPz1g
96D93T9esUo+KSwWyhhEqUwEHyrdnHVPkTAQ73ie/ZoSvdCPmdSA0RgKbyYHSTp1
Z1hS/SN0xLSshz8aur/dd6FC01Ju0dqjDgCMN6edNhJfMhZXc2xidcj7Ir2T77B9
kFnLqAADHL8yyHfQzU7EIzWp857mcn4sbtPV5CuMfSvOzAdQWMxtFQndJUTnokTz
e3Gg57gkNOa50jYbr0fxN7fUBWu7J/MyOErwbRq5TzF/ZfbHkrH5iXvMBaNjSQy1
RVQozDXJ+j5oc14TQDbi59kOi4ZJmXJTk+eCFMTalYrHqdtTqV9c7KsOdiceeajp
wec3Iowgben4uqEgBluJtn5lRoDSdmKWbYSYxL3E/wX+0df8P9aZpTTEGGfhH+RY
yxhalaRYmLHD8kJ8yBlPdcKx9y6hkkE5Me+IB9Soh4pqtTbk3k/7pHLRYD2sq1T2
gxipaSumoj5trfPnp75qOTubnJ+a3l5FPiv3JOe0nOxY8zFuv7IcOsvcVipo1z+X
miuOVgbZeZrKb7//zVb0Dn1IJSZITY0SsWbNh8MVB7N5xN9iGWAmE9adrnbCKFIZ
PWteIw7/tlZHdUEr0QJwim1Br639Ah41mMspltsKA2c
-> ssh-rsa GxPFJQ -> ssh-rsa GxPFJQ
sGxzilQ4r6X/D1MXKuXVI4p8v6KGnqN+4WUqda8OknlK79PTQY58fL/Mtmep+syZ bIDYJMyhT4Tt0oTNWGwahKnw7ewWky+O8J7ExiDqIRNskA99SJ45u4n03mc6uQl0
D11IuciWOSbaH21ZH3fuUNuNz0CRq+JWgkLnI0HwcnXH/Ni2MvXTiX9ihHzLawDE 56gTQ53HEQIH7u4DfITmKTf5iSn6O7QDW0c15dJ7P1hz3JaPu4p/Lyuzy9B1RcUY
ApkC+UbpUcZ5qsOQp2Kh0hbtLj+vegsQeIiMej4g13Z0QS6P7ElX5lYkdv/TBjXS XjNhmRyIAJdUWla/+k+o/dLRp46CtK3nIoxLd8all7vPys8i2gBQIr4HmmkZ4Nd1
b1AwwmSuhl/IPzfnvMqnwpa/QeyweC7aSPuuy4WQQwjJa7pAPvuyZl7Bi2KfSa/c CFQCXbb58asmAcYta1nTTY5yvFq6IHDbWPZDGOYCWceFoPCjlkvVH4VJjTQ7uyLX
p3SJsGNMJxeNUrD0FC/k/Jn0qm1B0Hf7qHi1/0ax58j1uNQCfqv6/YG0uC+SGHjY bopz3gKxUogk0RTuF0o8tfqeZzJhcXOB0tvMfpPmMnQh08u8t4j8kVlnv+Ru5ZsE
LcFKAvBPn3HvH672Ed6ytQ H95rbwVArprojzFBy1fcHQ
-> ssh-rsa K9mW1w -> ssh-rsa K9mW1w
FmNlXwGIN5E/7btwU2TBzyEJq99RNWLE8+P1VSqXI3ZRvbq4sGMW8wpEYSlkYrLk s/y+2ROtxC5AY/1KxqAYuFUJgV4QtrnhOwi+fF+61TKet/8ni1oEjvAiUwg40b9h
A9wsYA3x0U7oEt6pnJzuZkyVrc08k/7Jr8Oboscti7wPjbNyMCsPNHJU0CvpuVfh eNPGr/ohywXgAj77j8y/J3uWA6uXt1zhpoadZFw63Gdy236AAK6mqU+pf6tEFGYf
lRVyy8Ir793jNkqvtWpJS203YyPyV9WwYzH8Q6QlKVs8VLi8KLv4truVbM4MfBQd ZiD25Z+rhorfYsMS6CkWEVIrM8dgMAGri1pdhXTuoC7LYn9f7GRmcyujbwRUOT9Q
BiGYakuK+ckkoS3GBaSm8NNDV1+Ocf3M9RFJnqke7dQIS5tRyY2HCYzqZXbzDtSl DXmdb6V1j5Q5I6f6TYljGdhp6I8KrAnHMBEcZBECfgTnHE3Hot51p/aoS1KeNcsb
9CRaHnu/H46O3R9Fqq3314Uj94HoUe0SuayXBD7WCzkn9ZevsHZPhk9BHulHaRBT Y9gjpQgNIcccx3CANNJ8y8iZpPzd6Qp5eFk0/IrqqMlGfYrVJ6hX37mV1pqPp4Z+
ExOUcA6hCIDopz+xqErcRQ KTuVZ47PIByw6yabdJdmsg
-> ssh-ed25519 iWiFbA lsC4GR0vzRjpq20voTzHrzRuoU/aamdM3sIIHYpUQWc -> ssh-ed25519 iWiFbA SMZ9gRd/HVCXD7q7W+D5ooyS+k3Nr/hoU2bbwmv/3mI
KA5kjHA1lxdKM6Y2yK0rvtlUaB8EI8q5jMZPs/VywCg AZEH5d3rS9B27j52SYNt7wy2IanpmrYJor5OjZAzaVI
--- q/m5+KxRTtf5vgXnAXd8HLGCCE9BfsDs/uJuGSGbw/Y --- xWHau8xcErvYJZNB/HkjjfzWWvLrOqdI4ccGSmg/xjo
€@âºv<Y&4•[ýæð![U•<55>oÂ8³Œ`.Mt¤ÝSg¹.S5Tñg²˜»¼cp:g$¥f{eânñAdt¦Þò‰R@lŒ? Ý׍vÄď˝J/XçM<C3A7>Mkě@Î9ämÎ"vĹ «äĆŻî—ÉŤç¨ H÷ń-×<>cŽuĹ…€Z†3nv\°ĘMĽ5đXşQ6

View File

@ -1,31 +1,19 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-rsa JSzstA
HWrOsyGtCBR++xduIQUiaVMo8UplDwkbb6WnO6zOLdDD+ZRjje0X+jKbvpSD/k8m
d9p/0AnneewAPmP3xToEk9hRjhGwUcrYURH3ed7/1a+ef7wIGfeNfJfAe5muAUWE
OLNxu9s6OIRUK5f6EtHKto5IEhr/GoGWCCCxDJheXQ5e4DLzhrH3FxfWDXz7PqiH
trXWMploZArJ2f1RGr0wOJIhtHLcv5PxXpHz4ASx1m6pL+q3OdmIV7J+JQaDKVWE
LDa4tQnwcvFodB+g9U8a/KetsCyCdlQnpDqjVAYelMDz+IaMqz8htO/nTL8uS9bg
2AHdB7c1NiPzbI1M4G563jQ7q7n5eQB+nFSTiyXYfvz3tz47GlDvO3DiVtoRnfiY
Yp+K02/emsa6wcBVEPcLlWqACp3+DwL48BVll5XfPadXeR2jsv4JFuDfBSzhr7P8
Xb+PfXbcK3fbXykMrVlfuMfNgnnyFoyTSXqVByolU9lu+FHewgVkyFOhpOse/5eo
azm2Bg7DICsXiSXhlJj1iQmacjxdav771qqs71W68Vu3BgImKrRdgKJ1/DY/yZs+
UhyGN316EcMen+DhV1ZSD7FfO6A/HFB/GwoOgth+HAFCmL8XrDwWeSYHIqHmK9LI
z8rfksUGQPV1p1SL3UGBZZYO86ufXY9h0vdrKTUxGh0
-> ssh-rsa GxPFJQ -> ssh-rsa GxPFJQ
AaJUbzqcQ1JuhUECy6HAlijuUFCldS7YuLYnm6iv31IFK3W5X4k38CO5lHQGnzvy EpPN7UHHRuytMr2vXy9CHzjVkH1iCt9LiTLhFsqXbL03Rk+X82q233Lm12f0sQvz
GJKEhqETzgNk05MKu5kVWqPC/DwwO99JCmy6v3G88cTi1ekAox7OIwmeqnyT0NQX Hqjukkh9bU90TLKcEOFpKrU5FQwKUjzEy85A+4UoovWdJ8VwACOzoJf29Ys1bX3i
Un8eiBECIT3WXfHUZ263n0b96s8YW/MDVlBi+EKjhj701qsjpl2b1aFiPUfETGZd Xp4gUT7ne5+4afNwKXVFDS1YCPjIoQPu2cGw6iTNIYwVY5fNxz5y5ZHLkI9lOqJD
eyE0pi68mI3Mnp/WX6hR9DODAysJE0nubU/d50A+HtOSCNrrjguDuoEMhNgAPEjP mT7jCgLLdkK8vJiDcu4Ofr21GaziQh93YXK69i3gyAt6pqSRyQdAfhMGkykOWdrO
UzTMQ/+lrKJfIYRf+zvXnFbeUvQZu4Aswo+ghgwnNRYoYiEvbQyK+dhqQunHO6tI FXMtpzT82UCvfbFbbRCRuSFga0uq5zx2cwvBD4Xagw8Dfg9RQO0rX9NAbbgcoyfG
e+A5GMBycd4IRz0AvCeEaA qnk+0bYAk3pWfdXW9Z/psQ
-> ssh-rsa K9mW1w -> ssh-rsa K9mW1w
e/qVub+2c0GRMuVkaGwyQ1I7GodKg0njuLCLhgWcGfqvov2aqbBy5QuTEIwPm/CM NaR245c+88dGflT9cG73bQOBxQsVi5x8JkMTrqjabzwzHpRiBUdtP+Ou1w+klOI4
Wp+LcPU+m0wyw/oAtiANeb1TNXRwX/k2oSbbbhN6912Sf/7QRJukgSWaT/l/TDYz cv1RLngEZH9jsSiEdvpvRkzE2ILOR/abgABXZi/4vl7iXiC8T23QSOPXnMxrAgpH
H9RW4EJ3ir2aGS+/rZRchhrbTgMdluH132Pkg9hy0Wybj+PnqUFf2RXk3bC6CfMB RV9B3GcSClb70+Lf3pJtPBVHVENhFVFvj5JgxQ2Zi6eMpcMuL18r/Szn4erk8zXQ
uM1S6LdFPE09ublSk80U6M8Ihu8j2MSIQ+LSfHJJY3aoRZSr1DWz991+0WyC9fOQ 330oEau80X6WoPtRaSqSxVRrMGecGHdIE9chLosCf1x8CgIcYBTtviky+fDQMkKZ
U885VoYh8tmw7rs0aw8gHLZ23Rx/Kf8S/ZQIM9ZVQnQrCEsGCmPXOZLbPM0hawXh iwueW1luuBj1AuP33jUqjeyyMaJ6SqSmaxGqGHGXA/ayxF8HnHU9AJlhPH+tEEbs
gQUICXoa4AXslSdBn+FG4g 84Xu2vwg9ikUz7B1tTBYeA
-> ssh-ed25519 iWiFbA 0xrDzh2/OoYkwZck8r6VYNBsITWDuDBe+8AYYxvCiTM -> ssh-ed25519 iWiFbA CuUeGNUBc5K+AkXBRvp7SUTJNoMDW0bWRnYs3ZhFSGM
jSlH57h8pxoeyTbUQQUoTTK0KwTvvg2LUggAJ8xUL9s UwwyxNA2L9q6yYK+BqYcqOq6F5CF+iCUpuceWsEj7ck
--- QGRYDjRpaQ369Yej6tuziZ/TJOjjDc7FGX9LRNuHYLU --- 3XKIweSg0UFqbadbOP0APwaLyquaEdoanlvndvxcQkk
~”Ubp§ÜƒÖ³Š"0·2çw´“KdŠ†K.÷Ïmк Þ¾4š¥NbÊôºÅŒGßçnb+AD-cDÙùÛ¡Ž?8fbãö“GÚ© <0C> ß‰<C39F>& ßüu _śnTx#H-7<>‰yó—Îç<>¨—B„ô»uµŐÉîj<C3AE>ZHĐ'&÷_đś#ľĽ3ŕHÍ˝0f  šBęą×Ö™ýčÂLĽîz

Binary file not shown.

View File

@ -1,29 +1,18 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-rsa JSzstA
BZKLDxLAZZ/1TfFlNANKnS0NEzsrS45xVuppc21R8wx9OwzTGZIPJcEigYjbWCE1
XCvkvpw6oTk0RNXx6VdAdZ0dfvfOcU3PfR30/IeiEZyKioyO3gSPp1L2z4Qacz88
MZDsdFMKhivexSRcNl89Xa1LEDf30XYaLKMxhcgZ1b5Z8TEG5trIs2NKek0eHY5k
jBgfvAoKqILVeot8cRANoIhC7aVI6lvVxNVhKzshv/ZAADUN7AZgYyvD09i2qFRX
AP1Y8ld5Csi9pp1KQHn1qzu2ofGjkERUHDipfV7oL3C9s1/sJP2u1oBthqYhPi2R
YUv7k9c8jILWzYw0ryO5bvQJkUWW+SS4WuQAZA127+aq4XECAUiNS4R/aNKwzDK9
8N1k5vkzJLXdcmP8jL3D+03O7igV//CbxzbyLzJXP2dAQI85VW4oxsFiPBHLYqoo
Nq79K6iZll7FUvyPxiFEzll7N6wzM2nPIrDSJeeDxbfZiZzAW0FN7bWl4qS/olp6
sA62SyRPtLd1WugaULIeCa1hopJGUJM4kQpnXPu8uUIOpnHUbc+iGXMWqxTqmyZD
bH7oNIAtTQKXzZiO7M30rt85x1eiADZqWirH26yYufxg6KndUKe+SAsBZUAkoziO
0Lotv232mcwbyWrc3/+sk0rtEP8GYRlCFhP72EQW9dA
-> ssh-rsa GxPFJQ -> ssh-rsa GxPFJQ
EBc6e5bYK8E+adyWM+l4nKIHbun1S2nTh8sLJiZYd9EYdKG/2S/+Pe7vREB5I3Ab kYf/CWnC4WoFnELMnW4b3k1df6r1sZn7JeLPqIvQ7haKwA0SUrbMGiyWui9ewn6s
5femntN0JeCTwzjjlbBZKyULAN85sSm0pGibT/RUneOBzmENp1hQSbvGTNK0a/l1 VSZb7T7zCPFAgs546wiq9O3JzeQPtWdTFCA5F/U48ftbZsAL1YjINqm3ySUbg0O0
ELRxmlDvziU5DO0WK574lXdTdXTkk8SGCpvNBtwnTov3TqlcO36BoCE5Apw62b1g eh8wZnO4ludFG0bi0/7B6eDmDpfqn/TKLjDJkWiintYg1PMLMR0iDaF8D5oy0zCi
7l5/P9hMnIQovAHorh96kqj/unSCTc4Y0ZsNX9IqUqWLLxYNJovUEORFUnPTSvWh Yiz+sAWyYBVvUSD9PEdCPFu/q8ySj9upBxaObf/Z5pDC94I2Ex7NZm8lGoXyMmnk
Lbxp7wVXRxccY2bnr2BzmCObzujH7o4K1x/7zxVjxXc4TqGsPT/pzemZ6vzY0LPA vrhVuHc8eRcqqN+ID48JakdPopA/X7IvFIIJVh40yw4Qldzr7H+b7M98Wg0/UEiC
FCCV6Mk41j0O6ez0OyerHw mZldTPzpKznZntXXx6O89Q
-> ssh-rsa K9mW1w -> ssh-rsa K9mW1w
FHEQuY/JPZLSrSuHj8HTc+jNrxidPpM6qKAkZTl/0vYgWExdJtGi/IukNibjF47q M89fPs6WcToz9Jr2YXrRGM26lHU/8Xk72OExtArEsqKpHcRw27EeOQpcXkQ1baro
176i56gjkJZPts8FRgBFXUimBGUBiMCvEOV/Xc/ZK/Foz7JQuTpiNmxhPyVSrGhW 0MFQTKRsMc2PV0S85BPlUIBrvIiTTHNr/eusKTpAlDwnwllGk26xdaqPO3SYXzMX
GgyXqLycs2KxWbIz7fPLghGXXEeq86z0yTKiQOx5IkkwZOdvUDmzpHrqnCNi4uG5 /zo65i6837vQZr1aRPg1LFzRMWfrj7tLGQPuuE9F68Q/BYaCBbEo8t1vVVVNibjt
LfgzbAcZxhZEKEfOsqq46Gzww96uLmcLypnppUFfelioceMcMnzyXbwXYMDODoL4 1rGuaMnjJd7scHkJ+wEJURQQuwrIY4oH8obmrzjQrFbBiWPH/lIUH1OUv5SDbYul
c7rXqWqHA9Bu7P8uiPFeiGXuISQGsRUJVbK2GsT7lr6+WfSdTxJcOG/63nKWStbg /Oq0QEHws/o68EQxOKWrPWRu9P1A3xYu3I19YYZgrKr1G9c0+ZEtZsvfeqCE9w79
VkHYEs6vACX4gHb9BHvpLA OOz3GtRRHRCLBDDzv8nfrA
--- nPAuzxbz5u9828pB+pGjc8p63zEYMSyHjHdZZepEs1g --- e0EGzCgM5FbTE91OLwUaICK+yruDi8EAIBMGxFJXWLE
¢(dsÜç´WæâÆó3þo&<26>$÷îùIuÜßBF `PìíØHº¬}d4(H<>@&`kô«'öh«Õzqªâ2Š´[?0Ìt„<74>¾æU½ÊÈ ªœ£®AòÂÙî{3·…óÚûí€ñ=Õ89ð9<C3B0>es<65>Gïj
!”Áü;ætr0¼î&Øgd;ü‚¢&Ã¥Í1£^§ 'ø6û<36>Wh^qœ

View File

@ -1,31 +1,19 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-rsa JSzstA
YmBjkjwn3FjgeFaxQ9G5h3ex2ZGe1TStge4BZsHOPizJnaU0aGmN/e2hjgRRWBgc
Js+SrukIFZjrQ/z9qgEQhhktBkpn/y34a9jSeqYA7IUjBEb3puWFqREbkEtC91Wa
DGlJFnGQiFCZ5Z6cIj+CkylQme2UeFD8Mbzrnhslh3w3Y3M6oA0zbBmwsJZ3WtQv
1QUjkPoVEd7t5RDcvm7au+ezUFUm06TsVz77vYkm9P82/fq+u684kwsPTJY0AL6x
RXtAjN8y324nrwij/x1EHl1J9h4hYL8QT8S/9hnVQ5YuANAO3W39wRPedOyESIXt
MXssIp7mMdDzaWBBKsfGkV0SinN9LQ1m9lTEFthmhX76lrLUvlVCKIHMfZWUWf3i
fXf3AREcLCVcEqeWJw4Js8Phet7MsnWReDV/jrTFSISP7BJj5oSLtuLCRwa/imGk
rcZaCG14oo4Tnf4VJDV5UdjJQMo67/rROezv6wDKUW/NkNOKtN+fcErCLjiu2tGV
M9oe/G4sE6gCthy00BpeAJTiK8XDObnGAokBddS/SbhHyh3kZ6Zu49HWMBVW5dOV
RWmvKy++8nDft6oRVITOdxHoyurRUqSzN0p9K7HS6GDP78ThlDT9nigR1HAB1BMD
Ouh1N8tXdP4Ap5osPaOzcN5UWkdnFOPJ8+Fma8gQLZ4
-> ssh-rsa GxPFJQ -> ssh-rsa GxPFJQ
E9g838j5piMvfHhBSdMC5wDSkncDCP1GP2a5hVEL34Krn4+mWE9yRoYGTdcz5AK/ oP+PAtaEFPKwY/p94ofdBlLtCJDzaOkE7jblE4COKCp6NcfjUot7a7G2rSzG3Z9A
heVfg8h+NteAUYLcBw8B3TSxKKt1BBiQj3gGwX/mrMmOmOZD508JEQAVb6Bmvi5u cF3HcuKsMrG2Tth4ElBB0nwfaXUJZOBO3nrZaU0RGBBkxqooDVV2LzA+NG0HpIZ6
3DgxN9gci7iUF6BpaHcHi3U4Sl6bJK2oH6QmRFd/oM3c0f+0vDsTM1f0Yyt+Gab4 8Rd/Ch621gaBDYbSNFKLx5pAotqsARt13BMVY9nuifNGmWAamZ5UsJwZ/OhxKC5i
/DiGdSmvvTO9tq4sEd5Y1Y96HSBmRoCQU9VWv48/yx2HCiDioZH7vdgOdOkBWDX9 bkFZGeHZm4tilpsBEnh99PxofQmFy52AQhpx2UZETaD7yXvyEQjN9yBVKGhwA8Xs
Ba1Qa0pev2PJFiCujCLLvb+6YWzlBlUKc6Awv7tEicExFUXbfiKVGxZmI50xY0Wl xIRZLVgCbMv5lroYChpj/SiuoNhuaLo+05+3r5JnL/ODEl2dYZHkr2fAo31QUPnr
KXRzoyUmAodsdp/HkwaoEA kmir2Nwoq4MlNELjQvSfdQ
-> ssh-rsa K9mW1w -> ssh-rsa K9mW1w
GLZFcv1WXomvnn05f2db9MIAmDQXbD1dCpcNJNFK3Ax/efvgZxHNrppHZXDYwWn3 GVNgJY5cse7GnU0UpgfBT2a8Ev0KeFC+Tfvj8Jd7Wgu7pYv/DlwIumJN2NcmU76S
EkNDZVd9iMb+YZ8Zqa58TtTOhiNH8yTsZeq6jF3bM8Lc2ZoS+v/DqOA/pNALcS3b zW1Z6we+Fs4DO83v+4Bug4d+m7oUbKxbUfgIDE4MDEkc4B/XUKv0Ex1VaO4lGh6h
LlIkIH4cZ/4cvrVc32+uRFhByLR5vgKuf+F/p41zzFUeA50rCFUR9/gzCByrxSRT 0lRF4PO22OjyO4TT4tkLZgTAStq/vS20GhluEdVPp2ovSsn7KYLwmx81iBnfNDbm
zW6z+PbgNARqbburCp8Jh7yJo74Phki8pizgDrfvWH7hoSYxtf/hbo2DobRntsnn 0uEKAE2dj01BHSiRZ1rVj9OnTacrRpzp6mbVJxZqkUMJ+A/tMp1B7eTjWiGhUUGs
irlmXjXrXy3P41VoE+4PjbJpDBygAYy6uy0MwkSVXMc+y6i+txeMOw74amvOrF+f +de52Ba/ww1jM0BmbdemWS5SA1Kch1ttgnSFKIh24tYyRxX4AVsuYqPkIuH8+W4O
gCaexeMDPmyGm3N2j7qDFg Jh0387AJaR+3+Tvweo88Tw
-> ssh-ed25519 iWiFbA +U3hUeNDk/1M0AGubIlLJeJRiVG6yrLFeSxi5Q7rPBk -> ssh-ed25519 iWiFbA xx3oYrX6/Z1srbxmAztZV5AJgYZn20UMvRnn4qrSoAU
BVVyNpQ+BJOhl3/6gy96NXGGGA4nNHoUePDkIVj0xGU 98oe26dqhSE3eET7hwdV/jJTVu2ldBiZ6ysabwK97Co
--- 5udXYFRKZut6o3QTDjezohRg3uwaLSBo0IxC88yercs --- qrw4HhyaHrpDmws4EoABLFF3HU30AaZFCt4qHKo6gUM
`"íq·(9~úš‹:€S"ò±ê´1%ÉæNüÅ@â‹=†p„j?|Í_ñùeÈÊâdP)8`ÕEÀã¨FµAàæhÚÚJ<$ðò¢ÃtÌgüáP/z¶mÿHàu7Æja³|Ôsn÷Ð c ªz<àå5·¼> OnÄCfIÚìQÿlµç@‡?:5¸<09>Ö m*63ÿgtjÁÃïÖA8 ^;TÓx%;O»·»×ß׶YG¢€,mïÞÜ â¥ ®Éîs8Pƒ òR«\nòXA÷·w;—ÚXRMÛù2´òFÏ

Some files were not shown because too many files have changed in this diff Show More