Compare commits

..

2 Commits

Author SHA1 Message Date
Simon Bruder e3f09e9981
dreckiger commit 2021-01-19 19:32:50 +01:00
Simon Bruder d9fbbf1bc7
WIP: Add neomutt 2021-01-19 19:20:15 +01:00
195 changed files with 2290 additions and 10450 deletions

2
.envrc
View File

@ -1 +1 @@
use flake
use nix

2
.gitattributes vendored
View File

@ -1,6 +1,4 @@
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.svg filter=lfs diff=lfs merge=lfs -text
**/secrets/** filter=git-crypt diff=git-crypt
**/secrets.yaml diff=sops

View File

@ -1,48 +0,0 @@
keys:
- &simon 47E7559E037A35652DBBF8AA8D3C82F9F309F8EC
- &nunotaba 8C5091AEA213FB0642BD46F943EE19743FAC1D5C
- &sayuri 17FEEBB45E4245330507C960653378F10CA6E00A
- &vueko BB046D773F54739757553A053CB9B8EFD7FED749
- &fuuko 2372651C56E22972C2D9F3F569C8187C9C43754E
- &mayushii 23EEDF49AAF1B41DCD1CD10F44A37FA8C15053B3
- &yuzuru F4B5F6971A1FAEA1216FCE1C6745A652A31186DB
creation_rules:
- path_regex: machines/nunotaba/secrets\.yaml$
key_groups:
- pgp:
- *simon
- *nunotaba
- path_regex: machines/sayuri/secrets\.yaml$
key_groups:
- pgp:
- *simon
- *sayuri
- path_regex: machines/vueko/secrets\.yaml$
key_groups:
- pgp:
- *simon
- *vueko
- path_regex: machines/fuuko/secrets\.yaml$
key_groups:
- pgp:
- *simon
- *fuuko
- path_regex: machines/mayushii/secrets\.yaml$
key_groups:
- pgp:
- *simon
- *mayushii
- path_regex: machines/yuzuru/secrets\.yaml$
key_groups:
- pgp:
- *simon
- *yuzuru
- path_regex: secrets\.yaml$
key_groups:
- pgp:
- *simon
- *nunotaba
- *sayuri
- *vueko
- *fuuko
- *mayushii

133
README.md
View File

@ -1,45 +1,17 @@
# NixOS configuration
## Structure
* `machines`: Machine-specific configuration
+ `README.md`: Short overview of the hardware and usage of the machine
+ `configuration.nix`: Main configuration
+ `hardware-configuration.nix`: Hardware-specific configuration. It should
not depend on any modules or files from this repository, since it is used
for initial setup.
+ `services`: Non-trivial machine-specific configuration related to a
specific service the machine provides.
+ `secrets`: Nix expressions that include information that is not meant to
be visible to everyone (e.g. accounts, password hashes, private
information etc.) or secrets for services that dont provide any other
(easy) way of specifying them and whose secrets leaking does not pose a
huge threat
* `modules`: Custom modules. Many are activated by default, since I want them
on all systems.
* `pkgs`: My nixpkgs overlay
* `users/simon`: [home-manager](https://github.com/nix-community/home-manager)
configuration
Secrets are managed with [sops-nix](https://github.com/Mic92/sops-nix).
Machines can be deployed with `nix run .#deploy/hostname`, LUKS encrypted
systems can be unlocked over network with `nix run .#unlock/hostname`.
## How to install
This guide describes how to install this configuration with GPT and BIOS boot.
It is not a one-fits-all guide, but the base for what I use for interactive
systems. Servers and specialised systems may need a different setup (e.g. swap
with random luks passphrase and no LVM).
This guide describes how to install this configuration (or any NixOS
configuration) with GPT and legacy (BIOS) boot.
Set up wifi if no wired connection is available:
If you do not have a wired connection, first set up wifi
wpa_passphrase "SSID" "PSK" | wpa_supplicant -B -i wlp4s0 -c/dev/stdin
wpa_passphrase "SSID" "PSK" | sudo wpa_supplicant -B -i wlp4s0 -c/dev/stdin
Create the partition table (enter the indented lines in the repl):
Create the partition table (enter the indented lines in the repl).
parted /dev/sdX
sudo parted /dev/sdX
mktable GPT
mkpart primary 1MiB 2MiB
mkpart primary 2MiB 500MiB
@ -48,76 +20,69 @@ Create the partition table (enter the indented lines in the repl):
disk_toggle pmbr_boot
quit
On UEFI:
Format encrypted partition and open it
parted /dev/nvmeXnY
mktable GPT
mkpart ESP 1MiB 512MiB
mkpart root 512MiB 100%
set 1 esp on
quit
sudo cryptsetup luksFormat /dev/sdX3
sudo cryptsetup luksOpen /dev/sdX3 HOSTNAME-pv
Format encrypted partition and open it:
Create LVM (replace `8G` with desired swap size)
cryptsetup luksFormat --type luks2 /dev/sdX3
cryptsetup open --type luks2 /dev/sdX3 HOSTNAME-pv
Create LVM (replace `8G` with desired swap size):
pvcreate /dev/mapper/HOSTNAME-pv
vgcreate HOSTNAME-vg /dev/mapper/HOSTNAME-pv
lvcreate -L 8G -n swap HOSTNAME-vg
lvcreate -l '100%FREE' -n root HOSTNAME-vg
sudo pvcreate /dev/mapper/HOSTNAME-pv
sudo vgcreate HOSTNAME-vg /dev/mapper/HOSTNAME-pv
sudo lvcreate -L 8G -n swap HOSTNAME-vg
sudo lvcreate -l '100%FREE' -n root HOSTNAME-vg
**Hint**: If you have to reboot to the installation system later because
something went wrong and you need access to the LVM (but dont know LVM), do
the following after opening the luks partition: `vgchange -ay`.
the following after opening the luks partition: `sudo vgchange -ay`
Create filesystems:
Create filesystems
mkfs.ext2 /dev/sdX2
mkfs.btrfs -L root /dev/HOSTNAME-vg/root
mkswap -L swap /dev/HOSTNAME-vg/swap
sudo mkfs.ext2 /dev/sdX2
sudo mkfs.ext4 -L root /dev/HOSTNAME-vg/root
sudo mkswap -L swap /dev/HOSTNAME-vg/swap
On UEFI:
Mount the file systems and activate swap
mkfs.fat -F 32 -n boot /dev/nvmeXnYpZ
mkfs.btrfs -L root /dev/HOSTNAME-vg/root
mkswap -L swap /dev/HOSTNAME-vg/swap
sudo mount /dev/HOSTNAME-vg/root /mnt
sudo mkdir /mnt/boot
sudo mount /dev/sdX2 /mnt/boot
sudo swapon /dev/HOSTNAME-vg/swap
Mount the file systems and activate swap:
Create the configuration (see [below](#how-to-add-new-device)) and copy this
repository to your new home directory (e.g. `/mnt/home/simon/nixos`).
mount /dev/HOSTNAME-vg/root /mnt
mkdir /mnt/boot
mount /dev/sdX2 /mnt/boot
swapon /dev/HOSTNAME-vg/swap
Add a symlink as the global configuration
sudo mkdir -p /mnt/etc/nixos/
sudo ln -s ../../home/simon/nixos/machines/nunotaba/configuration.nix /mnt/etc/nixos/configuration.nix
Generate hardware configuration and copy hardware configuration to machine
configuration (skip this step if you already have a hardware-configuration for
this machine):
configuration
nixos-generate-config --root /mnt/
sudo nixos-generate-config --root /mnt/
sudo mv /mnt/etc/nixos/hardware-configuration.nix /mnt/home/simon/nixos/machines/nunotaba/hardware-configuration.nix
sudo ln -s ../../home/simon/nixos/machines/nunotaba/hardware-configuration.nix /mnt/etc/nixos/hardware-configuration.nix
Modify the hardware configuration as needed and add it to the machine
configuration in this repository. If necessary, create the machine
configuration first by basing it on an already existing configuration and
adding an entry to `machines/default.nix`. Then copy this repository to the
target machine and run (`--impure` is needed since `/mnt/nix/store` is not in
`/nix/store`):
Install NixOS
sudo nixos-install --no-root-passwd
nixos-install --impure --flake /path/to/repository#hostname
Enter the target as a container and set a user password
Add the krops sentinel file:
sudo cp /etc/resolv.conf /mnt/etc/ # see https://github.com/NixOS/nixpkgs/issues/39665
nixos-enter
passwd simon
^D # nixos-enter
sudo rm /mnt/etc/resolv.conf
reboot
mkdir -p /mnt/var/src
touch /mnt/var/src/.populate
## How to add new device
Reboot.
* Copy the config from the device that is similar to the new one
* Import profiles/modules you want
* Change settings in `configuration.nix`
* Change secrets
## License
Unless otherwise noted in the specific files or directories,
the files in this repository are licensed under the [MIT License](LICENSE).
This only applies to the nix expressions, not the built system or package closures.
Patches may also be licensed differently,
since they may be derivative works of the packages to which they apply.
[MIT License](LICENSE)

60
deploy.nix Normal file
View File

@ -0,0 +1,60 @@
let
sources = import ./nix/sources.nix;
krops = sources.krops;
lib = import "${krops}/lib";
kropsPkgs = import "${krops}/pkgs" { };
kropsDeploy =
{ hostname
, target ? null
, secrets ? true
, extraSources ? { }
}:
let
source = lib.evalSource [
{
nixpkgs.git = {
ref = sources.nixpkgs.rev;
url = https://github.com/NixOS/nixpkgs;
shallow = true;
};
config.file = {
path = toString ./.;
filters = [
{
type = "exclude";
pattern = ".git";
}
{
type = "exclude";
pattern = "*.qcow2";
}
];
};
nixos-config.symlink = "config/machines/${hostname}/configuration.nix";
}
(lib.mkIf secrets {
secrets.pass = {
dir = toString ~/.password-store;
name = "nixos/machines/${hostname}";
};
})
extraSources
];
in
kropsPkgs.krops.writeDeploy "deploy-${hostname}" {
source = source;
target = lib.mkTarget (if target == null then "root@${hostname}" else target) // {
extraOptions = [
# force allocation of tty to allow aborting with ^C and to show build progress
"-t"
];
};
};
in
builtins.mapAttrs (hostname: configuration: kropsDeploy ({ inherit hostname; } // configuration))
{
nunotaba = { };
sayuri = { };
}

View File

@ -1,286 +0,0 @@
{
"nodes": {
"AriaNg": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1641157028,
"narHash": "sha256-Da9GR1v2niJCU02NnC3aKLDMkUDEN2GULFgBQAT3tsY=",
"ref": "master",
"rev": "ea678a781a34613cf67c9c81d4f176d531f40630",
"revCount": 604,
"type": "git",
"url": "https://git.sbruder.de/simon/AriaNg"
},
"original": {
"type": "git",
"url": "https://git.sbruder.de/simon/AriaNg"
}
},
"aria2_exporter": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1621073204,
"narHash": "sha256-NXjp8rgWsNwX3WR8F11TAGxYoi8QZjrmuc5nsj/IjdQ=",
"owner": "sbruder",
"repo": "aria2_exporter",
"rev": "4b170f34720be5da2d2b8e791ff891624fe40e51",
"type": "github"
},
"original": {
"owner": "sbruder",
"repo": "aria2_exporter",
"type": "github"
}
},
"bang-evaluator": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1627835028,
"narHash": "sha256-LHTdNog+0EmRn+4DIz451vvQ2EeC8KwyV3/8JpX9yiw=",
"ref": "master",
"rev": "7fc3d5019c907566abbad8f84ba9555a5786bd01",
"revCount": 52,
"type": "git",
"url": "https://git.sbruder.de/simon/bangs"
},
"original": {
"type": "git",
"url": "https://git.sbruder.de/simon/bangs"
}
},
"flake-utils": {
"locked": {
"lastModified": 1638122382,
"narHash": "sha256-sQzZzAbvKEqN9s0bzWuYmRaA03v40gaJ4+iL1LXjaeI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "74f7e4319258e287b0f9cb95426c9853b282730b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1639871969,
"narHash": "sha256-6feWUnMygRzA9tzkrfAzpA5/NBYg75bkFxnqb1DtD7E=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "697cc8c68ed6a606296efbbe9614c32537078756",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "release-21.11",
"repo": "home-manager",
"type": "github"
}
},
"infinisilSystem": {
"flake": false,
"locked": {
"lastModified": 1626615686,
"narHash": "sha256-eXt4eon7oEg1gBUC8myZNACmDisgsQOAHGlnDhyG6zk=",
"owner": "Infinisil",
"repo": "system",
"rev": "f1fd247eca84abccbad3b57da39454702d7ef2c6",
"type": "github"
},
"original": {
"owner": "Infinisil",
"repo": "system",
"rev": "f1fd247eca84abccbad3b57da39454702d7ef2c6",
"type": "github"
}
},
"krops": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1632420452,
"narHash": "sha256-ncK6vABW/Ku9XI0kqj1otarUfblryoQzSaOCnaZ0oSs=",
"owner": "Mic92",
"repo": "krops",
"rev": "0388970c568905fedcbf429e5745aacd4f7a6633",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "krops",
"type": "github"
}
},
"nix-pre-commit-hooks": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1639823344,
"narHash": "sha256-jlsQb2y6A5dB1R0wVPLOfDGM0wLyfYqEJNzMtXuzCXw=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "ff9c0b459ddc4b79c06e19d44251daa8e9cd1746",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "master",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"nixos-hardware": {
"locked": {
"lastModified": 1641965797,
"narHash": "sha256-AfxfIzAZbt9aAzpVBn0Bwhd/M4Wix7G91kEjm9H6FPo=",
"owner": "nixos",
"repo": "nixos-hardware",
"rev": "87a35a0d58f546dc23f37b4f6af575d0e4be6a7a",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "master",
"repo": "nixos-hardware",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1641870998,
"narHash": "sha256-6HkxR2WZsm37VoQS7jgp6Omd71iw6t1kP8bDbaqCDuI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "386234e2a61e1e8acf94dfa3a3d3ca19a6776efb",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-21.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-overlay": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nix-pre-commit-hooks": [
"nix-pre-commit-hooks"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1638388788,
"narHash": "sha256-4t+iDoZO9X8fM1cWfbCbsIagRN0PRkpGcJKaMLJE7yc=",
"ref": "master",
"rev": "72d323ca0410a08abc2d981b812c5cd0fd3338bf",
"revCount": 38,
"type": "git",
"url": "https://git.sbruder.de/simon/nixpkgs-overlay"
},
"original": {
"type": "git",
"url": "https://git.sbruder.de/simon/nixpkgs-overlay"
}
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1641887635,
"narHash": "sha256-kDGpufwzVaiGe5e1sBUBPo9f1YN+nYHJlYqCaVpZTQQ=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "b2737d4980a17cc2b7d600d7d0b32fd7333aca88",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"AriaNg": "AriaNg",
"aria2_exporter": "aria2_exporter",
"bang-evaluator": "bang-evaluator",
"flake-utils": "flake-utils",
"home-manager": "home-manager",
"infinisilSystem": "infinisilSystem",
"krops": "krops",
"nix-pre-commit-hooks": "nix-pre-commit-hooks",
"nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs",
"nixpkgs-overlay": "nixpkgs-overlay",
"nixpkgs-unstable": "nixpkgs-unstable",
"sops-nix": "sops-nix"
}
},
"sops-nix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1641374494,
"narHash": "sha256-a56G6Um43+0+n+yNYhRCh/mSvDdRVzQHSKcFaDEB9/8=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "7edb4b080023ef12f39262a3aa7aab31015a7a0e",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

217
flake.nix
View File

@ -1,217 +0,0 @@
{
description = "NixOS system configuration";
inputs = {
flake-utils.url = "github:numtide/flake-utils";
nixpkgs.url = "github:nixos/nixpkgs/nixos-21.11";
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager/release-21.11";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
krops.url = "github:Mic92/krops";
krops.inputs.flake-utils.follows = "flake-utils";
krops.inputs.nixpkgs.follows = "nixpkgs";
nixos-hardware.url = "github:nixos/nixos-hardware/master";
nix-pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix/master";
nix-pre-commit-hooks.inputs.flake-utils.follows = "flake-utils";
nix-pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs";
sops-nix.url = "github:Mic92/sops-nix";
sops-nix.inputs.nixpkgs.follows = "nixpkgs";
infinisilSystem.url = "github:Infinisil/system/f1fd247eca84abccbad3b57da39454702d7ef2c6";
infinisilSystem.flake = false;
nixpkgs-overlay.url = "git+https://git.sbruder.de/simon/nixpkgs-overlay";
nixpkgs-overlay.inputs.flake-utils.follows = "flake-utils";
nixpkgs-overlay.inputs.nixpkgs.follows = "nixpkgs";
nixpkgs-overlay.inputs.nix-pre-commit-hooks.follows = "nix-pre-commit-hooks";
bang-evaluator.url = "git+https://git.sbruder.de/simon/bangs";
bang-evaluator.inputs.flake-utils.follows = "flake-utils";
bang-evaluator.inputs.nixpkgs.follows = "nixpkgs";
aria2_exporter.url = "github:sbruder/aria2_exporter";
aria2_exporter.inputs.flake-utils.follows = "flake-utils";
aria2_exporter.inputs.nixpkgs.follows = "nixpkgs";
AriaNg.url = "git+https://git.sbruder.de/simon/AriaNg";
AriaNg.inputs.flake-utils.follows = "flake-utils";
AriaNg.inputs.nixpkgs.follows = "nixpkgs";
};
outputs =
{ self
, flake-utils
, krops
, nix-pre-commit-hooks
, nixpkgs
, nixpkgs-overlay
, ...
}@inputs: flake-utils.lib.eachDefaultSystem
(system:
let
pkgs = import nixpkgs { inherit system; };
inherit (pkgs) lib;
in
{
checks = {
pre-commit-check = nix-pre-commit-hooks.lib.${system}.run {
src = self;
hooks = {
black.enable = true;
nixpkgs-fmt.enable = true;
shellcheck.enable = true;
};
};
};
apps = lib.mapAttrs
(name: program: { type = "app"; program = toString program; })
(flake-utils.lib.flattenTree {
deploy = lib.recurseIntoAttrs (lib.mapAttrs
(hostname: machine:
let
inherit (krops.packages.${system}) writeCommand;
inherit (krops) lib;
in
writeCommand "deploy-${hostname}" {
target = lib.mkTarget "root@${machine.config.deployment.targetHost}" // {
extraOptions = [
# force allocation of tty to allow aborting with ^C and to show build progress
"-t"
];
};
source = lib.evalSource (lib.singleton {
config.file = {
path = toString self;
useChecksum = true;
filters = [
{
type = "include";
pattern = "/machines/${hostname}/";
}
{
type = "exclude";
pattern = "/machines/*/";
}
];
};
});
command = targetPath: ''
nixos-rebuild switch --flake ${targetPath}/config -L --keep-going
'';
}
)
self.nixosConfigurations);
deploy-local = lib.recurseIntoAttrs (lib.mapAttrs
(hostname: machine: pkgs.writeShellScript "deploy-local-${hostname}" ''
${pkgs.nixos-rebuild.override { nix = pkgs.nixFlakes; }}/bin/nixos-rebuild \
switch \
--flake .#${hostname} \
-L \
--build-host localhost \
--target-host root@${machine.config.deployment.targetHost} \
--use-substitutes
'')
self.nixosConfigurations);
unlock = lib.recurseIntoAttrs (lib.mapAttrs
(hostname: machine:
let
inherit (machine.config.deployment)
targetHost
unlockOverV4;
in
pkgs.writeShellScript "unlock-${hostname}" ''
set -exo pipefail
# opening luks fails if gpg-agent is not unlocked yet
pass "devices/${hostname}/luks" >/dev/null
ssh \
${lib.optionalString unlockOverV4 "-4"} \
-p 2222 \
"root@$(${pkgs.dnsutils}/bin/dig \
+short \
@${if unlockOverV4 then "8.8.8.8" else "2001:4860:4860::8888"} \
${targetHost} \
${if unlockOverV4 then "A" else "AAAA"})" \
"cat > /crypt-ramfs/passphrase" < <(pass "devices/${hostname}/luks")
'')
self.nixosConfigurations);
showKeyFingerprint = pkgs.writeShellScript "show-key-fingerprint" ''
gpg --with-fingerprint --with-colons --show-key "keys/''${1}.asc" | awk -F: '$1 == "fpr" { print $10; exit }'
'';
});
devShell = pkgs.mkShell {
buildInputs = (with pkgs; [
black
nixpkgs-fmt
shellcheck
sops
ssh-to-pgp
]);
shellHook = ''
find ${./keys} -type f -print0 | xargs -0 ${pkgs.gnupg}/bin/gpg --quiet --import
'' + self.checks.${system}.pre-commit-check.shellHook;
};
}) // {
overlay = import ./pkgs;
nixosConfigurations = nixpkgs.lib.mapAttrs
(hostname: { system
, extraModules ? [ ]
, targetHost ? hostname
, unlockOverV4 ? true
, nixpkgs ? inputs.nixpkgs
}: nixpkgs.lib.nixosSystem rec {
inherit system;
modules = [
(./machines + "/${hostname}/configuration.nix")
{
_module.args.inputs = inputs;
}
# deployment settings
({ lib, ... }: {
options.deployment = {
targetHost = lib.mkOption {
type = lib.types.str;
readOnly = true;
internal = true;
};
unlockOverV4 = lib.mkOption {
type = lib.types.bool;
readOnly = true;
internal = true;
description = "Whether to unlock the host over IPv4 (only)";
};
};
config.deployment = {
inherit
targetHost
unlockOverV4;
};
})
] ++ (with inputs; [
home-manager.nixosModules.home-manager
sops-nix.nixosModules.sops
aria2_exporter.nixosModules.aria2_exporter
bang-evaluator.nixosModules.bang-evaluator
]) ++ (builtins.attrValues nixpkgs-overlay.nixosModules)
++ extraModules;
})
(import ./machines inputs);
};
}

View File

@ -1,28 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
xsFNBAAAAAABEACkl9IfFWt7bGRtnJmDsv3sfotEQZusmFA6d9+Lh3J3Z5Ekx1Yz
wIf26Y2MgOtxv8AJJ8QW13wH8/NOrySTPUaaQwjmkiv+7Hp3Ez7uoSg7BRrUXVez
oo6dIStda5rNmx1ClYnzBVu0q54/mOayYWxeJOTl1YVKr7cSx2jcV+h5vEMZYeym
AkHGNoFz83dguwNWTZvURjp6B65G84w3YuZyG0YHeQ8Lr0gCJDEmrP2NzIuXeGWy
VEaE4XAUOF/9T+WVkuQmz6Drnqpw59Wc/J51Z2bz/2KL1oI1vR1HSzJlv7kc3joJ
63yYv0TXy4AeptWoY8FX2wtHxfIUK6ClHNfBhjis0cYgvru0KZSMNAGQutlGB0yA
2YHOS1vSPXfdyKbODCP08CpA1lufYapJwSNgU0c5d22OCCYvdwdr0HRc/0zmUoVH
/ge2SL0dRTm85ny/wEE5TgL9qnh3iWpWM60lCX3MgkHRnfgmSYn/FJHB4+3miQ31
hYkw1X1ee5ZFNsptVT5vtz/b1reVA/+v6moReIsFaWKxEgGFHXBYCRt8HnxyYvcv
jv9B+qpL12p7gflMr/trA5xTu9yQLpLqxSRpl1vebLo5p6H084pUelwFtBq/hLs6
bEPw5R/n/7EyPauDeEPb/xHKACez3hhdS+GqxgcaaLqQZN1w7/cxXBVSFQARAQAB
zSlyb290IChJbXBvcnRlZCBmcm9tIFNTSCkgPHJvb3RAbG9jYWxob3N0PsLBYgQT
AQgAFgUCAAAAAAkQacgYfJxDdU4CGw8CGQEAALeFEABb6uheTtzwh2pmbEfahsMf
3Umb9E1hGVaKz9KUez2gU/C3EbnELm7qPSP8Bj5gp5hF527YpwcPTGMKXD+SyyUE
w+1lFun6RNEEeeJoOEtDoQZA6j4bcpZqvR7r7jAhdU1LHuIjD+4AM4jrTF3B2BrN
LpuX70MO0zX0b6ryHeH+9y3iCDmxViXmn0EVG/MLAjguWMrimZ66R0raKfs4eRR4
WbbFRl+xXPOv5JvPVhl0BQItVXrTTXFnRNF8y0AxmpxGZ8uFr3PwN9xB9I4o25mu
5Pj+aEfJkHTiMqzG44+TITu4pN3xvy32yqO9skn99pz16Q1jQy1cYYnl64nfktJ5
cH9Unq5CQIzyugrHhFTruN4PZR07mMMoIHRNisKOVifoyEQPqKUEOsYsaEv+zeU3
a42acC3AXJJrSgjN5XoA7bV4RRmU3QYQUsO87gJF2I3xnZwKkRL8R+g0cZeBTaG3
U1DwKNfb2WhiAtagixVk7bsKknYJDar41LA0FM5i6uRez+Pb1y8yscD9TP3xiR5d
m+/mbrz4fF+5ifRqhvfsewcZIwkVVXR0pBK8c/eGL7YrZ1pJwt3JDsWfM50TGvS1
O9LCghAw/SZPfyBik0vKc3R01Pfj3yC70gsG6DI9bIG1UavLhbGQCgDPcEpDZiIt
N7RsQdc2NwPnMMMH4mTAvg==
=9jYa
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,28 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
xsFNBAAAAAABEADjzT31zliBOnM3UALM6S3Oa5nEKHhwn6Dmi8uMABiDUJ0tF3Nw
cM8X69FI4oCA9YxQFWn/J8o/h5TvDPfiBwnjE/kuNCnRVkrPxRDFZybxgMyHM/dM
QjeZBqCexVa5IhugOrjnx/OWKaFhjLp4mTT/g+HhtvD15tandWxRhLBizKAnPQz9
da1nj0i6YbyWP/E+3EGHxw3qHkjDbts7c1oB2N7cTNFtTfdI24G/aiuSmrURHECl
bD9xokEui6ZYAtg6cXDsBlmZE1/9D/sUIdrYvspj5bW0XLZrPLNud10Nh7kumBPG
uy5xqzD7cl6xCcw4phlveHtDnNhNMH7LUplGyMKBc+CEQHC2uiEQ76P6oRTYSHnq
d2fRwzaynBKA00Bv7WH2mucA8fERyLxl/CuBvaswCu/XBWgr3Mi8s9E7p/vB7EUX
DDhJWYDBfy8ONUyWAUxdOwitoiPuKWO04mORLKYOQXS+Z4dpHJc8QwYeZoPNIh0H
yv8mb7U8MNO2DVPDsoDTvC3vtNo8lwEH5BL2zRruc4LMllSPtkLmWRgMz77LL+9W
HYFBfl3URR3MxE0RBU3BMrDeMFHjbxB0kQJL7vYahl6wwTlE6F3KF/l5oyCsd3R8
5oqh4gjkhwIlopXizO8kTqnPWeR51VgNvB+tj5o08sRanB54XREulhRsSwARAQAB
zSlyb290IChJbXBvcnRlZCBmcm9tIFNTSCkgPHJvb3RAbG9jYWxob3N0PsLBYgQT
AQgAFgUCAAAAAAkQRKN/qMFQU7MCGw8CGQEAAOAnEABGFmF4VKNUQoZYLbnANtHY
r0VGrSiAYQdj+HVP7W3dd04PSbH6YWjpP7yzZLncjd/+zr1azG14D8UjCZdnelGG
jlOLFZNMLwVHjz/quLSMKDgERLfxwDCZsjxnA0CvMvZbWo0VoAs/ncPClqYVjMGP
Lq8O+JVJYNGj0jra/PvLGweVqupbfAuJ6KBLlna9iYJiv8uCTjoRF90/dCPIEEQY
ZUQstHw5zfGs8cycTElfIv2XpPLmARJ+juyLLUvRQQFIif1o9VI4+MC9oFKS/Tku
Osa/KF86z1nLRFRyqKZwgOmZUADKqpEdQwHgyqKCE6XCey089hwBrwnwy/opdXUR
hnP28tc4MgUAEAJhBH3uHH4TQyUI5gUOST9MkmxqQLTNVV5IuK6KqO5XPxtczdCf
LISNRLjzL3H/zCy9BuhnwDZsdAz0ae5NMjjXnVpFcuGW7kP7RsiGL5aZSAYfx08N
mdq1EiK3e3EQAgeunLpGqlc0Os/fB937yuQoR3lYAug6bwa7RnElZMID+Xj1GsQb
qY1xodRDM6DE2qyYlDV2f0WoFjG2f2VjN0IVI0AxiydlIfrrK7v5TR9/8gVuo2Vl
D1/6pVotiCeUapXhf/ezEBRS1DhRXa0v9rpwzV1t91A+M30CGj2Cye0CQc6uDvno
lJ/oTo6bAXwmWGmvvyCtTw==
=S83g
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,28 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
xsFNBAAAAAABEACbZMv7VT/YLGIy1NnPmVO0c7ximkxFAx8N8UiCQB6aLL6WKIYB
xuDZAzkRbv7HvzfHbovjWKKrHDihtcup4WA2AF/fBk1grMDq+zIT17EMke2xqp92
OY788ijMPm63+sRgQMfyVOoh16VQb27kgCO8ouPCkjbgabiBz0sC2sVztoDK4xh5
RTT4mVjODeqX1wxhYO90Nez4yZt1zX9t9oOPawTCwzoLKco/QNflz3wAYx21DJ7B
UxfACkHfI3nxjbCbmVDLMzTmcn1UZoxtovJYp9gd//fCaySMxlfk489j/8kPVrxy
bCFtFWEqehLvgQZg0Yrpy/Ih4vuzoCRLPj17GC5LevhrS7sIaATd4UeU/ke9+f/U
T8Yf2dh3e7g0pmeiXphpyG7mUPhxCz3MN/FQnNQauQAwmB8MmhxQXPtfx2OyXnP4
xjLb8sAtrtpaKNQ50k3/1LVcrJozvx6ELkmOE87MIhbi61jeplhUAnqPP7rpUvhn
VeNQ5FgIei78oWVDa6/d1R4Z0Bos/kvNWCdG9OWuqgGnMOfvUfi2WojId8ZM2s2Q
eHqg/NO36zctyCtoF7NBIBsJVDA406M2H3B0Mkx2yGHBXLlgwCBl5mopgjc5wrn0
xMWgUv+H5jcwbzCNcA0dn/I1BlBWPk64T+iCJh4WO+/ZcD4IsXh+fmnB0wARAQAB
zSlyb290IChJbXBvcnRlZCBmcm9tIFNTSCkgPHJvb3RAbG9jYWxob3N0PsLBYgQT
AQgAFgUCAAAAAAkQZTN48Qym4AoCGw8CGQEAAP1OEAB8vJKvssUiZm72t3EDrc4i
KW6M/kCPTlHBPmkFiLIi1c0qjZ9Oziw20WMhwRdYu6Bv66Of6YqNWNHbDQjdDcSE
/echXBKwdo/uwGpYsIEB5pQwtxkmT+8MlHmfUD9cfPK0vweGq4OOiWtNwzS7jt6M
fvp6Ar2BDXxT7zt6j/2BgioldmlxXVewtEgC+m9jBnCbML4xAyj9AEMrwYVwAvY4
QJoUK18lPWX85bSLpTPyfpJl0DkDiFR1EXHgpiZs/cdv3r0lMb9EfpvZbHtqolMy
MDIdwUy2cnoQu8WazbMloe9nAx6kZ9ylnvjkxuhgNpYV397kESWXzl74es1KAOgg
xURdt/IM2MJoUTs3B5v3d6SkV+UtSzMLSbBPJ5T0ehykgIihHNINcXvQSDAHPBbv
+Add/40MSi7NcJVlGwJvYmIRSiH8nvcQy2UcCGJPx6h3CKk7OskROpSNZ4SbPDsQ
WJk2OXr3tNxBoUp565DRURvIANQLerYV8ziwHxhbIyEudm+9/g8CbDy+wPGulwMZ
ruN6Lu3L6ctYLniXf7mADNVeZWXlrFQB+qNag9TVhj++kv+qsC5VOVI8o/h6N3Ai
yo3aFmDEbsA3F5dE5GZ7kE/u0b3b8nvqKCp+5IQuKl9nwyzKqy9Zj55HmewES3mR
DUKUW9W7ZnROHuiQxO5jTA==
=XySc
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,28 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
xsFNBAAAAAABEADQYi6d6/laFq0OQWLZYL/48/SF1gnej22Ob+Cy0Tm0d2w9lU95
hASROWy6ZqUFwVXKp85uh6UJtA6q2XpaodfurGciCW7DYOjPNexJ0o2xmyFqGB/s
PuQDB4NxGXhCyNBXa42adfIlDyYHo5zIDuglMbwr7CQ3RZ1ktxudaA6t9Zlw/5pM
c1RXuTwvlhLGstnAz/ojNFwEH4lzYIIRpW4GXmWrtnmjXL/z4LLplYrfPGnsPIij
Qf31vhIrEp42nzJIY2wjshZaTvj5y0QIBPfgy9Q9I8/YwxFSY2wt3x8ooGLkTw4v
bshqUReatSdoIL4snCaA1oFtnKpqv2vJy/Z6LvURA4e/sbD+c5lMBTE/EkVgvCkC
6AbvCxwYHxB2G+lizKgRrQ8tVNDEHOFJBKNMaJAXpzz50ItaSpC+8FrYEP+y7iHk
0SBzKlJv3F+yuo1WrD4gHyxHAxACa2eDUU+EikO9BrOh78unOmWYEWVCju+ICHHP
STpW8jvEkldttv9Zr4YBDe22sjLKGuqngqabfSCokjjtEPgABCuJMLaGMW5nQm1K
Qdr0OHjr1apQMG454CMl4SGoXuNv0XIAcDpaR9xUB5cbBmAmwOWtdrqP2z772+9E
jw2WwavW6bn/cApa6BHSK+PQhF9wWvASy138i4m7aCLC8cteukOd6jCexwARAQAB
zSlyb290IChJbXBvcnRlZCBmcm9tIFNTSCkgPHJvb3RAbG9jYWxob3N0PsLBYgQT
AQgAFgUCAAAAAAkQPLm479f+10kCGw8CGQEAABX4EAAT59Yhu+JwOlmSI9UlzM/E
FJ+A8AHijh7Fc8+TjqnA7HmUSlhhVzhuSpjsSt8f1wswNXdcM9N7A5p0DCPZ+caG
9TyUrQXktiUdOj3O8bAwnsp7c/GYSBpIjhK1ZN8giN/c66l6z5IcolLA/KBPkMOp
2ipPBNjD7bk4khAzAqbPxGxGcpHqaNCS/nC/ovRlcQ2O8rgedXhhRZackuy6gw5+
fwGyrnAt9oVthBqhYSUNItQwEPWnEj1yZzsQVvpCX61Vkh7qfqiG/ewvWVVTVOL3
lEV5EUsFhiNX5ORUm3pk2qqELR8FbcVzTWf8sLgRM3NeqnotPS3rcHFb11Crh5SD
kqoAK2U0oYdGj5wlOH/yNtO5Q1auKwQ0Unttj8zmy55tCwqTiSrahmVxksCyINJn
B7h4Xct0ENH9gK/03aEGSZCzLxNG3BpOAOjWU+Ir5W2QLVxZDJT1KiaSftf81h9I
k57QsrXAoJNfzwONphQGSVKADBa0Y1P/zkm91gOcuIh3WXZ7BRcn5YZ72POqf61o
4uvT5xnDH2Y7upsCMTQkOUCenRUspapQZEQP+tZgQIwli86UeXfcPsqXX8j5QiJD
5HOl1jSRt5Rh4rqHfWYyobvLaEnWFEc3H/tYWSkk/w1ideiB3jMCdw65clQHGqJy
benF3GpcdU5XwmnJZ3XrCA==
=4Idg
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,28 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
xsFNBAAAAAABEADlgmSvdnFWue1i5dS1qA9df+cRQDA1NDBHYm5dGpsTe7xghvde
9B1aAzWxbxeppwr2IHvLo1boWyH0ODC5HFxvleaYd6R9oLljQvxZEPq8ANWMyxDx
T4MyRlLClegMrUaCoQTFxoO7LFujrhKPC1+r/JVBBehJrpw31WAUQV2SLDTPFRMJ
GVAJXR1vplafbftlkI9K3t12T1RrD1D5QxPtFPPEdwdfPQ8CDE7cCado9iv+P3e+
9gA3fE0HJzS1ZRySF0sZ5lP3RX3ZBoY7z/8s3ZHGCYfD9ssGwZS5ByjMk2eJiPY2
tX0ZwffBdzAwyq64e1/ddubGTIhKNPd5Iy2GCnOEgPMC8TCke5Zz5IeInUE3ANyS
zkuwpCbqT8Vu541yqhs8+dOnH3srgks9OH2Ar2ctMWx3gmICDoCLHrWfbvlkqUwB
cxnGxAeNzOXiem1Fu5IJwVC5JR1+5b4dqa3k+f/nuWRizvrU26OP/1S+NTz3T7/W
TEF6KyE7+dy3K4IO95SDYwVp6mF/0fh4FTahNi6B1BDEAZKZjaVXyd2TOk77Y7si
Tc98E4SUTUlRRCLh8SmUmxalI168LLgGMwUWhDvRw6EP7uh9FBEi1kLXnN6am0kP
q1jgQL798DzFwcgEYTx7rTDHZLkbwrxWA32Lpu3T6twtaZiQE+o7wuXMTQARAQAB
zSlyb290IChJbXBvcnRlZCBmcm9tIFNTSCkgPHJvb3RAbG9jYWxob3N0PsLBYgQT
AQgAFgUCAAAAAAkQZ0WmUqMRhtsCGw8CGQEAAIyAEAA89dyQvXx4sS7I1nRlMw9q
Agbi4h1lrCifEH6srlInbg3kZNgnlsDY+cVCIiy8m/Oyupn0U4uduMI8P7R5kgWQ
g9+FKFXoLK8P1kO5gani+tWNmBW49leSN8un9YAviKele5wDM/Dg+rNbWDaYHKu5
SspZV/SiP0JkxXOgxkMgOOl97kNmvv6O3qYHPG5rz5P/YV0pdDSi1cfhdREvTPAl
eNqzMrdEuE/GUrYJYeF8kN+TswBubTgy4WBqQdMlS+Go1B/7HQd56pl5BHiHM8HZ
l01ljbgqdYdggmXt7CI90Txe3RRduzKS4ncEQ1VVQiXEmOzU7emu+DFwknGnSgTW
gW6Nps3u2XhcsJNczf2PdEzDAv0oNAp4So7JdTGetkJ1Yw4quS0l1XWWBm+cf376
nanAGkENvuBbS36kgHNjNT1EnUnyJoMDMnc1AmSSlTf/ORc+JrzM4PtMonhWJTAU
eM66tozyJ3qYWApiI2doYwMDuh/u3jvqpTddxklaNFUOxIA2VITP0EgCFkVjW2u3
0gPY2tV6AtcxcUn1NnhS92xf0//O4fcGOwlTvNaPqDuF0mk9OazAPQ5L37mfNZzb
XUc3AyZXRZNhlE+aNfeJSKtzFCpGUJfstPmkdOwPxK29G4GDbjzWevpYF9Rv6Xpq
Ky38rXnis6Hpih/z6/7HOg==
=5Ki8
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,52 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBF/lCz0BEADKOij3IA1IIiZc9c8rgxTUtrn4W1R8ncgsnFuXIDGD35dBB9e0
wd5noQigoqts9N8ULHEV6J8AuBdl1IP2nAKAr6h3F+hrLjL5tZZCPpTN5fhxWguz
wt6aFZgcFwFmQfZHSInxO2XpcibyJAs5ZXW3cO+VYQdVxXLT6KOLKkqWCCGMlQSt
xNigzNbrjUcjrcGBcjNbFJs0P4BkVvD6+3xBerpT6zwAuFdBiUpZZk+XI1QCAuVF
6ld5A+x+pwvKoN/n040UAUAdLTne7oisNonLhSvZVrH2uH4dKkku/yi2glSkUwps
n+ffr0jD9VrdbxktcqQBE0WU2q7Eqe6EjSxURHI6uJ/wFh0QeYR8sT5mgPMt5O9T
T49Kz2uUdljuHW0eI37DJSUDcXWh0OtuENRFf7m0lvIIaaPpbPM4btS8j9lCFs9h
pJsQIQbNjV+UmIBvddDKGwcL+DHJFk0E2sqPYOwsebvbQLhVvPSPWWUVKrqMay9Y
Vd9KKy/KddESzM6c3TFmUbkEj1h4qWSZ0XX0vGL8LL68maaDHwO1nKuw/XfSpjAC
c+3wuqAgwFB+ihO/qWs8CB0z+wo+7NK9OUUVVucu2duUUjNknf6+v6fPedtziapp
SHVQQKWYvozxVa7XU+dnrU3ZUHzIrv6Fr6yTdGy6fw7pE3yPFIwbw9vsowARAQAB
tB9TaW1vbiBCcnVkZXIgPHNpbW9uQHNicnVkZXIuZGU+iQJSBBMBCgA8FiEER+dV
ngN6NWUtu/iqjTyC+fMJ+OwFAl/lCz0CGwMFCQeEzgAECwkIBwQVCgkIBRYCAwEA
Ah4BAheAAAoJEI08gvnzCfjsYFoP+weWMfiJ3mMeBeZBBcgp9NZTjrJoc2tKn/9s
RL4PL/3lwLRSEu6JS4LauAD6fW1d5QnNnUe4nIcvTO6RvJ7R/lDWg1KL+pdCfYtk
FiIesUkp+eW5Gqw5m6Bt1a9UjXdtHJuVGKQ/XjxC2914Ps6nhp5mY+NUm5zwZCBK
qbjiPjD17TeTCThEui3kwl0sgBhNX/eCPpJZtw3u7vzxpN24+sX8Ogo9r4nRtHKv
64vVggiT1Iu9JXm9KYlySFDZed9iVbgM2wKpylw1I0+F4VS8Jw/RDiIW61exKxAe
VuxPzbIGeJ0R8u0ZcvTiRbXr7op9barUDCQFn2K2oHXd8uCMUULinlO2pPYyshGh
znnZcZIvawqtWnImNnyTvKYe5Il9w2fmm6SzwRmcMvHBZ60eJC/PmnhpRcpBxyiG
mAWgFmmgMhc81wcPZFD0Mp91twMDHRchgfmBBlNdqMBt9nNJ2Mm7o52mVX/daMG4
VCqLdvbW9mWkyQVjfBq30XabanzN8RST63LlZEwArQqFpH8OifNMHI22fW2xGvPq
09k6SLA9qbobGFw+OGKIaGHiVbFq5aeTkqHr0sgL8QBHUJWv+SE0q49GfDDvA4JE
iDsLW6RJuNFGTaBq/NzN3A7iT8tTcdClYc7MSQxsEyTpuU+BlC9ewNC4cV/PyJ8l
13yeMkdZuQINBF/lCz0BEADs+rV9/tDQ6hyJlgMEKA34LjV4OEBdpwnRS51juXYt
nJiRC22Ljs6FY3NivOQPUNJR4yLU7/FGCGgyXlsLEyMIqH5Lldq1iaTMY8FHSdc4
e+BM4QYCiaYT05Jqeydorq0fZe0nIXobK7RqB4dG543JNzrttotQ94qpx/cFUy6i
ADxp216IyDFh0q10TKao/GB2gwkbOlRNuLYXXUMDON9i8VL0Yh7p0KhZuOl2vREm
9/IQDJJHFv4CbSTmdQ0de+k8rVgyiW05SdYq3vrqRmNuI9fbGTf3vw8bHljq1SiH
VoapbNJ8CnQCRzrsaX+pOlJwFVUUjxco7iyCHKFobfx+3ju5kwc+i/58nDiSkxMV
DPqfjFXnN+72EihfHiw56k1zIRhF9D9b8eq6aqGOIgTtjRujQUR9Rn5BJRZ87/pR
nlZsS3wE3nQxOo7fXKv9FU7TyEy6gu1LuK53dUk5xLlu4zMoIP8mc/mZchXqsksi
JSWPFDeXh9HLFhKyzintRxdXNp5xV5XaXsMlFkNiTBLUHLbU8Ln9tiLcuJZ29y3b
ynLtVo+GN4+G5b+koIoZ9065qSJ0coBPMUa6o7go2e1/oil+xKmtM3UHS+mMNa+4
elSqSRdpv3Xgo5lLNP+e60FpN155/93Hq33UMvh8rS9KVaQgp0c1unP99ewY84ra
9QARAQABiQI8BBgBCgAmFiEER+dVngN6NWUtu/iqjTyC+fMJ+OwFAl/lCz0CGwwF
CQeEzgAACgkQjTyC+fMJ+OzfUBAAkVNY0chFGvzWHOxEKNJY9rW5EQrayrKPNhjr
3j9xHoD+1AO7Yinqgd8Ribw88l1+2lVQGHIpIQ2ZPDz/XGND5FvP5PrW71FcUJ/z
AKaEnYP4iZ1jgnjp280bJ2iHBMmHc5cs/7OwTCs1uos1kWhjLGA9M12OWDWN9iqB
+UJo5W8hs9c5LpYp7ByThQp+g0m3E/ZWSbfZqi0BqWX/X6QC1MMXYS1lZcg6qttF
rs6d9hquNHZO7PkI73Ph89DWdxMIirmmn4Iwv88w3jW1KJXiGJbp0N2yooZFtsq+
Yd5SHexET9rtU49BfeggEcWuDWJCGvPqdqCfAH6lKe9ddXwQx/R4f+Ffib8WYA6k
49HA55U6WfPs74yfbR09mh79kDV2uQgtkaHFJyuVuO4e3oyUoqe3hQdqOMR2lCAR
NSc7j5JdR9LxkUDqjUT8ipjzsTxwgPHaO0QkUjugs2v1TpivsDSRooI7NzWFTxbk
MkUX5BGUnPnEivBiB3n++1o5kZp1jk3OAi8cqVkosOMjduWei8f6yKpQ4ZKg9cH7
ovqpDS9R6CDrACDPNJSTBn2VyOdjGVc4FrhGsXp3FAe5prt1b9psvYTTuXrZZJZP
dI1cLPI0Knyymf56gVMGCjp+x1+w7ef0ylGLPtFEuy/6iqWR3H5htZDQo3AgOVgd
R7VFGCA=
=7eg7
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,44 +0,0 @@
{ ... }@inputs:
let
hardware = inputs.nixos-hardware.nixosModules;
in
{
sayuri = {
system = "x86_64-linux";
extraModules = [
hardware.common-cpu-intel
hardware.common-pc-ssd
];
};
vueko = {
system = "x86_64-linux";
extraModules = [
"${inputs.infinisilSystem}/config/new-modules/murmur.nix"
];
targetHost = "vueko.sbruder.de";
};
fuuko = {
system = "x86_64-linux";
extraModules = [
hardware.common-cpu-intel
hardware.common-pc-ssd
];
targetHost = "fuuko.home.sbruder.de";
unlockOverV4 = false; # gets slaac ipv6 address from router
};
mayushii = {
system = "x86_64-linux";
extraModules = [
#hardware.lenovo-thinkpad-p14s-amd-gen2
(import "${inputs.nixos-hardware}/lenovo/thinkpad/p14s/amd/gen2")
hardware.common-pc-ssd
];
};
yuzuru = {
system = "x86_64-linux";
targetHost = "yuzuru.sbruder.xyz";
};
}

View File

@ -1,27 +0,0 @@
# fuuko
## Hardware
HP MicroServer Gen8 with an [Intel Xeon E3-1220L
v2](https://ark.intel.com/content/www/us/en/ark/products/65735/intel-xeon-processor-e3-1220l-v2-3m-cache-2-30-ghz.html)
and 8GiB ECC RAM (1600MHz). It isnt the best choice, but I already had it
lying around and it is acceptable after changing the CPU from the original
Celeron. I decided not to use another consumer-grade computer for this, since
the server offers ECC memory and therefore should be more reliable.
The SSD (Intel DC S4500 480GB) is connected to the first drive slot in a 3.5 ″
adapter. I originally wanted to connect it to the internal ODD SATA port, but
since it only supports SATA2 (3Gbit/s) and does not support booting from it,
requiring an additional boot drive, I decided against this.
For storage it has two Hard drives (Seagate Exos E 7E8 ST8000NM000A and WD
Ultrastar DC HC320 0B36404) in BTRFS RAID1. They are connected to the 2rd and
3th bay. Bay 3 is only SATA2, but that should not be the bottleneck.
## Purpose
It is my main server handling most long-runing tasks and services.
## Name
Fuuko Ibuki is a student in *Clannad* who carves starfish out of wood.

View File

@ -1,79 +0,0 @@
{ config, lib, pkgs, ... }:
{
imports = [
./hardware-configuration.nix
../../modules
../../users/simon
./services/ankisyncd.nix
./services/binary-cache.nix
./services/dnsmasq.nix
./services/factorio.nix
./services/gitea.nix
./services/grafana.nix
./services/hedgedoc.nix
./services/hydra.nix
./services/matrix
./services/media-backup.nix
./services/media.nix
./services/prometheus.nix
./services/scan.nix
./services/torrent.nix
./services/wordclock-dimmer.nix
];
sbruder = {
wireguard.home.enable = true;
nginx.hardening.enable = true;
restic.system = {
enable = true;
extraPaths = [
"/data"
];
extraExcludes = [
"/data/media/video"
"/data/misc"
"/data/torrent"
];
prune = true;
};
unfree.allowSoftware = true;
};
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts."fuuko.home.sbruder.de" = {
enableACME = true;
forceSSL = true;
};
virtualHosts."sbruder.de" = {
enableACME = true;
forceSSL = true;
root = pkgs.sbruder.contact;
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
systemd.services.nginx.serviceConfig.SupplementaryGroups = lib.singleton "keys";
services.postgresqlBackup = {
enable = true;
startAt = [ ]; # triggered by restic system backup
location = "/data/backup/postgresql";
};
systemd.services.restic-backups-system = {
after = [ "postgresqlBackup.service" ];
wants = [ "postgresqlBackup.service" ];
};
networking.hostName = "fuuko";
system.stateVersion = "20.09";
}

View File

@ -1,98 +0,0 @@
{ config, lib, modulesPath, pkgs, ... }:
{
imports =
[
(modulesPath + "/installer/scan/not-detected.nix")
];
boot = {
kernelModules = [ "kvm-intel" ];
blacklistedKernelModules = [ "acpi_power_meter" ]; # constantly pollutes kernel log
extraModulePackages = [ ];
supportedFilesystems = [ "btrfs" ];
kernelParams =
let
mainInterface = config.systemd.network.networks.eno1;
first = lib.flip lib.elemAt 0;
in
[
"ip=${first mainInterface.address}::${first mainInterface.gateway}::${config.networking.hostName}:${mainInterface.name}"
];
initrd = {
availableKernelModules = [
"aesni_intel" # hardware crypto for luks
"ahci"
"ehci_pci"
"sd_mod"
"tg3" # network interface
"uhci_hcd"
"usb_storage"
"usbhid"
"xhci_pci"
];
kernelModules = [ ];
network.enable = true; # remote unlocking
luks.devices = {
root = {
name = "root";
device = "/dev/disk/by-uuid/c5cf6858-cca0-40dc-a3b5-ab47a3f9d49c";
preLVM = true;
allowDiscards = true;
};
};
};
loader.grub.device = "/dev/disk/by-id/ata-INTEL_SSDSC2KB480G7_PHYS749202D6480BGN";
};
environment.etc.crypttab.text = ''
data0 UUID=aa692e73-2b75-4239-8a87-5f5b69ea56c5 /root/luks-data luks
data1 UUID=1f4120b6-a3a0-4973-8c4c-a4d6703eea2a /root/luks-data luks
'';
fileSystems = {
"/" = {
device = "/dev/disk/by-uuid/92a1f733-8a23-42ea-958b-0d01a5de7776";
fsType = "btrfs";
options = [ "compress=zstd" "discard" "noatime" ];
};
"/boot" = {
device = "/dev/disk/by-uuid/0f1822e1-643b-49e0-b279-5e3373c6a26c";
fsType = "ext2";
};
"/data" = {
device = "/dev/mapper/data0";
fsType = "btrfs";
options = [ "compress=zstd" ];
};
};
services.btrfs.autoScrub = {
enable = true;
fileSystems = [ "/data" ];
};
swapDevices = [
{
device = "/dev/disk/by-partuuid/22978e17-fbbf-4879-9385-5c9473df1706";
randomEncryption.enable = true;
}
];
powerManagement.cpuFreqGovernor = "performance";
networking.useDHCP = false;
systemd.network = {
enable = true;
networks = {
eno1 = {
name = "eno1";
dns = [ "192.168.100.1" ];
domains = [ "home.sbruder.de" ];
address = [ "192.168.100.61/24" ];
gateway = [ "192.168.100.1" ];
};
};
};
services.resolved.enable = false;
}

View File

@ -1,62 +0,0 @@
gitea-mail: ENC[AES256_GCM,data:ck4S9YJ1BLUb6+mOrRmg22KWI1xQwsdIw1dowNk1OOk=,iv:+aQiTSGzmBOLYbIVgwH/SIhslKgdJKoL1ZaGAXCeqHY=,tag:H3vCEGMktqAV/9BASVR5tg==,type:str]
go-neb-overrides: ENC[AES256_GCM,data:Ws/2yCNNLLEpa9MbN7mZk6BBBaJxtHN2X9I41baWJylZeUld6/h4WCxyHw4MWzigK7k26E+7CGVGThF5Ucd6AuvuD9dd21uaoOtwsAKJVsCavk6VPQvfAuSqYJcBYY2pSwDpA6KbXbQqhC9OgcktvYQdnvNPbsSffK4zhrDjcFpDYYyBRQWxqHu/ZGh2088ECbhm2OCWeC9/5u/2id8dHutip6tUXBIalFmWObc6zgx4atCJGdq9/bOPgajQzrpWlauV0h3ioMwp0gsulOJl2LuI7Lvbsvm+UWe8hVd9ZLqR+4ZAwC5oCQht68AxekKrLNl02KQ8rM4fmWJpbK4NsR/m8+ifMZhqIe8tqUUhWGvJqbxEI/Rsbqm92ToIHL5x9hNSZ/crm+hF4c2Uh9jnSA3E/tOxjZaMU5hB+2Y4tF83nz61tzFnwhQ32VxFeq6IHyMOhgQzGZkDPAyFg2e4tbG6zp5oMx2lsUlgbaXrSrzBU73CjWiLDiJFNyGLx7ADeZ4aZVsZnvGL6y7K4p0uVuK7KSNzoW0=,iv:tniWSP8RgSDJ8ap+PK83TcPAvRdaXWC/gchF6+8uffs=,tag:SC6RB8zyVmjjbLA73cFb4A==,type:str]
hcloud_exporter-environment: ENC[AES256_GCM,data:TPMeNK7uC716PC8UqDCnUKtriueIkg3l1ql9e3lse46Ko3TVvwW1oAQRSbwK8CG5AjuF2s2Y8GJdYcI8PN6Z5kERYF1RL2GDpN4pLSuw/l0YqsFkt0uK,iv:cmB+hZHvbk1p8uRmLDyYdPr6rTsFxKcoTcQVo729sAQ=,tag:nkiSvy7rsoInDN0l+1FOOQ==,type:str]
nix-binary-cache-htpasswd: ENC[AES256_GCM,data:IktPHrrvExeZlCPmP82W9AovC59ILPbMQExVDO7U2S9lJ9cQKP14mQPuYwA+yKTycIdA01MwRDbt/SxhVleZ+aKkyOPwx/iG5B0cQX6cVqQWVTNVmxlW2sjupnnwwibcdikU21CIw6YsDKs7pMqRAfC/U2OJ3POo2qH5GgFY,iv:ofzEQ143HQQGZIEVkdWCrcENz0i6JPljLDGmG0A7aJ8=,tag:a557cdgRD25jWHhZeT+CnQ==,type:str]
prometheus-htpasswd: ENC[AES256_GCM,data:eJOWrcTC3YISJJLuQV6sxzD0r8Gr8uoUt48D9sSEHhsbNUUy3pDgIPqJHrkG0ek2sIF6NvpWdDGK1kFcduRAL9h7nLxQLOtf7dxsdObGlPH5nwe6CwdR+1wTE/2WzrsmTGnUrMjMiBgLPV2yRiQg3VJ7W1Me8tHPYHrqYhM=,iv:WvgwIoIfxc3vyjF+znyUzOElv+sd/thoYpxWVaIavx0=,tag:9FnRw7ol++1PCbl1c2IyoA==,type:str]
restic-password: ENC[AES256_GCM,data:IVFXmuzzvvqDS0T3P0R5ZMIn2wdkbE1AqwDMkWqMpDdCOVMP4/HhP4jF+tEarq22,iv:Eu6Wspzm0rPl0CuSoYTTLz+MmaEtmwCD57nH2JTBuaA=,tag:tKqt5Z7nF7lLcSsDKS4E3A==,type:str]
restic-s3: ENC[AES256_GCM,data:VJ/jgYnUSkbsNMb1ciLiCcRVEpuaznsSFf0QkEnPhTRHpFv4Nt0f8ARnNtG5j3iXSIT4+H2+5HWKXEsjhvL85p0XE3xe4h45xGKnvvVO2obF+b/zsMDdceFJtLbcq+APzPBjchYU,iv:W+80GhAvYD/52dNZsNYiEhiLo4dhO8oxkd+GAbk42NU=,tag:Kj9CaGo/xAmYxdoLE/Lo1Q==,type:str]
synapse-registration-shared-secret: ENC[AES256_GCM,data:lNzK/7QAk4Scv+lNM8bTTKvowI139c4R4Y7Qpq60n8R61aahlxrnWc/PUEOv85Pdx+8IdBOLnV0kp7OQF6tStGBBCOkAicYmnsLoR36DmuDCvTSKVArryV7BrxL8pv0=,iv:ZT9IIF7W0NHqvnU3lPQclVS5uXXK5HIQUzXNYwYFMIo=,tag:a/sUixOlHEvn5ZOINPwQlg==,type:str]
synapse-turn-shared-secret: ENC[AES256_GCM,data:sAvP4/jVma7Uq9TR4W/zEoJA17Stj75uG+G4niYaQ1tflxRhE+/HfrhMn7whnmpSgXDb/ZPtLfVaW1DCfU2jovz3Y9Ij1kveXar2aAjlPSsSVwTbFmei,iv:S7uVlE2rhK7ta2S/eX+KXBMQyc69onHYjfMNro3OCjM=,tag:rvI299PQ9TVfVzQjgfUKww==,type:str]
wg-aria-private-key: ENC[AES256_GCM,data:qbxpfNRocrXDbUJ3MwR5WMXX8LB4Vnv9HMXN403ANaBbCLrRTEL9hy93roY=,iv:l2DYXGY1wN1rP2bG/s9uSwRhbvCUm2T6IJy5LKzguqk=,tag:51S+m1P1EtHk1QWEjdUCUA==,type:str]
wg-home-private-key: ENC[AES256_GCM,data:6l3CgB4qCsPuyYOWuwU2vNiEeC0D1wl6yZvXGGYVsZfYvdPjRz8j5yV7ekQ=,iv:slB/qr+cxi8r7cnTuZAd8CuzWVnvp24Li6A/AnZaFzo=,tag:ynh1Z2+IELAJcgBbHwFC0A==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2022-01-14T16:18:19Z"
mac: ENC[AES256_GCM,data:i6TJ+X85H+ptli5GaodNh6KbjqBLuJcs/Cy88JIQdq5az6nVJUtB55SuhkOAu35pPqlGX4tTBRO7OHupkEwS0Gpl2rC+OQB8gvnfuANzK8uFKGs4EK29BJsqNjsRdDmH1NjGjrIjau4spLz0wfELUcKtKofkZeLvzITsgzjRj+4=,iv:ZuFOIeXb+k1PWfWYPyIBKAnBaLZu+E4SeThysXCQ+iI=,tag:BFMwx9Am66pRSmWQWnVpgA==,type:str]
pgp:
- created_at: "2021-04-06T11:27:21Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMAwDgSONkM+d4AQ/+KSo1N4aEuIAF2JMX+3RborUdEMIJNqIQsBYejPF4o5UD
25XVDt+GrC4Lx6OJsWobLOHm+FDLPzm4Zfo+grU+JaEBo0ZSthUul610iqChwEGF
zVMkNKARsZE7lDQ3uN54Mq/A7RQaav4mrt1AbHTOwBR9UdG5hrEJ8JZjObS7Gqz2
/OFpX4xr214IA9ALx+O2UIkSAJT9u9Ann/xcKL5GpwE9etcGZbYqOhAPaSzbOSDr
BtWuM8Z5nKb1O90pXEe16yVUmFXyO7T+lU1gDrDReSXJJFg7zcjMY4s9rro2H7xq
u0z/ufl4sf1E5u7fLLpzrVcqKJAOw+fvfoPeqMrNsGy3r3AdATw9jPp6giRoB8qL
xm3gGvs/VedBBqbXMDSCTIuhBcTu3/rrTWb0TJeuMz9RM01owkvtTrL3zjwK81BK
pNTwz2a49ylCiDS8Vin2u2jwjoRlri4mPTzw5pvcGqNAoNopv6cjawGQ2toCD5qG
tqx0hY0uXAE1cnfewFC63VGFbaBwfCYLryjGLefRH7XFOAcqZ3dlZFi5lJTVnnXO
44uO7dW8wfJj45USIEoG6D0BiRU7JPUhgPIjMa1cEI4XpoBSj13EACxovE3z5AYa
pX72eJHMkKZ5u+eRrXkrFSGFWkYBGKtgIdbgXn1i9Zw/Ewbf7Qz8kC83kxkih7jS
XAEbvfL1DTAHDEyAXFoI2ekIoTTGAtCpsadQcTZ3+3DeWU5R8X29vflEG/kSeRO4
m2npmJ9OCKyEN+zAd/WRIQ0wChFgadlTugsDcmXazdvzJ1qJiuNGmzpRn3QF
=dltN
-----END PGP MESSAGE-----
fp: 47E7559E037A35652DBBF8AA8D3C82F9F309F8EC
- created_at: "2021-04-06T11:27:21Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMA2nIGHycQ3VOAQ//RC1NMySQoeqfTGEKFB7LwC3o0yLTMHAqoi4qm2Q8jKxH
6zSjHNoYI9+2VNEWJcSvUwd9ks79jkVOAWO+Lmv2h1QT3RrsSsj16VZwl+ORp50/
+PDrZjaimMafAKaqGJ3HaPlzFX7jUjCHS0yCaF6WIU1ztRLVnHAv3p8dsPzQ1w+7
p1h0oQ2noWibl2GLGI3+1O3sv1N5tusTGZWFacG6VsTbtbJmbVCO5FQRqX7vcJtM
xfClghFPoHCGbN5W1NWpo/a/lOLUucqO7bFB5DIOoXme6SSS7lrYQKtjBQy/4DRe
r3VIjvS6ncVUIYPPnEMlxI3MPUB2lwJLG2B89XNNWwfwREUXTG4DEg09Z6jMUqVr
yNO67YCF95fNUQFMQ0LWyVsWZW1n1ef7/iKtDHNoFubCVGjWimIa3ZDX/e4WemEN
ww7dab2RXEY3oTLJZwAFMN4jeqUfpgH1TOvcs9OHwF0CQjJIDyDj6uyt6wYqITT2
dorhmn1FN/tUUNn4hE0iRjFaD1QrN30KZ4pQ1S/G3IkHGzJ4AlelO0j9yE2VMR2q
E8wEhVtDlO/VAYZSx7tJ7jd24gFsGlL70OfSXvo7jyNpo+OjaN9yy5Qy8iogwpGC
Jua/Y7+XORx3+SVB+1AUNSwCABOhWL2RQGnGxRRQrST4uEv2Gn6IV5sQuPz6my3S
TgEtH78YDDWHFdEE4b3lQaPAR8NGNvuE0btjpdeR7QoTOAkmg0SaUNqAoqrz80jj
7kdIBtI8XA2CW/oXYcoxHlkqbPNqPAhaRu3YDci8oQ==
=ukYv
-----END PGP MESSAGE-----
fp: 2372651C56E22972C2D9F3F569C8187C9C43754E
unencrypted_suffix: _unencrypted
version: 3.7.1

View File

@ -1,17 +0,0 @@
{ config, ... }:
let
cfg = config.services.ankisyncd;
in
{
services.ankisyncd = {
enable = true;
host = "127.0.0.1";
};
services.nginx.virtualHosts."anki.sbruder.de" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://${cfg.host}:${toString cfg.port}";
};
}

View File

@ -1,76 +0,0 @@
# This serves a local binary cache. If the request comes from my home network,
# it will set its priority higher than cache.nixos.org (which has a priority of
# 40), so local devices get a faster binary cache. If the request coes from
# outside my home network, it will set its priority lower, only store paths
# exclusive to this cache will be substituted.
# This only works well when a host does not change its “location”, since nix
# caches binary caches locally (per-user, also for root!) in
# ${XDG_CACHE_HOME:-$HOME/.cache}/.cache/nix/binary-cache-v6.sqlite and does
# not re-check or invalidate them. Devices that often are not at home should
# ensure that the cached priority is 50 to avoid slow substitutions.
{ config, lib, pkgs, ... }:
let
binaryCachePath = "/data/cache/nix-binary-cache";
in
{
sops.secrets.nix-binary-cache-htpasswd = {
owner = "nginx";
sopsFile = ../secrets.yaml;
};
services.nginx = {
appendHttpConfig = ''
geo $nix_binary_cache_priority {
default 50;
192.168.100.0/24 30;
2001:470:1f0b:abc::/64 30;
}
'';
virtualHosts."nix-cache.sbruder.de" = rec {
enableACME = true;
forceSSL = true;
root = binaryCachePath;
locations = {
"/nix-cache-info" = {
return = "200 \"StoreDir: /nix/store\\nPriority: $nix_binary_cache_priority\\n\"";
};
"/".extraConfig = ''
log_not_found off;
client_max_body_size 5G;
# WebDAV (for uploading)
dav_methods PUT DELETE;
create_full_put_path on; # nar/ does not exist by default
dav_access user:rw group:r all:r;
# same filesystem for temporary files
client_body_temp_path ${root}/.upload-tmp;
limit_except GET {
auth_basic "restricted upload";
auth_basic_user_file ${config.sops.secrets.nix-binary-cache-htpasswd.path};
}
# workaround for nginx dropping parent headers
# see https://github.com/yandex/gixy/blob/master/docs/en/plugins/addheaderredefinition.md
${lib.concatStringsSep "\n" (lib.filter
(lib.hasPrefix "add_header ")
(lib.splitString "\n" config.services.nginx.commonHttpConfig))}
add_header Access-Control-Allow-Origin https://hydra.sbruder.de;
'';
"/nix/store/".proxyPass = "http://localhost:${toString config.services.nar-serve.port}";
};
};
};
systemd.services.nginx.serviceConfig.ReadWritePaths = lib.singleton binaryCachePath;
services.nar-serve = {
enable = true;
cacheURL = "file://${binaryCachePath}";
};
# nar-serve logs multiple lines on every request
systemd.services.nar-serve.serviceConfig.StandardOutput = "null";
}

View File

@ -1,44 +0,0 @@
{ config, lib, pkgs, ... }:
{
services.dnsmasq = {
enable = true;
extraConfig = ''
bogus-priv # do not forward revese lookups of internal addresses
domain-needed # do not forward names without domain
local-service # only respond to queries from local network
no-hosts # do not resolve hosts from /etc/hosts
no-resolv # only use explicitly configured resolvers
cache-size=10000
server=/fritz.box/192.168.100.1
domain=home.sbruder.de
dhcp-range=192.168.100.20,192.168.100.150,12h
dhcp-option=option:router,192.168.100.1
'';
servers = [
"9.9.9.9" # dns.quad9.net
"2620:fe::fe"
"194.150.168.168" # dns.as250.net
];
};
# Make `local-service` work (requires network interface with all addresses)
systemd.services.dnsmasq = {
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
};
services.prometheus.exporters.dnsmasq = {
enable = true;
listenAddress = "127.0.0.1";
leasesPath = "/var/lib/dnsmasq/dnsmasq.leases";
};
networking.firewall.allowedUDPPorts = [ 53 67 ];
networking.firewall.allowedTCPPorts = [ 53 ];
}

View File

@ -1,21 +0,0 @@
{ lib, pkgs, ... }:
{
services.factorio = {
enable = true;
package = pkgs.factorio-headless.overrideAttrs (o: o // rec {
name = "factorio-headless-${version}";
version = "1.1.42";
src = pkgs.fetchurl {
name = "factorio_headless_x64-${version}.tar.xz";
url = "https://factorio.com/get-download/${version}/headless/linux64";
sha256 = "sha256-QpCZBqJY3NU4FIJY3LDungPKBjhR09jKA9FxJpk7QdA=";
};
});
openFirewall = true;
admins = [ "sbruder" ];
game-name = "factorio.sbruder.de";
game-password = "MoinMoin";
};
}

View File

@ -1,75 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.gitea;
in
{
sops.secrets.gitea-mail = {
owner = cfg.user;
sopsFile = ../secrets.yaml;
};
systemd.services.gitea.serviceConfig.SupplementaryGroups = lib.singleton "keys";
services.gitea = {
enable = true;
rootUrl = "https://git.sbruder.de/";
appName = "sbrudergit";
cookieSecure = true;
log.level = "Warn";
lfs = {
enable = true;
contentDir = "/data/gitea/lfs/";
};
enableUnixSocket = true;
ssh = {
clonePort = 2022;
};
database.type = "postgres";
mailerPasswordFile = config.sops.secrets.gitea-mail.path;
settings = {
mailer = {
ENABLED = true;
HOST = "vueko.sbruder.de:587";
FROM = "gitea@sbruder.de";
USER = "gitea@sbruder.de";
};
avatar = {
DISABLE_GRAVATAR = true;
};
server = {
# privacy
DISABLE_ROUTER_LOG = true;
OFFLINE_MODE = true;
# internal ssh server
BUILTIN_SSH_SERVER_USER = "git";
START_SSH_SERVER = true;
SSH_SERVER_HOST_KEYS = "ssh/gitea.ed25519,ssh/gitea.rsa";
};
service = {
DEFAULT_KEEP_EMAIL_PRIVATE = true;
ENABLE_NOTIFY_MAIL = true;
NO_REPLY_ADDRESS = "users.git.sbruder.de";
REGISTER_EMAIL_CONFIRM = true;
};
session = {
PROVIDER = "file";
};
};
};
networking.firewall.allowedTCPPorts = [ cfg.ssh.clonePort ];
services.nginx.virtualHosts."git.sbruder.de" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://unix:/run/gitea/gitea.sock";
};
extraConfig = ''
client_max_body_size 1G; # Git LFS
'';
};
}

View File

@ -1,52 +0,0 @@
{ config, ... }:
let
cfg = config.services.grafana;
in
{
services.grafana = {
enable = true;
# grafana supports sockets, but no permission management (always 660 grafana:grafana)
addr = "127.0.0.1";
domain = "grafana.sbruder.de";
rootUrl = "https://%(domain)s/";
database = {
type = "postgres";
host = "/run/postgresql";
user = "grafana";
};
provision = {
enable = true;
datasources = [
{
name = "Prometheus";
type = "prometheus";
url = "http://${config.services.prometheus.listenAddress}:${toString config.services.prometheus.port}";
isDefault = true;
}
];
};
analytics.reporting.enable = false;
};
systemd.services.grafana.after = [ "postgresql.service" ];
services.postgresql = {
enable = true;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [
{
name = cfg.database.user;
ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; };
}
];
};
services.nginx.virtualHosts."grafana.sbruder.de" = {
enableACME = true;
forceSSL = true;
locations = {
"/".proxyPass = "http://${cfg.addr}:${toString cfg.port}";
};
};
}

View File

@ -1,63 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.hedgedoc;
in
{
services.postgresql = {
enable = true;
ensureDatabases = [ "hedgedoc" ];
ensureUsers = lib.singleton {
name = "codimd";
ensurePermissions = {
"DATABASE hedgedoc" = "ALL PRIVILEGES";
};
};
};
services.hedgedoc = {
enable = true;
configuration = {
host = "127.0.0.1";
port = 3001;
db = {
dialect = "postgres";
host = "/run/postgresql";
#user = "hedgedoc";
database = "hedgedoc";
};
domain = "pad.sbruder.de";
protocolUseSSL = true;
csp.enable = true;
imageUploadType = "filesystem";
uploadsPath = "/data/hedgedoc/uploads";
};
};
systemd.services.hedgedoc = {
after = [ "postgresql.service" ];
preStart = toString (pkgs.writeShellScript "hedgedoc-generate-session-secret" ''
if [ ! -f ${cfg.workDir}/session_secret_env ]; then
echo "CMD_SESSION_SECRET=$(${pkgs.pwgen}/bin/pwgen -s 32 1)" > ${cfg.workDir}/session_secret_env
fi
'');
serviceConfig = {
Environment = [
"CMD_LOGLEVEL=warn"
];
EnvironmentFile = [
"-${cfg.workDir}/session_secret_env" # - ensures that it will not fail on first start
];
};
};
systemd.tmpfiles.rules = [
"d ${cfg.configuration.uploadsPath} 0700 codimd codimd - -"
];
services.nginx.virtualHosts."pad.sbruder.de" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://${cfg.configuration.host}:${toString cfg.configuration.port}";
};
}

View File

@ -1,54 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.hydra;
in
{
services.hydra = {
enable = true;
listenHost = "127.0.0.1";
port = 3003;
hydraURL = "https://hydra.sbruder.de";
notificationSender = "hydra@sbruder.de";
buildMachinesFiles = [
(pkgs.writeText "hydra-build-machines" ''
# hostname system sshKey maxJobs speedFactor mandatory+supportedFeatures mandatoryFeatures
localhost x86_64-linux - 4 1 kvm,nixos-test
'')
];
useSubstitutes = true;
minimumDiskFreeEvaluator = 10;
minimumDiskFree = 10;
extraConfig = ''
store_uri = file:///data/cache/nix-binary-cache?secret-key=${config.sops.secrets.binary-cache-secret-key.path}
server_store_uri = file:///data/cache/nix-binary-cache
upload_logs_to_binary_cache = true
log_prefix = https://nix-cache.sbruder.de/
'';
};
sops.secrets.binary-cache-secret-key.owner = "hydra-queue-runner";
systemd.services.hydra-queue-runner.serviceConfig = {
SupplementaryGroups = lib.singleton "keys";
Nice = 10;
IOSchedulingPriority = 5;
};
# Hydra uses restricted eval, which by default does not work with flakes that
# use git+https inputs
nix.extraOptions = ''
allowed-uris = https://git.sbruder.de/
'';
services.nginx.virtualHosts."hydra.sbruder.de" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://${cfg.listenHost}:${toString cfg.port}";
};
};
}

View File

@ -1,7 +0,0 @@
{
imports = [
./synapse.nix
./mautrix-whatsapp.nix
./go-neb.nix
];
}

View File

@ -1,93 +0,0 @@
{ config, lib, pkgs, ... }:
let
synapseCfg = config.services.matrix-synapse;
in
{
sops.secrets = {
go-neb-overrides.sopsFile = ../../secrets.yaml;
};
users.users.go-neb = {
isSystemUser = true;
group = "go-neb";
};
users.groups.go-neb = { };
services.go-neb = rec {
enable = true;
bindAddress = "127.0.0.1:8010";
baseUrl = "http://${bindAddress}";
config = {
clients = [
{
UserID = "@alertmanager:${synapseCfg.server_name}";
HomeserverURL = synapseCfg.public_baseurl;
Sync = false;
AutoJoinRooms = false;
DisplayName = "Prometheus Alertmanager";
}
];
services = [
{
ID = "alertmanager_service";
Type = "alertmanager";
UserID = "@alertmanager:${synapseCfg.server_name}";
Config = {
webhook_url = "${baseUrl}/services/hooks/YWxlcnRtYW5hZ2VyX3NlcnZpY2U";
rooms = {
"!ceigaGYfREXXSeLFiH:sbruder.de" = {
text_template = "{{ range .Alerts }}{{ if eq .Status \"firing\" }}@room {{ end }}[{{ .Status }}] {{ index .Labels \"alertname\" }}: {{ index .Annotations \"description\" }}\n{{ end }}";
html_template = ''
{{ range .Alerts }}
{{- if eq .Status "firing" }}@room {{ end -}}
{{ $severity := index .Labels "severity" }}
<font{{ if eq .Status "firing" -}}
{{- if eq $severity "critical" }} color="red"
{{- else if eq $severity "warning" }} color="orange"
{{- end -}}
{{- else }} color="green"
{{- end }}>
<strong>{{ if eq .Status "firing" -}}
[firing{{ if ne $severity "" }} - {{ $severity }}{{ end }}]
{{- else -}}
[resolved]
{{- end }}</strong>
</font>
{{ index .Labels "alertname" }}: {{ index .Annotations "description" }} <a href="{{ .GeneratorURL }}">source</a><br/>
{{ end }}
'';
msg_type = "m.text";
};
};
};
}
];
};
};
# Load AccessToken and DeviceID from secret
systemd.services.go-neb = {
serviceConfig = {
RuntimeDirectory = "go-neb";
RuntimeDirectoryMode = "0750";
DynamicUser = lib.mkForce false;
ExecStartPre =
let
baseConfig = pkgs.writeText "config-base.json" (builtins.toJSON config.services.go-neb.config);
in
[
"!${pkgs.coreutils}/bin/install -g go-neb ${config.sops.secrets.go-neb-overrides.path} /run/go-neb/config-overrides.json"
# needs to be run in a shell script for redirection to work
(pkgs.writeShellScript "merge-go-neb-config" ''
${pkgs.jq}/bin/jq \
--slurp \
'. | map(map_values(. | with_entries(.key = (.value.ID // .value.SessionID // .value.UserID)))) | .[0] * .[1] | with_entries(.value = [.value[]])' \
${baseConfig} \
/run/go-neb/config-overrides.json \
> /run/go-neb/config.json
'')
];
};
environment.CONFIG_FILE = lib.mkForce "/run/go-neb/config.json";
};
}

View File

@ -1,78 +0,0 @@
# somewhat adapted from https://github.com/NixOS/nixpkgs/pull/59211
{ config, lib, pkgs, ... }:
let
synapseCfg = config.services.matrix-synapse;
in
let
config = rec {
homeserver = {
address = synapseCfg.public_baseurl;
domain = synapseCfg.server_name;
};
appservice = rec {
hostname = "127.0.0.1";
port = 29318;
address = "http://${hostname}:${toString port}";
provisioning.shared_secret = "disable";
database = {
type = "sqlite3";
uri = "/var/lib/mautrix-whatsapp/mautrix-whatsapp.db";
};
id = "whatsapp";
bot = {
username = "whatsappbot";
displayname = "WhatsApp bridge bot";
avatar = "mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr";
};
};
whatsapp = {
browser_name = "mx-wa";
os_name = "Mautrix-WhatsApp bridge";
};
bridge = {
command_prefix = "!wa";
delivery_receipts = true;
displayname_template = "{{if .FullName}}{{.FullName}}{{else if .Notify}}{{.Notify}}{{else}}{{.Jid}}{{end}} (WA)";
history_sync = {
backfill = true;
};
identity_change_notices = true;
permissions = {
# Only one user since using the name from the address book does not
# work with multiple users
"@simon:${homeserver.domain}" = 100;
};
private_chat_portal_meta = true;
reaction_notices = true;
relay.enable = false;
};
logging.print_level = "info";
};
generatedConfig = pkgs.runCommandNoCC "mautrix-whatsapp-config"
{
buildInputs = with pkgs; [ mautrix-whatsapp ];
}
''
mkdir $out
cat ${pkgs.writeText "mautrix-whatsapp.yaml" (lib.generators.toYAML { } config)} > $out/config.yaml
mautrix-whatsapp -c $out/config.yaml -g -r $out/registration.yaml
'';
in
{
systemd.services.mautrix-whatsapp = {
description = "Mautrix-WhatsApp Service - A WhatsApp bridge for Matrix";
after = [ "network.target" "matrix-synapse.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
DynamicUser = true;
StateDirectory = "mautrix-whatsapp";
WorkingDirectory = "/var/lib/mautrix-whatsapp";
ExecStart = "${pkgs.mautrix-whatsapp}/bin/mautrix-whatsapp -c ${generatedConfig}/config.yaml";
Restart = "on-failure";
};
};
services.matrix-synapse.app_service_config_files = lib.singleton "${generatedConfig}/registration.yaml";
}

View File

@ -1,153 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.matrix-synapse;
fqdn = "matrix.sbruder.de";
domain = "sbruder.de";
in
{
sops.secrets = {
synapse-registration-shared-secret = {
owner = "matrix-synapse";
sopsFile = ../../secrets.yaml;
};
synapse-turn-shared-secret = {
owner = "matrix-synapse";
sopsFile = ../../secrets.yaml;
};
};
systemd.services.matrix-synapse.serviceConfig.SupplementaryGroups = lib.singleton "keys";
services.matrix-synapse = {
enable = true;
server_name = domain;
public_baseurl = "https://${fqdn}";
listeners = lib.singleton {
port = 8008;
bind_address = "127.0.0.1";
type = "http";
tls = false;
x_forwarded = true;
resources = lib.singleton {
names = [ "client" "federation" "metrics" ];
compress = false;
};
};
dataDir = "/data/matrix/synapse";
turn_uris = [
"turns:turn.sbruder.de:5349?transport=udp"
"turns:turn.sbruder.de:5349?transport=tcp"
"turn:turn.sbruder.de:3478?transport=udp"
"turn:turn.sbruder.de:3478?transport=tcp"
];
turn_user_lifetime = "3600000"; # 1h
enable_metrics = true;
# adapted from https://github.com/NixOS/nixpkgs/blob/7e10bf4327491a6ebccbe1aaa8e6c6c0aca4663a/nixos/modules/services/misc/matrix-synapse-log_config.yaml
# - set root.level to WARNING instead of INFO
logConfig = builtins.toJSON {
version = 1;
formatters.journal_fmt.format = "%(name)s: [%(request)s] %(message)s";
filters.context = {
"()" = "synapse.util.logcontext.LoggingContextFilter";
request = "";
};
handlers.journal = {
class = "systemd.journal.JournalHandler";
formatter = "journal_fmt";
filters = [ "context" ];
SYSLOG_IDENTIFIER = "synapse";
};
root = {
level = "WARNING";
handlers = [ "journal" ];
};
disable_existing_loggers = false;
};
max_upload_size = "50M";
extraConfig = ''
# Im okay with using matrix.org as trusted key server
suppress_key_server_warning: true
'';
extraConfigFiles = with config.sops.secrets; [
synapse-registration-shared-secret.path
synapse-turn-shared-secret.path
];
};
services.postgresql = {
enable = true;
# synapse requires custom databse configuration:
# CREATE DATABASE "matrix-synapse" TEMPLATE template0 LC_COLLATE "C" LC_CTYPE "C";
ensureUsers = lib.singleton {
name = "matrix-synapse";
ensurePermissions = {
"DATABASE \"matrix-synapse\"" = "ALL PRIVILEGES";
};
};
};
services.nginx.virtualHosts = {
"${fqdn}" = {
enableACME = true;
forceSSL = true;
locations."/".return = "301 https://chat.sbruder.de";
locations."/_matrix" =
let
listenerCfg = (lib.elemAt cfg.listeners 0);
in
{
proxyPass = "http://${listenerCfg.bind_address}:${toString listenerCfg.port}";
extraConfig = ''
client_max_body_size ${cfg.max_upload_size};
'';
};
};
"${domain}" = {
enableACME = true;
forceSSL = true;
locations =
let
# workaround for nginx dropping parent headers
# see https://github.com/yandex/gixy/blob/master/docs/en/plugins/addheaderredefinition.md
parentHeaders = lib.concatStringsSep "\n" (lib.filter
(lib.hasPrefix "add_header ")
(lib.splitString "\n" config.services.nginx.commonHttpConfig));
in
{
"=/.well-known/matrix/server".extraConfig = ''
${parentHeaders}
add_header Content-Type application/json;
return 200 '${builtins.toJSON {
"m.server" = "${fqdn}:443";
}}';
'';
"=/.well-known/matrix/client".extraConfig = ''
${parentHeaders}
add_header Content-Type application/json;
add_header Access-Control-Allow-Origin *;
return 200 '${builtins.toJSON {
"m.homeserver"."base_url" = "https://${fqdn}";
}}';
'';
};
};
};
}

View File

@ -1,62 +0,0 @@
# This creates a backup of my media files when a specific hard drive is
# hotplugged. The hard drive has a btrfs filesystem inside of a luks container.
# The filesystem can be created with commands similar to this:
# cryptsetup luksFormat --label="fuuko-media-backup-luks" --key-file=/path/to/key /dev/sdb
# mkfs.btrfs -L "fuuko-media-backup" /dev/mapper/media-backup
{ lib, pkgs, ... }:
let
baseDir = "/data/media";
mountPoint = "/mnt/media-backup";
in
{
# Systemd mount units do not support cryptsetup
systemd.services.media-backup-luks = {
after = [ ''dev-disk-by\x2dlabel-fuuko\x2dmedia\x2dbackup\x2dluks.device'' ];
bindsTo = [ ''dev-disk-by\x2dlabel-fuuko\x2dmedia\x2dbackup\x2dluks.device'' ];
unitConfig = {
StopWhenUnneeded = true;
};
serviceConfig = {
Type = "oneshot";
RemainAfterExit = "yes";
ExecStart = "${pkgs.cryptsetup}/bin/cryptsetup open --type luks2 --key-file=${baseDir}/.backup-key /dev/disk/by-label/fuuko-media-backup-luks media-backup";
ExecStop = "${pkgs.cryptsetup}/bin/cryptsetup close media-backup";
};
};
systemd.mounts = lib.singleton {
after = [ "media-backup-luks.service" ];
bindsTo = [ "media-backup-luks.service" ];
unitConfig = {
StopWhenUnneeded = true;
};
what = "/dev/mapper/media-backup";
where = mountPoint;
};
systemd.services.media-backup = {
wantedBy = [ ''dev-disk-by\x2dlabel-fuuko\x2dmedia\x2dbackup\x2dluks.device'' ];
unitConfig = {
RequiresMountsFor = "/mnt/media-backup";
};
script = ''
${pkgs.rsync}/bin/rsync \
--archive \
--delete \
--links \
--partial \
--recursive\
--verbose \
${lib.escapeShellArg baseDir} \
${lib.escapeShellArg mountPoint}
'';
serviceConfig = {
IOSchedulingClass = "best-effort";
IOSchedulingPriority = 7;
Nice = 10;
};
};
}

View File

@ -1,14 +0,0 @@
{
services.nginx.virtualHosts."media.sbruder.de" = {
enableACME = true;
forceSSL = true;
basicAuthFile = "/data/media/.htpasswd";
root = "/data/media/";
locations."=/.htpasswd".return = "403";
};
services.nginx-interactive-index.virtualHosts."media.sbruder.de".locations."/".enable = true;
}

View File

@ -1,193 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.prometheus;
mkStaticTargets = targets: lib.singleton { inherit targets; };
mkStaticTarget = target: mkStaticTargets (lib.singleton target);
in
{
services.prometheus = {
enable = true;
listenAddress = "127.0.0.1";
webExternalUrl = "https://prometheus.sbruder.de";
globalConfig = {
scrape_interval = "15s";
evaluation_interval = "15s";
};
extraFlags = [
"--storage.tsdb.retention.time=90d"
"--web.enable-admin-api"
];
alertmanagers = [
{
static_configs = mkStaticTarget "${cfg.alertmanager.listenAddress}:${toString cfg.alertmanager.port}";
path_prefix = "/alertmanager/";
}
];
alertmanager = {
enable = true;
listenAddress = "127.0.0.1";
webExternalUrl = "https://prometheus.sbruder.de/alertmanager";
configuration = {
global.resolve_timeout = "2m";
route = {
receiver = "matrix";
group_by = [ "alertname" ];
group_wait = "3m";
};
receivers = [
{
name = "matrix";
webhook_configs = lib.singleton {
url = (lib.elemAt
(lib.filter
({ ID, ... }: ID == "alertmanager_service")
config.services.go-neb.config.services)
0).Config.webhook_url;
};
}
];
};
};
scrapeConfigs = [
{
job_name = "prometheus";
static_configs = mkStaticTarget "localhost:${toString cfg.port}";
}
{
job_name = "node";
static_configs = mkStaticTargets [
"fuuko.vpn.sbruder.de:9100"
"mayushii.vpn.sbruder.de:9100"
"sayuri.vpn.sbruder.de:9100"
"vueko.vpn.sbruder.de:9100"
"yuzuru.vpn.sbruder.de:9100"
];
}
{
job_name = "aria2";
static_configs = mkStaticTarget "127.0.0.1:9578";
relabel_configs = lib.singleton {
target_label = "instance";
replacement = "torrent.sbruder.de";
};
}
{
job_name = "fritzbox";
static_configs = mkStaticTarget "127.0.0.1:9133";
}
(
let
listenerCfg = (lib.elemAt config.services.matrix-synapse.listeners 0);
in
{
job_name = "synapse";
static_configs = mkStaticTarget "${listenerCfg.bind_address}:${toString listenerCfg.port}";
metrics_path = "/_synapse/metrics";
relabel_configs = lib.singleton {
target_label = "instance";
replacement = "matrix.sbruder.de";
};
}
)
{
job_name = "dnsmasq";
static_configs = mkStaticTarget (with config.services.prometheus.exporters.dnsmasq; "${listenAddress}:${toString port}");
relabel_configs = lib.singleton {
target_label = "instance";
replacement = "fuuko.home.sbruder.de";
};
}
{
job_name = "hcloud";
static_configs = mkStaticTarget config.services.hcloud_exporter.listenAddress;
}
];
rules =
let
mkAlert = { name, expr, for ? "1m", description ? null }: {
alert = name;
inherit expr for;
annotations = lib.optionalAttrs (description != null) { inherit description; };
};
in
[
(lib.generators.toYAML { } {
groups = lib.singleton {
name = "alert.rules";
rules = map mkAlert [
{
name = "InstanceDown";
expr = ''up{instance!~"(sayuri|mayushii).vpn.sbruder.de:.*"} == 0'';
description = "Instance {{ $labels.instance }} of job {{ $labels.job }} has been down for more than 1 minutes.";
}
{
name = "SystemdUnitFailed";
expr = ''node_systemd_unit_state{state="failed"} == 1'';
description = "Systemd unit {{ $labels.name }} on {{ $labels.instance }} has state failed.";
}
{
name = "NodeHighLoad";
expr = ''sum by (instance) (node_load15) / count by (instance) (node_cpu_seconds_total{mode="system"}) > 2'';
for = "15m";
description = "Node {{ $labels.instance }} is having a per-core load 2 for the last 15 minutes.";
}
{
name = "NodeHighMemory";
expr = ''(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes > 0.9'';
for = "2m";
description = "Node {{ $labels.instance }} is using more than 90% of available RAM.";
}
{
name = "TorrentNoPeers";
expr = "sum by (instance) (aria2_torrent_peers) == 0";
description = "Aria2 instance {{ $labels.instance }} has no peers. There might be a network connectivity problem";
}
];
};
})
];
exporters = {
fritzbox = {
enable = true;
gatewayAddress = "192.168.100.1";
listenAddress = "127.0.0.1";
};
};
};
# get rid of “could not call action: authorization required” every scrape
systemd.services.prometheus-fritzbox-exporter.serviceConfig.StandardOutput = "null";
# exporters that are not part of nixpkgs prometheus infrastructure
services.hcloud_exporter = {
enable = true;
listenAddress = "127.0.0.1:9501";
environmentFile = config.sops.secrets.hcloud_exporter-environment.path;
};
sops.secrets.hcloud_exporter-environment.sopsFile = ../secrets.yaml;
sops.secrets.prometheus-htpasswd = {
owner = "nginx";
sopsFile = ../secrets.yaml;
};
services.nginx.virtualHosts."prometheus.sbruder.de" = {
enableACME = true;
forceSSL = true;
basicAuthFile = config.sops.secrets.prometheus-htpasswd.path;
locations = {
"/".proxyPass = "http://${cfg.listenAddress}:${toString cfg.port}";
"/alertmanager/".proxyPass = "http://${cfg.alertmanager.listenAddress}:${toString cfg.alertmanager.port}";
};
};
}

View File

@ -1,89 +0,0 @@
{ lib, pkgs, ... }:
{
users.users.scan = {
home = "/var/lib/scans";
isSystemUser = true;
group = "scan";
# this is a low-risk account and since the only thing the account can do is
# login to the ftp server from my home network, you can also sniff the
# password since the connection is unencrypted
password = "meeB3laodoo8na3z";
};
users.groups.scan = { };
systemd.tmpfiles.rules = [
"d /var/lib/scans 0755 scan root 7d"
];
sbruder.restic.system.extraExcludes = [ "/var/lib/scans" ];
services.vsftpd = {
enable = true;
writeEnable = true;
localUsers = true;
userlist = [ "scan" ];
extraConfig = ''
# I only want this to be reachable from within my home network. Since
# IPv6 has all ports forwarded, it is disabled here.
listen=YES
listen_ipv6=NO
# users shell is nologin
check_shell=NO
# scans should be readable
local_umask=022
pasv_min_port=30000
pasv_max_port=30009
'';
};
services.nginx.virtualHosts."scan.sbruder.de" = {
enableACME = true;
forceSSL = true;
locations."/" = {
root = "/var/lib/scans";
extraConfig = ''
autoindex on;
allow 192.168.100.0/24;
allow 2001:470:1f0b:abc::/64;
deny all;
'';
};
};
networking.firewall = {
allowedTCPPorts = [ 21 ];
allowedTCPPortRanges = [{ from = 30000; to = 30009; }];
};
systemd.services.scan-converter = {
wantedBy = [ "multi-user.target" ];
script = ''
set -euo pipefail
${pkgs.inotify-tools}/bin/inotifywait -m --include "\.tif$" -e close_write /var/lib/scans | while read path action file; do
echo "Converting ''${file}"
${pkgs.imagemagick}/bin/convert -strip "/var/lib/scans/$file" "/var/lib/scans/''${file%.*}.png"
rm "/var/lib/scans/$file"
done
'';
serviceConfig = {
User = "scan";
Restart = "always";
# systemd-analyze --no-pager security scan-converter.service
CapabilityBoundingSet = null;
PrivateDevices = true;
PrivateNetwork = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectHome = true;
RestrictNamespaces = true;
SystemCallFilter = "@system-service";
};
};
}

View File

@ -1,199 +0,0 @@
{ config, lib, pkgs, ... }:
let
homeDir = "/var/lib/aria2";
downloadDir = "/data/torrent";
sessionFile = "${homeDir}/session";
settings = {
# locations
dir = downloadDir;
# logging
show-console-readout = false;
summary-interval = 0;
# rpc
enable-rpc = true;
# permanent queue
bt-load-saved-metadata = true;
bt-save-metadata = true;
force-save = true;
input-file = sessionFile;
save-session = sessionFile;
save-session-interval = 900; # automatic saving
# network
async-dns-server = "193.138.218.74"; # aria2 does not respect netns resolv.conf
dht-listen-port = 56595;
listen-port = 56718;
interface = "wg-aria";
# limits
max-concurrent-downloads = 65536;
max-overall-download-limit = "6M";
max-overall-upload-limit = "4M";
seed-ratio = 0; # do not stop seeding after reaching ratio
};
toString' = value:
if lib.isBool value
then (if value then "true" else "false")
else (toString value);
configFile = pkgs.writeText "aria2.conf" (lib.concatStringsSep
"\n"
(lib.mapAttrsToList
(k: v: "${k}=${toString' v}")
settings));
mkProxyService = socket: port: {
wantedBy = [ "multi-user.target" ];
after = [ "wireguard-wg-aria.service" ];
partOf = [ "wireguard-wg-aria.service" ];
serviceConfig = {
PrivateNetwork = true;
NetworkNamespacePath = "/run/netns/aria2";
Restart = "always";
ExecStart = "${pkgs.socat}/bin/socat UNIX-LISTEN:${socket},fork,reuseaddr,mode=660,unlink-early TCP:127.0.0.1:${toString port}";
User = "aria2";
Group = "nginx";
# systemd-analyze --no-pager security aria2-rpc-proxy.service
CapabilityBoundingSet = null;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectHome = true;
RestrictNamespaces = true;
SystemCallFilter = "@system-service";
};
};
in
{
users.users.aria2 = {
group = "aria2";
uid = config.ids.uids.aria2;
home = homeDir;
};
users.groups.aria2.gid = config.ids.gids.aria2;
systemd.tmpfiles.rules = [
"d '${downloadDir}' 0775 aria2 users - -"
"d '${homeDir}' 0771 aria2 aria2 - -"
];
sops.secrets.wg-aria-private-key.sopsFile = ../secrets.yaml;
networking.wireguard.interfaces.wg-aria = {
interfaceNamespace = "aria2";
preSetup = "ip netns add aria2 && ip -n aria2 link set lo up";
postShutdown = "ip netns del aria2";
privateKeyFile = config.sops.secrets.wg-aria-private-key.path;
} // (import ../secrets/aria2-wireguard.nix); # potentially sensitive data
environment.etc."netns/aria2/resolv.conf".text = ''
nameserver 193.138.218.74
'';
systemd.services.aria2 = {
description = "aria2 Service";
after = [ "wireguard-wg-aria.service" ];
requires = [ "wireguard-wg-aria.service" ];
wantedBy = [ "multi-user.target" ];
preStart = ''
if [[ ! -e "${sessionFile}" ]]; then
touch "${sessionFile}"
fi
'';
serviceConfig = {
PrivateNetwork = true;
NetworkNamespacePath = "/run/netns/aria2";
Restart = "always";
ExecStart = "${pkgs.aria2}/bin/aria2c --conf-path=${configFile}";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
User = "aria2";
Group = "aria2";
# Increase number of open file descriptors (default: 1024)
LimitNOFILE = 65536;
# systemd-analyze --no-pager security aria2.service
CapabilityBoundingSet = null;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectHome = true;
RestrictNamespaces = true;
SystemCallFilter = "@system-service";
};
};
systemd.services.aria2-rpc-proxy = mkProxyService "${homeDir}/rpc.sock" 6800;
services.aria2_exporter = {
enable = true;
listenAddress = "localhost:9578";
};
systemd.services.aria2_exporter = {
after = [ "wireguard-wg-aria.service" ];
partOf = [ "wireguard-wg-aria.service" ];
serviceConfig = {
PrivateNetwork = true;
NetworkNamespacePath = "/run/netns/aria2";
};
};
systemd.services.aria2_exporter-proxy = mkProxyService "${homeDir}/metrics.sock" 9578;
services.nginx.virtualHosts."torrent.sbruder.de" = {
enableACME = true;
forceSSL = true;
# treated as state
basicAuthFile = "${homeDir}/htpasswd";
locations = {
"/" = {
root = pkgs.AriaNg;
};
"/jsonrpc" = {
proxyPass = "http://unix:${homeDir}/rpc.sock";
proxyWebsockets = true;
};
"/download/" = {
alias = "${downloadDir}/";
extraConfig = ''
autoindex on;
'';
};
"=/metrics" = {
proxyPass = "http://unix:${homeDir}/metrics.sock";
};
};
};
services.nginx.virtualHosts."aria2-metrics" = {
listen = lib.singleton {
addr = "127.0.0.1";
port = 9578;
};
locations."=/metrics" = {
proxyPass = "http://unix:${homeDir}/metrics.sock";
};
};
environment.systemPackages = with pkgs; [
aria2
mktorrent
];
}

View File

@ -1,35 +0,0 @@
{ config, ... }:
let
password = "ymfQkXcEqGuk62S";
in
{
services.mosquitto = {
enable = true;
listeners = [
{
users = {
wordclock = {
acl = [
"readwrite wordclock/color/+"
];
inherit password;
};
};
settings = {
allow_anonymous = false;
};
}
];
};
networking.firewall.allowedTCPPorts = [ 1883 ];
services.wordclock-dimmer = {
enable = true;
mqtt = {
user = "wordclock";
inherit password;
host = "localhost";
};
};
}

View File

@ -1,22 +0,0 @@
# mayushii
## Hardware
ThinkPad P14s AMD Gen2 (≈ T14 AMD Gen2).
* [AMD Ryzen 7 PRO 5850U](https://www.amd.com/en/products/apu/amd-ryzen-7-pro-5850u) (= Ryzen 7 5800U + “PRO Management”)
* 32 GiB DDR4 3200 MHz non-ECC memory
* 1TB Samsung PM981a NVMe SSD
* 1920×1080 IPS 400nits screen
* Realtek RTL8852AE Wireless
Often used docked to a ThinkPad USB-C Dock Gen2 (40AS),
because paying 300€ for a mechanical dock is ridiculous.
## Purpose
It is my daily driver so it does everything (except server stuff obviously).
## Name
Mayuri Shiina is a student from *Steins;Gate*

View File

@ -1,65 +0,0 @@
{ pkgs, ... }:
{
imports = [
./hardware-configuration.nix
../../modules
../../users/simon
];
sbruder = {
games = {
enable = true;
performanceIndex = 8;
};
gui.enable = true;
media-proxy.enable = true;
mullvad.enable = true;
restic.system.enable = true;
unfree.allowSoftware = true;
wireguard.home.enable = true;
};
virtualisation.libvirtd = {
enable = true;
qemu.package = pkgs.qemu_kvm;
};
services.samba = {
enable = true;
securityType = "user";
extraConfig = ''
interfaces = 192.168.122.1
bind interfaces only = yes
map to guest = bad user
load printers = no
printing = bsd
disable spoolss = yes
usershare max shares = 0
acl allow execute always = True
'';
shares = {
qemu = {
path = "/home/simon/.cache/vm-share";
browseable = "yes";
"read only" = "no";
"guest ok" = "yes";
"force user" = "simon";
};
};
};
networking.firewall.trustedInterfaces = [ "virbr0" ];
services.tor = {
enable = true;
client.enable = true;
};
services.privoxy = {
enable = true;
enableTor = true;
};
networking.hostName = "mayushii";
system.stateVersion = "21.05";
}

View File

@ -1,64 +0,0 @@
{ config, lib, modulesPath, pkgs, ... }:
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot = {
kernelModules = [ "kvm-amd" ];
loader = {
grub.enable = false;
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
};
initrd = {
availableKernelModules = [ "aesni_intel" "cryptd" "nvme" "sd_mod" "sdhci_pci" "usb_storage" "xhci_pci" ];
luks.devices = {
root = {
name = "root";
device = "/dev/disk/by-uuid/16d97095-34d2-4422-819c-d1ddc9c3ce1e";
preLVM = true;
allowDiscards = true;
};
};
};
extraModprobeConfig = ''
options thinkpad_acpi fan_control=1
'';
};
fileSystems = {
"/" = {
device = "/dev/disk/by-uuid/cd7ed921-4b59-4de4-b39e-9679571ce034";
fsType = "btrfs";
options = [ "discard=async" "noatime" "compress=zstd" ];
};
"/boot" = {
device = "/dev/disk/by-uuid/861A-D1A2";
fsType = "vfat";
};
};
powerManagement = {
cpuFreqGovernor = "schedutil";
};
services.tlp = {
enable = true;
settings = {
START_CHARGE_THRESH_BAT0 = 75;
STOP_CHARGE_THRESH_BAT0 = 92;
USB_DENYLIST = lib.concatStringsSep " " [
];
};
};
# logind fails to detect that the system is still docked when the external
# monitor is switched off via dpms
services.logind.lidSwitchExternalPower = "ignore";
environment.systemPackages = with pkgs; [
radeontop
];
}

View File

@ -1,52 +0,0 @@
wg-home-private-key: ENC[AES256_GCM,data:ZPPEuIOKCAEv6uN3ZmQpf1SfaQdzUORYBv6u91/rm9g/nxHww6b3umL8eDc=,iv:wtIEEbs6RbINbouW/qc/T1lm4s+5+n27co2AKu2IfTs=,tag:QOpNmYWGYD10DQJtKqIAzw==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2021-10-05T18:14:40Z"
mac: ENC[AES256_GCM,data:Uck/kX7BE3gqpMD8wgsksEX3DKzNSUinSRAPqpafH5UbVfQLYVOD637j7wltrtcHSOLjqGSrSbf6jhql/Ve3yTthYB72cHKcJ1UOk5cTD9xCpUJCx56Eid0yj9UZpifIM3PLRjnqqZFF2TYa/s8HcmsY4uvcN+U5dyXYpS6XYMU=,iv:2mhjUTxjU9xH0wFS0ZbgQ3GYRL+8BQboeQuVBpAQvsI=,tag:ZhAKuPo6iPE8890tkxHdaw==,type:str]
pgp:
- created_at: "2021-10-05T18:14:16Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMAwDgSONkM+d4ARAAvcpLQ4pl2zWfpNnyoi5Vu7Ok6kiQF2UveJQkxkvgQom0
TtvlazVEy7kBebM9sgYz9NtcWlTFTMCXC04gpJz9fGYAyssnZ9+D7J/yekK6vyEY
5vY9Dd6FX9HGOQuG3wAwBr98AgNHB76Rt31LBSUjIzNZj6RdsbakM2GRIRocFB9V
mykpRozkE1ju9l+E3NqnBm65AhjEX9q8W48oyrZLd0lFlfo3Lseda3AlGIMz+PV+
MNZ9jTERJZQStpeenE2u2+cS+tMJZbXGk0QBY3+Clz7fTOBlA30ePiWefy1ix3XG
mIm5WM12GP5cCpLc1mwAJvyNi/kTw4Myfy0+xth9j65nZCOl2xLIAGqgfikcmQoc
/NKs/ijpTwSaqbh3o2vmlmYoif7UkVDxoz/cQKoh9Boa0br7eEI6beKwL2bvDcn9
KBNYBeHftt08+sPrg8hSLGjVSpcES9IH6u1WHUWnQYH9ykN9b2VcFeMVUjjYsyWd
AwO+quTMF0dfo6es6t21/whzE5TrYZQGSAZzaGASPbzk9MKWQ92hJxICPyyFuZFq
NOdWZWRQfYS2Ia9HXqdzcEIiLtLBm4gZ6sZQ/vkv3bBKFcq1rZ2UqfJhsaL9eOsw
QiSOoiVpjOAq6SXLF6yQnTmPZczQV02XSvwtNjBSD3yXAIMsXt5JyIW4bCcEIJvS
XgESvf5cIkUUA/zmoSmiKFNhHDO7X7b9xMPAE4BqnJqFRL5iBkY9Wkwlv+DFOCDw
0W6U4V5dFtnGYMudnjQMp0qtsHeDkfhj/IQGAY7RuBaag7HnmBPAzWnYmgE7DW0=
=Fru9
-----END PGP MESSAGE-----
fp: 47E7559E037A35652DBBF8AA8D3C82F9F309F8EC
- created_at: "2021-10-05T18:14:16Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMA0Sjf6jBUFOzAQ/5AbFqOiaNS2Wy5al/H0AVNbpPNPHYYYUaAiDYitdwNgur
oChxTYVP+h1UVwNhy+5e1XnLpEwJNcLrzfeQgxr21CqBcaSbOzEE7G9/COX0TD7z
pyEP5aup2TmCx8Gzc7Ugjbfiksg1m6EhoZV1k1bsuh5mrFMQqhnhI/xQr0Kehl9E
dggOw6IGfu7rZ77U++AHF4b22ZqR2LuRdhpHAvC4H7qlCXIiRlV2qQBT7ArnaOG5
7b9WxPI+PjJUNdm/O3rv/ooAtdYz+mvsoZJIMuS0ruxKNGGO0SInxY16QFECKixY
n7/q5OmlNTVr4i9++JPSAu0enQsqOscSZm7TctiGF0ekHEn+axRsrMBi8pqEzu08
nHb4HXmf/jkdlYjg/K34I4mec9jy1L7a11y6lfsAab1FnabbKJjgm3jrBMMoM/Fj
hEH7CWpAAvG0+rwJ9EmuVjq1gGbi6Q8mBpmX0g6/hfSao/YWOhXMi8tDmRNeVWpa
eBYhRto2SRB0MhLbOeZyC3UkDASDBIsNgmFz9JTbwLh/opv6anqE7O2sLmKIuXDA
IfLJk+ahm05Fdv3AfbPsWGevo1OzxSOxRYn5cDEuF22rcZNDOuRylLJIkkxF9OzN
XpsgV7aoSYFgG84u1qa59dE+rvKlhSi8xLQm2mZTRB6L6sDZw/gQ0H4AeXCZC1XS
UAF7lyInB6tXrEoNCCIdON9JSrBmSyARMGLoPOX6YqvPV2MQ4OEWf7BZ+SPRgbuI
ZFQLv6hk0fYb0fb8xHarmI8krq7k9dsqYxBZI5DjVaPz
=7LEL
-----END PGP MESSAGE-----
fp: 23EEDF49AAF1B41DCD1CD10F44A37FA8C15053B3
unencrypted_suffix: _unencrypted
version: 3.7.1

View File

@ -0,0 +1,21 @@
# nunotaba
## Hardware
ThinkPad T440 with mods to make it acceptable:
* Touchpad is changed for the T450s, which has physical mouse buttons (I
fucked up during the installation and the touchpad part does not work, so it
does not need to be disabled in software).
* Screen has a resolution of 1920×1080 and has an IPS panel
It is used standalone or in on a docking station that connects it to an
external mouse, keyboard and monitor (Dell U2410).
## Purpose
It is my daily driver so it does everything (except server stuff obviously).
## Name
Shinobu Nunotaba is a student/scientist from *A Certain Scientific Railgun*

View File

@ -0,0 +1,33 @@
{ config, pkgs, ... }:
{
imports = [
./hardware-configuration.nix
../../modules
../../users/simon
];
sbruder = {
cpu.intel.enable = true;
docker.enable = true;
games.enable = true;
gpu.intel.enable = true;
gui.enable = true;
libvirt.enable = true;
media-proxy.enable = true;
restic.enable = true;
ssd.enable = true;
unfree.allowSoftware = true;
wireguard.home = {
enable = true;
address = "10.80.0.4";
};
};
services.tor = {
enable = true;
client.enable = true;
};
networking.hostName = "nunotaba";
}

View File

@ -0,0 +1,43 @@
{ config, lib, modulesPath, pkgs, ... }:
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot = {
kernelModules = [ "kvm-intel" ];
extraModulePackages = [ ];
loader.grub.device = "/dev/disk/by-id/ata-INTEL_SSDSC2KB480G7_PHYS749202D6480BGN";
initrd = {
availableKernelModules = [ "ahci" "ehci_pci" "rtsx_pci_sdmmc" "sd_mod" "usb_storage" "usbhid" "xhci_pci" ];
kernelModules = [ "dm-snapshot" ];
luks.devices = {
root = {
name = "root";
device = "/dev/disk/by-uuid/f3a2fa57-581b-4e95-9a45-d61cda9edc54";
preLVM = true;
allowDiscards = true;
};
};
};
};
fileSystems = {
"/" = {
device = "/dev/disk/by-uuid/8937d1ac-23cb-456f-9c16-e348acc66bb7";
fsType = "ext4";
};
"/boot" = {
device = "/dev/disk/by-uuid/da2e90cc-1e0c-4691-8807-5d2f4858df6e";
fsType = "ext2";
};
};
swapDevices = [
{ device = "/dev/disk/by-uuid/b9ad2d56-fee0-49df-98c1-00d93d991b9f"; }
];
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
}

View File

@ -5,16 +5,13 @@
HP Z440 workstation.
* [Intel Xeon E5-1620 v4](https://ark.intel.com/content/www/us/en/ark/products/92991/intel-xeon-processor-e5-1620-v4-10m-cache-3-50-ghz.html)
* 16 GiB DDR4 2400 MHz ECC memory
* 250GB Samsung 970 Evo Pro NVMe SSD
* 16 GiB DDR4 ECC memory
* 256GB micron SSD
* 2TB Toshiba HDWA120 HDD
* Sapphire Nitro+ Radeon RX 480
## Purpose
Tasks that benefit from parallel computing, require a decent amount of GPU
power or possibly even both.
FIMXE
## Name

View File

@ -1,4 +1,4 @@
{ config, lib, pkgs, ... }:
{ config, pkgs, ... }:
{
imports = [
@ -8,90 +8,31 @@
];
sbruder = {
games = {
enable = true;
performanceIndex = 8;
};
cpu.intel.enable = true;
docker.enable = true;
games.enable = true;
gpu.amd.enable = true;
gui.enable = true;
libvirt.enable = true;
media-proxy.enable = true;
mullvad.enable = true;
restic.system = {
restic = {
enable = true;
extraPaths = [
"/data"
];
};
ssd.enable = true;
unfree.allowSoftware = true;
wireguard.home.enable = true;
};
virtualisation.libvirtd = {
enable = true;
qemu.package = pkgs.qemu_kvm;
wireguard.home = {
enable = true;
address = "10.80.0.5";
};
};
services.tor = {
enable = true;
client.enable = true;
};
services.privoxy = {
enable = true;
enableTor = true;
};
services.samba = {
enable = true;
securityType = "user";
extraConfig = ''
interfaces = 192.168.122.1
bind interfaces only = yes
map to guest = bad user
load printers = no
printing = bsd
disable spoolss = yes
usershare max shares = 0
acl allow execute always = True
'';
shares = {
qemu = {
path = "/data/cache/win10/shared";
browseable = "yes";
"read only" = "no";
"guest ok" = "yes";
"force user" = "simon";
};
};
};
networking.firewall.trustedInterfaces = [ "virbr0" ];
networking.hostName = "sayuri";
system.stateVersion = "20.03";
specialisation = {
foldingathome.configuration = {
services.foldingathome = {
enable = true;
user = "sbruder";
};
};
intel-sucks.configuration = {
# https://make-linux-fast-again.com/
boot.kernelParams = [
"l1tf=off"
"mds=off"
"mitigations=off"
"no_stf_barrier"
"noibpb"
"noibrs"
"nopti"
"nospec_store_bypass_disable"
"nospectre_v1"
"nospectre_v2"
"tsx=on"
"tsx_async_abort=off"
];
sbruder.gui.enable = lib.mkForce false;
};
};
}

View File

@ -8,14 +8,14 @@
boot = {
kernelModules = [ "kvm-intel" ];
extraModulePackages = [ ];
loader.grub.device = "/dev/disk/by-id/nvme-Samsung_SSD_970_EVO_Plus_250GB_S4EUNJ0N412342P";
loader.grub.device = "/dev/disk/by-id/ata-MTFDDAK256TBN-1AR15ABHA_UFZMQ01ZR50NMM";
initrd = {
availableKernelModules = [ "aesni_intel" "ahci" "ehci_pci" "nvme" "sd_mod" "sr_mod" "usb_storage" "usbhid" "xhci_pci" ];
availableKernelModules = [ "ahci" "ehci_pci" "sd_mod" "usb_storage" "usbhid" "xhci_pci" ];
kernelModules = [ "dm-snapshot" ];
luks.devices = {
root = {
name = "root";
device = "/dev/disk/by-uuid/1607bb2a-329b-4252-b11a-b43eb6b7bf0c";
device = "/dev/disk/by-uuid/d7e4d213-8a13-4059-a011-0f68081e86d8";
preLVM = true;
allowDiscards = true;
};
@ -25,56 +25,29 @@
fileSystems = {
"/" = {
device = "/dev/disk/by-uuid/9e6b279e-6995-44da-b673-21b9e23a5278";
fsType = "btrfs";
options = [ "discard=async" "noatime" "compress=zstd" ];
device = "/dev/disk/by-uuid/024e31ab-aa98-4070-95be-7980043541ac";
fsType = "ext4";
};
"/boot" = {
device = "/dev/disk/by-uuid/7b8b75d2-f779-4a49-b09d-b2a1bbd801bb";
device = "/dev/disk/by-uuid/c5bde64b-c629-438d-a78b-c4341796dae9";
fsType = "ext2";
};
"/data" = {
device = "/dev/mapper/data";
fsType = "btrfs";
options = [ "compress=zstd" ];
encrypted = {
label = "data";
enable = true;
blkDev = "/dev/disk/by-uuid/7f4ba71e-3aca-4294-b37f-49f37b584dbd";
keyFile = "/mnt-root/root/luks-data";
};
};
"/data/ssd" = {
device = "/dev/mapper/data-ssd";
fsType = "btrfs";
options = [ "discard=async" "noatime" "compress=zstd" ];
encrypted = {
# !!! HACK
label = "data-ssd --allow-discards";
enable = true;
blkDev = "/dev/disk/by-uuid/41baa168-7fa0-4eb3-b314-50766ddf126d";
keyFile = "/mnt-root/root/luks-data";
blkDev = "/dev/disk/by-uuid/576088d4-9aae-4159-a028-feadb2621a1a";
keyFile = "/mnt-root" + toString <secrets/luks-data>;
};
};
};
swapDevices = [
{ device = "/dev/disk/by-uuid/2774d182-ddc9-4d79-886e-995fcd60a88a"; }
{ device = "/dev/disk/by-uuid/78f5277f-a6e5-4297-99cd-d3ea5de5317e"; }
];
powerManagement.cpuFreqGovernor = lib.mkDefault "performance";
# GPU
hardware.opengl.extraPackages = with pkgs; [
rocm-opencl-icd
];
environment.systemPackages = with pkgs; [
clinfo
radeontop
rocm-smi
];
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
}

View File

@ -1,51 +0,0 @@
wg-home-private-key: ENC[AES256_GCM,data:0KVRmI3QrtLF5rPwL1XjVcI1q3UT8iJojXrzXhnvdyDiDAh6zk1ppPwZ/tM=,iv:CWkCy9EBT7zubB9BsnIp95fdc1/aSzBzBcgjWaiROzE=,tag:beDPXpB/L2c3+jwoJvKJwg==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
lastmodified: '2021-04-10T09:42:48Z'
mac: ENC[AES256_GCM,data:kKi9fAbikpohqIUEBR8c5ge0/fStxkrnWXfVhPvQMMeMO+rN/UPHpHJJMCC/v6TjFMC5ckTKTBflpGWL7xYiREoKONLIx9tMtaH02NrTs/MxVJZ4Ji+GKG0TY8mKGfidoJ4tM6a+8Yk1kgugeePmRXwCJDQKxQyEFyZ3BNKMxcA=,iv:l0OmGCg+DTs9KuFj2ZdW5DDH/0kKxjjX3ej43+X9x5c=,tag:/x8CigyZZJQIV3ZvqqVeXg==,type:str]
pgp:
- created_at: '2021-04-10T09:42:21Z'
enc: |
-----BEGIN PGP MESSAGE-----
hQIMAwDgSONkM+d4ARAA491uKx1mGdZ4QpjGkVeS5O8UowNdiLAvSnBZ31BGbzQc
MrGffPpaDJgjxRfZ4yaGVra8OKOsGg5gAinTc+SCNaHjhIqKFpyQbKjFUDGlu4RW
9flBowWQzz0VP475zxTALQ2i9ZrDdAIBMtycA3XdcZx241h4Ty5gvnB8WIqNp0+n
9RpOtK4jEZ+SSJXSGlI2RR+3cEI863N0PidepFf4wsqKhWvv34p9kQ3rVCt8VTMG
pPelbcxLdx6JfVXFKHSKjJApW+cOUcaVwOU27GefWHclanZWMOYsl16+eGKnmSqB
sTiH7z9o0khVxU5vVq6+q63Xu9reaBoAHIq/tTwpTswxGhAoY4CXbPqK1pVFcnKV
RfIxkjYffYR9x5W1zWuLoVwC3ueknGWj6g79aMVtcC8lJoRWT/w+GOdwW7lJGex1
W56n2+jcnnWtL2ljvUz3AuoJlx3dluquX1Q7H/76U8Gy0FN2TzgBoQw0jo6kvnX9
BDLzN/mtA7ph0oWDMCdDSKMW3OBWg3C9Ak+nmV67mIDnysNRfT93fi2OJ7Y5Tb1p
KuoodOOo7BqS8hbiS9G4ZUImGECb+GlivwuuoJ7LPrEPdvn87cWzsjDimTyQLgPi
RlFPVpw5nsVy8UihVvs/tj7LX99O4B1NNxXlW0Yj1qgcOhPBpvDcNms3o9GK+cDS
XgGalgUfb4BNzDclTwNYVILdNYM9AG9Ic5iJCZDNVtUXN65ptHHlCtiut08hqbFV
2+mMRJvH5gRTI1l+ZDAoHRV2LgWcn5s7xjENksx28xes9qH94GhWFK+b0yeoMKw=
=XxbY
-----END PGP MESSAGE-----
fp: 47E7559E037A35652DBBF8AA8D3C82F9F309F8EC
- created_at: '2021-04-10T09:42:21Z'
enc: |
-----BEGIN PGP MESSAGE-----
hQIMA2UzePEMpuAKAQ/8DzlMIWH7nDMIeM8HlDckfzeGgYhzr6lJ40vjtYtNqt3j
OF3i+6eaBX/SMsqStk7zLj53sNp++pCGev+TZV+1c+yJd4t8fllLTuRh2rfPXONT
Pehu3VhsudOjXKxBJcWmyfnPhtLjtIxdKEQpVgLFiEbbDW+OCSn1RveSiQ63/pyd
Su0BNYGmpF89/jEA1ttfknhxd69wsuBKGrxQc9P4ZPQvZajnbhQ2TbLeuLnub6yb
QTUNbJkAofw19AgBXY77AX+qreYq4esrAMDsz8ICnisPSO6g4FJ2feMc0Tvf5fwA
B0janl3G6D1znUG88tjsjUwv8/x/MHsGFJQvBLm4vqLOFoPDaJ9cO0n1Pv5uFtQB
XEwFFgkw9TY1gwsR2eJE/4qSiFaW1JYBHx70/Wyn1ZlJMmdUVh00RhY7Xjn3LMkj
JiA+LxvzbTglsMSvkswPbIfUUmB4Ws42P3fF55hCXkxd8jj0NjxByrfFy0VXNgJQ
KVYtcQS4ZWXyko+yllEV2TbxmTQilaBEUUdty4hYaoLtSX0jh3s8ZVN9jTv7SPcs
VhURedXKmtzogujft1wN8lcqzVGQhWHws2qjOMEiMmeyslooUptg7FkBt/Qw6z5j
rlJvWeudR20LCHjjCJnPl/eoNEkQkpOeb5kz4NV7n1okA0jEcOMBbG3+rWiX+JXS
UAEGnN0ClALycCU8Fj9lnswEd5LP20ohZUbzk30K2K0bqRregxoY+UMWAQ1asSdK
Xd4DYz27BFFPHmrpM1F5Gbxhvy+NiFYNu7+2DCkuLGNj
=w8xW
-----END PGP MESSAGE-----
fp: 17FEEBB45E4245330507C960653378F10CA6E00A
unencrypted_suffix: _unencrypted
version: 3.6.0

View File

@ -1,15 +0,0 @@
# vueko
## Hardware
[Hetzner Cloud](https://hetzner.com/cloud) CX11 (1 vCPU, 2 GB RAM, 20 GB SSD).
It has no swap, since the disk is already small enough.
## Purpose
It provides services that should not be down that often and dont require much
disk space.
## Name
Vueko is a character from *Made in Abyss*

View File

@ -1,119 +0,0 @@
{ config, lib, pkgs, ... }:
{
imports = [
./hardware-configuration.nix
../../modules
./services/coturn.nix
./services/element-web.nix
];
sbruder = {
nginx.hardening.enable = true;
restic.system.enable = true;
wireguard.home.enable = true;
full = false;
mailserver = {
enable = true;
fqdn = "vueko.sbruder.de";
domains = [
"kegelschiene.net"
"sbruder.de"
];
users = import ./secrets/mail-users.nix;
rejectSenders = import ./secrets/mail-reject-senders.nix;
};
};
networking.hostName = "vueko";
system.stateVersion = "20.09";
# sadly, too many (legitimate) mail servers have broken dnssec on reverse
# lookups
services.resolved.dnssec = "false";
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts = {
"vueko.sbruder.de" = {
enableACME = true;
forceSSL = true;
default = true;
root = pkgs.sbruder.imprint;
};
"dav.sbruder.de" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://localhost:5232";
};
"mumble.sbruder.de" = {
enableACME = true;
forceSSL = true;
};
"bangs.sbruder.de" = {
enableACME = true;
forceSSL = true;
locations."/".proxyPass = "http://localhost:8000";
};
};
};
networking.firewall.allowedTCPPorts = [
80 # HTTP
443 # HTTPS
];
services.radicale = {
enable = true;
settings = {
auth = {
type = "htpasswd";
htpasswd_encryption = "bcrypt";
htpasswd_filename = toString (pkgs.writeText
"radicale-htpasswd"
(lib.concatMapStringsSep
"\n"
({ address, passwordHash, ... }: "${address}:${passwordHash}")
config.sbruder.mailserver.users));
};
};
};
sops.secrets.murmur-superuser = {
owner = config.users.users.murmur.name;
sopsFile = ./secrets.yaml;
};
users.users.murmur.isSystemUser = true; # Infinisils module does not set that
services.murmur = {
enable = true;
openFirewall = true;
superuserPasswordFile = config.sops.secrets.murmur-superuser.path;
acmeDomain = "mumble.sbruder.de";
config = {
bandwidth = "128000";
obfuscate = true;
logfile = ""; # log to stdout
channelname = ''[ \\-=\\w\\#\\[\\]\\{\\}\\(\\)\\@\\|]+'';
username = "[-_a-zäöüß]+|SuperUser";
};
};
services.bang-evaluator = {
enable = true;
listenAddress = ":8000";
};
}

View File

@ -1,49 +0,0 @@
{ config, lib, pkgs, modulesPath, ... }:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot = {
kernelModules = [ ];
extraModulePackages = [ ];
kernelParams = [ "ip=dhcp" ];
initrd = {
availableKernelModules = [ "aesni_intel" "ata_piix" "virtio_pci" "xhci_pci" "sd_mod" "sr_mod" ];
kernelModules = [ ];
network.enable = true; # remote unlocking
luks.devices."root".device = "/dev/disk/by-uuid/9d3f544f-d502-4788-8187-1378a9ee0103";
};
loader.grub.device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-0-0-0";
};
fileSystems = {
"/" = {
device = "/dev/disk/by-uuid/cad3325d-775d-4771-bb2d-7beaff9dbaf1";
fsType = "ext4";
};
"/boot" = {
device = "/dev/disk/by-uuid/52c65d2f-2208-48aa-9d0a-592bca2ecfe3";
fsType = "ext2";
};
};
networking.useDHCP = false;
networking.usePredictableInterfaceNames = false;
systemd.network = {
enable = true;
networks = {
eth0 = {
name = "eth0";
DHCP = "yes";
domains = [ "sbruder.de" ];
address = [ "2a01:4f8:1c1c:4397::/64" ];
gateway = [ "fe80::1" ];
};
};
};
# no smart on qemu disk
services.smartd.enable = false;
}

View File

@ -1,54 +0,0 @@
murmur-superuser: ENC[AES256_GCM,data:jTVEa1KmbGAIxxFS2/uIlDCnnJTtGmKFZQ==,iv:YJIfcXlgKEwIRzFEY94dgReNjWZqLAqL0Rb6TG4IHIE=,tag:MVzaRkb24QyyNyFCEMwmzQ==,type:str]
wg-home-private-key: ENC[AES256_GCM,data:/RHNF6Zw6CTWa9ahUhGWRfkR8KIj+HdqUIojA1w6HQBFbZ/+Vo+CcYTYO5I=,iv:2sDH1P3VRjmLw6Ilkq0rw/hossHrNWP5uRvX9yr5fLE=,tag:KIT5GCfXuhg6RjA8+Nmtnw==,type:str]
turn-static-auth-secret: ENC[AES256_GCM,data:Nz94xw5sBuAgEqVpwiV44Rd3km16H46X6jVf2gzE+mbbVt2TXExv/7yegQtXI++eBo6q4wbpOfxwl0b1Pvsa/A==,iv:HSdqj43Vmq5McWAbMoxeNUa38UD75Xe4PJEwY5mKjOQ=,tag:cFpFsVwhisWt7JMMzJemCA==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2021-12-01T16:49:21Z"
mac: ENC[AES256_GCM,data:wLy9If4/YdAVILwz1vSzCQsjG0U8Z2GvpME/+xW9pS/xmKoXTwaxP2QQpy8ReTmtikpbKS327j5pz2dSMiweqaUFSVb1nIEvUFxV4PKnxf5ubJalPZAGa82Cw0aassMKz0IAd8rDF/xK9RoB3ayRluYKAP/qnbEcFrys0BokGE0=,iv:Yw3tG1J135QImJqXEGrpSq3k8Lo++uUXfEKmCCNCpDg=,tag:FChnsJ1qIzalpVypMIilrg==,type:str]
pgp:
- created_at: "2021-04-06T11:13:54Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMAwDgSONkM+d4ARAAxn8UVtRKn0s+wpuUBpk3cCwSSa3te4BjHshyNrI3TyZ9
A2jEVz7xfZXItD5VMs9cZmwhm5kD5qC+2qFauwAnQA8JVn5pCKL1gVxGZURZHgPe
eLON75sxWCt6+A+HCXvl8x8ay2ZMSgQ3N+SSuqrihMKe0UcsngzAJQS4qIUPIrQd
YQYkm2Nf6n1Ya+t05W0CRqyHLLkwObOF0OWN/t8wvBOh4HY2UCRqvXqSEz6nCb06
8jDfy6GLhJBjSMV5000/GTvnbVNH11vYjqq0U/2k33HYD/ddX2TPRarWKQsWi8Fe
QYYMjU/zIubNQ1y2Iv89zzpd7DBVFlnCkjnSIjxop+eR4Kk8EUkJnGFHlRek67lc
k9le8sdlBTYBahT48igpKWfxrZ3bky27O39TLY7luLAXxpjWTGZ//8WD3eJyiY9d
k/TmI7ZLLtR42NKeD/anVmHpSf/rHtgHWwYm1m0Qz0/mvKWhZbdkFTPGWMPVAPNu
hBiBjuXd1Gt8ekKr3jZxLR4uRCzzeCA/zXib4x7HvYs/9cLib2UblHsB2hLYwZQ8
ah59+O51SrcJWcq56kRhwKbrqh6Oui/KCXUSTdbO2auwtzBxUMmcbJAZV5cxRdtA
eD9RXW8WfXVtcmvJ+B9Ab52+RfdYmd/bVpljLPY1kmUEKZG08jDfH08kAtcScyLS
XgG0mxcyhD+ZiGIeLgIPUwFC0UT8FT2V0+VAAso1CVH+iIzdF+9BiGPpc2usoOiY
XDcaU74seCR/EeiuMWfEeNasu6EULEG+AKOnG9s8zoPp5730EG9v8r4q7ma89jc=
=JlIF
-----END PGP MESSAGE-----
fp: 47E7559E037A35652DBBF8AA8D3C82F9F309F8EC
- created_at: "2021-04-06T11:13:54Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMAzy5uO/X/tdJAQ/9Hx6h7IIjr4vwFPC3UCx07rt/lljWHwqA8d8bN3VIcVWJ
39doJ3DigerCeZWZo/5Wvdm1TBLnbvnQndl+7EcP5mbAuGUmNo2VajTBOkFoySLa
A6g0HwkztuftjtxQV2ICunw1NEsqBCWlNKziGKBjEzsDgOuXLzIaN5ArJAkiUFel
kH8jGyHCP6W+nplHE1zOD20SA/oIyRfLW1m+G7d8KU6EuluaPSgASocS6t4oGtsG
gnApj6WwWOdM3tDefxtYxa/PlPDXo4gj+Dhak6mOMK88UW/wrDC/f4fYL9JrILmT
ImjtA+BIWCI9nLkeo3FTTFhtfr+evOhCsLc8qGL/NMCVZOXB0gK7rpCsReBRQS09
4t2KGI1Jti01rNFYvdTN16o59+oF0DoFYnE2dXHAnBA4jmWt+9eDqd5TPmlsuIyr
XBiqBcKK+1z0/3ad7nv7vb8jOYkUjKasJl+qhLUaUD5ehojfaCawDMUVia7Y2k72
yS77m3m/hCEq0vVvUvMev7hvSTKbfQy3gQkjcnWGavbFfdz64pVBI/KgSJPBM5YE
1VFRFZIf30wOF9Xlt++9Cc6xFMQH9JVLG/WouK5On4mfdWwcfnMLgpu83qmYtS6b
30hYAuuqKUwWDMbZtXsYOrfb6HXGqs0mtBfpJzgFaiZyHyIVVhb/blXF4ML4dfnS
UAGUryszfSsH+ag2oerNKEaDFmgdktmL0FdpP3ycf2qVkMmBNbTpTf2BZaVPcrzF
mSfsOU6k+KcWtXYpurZr31zUVK626Re0fsr5XbPSj+9G
=Grqu
-----END PGP MESSAGE-----
fp: BB046D773F54739757553A053CB9B8EFD7FED749
unencrypted_suffix: _unencrypted
version: 3.7.1

View File

@ -1,78 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.coturn;
fqdn = "turn.sbruder.de";
ipAddresses = [ "195.201.139.15" "2a01:4f8:1c1c:4397::" ];
in
{
sops.secrets.turn-static-auth-secret = {
owner = "turnserver";
sopsFile = ../secrets.yaml;
};
services.coturn = {
enable = true;
# config adapted from synapses turn howto:
# https://github.com/matrix-org/synapse/blob/develop/docs/turn-howto.md
use-auth-secret = true;
realm = fqdn;
# the NixOS module does not support loading the secret from a dedicated file
static-auth-secret-file = config.sops.secrets.turn-static-auth-secret.path;
no-tcp-relay = true;
cert = "/run/turnserver/fullchain.pem";
pkey = "/run/turnserver/key.pem";
min-port = 49160;
max-port = 49200;
listening-ips = ipAddresses;
relay-ips = ipAddresses;
no-cli = true;
extraConfig = ''
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
user-quota=12
total-quota=1200
'';
};
systemd.services.coturn = {
after = [ "acme-finished-${fqdn}.target" ];
serviceConfig = {
ExecStartPre = lib.singleton "!${pkgs.writeShellScript "coturn-setup-tls" ''
cp ${config.security.acme.certs."${fqdn}".directory}/{fullchain,key}.pem /run/turnserver/
chgrp turnserver /run/turnserver/{fullchain,key}.pem
''}";
};
};
security.acme.certs."${fqdn}".postRun = ''
if systemctl is-active coturn; then
systemctl --no-block restart coturn
fi
'';
services.nginx.virtualHosts."${fqdn}" = {
enableACME = true;
forceSSL = true;
};
networking.firewall = {
allowedTCPPorts = with cfg; [ listening-port alt-listening-port tls-listening-port ];
allowedUDPPorts = with cfg; [ listening-port alt-listening-port tls-listening-port ];
allowedUDPPortRanges = lib.singleton {
from = cfg.min-port;
to = cfg.min-port;
};
};
}

View File

@ -1,53 +0,0 @@
{ lib, pkgs, ... }:
let
# This uses
# https://github.com/vector-im/element-web#configuration-best-practices
# but allows to disable the frame-ancestors rule for /usercontent/.
mkSecurityHeaders = withFrameOptions: ''
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header X-XSS-Protection "1; mode=block";
'' + lib.optionalString withFrameOptions ''
add_header Content-Security-Policy "frame-ancestors 'none'";
'' + lib.optionalString (!withFrameOptions) ''
add_header Content-Security-Policy "frame-ancestors 'self'";
'';
in
{
services.nginx.virtualHosts."chat.sbruder.de" = {
enableACME = true;
forceSSL = true;
root = pkgs.element-web;
extraConfig = mkSecurityHeaders true;
locations."/usercontent/".extraConfig = mkSecurityHeaders false;
# nixpkgss override mechanism doesnt allow overriding of all options
locations."=/config.chat.sbruder.de.json".alias = pkgs.writeText "config.chat.sbruder.de.json" (lib.generators.toJSON { } {
default_server_config = {
"m.homeserver" = {
base_url = "https://matrix.sbruder.de";
server_name = "matrix.sbruder.de";
};
};
showLabsSettings = true;
branding = {
authFooterLinks = [ ];
};
piwik = false;
defaultCountryCode = "DE";
settingDefaults = {
"UIFeature.feedback" = false;
"UIFeature.shareSocial" = false;
"UIFeature.identityServer" = false;
"UIFeature.thirdPartyId" = false;
};
disable_custom_urls = true;
jitsi.preferredDomain = "meet.jalr.de";
disable_guests = true;
disable_3pid_login = true;
desktopBuilds.available = false;
});
};
}

View File

@ -1,18 +0,0 @@
# yuzuru
## Hardware
[Hetzner Cloud](https://hetzner.com/cloud) CX11 (1 vCPU, 2 GB RAM, 20 GB SSD).
It has no swap, since the disk is already small enough.
## Purpose
It provides privacy-friendly proxies/alternatives to popular web services:
* Invidious
* Libreddit
* Nitter
## Name
Yuzuru Nishimiya is a character from *A Silent Voice*

View File

@ -1,40 +0,0 @@
{ config, lib, pkgs, ... }:
{
imports = [
./hardware-configuration.nix
../../modules
./services/invidious
./services/libreddit.nix
./services/nitter.nix
./services/sbruder.xyz
./services/schabernack.nix
];
sbruder = {
nginx.hardening.enable = true;
wireguard.home.enable = true;
full = false;
trusted = false;
};
networking.hostName = "yuzuru";
system.stateVersion = "21.05";
networking.firewall.allowedTCPPorts = [ 80 443 ];
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
};
services.journald.extraConfig = ''
MaxRetentionSec=1week
'';
}

View File

@ -1,39 +0,0 @@
{ config, lib, pkgs, modulesPath, ... }:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot = {
initrd.kernelModules = [ "nvme" ];
loader.grub.device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-0-0-0";
};
fileSystems = {
"/" = {
device = "/dev/disk/by-uuid/b8ceb0bf-1a67-484b-bf57-c16653c23716";
fsType = "btrfs";
options = [ "discard=async" "noatime" "compress=zstd" ];
};
};
networking = {
useDHCP = false;
usePredictableInterfaceNames = false;
interfaces.eth0 = {
useDHCP = true;
ipv6.addresses = lib.singleton {
address = "2a01:4f9:c010:e4a7::";
prefixLength = 64;
};
};
defaultGateway6 = {
address = "fe80::1";
interface = "eth0";
};
};
# no smart on qemu disk
services.smartd.enable = false;
}

View File

@ -1,53 +0,0 @@
invidious-extra-settings: ENC[AES256_GCM,data:sWvf8ASNUTmdRj9HTsXCkPDg0yQ+Hc+ddnHst72pGBKq0403o5erMzudPm5TVvTEzHeeNDB5d+lTt760s6S2diUMc8l/k3G8Z9loYf0Dpx7o,iv:vqyzZ2B4WQB7AmGDp64nu+Xi+6Jxm6m7D3SUfYq0DZs=,tag:aeQQLerfBEjkpi1NW1x2jw==,type:str]
wg-home-private-key: ENC[AES256_GCM,data:KIUvsIhz2Rc4uHRQla714xfOxL9ke1WzRAbXVTDd6UyNkYQkuYIxIpmXQw4=,iv:usnONR35DtIVH2CV4tGSBz5FsZyMlEDzSQiYLDQLRnw=,tag:M1V4HhtByXogMacjajl1iw==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2021-09-08T16:21:04Z"
mac: ENC[AES256_GCM,data:8Q52a8+6mO/LCjNR7yo4olqz8fJIqus7XUZ6FtRzzlEGeYvkBD6zFuz0QJBUl8gRtmj04tQWUn4fEKz8LApSluHXHoBv4/WVBNm/vL9T2k7SiAJmxhbU5wZmNt+Hg++Kvn8yZ6KXgpG6KVl5qu+/CHuJu2m39AvpTj9NJ+ThCUc=,iv:r037pF9rVUqe87+D7pVjxqgFM/hFALSWHFx8kB/fXFk=,tag:GsA95+KyajrKb5XMpVOB2g==,type:str]
pgp:
- created_at: "2021-09-08T16:11:14Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMAwDgSONkM+d4ARAAhB2PfDQ+KeTI22tc2i4Bc5mVUMDHVpUFn81GzEubwrL0
xKqhDgCYfOogahJ7nvor/kLo0YSQuNs8mSJEgnBVnC4GnzeTQucJ5y8Ke/erBV0P
xscrZSINv4XtUllGFKc6LcKC+J9sbEcjDUMLwTiMBMcnhjm6mjOkT46ldIwXfnVq
vbKaVvUj0U/6awt0f/mqmce8PNfHzJ6rubcEEplBTLG/Qu+tmYFNVcWtsmP21SCt
u3Va9JeKmkIa83MY1khtnpSA2rnUa/acZL7vTRTcpCh8qvShtfoMrn9BKTjFhV6i
ggrkZKf4StJ+A1wgqw2IbwTH+M+5FM5loI4/9xQnkPkyiJIQByZXwQP2/EmuFpPE
sF5UByFTrpC/d7kN7R/xXFcGDIf384RM7Ia4W4XleyKUJ4XHWDkecFU1oT1kLcsA
kIYNgjEq4TSAVJMCKa4q3fQilaJ0K27Bvs3p90brzVEnM128k6eavpkrcjojs0JU
mV3ixEcS9OBwFfmQolekEt9TJebGNVmzg89TAQ3xn3DAJJPtBsmgM1LliJ39/ev3
SeO1rQPBWaxurKksWsDoqcqUtB0r+yR/flfh+Lr+iAgi+fS4W67WwcPm/9SENlUV
8OJ/YEkFxhBGiwJEudIGXQ965Z7+wSbpn1ILUaEvGvWvuOg1L6KjCUVbIbH92fjS
XAETVqe2zqU2IENVIY/HiMfUQG58M+CVytaWr4zyQ9X4Fc9BmvmjUgSn/4d/LdU3
kDT/tDL1fvdX1prXIGUseScSQGPxOamWFB3TPqzWdjhvbkEtT8wp8FqKP/Es
=rPPP
-----END PGP MESSAGE-----
fp: 47E7559E037A35652DBBF8AA8D3C82F9F309F8EC
- created_at: "2021-09-08T16:11:14Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQIMA2dFplKjEYbbARAAyvcLSp8ktZ/dqVROfa+xeeIFt9J5EGREnAgES2h9wy8m
21tsQWPajIwD3H52XW6Z1s0nxG8qUe1bz9RWvd51sonmZZobezagr9YfDMTMji8Z
Hmj+fQ0OdhQdJgaUc8JObvmTNeJyjodKS4TbOZqT/SCheS7DhnzcucqlN0uiVuHT
DIUzhM1uzHKcU8IOSclz4LPWLrKvn1yuRGKOplBuvwvd5g2I4QA5obq9Je4WYKEv
XL9quQfWW2OBV5XMK132Ttv6aXSJcrxDiI5CsvKivOcB+Rw9wjEesMJ9wBe8Od0L
jP/ehkGBsxq107M9srbn2WKjkvXFwpdDzpaQG2w1ZSIwHnsNunlDiU95oIDUcW3Y
p0JeL9Nn7uBvsnOKkBMCgXNH1VOBSLxRUDHlDVJIHWNl7TCqPfzKCc8ttq+lbmOf
dbATPhXh9wXQ1GgduexFGK4DSKteqSC8bgKC5JnmLx2ijOSgLGxaL4snAs3oqD2Q
gQptmLgiuFlof98l3TVJDN1yc6ononyIA72gvQ7e+zme6Q7UkkXU7gJHnd9k9YAL
7GQcxn9kTCz/iXxC3+ac/IMZae9b5bz8UGZdsI47RoovZ3dJlGj8jkjPJ7QTfZml
9EVuGkO0qWyPDzy14VTaCtKjtTOGm5iZwd8G63BPbaAlfyd6412QbisyC5ClICLS
TgF/ABxdrd/GbBzs3w7/8bAjR13EAVJWzqUQgKxluP0UxIthZn5od2f3pPaEyvfd
30eBLqpclcaQNIbGtv0qr5Ehjs26uKbAOXmNX+GbdA==
=h33S
-----END PGP MESSAGE-----
fp: F4B5F6971A1FAEA1216FCE1C6745A652A31186DB
unencrypted_suffix: _unencrypted
version: 3.7.1

View File

@ -1,33 +0,0 @@
From 3c692fc4fd5ea7faefc6b6ef63c9b6b20205a1cb Mon Sep 17 00:00:00 2001
From: Simon Bruder <simon@sbruder.de>
Date: Thu, 9 Sep 2021 16:56:57 +0200
Subject: [PATCH] Prefer opus audio streams in listen mode
---
src/invidious/views/components/player.ecr | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/invidious/views/components/player.ecr b/src/invidious/views/components/player.ecr
index 6418f66b..73524cfd 100644
--- a/src/invidious/views/components/player.ecr
+++ b/src/invidious/views/components/player.ecr
@@ -7,6 +7,16 @@
<source src="<%= URI.parse(hlsvp).request_target %><% if params.local %>?local=true<% end %>" type="application/x-mpegURL" label="livestream">
<% else %>
<% if params.listen %>
+ <%
+ opus_streams = audio_streams.select { |fmt|
+ metadata = itag_to_metadata?(fmt["itag"])
+ metadata ? metadata["acodec"] == "opus" : false
+ }.reverse!
+ if opus_streams.size > 0
+ audio_streams = opus_streams
+ end
+ audio_streams.sort_by! { |fmt| fmt["bitrate"].as_i }.reverse!
+ %>
<% audio_streams.each_with_index do |fmt, i| %>
<source src="/latest_version?id=<%= video.id %>&itag=<%= fmt["itag"] %><% if params.local %>&local=true<% end %>" type='<%= fmt["mimeType"] %>' label="<%= fmt["bitrate"] %>k" selected="<%= i == 0 ? true : false %>">
<% end %>
--
2.31.1

View File

@ -1,53 +0,0 @@
{ config, pkgs, ... }:
{
sops.secrets.invidious-extra-settings = {
sopsFile = ../../secrets.yaml;
group = "keys"; # not ideal, but required since the invidious user is dynamic
mode = "440";
};
systemd.services.invidious.serviceConfig.SupplementaryGroups = [ "keys" ];
services.invidious = {
enable = true;
package = pkgs.invidious.overrideAttrs (o: o // {
patches = (o.patches or [ ]) ++ [
./0001-Prefer-opus-audio-streams-in-listen-mode.patch
];
});
nginx.enable = true;
domain = "iv.sbruder.xyz";
settings = {
host_binding = "127.0.0.1";
log_level = "Warn";
default_user_preferences = {
# allow higher qualities
quality = "dash";
quality_dash = "auto";
# humane volume
volume = 50;
# no “popular” content
feed_menu = [ "Subscriptions" "Playlists" ];
default_home = ""; # search on /
};
disable_proxy = [ "downloads" ]; # legal precaution
local = true; # no external requests
use_pubsub_feeds = true;
modified_source_code_url = "https://github.com/sbruder/invidious/tree/patches";
};
extraSettingsFile = config.sops.secrets.invidious-extra-settings.path;
};
systemd.services.invidious.serviceConfig = {
Restart = "on-failure";
};
services.nginx.virtualHosts."iv.sbruder.xyz" = {
locations = {
"/robots.txt".return = "200 'User-agent: *\\nDisallow: /'";
"/privacy".return = "301 'https://sbruder.xyz/#privacy'";
};
};
}

View File

@ -1,19 +0,0 @@
{ config, ... }:
let
cfg = config.services.libreddit;
in
{
services.libreddit = {
enable = true;
address = "127.0.0.1";
};
services.nginx.virtualHosts."libreddit.sbruder.xyz" = {
forceSSL = true;
enableACME = true;
locations = {
"/robots.txt".return = "200 'User-agent: *\\nDisallow: /'";
"/".proxyPass = "http://${cfg.address}:${toString cfg.port}";
};
};
}

View File

@ -1,44 +0,0 @@
{ config, lib, ... }:
let
cfg = config.services.nitter;
in
{
services.nitter = {
enable = true;
server = {
port = 8081;
hostname = "nitter.sbruder.xyz";
address = "127.0.0.1";
};
preferences = {
theme = "Auto";
replaceTwitter = "${cfg.server.hostname}";
muteVideos = true;
hlsPlayback = true;
replaceYouTube = "${config.services.invidious.domain}";
};
};
services.nginx.virtualHosts.${cfg.server.hostname} = {
forceSSL = true;
enableACME = true;
locations = {
"/robots.txt".return = "200 'User-agent: *\\nDisallow: /'";
"/" = {
proxyPass = "http://${cfg.server.address}:${toString cfg.server.port}";
extraConfig =
let
# workaround for nginx dropping parent headers
# see https://github.com/yandex/gixy/blob/master/docs/en/plugins/addheaderredefinition.md
parentHeaders = lib.concatStringsSep "\n" (lib.filter
(lib.hasPrefix "add_header ")
(lib.splitString "\n" config.services.nginx.commonHttpConfig));
in
''
${parentHeaders}
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' blob:; style-src 'self' 'unsafe-inline'; media-src 'self' blob:";
'';
};
};
};
}

View File

@ -1 +0,0 @@
index.html

View File

@ -1,40 +0,0 @@
{ pkgs, ... }:
{
services.nginx.virtualHosts."sbruder.xyz" = {
forceSSL = true;
enableACME = true;
root = pkgs.stdenvNoCC.mkDerivation {
name = "sbruder.xyz";
src = ./.;
nativeBuildInputs = with pkgs; [ pandoc ];
buildPhase = ''
runHook preBuild
pandoc \
-s \
--metadata-file metadata.yaml \
-f commonmark_x \
-t html5 \
-o index.html \
index.md
runHook postBuild
'';
installPhase = ''
runHook preInstall
install -D index.html $out/index.html
runHook postInstall
'';
};
locations = {
"/imprint/".alias = "${pkgs.sbruder.imprint}/";
};
};
}

View File

@ -1,64 +0,0 @@
On this domain, the following services are currently available:
* [Invidious](https://iv.sbruder.xyz)
* [Libreddit](https://libreddit.sbruder.xyz)
* [Nitter](https://nitter.sbruder.xyz)
They are all semi-public instances.
That means, they are not included in lists of public instances,
but feel free to use them for personal purposes.
You can do so by using a browser plugin like [Privacy Redirect](https://github.com/SimonBrazell/privacy-redirect)
and configuring the addresses to point to this server.
However, please note the following if you want to use them:
* These services are provided as-is without any guarantees.
* You must not use these services for any activities illegal under Finnish or German law.
* You must not use these services to interfere with the operation of the services
or the sites that originally provide the data.
* Please dont over/abuse these services.
They run on a tiny VPS and wont be able to handle high workloads.
Also note the following service-specific things:
* **Invidious**: There are no backups, so you are responsible for using the data export feature to back up important data.
The VPS providing the services is running NixOS.
The configuration is available [here](https://git.sbruder.de/simon/nixos-config/src/branch/master/machines/yuzuru).
If you have any questions, please [contact me](https://sbruder.de).
## A Note to Copyright Holders
The services are only relaying content that is otherwise already available on the Internet.
If your rights are infringed by content available from this site,
please report this to the site originally making it available.
Otherwise the content will still be available on the Internet.
If you still want to report illegal content to me instead of the original site,
send me an Email to the address stated in the imprint.
This is the fastest way to resolve the issue,
so please use that if you care about it.
## Imprint
See [Imprint](/imprint/).
## Privacy
The Libreddit and Nitter services do not store your personally identifiable information.
If you log in to an Invidious account,
the data you provide to the service will be stored.
You can export or delete that data by using its built-in data control feature.
In the case of an error, details of the problematic request might be stored on the server
and used strictly for debugging and fixing the error.
Those logs will be deleted after one week.
#### Fine Print
<small>
This site and the services provided by it are not associated with YouTube, Reddit and/or Twitter.
Trademarks are property of their respective owners.
</small>

View File

@ -1,3 +0,0 @@
title: sbruder.xyz
mainfont: Roboto, Helvetica, Arial, sans-serif

View File

@ -1,72 +0,0 @@
{ config, lib, pkgs, ... }:
let
domain = "schulischer-schabernack.de";
in
{
services.nginx = {
commonHttpConfig = ''
# privacy-aware log format
log_format schabernack '$remote_addr_schabernack - - [$time_local] "$request" $status $body_bytes_sent "-" "$http_user_agent"';
# anonymise ip address
map $remote_addr $remote_addr_schabernack {
~(?P<ip>\d+\.\d+)\. $ip.0.0;
~(?P<ip>[^:]+:[^:]+): $ip::;
default 0.0.0.0;
}
'';
virtualHosts = {
${domain} = {
forceSSL = true;
enableACME = true;
root = "/var/www/schabernack/production";
# only log page views, rss feed access, media file download and embed views
extraConfig = ''
location ~ index\.html|rss\.xml|\.(opus|m4a|ogg|mp3|\.podlove.json)$ {
access_log /var/log/nginx/schabernack.log schabernack;
}
'';
};
"www.${domain}" = {
forceSSL = true;
enableACME = true;
globalRedirect = domain;
extraConfig = ''
access_log off;
'';
};
"staging.${domain}" = {
forceSSL = true;
enableACME = true;
root = "/var/www/schabernack/staging";
extraConfig = ''
access_log off;
'';
};
};
};
systemd.tmpfiles.rules = [
"d /var/www/schabernack/production 0755 schabernack root -"
"d /var/www/schabernack/staging 0755 schabernack root -"
];
users = {
users.schabernack = {
isSystemUser = true;
group = "schabernack";
shell = "/bin/sh";
openssh.authorizedKeys.keys = map
(key: "command=\"${pkgs.rrsync}/bin/rrsync -wo /var/www/schabernack/\",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ${key}")
config.sbruder.pubkeys.trustedKeys;
};
groups.schabernack = { };
};
}

View File

@ -1,5 +1,5 @@
{
imports = [
./system.nix
./intel.nix
];
}

11
modules/cpu/intel.nix Normal file
View File

@ -0,0 +1,11 @@
{ config, lib, ... }:
let
cfg = config.sbruder.cpu.intel;
in
{
options.sbruder.cpu.intel.enable = lib.mkEnableOption "intel cpu configuration";
config = lib.mkIf cfg.enable {
hardware.cpu.intel.updateMicrocode = true;
};
}

View File

@ -8,25 +8,33 @@ lib.mkIf config.sbruder.gui.enable {
enable = true;
drivers = with pkgs; [
gutenprint
] ++ lib.optional config.sbruder.unfree.allowSoftware (cups-kyocera-ecosys-m552x-p502x.override {
# in Kyocera terms, EU means duplex enabled by default
region = "EU";
});
];
};
avahi.enable = true;
};
hardware.printers.ensurePrinters = [
{
name = "kanna";
deviceUri = "socket://kanna.home.sbruder.de";
model = "${gutenprintWithVersion}://kyocera-fs-c5200dn/expert";
ppdOptions = {
PageSize = "A4";
};
}
# printer is broken and makes systemd unit fail
#{
# name = "tintenpisser";
# deviceUri = "ipp://tintenpisser.home.sbruder.de:631/ipp/print";
# model = "everywhere";
# ppdOptions = {
# PageSize = "A4";
# };
#}
{
name = "ich_drucke_nicht";
deviceUri = "socket://192.168.178.26";
model = "${gutenprintWithVersion}://bjc-TS3100-series/expert";
}
] ++ lib.optionals config.sbruder.unfree.allowSoftware [
{
name = "elma";
deviceUri = "socket://elma.home.sbruder.de";
model = "Kyocera/Kyocera ECOSYS P5021cdn.PPD";
}
];
}

View File

@ -1,45 +1,50 @@
{ config, lib, pkgs, ... }:
let
# Taken from https://nixos.wiki/wiki/Overlays
overlaysCompat = pkgs.writeTextFile {
name = "overlays-compat";
destination = "/overlays.nix";
text = ''
self: super:
with super.lib;
let
# Load the system config and get the `nixpkgs.overlays` option
overlays = (import <nixpkgs/nixos> { }).config.nixpkgs.overlays;
in
# Apply all overlays to the input of the current "main" overlay
foldl' (flip extends) (_: super) overlays self
'';
};
in
{
# Options that affect multiple modules
options.sbruder = {
full = lib.mkOption {
type = lib.types.bool;
description = ''
Whether to build the full system. If disabled, the system closure will
be smaller, but some features will not be available.
'';
default = true;
};
trusted = (lib.mkEnableOption "the trusted status of this machine (i.e. encrypted root)") // { default = true; };
gui.enable = lib.mkEnableOption "gui";
games.enable = lib.mkEnableOption "games";
};
# All modules are imported but non-essential modules are activated by
# configuration options
imports = [
../pkgs/modules.nix
./cpu
./cups.nix
./docker.nix
./fonts.nix
./games.nix
./gpu
./grub.nix
./gui.nix
./initrd-ssh.nix
./libvirt.nix
./locales.nix
./mailserver.nix
./media-proxy.nix
./mullvad
./network-manager.nix
./nginx-interactive-index
./nginx.nix
./nix.nix
./office.nix
./prometheus/node_exporter.nix
./pubkeys.nix
./pipewire.nix
./restic
./pulseaudio.nix
./restic.nix
./secrets.nix
./ssd.nix
./ssh.nix
./tools.nix
./udev.nix
@ -47,75 +52,79 @@
./wireguard
];
config = lib.mkMerge [
{
# Essential system tools
environment.systemPackages = with pkgs; [
git
git-crypt # used to store secrets in configuration
git-lfs # not so essential, but required to clone config
htop
tmux
vim
config = {
# Essential system tools
environment.systemPackages = with pkgs; [
git
git-crypt # used to store secrets in configuration
git-lfs # not so essential, but required to clone config
htop
tmux
vim
];
# Clean temporary files on boot
boot.cleanTmpDir = true;
# Set zsh as default shell
programs.zsh.enable = true;
users.defaultUserShell = pkgs.zsh;
# command-not-found does not work without channels
programs.command-not-found.enable = false;
# Sane swapping
boot.kernel.sysctl."vm.swapiness" = 10;
# Store logs persistently
services.journald.extraConfig = "Storage = persistent";
# Hard drive monitoring
services.smartd.enable = true;
# Network monitoring
services.vnstat.enable = true;
# Authentication/Encryption agents
programs.gnupg.agent.enable = true;
programs.ssh.startAgent = true;
# NixOS state version (see https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion)
system.stateVersion = "20.03";
nix = {
nixPath = [
"/var/src" # pinned nixpkgs and configuration
"nixpkgs=/var/src/nixpkgs" # for nix run
"nixpkgs-overlays=${overlaysCompat}"
];
# Make sudoers trusted nix users
trustedUsers = [ "@wheel" ];
# Clean temporary files on boot
boot.cleanTmpDir = true;
# Set zsh as default shell
programs.zsh.enable = true;
users.defaultUserShell = pkgs.zsh;
environment.etc."zshrc.local".source = "${pkgs.grml-zsh-config}/etc/zsh/zshrc";
# command-not-found does not work without channels
programs.command-not-found.enable = false;
# Hard drive monitoring
services.smartd.enable = lib.mkDefault true;
# Network monitoring
services.vnstat.enable = true;
# Support for exotic file systems
boot.supportedFilesystems = lib.optional config.sbruder.full "ntfs";
# Authentication/Encryption agents
programs.gnupg.agent.enable = true;
programs.ssh.startAgent = true;
# When this is set to true (default), routing everything through a
# wireguard tunnel does not work.
networking.firewall.checkReversePath = false;
# Open ports for quick tests
networking.firewall = {
allowedTCPPortRanges = lib.singleton { from = 9990; to = 9999; };
allowedUDPPortRanges = lib.singleton { from = 9990; to = 9999; };
};
# Globally set Lets Encrypt requirements
security.acme = {
acceptTerms = true;
email = "security@sbruder.de";
};
system.activationScripts.diff = ''
[ -L /run/current-system ] && ${pkgs.nixFlakes}/bin/nix \
--experimental-features 'nix-command' \
store \
diff-closures /run/current-system "$systemConfig"
# On-the-fly optimisation of nix store
autoOptimiseStore = true;
# Keep output of derivations with gc root
extraOptions = ''
keep-outputs = true
keep-derivations = true
'';
}
(lib.mkIf config.sbruder.full {
services.fwupd.enable = true;
})
(lib.mkIf (!config.sbruder.full) {
# Adapted from nixpkgs/nixos/modules/profiles/minimal.nix
i18n.supportedLocales = map
(locale: locale + "/UTF-8")
((lib.singleton config.i18n.defaultLocale)
++ (lib.attrValues config.i18n.extraLocaleSettings));
documentation.enable = lib.mkDefault false;
})
];
# Make nix build in background less noticeable
daemonIONiceLevel = 5; # 0-7
};
systemd.services.nix-daemon.serviceConfig.CPUSchedulingPolicy = "batch";
nixpkgs.config = {
# Add unstable channel
packageOverrides = pkgs: {
unstable = import (import ../nix/sources.nix).nixpkgs-unstable {
config = config.nixpkgs.config;
overlays = config.nixpkgs.overlays;
};
};
};
nixpkgs.overlays = [
(import ../pkgs)
];
};
}

View File

@ -17,7 +17,7 @@
docker = {
enable = true;
logDriver = "journald";
extraOptions = lib.concatStringsSep " " [
extraOptions = builtins.concatStringsSep " " [
"--ipv6"
"--fixed-cidr-v6=fd00:d0ce:d0ce:d0ce::/64"
];

View File

@ -3,20 +3,19 @@
lib.mkIf config.sbruder.gui.enable {
fonts = {
fonts = with pkgs; [
(nerdfonts.override { fonts = [ "Iosevka" ]; }) # default monospace font
] ++ lib.optionals config.sbruder.full [
google-fonts # google font collection (free)
lmodern # Latin Modern for non-latex applications
(nerdfonts.override { fonts = [ "Iosevka" ]; })
#roboto # standalone roboto has awful kerning
source-han-sans
source-han-serif # CJK fonts
] ++ lib.optionals (!config.sbruder.full) [
roboto # default sans-serif font (normally included in google-fonts)
] ++ lib.optionals config.sbruder.unfree.allowAssets [
corefonts # good ol microsoft fonts
vistafonts # newer microsoft fonts
];
enableDefaultFonts = true;
enableFontDir = true;
fontconfig = {
defaultFonts = {
@ -24,7 +23,7 @@ lib.mkIf config.sbruder.gui.enable {
sansSerif = [ "Roboto" "Source Han Sans" ];
serif = [ "Georgia" "Source Han Serif" ];
};
localConf = /* xml */ ''
localConf = ''
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>

View File

@ -1,23 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.sbruder.games;
in
{
options.sbruder.games = {
enable = lib.mkEnableOption "games";
performanceIndex = lib.mkOption {
type = lib.types.int;
description = ''
Arbitrary number specifying how powerful the machine is. To be
replaced by taking into account single- and multi-core CPU and GPU
metrics separately should this system not map to my machines in
practice.
* 2: ~ 2014 ultrabook
* 8: ~ 2016 quad-core workstation with mid-range GPU
'';
default = 1;
};
};
config = lib.mkIf cfg.enable { };
}

32
modules/gpu/amd.nix Normal file
View File

@ -0,0 +1,32 @@
{ config, lib, pkgs, ... }:
let
cfg = config.sbruder.gpu.amd;
in
{
options.sbruder.gpu.amd.enable = lib.mkEnableOption "amd gpu configuration";
config = lib.mkIf cfg.enable {
hardware.opengl.extraPackages = with pkgs; [
amdvlk
rocm-opencl-icd
];
environment.systemPackages = with pkgs; [
clinfo
radeontop
rocm-smi
];
# force RGB otput for HDMI (otherwise the default is YCbCr)
# see https://gitlab.freedesktop.org/drm/amd/-/issues/476
#boot.kernelPatches = [
# {
# name = "force-rgb";
# patch = pkgs.fetchpatch {
# url = "https://gitlab.freedesktop.org/drm/amd/uploads/99b3664a49ec759075bde5c454e1d7c2/0001-force-rgb.patch";
# sha256 = "03dhnlxx9vlj1x8izh3c3j4r9s75q47nx8kf6mbdxqfy3cj96mjm";
# };
# }
#];
};
}

7
modules/gpu/default.nix Normal file
View File

@ -0,0 +1,7 @@
{ lib, ... }:
{
imports = [
./amd.nix
./intel.nix
];
}

14
modules/gpu/intel.nix Normal file
View File

@ -0,0 +1,14 @@
{ config, lib, pkgs, ... }:
let
cfg = config.sbruder.gpu.intel;
in
{
options.sbruder.gpu.intel.enable = lib.mkEnableOption "intel gpu configuration";
config = lib.mkIf cfg.enable {
hardware.opengl.extraPackages = with pkgs; [
beignet
vaapiIntel
];
};
}

View File

@ -8,23 +8,8 @@ lib.mkIf config.sbruder.gui.enable {
extraPackages = [ ];
};
xdg = {
portal = {
enable = true;
extraPortals = with pkgs; [
xdg-desktop-portal-wlr
xdg-desktop-portal-gtk
];
gtkUsePortal = true;
};
};
services.upower.enable = true;
# steam (and other high quality software) still ships 32 bit binaries
hardware.opengl.driSupport32Bit = lib.mkDefault pkgs.stdenv.isx86_64;
hardware.opengl.driSupport32Bit = lib.mkIf pkgs.stdenv.isx86_64 true;
environment.systemPackages = with pkgs; [
pkgs.gnome3.adwaita-icon-theme # lutris requires system-wide installation
];
services.logind.lidSwitchDocked = config.services.logind.lidSwitch;
}

View File

@ -9,10 +9,10 @@
ssh = {
enable = lib.mkDefault config.boot.initrd.network.enable;
port = 2222;
# ssh-keygen -t ed25519 -N "" -f ssh_host_ed25519_key_initrd -C HOSTNAME
# scp ssh_host_ed25519_key_initrd root@machine:/etc/ssh/
# ssh-keygen -t ed25519 -N "" -f initrd-ssh-host-key -C HOSTNAME
# pass insert -m nixos/machines/HOSTNAME/initrd-ssh-host-key < initrd-ssh-host-key
hostKeys = [
"/etc/ssh/ssh_host_ed25519_key_initrd"
(toString <secrets/initrd-ssh-host-key>)
];
};
};

11
modules/libvirt.nix Normal file
View File

@ -0,0 +1,11 @@
{ config, lib, pkgs, ... }:
{
options.sbruder.libvirt.enable = lib.mkEnableOption "libvirt";
config = {
virtualisation.libvirtd.enable = config.sbruder.libvirt.enable;
environment.systemPackages = lib.mkIf config.sbruder.gui.enable [ pkgs.virt-manager ];
};
}

View File

@ -10,9 +10,4 @@
console.keyMap = "de";
time.timeZone = "Europe/Berlin";
location = {
latitude = 49.52;
longitude = 10.17;
};
}

View File

@ -1,346 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.sbruder.mailserver;
certDir = config.security.acme.certs."${cfg.fqdn}".directory;
in
{
options.sbruder.mailserver = with lib; with lib.types; {
enable = mkEnableOption "simple mail server";
fqdn = mkOption {
type = str;
description = ''
FQDN of the mail server
It needs to have a matching reverse DNS record. Also, an acme
certificate with this name has to be present.
'';
example = "mail.example.com";
};
storage = mkOption {
type = path;
description = "Location of the storage for mails";
default = "/var/vmail";
};
domains = mkOption {
type = listOf str;
description = "Domains to serve";
example = [ "example.com" "example.org" ];
};
users = mkOption {
type = listOf (submodule {
options = {
address = mkOption {
type = str;
description = "Primary e-mail address of the user";
example = "jdoe@example.com";
};
passwordHash = mkOption {
type = str;
description = ''
Bcrypt hash of the users password. Please note that it will be
world-readable in the nix store.
You can generate a password with `nix run nixpkgs.apacheHttpd -c
htpasswd -nBC 12 "" | cut -d: -f2`
'';
example = "$2y$05$SHxhwVGx.XCd19HAcb1NKuidUxW1BwU7GeO0ZIcMTc5t2uZoYLVRK";
};
aliases = mkOption {
type = listOf str;
description = ''
A list of aliases for the user.
If multiple users have the same alias defined, mail will be
delivered to both of them.
'';
default = [ ];
example = [
"j.doe@example.com"
"jane.doe@example.com"
"postmaster@example.com"
];
};
};
});
description = "Users of the mail server";
};
cleanHeaders = mkOption {
type = listOf str;
description = "A list of regular expressions that define what headers are filtered";
default = [
"/^\\s*Received:/"
"/^\\s*User-Agent:/"
"/^\\s*X-Mailer:/"
"/^\\s*X-Originating-IP:/"
];
};
rejectSenders = mkOption {
type = listOf str;
description = "A list of senders to reject mails from";
default = [ ];
example = [
"newsletter@example.com"
"spammer@example.com"
];
};
};
config = lib.mkIf cfg.enable {
# Users and groups
users.users.vmail = {
uid = 10000;
group = "vmail";
home = cfg.storage;
createHome = true;
};
users.groups.vmail.gid = 10000;
# Firewall
networking.firewall.allowedTCPPorts = [
143 # IMAP
25 # SMTP
587 # SMTP submission
];
# Service dependencies
systemd.services.dovecot2 = {
wants = [ "acme-finished-${cfg.fqdn}.target" ];
after = [ "acme-finished-${cfg.fqdn}.target" ];
};
systemd.services.postfix = {
wants = [ "acme-finished-${cfg.fqdn}.target" ];
requires = [ "dovecot2.service" ];
after = [ "acme-finished-${cfg.fqdn}.target" "dovecot2.service" ];
};
# Reload on certificate renewal
security.acme.certs."${cfg.fqdn}".postRun = ''
if systemctl is-active dovecot2; then
systemctl --no-block reload dovecot2
fi
if systemctl is-active postfix; then
systemctl --no-block reload postfix
fi
'';
# Postfix
security.dhparams.params.postfix = { };
services.postfix =
let
listToString = lib.concatStringsSep ",";
valiases =
let
# List of attribute sets with single key-value pair
plainAliases = (lib.flatten
(map
({ address, aliases, ... }:
map
(alias: { "${alias}" = address; })
(aliases ++ lib.singleton address))
cfg.users));
# Attribute set with every alias mapped to a list of receivers
mergedAliases = (lib.attrsets.foldAttrs
(val: col: lib.singleton val ++ col)
[ ]
plainAliases);
# Contents of the aliases file
aliasesString = (lib.concatStringsSep
"\n"
(lib.mapAttrsToList
(alias: addresses: "${alias} ${listToString addresses}")
mergedAliases));
in
pkgs.writeText
"valiases"
aliasesString;
access_sender = pkgs.writeText
"access_sender"
(lib.concatMapStringsSep
"\n"
(sender: "${sender} REJECT")
cfg.rejectSenders);
submissionHeaderCleanupRules = pkgs.writeText "submission_header_cleanup_rules"
(lib.concatMapStringsSep
"\n"
(regex: "${regex} IGNORE")
cfg.cleanHeaders);
in
{
enable = true;
enableSubmission = true;
hostname = cfg.fqdn;
networksStyle = "host";
sslCert = "${certDir}/fullchain.pem";
sslKey = "${certDir}/key.pem";
recipientDelimiter = "+";
mapFiles = {
inherit access_sender valiases;
};
config = {
# General
smtpd_banner = "${cfg.fqdn} ESMTP NO UCE";
disable_vrfy_command = true; # disable check if mailbox exists
enable_long_queue_ids = true; # better for debugging
strict_rfc821_envelopes = true; # only accept properly formatted envelope
message_size_limit = "50331648"; # 48MiB
virtual_mailbox_domains = listToString cfg.domains;
virtual_mailbox_maps = "hash:/var/lib/postfix/conf/valiases";
virtual_alias_maps = "hash:/var/lib/postfix/conf/valiases";
virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp";
smtpd_recipient_restrictions = listToString [
"reject_non_fqdn_recipient"
"reject_rbl_client ix.dnsbl.manitu.net"
"reject_unknown_recipient_domain"
"reject_unverified_recipient"
];
smtpd_client_restrictions = listToString [
"reject_rbl_client ix.dnsbl.manitu.net"
"reject_unknown_client_hostname"
];
smtpd_sender_restrictions = listToString [
"check_sender_access hash:/var/lib/postfix/conf/access_sender"
"reject_non_fqdn_sender"
"reject_unknown_sender_domain"
];
# generated 2021-02-04, Mozilla Guideline v5.6, Postfix 3.5.6, OpenSSL 1.1.1i, intermediate configuration
# https://ssl-config.mozilla.org/#server=postfix&version=3.5.6&config=intermediate&openssl=1.1.1i&guideline=5.6
smtpd_tls_security_level = "may";
smtpd_tls_auth_only = "yes";
smtpd_tls_mandatory_protocols = "!SSLv2, !SSLv3, !TLSv1, !TLSv1.1";
smtpd_tls_protocols = "!SSLv2, !SSLv3, !TLSv1, !TLSv1.1";
smtpd_tls_mandatory_ciphers = "medium";
smtpd_tls_loglevel = "1";
tls_medium_cipherlist = listToString [
"ECDHE-ECDSA-AES128-GCM-SHA256"
"ECDHE-RSA-AES128-GCM-SHA256"
"ECDHE-ECDSA-AES256-GCM-SHA384"
"ECDHE-RSA-AES256-GCM-SHA384"
"ECDHE-ECDSA-CHACHA20-POLY1305"
"ECDHE-RSA-CHACHA20-POLY1305"
"DHE-RSA-AES128-GCM-SHA256"
"DHE-RSA-AES256-GCM-SHA384"
];
tls_preempt_cipherlist = "no";
smtpd_tls_dh1024_param_file = config.security.dhparams.params.postfix.path;
};
submissionOptions = {
smtpd_tls_security_level = "encrypt";
smtpd_sasl_auth_enable = "yes";
smtpd_sasl_type = "dovecot";
smtpd_sasl_path = "/run/dovecot2/auth";
smtpd_sender_login_maps = "hash:/etc/postfix/valiases";
smtpd_recipient_restrictions = listToString [ ];
smtpd_client_restrictions = listToString [
"permit_sasl_authenticated"
"reject"
];
smtpd_sender_restrictions = listToString [
"reject_sender_login_mismatch"
];
cleanup_service_name = "submission-header-cleanup";
};
masterConfig = {
submission-header-cleanup = {
private = false;
maxproc = 0;
command = "cleanup";
args = [ "-o" "header_checks=pcre:${submissionHeaderCleanupRules}" ];
};
};
};
# Dovecot
services.dovecot2 =
let
postfixCfg = config.services.postfix;
passdb = pkgs.writeText "dovecot-users"
(lib.concatMapStringsSep
"\n"
({ address, passwordHash, ... }: "${address}:{BLF-CRYPT}${passwordHash}")
cfg.users);
in
{
enable = true;
enableLmtp = true;
enablePAM = false;
mailUser = "vmail";
mailGroup = "vmail";
mailLocation = "maildir:${cfg.storage}/%d/%n";
sslServerCert = "${certDir}/fullchain.pem";
sslServerKey = "${certDir}/key.pem";
extraConfig = ''
# generated 2021-02-04, Mozilla Guideline v5.6, Dovecot 2.3.13, OpenSSL 1.1.1i, intermediate configuration
# https://ssl-config.mozilla.org/#server=dovecot&version=2.3.13&config=intermediate&openssl=1.1.1i&guideline=5.6
ssl = required
ssl_min_protocol = TLSv1.2
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl_prefer_server_ciphers = no
service imap-login {
inet_listener imap {
}
}
service lmtp {
unix_listener dovecot-lmtp {
mode = 0600
user = ${postfixCfg.user}
group = ${postfixCfg.group}
}
}
passdb {
driver = passwd-file
args = username_format=%u ${passdb}
}
userdb {
driver = static
args = uid=vmail gid=vmail home=${cfg.storage}/%d/%n
}
service auth {
unix_listener auth {
mode = 0660
user = ${postfixCfg.user}
group = ${postfixCfg.group}
}
}
lda_mailbox_autosubscribe = yes
lda_mailbox_autocreate = yes
'';
};
};
}

View File

@ -2,22 +2,21 @@
let
port = 8888;
services = {
"media" = config.sops.secrets.media-proxy-auth.path;
"torrent" = config.sops.secrets.torrent-proxy-auth.path;
"media" = config.krops.secrets.media-proxy-auth.path;
"scan" = config.krops.secrets.media-proxy-auth.path;
"torrent" = config.krops.secrets.torrent-proxy-auth.path;
};
in
{
options.sbruder.media-proxy.enable = lib.mkEnableOption "media proxy";
config = lib.mkIf config.sbruder.media-proxy.enable {
sops.secrets = {
torrent-proxy-auth.owner = "nginx";
media-proxy-auth.owner = "nginx";
krops.secrets = {
torrent-proxy-auth.group = "nginx";
media-proxy-auth.group = "nginx";
};
systemd.services.nginx.serviceConfig.SupplementaryGroups = lib.singleton config.users.groups.keys.name;
users.users.nginx.extraGroups = [ "keys" ];
# otherwise name resolution fails
systemd.services.nginx.after = [ "network-online.target" ];
services.nginx = {
enable = true;
virtualHosts.media-proxy = {
@ -28,7 +27,7 @@ in
];
locations = {
"/".extraConfig = ''
rewrite ^/__nginx-interactive-index-assets__/(.*)$ /media/__nginx-interactive-index-assets__/$1;
rewrite ^/__assets/(.*)$ /media/__assets/$1;
'';
} // lib.mapAttrs'
(name: secret: {

View File

@ -1,72 +0,0 @@
{ config, lib, pkgs, ... }:
let
relays = builtins.fromJSON (builtins.readFile ./relays.json);
cfg = config.sbruder.mullvad;
relayConfigs = lib.mapAttrs'
(name: configuration: lib.nameValuePair "mullvad-${name}.conf" (with configuration; ''
[Interface]
DNS = ${cfg.dnsServer}
[Peer]
Endpoint = ${if cfg.ipVersion == 4 then endpoint4 else endpoint6}:${toString cfg.port}
PublicKey = ${pubkey}
AllowedIPs = 0.0.0.0/0,::0/0
''))
relays;
# Creating 100+ files in a separate derivation each has too much overhead
relayConfigFiles = pkgs.runCommandNoCC "etc-wireguard-mullvad" { } (''
mkdir $out
'' + (lib.concatStringsSep
"\n"
(lib.mapAttrsToList
(name: content: ''
cat > $out/${lib.escapeShellArg name} << EOF
${content}
EOF
'')
relayConfigs)));
in
{
options.sbruder.mullvad = {
enable = lib.mkEnableOption "wg-quick compatible configuration files in /etc/wireguard for Mullvad VPN";
dnsServer = lib.mkOption {
type = lib.types.str;
default = "193.138.218.74";
};
ipVersion = lib.mkOption {
type = lib.types.enum [ 4 6 ];
default = 4;
};
port = lib.mkOption {
type = lib.types.port;
default = 51820;
};
};
config = lib.mkIf cfg.enable {
environment = {
etc = builtins.listToAttrs
(map
(name: lib.nameValuePair "wireguard/${name}" { source = "${relayConfigFiles}/${name}"; })
(lib.attrNames relayConfigs));
systemPackages = lib.singleton (pkgs.stdenv.mkDerivation {
name = "mullvad-on-demand";
src = ./mullvad.sh;
dontUnpack = true;
dontBuild = true;
installPhase = ''
runHook preInstall
install -D $src $out/bin/mullvad
runHook postInstall
'';
});
};
};
}

View File

@ -1,60 +0,0 @@
#!/usr/bin/env bash
# This reads wg-quick compatible configuration files from
# /etc/wireguard/mullvad-LOCATION.conf
#
# Since they are autogenerated by nix and therefore world-readable, they do not
# include secrets like the private key and client address. Instead, they are
# manually added after wg-quick set up the tunnel by retrieving them with
# pass(1) from web/mullvad.net/wireguard.
#
# Format of pass entry:
# PrivateKey: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=
# Address4: 10.0.0.1/32
# Address6: fd00::1/128
set -euo pipefail
if (( $# < 1 )); then
echo "USAGE: $0 LOCATION|off" >&2
exit 1
fi
INTERFACE="mullvad-$1"
cmd() {
echo "[#] $*" >&2
sudo "$@"
}
for interface in /sys/class/net/*; do
interface="${interface#/sys/class/net/}"
[[ $interface =~ ^mullvad-(v6-)?[a-z]{2}[0-9]*$ ]] && cmd wg-quick down "$interface"
done
if [ "$1" != "off" ]; then
# Make sure gpg-agent is unlocked so the period where the interface exists but
# no private key is set is minised.
pass web/mullvad.net/wireguard >/dev/null
cmd wg-quick up "$INTERFACE"
pass web/mullvad.net/wireguard | while read -r line; do
key="${line%%: *}"
value="${line#*: }"
case "$key" in
PrivateKey)
cmd wg set "$INTERFACE" private-key /dev/stdin <<< "$value"
continue
;;
Address4)
cmd ip -4 address add "$value" dev "$INTERFACE"
continue
;;
Address6)
cmd ip -6 address add "$value" dev "$INTERFACE"
continue
;;
*)
echo "Invalid key '$key'"
exit 1
esac
done
fi

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
#!/usr/bin/env bash
# This gets the current wireguard relay list from mullvads API and transforms
# it into a format that takes up less space than the original response.
set -euo pipefail
curl -s 'https://api.mullvad.net/www/relays/wireguard/' | jq '. | map({
key: .hostname | split("-")[0],
value: {
endpoint4: .ipv4_addr_in,
endpoint6: .ipv6_addr_in,
pubkey: .pubkey
}
}) | from_entries' > relays.json

View File

@ -1,9 +1,7 @@
{ config, lib, pkgs, ... }:
{ config, lib, ... }:
lib.mkIf config.sbruder.gui.enable {
networking.networkmanager.enable = true;
environment.systemPackages = with pkgs; [
networkmanagerapplet
];
networking.networkmanager = {
enable = true;
};
}

View File

@ -1,69 +0,0 @@
# This module implements an option with the same structure as the nginx module
# but does not extend the nginx module since that would cause infinite
# recursion.
{ config, lib, pkgs, ... }:
let
enabledLocations = lib.fold
(x: a: a ++ x)
[ ]
(lib.mapAttrsToList
(vhostName: vhostConfig: lib.mapAttrsToList
(locationName: locationConfig: [ vhostName locationName ])
(lib.filterAttrs
(_: location: location.enable)
vhostConfig.locations))
config.services.nginx-interactive-index.virtualHosts);
in
{
options.services.nginx-interactive-index.virtualHosts = with lib.types; lib.mkOption {
default = { };
type = attrsOf (submodule {
options = {
locations = lib.mkOption {
default = { };
type = attrsOf (submodule {
options = {
enable = lib.mkEnableOption "interactive directory index";
};
});
};
};
});
};
config.services.nginx.virtualHosts = lib.fold
(x: a: a // x)
{ }
(map
(path:
let
vhost = lib.elemAt path 0;
location = lib.elemAt path 1;
assetsPath = "${location}__nginx-interactive-index-assets__";
in
{
"${vhost}".locations = {
"${location}" = {
extraConfig = ''
autoindex on;
autoindex_exact_size on;
add_before_body ${assetsPath}/header.html;
'';
};
"${assetsPath}/" = {
alias = "${builtins.filterSource
(path: type: baseNameOf path != "default.nix")
./.}/";
};
"=${assetsPath}/header.html" = {
alias = pkgs.writeText "nginx-interactive-index-${location}-header.html" ''
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="stylesheet" href="${assetsPath}/listing.css">
<script src="${assetsPath}/listing.js"></script>
'';
};
};
})
enabledLocations);
}

View File

@ -1,48 +0,0 @@
body, html {
background-color: #fdf6e3;
color: #657b83;
font-family: "TeX Gyre Heros", "Roboto", "Helvetica", "Arial", sans-serif;
}
tr.hidden {
display: none;
}
tr.zebra-stripe {
background: #eee8d5;
}
th, td {
padding: 0.1em 0.5em;
}
th {
text-align: left;
font-weight: bold;
background: #eee8d5;
border-bottom: 1px solid #657b83;
}
a {
color: #586e75;
}
a:hover {
color: #073642;
}
table {
width: 100%;
}
#search-field {
width: 100%;
border: none;
margin-bottom: 15px;
background: #eee8d5;
color: inherit;
}
hr {
display: none;
}

View File

@ -1,91 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
function humanFileSize(bytes) {
const thresh = 1024
if(Math.abs(bytes) < thresh) {
return bytes + ' B'
}
const units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB']
var u = -1
do {
bytes /= thresh
++u
} while(Math.abs(bytes) >= thresh && u < units.length - 1)
return bytes.toFixed(1)+' '+units[u]
}
function textToA(line) {
let outerElement = document.createElement('div')
outerElement.innerHTML = line
return outerElement.getElementsByTagName('a')[0]
}
function parseLine(line) {
const href = textToA(line).href
const filename = href.substr(-1) === '/' ? decodeURIComponent(href.split('/').slice(-2, -1)[0]) : decodeURIComponent(href.split('/').pop())
const size = line.split(' ').pop()
return {
href: href,
filename: filename,
size: size
}
}
function processLine(line) {
meta = parseLine(line)
return `<tr><td><a href="${meta.href}">${meta.filename}</a></td><td>${meta.size === '-' ? '-' : humanFileSize(meta.size)}</td></tr>`
}
function addZebraStripes(rows) {
// this should be done in CSS, but AFAIU it does not support limiting
// :nth-child to elements matching a previous :not selector
rows.forEach((row, idx) => {
if (idx % 2 === 0) {
row.classList.add("zebra-stripe")
} else {
row.classList.remove("zebra-stripe")
}
})
}
const collator = new Intl.Collator('kn', {numeric: true})
// transform plain text to table
document.querySelector('pre').outerHTML = '<table><thead><tr><th>Name</th><th>Size</th></tr></thead><tbody><tr><td><a href="..">..</a></td><td>-</td></tr>' + document.querySelector('pre').innerHTML
.split('\n')
.filter(line => line !== '')
.filter(line => line !== '<a href="../">../</a>')
.map(processLine)
.sort(collator.compare)
.join('\n') + '</tbody></table>'
let searchField = document.createElement('input')
searchField.id = 'search-field'
searchField.autofocus = true
document.querySelector('body').insertBefore(searchField, document.querySelector('table'))
const rows = Array.from(document.querySelectorAll('tbody tr'))
addZebraStripes(rows)
document.querySelector('#search-field').addEventListener("input", e => {
const searchValue = e.target.value.toLowerCase()
rows.forEach(row => {
const file = row.querySelector('td:nth-child(1) a').innerText
if (!file.toLowerCase().includes(searchValue)) {
row.classList.add("hidden")
} else {
row.classList.remove("hidden")
}
})
const visibleRows = rows.filter(row => !row.classList.contains("hidden"))
if (visibleRows.length === 1) {
const target = visibleRows[0].querySelector('td a').href
if (target.substr(-1) === '/') {
window.location = target
}
}
addZebraStripes(visibleRows)
})
})

View File

@ -1,30 +0,0 @@
{ config, lib, ... }:
let
cfg = config.sbruder.nginx;
in
{
options.sbruder.nginx = {
hardening.enable = lib.mkEnableOption "nginx hardening";
privacy.enable = (lib.mkEnableOption "nginx privacy options") // { default = true; };
};
config = lib.mkMerge [
(lib.mkIf cfg.hardening.enable {
services.nginx.commonHttpConfig = ''
map $scheme $hsts_header {
https "max-age=31536000";
}
add_header Strict-Transport-Security $hsts_header;
add_header Referrer-Policy strict-origin;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
'';
})
(lib.mkIf cfg.privacy.enable {
services.nginx.commonHttpConfig = ''
access_log off;
'';
})
];
}

View File

@ -1,91 +0,0 @@
{ config, inputs, lib, pkgs, ... }:
let
# Adapted from https://nixos.wiki/wiki/Overlays
overlaysCompat = pkgs.writeTextFile {
name = "overlays-compat";
destination = "/overlays.nix";
text = /* nix */ ''
self: super:
with super.lib;
let
# Load the system config and get the `nixpkgs.overlays` option
# This fails gracefully if getFlake is not available
overlays = if builtins.hasAttr "getFlake" builtins
then (builtins.getFlake "/var/src/config").nixosConfigurations.${config.networking.hostName}.config.nixpkgs.overlays
else [ ];
in
# Apply all overlays to the input of the current "main" overlay
foldl' (flip extends) (_: super) overlays self
'';
};
in
{
sops.secrets = lib.mkIf config.sbruder.trusted {
binary-cache-secret-key = { };
nix-netrc = {
group = "wheel";
mode = "0440";
};
};
nix = {
# nix with flake support
package = pkgs.nixFlakes;
registry = with inputs; {
nixpkgs.flake = nixpkgs;
nixpkgs-unstable.flake = nixpkgs-unstable;
};
nixPath = [
"nixpkgs=${inputs.nixpkgs}"
"nixpkgs-overlays=${overlaysCompat}"
];
# Make sudoers trusted nix users
trustedUsers = [ "@wheel" ];
binaryCaches = [
"https://nix-cache.sbruder.de/"
];
binaryCachePublicKeys = [
"nix-cache.sbruder.de-1:bU13eF6IMMW2hgO7StgB6JCAoZPeAQ27NAzV0kru1XM="
];
# On-the-fly optimisation of nix store
autoOptimiseStore = true;
extraOptions = ''
experimental-features = nix-command flakes
'' + lib.optionalString config.sbruder.trusted ''
# Binary cache upload
secret-key-files = ${config.sops.secrets.binary-cache-secret-key.path}
netrc-file = ${config.sops.secrets.nix-netrc.path}
'' + lib.optionalString config.sbruder.full ''
# Keep output of derivations with gc root
keep-outputs = true
keep-derivations = true
'';
# Make nix build in background less noticeable
daemonCPUSchedPolicy = "batch";
daemonIOSchedPriority = 5; # 0-7
};
nixpkgs.overlays = with inputs; [
self.overlay
nixpkgs-overlay.overlay
(final: prev: {
unstable = import nixpkgs-unstable {
inherit (config.nixpkgs)
config
overlays
system;
};
})
AriaNg.overlay
];
environment.systemPackages = with pkgs; [
cached-nix-shell
];
}

View File

@ -1,34 +0,0 @@
{ config, lib, modulesPath, pkgs, ... }:
let
bluetoothSupport = config.sbruder.full;
in
lib.mkIf config.sbruder.gui.enable {
sound.enable = true;
security.rtkit.enable = true;
services.pipewire = {
enable = true;
pulse.enable = true;
alsa = {
enable = true;
support32Bit = true;
};
media-session = {
config = {
bluez-monitor = {
"bluez5.enable-hw-volume" = true;
};
};
};
};
environment.systemPackages = with pkgs; [
helvum # patch panel
pavucontrol
pulseaudio # pacmd and pactl
];
hardware.bluetooth.enable = lib.mkDefault bluetoothSupport;
services.blueman.enable = lib.mkDefault bluetoothSupport;
}

View File

@ -3,8 +3,7 @@
services.prometheus.exporters.node = {
enable = config.sbruder.wireguard.home.enable;
listenAddress = config.sbruder.wireguard.home.address;
enabledCollectors = [ "systemd" ];
disabledCollectors = [ "rapl" ];
enabledCollectors = [ "systemd " ];
};
systemd.services.prometheus-node-exporter.after = [ "wireguard-wg-home.service" ];

View File

@ -8,22 +8,22 @@ in
type = lib.types.attrsOf lib.types.str;
description = "Known public keys that can be used in the configuration";
default = {
"simon@nunotaba" = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwMo0mYcTU1Y4BKpEUsvKAtcTPq3ylKaw+ZjUxNg9VqU5gDy2TDUfWk2FjM2VYcqQJ9ZaNGKE1S18fRU7ZHrcgtFPMgAuji87yOKojH74cwz9ZRf5ZiluWBmR3dFd7kddqHUKVS8utpiQuTLIyQwpgmUHA81IasWXuB2pHaI6HGntMlJTm1CvpcQvwKsDBqJ2bFjFMk6EDgAZWXyooQgthYAfmc+YfAX5T9fWKiqFnEJ0ryN3/RngJZe65HWV8WZwY1CxgKQhOZuRcPdkTEQlUk9Qu0JbVa2sTgdYDpw/Dz0ma+h4rxOrH63MD6Cf0pFgOwLeZVSmXqKTjXVaH1QkHWRat88J8Q6MM6LlhLx/48VcQshhIssAZ37YoW2W0NxnGSM7YtlwTVe+w7rU//cS5TyIQa4joq2pnIh4uurbNkIULa4Q2t2nEMzlqI9gEE9DK1ctOcuCyFOerNZD0yRZ5Rs8WouDLL1PR6ps4czK2N7h2MXABcELuVwX+sdxwFgf6AJaRvrlw4qIOohpeX48FhzZfcI9Cqvnakm+O42J3qXuUDVc6/NjE9zBku3dNaeseGv9CQxtvyVDq6o9MRDiFror3yEiN0Fwou7CXBfXrbeb7MvahsRxSKkSDY0uA+AXmsm1UwdArjEcEMsS1JeFQCdX1yR/Z5xzj2gx60NcR4w==";
"simon@sayuri" = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1kQUoPII8A9/bgPA+OrZGQLPA8MxkdmPSCCsfGMh9qRZfF7BSD8W6VdE/28tLw+39QeUl1+/9VuVvGjZBP1zBAbKIcKx4DjtgxpNXCsfWMjXFtpTGk2dyl71CaY5n72YlADxXYwtEvuwfNixgE2yTCefMbBsfwqYC0GZGiDlFtjxdg+RuUC8jU++C+WFUFct9gj9ieQ0LWjud+Oh0AF0JhyGnou+wVZIIO8mwo7Cc5xiPldXhbc13XiNC3mpNGCLFj+nh1feazk8TeAVDBps6xaDkOd+hDwTBQh8LoimePK7MiShzLvC38Vd/sim5ym/IqY634CjqBDGCMp1KXnqHUTT8CqeifMv10+aRJKUPevVkO3nEE3VoSPt7Ui9ZzLnL4qhZyygoBau+PvD2WCWm+gRwBkvU1uNrYKi4HIGhB/gXcYHKJimqJwLMyqG5Wv1jfuhn3ZZN+uNqTgdAznGgPRU1Q/Mx6nMEDiQip78qdYEc0YGwdb/TldEL6aHRjuNuZPpTW+zakQHiQTRb/0VdZT1bAwyT9yL0Uf40h706Kh/pKiSQ1yq1dlSdl3RlfedbqLqGjspds1iRSrSXyH2MBghPbz/SF7Vt4LW/tXF0rcyV7CU98ZvxJDWeN60OE0vPf/AT5udYyfPO1691y0F8jGKxGYYPg9R/Y5o7J24PbQ==";
"simon@mayushii" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAJ7qUGZUjiDhQ6Se+aXr9DbgRTG2tx69owqVMkd2bna";
};
};
trustedNames = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = "Names of trusted public keys, used to generate <literal>sbruder.pubkeys.trustedKeys</literal>";
default = [
"simon@nunotaba"
"simon@sayuri"
"simon@mayushii"
];
};
trustedKeys = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = "Trusted public keys, automatically generated from <literal>sbruder.pubkeys.trustedNames</literal>";
default = map
default = builtins.map
(name: cfg.keys."${name}")
cfg.trustedNames;
};

27
modules/pulseaudio.nix Normal file
View File

@ -0,0 +1,27 @@
{ config, lib, pkgs, ... }:
lib.mkIf config.sbruder.gui.enable {
sound.enable = true;
hardware.pulseaudio = {
enable = true;
package = pkgs.pulseaudioFull;
extraModules = [
pkgs.pulseaudio-modules-bt # Non-standard codecs for bluetooth
];
daemon.config = {
"default-sample-format" = "s16le";
"default-sample-rate" = "48000";
"alternate-sample-rate" = "44100";
"resample-method" = "soxr-hq";
"flat-volumes" = "no";
};
};
# Bluetooth support
hardware.bluetooth.enable = true;
services.blueman.enable = true;
environment.systemPackages = with pkgs; [
pavucontrol
];
}

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