nix: add loki system configuration

This commit is contained in:
surtur 2023-10-15 22:16:06 +02:00
parent 253c68f590
commit 04b877ddb1
Signed by: wanderer
SSH Key Fingerprint: SHA256:MdCZyJ2sHLltrLBp0xQO0O1qTW9BT/xl5nXkDvhlMCI
40 changed files with 2508 additions and 5 deletions

1
.gitattributes vendored Normal file

@ -0,0 +1 @@
secrets.yaml filter=sops

@ -3,16 +3,20 @@
this repo holds the code describing my very own infra (machines I use/manage) this repo holds the code describing my very own infra (machines I use/manage)
and is very much a WIP. and is very much a WIP.
should contain zero secrets, except encrypted either with [`age`][age] or :nixos: [NixOS][nixos] configurations are present in the [`./nix`](nix) folder.
[`ansible-vault`][ansible-vault].
should contain zero secrets, except encrypted either with [`age`][age],
[`sops-nix`][sops-nix], or [`ansible-vault`][ansible-vault].
[`terraform`][tf] secrets are supplied as ENV vars at runtime by sourcing the [`terraform`][tf] secrets are supplied as ENV vars at runtime by sourcing the
decrypted `infra-vars` file using [`direnv`][direnv], which is in turn decrypted `infra-vars` file (stationed in its place with [`home-manager`][hm])
stationed in its place using [`home-manager`][hm]. using [`direnv`][direnv].
[infra]: https://git.dotya.ml/wanderer/infra [infra]: https://git.dotya.ml/wanderer/infra
[nixos]: https://nixos.org/
[age]: https://github.com/FiloSottile/age [age]: https://github.com/FiloSottile/age
[sops-nix]: https://github.com/Mic92/sops-nix
[ansible-vault]: https://docs.ansible.com/ansible/latest/cli/ansible-vault.html [ansible-vault]: https://docs.ansible.com/ansible/latest/cli/ansible-vault.html
[tf]: https://www.terraform.io/ [tf]: https://www.terraform.io/
[direnv]: https://direnv.net/
[hm]: https://github.com/nix-community/home-manager [hm]: https://github.com/nix-community/home-manager
[direnv]: https://direnv.net/

19
nix/.sops.yaml Normal file

@ -0,0 +1,19 @@
---
keys:
- &it age1nt7a9nsgwsf7c9x8yx3qu8w24svz02hpfuwtmk8dazw6j6lh33hsgv8erk
- &loki age136558pknq6glx2xftavt7mm3p4jcpu54kej2kxryeu78m5r59e0qvawl5l
- &backup age15959gprm59azjflvpj97yt0lj6dj4d2yv0nd6u9jp32lzwp3de7qzhf85y
- &surtur age1drh8uq93mhzhj3rz9s2gcnht04wc5hukzutlu4l5qc55hxaznd5s9xs2f6
creation_rules:
- path_regex: hosts/loki/*.*
key_groups:
- age:
- *backup
- *loki
- path_regex: ./secrets/*
key_groups:
- age:
- *backup
- *surtur
- *loki
...

18
nix/README.md Normal file

@ -0,0 +1,18 @@
# [`infra/nix`](.)
## [:nixos: NixOS][nixos] configurations
* [`./hosts`](hosts) folder contains host-specific configurations
* [`./modules`](modules) folder contains reusable code
:rocket: deploy (build and switch to a new system) remotely using:
```sh
nixos-rebuild switch --fast --flake .#loki --target-host loki
```
where the *target host* `loki` is the `ssh-config` name of the host being
configured using the `.#loki` attribute of `nixosConfigurations`.
see `nixosConfigurations` attr in [`./flake.nix`](flake.nix) for a complete list of hosts.
[nixos]: https://nixos.org/

524
nix/flake.lock Normal file

@ -0,0 +1,524 @@
{
"nodes": {
"agenix": {
"inputs": {
"darwin": "darwin",
"home-manager": "home-manager",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1696775529,
"narHash": "sha256-TYlE4B0ktPtlJJF9IFxTWrEeq+XKG8Ny0gc2FGEAdj0=",
"owner": "ryantm",
"repo": "agenix",
"rev": "daf42cb35b2dc614d1551e37f96406e4c4a2d3e4",
"type": "github"
},
"original": {
"owner": "ryantm",
"repo": "agenix",
"type": "github"
}
},
"attic": {
"inputs": {
"crane": "crane",
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1698258239,
"narHash": "sha256-qnhoYYIJ0L/P7H/f56lQUEvpzNlXh4sxuHpRERV+B44=",
"owner": "zhaofengli",
"repo": "attic",
"rev": "e9918bc6be268da6fa97af6ced15193d8a0421c0",
"type": "github"
},
"original": {
"owner": "zhaofengli",
"repo": "attic",
"type": "github"
}
},
"authentik-nix": {
"inputs": {
"authentik-src": "authentik-src",
"flake-compat": "flake-compat_2",
"flake-parts": "flake-parts",
"flake-utils": "flake-utils_2",
"napalm": "napalm",
"nixpkgs": "nixpkgs_2",
"poetry2nix": "poetry2nix"
},
"locked": {
"lastModified": 1696443205,
"narHash": "sha256-aEhAb4GBqOgkGYEHWJ+Y6ADa/EnwnF9TcuyZbSvLtw8=",
"owner": "mayflower",
"repo": "authentik-nix",
"rev": "e3e7edaba410014bd246d05783dd93dc827fa53c",
"type": "github"
},
"original": {
"owner": "mayflower",
"repo": "authentik-nix",
"type": "github"
}
},
"authentik-src": {
"flake": false,
"locked": {
"lastModified": 1694451308,
"narHash": "sha256-dpGvxhA5NWO8LKrGXzalV9EVn/nUIj6sMy2HdY5tjlM=",
"owner": "goauthentik",
"repo": "authentik",
"rev": "f885f8c0395df639ccabd762910867bef0f4577c",
"type": "github"
},
"original": {
"owner": "goauthentik",
"ref": "version/2023.8.3",
"repo": "authentik",
"type": "github"
}
},
"crane": {
"inputs": {
"flake-compat": [
"attic",
"flake-compat"
],
"flake-utils": [
"attic",
"flake-utils"
],
"nixpkgs": [
"attic",
"nixpkgs"
],
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1677892403,
"narHash": "sha256-/Wi0L1spSWLFj+UQxN3j0mPYMoc7ZoAujpUF/juFVII=",
"owner": "ipetkov",
"repo": "crane",
"rev": "105e27adb70a9890986b6d543a67761cbc1964a2",
"type": "github"
},
"original": {
"owner": "ipetkov",
"repo": "crane",
"type": "github"
}
},
"darwin": {
"inputs": {
"nixpkgs": [
"agenix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1673295039,
"narHash": "sha256-AsdYgE8/GPwcelGgrntlijMg4t3hLFJFCRF3tL5WVjA=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "87b9d090ad39b25b2400029c64825fc2a8868943",
"type": "github"
},
"original": {
"owner": "lnl7",
"ref": "master",
"repo": "nix-darwin",
"type": "github"
}
},
"disko": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1697073574,
"narHash": "sha256-Np603TUNj+fzQYmaNPS7pmsy52KHq4fpWP5GCpTJ38Y=",
"owner": "nix-community",
"repo": "disko",
"rev": "3c41ae36ff12afbada9396c7d8282c2c74f74e06",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "disko",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1693611461,
"narHash": "sha256-aPODl8vAgGQ0ZYFIRisxYG5MOGSkIczvu2Cd8Gb9+1Y=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "7f53fdb7bdc5bb237da7fefef12d099e4fd611ca",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1692799911,
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
"agenix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1682203081,
"narHash": "sha256-kRL4ejWDhi0zph/FpebFYhzqlOBrk0Pl3dzGEKSAlEw=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "32d3e39c491e2f91152c84f8ad8b003420eab0a1",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"napalm": {
"inputs": {
"flake-utils": [
"authentik-nix",
"flake-utils"
],
"nixpkgs": [
"authentik-nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1693989153,
"narHash": "sha256-gx39Y3opGB25+44OjM+h1bdJyzgLD963va8ULGYlbhM=",
"owner": "nix-community",
"repo": "napalm",
"rev": "a8215ccf1c80070f51a92771f3bc637dd9b9f7ee",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "napalm",
"type": "github"
}
},
"nix-github-actions": {
"inputs": {
"nixpkgs": [
"authentik-nix",
"poetry2nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1688870561,
"narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=",
"owner": "nix-community",
"repo": "nix-github-actions",
"rev": "165b1650b753316aa7f1787f3005a8d2da0f5301",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nix-github-actions",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1691853136,
"narHash": "sha256-wTzDsRV4HN8A2Sl0SVQY0q8ILs90CD43Ha//7gNZE+E=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f0451844bbdf545f696f029d1448de4906c7f753",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"dir": "lib",
"lastModified": 1693471703,
"narHash": "sha256-0l03ZBL8P1P6z8MaSDS/MvuU8E75rVxe5eE1N6gxeTo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3e52e76b70d5508f3cec70b882a29199f4d1ee85",
"type": "github"
},
"original": {
"dir": "lib",
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1685004253,
"narHash": "sha256-AbVL1nN/TDicUQ5wXZ8xdLERxz/eJr7+o8lqkIOVuaE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3e01645c40b92d29f3ae76344a6d654986a91a91",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable_2": {
"locked": {
"lastModified": 1697332183,
"narHash": "sha256-ACYvYsgLETfEI2xM1jjp8ZLVNGGC0onoCGe+69VJGGE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0e1cff585c1a85aeab059d3109f66134a8f76935",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-23.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1697226376,
"narHash": "sha256-cumLLb1QOUtWieUnLGqo+ylNt3+fU8Lcv5Zl+tYbRUE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "898cb2064b6e98b8c5499f37e81adbdf2925f7c5",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1697144559,
"narHash": "sha256-pzo1nxxr2niEnkvZEHdG8E5f8BPgj1dWxN0NvW/OnTk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "30e70aded1a399e13b515426ec8e17841b9a9f1d",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1697009197,
"narHash": "sha256-viVRhBTFT8fPJTb1N3brQIpFZnttmwo3JVKNuWRVc3s=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "01441e14af5e29c9d27ace398e6dd0b293e25a54",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"poetry2nix": {
"inputs": {
"flake-utils": [
"authentik-nix",
"flake-utils"
],
"nix-github-actions": "nix-github-actions",
"nixpkgs": [
"authentik-nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1694165861,
"narHash": "sha256-FMiPKVcNxb9QWATnQrC68nIL2t8Fm4zBH0XyLz9uqko=",
"owner": "nix-community",
"repo": "poetry2nix",
"rev": "c3d3c4a0396b1bcccd72c82551a319229997f6e4",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "poetry2nix",
"type": "github"
}
},
"root": {
"inputs": {
"agenix": "agenix",
"attic": "attic",
"authentik-nix": "authentik-nix",
"disko": "disko",
"nixpkgs": "nixpkgs_3",
"sops-nix": "sops-nix"
}
},
"rust-overlay": {
"inputs": {
"flake-utils": [
"attic",
"crane",
"flake-utils"
],
"nixpkgs": [
"attic",
"crane",
"nixpkgs"
]
},
"locked": {
"lastModified": 1675391458,
"narHash": "sha256-ukDKZw922BnK5ohL9LhwtaDAdCsJL7L6ScNEyF1lO9w=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "383a4acfd11d778d5c2efcf28376cbd845eeaedf",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"sops-nix": {
"inputs": {
"nixpkgs": "nixpkgs_4",
"nixpkgs-stable": "nixpkgs-stable_2"
},
"locked": {
"lastModified": 1697339241,
"narHash": "sha256-ITsFtEtRbCBeEH9XrES1dxZBkE1fyNNUfIyQjQ2AYQs=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "51186b8012068c417dac7c31fb12861726577898",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

89
nix/flake.nix Normal file

@ -0,0 +1,89 @@
{
description = "NixOS configuration for all the things (as many as we can get)";
inputs.nixpkgs.url = "github:NixOS/nixpkgs";
inputs.disko.url = "github:nix-community/disko";
inputs.disko.inputs.nixpkgs.follows = "nixpkgs";
inputs.agenix.url = "github:ryantm/agenix";
inputs.agenix.inputs.nixpkgs.follows = "nixpkgs";
inputs.sops-nix.url = "github:Mic92/sops-nix";
inputs.attic.url = "github:zhaofengli/attic";
inputs.authentik-nix.url = "github:mayflower/authentik-nix";
outputs = {
self,
nixpkgs,
disko,
agenix,
sops-nix,
attic,
authentik-nix,
...
}: let
projname = "nix-infra";
system = "x86_64-linux";
supportedSystems = ["x86_64-linux" "aarch64-linux"];
# Helper function to generate an attrset '{ x86_64-linux = f "x86_64-linux"; ... }'.
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
# Nixpkgs instantiated for supported system types.
nixpkgsFor = forAllSystems (system:
import nixpkgs {
inherit system;
overlays = [
# no overlay imports atm
];
});
pkgs = nixpkgs.legacyPackages.${system};
# pkgs = nixpkgsFor.${system};
in {
formatter = forAllSystems (
system:
nixpkgsFor.${system}.alejandra
);
# formatter.${system} = pkgs.alejandra;
nixosConfigurations.loki = nixpkgs.lib.nixosSystem {
inherit pkgs system;
modules = [
disko.nixosModules.disko
agenix.nixosModules.default
sops-nix.nixosModules.sops
attic.nixosModules.atticd
authentik-nix.nixosModules.default
./hosts/loki/configuration.nix
];
};
devShells = forAllSystems (
system: let
pkgs = import nixpkgs {
inherit system;
overlays = [
];
};
in {
default = with pkgs;
mkShell
{
name = "${projname}";
shellHook = ''
echo " -- in ${projname} dev shell..."
'';
nativeBuildInputs = [
];
packages =
[cachix]
++ (
if stdenv.isLinux
then [
]
else []
);
};
}
);
};
}

@ -0,0 +1,219 @@
{
config,
lib,
pkgs,
...
}: {
imports = [
# Include the results of the hardware scan.
./hardware-configuration.nix
./disko-config.nix
./modules/caddy.nix
./modules/coredns.nix
# ./modules/authelia.nix
./modules/authentik.nix
./modules/gonic.nix
./modules/attic.nix
../../modules/base.nix
../../modules/dnscrypt.nix
# ../../modules/nix-serve.nix
../../modules/uptime-kuma.nix
];
sops = {
defaultSopsFile = ./secrets.yaml;
age = {
keyFile = "/root/.age/loki-key";
sshKeyPaths = ["/root/.ssh/lokiage" "/etc/ssh/ssh_host_ed25519_key"];
generateKey = false;
};
secrets.domainName.restartUnits = ["caddy.service" "coredns.service"];
secrets.nixServeSecretKey.restartUnits = ["nix-serve.service"];
};
age = {
# `lokiage` key needs to be manually when setting up the machine;
identityPaths = ["/root/.ssh/lokiage"];
# identityPaths = ["/root/.ssh/lokiage" "/var/lib/persistent/ssh_host_ed25519_key"];
secrets.rootPassphrase.file = ./secrets/rootPassphrase.age;
# secrets."zfs-DATA".file = ./secrets/zfs-DATA.age;
};
nix.settings.trusted-users = ["@wheel" "root"];
nix.sshServe.enable = true;
nix.sshServe.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBtG6NCgdLHX4ztpfvYNRaslKWZcl6KdTc1DehVH4kAL"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBZbkw9vjCfbMPEH7ZAFq20XE9oIJ4w/HRIMu2ivNcej caelum's nixbldr key"
];
# forbid hibernation due to zfs-on-root.
boot.kernelParams = ["nohibernate"];
boot.kernel.sysctl = {
"dev.i915.perf_stream_paranoid" = 0;
};
# Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
boot.loader.systemd-boot.configurationLimit = 42;
boot.loader.systemd-boot.netbootxyz.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.supportedFilesystems = ["zfs"];
boot.zfs.forceImportRoot = true;
boot.initrd.kernelModules = ["zfs" "e1000e"];
boot.initrd.network = {
# This will use udhcp to get an ip address.
# Make sure you have added the kernel module for your network driver to `boot.initrd.availableKernelModules`,
# so your initrd can load it!
# Static ip addresses might be configured using the ip argument in kernel command line:
# https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt
enable = false;
ssh = {
enable = false;
# To prevent ssh clients from freaking out because a different host key is used,
# a different port for ssh is useful (assuming the same host has also a regular sshd running)
port = 2222;
# hostKeys paths must be unquoted strings, otherwise you'll run into issues with boot.initrd.secrets
# the keys are copied to initrd from the path specified; multiple keys can be set
# you can generate any number of host keys using
# `ssh-keygen -t ed25519 -N "" -f /path/to/ssh_host_ed25519_key`
# hostKeys = [/root/.initrd-ssh_host_ed25519_key];
ignoreEmptyHostKeys = true;
authorizedKeys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIODmLwtQj6ylgdTPo1/H5jW7jsLzwaCTGdIsTQAdc896"];
};
};
# boot.initrd.systemd.contents
boot.binfmt = {
emulatedSystems = [
"wasm32-wasi"
"aarch64-linux"
];
};
networking = {
# hostId = pkgs.lib.mkForce "00000000";
hostId = "deadb33f";
hostName = "loki";
nftables.enable = true;
networkmanager.enable = true;
interfaces.enp0s25.wakeOnLan.enable = true;
firewall = {
allowPing = true;
};
# Configure network proxy if necessary
# networking.proxy.default = "http://user:password@proxy:port/";
# networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
};
users.users.root = {
shell = pkgs.zsh;
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBtG6NCgdLHX4ztpfvYNRaslKWZcl6KdTc1DehVH4kAL"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJaXmXbNegxiXLldy/sMYX8kCsghY1SGqn2FZ5Jk7QJw"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBZbkw9vjCfbMPEH7ZAFq20XE9oIJ4w/HRIMu2ivNcej caelum's nixbldr key"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGKzPC0ZK4zrOEBUdu1KNThEleVb1T5Pl3+n3KB3o0b8 surtur's nixbldr key"
];
hashedPasswordFile = config.age.secrets.rootPassphrase.path;
subUidRanges = [
{
count = 65536;
startUid = 65536 * 28; # 1835008, docker
}
];
};
services = {
atd.enable = true;
udev.extraRules = ''
# set brightness to minimum level.
ACTION=="add", SUBSYSTEM=="backlight", ATTR{brightness}!="0", ATTR{brightness}="0"
# wol
ACTION=="add", SUBSYSTEM=="net", NAME=="en*", RUN+="${pkgs.ethtool}/bin/ethtool -s $name wol g"
'';
power-profiles-daemon.enable = false;
#tlp.enable =
# lib.mkDefault ((lib.versionOlder (lib.versions.majorMinor lib.version) "23.11")
# || !config.services.power-profiles-daemon.enable);
auto-cpufreq.enable = true;
auto-cpufreq.settings = {
battery = {
governor = "powersave";
turbo = "never";
};
charger = {
governor = "schedutil";
turbo = "auto";
};
};
prometheus = {
# WIP.
enable = true;
# openFirewall = true;
port = 9090;
exporters = {
node = {
enable = true;
enabledCollectors = [
"logind"
"systemd"
];
port = 9100;
};
};
scrapeConfigs = [
{
job_name = "node";
static_configs = [
{
targets = [
"loki.local:${toString config.services.prometheus.exporters.node.port}"
];
}
];
}
{
job_name = "coredns";
static_configs = [{targets = ["loki.local:9153"];}];
}
];
};
nix-serve.secretKeyFile = config.sops.secrets.nixServeSecretKey.path;
# TS is enabled in the imported module, this is additional config.
tailscale = {
useRoutingFeatures = "both";
# accept-routes = true;
};
zfs = {
autoScrub = {
enable = true;
interval = "weekly";
};
trim.enable = true;
};
};
# Copy the NixOS configuration file and link it from the resulting system
# (/run/current-system/configuration.nix). This is useful in case you
# accidentally delete configuration.nix.
# Does not work with flakes - yet™.
system.copySystemConfiguration = false;
}

@ -0,0 +1,86 @@
{
config,
disks ? ["/dev/sda"],
lib,
...
}: let
zfs-DATA = config.age.secrets.zfs-DATA;
in {
disko.devices = {
disk = {
x = {
type = "disk";
device = "/dev/sda";
content = {
type = "gpt";
partitions = {
ESP = {
type = "EF00";
size = "700M";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "zroot";
};
};
};
};
};
};
zpool = {
zroot = {
type = "zpool";
mode = ""; # == single disk
options = {
ashift = "12";
autotrim = "on";
};
rootFsOptions = {
checksum = "sha512";
compression = "zstd";
"com.sun:auto-snapshot" = "false";
};
mountpoint = null;
postCreateHook = "zfs snapshot zroot@blank";
datasets = {
"ROOT" = {
type = "zfs_fs";
mountpoint = null;
options."com.sun:auto-snapshot" = "false";
};
"ROOT/nixos" = {
type = "zfs_fs";
mountpoint = "/";
options."com.sun:auto-snapshot" = "true";
};
nix = {
type = "zfs_fs";
mountpoint = "/nix";
options."com.sun:auto-snapshot" = "true";
};
#DATA = {
# type = "zfs_fs";
# options = {
# encryption = "aes-256-gcm";
# keyformat = "passphrase";
# keylocation = "file://${zfs-DATA.path}";
# mountpoint = "none";
# "com.sun:auto-snapshot" = "true";
# };
# # postCreateHook = ''
# # zfs set keylocation="file://${zfs-DATA}.path" "zroot/$name";
# # '';
#};
};
};
};
};
}

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

@ -0,0 +1,25 @@
{config, ...}: let
svc = "atticd.service";
p = config.sops.placeholder;
in {
imports = [
../../../modules/attic.nix
];
sops = {
secrets = {
"attic/serverToken".restartUnits = [svc];
};
templates.atticCreds = {
content = ''
ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64="${p."attic/serverToken"}"
'';
};
};
services.atticd = {
enable = true;
credentialsFile = config.sops.templates.atticCreds.path;
settings.listen = "127.0.0.1:5000";
};
}

@ -0,0 +1,46 @@
{
config,
pkgs,
...
}: {
imports = [
../../../modules/authelia.nix
];
age = {
secrets.autheliaEnv.file = ./secrets/autheliaEnv.age;
secrets.autheliaStorage.file = ./secrets/autheliaStorage.age;
secrets.autheliaJWT.file = ./secrets/autheliaJWT.age;
secrets.autheliaStorage.owner = "${toString config.services.authelia.instances.main.user}";
secrets.autheliaJWT.owner = "${toString config.services.authelia.instances.main.user}";
};
services = {
authelia.instances.main = {
secrets.storageEncryptionKeyFile = config.age.secrets.autheliaStorage.path;
secrets.jwtSecretFile = config.age.secrets.autheliaJWT.path;
settings = {
access_control = {
rules = [
{
domain = "*.*";
policy = "one_factor";
}
];
};
storage.local.path = "/var/lib/authelia-main/data";
authentication_backend.file.path = "/var/lib/authelia-main/users_database.yml";
notifier.filesystem.filename = "/var/lib/authelia-main/notif.txt";
# ntp.address = "ptbtime.ptb.de:123"
ntp.disable_startup_check = true;
};
};
};
systemd.services.authelia-main.serviceConfig = {
EnvironmentFile = config.age.secrets.autheliaEnv.path;
};
}

@ -0,0 +1,41 @@
{
config,
pkgs,
sops-nix,
...
}: let
svc = "authentik.service";
in {
sops.secrets = {
"authentik/secretKey".restartUnits = [svc];
"authentik/emailHost".restartUnits = [svc];
"authentik/emailUsername".restartUnits = [svc];
"authentik/emailPassword".restartUnits = [svc];
"authentik/emailFrom".restartUnits = [svc];
};
services.authentik = {
enable = true;
# The environmentFile needs to be on the target host!
# Best use something like sops-nix or agenix to manage it
environmentFile = config.sops.templates.authentikEnv.path;
settings = {
disable_startup_analytics = true;
avatars = "initials";
disable_update_check = true;
error_reporting_enabled = false;
};
};
sops.templates.authentikEnv = {
content = ''
AUTHENTIK_SECRET_KEY=${config.sops.placeholder."authentik/secretKey"}
AUTHENTIK_EMAIL__HOST=${config.sops.placeholder."authentik/emailHost"}
AUTHENTIK_EMAIL__USERNAME=${config.sops.placeholder."authentik/emailUsername"}
AUTHENTIK_EMAIL__PASSWORD=${config.sops.placeholder."authentik/emailPassword"}
AUTHENTIK_EMAIL__FROM=${config.sops.placeholder."authentik/emailFrom"}
# AUTHENTIK_DISABLE_UPDATE_CHECK=true
# AUTHENTIK_ERROR_REPORTING__ENABLED=false
'';
};
}

@ -0,0 +1,195 @@
{
config,
pkgs,
sops-nix,
...
}: let
caddyPkg = pkgs.callPackage ../../../modules/caddy-custom-package.nix {
plugins = [
"github.com/caddy-dns/njalla"
"github.com/caddy-dns/desec"
"github.com/dulli/caddy-wol"
"github.com/ueffel/caddy-brotli"
"github.com/greenpau/caddy-security"
];
vendorSha256 = "sha256-4Yzqo8aUUivNtgV7hljzoN9VZ5J51AQgV+NrbZ8on5s=";
};
p = config.sops.placeholder;
domain = p.domainName;
svc = "caddy.service";
in {
networking.firewall.allowedTCPPorts = [80 443];
services = {
caddy = {
enable = true;
package = caddyPkg;
configFile = config.sops.templates.caddyPls.path;
adapter = "caddyfile";
};
};
systemd.services.caddy = {
description = "Caddy web server";
after = ["network-online.target" "sops-nix.service"];
wants = ["network-online.target"];
wantedBy = ["multi-user.target"];
serviceConfig = {
TimeoutStopSec = "5s";
# LimitNOFILE = 1048576;
# LimitNPROC = 512;
PrivateTmp = true;
# ProtectSystem = "full";
AmbientCapabilities = "cap_net_bind_service";
};
};
sops.secrets = {
"caddy/njallaApiKey".restartUnits = [svc];
"caddy/email".restartUnits = [svc];
};
sops.templates.caddyPls = {
owner = config.systemd.services.caddy.serviceConfig.User;
content = ''
(tlsCommon) {
tls {
dns njalla ${p."caddy/njallaApiKey"}
# propagation_timeout 1m
propagation_timeout -1
curves x25519
key_type p384
protocols tls1.2 tls1.3
}
}
(headersCommon) {
header / {
x-frame-options "sameorigin"
x-content-type-options "nosniff"
x-xss-protection "1; mode=block"
content-security-policy "
upgrade-insecure-requests;
default-src 'self';
style-src 'self';
script-src 'self';
font-src 'self';
img-src data: 'self';
form-action 'self';
connect-src 'self';
frame-ancestors 'none';
"
cross-origin-opener-policy "same-origin"
permissions-policy "geolocation=(), midi=(), sync-xhr=(), microphone=(), camera=(), magnetometer=(), gyroscope=(), fullscreen=(self), payment=()"
referrer-policy "no-referrer; strict-origin-when-cross-origin"
-Server
}
}
(authentik) {
# Always forward outpost path to actual outpost
reverse_proxy /outpost.goauthentik.io/* http://localhost:9000
# Forward authentication to outpost
forward_auth http://localhost:9000 {
uri /outpost.goauthentik.io/auth/caddy
# Capitalization of the headers is important, otherwise they will be empty
copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version
}
}
{
admin off
acme_dns njalla ${p."caddy/njallaApiKey"}
email ${p."caddy/email"}
grace_period 60s
log default {
output stdout
format json
}
}
auth.${domain} {
encode zstd br
log {
level INFO
}
import tlsCommon
# authelia
# reverse_proxy localhost:9091
# authentik
reverse_proxy localhost:9000
import headersCommon
}
whoami.${domain} {
encode zstd br
log {
level INFO
}
import tlsCommon
import headersCommon
import authentik
respond "I am whoami"
}
gonic.${domain} {
encode zstd br
log {
level INFO
}
import tlsCommon
import headersCommon
# import authentik
reverse_proxy localhost:4747
}
ffsync.${domain} {
encode zstd br
log {
level INFO
}
import tlsCommon
import headersCommon
# import authentik
reverse_proxy localhost:${toString config.services.firefox-syncserver.settings.port}
}
# attic - nix cache.
cache.${domain} nixcache.${domain} {
encode zstd br
log {
level INFO
}
import tlsCommon
import headersCommon
# import authentik
reverse_proxy localhost:5000
}
# uptime kuma
uptime.${domain} {
encode zstd br
log {
level INFO
}
import tlsCommon
import headersCommon
# import authentik
reverse_proxy localhost:3001
}
'';
};
}

@ -0,0 +1,369 @@
{
lib,
config,
pkgs,
sops-nix,
...
}: let
serial = toString 14;
svc = "coredns.service";
usr = "${toString config.users.users.coredns.name}";
domain = p.domainName;
p = config.sops.placeholder;
in {
networking.firewall = {
allowedTCPPorts = [53];
allowedUDPPorts = [53];
};
age = {
secrets.zoneInternal.file = ../secrets/zoneInternal.age;
secrets.zoneInternal.owner = "${toString config.users.users.coredns.name}";
secrets.zoneExternal.file = ../secrets/zoneExternal.age;
secrets.zoneExternal.owner = "${toString config.users.users.coredns.name}";
# secrets.corednsEnv.file = ../secrets/corednsEnv.age;
};
sops = {
secrets = {
"coredns/cidrHomenet".restartUnits = [svc];
"coredns/cidrTailnet".restartUnits = [svc];
"coredns/ip".restartUnits = [svc];
"coredns/ipwlan".restartUnits = [svc];
"coredns/iptailscale".restartUnits = [svc];
"coredns/localDNSCryptResolver".restartUnits = [svc];
"net/ethLoki".restartUnits = [svc];
"net/ethCaelum".restartUnits = [svc];
"net/ethCarina".restartUnits = [svc];
"net/wlanLoki".restartUnits = [svc];
"net/wlanCarina".restartUnits = [svc];
"coredns/cidrHomenet".owner = usr;
"coredns/cidrTailnet".owner = usr;
"coredns/ip".owner = usr;
"coredns/ipwlan".owner = usr;
"coredns/iptailscale".owner = usr;
"coredns/localDNSCryptResolver".owner = usr;
"net/ethLoki".owner = usr;
"net/ethCaelum".owner = usr;
"net/ethCarina".owner = usr;
"net/wlanLoki".owner = usr;
"net/wlanCarina".owner = usr;
};
};
sops.templates.corednsZoneInternal = {
owner = usr;
content = ''
$ORIGIN ${domain}.
@ 1D IN SOA ${domain}. root.${domain}. (
${serial} ; serial (yyyymmdd##)
1M ; refresh
1M ; retry
1M ; expiry
1m ) ; minimum ttl
5m IN NS ${p."net/ethLoki"}.
5m IN NS ${p."net/wlanLoki"}.
5m IN NS ${p."net/ethCarina"}.
5m IN NS ${p."net/wlanCarina"}.
grocy.${domain}. 5m IN A ${p."net/ethCaelum"}
gonic.${domain}. 5m IN A ${p."net/ethLoki"}
cloud.${domain}. 5m IN A ${p."net/ethCaelum"}
media.${domain}. 5m IN A ${p."net/ethCaelum"}
llama.${domain}. 5m IN A ${p."net/ethCaelum"}
llama2.${domain}. 5m IN A ${p."net/ethCaelum"}
auth.${domain}. 5m IN A ${p."net/ethLoki"}
whoami.${domain}. 5m IN A ${p."net/ethLoki"}
ffsync.${domain}. 5m IN A ${p."net/ethLoki"}
cache.${domain}. 5m IN A ${p."net/ethLoki"}
nixcache.${domain}. 5m IN CNAME cache.${domain}
uptime.${domain}. 5m IN A ${p."net/ethLoki"}
carina.${domain}. 5m IN A ${p."net/ethCarina"}
caelum.${domain}. 5m IN A ${p."net/ethCaelum"}
loki.${domain}. 5m IN A ${p."net/ethLoki"}
'';
};
sops.templates.corednsPls = {
owner = usr;
content = ''
. {
# TODO: listen on 853 and 443 and 1443 for DoT and DoH,
# certs will be courtesy of caddy (or acme).
# TODO: ad blocking?
# hosts /etc/coredns/blocklist.hosts {
# fallthrough
# }
reload
bufsize 1232
# TODO: add wlan and tailscale IPs
# bind {$IP} {$IPWLAN} {$IPTailscale}
bind ${p."coredns/ip"} ${p."coredns/ipwlan"}
acl {
allow net 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 192.0.0.0/24 100.64.0.0/10
block
}
hosts {
reload 0
fallthrough
}
# loadbalance
# local dnscrypt-proxy.
forward . ${p."coredns/localDNSCryptResolver"} {
health_check 5s
expire 600s
policy sequential
}
#cache {
# success 4096
# success 10000
# denial 2048
# prefetch 512
#}
whoami
health
prometheus :9153
errors
log
local
any
}
# ${domain} {
# bind {$IPTailscale}
# view tailscale {
# expr incidr(server_ip(), '{$cidrTailnet}')
# }
# reload 300s
# file /etc/coredns/external-tailnet.zone
# cache {
# #success 1000
# success 4096
# denial 2048
# prefetch 512
# keepttl
# }
# errors
# log
#}
${domain} {
bind ${p."coredns/ip"} ${p."coredns/ipwlan"}
view homenet {
expr incidr(server_ip(), '${p."coredns/cidrHomenet"}')
}
reload 300s
# file ${config.age.secrets.zoneInternal.path}
file ${config.sops.templates.corednsZoneInternal.path}
cache {
success 4096
denial 2048
prefetch 512
keepttl
}
errors
log
local
any
}
# vim: noexpandtab:ft=Corefile
'';
};
sops.templates.corednsEnv = {
content = ''
cidrHomenet=${p."coredns/cidrHomenet"}
cidrTailnet=${p."coredns/cidrTailnet"}
domainName=${domain}
IP=${p."coredns/ip"}
IPWLAN=${p."coredns/ipwlan"}
IPTailscale=${p."coredns/iptailscale"}
localDNSCryptResolver=${p."coredns/localDNSCryptResolver"}
'';
};
services.coredns = {
enable = true;
config = "import ${config.sops.templates.corednsPls.path}";
#config = ''
# . {
# # TODO: listen on 853 and 443 and 1443 for DoT and DoH,
# # certs will be courtesy of caddy
# # TODO: ad blocking?
# # hosts /etc/coredns/blocklist.hosts {
# # fallthrough
# # }
# reload
# bufsize 1232
# # TODO: add wlan and tailscale IPs
# # bind {$IP} {$IPWLAN} {$IPTailscale}
# bind {$IP}
# acl {
# allow net 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 192.0.0.0/24 100.64.0.0/10
# block
# }
# hosts {
# reload 0
# fallthrough
# }
# # loadbalance
# # local dnscrypt-proxy.
# forward . {$localDNSCryptResolver} {
# health_check 5s
# expire 600s
# policy sequential
# }
# #cache {
# # success 4096
# # success 10000
# # denial 2048
# # prefetch 512
# #}
# whoami
# health
# prometheus :9153
# errors
# log
# }
# # {$domainName} {
# # bind {$IPTailscale}
# # view tailscale {
# # expr incidr(server_ip(), '{$cidrTailnet}')
# # }
# # reload 300s
# # file /etc/coredns/external-tailnet.zone
# # cache {
# # #success 1000
# # success 4096
# # denial 2048
# # prefetch 512
# # keepttl
# # }
# # errors
# # log
# #}
# {$domainName} {
# bind {$IP}
# view homenet {
# expr incidr(server_ip(), '{$cidrHomenet}')
# }
# reload 300s
# # file ${config.age.secrets.zoneInternal.path}
# file ${config.sops.templates.corednsZoneInternal.path}
# cache {
# success 4096
# denial 2048
# prefetch 512
# keepttl
# }
# errors
# log
# }
# # vim: noexpandtab:ft=Corefile
#'';
};
# systemd.services.coredns.unitConfig = {
# upholds = config.systemd.services.dnscrypt-proxy2;
# wants = config.systemd.services.dnscrypt-proxy2;
# };
# systemd.services.coredns.serviceConfig = {
systemd.services.coredns = {
after = ["sops-nix.service"];
wants = ["dnscrypt-proxy2.service"];
serviceConfig = {
# StateDirectory = "coredns";
# WorkingDirectory = "/etc/coredns";
WorkingDirectory = "/";
# StartLimitIntervalSec = 5;
StartLimitBurst = 10;
Restart = lib.mkDefault "always";
RestartSec = 10;
# PermissionsStartOnly = true;
ProtectSystem = "strict";
LimitNOFILE = 1048576;
LimitNPROC = 512;
User = "coredns";
# EnvironmentFile = config.age.secrets.corednsEnv.path;
EnvironmentFile = config.sops.templates.corednsEnv.path;
# LoadCredential = lib.mapAttrsToList (name: path: "${name}:${path}") cfg.credentials;
DeviceAllow = "";
LockPersonality = true;
MemoryDenyWriteExecute = false;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
# DynamicUser = true;
ProtectProc = "invisible";
RemoveIPC = true;
# RestrictAddressFamilies = ["AF_INET" "AF_INET6" "AF_UNIX"];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallErrorNumber = "EPERM";
SystemCallFilter = [
"@system-service"
"~@cpu-emulation"
"~@debug"
"~@keyring"
"~@memlock"
"~@obsolete"
# "~@privileged"
"~@setuid"
];
UMask = 0027;
};
};
users.users.coredns = {
group = "coredns";
home = "/etc/coredns";
createHome = false;
isSystemUser = true;
extraGroups = ["users"];
};
users.groups.coredns = {};
}

@ -0,0 +1,15 @@
{config, ...}: {
services.gonic = {
enable = true;
settings = {
music-path = "/DATA/music";
podcast-path = "/DATA/podcasts";
cache-path = "/var/cache/gonic";
# db-path ="/DATA/services/gonic/gonic.db";
db-path = "/var/lib/gonic/gonic.db";
jukebox-enabled = false;
listen-addr = "127.0.0.1:4747";
scan-interval = 60;
};
};
}

@ -0,0 +1,70 @@
domainName: ENC[AES256_GCM,data:E2UFsEHoCPASUxB/YqqWrUavqA==,iv:IM6iMZLeKztTHjF8Fy4gbZGUX5Orh77opYvOmrER3RY=,tag:o3KmFgHgP1dXDUiWTIxT+Q==,type:str]
shortDomain: ENC[AES256_GCM,data:L80YrbWy69gW3r0L5PJ3+zE=,iv:q32iqxRzFW4nOfk+7+ceOURF/CO6Y6ewnaVXV3vopv0=,tag:qVjXHB/GtsV9Ej7VZvQ2TQ==,type:str]
nixServeSecretKey: ENC[AES256_GCM,data:0VFFgsYGl6/FdM9KQ6PiNxApFlYlDQd+Qfes1BkVn9u9h4XBqAQa1jYuF7FSuemDoikQX040fDIEwmwBtFgfZ7+hBuQHVDyErh817CeDhMcsnKlyf+UVZCL3atV3hgrq/w==,iv:kcyylbpHtB2Nniwp9uxGAHS8Q0E7QRLndZ26dBTFb70=,tag:WF+r1gEdGq7fVUBOjmZyUw==,type:str]
nixServePubKey: ENC[AES256_GCM,data:XcnS7U6y47CmF3EgLDvovukI3ZrWHF/78L/uYrvfzNgT1RJD6UDTzR2iJzXV2wISfv/EGt0=,iv:21dN0bqlFhqoNdnx/GOmRgGPJqAnv7+p7XTIYBEyRCQ=,tag:iUP47jEsd0B1eteJjL2oyQ==,type:str]
caddy:
njallaApiKey: ENC[AES256_GCM,data:MOgTmZF+kWPJ/pEhGLpZ6Dh3rRdSemByxYfWbgJDuzScKzlpe47sfA==,iv:X7aZcwALwUmKS3JF9/+1eqTot+7FTApqHCMv0zx9gLs=,tag:8cpdrWQI6p1aAtvTUim99A==,type:str]
email: ENC[AES256_GCM,data:3heYJXQd7lg6p5PUI9BmEhodCvb9kzrn80nvZOk=,iv:8WAPyK8wT+CTjLbjyTsfruAaIIdFLrDT8TKuq7YC+XU=,tag:FVMM8rBTuVr5sg2VLYgugQ==,type:str]
authentik:
secretKey: ENC[AES256_GCM,data:UIGYAi/g7sgM+MEn7wBS3hbWsgPl5ePBi8fR9AbbFf0NjfE4Pw8VqoCfW5Q=,iv:y0tQVsIBl0Tu9kere6hEw4caxg0y+Rst8JLTMmX6rys=,tag:Y2DfgSPvqLNFIF6hlDXJFg==,type:str]
emailHost: ENC[AES256_GCM,data:lRyFRzhuNgC9VNPO9A==,iv:R8AWmA7JTLPWAXnN2Lwg9lTE5FnGgOC3zYRhGDthKXQ=,tag:sqPaHQPVDW6lbc7rJ6Fb1A==,type:str]
emailUsername: ENC[AES256_GCM,data:XIN/hRzwIMlH2Vt9jhSAK+WN,iv:f4KhU7v6SXlW9wbyl8jrOJn/OyhR6XDoI9Xs8imTBwc=,tag:7O6sXLyLQrrYo93Si2mAQw==,type:str]
emailFrom: ENC[AES256_GCM,data:aWpZR5jq1XSCYCDaSx8pE3Xx,iv:HAKQbnoA+uXNh/N3EjoIjId7MYu5ivZd5G7ccwmlz0I=,tag:yw9of9h8a+6annAi+rBdVA==,type:str]
#ENC[AES256_GCM,data:7Ux8lB94gwD/7pab3THr8ExJ5DwsMBikqECFIRYEmIAIJh8RnGjORnGIk+Dx06NZ0yr16JMD3o0kyjNL,iv:bIfJmwB4Y/oS241keTPG7Ty9hT7U12ES3XV2vHKFKgI=,tag:qDTXF62SzpMqDNqklkZdsg==,type:comment]
emailPassword: ENC[AES256_GCM,data:Jr1lpggvsxO50dvQ/jWjinN9CtSA5KiVbIuisYtx+lzzkOZojBlYkOiX3aYNfxX1MOPlsA==,iv:Bl6siYZ6wneYOeZ2PivAUJS1JnLFRgYtdbjrmrKOOBI=,tag:YrsvF3Q1cs6w+bUlHA9Wgw==,type:str]
net:
ethLoki: ENC[AES256_GCM,data:dP23Oj9pPPntNnx0,iv:kdfdkKhHQQED/iH1BDRUB/C3R/vdVgY4Pm8nZMc62uQ=,tag:8qb669FIhwI5AU/LHfj7wg==,type:str]
ethCaelum: ENC[AES256_GCM,data:KRiIHgqJVZHbMOEPlw==,iv:xbZBkEboi5B7M0PuWytkc6+Y2FoZ7LhDox39yX4ZTIk=,tag:Y2wElHZzxTn68kTK0e48UQ==,type:str]
ethCarina: ENC[AES256_GCM,data:IIzTlIdGo17ie1XA6w==,iv:v79kkPFbhj5x+8xTkxSKCS9xCaTzlMK+RaGQgiKnDn8=,tag:cFNDqag0JGLHgVFQ3tA9mA==,type:str]
wlanLoki: ENC[AES256_GCM,data:eSa++RH6t/W5yQWt,iv:xn6IEROjq6CLZ4mGBZB6vZCIAtVJmrjCTs66G+OzCcY=,tag:jLFogLZtyPbprXK2OhWXIw==,type:str]
wlanCarina: ENC[AES256_GCM,data:ugykYJujsQLk4RvwGw==,iv:Ge4c+bmUWcJCKv8cVXX1Wos14rCfUTA+AvLBLq4SsyM=,tag:9litWR7kWu8f+aml0MXzEQ==,type:str]
coredns:
cidrHomenet: ENC[AES256_GCM,data:Br7ixh52tVp4fqr9W6U=,iv:neSAnc66BXK++PhIIOQSrs5gyMtB2IX1nLwClTwemq8=,tag:bgqIL/nPOnbbRPjBXC0Azg==,type:str]
cidrTailnet: ENC[AES256_GCM,data:+ZqzEqfERBFHwTNV2w==,iv:9VZitgr4zvy3l/EwQx2M8P8fAo2UZ9sMQ7jp3Soblto=,tag:MWxn1PXtA3BLo/1WXRUrcg==,type:str]
ip: ENC[AES256_GCM,data:zucOcXk1dnGvhmlM,iv:rWIO6uMmMSNi+SvKtZGrCF1J/7hvvWzW6vZUqMkwQZg=,tag:/v93vM42IQJQJhd7kbGLbw==,type:str]
ipwlan: ENC[AES256_GCM,data:2aMXVAMm5TmPuPog,iv:B8Rl+udtRGBHSTij8w1xvxAaVcjyyuSwXJYwQKcqNQU=,tag:bp/EhvEGI0hK8+le0j8OKQ==,type:str]
iptailscale: ENC[AES256_GCM,data:eNAUjBp8Ad5E,iv:EOd/go9iW36tXjPr+T9J32RNIRk+oLG25GqWcUww2dI=,tag:03yCgvgSayY/gkQ73X74jA==,type:str]
localDNSCryptResolver: ENC[AES256_GCM,data:ANwDFvg1dMFF77jJ,iv:yIZOhD1G78saflyeR7BBqeM1s/PBGbeb5zg0hYLmGTo=,tag:nM41w2n1cfbkrhPdPJfoyw==,type:str]
ffsync:
masterSecret: ENC[AES256_GCM,data:os90pvduX4nni2pM6suYr7PODNitUSN3sqsu062eI9PE9XYM6aAVlCubFDBfzgDIs/UAZpULD5Q20ZXQF70gUllNS2QzEoaMU8NerrGWYufjZO8n4Xvm5K/zRTyZbjBcFgKwwC9pQ785oISnumX0EF7hWyfVv/XX5g0ietQOpgk=,iv:xSVg5QB9EzXmOWp+66Wu8tZQjQQ6DMJzYOT2lKNVFfM=,tag:XDmgsXNeP2lzTSVS2//kbg==,type:str]
tokenserverMetricsHashSecret: ENC[AES256_GCM,data:OGMjG+JfWdfo8q38QbauVEpJOTZLkW1IsCJjHCPcEbMxjvhyIWhON9iczIdkALiQgjY7RK8YzE3Uss8U/caqmqNszy8uJ7X31XV6fIpM57vHn0X9vPhcthcNG7qLgKZ4kouYLA4ERtpOhpaBGL1FJbJsYoJi3oA9PprxkRoz65M=,iv:pPzK7D4UlvuRDqAwFcPnwy1rWc5zm091q0qKafT0IZ4=,tag:xlH8DRzBoICknSgkYuRJdA==,type:str]
attic:
serverToken: ENC[AES256_GCM,data:jDdtY2pao7Hbfn09nCB2M9mag8tMOtVTZOkbFmc6XzKWu6cvQdkYqRVfWfl7mlig/7BRdKg+Y4N0D91NqhN7UWXJwCJ1ZjjipsahDMj95hYiOzMNuVx5Vg==,iv:EbEuGPgY20zeumOk8kQ7vppaCWj1IorjIroMMXXwJE4=,tag:Zo0vvQv0NM4yLhgryPqREw==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1nt7a9nsgwsf7c9x8yx3qu8w24svz02hpfuwtmk8dazw6j6lh33hsgv8erk
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0RWVwWDBtSFdxVzArbDUw
MDVxOHU0RSt5eVJRTE5zT2g1eVQwaDl6NEJJCmErblkxWkkrOG9Sbk14K2dtd3VZ
MFYrSDB2ejFBcnJQZFFsSktEblEzV0EKLS0tIGxzU0RRVXAybnFPZm9xNFJ5RU9p
b3grVTRBL2NqdkZyb2JkL2tRRzlHZXcKQ2h/wKDs0P1g2tXgfAi/DszSdLYhcbeL
hZP5Bb1zkCXadRlncRMMS05ZqAdErP0fTy410jcpX5iQFZqHA3zj5Q==
-----END AGE ENCRYPTED FILE-----
- recipient: age136558pknq6glx2xftavt7mm3p4jcpu54kej2kxryeu78m5r59e0qvawl5l
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzT2xKNmFKb0ZWNzF1Ymxj
cEs0cWFRdmlKb3pHSmNwajhyRWYwK0RTYnlZClVBUVV2NGNqWDdzMkVRNGZoT1J0
UFFUU1B0UVpWbENQTThrQUdSN2tINHMKLS0tIHc0ZlIxdXNXUEVYZWNTTFJxdE5z
ZHRmZ2lzci9ZVlJRVCsxa3pWNVl3eGcKFA9A2nwRcYMf/RnEHUgtxV53l/Kn6rhG
BEffZq7es2mZH6PEt5DZ4T8LZG2vi7H9RTQAfFBzGiocB41QIk50Nw==
-----END AGE ENCRYPTED FILE-----
- recipient: age15959gprm59azjflvpj97yt0lj6dj4d2yv0nd6u9jp32lzwp3de7qzhf85y
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2UDVoakZxTCtlSGN6ZGRx
clRCMzVLMGI2L1ZIcUc0bmFnS01oSFBjMkJnCmNoWE0zUy8ySll1YnV0Z0NpR0xD
aFJuVnBDU05ha3dSS2NhN3d4MWVnSWMKLS0tIGNDVTM0Z25BYWY5MkhDQm5Cd2JD
c200TjlWUnFqRCs4V0FjM25iT3YrZTQKfpfrN++o6SZerazvwpuiYLpvJL4Bb4U/
UIpMVS/rJhDrrBfMsCj253CRYRu73mbN28xnK+e68cl8l3EiMyEkEA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2023-11-01T22:20:35Z"
mac: ENC[AES256_GCM,data:tR1SlKiL9frBg3/KYrb8Igdgbx17mDreNOZEbkR1b7KmwoCvzJbO//5DT7yNPp4xiezTB/fW9xKNVSpBTJCbeifpj2hJGGC3VgUDpuZ9PiNcslIgvdw3tesGkRNq8srDgCx78CGl2q8wYxTtm4CjmjHv662OgNiXqbVHTRzOmZo=,iv:9SzPvUVlh8yNnSKEbaTyXw4JlQ0kbmR+L+9tyI3s2SU=,tag:wbq7R+tkt9uSGQzRs2g/Cw==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.7.3

@ -0,0 +1,7 @@
age-encryption.org/v1
-> ssh-ed25519 2raHcA UopagrzhQ7o6Ei5ohB/AKvXAQpYoymqzRfkSq6Te+FI
B4sKbyqTDQYLkAufkmCKpqNnfsBqRIFW9Na8Wmaes+0
-> -T{-grease &FHP)IRf ^^=1
sO0uI5cTK1vzegmFu6Z1MWOmdHl5KLNNt8zM
--- 9Yi8JpNjdS7+7f1iDqiMimO+NZPOWQlANzxv0+CRjh4
<EFBFBD>Ê2 öo€žó6+>nƒ€ Õ¯ÌbÏà<C38F>OšìÎc_¤x$¢M4ôYm0p“!Ž¹ ök qrÑ°åx@xüŠÿÒ;µú6³À˜FóÓ•°ãHE L²ô¡qéÏ6À¡áÇ0VÅÀ[h§ž®—ýè‡ûØ3¼9¹)öŸ><3E>îNç¡_ñ7ð°P(ù,

Binary file not shown.

@ -0,0 +1,7 @@
age-encryption.org/v1
-> ssh-ed25519 2raHcA 48PYTDeCjvtaFRWJIx7v4SNpXfEpyZLtZDv6v5ncTDg
17y3dtifigTR9UhE4pYwiL5mxHV55euqqHujAjRLfWA
-> 4v-grease
Ng4P0N2e3Y8
--- EA0m2jKaIGJTCpByITWXMpKYMOYl8YDhtQ36SWyamvQ
R4<€8h.:äêÏÉ# QO êßÐFƒ®äãÌ€ˆ ùíy™ÌÉ@@—<>ƒƒVž>Ò—4]Ú² t™Ðü°%ª!<21>aå‚ ÌyºFÈïoÞBÒŸm£.f &À-‡

@ -0,0 +1,7 @@
age-encryption.org/v1
-> ssh-ed25519 2raHcA iMG/QdssSuUj8g+BzXHVSmxVQhjFjSFSF2mXzsDLKyw
hyWCfDgSNeqdOMHvxLUlN4tIoNIkWbHLtFDgNe3PPnI
-> [ln-grease
Mg
--- Ftv6pBfLBnx+g53L2JlHuuEDnFSFyQCA64dRVm7A+Lk
z=£•êšq?<3F>KaW»“9¦ï.‰CW±Ûn¯<6E>ˆƒÕQCkr« ½¤ý³×âÞ5L=b«# ä]<³EqUizY$J8 1©è5‰ù<E280B0>ëªàÄXSÝJÖ{—YíË•f3'3ËÍͽ¶0Ô²bVL´ §MÿèMˆW$©¦ËÖÔ9½%€9 µàÂT{‡]<5D>¹…éK†-ªM<C2AA>û ó§®¥â<C2A5>AêÑ «a ת´þÇÒ6Î|Žû®hq¦ÃDÜÕ1|[õ=áìí¬!ˆ!Z£†—óââ

@ -0,0 +1,8 @@
age-encryption.org/v1
-> ssh-ed25519 2raHcA fLJf572ssCY1R/j8Ab6M78mVbu0LB4WnCoYWLUX0ThY
62C1EHeQw6TiEmvJzrnT6mL57KYrd0u3ac7fXLkysCc
-> k.)s"?Q{-grease xrn[$ K g/46Dt[ +BPLyp(2
Reov4yvYn+RO3uF24VMGVRbc7ON9FaJyTmKI6RTtN63eCV3so5N+857CAPX5Wgkl
9A9THJyJGmOiOH0
--- YFSiKZSahCQd0NzVN+cqbYudvqSVfaT93G5cCk7pF9o
½yfŸƒE`’©~)ůÑ5V?9øÛlהϜ®E8„”¿q wÙ`å<WTHƤ¤

@ -0,0 +1,10 @@
age-encryption.org/v1
-> ssh-ed25519 2raHcA HUqsFDZZMXcgzLwLg0qoCUGLg6KoQtHV2CULJD01ST8
/R7VIHIiH5OgObzxZ+uME1tsrd0pRXWw5nk7i5IfCZo
-> ssh-ed25519 6Tz/TQ IXXM4piUxgyVPFp85sI/5ZsZJR5X57QRky/9QZ+Cgw4
P3HNkpcbVnZyaAILG7J6Zcv4m3g62tOqeDtFIKt9ZQE
-> <b3-grease yE
HkAUC9ihXJrFvIzjlx6Mgf+iFgfSutNKGDPUgvlW0XjjgYmmn2rh8ZN9JNhRSCEW
3T94Hd+knmF4l7ppKeKDh2++iaxc7SrO
--- I8gutQ6AzRV/mx6F2WxXpUgPpxXAiEvqFWjKvGe/QTA
<EFBFBD>„+ŠøÙÈöÐǑ׼{{˜GÖÛÓéÄpÃWžÓ)+­hœ

@ -0,0 +1,21 @@
let
# lokiage.
user1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILKgwY12VnsfIKMNd0X/ZmevMdw2lEf1EUjbuxmmrsNb";
users = [user1];
system1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGzJL8/M+tTejrAPoomHKtlYk8lINBLHaH+p4SLt3sBG";
systems = [system1];
in {
"rootPassphrase.age".publicKeys = [user1];
"zoneInternal.age".publicKeys = [user1];
"zoneExternal.age".publicKeys = [user1];
"corednsEnv.age".publicKeys = [user1];
"autheliaStorage.age".publicKeys = [user1];
"autheliaJWT.age".publicKeys = [user1];
"autheliaEnv.age".publicKeys = [user1];
"domainName.age".publicKeys = [user1];
# "zfs-DATA.age".publicKeys = [user1 system1];
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

28
nix/modules/attic.nix Normal file

@ -0,0 +1,28 @@
{attic, ...}: {
services.atticd = {
settings = {
# Data chunking
#
# Warning: If you change any of the values here, it will be
# difficult to reuse existing chunks for newly-uploaded NARs
# since the cutpoints will be different. As a result, the
# deduplication ratio will suffer for a while after the change.
chunking = {
# The minimum NAR size to trigger chunking
#
# If 0, chunking is disabled entirely for newly-uploaded NARs.
# If 1, all NARs are chunked.
nar-size-threshold = 64 * 1024; # 64 KiB
# The preferred minimum size of a chunk, in bytes
min-size = 16 * 1024; # 16 KiB
# The preferred average size of a chunk, in bytes
avg-size = 64 * 1024; # 64 KiB
# The preferred maximum size of a chunk, in bytes
max-size = 256 * 1024; # 256 KiB
};
};
};
}

14
nix/modules/authelia.nix Normal file

@ -0,0 +1,14 @@
{...}: {
services.authelia.instances = {
main = {
enable = true;
settings = {
theme = "dark";
default_2fa_method = "totp";
log.level = "debug";
server.disable_healthcheck = false;
telemetry.metrics.enabled = true;
};
};
};
}

21
nix/modules/avahi.nix Normal file

@ -0,0 +1,21 @@
{
config,
pkgs,
...
}: {
services = {
avahi.enable = true;
avahi.openFirewall = true;
# avahi.nssmdns = true;
avahi.nssmdns = false; # configure nssModules manually below.
avahi.publish.enable = true;
avahi.publish.userServices = true;
};
# settings from avahi-daemon.nix where mdns is replaced with mdns4
system.nssModules = pkgs.lib.optional (!config.services.avahi.nssmdns) pkgs.nssmdns;
system.nssDatabases.hosts = with pkgs.lib;
optionals (!config.services.avahi.nssmdns) (mkMerge [
(mkBefore ["mdns4 [NOTFOUND=return]"]) # before resolve
]);
}

61
nix/modules/base.nix Normal file

@ -0,0 +1,61 @@
{
lib,
pkgs,
...
}: {
imports = [
./avahi.nix
./nix.nix
./packages.nix
./tailscale.nix
./sysctl.nix
./zsh.nix
];
boot.tmp.cleanOnBoot = true;
environment = {
variables = {
EDITOR = "vim";
PAGER = "less";
};
shells = with pkgs; [bash zsh];
};
# Select internationalisation properties.
i18n.defaultLocale = "en_GB.UTF-8";
console = {
# font = "Lat2-Terminus16";
keyMap = "uk";
# useXkbConfig = true; # use xkbOptions in tty.
};
programs.zsh.enable = true;
programs.zsh.enableCompletion = true;
security = {
rtkit.enable = true;
sudo.extraConfig = "Defaults timestamp_timeout=300";
};
services = {
earlyoom = {
enable = true;
enableNotifications = true;
freeMemThreshold = 5;
};
openssh.enable = true;
openssh.openFirewall = true;
};
systemd.extraConfig = "DefaultLimitNOFILE=1048576";
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = lib.mkDefault "23.11";
# Set your time zone.
time.timeZone = lib.mkForce "Europe/Berlin";
}

@ -0,0 +1,67 @@
{
lib,
buildGoModule,
fetchFromGitHub,
plugins ? [],
vendorSha256 ? "",
pkgs,
}:
with lib; let
imports = flip concatMapStrings plugins (pkg: "\t\t\t_ \"${pkg}\"\n");
main = ''
package main
import (
caddycmd "github.com/caddyserver/caddy/v2/cmd"
${imports}
_ "github.com/caddyserver/caddy/v2/modules/standard"
)
func main() {
caddycmd.Main()
}
'';
in
pkgs.buildGo121Module rec {
pname = "caddy";
version = "2.7.4";
# version = "latest";
subPackages = ["cmd/caddy"];
ldflags = [
"-s -w"
];
src = fetchFromGitHub {
owner = "caddyserver";
repo = pname;
rev = "v${version}";
sha256 = "sha256-oZSAY7vS8ersnj3vUtxj/qKlLvNvNL2RQHrNr4Cc60k=";
};
inherit vendorSha256;
overrideModAttrs = _: {
preBuild = "echo '${main}' > cmd/caddy/main.go && go mod tidy";
postInstall = "cp go.sum go.mod $out/ && ls $out/";
};
postPatch = ''
echo '${main}' > cmd/caddy/main.go
cat cmd/caddy/main.go
'';
postConfigure = ''
cp vendor/go.sum ./
cp vendor/go.mod ./
'';
meta = with lib; {
homepage = https://caddyserver.com;
description = "Fast, cross-platform HTTP/2 web server with automatic HTTPS";
license = licenses.asl20;
maintainers = with maintainers; [rushmorem fpletz zimbatm];
};
}

118
nix/modules/dnscrypt.nix Normal file

@ -0,0 +1,118 @@
{lib, ...}: {
services.dnscrypt-proxy2 = {
enable = true;
# don't go from scratch.
upstreamDefaults = true;
settings = {
listen_addresses = [
"127.0.0.1:53"
"[::1]:53"
];
ipv4_servers = true;
ipv6_servers = false;
dnscrypt_servers = true;
doh_servers = true;
odoh_servers = false;
require_dnssec = true;
require_nolog = true;
require_nofilter = true;
disabled_server_names = [
"google-ipv6"
"cloudflare"
"cloudflare-ipv6"
"cisco"
"cisco-ipv6"
"cisco-familyshield"
"cisco-familyshield-ipv6"
"yandex"
"apple"
"doh.dns.apple.com"
"ffmuc.net"
# "dnswarden-uncensor-dc",
# "dnswarden-uncensor-dc-swiss",
# "techsaviours.org-dnscrypt",
"dns.watch"
"pryv8boi"
"dct-at1"
"dct-ru1"
"dct-de1"
# "dnscrypt.be",
# "meganerd",
"scaleway-ams"
"scaleway-fr"
"dnscrypt.pl"
"acsacsar-ams-ipv4"
"dnscrypt.uk-ipv4"
"adguard-dns-unfiltered"
];
http3 = true;
timeout = 1000;
keepalive = 30;
lb_strategy = "p7";
lb_estimator = true;
log_level = 2;
use_syslog = true;
cert_refresh_delay = 60;
bootstrap_resolvers = [
"9.9.9.9:53"
"84.200.69.80:53"
"84.200.70.40:53"
"185.38.27.139:53"
"130.226.161.34:53"
# "[2a01:3a0:53:53::]:53"
# "[2001:67c:28a4::]:53"
# "[2001:1608:10:25::1c04:b12f]:53"
];
ignore_system_dns = true;
# never timeout;
netprobe_timeout = -1;
netprobe_address = "9.9.9.9:53";
# netprobe_address = "144.91.70.62:80";
block_ipv6 = false;
block_unqualified = true;
# block_undelegated = true;
block_undelegated = false;
reject_ttl = 10;
cache = true;
cache_size = 10000;
cache_min_ttl = 2400;
cache_max_ttl = 86400;
cache_neg_min_ttl = 60;
cache_neg_max_ttl = 600;
sources.opennic = {
urls = [
"https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/opennic.md"
"https://download.dnscrypt.info/resolvers-list/v3/opennic.md"
];
minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3";
cache_file = "/var/cache/dnscrypt-proxy/opennic.md";
refresh_delay = 24;
prefix = "";
};
static."dotya.ml".stamp = "sdns://AQcAAAAAAAAAETE0NC45MS43MC42Mjo1NDQzIHF-JiN46cNwFXJleEVWGWgrhe2QeysUtZoo9HwzYCMzITIuZG5zY3J5cHQtY2VydC5kbnNjcnlwdC5kb3R5YS5tbA";
#sources.public-resolvers = {
# urls = [
# "https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md"
# "https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md"
# ];
# cache_file = "/var/lib/dnscrypt-proxy2/public-resolvers.md";
# minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3";
#};
# You can choose a specific set of servers from https://github.com/DNSCrypt/dnscrypt-resolvers/blob/master/v3/public-resolvers.md
# server_names = [ ... ];
};
};
systemd.services.dnscrypt-proxy2.serviceConfig = {
StateDirectory = "dnscrypt-proxy";
WorkingDirectory = "/";
# StartLimitIntervalSec = 5;
StartLimitBurst = 10;
Restart = "always";
RestartSec = 7;
};
}

@ -0,0 +1,73 @@
{
config,
pkgs,
sops-nix,
...
}: let
domain = p.domainName;
d = p.shortDomain;
p = config.sops.placeholder;
svc = "firefox-syncserver.service";
in {
# ref: https://nixos.org/manual/nixos/stable/#module-services-firefox-syncserver
sops = {
secrets = {
"shortDomain" = {
restartUnits = [svc];
};
"ffsync/masterSecret" = {
restartUnits = [svc];
};
"ffsync/tokenserverMetricsHashSecret" = {
restartUnits = [svc];
};
};
templates = {
ffsync-secrets = {
content = ''
SYNC_MASTER_SECRET=${p."ffsync/masterSecret"}
SYNC_TOKENSERVER__FXA_METRICS_HASH_SECRET=${p."ffsync/tokenserverMetricsHashSecret"}
'';
};
};
};
services.mysql.package = pkgs.mariadb;
services.firefox-syncserver = {
enable = true;
secrets = config.sops.templates.ffsync-secrets.path;
#secrets = builtins.toFile "sync-secrets" ''
# SYNC_MASTER_SECRET=this-secret-is-actually-leaked-to-/nix/store
#'';
database.createLocally = true;
singleNode = {
# autoconfigure.
enable = true;
hostname = "localhost";
# hostname = "ffsync." + domain;
# hostname = "ffsync." + d;
# url = "https://ffsync." + d;
# url = "https://ffsync." + domain;
# url = "https://ffsync.${domain}";
#url = "http://localhost:" + toString config.services.firefox-syncserver.settings.port;
# url = "http://localhost:5000";
};
settings = {
port = 5678;
syncserver = {
public_url = "https://ffsync.${domain}/";
sqluri = "sqlite://///tmp/syncserver.db";
};
browserid = {
backend = "tokenserver.verifiers.LocalVerifier";
audiences = "https://ffsync.${domain}/";
};
tokenserver = {
node_type = "sqlite";
};
};
};
systemd.services.firefox-syncserver.wants = ["sops-nix.service"];
}

@ -0,0 +1,7 @@
{config, ...}: {
services.nix-serve = {
enable = true;
openFirewall = true;
bindAddress = "127.0.0.1";
};
}

18
nix/modules/nix.nix Normal file

@ -0,0 +1,18 @@
{pkgs, ...}: {
nix = {
gc.automatic = true;
gc.options = "--delete-older-than 30d";
optimise.automatic = true;
settings = {
experimental-features = ["nix-command" "flakes" "recursive-nix"];
keep-derivations = true;
keep-outputs = true;
auto-optimise-store = true;
fallback = true;
sandbox = true;
trusted-public-keys = ["nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="];
trusted-substituters = ["trusted-substituters = https://nix-community.cachix.org https://cache.nixos.org"];
};
package = pkgs.nixUnstable;
};
}

48
nix/modules/packages.nix Normal file

@ -0,0 +1,48 @@
{pkgs, ...}: {
environment = {
# https://github.com/NixOS/nixpkgs/issues/195795
defaultPackages = [];
# List packages installed in system profile. To search, run:
# $ nix search wget
systemPackages = with pkgs; [
vim
git
curl
wget
rsync
file
gnused
bat
p7zip
zstd
b3sum
btop
htop
iotop
lsof
tcpdump
dnsutils
netcat
ethtool
avahi
nix-zsh-completions
direnv
sops
age
starship
eza
silver-searcher
ripgrep
zellij
du-dust
# dhall
tailscale
];
};
}

146
nix/modules/sysctl.nix Normal file

@ -0,0 +1,146 @@
{...}: {
boot.kernel.sysctl = {
"kernel.panic" = 60;
"vm.swappiness" = 2;
#"vm.vfs_cache_pressure" = 80;
"net.ipv4.ip_forward" = 1;
#"net.ipv4.tcp_window_scaling" = 0;
# as per https://wiki.archlinux.org/index.php/Sysctl#Improving_performance
"net.core.rmem_default" = 1048576;
"net.core.rmem_max" = 16777216;
# "net.core.rmem_max" = 268435456;
"net.core.wmem_default" = 1048576;
"net.core.wmem_max" = 16777216;
# "net.core.wmem_max" = 268435456;
"net.core.optmem_max" = 65536;
# https://unix.stackexchange.com/a/471951
#
# "net.ipv4.tcp_rmem" = "4096 87380 20097152";
# "net.ipv4.tcp_wmem" = "4096 65536 16777216";
"net.ipv4.tcp_rmem" = "4096 87380 134217728";
"net.ipv4.tcp_wmem" = "4096 65536 134217728";
"net.ipv4.udp_rmem_min" = 8192;
"net.ipv4.udp_wmem_min" = 8192;
# TCP Fast Open is an extension to the transmission control protocol (TCP) that
# helps reduce network latency by enabling data to be exchanged during the
# sender's initial TCP SYN. Using the value 3 instead of the default 1 allows
# TCP Fast Open for both incoming and outgoing connections
"net.ipv4.tcp_fastopen" = 3;
# tcp_max_tw_buckets is the maximum number of sockets in TIME_WAIT state.
# After reaching this number the system will start destroying the socket that
# are in this state. Increase this to prevent simple DOS attacks
"net.ipv4.tcp_max_tw_buckets" = 2000000;
# tcp_tw_reuse sets whether TCP should reuse an existing connection in the
# TIME-WAIT state for a new outgoing connection if the new timestamp is
# strictly bigger than the most recent timestamp recorded for the previous
# connection.
# This helps avoid from running out of available network sockets
"net.ipv4.tcp_tw_reuse" = 1;
# With the following settings, your application will detect dead TCP
# connections after 120 seconds (60s + 10s + 10s + 10s + 10s + 10s + 10s).
"net.ipv4.tcp_keepalive_time" = 60;
"net.ipv4.tcp_keepalive_intvl" = 10;
"net.ipv4.tcp_keepalive_probes" = 6;
"net.ipv4.conf.default.rp_filter" = 2;
"net.ipv4.conf.all.rp_filter" = 2;
"net.ipv4.conf.default.log_martians" = 1;
"net.ipv4.conf.all.log_martians" = 1;
# Route cache is full: consider increasing sysctl net.ipv6.route.max_size
# net.ipv6.route.max_size = 8192;
"net.ipv6.route.max_size" = 65536;
# https://developer.akamai.com/blog/2012/09/27/linux-tcpip-tuning-scalability
"net.ipv4.ip_local_port_range" = "18000 65535";
#"net.netfilter.nf_conntrack_tcp_timeout_time_wait" = 30;
"net.netfilter.nf_conntrack_tcp_timeout_time_wait" = 60;
"net.netfilter.nf_conntrack_tcp_timeout_established" = 600;
"net.ipv4.tcp_slow_start_after_idle" = 0;
"net.ipv4.tcp_no_metrics_save" = 1;
# doesn't work on arch with Zen, works on fedora with XanMod.
"net.core.default_qdisc" = "fq";
# failed to initialize inotify - default value here was 128
"fs.inotify.max_user_instances" = 256;
"net.ipv4.tcp_window_scaling" = 1;
# The longer the maximum transmission unit (MTU) the better for performance,
# but the worse for reliability. This is because a lost packet means more data
# to be retransmitted and because many routers on the Internet cannot deliver
# very long packets
"net.ipv4.tcp_mtu_probing" = 1;
# sync disk when buffer reach 6% of memory
"vm.dirty_ratio" = 6;
"kernel.numa_balancing" = 1;
"net.core.netdev_max_backlog" = 250000;
# tcp_max_syn_backlog is the maximum queue length of pending connections
# 'Waiting Acknowledgment'. In the event of a synflood DOS attack, this queue
# can fill up pretty quickly, at which point TCP SYN cookies will kick in
# allowing your system to continue to respond to legitimate traffic, and
# allowing you to gain access to block malicious IPs. If the server suffers
# from overloads at peak times, you may want to increase this value a little
# bit
"net.ipv4.tcp_max_syn_backlog" = 8192;
# TCP SYN cookie protection
# Helps protect against SYN flood attacks. Only kicks in when
# net.ipv4.tcp_max_syn_backlog is reached. More details at, for example, [6].
# As of linux 5.10, it is set by default.
"net.ipv4.tcp_syncookies" = 1;
# Protect against tcp time-wait assassination hazards, drop RST packets for
# sockets in the time-wait state. Not widely supported outside of Linux, but
# conforms to RFC
"net.ipv4.tcp_rfc1337" = 1;
# Specify how many seconds to wait for a final FIN packet before the socket is
# forcibly closed. This is strictly a violation of the TCP specification, but
# required to prevent denial-of-service attacks. In Linux 2.2, the default
# value was 180
"net.ipv4.tcp_fin_timeout" = 30;
# When an attacker is trying to exploit the local kernel, it is often
# helpful to be able to examine where in memory the kernel, modules,
# and data structures live. As such, kernel addresses should be treated
# as sensitive information.
#
# Many files and interfaces contain these addresses (e.g. /proc/kallsyms,
# /proc/modules, etc), and this setting can censor the addresses. A value
# of "0" allows all users to see the kernel addresses. A value of "1"
# limits visibility to the root user, and "2" blocks even the root user.
"kernel.kptr_restrict" = 1;
# mitigate JIT spraying attacks from unprivileged users
"net.core.bpf_jit_harden" = 1;
# disallow regular users to run BPF programs
"kernel.unprivileged_bpf_disabled" = 0;
"fs.protected_fifos" = 1;
"fs.protected_symlinks" = 1;
"fs.protected_hardlinks" = 1;
"fs.protected_regular" = 2;
# full randomisation
"kernel.randomize_va_space" = 2;
"kernel.pid_max " = 4194304;
# ad rootless podman
"user.max_user_namespaces" = 15000;
"net.ipv4.ping_group_range" = "0 2000000";
};
}

10
nix/modules/tailscale.nix Normal file

@ -0,0 +1,10 @@
{config, ...}: {
services.tailscale.enable = true;
networking.firewall = {
trustedInterfaces = [config.services.tailscale.interfaceName];
allowedUDPPorts = [config.services.tailscale.port];
# specifically for Tailscale.
checkReversePath = "loose";
};
}

@ -0,0 +1,3 @@
{config, ...}: {
services.uptime-kuma.enable = true;
}

77
nix/modules/zsh.nix Normal file

@ -0,0 +1,77 @@
{pkgs, ...}: {
users.defaultUserShell = pkgs.zsh;
programs.zsh.interactiveShellInit = ''
if [[ ! -f $HOME/.local/share/zinit/zinit.git/zinit.zsh ]]; then
print -P "%F{33} %F{220}Installing %F{33}ZDHARMA-CONTINUUM%F{220} Initiative Plugin Manager (%F{33}zdharma-continuum/zinit%F{220})%f"
command mkdir -p "$HOME/.local/share/zinit" && command chmod g-rwX "$HOME/.local/share/zinit"
command git clone https://github.com/zdharma-continuum/zinit "$HOME/.local/share/zinit/zinit.git" && \
print -P "%F{33} %F{34}Installation successful.%f%b" || \
print -P "%F{160} The clone has failed.%f%b"
fi
source "$HOME/.local/share/zinit/zinit.git/zinit.zsh"
autoload -Uz _zinit
(( ''${+_comps} )) && _comps[zinit]=_zinit
# Load the pure theme, with zsh-async library that's bundled with it.
zi ice pick"async.zsh" src"pure.zsh"
zi light sindresorhus/pure
# A glance at the new for-syntax - load all of the above
# plugins with a single command. For more information see:
# https://zdharma-continuum.github.io/zinit/wiki/For-Syntax/
zinit for \
light-mode \
zsh-users/zsh-autosuggestions \
light-mode \
zdharma-continuum/fast-syntax-highlighting \
zdharma-continuum/history-search-multi-word #\
#light-mode \
#pick"async.zsh" \
#src"pure.zsh" \
#sindresorhus/pure
zinit ice wait"2" lucid # load after 2 seconds
zinit load zdharma-continuum/history-search-multi-word
zinit load sindresorhus/pure
zi ice as"program" make'!' atclone'./direnv hook zsh > zhook.zsh' atpull'%atclone' src"zhook.zsh"
zi light direnv/direnv
plugins=(
git
gitignore
golang
# fzf
terraform
systemd
safe-paste
colored-man-pages
)
zi snippet OMZP::git
zi snippet OMZP::gitignore
zi snippet OMZP::golang
# zi snippet OMZP::fzf
zi snippet OMZP::systemd
zi snippet OMZP::terraform
zi snippet OMZP::safe-paste
zi snippet OMZP::colored-man-pages
HISTSIZE=10000
SAVEHIST=10000
setopt inc_append_history
setopt extended_history # write the history file in the ":start:elapsed;command" format
setopt share_history
setopt hist_expire_dups_first # expire duplicate entries first when trimming history
setopt hist_ignore_dups
setopt hist_ignore_all_dups
setopt hist_save_no_dups
setopt hist_ignore_space
setopt hist_reduce_blanks # remove superfluous blanks before recording entry
setopt hist_verify # don't execute immediately after expansion
# eval "$(starship init zsh)"
# zinit load sindresorhus/pure
'';
}