Compare commits
152 Commits
kexec_luks
...
f4e40955c8
| Author | SHA1 | Date | |
|---|---|---|---|
| f4e40955c8 | |||
| af9e462b27 | |||
| 2faea9d380 | |||
| 8571922796 | |||
| 131d5e9313 | |||
| fe0ce3a245 | |||
| 7b26cfb4eb | |||
| 1c9fa418b3 | |||
| 8c4dc9cb74 | |||
| 1f9fbd87ac | |||
| 23c8076e4d | |||
| 75ae399b5a | |||
| 87ddad27a4 | |||
| 8dd2a00123 | |||
| 944a783ff2 | |||
| c2cb43fd2c | |||
| 02b2fb6309 | |||
| b43660aaef | |||
| 567d755850 | |||
| adc9b9f2b7 | |||
| 9181e3bfa3 | |||
| 9845270512 | |||
| b3b3044690 | |||
| fb1970c316 | |||
| 34f1edf3b3 | |||
| 823f0a6ef2 | |||
| 00d2ccc684 | |||
| b2acaff783 | |||
| c51f4ad65b | |||
| eb6a50664c | |||
| 89ce0f7fc0 | |||
| 8ff552818b | |||
| 020689d987 | |||
| 9109e356bd | |||
| c7d9e84f73 | |||
| 5b666a0565 | |||
| 6bc11767ca | |||
| bdd2d9bef9 | |||
| 5acc8b3fca | |||
| 1e25d8bb71 | |||
| ac1cf1c531 | |||
| 02357198bc | |||
| 89b49aafc0 | |||
| e56271b2c3 | |||
| f9ef5e4b89 | |||
| e516bd87b5 | |||
| 7c9c657bd0 | |||
| dff7d65456 | |||
| d269d2e5a0 | |||
| 2527b614e9 | |||
| 528a53a606 | |||
| 66bfc62566 | |||
| 91874b9d53 | |||
| 50fc0a53d2 | |||
| 0b3322afda | |||
| b32f6fa315 | |||
| fe41ffc788 | |||
| eac443f280 | |||
| d557820d6c | |||
| 4d658e10d3 | |||
| 9ac9613d67 | |||
| e657ebb134 | |||
| d1b07ec06b | |||
| 89621945f8 | |||
| e69fd5bf8f | |||
| c856b762e7 | |||
| b7f82f2d44 | |||
| 588e94dcf4 | |||
| fd1ead0b62 | |||
| 37bd7254b9 | |||
| 74e41de9d6 | |||
| 0bf0b8b88b | |||
| 702129d778 | |||
| 88c67dde84 | |||
| 8e3a0761e8 | |||
| a785890990 | |||
| b482a8c106 | |||
| efe50be604 | |||
| 99904d0066 | |||
| 55e44bc3d0 | |||
| da7ffa839b | |||
| 01af25a57e | |||
| bfc1bb2da9 | |||
| 0e59fa3518 | |||
| 7e812001f0 | |||
| 14c19b80ef | |||
| e8dd0cb5ff | |||
| dc9f5e969a | |||
| 03150667b6 | |||
| 1dfd7bc8a2 | |||
| fa649b1e2a | |||
| e34752c791 | |||
| 75031567bd | |||
| 800a95d431 | |||
| 932b05a42e | |||
| b5cc4d4609 | |||
| ba3d15d82a | |||
| e80fb7b3db | |||
| 84e1f6e573 | |||
| c4847bd39b | |||
| c0c1ec5c67 | |||
| 6739115cfb | |||
| 4606cc32ba | |||
| 2d27bf7505 | |||
| d07af6d101 | |||
| 4890dc20e0 | |||
| 8b01a9b240 | |||
| 8dfba8646c | |||
| 63c0f52955 | |||
| 5413a8e7db | |||
| 330c801e43 | |||
| 8ba08ce982 | |||
| 2b50aeba93 | |||
| c1aef574b1 | |||
| 52ed25f1b9 | |||
| 0446d18712 | |||
| d2bbbb827e | |||
| 6fba594625 | |||
| fa6e092c06 | |||
| 3a6dae2b82 | |||
| 62bb740634 | |||
| 577e0d21bc | |||
| b481a518f5 | |||
| f93b2c6908 | |||
| 890b24200e | |||
| d3259457de | |||
| 8eb42ee68b | |||
| 9d4c48badb | |||
| 9cf2b82e92 | |||
| 61ca918cca | |||
| ef61792da4 | |||
| 3dc97f4960 | |||
| f4a26a8d15 | |||
| 37782a26d5 | |||
| 1434bd2df1 | |||
| e49ea3a7c4 | |||
| 9a6cde1e89 | |||
| 35972b6d68 | |||
| b8021c1756 | |||
| 4b21489141 | |||
| a256ab7728 | |||
| da7ebe7baa | |||
| 1922bbbcfd | |||
| b17be86927 | |||
| ec73a63e09 | |||
| af26a004e5 | |||
| d83782f315 | |||
| 162b544249 | |||
| 0c58e62ed4 | |||
| 96de109d62 | |||
| 0efcf8f3fc | |||
| 2009180827 |
19
.gitea/workflows/check-flake.yaml
Normal file
19
.gitea/workflows/check-flake.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
name: Check Flake
|
||||
|
||||
on: [push]
|
||||
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
PATH: /run/current-system/sw/bin/
|
||||
|
||||
jobs:
|
||||
check-flake:
|
||||
runs-on: nixos
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check Flake
|
||||
run: nix flake check --all-systems --print-build-logs --log-format raw --show-trace
|
||||
32
Makefile
Normal file
32
Makefile
Normal file
@@ -0,0 +1,32 @@
|
||||
# Lockfile utils
|
||||
.PHONY: update-lockfile
|
||||
update-lockfile:
|
||||
nix flake update --commit-lock-file
|
||||
|
||||
.PHONY: update-lockfile-without-commit
|
||||
update-lockfile-without-commit:
|
||||
nix flake update
|
||||
|
||||
# Agenix utils
|
||||
.PHONY: edit-secret
|
||||
edit-secret:
|
||||
cd secrets && agenix -e $(filter-out $@,$(MAKECMDGOALS))
|
||||
|
||||
.PHONY: rekey-secrets
|
||||
rekey-secrets:
|
||||
cd secrets && agenix -r
|
||||
|
||||
# NixOS utils
|
||||
.PHONY: clean-old-nixos-profiles
|
||||
clean-old-nixos-profiles:
|
||||
doas nix-collect-garbage -d
|
||||
|
||||
# Garbage Collect
|
||||
.PHONY: gc
|
||||
gc:
|
||||
nix store gc
|
||||
|
||||
# Update a flake input by name (ex: 'nixpkgs')
|
||||
.PHONY: update-input
|
||||
update-input:
|
||||
nix flake update $(filter-out $@,$(MAKECMDGOALS))
|
||||
@@ -4,7 +4,7 @@
|
||||
- `/common` - common configuration imported into all `/machines`
|
||||
- `/boot` - config related to bootloaders, cpu microcode, and unlocking LUKS root disks over tor
|
||||
- `/network` - config for tailscale, and NixOS container with automatic vpn tunneling via PIA
|
||||
- `/pc` - config that a graphical desktop computer should have. Use `de.enable = true;` to enable everthing.
|
||||
- `/pc` - config that a graphical PC should have. Have the `personal` role set in the machine's `properties.nix` to enable everthing.
|
||||
- `/server` - config that creates new nixos services or extends existing ones to meet my needs
|
||||
- `/machines` - all my NixOS machines along with their machine unique configuration for hardware and services
|
||||
- `/kexec` - a special machine for generating minimal kexec images. Does not import `/common`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
{ config, lib, ... }:
|
||||
|
||||
# Modify auto-update so that it pulls a flake
|
||||
|
||||
@@ -6,20 +6,10 @@ let
|
||||
cfg = config.system.autoUpgrade;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable (lib.mkMerge [
|
||||
{
|
||||
system.autoUpgrade = {
|
||||
flake = "git+https://git.neet.dev/zuckerberg/nix-config.git";
|
||||
flags = [ "--recreate-lock-file" "--no-write-lock-file" ]; # ignore lock file, just pull the latest
|
||||
|
||||
# dates = "03:40";
|
||||
# kexecWindow = lib.mkDefault { lower = "01:00"; upper = "05:00"; };
|
||||
# randomizedDelaySec = "45min";
|
||||
};
|
||||
|
||||
system.autoUpgrade.allowKexec = lib.mkDefault true;
|
||||
|
||||
luks.enableKexec = cfg.allowKexec && builtins.length config.luks.devices > 0;
|
||||
}
|
||||
]);
|
||||
config = lib.mkIf cfg.enable {
|
||||
system.autoUpgrade = {
|
||||
flake = "git+https://git.neet.dev/zuckerberg/nix-config.git";
|
||||
flags = [ "--recreate-lock-file" "--no-write-lock-file" ]; # ignore lock file, just pull the latest
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
24
common/binary-cache.nix
Normal file
24
common/binary-cache.nix
Normal file
@@ -0,0 +1,24 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
{
|
||||
nix = {
|
||||
settings = {
|
||||
substituters = [
|
||||
"https://cache.nixos.org/"
|
||||
"https://nix-community.cachix.org"
|
||||
"http://s0.koi-bebop.ts.net:5000"
|
||||
];
|
||||
trusted-public-keys = [
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
"s0.koi-bebop.ts.net:OjbzD86YjyJZpCp9RWaQKANaflcpKhtzBMNP8I2aPUU="
|
||||
];
|
||||
|
||||
# Allow substituters to be offline
|
||||
# This isn't exactly ideal since it would be best if I could set up a system
|
||||
# so that it is an error if a derivation isn't available for any substituters
|
||||
# and use this flag as intended for deciding if it should build missing
|
||||
# derivations locally. See https://github.com/NixOS/nix/issues/6901
|
||||
fallback = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -10,18 +10,20 @@ in
|
||||
device = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
configurationLimit = mkOption {
|
||||
default = 20;
|
||||
type = types.int;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Use GRUB 2 for BIOS
|
||||
boot.loader = {
|
||||
timeout = 2;
|
||||
grub = {
|
||||
enable = true;
|
||||
device = cfg.device;
|
||||
version = 2;
|
||||
useOSProber = true;
|
||||
configurationLimit = 20;
|
||||
configurationLimit = cfg.configurationLimit;
|
||||
theme = pkgs.nixos-grub2-theme;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
./firmware.nix
|
||||
./efi.nix
|
||||
./bios.nix
|
||||
./kexec-luks.nix
|
||||
./luks.nix
|
||||
./remote-luks-unlock.nix
|
||||
];
|
||||
}
|
||||
|
||||
@@ -7,21 +7,23 @@ in
|
||||
{
|
||||
options.efi = {
|
||||
enable = mkEnableOption "enable efi boot";
|
||||
configurationLimit = mkOption {
|
||||
default = 20;
|
||||
type = types.int;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Use GRUB2 for EFI
|
||||
boot.loader = {
|
||||
efi.canTouchEfiVariables = true;
|
||||
timeout = 2;
|
||||
grub = {
|
||||
enable = true;
|
||||
device = "nodev";
|
||||
version = 2;
|
||||
efiSupport = true;
|
||||
useOSProber = true;
|
||||
# memtest86.enable = true;
|
||||
configurationLimit = 20;
|
||||
configurationLimit = cfg.configurationLimit;
|
||||
theme = pkgs.nixos-grub2-theme;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
# Allows kexec'ing as an alternative to rebooting for machines that
|
||||
# have luks encrypted partitions that need to be mounted at boot.
|
||||
# These luks partitions will be automatically unlocked, no password,
|
||||
# or any interaction needed whatsoever.
|
||||
|
||||
# This is accomplished by fetching the luks key(s) while the system is running,
|
||||
# then building a temporary initrd that contains the luks key(s), and kexec'ing.
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
options.luks = {
|
||||
enableKexec = lib.mkEnableOption "Enable support for transparent passwordless kexec while using luks";
|
||||
};
|
||||
|
||||
config = lib.mkIf config.luks.enableKexec {
|
||||
luks.fallbackToPassword = true;
|
||||
luks.disableKeyring = true;
|
||||
|
||||
boot.initrd.luks.devices = lib.listToAttrs
|
||||
(builtins.map
|
||||
(item:
|
||||
{
|
||||
name = item;
|
||||
value = {
|
||||
masterKeyFile = "/etc/${item}.key";
|
||||
};
|
||||
})
|
||||
config.luks.deviceNames);
|
||||
|
||||
systemd.services.prepare-luks-kexec-image = {
|
||||
description = "Prepare kexec automatic LUKS unlock on kexec reboot without a password";
|
||||
|
||||
wantedBy = [ "kexec.target" ];
|
||||
unitConfig.DefaultDependencies = false;
|
||||
serviceConfig.Type = "oneshot";
|
||||
|
||||
path = with pkgs; [ file kexec-tools coreutils-full cpio findutils gzip xz zstd lvm2 xxd gawk ];
|
||||
|
||||
# based on https://github.com/flowztul/keyexec
|
||||
script = ''
|
||||
system=/nix/var/nix/profiles/system
|
||||
old_initrd=$(readlink -f "$system/initrd")
|
||||
|
||||
umask 0077
|
||||
CRYPTROOT_TMPDIR="$(mktemp -d --tmpdir=/dev/shm)"
|
||||
|
||||
cleanup() {
|
||||
shred -fu "$CRYPTROOT_TMPDIR/initrd_contents/etc/"*.key || true
|
||||
shred -fu "$CRYPTROOT_TMPDIR/new_initrd" || true
|
||||
shred -fu "$CRYPTROOT_TMPDIR/secret/"* || true
|
||||
rm -rf "$CRYPTROOT_TMPDIR"
|
||||
}
|
||||
# trap cleanup INT TERM EXIT
|
||||
|
||||
mkdir -p "$CRYPTROOT_TMPDIR"
|
||||
cd "$CRYPTROOT_TMPDIR"
|
||||
|
||||
# Determine the compression type of the initrd image
|
||||
compression=$(file -b --mime-type "$old_initrd" | awk -F'/' '{print $2}')
|
||||
|
||||
# Decompress the initrd image based on its compression type
|
||||
case "$compression" in
|
||||
gzip)
|
||||
gunzip -c "$old_initrd" > initrd.cpio
|
||||
;;
|
||||
xz)
|
||||
unxz -c "$old_initrd" > initrd.cpio
|
||||
;;
|
||||
zstd)
|
||||
zstd -d -c "$old_initrd" > initrd.cpio
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported compression type: $compression"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Extract the contents of the cpio archive
|
||||
mkdir -p initrd_contents
|
||||
cd initrd_contents
|
||||
cpio -idv < ../initrd.cpio
|
||||
|
||||
# Generate keys and add them to the extracted initrd filesystem
|
||||
luksDeviceNames=(${builtins.concatStringsSep " " config.luks.deviceNames})
|
||||
for item in "''${luksDeviceNames[@]}"; do
|
||||
dmsetup --showkeys table "$item" | cut -d ' ' -f5 | xxd -ps -g1 -r > "./etc/$item.key"
|
||||
done
|
||||
|
||||
# Add normal initrd secrets too
|
||||
${lib.concatStringsSep "\n" (lib.mapAttrsToList (dest: source:
|
||||
let source' = if source == null then dest else builtins.toString source; in
|
||||
''
|
||||
mkdir -p $(dirname "./${dest}")
|
||||
cp -a ${source'} "./${dest}"
|
||||
''
|
||||
) config.boot.initrd.secrets)
|
||||
}
|
||||
|
||||
# Create a new cpio archive with the modified contents
|
||||
find . | cpio -o -H newc -v > ../new_initrd.cpio
|
||||
|
||||
# Compress the new cpio archive using the original compression type
|
||||
cd ..
|
||||
case "$compression" in
|
||||
gzip)
|
||||
gunzip -c new_initrd.cpio > new_initrd
|
||||
;;
|
||||
xz)
|
||||
unxz -c new_initrd.cpio > new_initrd
|
||||
;;
|
||||
zstd)
|
||||
zstd -c new_initrd.cpio > new_initrd
|
||||
;;
|
||||
esac
|
||||
|
||||
kexec --load "$system/kernel" --append "init=$system/init ${builtins.concatStringsSep " " config.boot.kernelParams}" --initrd "$CRYPTROOT_TMPDIR/new_initrd"
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
# Makes it a little easier to configure luks partitions for boot
|
||||
# Additionally, this solves a circular dependency between kexec luks
|
||||
# and NixOS's luks module.
|
||||
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.luks;
|
||||
|
||||
deviceCount = builtins.length cfg.devices;
|
||||
|
||||
deviceMap = lib.imap
|
||||
(i: item: {
|
||||
device = item;
|
||||
name =
|
||||
if deviceCount == 1 then "enc-pv"
|
||||
else "enc-pv${builtins.toString (i + 1)}";
|
||||
})
|
||||
cfg.devices;
|
||||
in
|
||||
{
|
||||
options.luks = {
|
||||
devices = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
allowDiscards = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
};
|
||||
|
||||
fallbackToPassword = lib.mkEnableOption
|
||||
"Fallback to interactive passphrase prompt if the cannot be found.";
|
||||
|
||||
disableKeyring = lib.mkEnableOption
|
||||
"When opening LUKS2 devices, don't use the kernel keyring";
|
||||
|
||||
# set automatically, don't touch
|
||||
deviceNames = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
{
|
||||
assertions = [
|
||||
{
|
||||
assertion = deviceCount == builtins.length (builtins.attrNames config.boot.initrd.luks.devices);
|
||||
message = ''
|
||||
All luks devices must be specified using `luks.devices` not `boot.initrd.luks.devices`.
|
||||
'';
|
||||
}
|
||||
];
|
||||
}
|
||||
(lib.mkIf (deviceCount != 0) {
|
||||
luks.deviceNames = builtins.map (device: device.name) deviceMap;
|
||||
|
||||
boot.initrd.luks.devices = lib.listToAttrs (
|
||||
builtins.map
|
||||
(item:
|
||||
{
|
||||
name = item.name;
|
||||
value = {
|
||||
device = item.device;
|
||||
allowDiscards = cfg.allowDiscards;
|
||||
fallbackToPassword = cfg.fallbackToPassword;
|
||||
disableKeyring = cfg.disableKeyring;
|
||||
};
|
||||
})
|
||||
deviceMap);
|
||||
})
|
||||
];
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
# TODO: use tailscale instead of tor https://gist.github.com/antifuchs/e30d58a64988907f282c82231dde2cbc
|
||||
|
||||
let
|
||||
cfg = config.remoteLuksUnlock;
|
||||
in
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
{ config, pkgs, ... }:
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./backups.nix
|
||||
./binary-cache.nix
|
||||
./flakes.nix
|
||||
./auto-update.nix
|
||||
./shell.nix
|
||||
@@ -11,20 +12,27 @@
|
||||
./server
|
||||
./pc
|
||||
./machine-info
|
||||
./nix-builder.nix
|
||||
./ssh.nix
|
||||
];
|
||||
|
||||
nix.flakes.enable = true;
|
||||
|
||||
system.stateVersion = "21.11";
|
||||
system.stateVersion = "23.11";
|
||||
|
||||
networking.useDHCP = false;
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
|
||||
networking.firewall.enable = true;
|
||||
networking.firewall.allowPing = true;
|
||||
|
||||
time.timeZone = "America/Denver";
|
||||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
time.timeZone = "America/Los_Angeles";
|
||||
i18n = {
|
||||
defaultLocale = "en_US.UTF-8";
|
||||
extraLocaleSettings = {
|
||||
LANGUAGE = "en_US.UTF-8";
|
||||
LC_ALL = "en_US.UTF-8";
|
||||
};
|
||||
};
|
||||
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
@@ -53,6 +61,8 @@
|
||||
lm_sensors
|
||||
picocom
|
||||
lf
|
||||
gnumake
|
||||
tree
|
||||
];
|
||||
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
@@ -88,4 +98,7 @@
|
||||
|
||||
security.acme.acceptTerms = true;
|
||||
security.acme.defaults.email = "zuckerberg@neet.dev";
|
||||
|
||||
# Enable Desktop Environment if this is a PC (machine role is "personal")
|
||||
de.enable = lib.mkDefault (config.thisMachine.hasRole."personal");
|
||||
}
|
||||
|
||||
@@ -10,16 +10,9 @@ in
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
nix = {
|
||||
package = pkgs.nixFlakes;
|
||||
extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
'';
|
||||
|
||||
# pin nixpkgs for system commands such as "nix shell"
|
||||
registry.nixpkgs.flake = config.inputs.nixpkgs;
|
||||
|
||||
# pin system nixpkgs to the same version as the flake input
|
||||
nixPath = [ "nixpkgs=${config.inputs.nixpkgs}" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,6 +5,90 @@
|
||||
|
||||
let
|
||||
machines = config.machines.hosts;
|
||||
|
||||
hostOptionsSubmoduleType = lib.types.submodule {
|
||||
options = {
|
||||
hostNames = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = ''
|
||||
List of hostnames for this machine. The first one is the default so it is the target of deployments.
|
||||
Used for automatically trusting hosts for ssh connections.
|
||||
'';
|
||||
};
|
||||
arch = lib.mkOption {
|
||||
type = lib.types.enum [ "x86_64-linux" "aarch64-linux" ];
|
||||
description = ''
|
||||
The architecture of this machine.
|
||||
'';
|
||||
};
|
||||
systemRoles = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str; # TODO: maybe use an enum?
|
||||
description = ''
|
||||
The set of roles this machine holds. Affects secrets available. (TODO add service config as well using this info)
|
||||
'';
|
||||
};
|
||||
hostKey = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The system ssh host key of this machine. Used for automatically trusting hosts for ssh connections
|
||||
and for decrypting secrets with agenix.
|
||||
'';
|
||||
};
|
||||
remoteUnlock = lib.mkOption {
|
||||
default = null;
|
||||
type = lib.types.nullOr (lib.types.submodule {
|
||||
options = {
|
||||
|
||||
hostKey = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The system ssh host key of this machine used for luks boot unlocking only.
|
||||
'';
|
||||
};
|
||||
|
||||
clearnetHost = lib.mkOption {
|
||||
default = null;
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
The hostname resolvable over clearnet used to luks boot unlock this machine
|
||||
'';
|
||||
};
|
||||
|
||||
onionHost = lib.mkOption {
|
||||
default = null;
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
The hostname resolvable over tor used to luks boot unlock this machine
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
});
|
||||
};
|
||||
userKeys = lib.mkOption {
|
||||
default = [ ];
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = ''
|
||||
The list of user keys. Each key here can be used to log into all other systems as `googlebot`.
|
||||
|
||||
TODO: consider auto populating other programs that use ssh keys such as gitea
|
||||
'';
|
||||
};
|
||||
deployKeys = lib.mkOption {
|
||||
default = [ ];
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = ''
|
||||
The list of deployment keys. Each key here can be used to log into all other systems as `root`.
|
||||
'';
|
||||
};
|
||||
configurationPath = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = ''
|
||||
The path to this machine's configuration directory.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
@@ -13,104 +97,16 @@ in
|
||||
];
|
||||
|
||||
options.machines = {
|
||||
|
||||
hosts = lib.mkOption {
|
||||
type = lib.types.attrsOf
|
||||
(lib.types.submodule {
|
||||
options = {
|
||||
|
||||
hostNames = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = ''
|
||||
List of hostnames for this machine. The first one is the default so it is the target of deployments.
|
||||
Used for automatically trusting hosts for ssh connections.
|
||||
'';
|
||||
};
|
||||
|
||||
arch = lib.mkOption {
|
||||
type = lib.types.enum [ "x86_64-linux" "aarch64-linux" ];
|
||||
description = ''
|
||||
The architecture of this machine.
|
||||
'';
|
||||
};
|
||||
|
||||
systemRoles = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str; # TODO: maybe use an enum?
|
||||
description = ''
|
||||
The set of roles this machine holds. Affects secrets available. (TODO add service config as well using this info)
|
||||
'';
|
||||
};
|
||||
|
||||
hostKey = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The system ssh host key of this machine. Used for automatically trusting hosts for ssh connections
|
||||
and for decrypting secrets with agenix.
|
||||
'';
|
||||
};
|
||||
|
||||
remoteUnlock = lib.mkOption {
|
||||
default = null;
|
||||
type = lib.types.nullOr (lib.types.submodule {
|
||||
options = {
|
||||
|
||||
hostKey = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The system ssh host key of this machine used for luks boot unlocking only.
|
||||
'';
|
||||
};
|
||||
|
||||
clearnetHost = lib.mkOption {
|
||||
default = null;
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
The hostname resolvable over clearnet used to luks boot unlock this machine
|
||||
'';
|
||||
};
|
||||
|
||||
onionHost = lib.mkOption {
|
||||
default = null;
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
description = ''
|
||||
The hostname resolvable over tor used to luks boot unlock this machine
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
userKeys = lib.mkOption {
|
||||
default = [ ];
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = ''
|
||||
The list of user keys. Each key here can be used to log into all other systems as `googlebot`.
|
||||
|
||||
TODO: consider auto populating other programs that use ssh keys such as gitea
|
||||
'';
|
||||
};
|
||||
|
||||
deployKeys = lib.mkOption {
|
||||
default = [ ];
|
||||
type = lib.types.listOf lib.types.str;
|
||||
description = ''
|
||||
The list of deployment keys. Each key here can be used to log into all other systems as `root`.
|
||||
'';
|
||||
};
|
||||
|
||||
configurationPath = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = ''
|
||||
The path to this machine's configuration directory.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
});
|
||||
type = lib.types.attrsOf hostOptionsSubmoduleType;
|
||||
};
|
||||
};
|
||||
|
||||
options.thisMachine.config = lib.mkOption {
|
||||
# For ease of use, a direct copy of the host config from machines.hosts.${hostName}
|
||||
type = hostOptionsSubmoduleType;
|
||||
};
|
||||
|
||||
config = {
|
||||
assertions = (lib.concatLists (lib.mapAttrsToList
|
||||
(
|
||||
@@ -196,5 +192,12 @@ in
|
||||
builtins.map (p: { "${dirName p}" = p; }) propFiles;
|
||||
in
|
||||
properties ../../machines;
|
||||
|
||||
# Don't try to evaluate "thisMachine" when reflecting using moduleless.nix.
|
||||
# When evaluated by moduleless.nix this will fail due to networking.hostName not
|
||||
# existing. This is because moduleless.nix is not intended for reflection from the
|
||||
# perspective of a perticular machine but is instead intended for reflecting on
|
||||
# the properties of all machines as a whole system.
|
||||
thisMachine.config = config.machines.hosts.${config.networking.hostName};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,19 +1,55 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
# Maps roles to their hosts
|
||||
# Maps roles to their hosts.
|
||||
# machines.withRole = {
|
||||
# personal = [
|
||||
# "machine1" "machine3"
|
||||
# ];
|
||||
# cache = [
|
||||
# "machine2"
|
||||
# ];
|
||||
# };
|
||||
#
|
||||
# A list of all possible roles
|
||||
# machines.allRoles = [
|
||||
# "personal"
|
||||
# "cache"
|
||||
# ];
|
||||
#
|
||||
# For each role has true or false if the current machine has that role
|
||||
# thisMachine.hasRole = {
|
||||
# personal = true;
|
||||
# cache = false;
|
||||
# };
|
||||
|
||||
{
|
||||
options.machines.roles = lib.mkOption {
|
||||
options.machines.withRole = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.listOf lib.types.str);
|
||||
};
|
||||
|
||||
options.machines.allRoles = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
};
|
||||
|
||||
options.thisMachine.hasRole = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.bool;
|
||||
};
|
||||
|
||||
config = {
|
||||
machines.roles = lib.zipAttrs
|
||||
machines.withRole = lib.zipAttrs
|
||||
(lib.mapAttrsToList
|
||||
(host: cfg:
|
||||
lib.foldl (lib.mergeAttrs) { }
|
||||
(builtins.map (role: { ${role} = host; })
|
||||
cfg.systemRoles))
|
||||
config.machines.hosts);
|
||||
|
||||
machines.allRoles = lib.attrNames config.machines.withRole;
|
||||
|
||||
thisMachine.hasRole = lib.mapAttrs
|
||||
(role: cfg:
|
||||
builtins.elem config.networking.hostName config.machines.withRole.${role}
|
||||
)
|
||||
config.machines.withRole;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,6 +39,6 @@ in
|
||||
builtins.map
|
||||
(host: machines.hosts.${host}.hostKey)
|
||||
hosts)
|
||||
machines.roles;
|
||||
machines.withRole;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
# TODO implement this module such that the wireguard VPN doesn't have to live in a container
|
||||
# TODO don't add forward rules if the PIA port is the same as cfg.forwardedPort
|
||||
# TODO verify signatures of PIA responses
|
||||
# TODO `RuntimeMaxSec = "30d";` for pia-vpn-wireguard-init isn't allowed per the systemd logs. Find alternative.
|
||||
|
||||
with builtins;
|
||||
with lib;
|
||||
@@ -143,14 +144,14 @@ in
|
||||
systemd.services.pia-vpn-wireguard-init = {
|
||||
description = "Creates PIA VPN Wireguard Interface";
|
||||
|
||||
requires = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network.target" "network-online.target" ];
|
||||
before = [ containerServiceName ];
|
||||
requiredBy = [ containerServiceName ];
|
||||
partOf = [ containerServiceName ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
path = with pkgs; [ wireguard-tools jq curl iproute ];
|
||||
path = with pkgs; [ wireguard-tools jq curl iproute2 iputils ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
@@ -162,6 +163,11 @@ in
|
||||
};
|
||||
|
||||
script = ''
|
||||
echo Waiting for internet...
|
||||
while ! ping -c 1 -W 1 1.1.1.1; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Prepare to connect by generating wg secrets and auth'ing with PIA since the container
|
||||
# cannot do without internet to start with. NAT'ing the host's internet would address this
|
||||
# issue but is not ideal because then leaking network outside of the VPN is more likely.
|
||||
@@ -214,11 +220,11 @@ in
|
||||
vpn-container.config.systemd.services.pia-vpn-wireguard = {
|
||||
description = "Initializes the PIA VPN WireGuard Tunnel";
|
||||
|
||||
requires = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network.target" "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
path = with pkgs; [ wireguard-tools iproute curl jq iptables ];
|
||||
path = with pkgs; [ wireguard-tools iproute2 curl jq iptables ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
|
||||
@@ -72,9 +72,6 @@ in
|
||||
config = {
|
||||
imports = allModules ++ [ cfg.config ];
|
||||
|
||||
# speeds up evaluation
|
||||
nixpkgs.pkgs = pkgs;
|
||||
|
||||
# networking.firewall.enable = mkForce false;
|
||||
networking.firewall.trustedInterfaces = [
|
||||
# completely trust internal interface to host
|
||||
|
||||
56
common/nix-builder.nix
Normal file
56
common/nix-builder.nix
Normal file
@@ -0,0 +1,56 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
builderUserName = "nix-builder";
|
||||
|
||||
builderRole = "nix-builder";
|
||||
builders = config.machines.withRole.${builderRole};
|
||||
thisMachineIsABuilder = config.thisMachine.hasRole.${builderRole};
|
||||
|
||||
# builders don't include themselves as a remote builder
|
||||
otherBuilders = lib.filter (hostname: hostname != config.networking.hostName) builders;
|
||||
in
|
||||
lib.mkMerge [
|
||||
# configure builder
|
||||
(lib.mkIf thisMachineIsABuilder {
|
||||
users.users.${builderUserName} = {
|
||||
description = "Distributed Nix Build User";
|
||||
group = builderUserName;
|
||||
isSystemUser = true;
|
||||
createHome = true;
|
||||
home = "/var/lib/nix-builder";
|
||||
useDefaultShell = true;
|
||||
openssh.authorizedKeys.keys = builtins.map
|
||||
(builderCfg: builderCfg.hostKey)
|
||||
(builtins.attrValues config.machines.hosts);
|
||||
};
|
||||
users.groups.${builderUserName} = { };
|
||||
|
||||
nix.settings.trusted-users = [
|
||||
builderUserName
|
||||
];
|
||||
})
|
||||
|
||||
# use each builder
|
||||
{
|
||||
nix.distributedBuilds = true;
|
||||
|
||||
nix.buildMachines = builtins.map
|
||||
(builderHostname: {
|
||||
hostName = builderHostname;
|
||||
system = config.machines.hosts.${builderHostname}.arch;
|
||||
protocol = "ssh-ng";
|
||||
sshUser = builderUserName;
|
||||
sshKey = "/etc/ssh/ssh_host_ed25519_key";
|
||||
maxJobs = 3;
|
||||
speedFactor = 10;
|
||||
supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ];
|
||||
})
|
||||
otherBuilders;
|
||||
|
||||
# It is very likely that the builder's internet is faster or just as fast
|
||||
nix.extraOptions = ''
|
||||
builders-use-substitutes = true
|
||||
'';
|
||||
}
|
||||
]
|
||||
@@ -19,6 +19,15 @@ in
|
||||
jack.enable = true;
|
||||
};
|
||||
|
||||
services.pipewire.extraConfig.pipewire."92-fix-wine-audio" = {
|
||||
context.properties = {
|
||||
default.clock.rate = 48000;
|
||||
default.clock.quantum = 256;
|
||||
default.clock.min-quantum = 256;
|
||||
default.clock.max-quantum = 2048;
|
||||
};
|
||||
};
|
||||
|
||||
users.users.googlebot.extraGroups = [ "audio" ];
|
||||
|
||||
# bt headset support
|
||||
|
||||
@@ -17,38 +17,6 @@ let
|
||||
"PREFIX=$(out)"
|
||||
];
|
||||
};
|
||||
|
||||
nvidia-vaapi-driver = pkgs.stdenv.mkDerivation rec {
|
||||
pname = "nvidia-vaapi-driver";
|
||||
version = "0.0.5";
|
||||
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "elFarto";
|
||||
repo = pname;
|
||||
rev = "v${version}";
|
||||
sha256 = "2bycqKolVoaHK64XYcReteuaON9TjzrFhaG5kty28YY=";
|
||||
};
|
||||
|
||||
patches = [
|
||||
./use-meson-v57.patch
|
||||
];
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
meson
|
||||
cmake
|
||||
ninja
|
||||
pkg-config
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
nv-codec-headers-11-1-5-1
|
||||
libva
|
||||
gst_all_1.gstreamer
|
||||
gst_all_1.gst-plugins-bad
|
||||
libglvnd
|
||||
];
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable {
|
||||
@@ -73,7 +41,7 @@ in
|
||||
"SpellcheckLanguage" = [ "en-US" ];
|
||||
};
|
||||
defaultSearchProviderSuggestURL = null;
|
||||
defaultSearchProviderSearchURL = " https://duckduckgo.com/?q={searchTerms}&kp=-1&kl=us-en";
|
||||
defaultSearchProviderSearchURL = "https://duckduckgo.com/?q={searchTerms}&kp=-1&kl=us-en";
|
||||
};
|
||||
|
||||
# hardware accelerated video playback (on intel)
|
||||
@@ -84,12 +52,12 @@ in
|
||||
# ungoogled = true;
|
||||
# --enable-native-gpu-memory-buffers # fails on AMD APU
|
||||
# --enable-webrtc-vp9-support
|
||||
commandLineArgs = "--use-vulkan --use-gl=desktop --enable-zero-copy --enable-hardware-overlays --enable-features=VaapiVideoDecoder,CanvasOopRasterization --ignore-gpu-blocklist --enable-accelerated-mjpeg-decode --enable-accelerated-video --enable-gpu-rasterization";
|
||||
commandLineArgs = "--use-vulkan";
|
||||
};
|
||||
};
|
||||
# todo vulkan in chrome
|
||||
# todo video encoding in chrome
|
||||
hardware.opengl = {
|
||||
hardware.graphics = {
|
||||
enable = true;
|
||||
extraPackages = with pkgs; [
|
||||
intel-media-driver # LIBVA_DRIVER_NAME=iHD
|
||||
|
||||
@@ -6,19 +6,18 @@ in
|
||||
{
|
||||
imports = [
|
||||
./kde.nix
|
||||
./xfce.nix
|
||||
./yubikey.nix
|
||||
./chromium.nix
|
||||
# ./firefox.nix
|
||||
./firefox.nix
|
||||
./audio.nix
|
||||
# ./torbrowser.nix
|
||||
./pithos.nix
|
||||
./spotify.nix
|
||||
./vscodium.nix
|
||||
./discord.nix
|
||||
./steam.nix
|
||||
./touchpad.nix
|
||||
./mount-samba.nix
|
||||
./udev.nix
|
||||
./virtualisation.nix
|
||||
];
|
||||
|
||||
options.de = {
|
||||
@@ -26,9 +25,10 @@ in
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
# vulkan
|
||||
hardware.opengl.driSupport = true;
|
||||
hardware.opengl.driSupport32Bit = true;
|
||||
environment.systemPackages = with pkgs; [
|
||||
# https://github.com/NixOS/nixpkgs/pull/328086#issuecomment-2235384618
|
||||
gparted
|
||||
];
|
||||
|
||||
# Applications
|
||||
users.users.googlebot.packages = with pkgs; [
|
||||
@@ -37,26 +37,25 @@ in
|
||||
mumble
|
||||
tigervnc
|
||||
bluez-tools
|
||||
vscodium
|
||||
element-desktop
|
||||
mpv
|
||||
nextcloud-client
|
||||
signal-desktop
|
||||
minecraft
|
||||
gparted
|
||||
libreoffice-fresh
|
||||
thunderbird
|
||||
spotifyd
|
||||
spotify-qt
|
||||
spotify
|
||||
arduino
|
||||
yt-dlp
|
||||
jellyfin-media-player
|
||||
joplin-desktop
|
||||
config.inputs.deploy-rs.packages.${config.currentSystem}.deploy-rs
|
||||
lxqt.pavucontrol-qt
|
||||
barrier
|
||||
|
||||
# For Nix IDE
|
||||
nixpkgs-fmt
|
||||
rnix-lsp
|
||||
nixd
|
||||
nil
|
||||
];
|
||||
|
||||
# Networking
|
||||
@@ -70,12 +69,30 @@ in
|
||||
];
|
||||
# Printer discovery
|
||||
services.avahi.enable = true;
|
||||
services.avahi.nssmdns = true;
|
||||
services.avahi.nssmdns4 = true;
|
||||
|
||||
programs.file-roller.enable = true;
|
||||
|
||||
# Security
|
||||
services.gnome.gnome-keyring.enable = true;
|
||||
security.pam.services.googlebot.enableGnomeKeyring = true;
|
||||
|
||||
# Android dev
|
||||
programs.adb.enable = true;
|
||||
|
||||
# Mount personal SMB stores
|
||||
services.mount-samba.enable = true;
|
||||
|
||||
# allow building ARM derivations
|
||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||
|
||||
# for luks onlock over tor
|
||||
services.tor.enable = true;
|
||||
services.tor.client.enable = true;
|
||||
|
||||
# Enable wayland support in various chromium based applications
|
||||
environment.sessionVariables.NIXOS_OZONE_WL = "1";
|
||||
|
||||
fonts.packages = with pkgs; [ nerd-fonts.symbols-only ];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,31 +20,6 @@ let
|
||||
};
|
||||
|
||||
firefox = pkgs.wrapFirefox somewhatPrivateFF {
|
||||
desktopName = "Sneed Browser";
|
||||
|
||||
nixExtensions = [
|
||||
(pkgs.fetchFirefoxAddon {
|
||||
name = "ublock-origin";
|
||||
url = "https://addons.mozilla.org/firefox/downloads/file/3719054/ublock_origin-1.33.2-an+fx.xpi";
|
||||
sha256 = "XDpe9vW1R1iVBTI4AmNgAg1nk7BVQdIAMuqd0cnK5FE=";
|
||||
})
|
||||
(pkgs.fetchFirefoxAddon {
|
||||
name = "sponsorblock";
|
||||
url = "https://addons.mozilla.org/firefox/downloads/file/3720594/sponsorblock_skip_sponsorships_on_youtube-2.0.12.3-an+fx.xpi";
|
||||
sha256 = "HRtnmZWyXN3MKo4AvSYgNJGkBEsa2RaMamFbkz+YzQg=";
|
||||
})
|
||||
(pkgs.fetchFirefoxAddon {
|
||||
name = "KeePassXC-Browser";
|
||||
url = "https://addons.mozilla.org/firefox/downloads/file/3720664/keepassxc_browser-1.7.6-fx.xpi";
|
||||
sha256 = "3K404/eq3amHhIT0WhzQtC892he5I0kp2SvbzE9dbZg=";
|
||||
})
|
||||
(pkgs.fetchFirefoxAddon {
|
||||
name = "https-everywhere";
|
||||
url = "https://addons.mozilla.org/firefox/downloads/file/3716461/https_everywhere-2021.1.27-an+fx.xpi";
|
||||
sha256 = "2gSXSLunKCwPjAq4Wsj0lOeV551r3G+fcm1oeqjMKh8=";
|
||||
})
|
||||
];
|
||||
|
||||
extraPolicies = {
|
||||
CaptivePortal = false;
|
||||
DisableFirefoxStudies = true;
|
||||
@@ -74,12 +49,6 @@ let
|
||||
ExtensionRecommendations = false;
|
||||
SkipOnboarding = true;
|
||||
};
|
||||
WebsiteFilter = {
|
||||
Block = [
|
||||
"http://paradigminteractive.io/"
|
||||
"https://paradigminteractive.io/"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
extraPrefs = ''
|
||||
|
||||
@@ -5,20 +5,16 @@ let
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable {
|
||||
# kde plasma
|
||||
services.xserver = {
|
||||
enable = true;
|
||||
desktopManager.plasma5.enable = true;
|
||||
displayManager.sddm.enable = true;
|
||||
};
|
||||
services.displayManager.sddm.enable = true;
|
||||
services.displayManager.sddm.wayland.enable = true;
|
||||
services.desktopManager.plasma6.enable = true;
|
||||
|
||||
# kde apps
|
||||
nixpkgs.config.firefox.enablePlasmaBrowserIntegration = true;
|
||||
users.users.googlebot.packages = with pkgs; [
|
||||
# akonadi
|
||||
# kmail
|
||||
# plasma5Packages.kmail-account-wizard
|
||||
kate
|
||||
kdePackages.kate
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ let
|
||||
auth_opts = "sec=ntlmv2i,credentials=/run/agenix/smb-secrets";
|
||||
version_opts = "vers=3.1.1";
|
||||
|
||||
public_user_opts = "gid=${toString config.users.groups.users.gid}";
|
||||
|
||||
opts = "${systemd_opts},${network_opts},${user_opts},${version_opts},${auth_opts}";
|
||||
in
|
||||
{
|
||||
@@ -24,7 +26,7 @@ in
|
||||
fileSystems."/mnt/public" = {
|
||||
device = "//s0.koi-bebop.ts.net/public";
|
||||
fsType = "cifs";
|
||||
options = [ opts ];
|
||||
options = [ "${opts},${public_user_opts}" ];
|
||||
};
|
||||
|
||||
fileSystems."/mnt/private" = {
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
{ lib, config, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.spotifyd;
|
||||
toml = pkgs.formats.toml { };
|
||||
spotifydConf = toml.generate "spotify.conf" cfg.settings;
|
||||
in
|
||||
{
|
||||
disabledModules = [
|
||||
"services/audio/spotifyd.nix"
|
||||
];
|
||||
|
||||
options = {
|
||||
services.spotifyd = {
|
||||
enable = mkEnableOption "spotifyd, a Spotify playing daemon";
|
||||
|
||||
settings = mkOption {
|
||||
default = { };
|
||||
type = toml.type;
|
||||
example = { global.bitrate = 320; };
|
||||
description = ''
|
||||
Configuration for Spotifyd. For syntax and directives, see
|
||||
<link xlink:href="https://github.com/Spotifyd/spotifyd#Configuration"/>.
|
||||
'';
|
||||
};
|
||||
|
||||
users = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ ];
|
||||
description = ''
|
||||
Usernames to be added to the "spotifyd" group, so that they
|
||||
can start and interact with the userspace daemon.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
# username specific stuff because i'm lazy...
|
||||
services.spotifyd.users = [ "googlebot" ];
|
||||
users.users.googlebot.packages = with pkgs; [
|
||||
spotify
|
||||
spotify-tui
|
||||
];
|
||||
|
||||
users.groups.spotifyd = {
|
||||
members = cfg.users;
|
||||
};
|
||||
|
||||
age.secrets.spotifyd = {
|
||||
file = ../../secrets/spotifyd.age;
|
||||
group = "spotifyd";
|
||||
mode = "0440"; # group can read
|
||||
};
|
||||
|
||||
# spotifyd to read secrets and run as user service
|
||||
services.spotifyd = {
|
||||
settings.global = {
|
||||
username_cmd = "sed '1q;d' /run/agenix/spotifyd";
|
||||
password_cmd = "sed '2q;d' /run/agenix/spotifyd";
|
||||
bitrate = 320;
|
||||
backend = "pulseaudio";
|
||||
device_name = config.networking.hostName;
|
||||
device_type = "computer";
|
||||
# on_song_change_hook = "command_to_run_on_playback_events"
|
||||
autoplay = true;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.user.services.spotifyd-daemon = {
|
||||
enable = true;
|
||||
wantedBy = [ "graphical-session.target" ];
|
||||
partOf = [ "graphical-session.target" ];
|
||||
description = "spotifyd, a Spotify playing daemon";
|
||||
environment.SHELL = "/bin/sh";
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.spotifyd}/bin/spotifyd --no-daemon --config-path ${spotifydConf}";
|
||||
Restart = "always";
|
||||
CacheDirectory = "spotifyd";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
{ lib, config, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.de;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [
|
||||
(self: super: {
|
||||
tor-browser-bundle-bin = super.tor-browser-bundle-bin.overrideAttrs (old: rec {
|
||||
version = "10.0.10";
|
||||
lang = "en-US";
|
||||
src = pkgs.fetchurl {
|
||||
url = "https://dist.torproject.org/torbrowser/${version}/tor-browser-linux64-${version}_${lang}.tar.xz";
|
||||
sha256 = "vYWZ+NsGN8YH5O61+zrUjlFv3rieaBqjBQ+a18sQcZg=";
|
||||
};
|
||||
});
|
||||
})
|
||||
];
|
||||
|
||||
users.users.googlebot.packages = with pkgs; [
|
||||
tor-browser-bundle-bin
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,15 +1,11 @@
|
||||
{ lib, config, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.de.touchpad;
|
||||
cfg = config.de;
|
||||
in
|
||||
{
|
||||
options.de.touchpad = {
|
||||
enable = lib.mkEnableOption "enable touchpad";
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.xserver.libinput.enable = true;
|
||||
services.xserver.libinput.touchpad.naturalScrolling = true;
|
||||
services.libinput.enable = true;
|
||||
services.libinput.touchpad.naturalScrolling = true;
|
||||
};
|
||||
}
|
||||
|
||||
25
common/pc/udev.nix
Normal file
25
common/pc/udev.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.de;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.udev.extraRules = ''
|
||||
# depthai
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="03e7", MODE="0666"
|
||||
|
||||
# Moonlander
|
||||
# Rules for Oryx web flashing and live training
|
||||
KERNEL=="hidraw*", ATTRS{idVendor}=="16c0", MODE="0664", GROUP="plugdev"
|
||||
KERNEL=="hidraw*", ATTRS{idVendor}=="3297", MODE="0664", GROUP="plugdev"
|
||||
# Wally Flashing rules for the Moonlander and Planck EZ
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE:="0666", SYMLINK+="stm32_dfu"
|
||||
'';
|
||||
services.udev.packages = [ pkgs.platformio ];
|
||||
|
||||
users.groups.plugdev = {
|
||||
members = [ "googlebot" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
diff --git a/meson.build b/meson.build
|
||||
index dace367..8c0e290 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -8,7 +8,7 @@ project(
|
||||
'warning_level=0',
|
||||
],
|
||||
license: 'MIT',
|
||||
- meson_version: '>= 0.58.0',
|
||||
+ meson_version: '>= 0.57.0',
|
||||
)
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
@@ -47,8 +47,3 @@ shared_library(
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
)
|
||||
|
||||
-meson.add_devenv(environment({
|
||||
- 'NVD_LOG': '1',
|
||||
- 'LIBVA_DRIVER_NAME': 'nvidia',
|
||||
- 'LIBVA_DRIVERS_PATH': meson.project_build_root(),
|
||||
-}))
|
||||
23
common/pc/virtualisation.nix
Normal file
23
common/pc/virtualisation.nix
Normal file
@@ -0,0 +1,23 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.de;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable {
|
||||
# AppVMs
|
||||
virtualisation.appvm.enable = true;
|
||||
virtualisation.appvm.user = "googlebot";
|
||||
|
||||
# Use podman instead of docker
|
||||
virtualisation.podman.enable = true;
|
||||
virtualisation.podman.dockerCompat = true;
|
||||
|
||||
# virt-manager
|
||||
virtualisation.libvirtd.enable = true;
|
||||
programs.dconf.enable = true;
|
||||
virtualisation.spiceUSBRedirection.enable = true;
|
||||
environment.systemPackages = with pkgs; [ virt-manager ];
|
||||
users.users.googlebot.extraGroups = [ "libvirtd" "adbusers" ];
|
||||
};
|
||||
}
|
||||
@@ -4,8 +4,35 @@ let
|
||||
cfg = config.de;
|
||||
|
||||
extensions = with pkgs.vscode-extensions; [
|
||||
# bbenoist.Nix # nix syntax support
|
||||
# arrterian.nix-env-selector # nix dev envs
|
||||
bbenoist.nix # nix syntax support
|
||||
arrterian.nix-env-selector # nix dev envs
|
||||
dart-code.dart-code
|
||||
dart-code.flutter
|
||||
golang.go
|
||||
jnoortheen.nix-ide
|
||||
ms-vscode.cpptools
|
||||
rust-lang.rust-analyzer
|
||||
vadimcn.vscode-lldb
|
||||
tauri-apps.tauri-vscode
|
||||
] ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [
|
||||
{
|
||||
name = "platformio-ide";
|
||||
publisher = "platformio";
|
||||
version = "3.1.1";
|
||||
sha256 = "g9yTG3DjVUS2w9eHGAai5LoIfEGus+FPhqDnCi4e90Q=";
|
||||
}
|
||||
{
|
||||
name = "wgsl-analyzer";
|
||||
publisher = "wgsl-analyzer";
|
||||
version = "0.8.1";
|
||||
sha256 = "ckclcxdUxhjWlPnDFVleLCWgWxUEENe0V328cjaZv+Y=";
|
||||
}
|
||||
{
|
||||
name = "volar";
|
||||
publisher = "Vue";
|
||||
version = "2.2.4";
|
||||
sha256 = "FHS/LNjSUVfCb4SVF9naR4W0JqycWzSWiK54jfbRagA=";
|
||||
}
|
||||
];
|
||||
|
||||
vscodium-with-extensions = pkgs.vscode-with-extensions.override {
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
{ lib, config, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.de;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.xserver = {
|
||||
enable = true;
|
||||
desktopManager = {
|
||||
xterm.enable = false;
|
||||
xfce.enable = true;
|
||||
};
|
||||
displayManager.sddm.enable = true;
|
||||
};
|
||||
|
||||
# xfce apps
|
||||
# TODO for some reason whiskermenu needs to be global for it to work
|
||||
environment.systemPackages = with pkgs; [
|
||||
xfce.xfce4-whiskermenu-plugin
|
||||
];
|
||||
};
|
||||
}
|
||||
16
common/server/actualbudget.nix
Normal file
16
common/server/actualbudget.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.actual;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.actual.settings = {
|
||||
port = 25448;
|
||||
};
|
||||
|
||||
backup.group."actual-budget".paths = [
|
||||
"/var/lib/actual"
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -10,14 +10,15 @@
|
||||
./matrix.nix
|
||||
./zerobin.nix
|
||||
./gitea.nix
|
||||
./gitea-runner.nix
|
||||
./privatebin/privatebin.nix
|
||||
./radio.nix
|
||||
./samba.nix
|
||||
./owncast.nix
|
||||
./mailserver.nix
|
||||
./nextcloud.nix
|
||||
./iodine.nix
|
||||
./searx.nix
|
||||
./gitea-actions-runner.nix
|
||||
./librechat.nix
|
||||
./actualbudget.nix
|
||||
./unifi.nix
|
||||
];
|
||||
}
|
||||
|
||||
133
common/server/gitea-actions-runner.nix
Normal file
133
common/server/gitea-actions-runner.nix
Normal file
@@ -0,0 +1,133 @@
|
||||
{ config, pkgs, lib, allModules, ... }:
|
||||
|
||||
# Gitea Actions Runner. Starts 'host' runner that runs directly on the host inside of a nixos container
|
||||
# This is useful for providing a real Nix/OS builder to gitea.
|
||||
# Warning, NixOS containers are not secure. For example, the container shares the /nix/store
|
||||
# Therefore, this should not be used to run untrusted code.
|
||||
# To enable, assign a machine the 'gitea-actions-runner' system role
|
||||
|
||||
# TODO: skipping running inside of nixos container for now because of issues getting docker/podman running
|
||||
|
||||
let
|
||||
thisMachineIsARunner = config.thisMachine.hasRole."gitea-actions-runner";
|
||||
containerName = "gitea-runner";
|
||||
in
|
||||
{
|
||||
config = lib.mkIf (thisMachineIsARunner && !config.boot.isContainer) {
|
||||
# containers.${containerName} = {
|
||||
# ephemeral = true;
|
||||
# autoStart = true;
|
||||
|
||||
# # for podman
|
||||
# enableTun = true;
|
||||
|
||||
# # privateNetwork = true;
|
||||
# # hostAddress = "172.16.101.1";
|
||||
# # localAddress = "172.16.101.2";
|
||||
|
||||
# bindMounts =
|
||||
# {
|
||||
# "/run/agenix/gitea-actions-runner-token" = {
|
||||
# hostPath = "/run/agenix/gitea-actions-runner-token";
|
||||
# isReadOnly = true;
|
||||
# };
|
||||
# "/var/lib/gitea-runner" = {
|
||||
# hostPath = "/var/lib/gitea-runner";
|
||||
# isReadOnly = false;
|
||||
# };
|
||||
# };
|
||||
|
||||
# extraFlags = [
|
||||
# # Allow podman
|
||||
# ''--system-call-filter=thisystemcalldoesnotexistforsure''
|
||||
# ];
|
||||
|
||||
# additionalCapabilities = [
|
||||
# "CAP_SYS_ADMIN"
|
||||
# ];
|
||||
|
||||
# config = {
|
||||
# imports = allModules;
|
||||
|
||||
# # speeds up evaluation
|
||||
# nixpkgs.pkgs = pkgs;
|
||||
|
||||
# networking.hostName = lib.mkForce containerName;
|
||||
|
||||
# # don't use remote builders
|
||||
# nix.distributedBuilds = lib.mkForce false;
|
||||
|
||||
# environment.systemPackages = with pkgs; [
|
||||
# git
|
||||
# # Gitea Actions rely heavily on node. Include it because it would be installed anyway.
|
||||
# nodejs
|
||||
# ];
|
||||
|
||||
# services.gitea-actions-runner.instances.inst = {
|
||||
# enable = true;
|
||||
# name = config.networking.hostName;
|
||||
# url = "https://git.neet.dev/";
|
||||
# tokenFile = "/run/agenix/gitea-actions-runner-token";
|
||||
# labels = [
|
||||
# "ubuntu-latest:docker://node:18-bullseye"
|
||||
# "nixos:host"
|
||||
# ];
|
||||
# };
|
||||
|
||||
# # To allow building on the host, must override the the service's config so it doesn't use a dynamic user
|
||||
# systemd.services.gitea-runner-inst.serviceConfig.DynamicUser = lib.mkForce false;
|
||||
# users.users.gitea-runner = {
|
||||
# home = "/var/lib/gitea-runner";
|
||||
# group = "gitea-runner";
|
||||
# isSystemUser = true;
|
||||
# createHome = true;
|
||||
# };
|
||||
# users.groups.gitea-runner = { };
|
||||
|
||||
# virtualisation.podman.enable = true;
|
||||
# boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||
# };
|
||||
# };
|
||||
|
||||
# networking.nat.enable = true;
|
||||
# networking.nat.internalInterfaces = [
|
||||
# "ve-${containerName}"
|
||||
# ];
|
||||
# networking.ip_forward = true;
|
||||
|
||||
# don't use remote builders
|
||||
nix.distributedBuilds = lib.mkForce false;
|
||||
|
||||
services.gitea-actions-runner.instances.inst = {
|
||||
enable = true;
|
||||
name = config.networking.hostName;
|
||||
url = "https://git.neet.dev/";
|
||||
tokenFile = "/run/agenix/gitea-actions-runner-token";
|
||||
labels = [
|
||||
"ubuntu-latest:docker://node:18-bullseye"
|
||||
"nixos:host"
|
||||
];
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
git
|
||||
# Gitea Actions rely heavily on node. Include it because it would be installed anyway.
|
||||
nodejs
|
||||
];
|
||||
|
||||
# To allow building on the host, must override the the service's config so it doesn't use a dynamic user
|
||||
systemd.services.gitea-runner-inst.serviceConfig.DynamicUser = lib.mkForce false;
|
||||
users.users.gitea-runner = {
|
||||
home = "/var/lib/gitea-runner";
|
||||
group = "gitea-runner";
|
||||
isSystemUser = true;
|
||||
createHome = true;
|
||||
};
|
||||
users.groups.gitea-runner = { };
|
||||
|
||||
virtualisation.podman.enable = true;
|
||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||
|
||||
age.secrets.gitea-actions-runner-token.file = ../../secrets/gitea-actions-runner-token.age;
|
||||
};
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.gitea-runner;
|
||||
in
|
||||
{
|
||||
options.services.gitea-runner = {
|
||||
enable = lib.mkEnableOption "Enables gitea runner";
|
||||
dataDir = lib.mkOption {
|
||||
default = "/var/lib/gitea-runner";
|
||||
type = lib.types.str;
|
||||
description = lib.mdDoc "gitea runner data directory.";
|
||||
};
|
||||
instanceUrl = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
};
|
||||
registrationTokenFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
virtualisation.docker.enable = true;
|
||||
|
||||
users.users.gitea-runner = {
|
||||
description = "Gitea Runner Service";
|
||||
home = cfg.dataDir;
|
||||
useDefaultShell = true;
|
||||
group = "gitea-runner";
|
||||
isSystemUser = true;
|
||||
createHome = true;
|
||||
extraGroups = [
|
||||
"docker" # allow creating docker containers
|
||||
];
|
||||
};
|
||||
users.groups.gitea-runner = { };
|
||||
|
||||
# registration token
|
||||
services.gitea-runner.registrationTokenFile = "/run/agenix/gitea-runner-registration-token";
|
||||
age.secrets.gitea-runner-registration-token = {
|
||||
file = ../../secrets/gitea-runner-registration-token.age;
|
||||
owner = "gitea-runner";
|
||||
};
|
||||
|
||||
systemd.services.gitea-runner = {
|
||||
description = "Gitea Runner";
|
||||
|
||||
serviceConfig = {
|
||||
WorkingDirectory = cfg.dataDir;
|
||||
User = "gitea-runner";
|
||||
Group = "gitea-runner";
|
||||
};
|
||||
|
||||
requires = [ "network-online.target" ];
|
||||
after = [ "network.target" "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
path = with pkgs; [ gitea-actions-runner ];
|
||||
|
||||
# based on https://gitea.com/gitea/act_runner/src/branch/main/run.sh
|
||||
script = ''
|
||||
. ${cfg.registrationTokenFile}
|
||||
|
||||
if [[ ! -s .runner ]]; then
|
||||
try=$((try + 1))
|
||||
success=0
|
||||
|
||||
LOGFILE="$(mktemp)"
|
||||
|
||||
# The point of this loop is to make it simple, when running both act_runner and gitea in docker,
|
||||
# for the act_runner to wait a moment for gitea to become available before erroring out. Within
|
||||
# the context of a single docker-compose, something similar could be done via healthchecks, but
|
||||
# this is more flexible.
|
||||
while [[ $success -eq 0 ]] && [[ $try -lt ''${10:-10} ]]; do
|
||||
act_runner register \
|
||||
--instance "${cfg.instanceUrl}" \
|
||||
--token "$GITEA_RUNNER_REGISTRATION_TOKEN" \
|
||||
--name "${config.networking.hostName}" \
|
||||
--no-interactive > $LOGFILE 2>&1
|
||||
|
||||
cat $LOGFILE
|
||||
|
||||
cat $LOGFILE | grep 'Runner registered successfully' > /dev/null
|
||||
if [[ $? -eq 0 ]]; then
|
||||
echo "SUCCESS"
|
||||
success=1
|
||||
else
|
||||
echo "Waiting to retry ..."
|
||||
sleep 5
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
exec act_runner daemon
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -12,23 +12,28 @@ in
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.gitea = {
|
||||
domain = cfg.hostname;
|
||||
rootUrl = "https://${cfg.hostname}/";
|
||||
appName = cfg.hostname;
|
||||
# lfs.enable = true;
|
||||
lfs.enable = true;
|
||||
# dump.enable = true;
|
||||
settings = {
|
||||
server = {
|
||||
ROOT_URL = "https://${cfg.hostname}/";
|
||||
DOMAIN = cfg.hostname;
|
||||
};
|
||||
other = {
|
||||
SHOW_FOOTER_VERSION = false;
|
||||
};
|
||||
ui = {
|
||||
DEFAULT_THEME = "arc-green";
|
||||
DEFAULT_THEME = "gitea-dark";
|
||||
};
|
||||
service = {
|
||||
DISABLE_REGISTRATION = true;
|
||||
};
|
||||
session = {
|
||||
COOKIE_SECURE = true;
|
||||
PROVIDER = "db";
|
||||
SESSION_LIFE_TIME = 259200; # 3 days
|
||||
GC_INTERVAL_TIME = 259200; # 3 days
|
||||
};
|
||||
mailer = {
|
||||
ENABLED = true;
|
||||
@@ -42,6 +47,9 @@ in
|
||||
actions = {
|
||||
ENABLED = true;
|
||||
};
|
||||
indexer = {
|
||||
REPO_INDEXER_ENABLED = true;
|
||||
};
|
||||
};
|
||||
mailerPasswordFile = "/run/agenix/robots-email-pw";
|
||||
};
|
||||
@@ -60,7 +68,7 @@ in
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:${toString cfg.httpPort}";
|
||||
proxyPass = "http://localhost:${toString cfg.settings.server.HTTP_PORT}";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
69
common/server/librechat.nix
Normal file
69
common/server/librechat.nix
Normal file
@@ -0,0 +1,69 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.librechat;
|
||||
in
|
||||
{
|
||||
options.services.librechat = {
|
||||
enable = mkEnableOption "librechat";
|
||||
port = mkOption {
|
||||
type = types.int;
|
||||
default = 3080;
|
||||
};
|
||||
host = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "example.com";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
virtualisation.oci-containers.containers = {
|
||||
librechat = {
|
||||
image = "ghcr.io/danny-avila/librechat:v0.7.7";
|
||||
environment = {
|
||||
HOST = "0.0.0.0";
|
||||
MONGO_URI = "mongodb://host.containers.internal:27017/LibreChat";
|
||||
ENDPOINTS = "openAI,google,bingAI,gptPlugins";
|
||||
OPENAI_MODELS = lib.concatStringsSep "," [
|
||||
"gpt-4o-mini"
|
||||
"o3-mini"
|
||||
"gpt-4o"
|
||||
"o1"
|
||||
];
|
||||
REFRESH_TOKEN_EXPIRY = toString (1000 * 60 * 60 * 24 * 30); # 30 days
|
||||
};
|
||||
environmentFiles = [
|
||||
"/run/agenix/librechat-env-file"
|
||||
];
|
||||
ports = [
|
||||
"${toString cfg.port}:3080"
|
||||
];
|
||||
};
|
||||
};
|
||||
age.secrets.librechat-env-file.file = ../../secrets/librechat-env-file.age;
|
||||
|
||||
services.mongodb.enable = true;
|
||||
services.mongodb.bind_ip = "0.0.0.0";
|
||||
|
||||
# easier podman maintenance
|
||||
virtualisation.oci-containers.backend = "podman";
|
||||
virtualisation.podman.dockerSocket.enable = true;
|
||||
virtualisation.podman.dockerCompat = true;
|
||||
|
||||
# For mongodb access
|
||||
networking.firewall.trustedInterfaces = [
|
||||
"podman0" # for librechat
|
||||
];
|
||||
|
||||
services.nginx.virtualHosts.${cfg.host} = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:${toString cfg.port}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -28,7 +28,6 @@ in
|
||||
indexDir = "/var/lib/mailindex";
|
||||
enableManageSieve = true;
|
||||
fullTextSearch.enable = true;
|
||||
fullTextSearch.indexAttachments = true;
|
||||
fullTextSearch.memoryLimit = 500;
|
||||
inherit domains;
|
||||
loginAccounts = {
|
||||
@@ -37,6 +36,10 @@ in
|
||||
# catchall for all domains
|
||||
aliases = map (domain: "@${domain}") domains;
|
||||
};
|
||||
"cris@runyan.org" = {
|
||||
hashedPasswordFile = "/run/agenix/cris-hashed-email-pw";
|
||||
aliases = [ "chris@runyan.org" ];
|
||||
};
|
||||
"robot@runyan.org" = {
|
||||
aliases = [
|
||||
"no-reply@neet.dev"
|
||||
@@ -51,10 +54,19 @@ in
|
||||
"joslyn@runyan.org"
|
||||
"damon@runyan.org"
|
||||
"jonas@runyan.org"
|
||||
"simon@neet.dev"
|
||||
"ellen@runyan.org"
|
||||
];
|
||||
certificateScheme = 3; # use let's encrypt for certs
|
||||
forwards = {
|
||||
"amazon@runyan.org" = [
|
||||
"jeremy@runyan.org"
|
||||
"cris@runyan.org"
|
||||
];
|
||||
};
|
||||
certificateScheme = "acme-nginx"; # use let's encrypt for certs
|
||||
};
|
||||
age.secrets.hashed-email-pw.file = ../../secrets/hashed-email-pw.age;
|
||||
age.secrets.cris-hashed-email-pw.file = ../../secrets/cris-hashed-email-pw.age;
|
||||
age.secrets.hashed-robots-email-pw.file = ../../secrets/hashed-robots-email-pw.age;
|
||||
|
||||
# sendmail to use xxx@domain instead of xxx@mail.domain
|
||||
|
||||
@@ -8,13 +8,23 @@ in
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.nextcloud = {
|
||||
https = true;
|
||||
package = pkgs.nextcloud25;
|
||||
package = pkgs.nextcloud31;
|
||||
hostName = "neet.cloud";
|
||||
config.dbtype = "sqlite";
|
||||
config.adminuser = "jeremy";
|
||||
config.adminpassFile = "/run/agenix/nextcloud-pw";
|
||||
autoUpdateApps.enable = true;
|
||||
enableBrokenCiphersForSSE = false;
|
||||
extraApps = with config.services.nextcloud.package.packages.apps; {
|
||||
# Want
|
||||
inherit end_to_end_encryption mail spreed;
|
||||
|
||||
# Might use
|
||||
inherit bookmarks calendar cookbook deck memories onlyoffice qownnotesapi;
|
||||
|
||||
# Try out
|
||||
# inherit maps music news notes phonetrack polls forms;
|
||||
};
|
||||
extraAppsEnable = true;
|
||||
};
|
||||
age.secrets.nextcloud-pw = {
|
||||
file = ../../secrets/nextcloud-pw.age;
|
||||
|
||||
@@ -4,6 +4,10 @@ let
|
||||
cfg = config.services.nginx;
|
||||
in
|
||||
{
|
||||
options.services.nginx = {
|
||||
openFirewall = lib.mkEnableOption "Open firewall ports 80 and 443";
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.nginx = {
|
||||
recommendedGzipSettings = true;
|
||||
@@ -12,6 +16,8 @@ in
|
||||
recommendedTlsSettings = true;
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
services.nginx.openFirewall = lib.mkDefault true;
|
||||
|
||||
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 80 443 ];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
;<?php http_response_code(403); /*
|
||||
[main]
|
||||
name = "Kode Paste"
|
||||
discussion = false
|
||||
opendiscussion = false
|
||||
password = true
|
||||
fileupload = false
|
||||
burnafterreadingselected = false
|
||||
defaultformatter = "plaintext"
|
||||
sizelimit = 10485760
|
||||
template = "bootstrap"
|
||||
languageselection = false
|
||||
|
||||
[expire]
|
||||
default = "1week"
|
||||
|
||||
[expire_options]
|
||||
5min = 300
|
||||
10min = 600
|
||||
1hour = 3600
|
||||
1day = 86400
|
||||
1week = 604800
|
||||
|
||||
[formatter_options]
|
||||
plaintext = "Plain Text"
|
||||
syntaxhighlighting = "Source Code"
|
||||
markdown = "Markdown"
|
||||
|
||||
[traffic]
|
||||
limit = 10
|
||||
dir = "/var/lib/privatebin"
|
||||
|
||||
[purge]
|
||||
limit = 300
|
||||
batchsize = 10
|
||||
dir = "/var/lib/privatebin"
|
||||
|
||||
[model]
|
||||
class = Filesystem
|
||||
|
||||
[model_options]
|
||||
dir = "/var/lib/privatebin"
|
||||
@@ -1,74 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.privatebin;
|
||||
privateBinSrc = pkgs.stdenv.mkDerivation {
|
||||
name = "privatebin";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "privatebin";
|
||||
repo = "privatebin";
|
||||
rev = "d65bf02d7819a530c3c2a88f6f9947651fe5258d";
|
||||
sha256 = "7ttAvEDL1ab0cUZcqZzXFkXwB2rF2t4eNpPxt48ap94=";
|
||||
};
|
||||
installPhase = ''
|
||||
cp -ar $src $out
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
options.services.privatebin = {
|
||||
enable = lib.mkEnableOption "enable privatebin";
|
||||
host = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "example.com";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
users.users.privatebin = {
|
||||
description = "privatebin service user";
|
||||
group = "privatebin";
|
||||
isSystemUser = true;
|
||||
};
|
||||
users.groups.privatebin = { };
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts.${cfg.host} = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/" = {
|
||||
root = privateBinSrc;
|
||||
index = "index.php";
|
||||
};
|
||||
locations."~ \.php$" = {
|
||||
root = privateBinSrc;
|
||||
extraConfig = ''
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools.privatebin.socket};
|
||||
fastcgi_index index.php;
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d '/var/lib/privatebin' 0750 privatebin privatebin - -"
|
||||
];
|
||||
|
||||
services.phpfpm.pools.privatebin = {
|
||||
user = "privatebin";
|
||||
group = "privatebin";
|
||||
phpEnv = {
|
||||
CONFIG_PATH = "${./conf.php}";
|
||||
};
|
||||
settings = {
|
||||
pm = "dynamic";
|
||||
"listen.owner" = config.services.nginx.user;
|
||||
"pm.max_children" = 5;
|
||||
"pm.start_servers" = 2;
|
||||
"pm.min_spare_servers" = 1;
|
||||
"pm.max_spare_servers" = 3;
|
||||
"pm.max_requests" = 500;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.radio;
|
||||
radioPackage = config.inputs.radio.packages.${config.currentSystem}.radio;
|
||||
in
|
||||
{
|
||||
options.services.radio = {
|
||||
enable = lib.mkEnableOption "enable radio";
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "radio";
|
||||
description = ''
|
||||
The user radio should run as
|
||||
'';
|
||||
};
|
||||
group = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "radio";
|
||||
description = ''
|
||||
The group radio should run as
|
||||
'';
|
||||
};
|
||||
dataDir = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "/var/lib/radio";
|
||||
description = ''
|
||||
Path to the radio data directory
|
||||
'';
|
||||
};
|
||||
host = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
Domain radio is hosted on
|
||||
'';
|
||||
};
|
||||
nginx = lib.mkEnableOption "enable nginx";
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.icecast = {
|
||||
enable = true;
|
||||
hostname = cfg.host;
|
||||
mount = "stream.mp3";
|
||||
fallback = "fallback.mp3";
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts.${cfg.host} = lib.mkIf cfg.nginx {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/".root = config.inputs.radio-web;
|
||||
};
|
||||
|
||||
users.users.${cfg.user} = {
|
||||
isSystemUser = true;
|
||||
group = cfg.group;
|
||||
home = cfg.dataDir;
|
||||
createHome = true;
|
||||
};
|
||||
users.groups.${cfg.group} = { };
|
||||
systemd.services.radio = {
|
||||
enable = true;
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig.ExecStart = "${radioPackage}/bin/radio ${config.services.icecast.listen.address}:${toString config.services.icecast.listen.port} ${config.services.icecast.mount} 5500";
|
||||
serviceConfig.User = cfg.user;
|
||||
serviceConfig.Group = cfg.group;
|
||||
serviceConfig.WorkingDirectory = cfg.dataDir;
|
||||
preStart = ''
|
||||
mkdir -p ${cfg.dataDir}
|
||||
chown ${cfg.user} ${cfg.dataDir}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -5,30 +5,28 @@
|
||||
services.samba = {
|
||||
openFirewall = true;
|
||||
package = pkgs.sambaFull; # printer sharing
|
||||
securityType = "user";
|
||||
|
||||
# should this be on?
|
||||
nsswins = true;
|
||||
|
||||
extraConfig = ''
|
||||
workgroup = HOME
|
||||
server string = smbnix
|
||||
netbios name = smbnix
|
||||
security = user
|
||||
use sendfile = yes
|
||||
min protocol = smb2
|
||||
guest account = nobody
|
||||
map to guest = bad user
|
||||
settings = {
|
||||
global = {
|
||||
security = "user";
|
||||
workgroup = "HOME";
|
||||
"server string" = "smbnix";
|
||||
"netbios name" = "smbnix";
|
||||
"use sendfile" = "yes";
|
||||
"min protocol" = "smb2";
|
||||
"guest account" = "nobody";
|
||||
"map to guest" = "bad user";
|
||||
|
||||
# printing
|
||||
load printers = yes
|
||||
printing = cups
|
||||
printcap name = cups
|
||||
# printing
|
||||
"load printers" = "yes";
|
||||
printing = "cups";
|
||||
"printcap name" = "cups";
|
||||
|
||||
hide files = /.nobackup/.DS_Store/._.DS_Store/
|
||||
'';
|
||||
|
||||
shares = {
|
||||
"hide files" = "/.nobackup/.DS_Store/._.DS_Store/";
|
||||
};
|
||||
public = {
|
||||
path = "/data/samba/Public";
|
||||
browseable = "yes";
|
||||
@@ -77,9 +75,9 @@
|
||||
|
||||
# backups
|
||||
backup.group."samba".paths = [
|
||||
config.services.samba.shares.googlebot.path
|
||||
config.services.samba.shares.cris.path
|
||||
config.services.samba.shares.public.path
|
||||
config.services.samba.settings.googlebot.path
|
||||
config.services.samba.settings.cris.path
|
||||
config.services.samba.settings.public.path
|
||||
];
|
||||
|
||||
# Windows discovery of samba server
|
||||
@@ -97,7 +95,7 @@
|
||||
# Printer discovery
|
||||
# (is this needed?)
|
||||
services.avahi.enable = true;
|
||||
services.avahi.nssmdns = true;
|
||||
services.avahi.nssmdns4 = true;
|
||||
|
||||
# printer sharing
|
||||
systemd.tmpfiles.rules = [
|
||||
|
||||
26
common/server/unifi.nix
Normal file
26
common/server/unifi.nix
Normal file
@@ -0,0 +1,26 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.services.unifi;
|
||||
in
|
||||
{
|
||||
options.services.unifi = {
|
||||
# Open select Unifi ports instead of using openFirewall to avoid opening access to unifi's control panel
|
||||
openMinimalFirewall = lib.mkEnableOption "Open bare minimum firewall ports";
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.unifi.unifiPackage = pkgs.unifi;
|
||||
services.unifi.mongodbPackage = pkgs.mongodb-7_0;
|
||||
|
||||
networking.firewall = lib.mkIf cfg.openMinimalFirewall {
|
||||
allowedUDPPorts = [
|
||||
3478 # STUN
|
||||
10001 # used for device discovery.
|
||||
];
|
||||
allowedTCPPorts = [
|
||||
8080 # Used for device and application communication.
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -21,8 +21,6 @@
|
||||
shellInit = ''
|
||||
# disable annoying fish shell greeting
|
||||
set fish_greeting
|
||||
|
||||
alias sudo="doas"
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -34,6 +32,15 @@
|
||||
io_seq_write = "${pkgs.fio}/bin/fio --name TEST --eta-newline=5s --filename=temp.file --rw=write --size=2g --io_size=10g --blocksize=1024k --ioengine=libaio --fsync=10000 --iodepth=32 --direct=1 --numjobs=1 --runtime=60 --group_reporting; rm temp.file";
|
||||
io_rand_read = "${pkgs.fio}/bin/fio --name TEST --eta-newline=5s --filename=temp.file --rw=randread --size=2g --io_size=10g --blocksize=4k --ioengine=libaio --fsync=1 --iodepth=1 --direct=1 --numjobs=32 --runtime=60 --group_reporting; rm temp.file";
|
||||
io_rand_write = "${pkgs.fio}/bin/fio --name TEST --eta-newline=5s --filename=temp.file --rw=randrw --size=2g --io_size=10g --blocksize=4k --ioengine=libaio --fsync=1 --iodepth=1 --direct=1 --numjobs=1 --runtime=60 --group_reporting; rm temp.file";
|
||||
|
||||
llsblk = "lsblk -o +uuid,fsType";
|
||||
|
||||
sudo = "doas";
|
||||
|
||||
ls = "pls";
|
||||
ls2 = "eza";
|
||||
|
||||
explorer = "broot";
|
||||
};
|
||||
|
||||
nixpkgs.overlays = [
|
||||
|
||||
289
flake.lock
generated
289
flake.lock
generated
@@ -3,45 +3,28 @@
|
||||
"agenix": {
|
||||
"inputs": {
|
||||
"darwin": "darwin",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1682101079,
|
||||
"narHash": "sha256-MdAhtjrLKnk2uiqun1FWABbKpLH090oeqCSiWemtuck=",
|
||||
"owner": "ryantm",
|
||||
"repo": "agenix",
|
||||
"rev": "2994d002dcff5353ca1ac48ec584c7f6589fe447",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ryantm",
|
||||
"repo": "agenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"archivebox": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
"home-manager": [
|
||||
"home-manager"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1648612759,
|
||||
"narHash": "sha256-SJwlpD2Wz3zFoX2mIYCQfwIOYHaOdeiWGFeDXsLGM84=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "39d338b9b24159d8ef3309eecc0d32a2a9f102b5",
|
||||
"revCount": 2,
|
||||
"type": "git",
|
||||
"url": "https://git.neet.dev/zuckerberg/archivebox.git"
|
||||
"lastModified": 1750173260,
|
||||
"narHash": "sha256-9P1FziAwl5+3edkfFcr5HeGtQUtrSdk/MksX39GieoA=",
|
||||
"owner": "ryantm",
|
||||
"repo": "agenix",
|
||||
"rev": "531beac616433bac6f9e2a19feb8e99a22a66baf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.neet.dev/zuckerberg/archivebox.git"
|
||||
"owner": "ryantm",
|
||||
"repo": "agenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"blobs": {
|
||||
@@ -70,17 +53,17 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1651719222,
|
||||
"narHash": "sha256-p/GY5vOP+HUlxNL4OtEhmBNEVQsedOHXEmjfCGONVmE=",
|
||||
"lastModified": 1739947126,
|
||||
"narHash": "sha256-JoiddH5H9up8jC/VKU8M7wDlk/bstKoJ3rHj+TkW4Zo=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "1290ddd9a2ff2bf2d0f702750768312b80efcd34",
|
||||
"revCount": 19,
|
||||
"rev": "ea1ad60f1c6662103ef4a3705d8e15aa01219529",
|
||||
"revCount": 20,
|
||||
"type": "git",
|
||||
"url": "https://git.neet.dev/zuckerberg/dailybuild_modules.git"
|
||||
"url": "https://git.neet.dev/zuckerberg/dailybot.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.neet.dev/zuckerberg/dailybuild_modules.git"
|
||||
"url": "https://git.neet.dev/zuckerberg/dailybot.git"
|
||||
}
|
||||
},
|
||||
"darwin": {
|
||||
@@ -91,11 +74,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1673295039,
|
||||
"narHash": "sha256-AsdYgE8/GPwcelGgrntlijMg4t3hLFJFCRF3tL5WVjA=",
|
||||
"lastModified": 1744478979,
|
||||
"narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=",
|
||||
"owner": "lnl7",
|
||||
"repo": "nix-darwin",
|
||||
"rev": "87b9d090ad39b25b2400029c64825fc2a8868943",
|
||||
"rev": "43975d782b418ebf4969e9ccba82466728c2851b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -107,21 +90,22 @@
|
||||
},
|
||||
"deploy-rs": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-compat": [
|
||||
"flake-compat"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"utils": [
|
||||
"simple-nixos-mailserver",
|
||||
"utils"
|
||||
"flake-utils"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1682063650,
|
||||
"narHash": "sha256-VaDHh2z6xlnTHaONlNVHP7qEMcK5rZ8Js3sT6mKb2XY=",
|
||||
"lastModified": 1749105467,
|
||||
"narHash": "sha256-hXh76y/wDl15almBcqvjryB50B0BaiXJKk20f314RoE=",
|
||||
"owner": "serokell",
|
||||
"repo": "deploy-rs",
|
||||
"rev": "c2ea4e642dc50fd44b537e9860ec95867af30d39",
|
||||
"rev": "6bc76b872374845ba9d645a2f012b764fecd765f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -133,11 +117,11 @@
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1668681692,
|
||||
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
|
||||
"lastModified": 1747046372,
|
||||
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
|
||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -148,14 +132,16 @@
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681202837,
|
||||
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -164,6 +150,75 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"git-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"simple-nixos-mailserver",
|
||||
"flake-compat"
|
||||
],
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"simple-nixos-mailserver",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750779888,
|
||||
"narHash": "sha256-wibppH3g/E2lxU43ZQHC5yA/7kIKLGxVEnsnVK1BtRg=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "16ec914f6fb6f599ce988427d9d94efddf25fe6d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"simple-nixos-mailserver",
|
||||
"git-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"home-manager": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752208517,
|
||||
"narHash": "sha256-aRY1cYOdVdXdNjcL/Twpa27CknO7pVHxooPsBizDraE=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "c6a01e54af81b381695db796a43360bf6db5702f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "release-25.05",
|
||||
"repo": "home-manager",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-index-database": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -171,11 +226,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681591833,
|
||||
"narHash": "sha256-lW+xOELafAs29yw56FG4MzNOFkh8VHC/X/tRs1wsGn8=",
|
||||
"lastModified": 1752346111,
|
||||
"narHash": "sha256-SVxCIYnbED0rNYSpm3QQoOhqxYRp1GuE9FkyM5Y2afs=",
|
||||
"owner": "Mic92",
|
||||
"repo": "nix-index-database",
|
||||
"rev": "68ec961c51f48768f72d2bbdb396ce65a316677e",
|
||||
"rev": "deff7a9a0aa98a08d8c7839fe2658199ce9828f8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -184,125 +239,78 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"nixos-hardware": {
|
||||
"locked": {
|
||||
"lastModified": 1682133240,
|
||||
"narHash": "sha256-s6yRsI/7V+k/+rckp0+/2cs/UXnea3SEfMpy95QiGcc=",
|
||||
"lastModified": 1752048960,
|
||||
"narHash": "sha256-gATnkOe37eeVwKKYCsL+OnS2gU4MmLuZFzzWCtaKLI8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "8dafae7c03d6aa8c2ae0a0612fbcb47e994e3fb8",
|
||||
"repo": "nixos-hardware",
|
||||
"rev": "7ced9122cff2163c6a0212b8d1ec8c33a1660806",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "master",
|
||||
"repo": "nixpkgs",
|
||||
"repo": "nixos-hardware",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-22_05": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1654936503,
|
||||
"narHash": "sha256-soKzdhI4jTHv/rSbh89RdlcJmrPgH8oMb/PLqiqIYVQ=",
|
||||
"lastModified": 1752431364,
|
||||
"narHash": "sha256-ciGIXIMq2daX5o4Tn6pnZTd1pf5FICHbqUlHu658G9c=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "dab6df51387c3878cdea09f43589a15729cae9f4",
|
||||
"rev": "fb0f0dbfd95f0e19fdeab8e0f18bf0b5cf057b68",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-22.05",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"nixpkgs-hostapd-pr": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"narHash": "sha256-1rGQKcB1jeRPc1n021ulyOVkA6L6xmNYKmeqQ94+iRc=",
|
||||
"type": "file",
|
||||
"url": "https://github.com/NixOS/nixpkgs/pull/222536.patch"
|
||||
},
|
||||
"original": {
|
||||
"type": "file",
|
||||
"url": "https://github.com/NixOS/nixpkgs/pull/222536.patch"
|
||||
}
|
||||
},
|
||||
"radio": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1631585589,
|
||||
"narHash": "sha256-q4o/4/2pEuJyaKZwNQC5KHnzG1obClzFB7zWk9XSDfY=",
|
||||
"ref": "main",
|
||||
"rev": "5bf607fed977d41a269942a7d1e92f3e6d4f2473",
|
||||
"revCount": 38,
|
||||
"type": "git",
|
||||
"url": "https://git.neet.dev/zuckerberg/radio.git"
|
||||
},
|
||||
"original": {
|
||||
"ref": "main",
|
||||
"rev": "5bf607fed977d41a269942a7d1e92f3e6d4f2473",
|
||||
"type": "git",
|
||||
"url": "https://git.neet.dev/zuckerberg/radio.git"
|
||||
}
|
||||
},
|
||||
"radio-web": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1652121792,
|
||||
"narHash": "sha256-j1Y9MAjUVNgyFSeGzPoqibAnEysJDjZSXukVfQ7+bsQ=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "72e7a9e80b780c84ed8d4a6374bfbb242701f900",
|
||||
"revCount": 5,
|
||||
"type": "git",
|
||||
"url": "https://git.neet.dev/zuckerberg/radio-web.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.neet.dev/zuckerberg/radio-web.git"
|
||||
"owner": "NixOS",
|
||||
"ref": "release-25.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"agenix": "agenix",
|
||||
"archivebox": "archivebox",
|
||||
"dailybuild_modules": "dailybuild_modules",
|
||||
"deploy-rs": "deploy-rs",
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils",
|
||||
"home-manager": "home-manager",
|
||||
"nix-index-database": "nix-index-database",
|
||||
"nixos-hardware": "nixos-hardware",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-hostapd-pr": "nixpkgs-hostapd-pr",
|
||||
"radio": "radio",
|
||||
"radio-web": "radio-web",
|
||||
"simple-nixos-mailserver": "simple-nixos-mailserver"
|
||||
"simple-nixos-mailserver": "simple-nixos-mailserver",
|
||||
"systems": "systems"
|
||||
}
|
||||
},
|
||||
"simple-nixos-mailserver": {
|
||||
"inputs": {
|
||||
"blobs": "blobs",
|
||||
"flake-compat": [
|
||||
"flake-compat"
|
||||
],
|
||||
"git-hooks": "git-hooks",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-22_05": "nixpkgs-22_05",
|
||||
"utils": "utils"
|
||||
"nixpkgs-25_05": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1655930346,
|
||||
"narHash": "sha256-ht56HHOzEhjeIgAv5ZNFjSVX/in1YlUs0HG9c1EUXTM=",
|
||||
"lastModified": 1747965231,
|
||||
"narHash": "sha256-BW3ktviEhfCN/z3+kEyzpDKAI8qFTwO7+S0NVA0C90o=",
|
||||
"owner": "simple-nixos-mailserver",
|
||||
"repo": "nixos-mailserver",
|
||||
"rev": "f535d8123c4761b2ed8138f3d202ea710a334a1d",
|
||||
"rev": "53007af63fade28853408370c4c600a63dd97f41",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"owner": "simple-nixos-mailserver",
|
||||
"ref": "nixos-22.05",
|
||||
"ref": "nixos-25.05",
|
||||
"repo": "nixos-mailserver",
|
||||
"type": "gitlab"
|
||||
}
|
||||
@@ -321,21 +329,6 @@
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"utils": {
|
||||
"locked": {
|
||||
"lastModified": 1605370193,
|
||||
"narHash": "sha256-YyMTf3URDL/otKdKgtoMChu4vfVL3vCMkRqpGifhUn0=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "5021eac20303a61fafe17224c087f5519baed54d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
||||
119
flake.nix
119
flake.nix
@@ -1,52 +1,77 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/master";
|
||||
# nixpkgs-patch-howdy.url = "https://github.com/NixOS/nixpkgs/pull/216245.diff";
|
||||
# nixpkgs-patch-howdy.flake = false;
|
||||
# nixpkgs
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/release-25.05";
|
||||
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
# Common Utils Among flake inputs
|
||||
systems.url = "github:nix-systems/default";
|
||||
flake-utils = {
|
||||
url = "github:numtide/flake-utils";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
flake-compat = {
|
||||
url = "github:edolstra/flake-compat";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
# mail server
|
||||
simple-nixos-mailserver.url = "gitlab:simple-nixos-mailserver/nixos-mailserver/nixos-22.05";
|
||||
simple-nixos-mailserver.inputs.nixpkgs.follows = "nixpkgs";
|
||||
# NixOS hardware
|
||||
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
|
||||
|
||||
# agenix
|
||||
agenix.url = "github:ryantm/agenix";
|
||||
agenix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
# Home Manager
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager/release-25.05";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
# radio
|
||||
radio.url = "git+https://git.neet.dev/zuckerberg/radio.git?ref=main&rev=5bf607fed977d41a269942a7d1e92f3e6d4f2473";
|
||||
radio.inputs.nixpkgs.follows = "nixpkgs";
|
||||
radio.inputs.flake-utils.follows = "flake-utils";
|
||||
radio-web.url = "git+https://git.neet.dev/zuckerberg/radio-web.git";
|
||||
radio-web.flake = false;
|
||||
# Mail Server
|
||||
simple-nixos-mailserver = {
|
||||
url = "gitlab:simple-nixos-mailserver/nixos-mailserver/nixos-25.05";
|
||||
inputs = {
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
nixpkgs-25_05.follows = "nixpkgs";
|
||||
flake-compat.follows = "flake-compat";
|
||||
};
|
||||
};
|
||||
|
||||
# drastikbot
|
||||
dailybuild_modules.url = "git+https://git.neet.dev/zuckerberg/dailybuild_modules.git";
|
||||
dailybuild_modules.inputs.nixpkgs.follows = "nixpkgs";
|
||||
dailybuild_modules.inputs.flake-utils.follows = "flake-utils";
|
||||
# Agenix
|
||||
agenix = {
|
||||
url = "github:ryantm/agenix";
|
||||
inputs = {
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
systems.follows = "systems";
|
||||
home-manager.follows = "home-manager";
|
||||
};
|
||||
};
|
||||
|
||||
# archivebox
|
||||
archivebox.url = "git+https://git.neet.dev/zuckerberg/archivebox.git";
|
||||
archivebox.inputs.nixpkgs.follows = "nixpkgs";
|
||||
archivebox.inputs.flake-utils.follows = "flake-utils";
|
||||
# Dailybot
|
||||
dailybuild_modules = {
|
||||
url = "git+https://git.neet.dev/zuckerberg/dailybot.git";
|
||||
inputs = {
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
flake-utils.follows = "flake-utils";
|
||||
};
|
||||
};
|
||||
|
||||
# nixos config deployment
|
||||
deploy-rs.url = "github:serokell/deploy-rs";
|
||||
deploy-rs.inputs.nixpkgs.follows = "nixpkgs";
|
||||
deploy-rs.inputs.utils.follows = "simple-nixos-mailserver/utils";
|
||||
# NixOS deployment
|
||||
deploy-rs = {
|
||||
url = "github:serokell/deploy-rs";
|
||||
inputs = {
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
flake-compat.follows = "flake-compat";
|
||||
utils.follows = "flake-utils";
|
||||
};
|
||||
};
|
||||
|
||||
# prebuilt nix-index database
|
||||
nix-index-database.url = "github:Mic92/nix-index-database";
|
||||
nix-index-database.inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
||||
nixpkgs-hostapd-pr.url = "https://github.com/NixOS/nixpkgs/pull/222536.patch";
|
||||
nixpkgs-hostapd-pr.flake = false;
|
||||
# Prebuilt nix-index database
|
||||
nix-index-database = {
|
||||
url = "github:Mic92/nix-index-database";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, ... }@inputs:
|
||||
let
|
||||
machines = (import ./common/machine-info/moduleless.nix
|
||||
machineHosts = (import ./common/machine-info/moduleless.nix
|
||||
{
|
||||
inherit nixpkgs;
|
||||
assertionsModule = "${nixpkgs}/nixos/modules/misc/assertions.nix";
|
||||
@@ -60,15 +85,22 @@
|
||||
simple-nixos-mailserver.nixosModule
|
||||
agenix.nixosModules.default
|
||||
dailybuild_modules.nixosModule
|
||||
archivebox.nixosModule
|
||||
nix-index-database.nixosModules.nix-index
|
||||
home-manager.nixosModules.home-manager
|
||||
self.nixosModules.kernel-modules
|
||||
({ lib, ... }: {
|
||||
config = {
|
||||
nixpkgs.overlays = [ self.overlays.default ];
|
||||
|
||||
environment.systemPackages = [
|
||||
agenix.packages.${system}.agenix
|
||||
];
|
||||
|
||||
networking.hostName = hostname;
|
||||
|
||||
home-manager.useGlobalPkgs = true;
|
||||
home-manager.useUserPackages = true;
|
||||
home-manager.users.googlebot = import ./home/googlebot.nix;
|
||||
};
|
||||
|
||||
# because nixos specialArgs doesn't work for containers... need to pass in inputs a different way
|
||||
@@ -86,8 +118,8 @@
|
||||
name = "nixpkgs-patched";
|
||||
src = nixpkgs;
|
||||
patches = [
|
||||
inputs.nixpkgs-hostapd-pr
|
||||
./patches/kexec-luks.patch
|
||||
# ./patches/gamepadui.patch
|
||||
./patches/dont-break-nix-serve.patch
|
||||
];
|
||||
};
|
||||
patchedNixpkgs = nixpkgs.lib.fix (self: (import "${patchedNixpkgsSrc}/flake.nix").outputs { self = nixpkgs; });
|
||||
@@ -99,13 +131,15 @@
|
||||
|
||||
specialArgs = {
|
||||
inherit allModules;
|
||||
lib = self.lib;
|
||||
nixos-hardware = inputs.nixos-hardware;
|
||||
};
|
||||
};
|
||||
in
|
||||
nixpkgs.lib.mapAttrs
|
||||
(hostname: cfg:
|
||||
mkSystem cfg.arch nixpkgs cfg.configurationPath hostname)
|
||||
machines;
|
||||
machineHosts;
|
||||
|
||||
packages =
|
||||
let
|
||||
@@ -127,6 +161,9 @@
|
||||
"aarch64-linux"."iso" = mkIso "aarch64-linux";
|
||||
};
|
||||
|
||||
overlays.default = import ./overlays { inherit inputs; };
|
||||
nixosModules.kernel-modules = import ./overlays/kernel-modules;
|
||||
|
||||
deploy.nodes =
|
||||
let
|
||||
mkDeploy = configName: arch: hostname: {
|
||||
@@ -139,8 +176,10 @@
|
||||
nixpkgs.lib.mapAttrs
|
||||
(hostname: cfg:
|
||||
mkDeploy hostname cfg.arch (builtins.head cfg.hostNames))
|
||||
machines;
|
||||
machineHosts;
|
||||
|
||||
checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) inputs.deploy-rs.lib;
|
||||
|
||||
lib = nixpkgs.lib.extend (final: prev: import ./lib { lib = nixpkgs.lib; });
|
||||
};
|
||||
}
|
||||
|
||||
112
home/googlebot.nix
Normal file
112
home/googlebot.nix
Normal file
@@ -0,0 +1,112 @@
|
||||
{ config, lib, pkgs, osConfig, ... }:
|
||||
|
||||
let
|
||||
# Check if the current machine has the role "personal"
|
||||
thisMachineIsPersonal = osConfig.thisMachine.hasRole."personal";
|
||||
in
|
||||
{
|
||||
home.username = "googlebot";
|
||||
home.homeDirectory = "/home/googlebot";
|
||||
|
||||
home.stateVersion = "24.11";
|
||||
programs.home-manager.enable = true;
|
||||
|
||||
services.ssh-agent.enable = true;
|
||||
|
||||
# System Monitoring
|
||||
programs.btop.enable = true;
|
||||
programs.bottom.enable = true;
|
||||
|
||||
# Modern "ls" replacement
|
||||
programs.pls.enable = true;
|
||||
programs.eza.enable = true;
|
||||
|
||||
# Graphical terminal
|
||||
programs.ghostty.enable = thisMachineIsPersonal;
|
||||
|
||||
# Advanced terminal file explorer
|
||||
programs.broot.enable = true;
|
||||
|
||||
# Shell promt theming
|
||||
programs.fish.enable = true;
|
||||
programs.starship.enable = true;
|
||||
programs.starship.enableFishIntegration = true;
|
||||
programs.starship.enableInteractive = true;
|
||||
# programs.oh-my-posh.enable = true;
|
||||
# programs.oh-my-posh.enableFishIntegration = true;
|
||||
|
||||
# Advanced search
|
||||
programs.ripgrep.enable = true;
|
||||
|
||||
# tldr: Simplified, example based and community-driven man pages.
|
||||
programs.tealdeer.enable = true;
|
||||
|
||||
programs.zed-editor = {
|
||||
enable = thisMachineIsPersonal;
|
||||
extensions = [
|
||||
"nix"
|
||||
"toml"
|
||||
"html"
|
||||
"make"
|
||||
"git-firefly"
|
||||
"vue"
|
||||
"scss"
|
||||
];
|
||||
|
||||
userSettings = {
|
||||
assistant = {
|
||||
enabled = true;
|
||||
version = "2";
|
||||
default_model = {
|
||||
provider = "openai";
|
||||
model = "gpt-4-turbo";
|
||||
};
|
||||
};
|
||||
|
||||
features = {
|
||||
edit_prediction_provider = "zed";
|
||||
};
|
||||
|
||||
node = {
|
||||
path = lib.getExe pkgs.nodejs;
|
||||
npm_path = lib.getExe' pkgs.nodejs "npm";
|
||||
};
|
||||
|
||||
auto_update = false;
|
||||
|
||||
terminal = {
|
||||
blinking = "off";
|
||||
copy_on_select = false;
|
||||
};
|
||||
|
||||
lsp = {
|
||||
rust-analyzer = {
|
||||
# binary = {
|
||||
# path = lib.getExe pkgs.rust-analyzer;
|
||||
# };
|
||||
binary = {
|
||||
path = "/run/current-system/sw/bin/nix";
|
||||
arguments = [ "develop" "--command" "rust-analyzer" ];
|
||||
};
|
||||
initialization_options = {
|
||||
cargo = {
|
||||
features = "all";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# tell zed to use direnv and direnv can use a flake.nix enviroment.
|
||||
load_direnv = "shell_hook";
|
||||
|
||||
base_keymap = "VSCode";
|
||||
theme = {
|
||||
mode = "system";
|
||||
light = "One Light";
|
||||
dark = "Andrometa";
|
||||
};
|
||||
ui_font_size = 12;
|
||||
buffer_font_size = 12;
|
||||
};
|
||||
};
|
||||
}
|
||||
56
lib/default.nix
Normal file
56
lib/default.nix
Normal file
@@ -0,0 +1,56 @@
|
||||
{ lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
# Passthrough trace for debugging
|
||||
pTrace = v: traceSeq v v;
|
||||
# find the total sum of a int list
|
||||
sum = foldr (x: y: x + y) 0;
|
||||
# splits a list of length two into two params then they're passed to a func
|
||||
splitPair = f: pair: f (head pair) (last pair);
|
||||
# Finds the max value in a list
|
||||
maxList = foldr max 0;
|
||||
# Sorts a int list. Greatest value first
|
||||
sortList = sort (x: y: x > y);
|
||||
# Cuts a list in half and returns the two parts in a list
|
||||
cutInHalf = l: [ (take (length l / 2) l) (drop (length l / 2) l) ];
|
||||
# Splits a list into a list of lists with length cnt
|
||||
chunksOf = cnt: l:
|
||||
if length l > 0 then
|
||||
[ (take cnt l) ] ++ chunksOf cnt (drop cnt l)
|
||||
else [ ];
|
||||
# same as intersectLists but takes an array of lists to intersect instead of just two
|
||||
intersectManyLists = ll: foldr intersectLists (head ll) ll;
|
||||
# converts a boolean to a int (c style)
|
||||
boolToInt = b: if b then 1 else 0;
|
||||
# drops the last element of a list
|
||||
dropLast = l: take (length l - 1) l;
|
||||
# transposes a matrix
|
||||
transpose = ll:
|
||||
let
|
||||
outerSize = length ll;
|
||||
innerSize = length (elemAt ll 0);
|
||||
in
|
||||
genList (i: genList (j: elemAt (elemAt ll j) i) outerSize) innerSize;
|
||||
# attriset recursiveUpdate but for a list of attrisets
|
||||
combineAttrs = foldl recursiveUpdate { };
|
||||
# visits every single attriset element of an attriset recursively
|
||||
# and accumulates the result of every visit in a flat list
|
||||
recurisveVisitAttrs = f: set:
|
||||
let
|
||||
visitor = n: v:
|
||||
if isAttrs v then [ (f n v) ] ++ recurisveVisitAttrs f v
|
||||
else [ (f n v) ];
|
||||
in
|
||||
concatLists (map (name: visitor name set.${name}) (attrNames set));
|
||||
# merges two lists of the same size (similar to map but both lists are inputs per iteration)
|
||||
mergeLists = f: a: imap0 (i: f (elemAt a i));
|
||||
map2D = f: ll:
|
||||
let
|
||||
outerSize = length ll;
|
||||
innerSize = length (elemAt ll 0);
|
||||
getElem = x: y: elemAt (elemAt ll y) x;
|
||||
in
|
||||
genList (y: genList (x: f x y (getElem x y)) innerSize) outerSize;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
#! /usr/bin/env nix-shell
|
||||
#! nix-shell -i bash -p bash
|
||||
|
||||
nix flake update --commit-lock-file
|
||||
@@ -29,10 +29,10 @@
|
||||
text = ''
|
||||
#!${pkgs.stdenv.shell}
|
||||
set -e
|
||||
${pkgs.kexectools}/bin/kexec -l ${image}/kernel --initrd=${image}/initrd --append="init=${builtins.unsafeDiscardStringContext config.system.build.toplevel}/init ${toString config.boot.kernelParams}"
|
||||
${pkgs.kexec-tools}/bin/kexec -l ${image}/kernel --initrd=${image}/initrd --append="init=${builtins.unsafeDiscardStringContext config.system.build.toplevel}/init ${toString config.boot.kernelParams}"
|
||||
sync
|
||||
echo "executing kernel, filesystems will be improperly umounted"
|
||||
${pkgs.kexectools}/bin/kexec -e
|
||||
${pkgs.kexec-tools}/bin/kexec -e
|
||||
'';
|
||||
};
|
||||
kexec_tarball = pkgs.callPackage (modulesPath + "/../lib/make-system-tarball.nix") {
|
||||
|
||||
57
machines/ephemeral/sdimg.nix
Normal file
57
machines/ephemeral/sdimg.nix
Normal file
@@ -0,0 +1,57 @@
|
||||
{ config, modulesPath, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
pinecube-uboot = pkgs.buildUBoot {
|
||||
defconfig = "pinecube_defconfig";
|
||||
extraMeta.platforms = [ "armv7l-linux" ];
|
||||
filesToInstall = [ "u-boot-sunxi-with-spl.bin" ];
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(modulesPath + "/installer/sd-card/sd-image.nix")
|
||||
./minimal.nix
|
||||
];
|
||||
|
||||
sdImage.populateFirmwareCommands = "";
|
||||
sdImage.populateRootCommands = ''
|
||||
mkdir -p ./files/boot
|
||||
${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot
|
||||
'';
|
||||
sdImage.postBuildCommands = ''
|
||||
dd if=${pinecube-uboot}/u-boot-sunxi-with-spl.bin of=$img bs=1024 seek=8 conv=notrunc
|
||||
'';
|
||||
|
||||
###
|
||||
|
||||
networking.hostName = "pinecube";
|
||||
|
||||
boot.loader.grub.enable = false;
|
||||
boot.loader.generic-extlinux-compatible.enable = true;
|
||||
boot.consoleLogLevel = 7;
|
||||
|
||||
# cma is 64M by default which is waay too much and we can't even unpack initrd
|
||||
boot.kernelParams = [ "console=ttyS0,115200n8" "cma=32M" ];
|
||||
|
||||
boot.kernelModules = [ "spi-nor" ]; # Not sure why this doesn't autoload. Provides SPI NOR at /dev/mtd0
|
||||
boot.extraModulePackages = [ config.boot.kernelPackages.rtl8189es ];
|
||||
|
||||
zramSwap.enable = true; # 128MB is not much to work with
|
||||
|
||||
sound.enable = true;
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
ffmpeg
|
||||
(v4l_utils.override { withGUI = false; })
|
||||
usbutils
|
||||
];
|
||||
|
||||
services.getty.autologinUser = lib.mkForce "googlebot";
|
||||
users.users.googlebot = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [ "wheel" "networkmanager" "video" ];
|
||||
openssh.authorizedKeys.keys = config.machines.ssh.userKeys;
|
||||
};
|
||||
|
||||
networking.wireless.enable = true;
|
||||
}
|
||||
12
machines/howl/default.nix
Normal file
12
machines/howl/default.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
# don't use remote builders
|
||||
nix.distributedBuilds = lib.mkForce false;
|
||||
|
||||
nix.gc.automatic = lib.mkForce false;
|
||||
}
|
||||
58
machines/howl/hardware-configuration.nix
Normal file
58
machines/howl/hardware-configuration.nix
Normal file
@@ -0,0 +1,58 @@
|
||||
{ config, lib, pkgs, modulesPath, nixos-hardware, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
nixos-hardware.nixosModules.framework-13-7040-amd
|
||||
];
|
||||
|
||||
boot.kernelPackages = pkgs.linuxPackages_6_14;
|
||||
|
||||
hardware.framework.amd-7040.preventWakeOnAC = true;
|
||||
services.fwupd.enable = true;
|
||||
# fingerprint reader has initially shown to be more of a nuisance than a help
|
||||
# it makes sddm log in fail most of the time and take several minutes to finish
|
||||
services.fprintd.enable = false;
|
||||
|
||||
# boot
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "thunderbolt" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ "dm-snapshot" ];
|
||||
boot.kernelModules = [ "kvm-amd" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
# thunderbolt
|
||||
services.hardware.bolt.enable = true;
|
||||
|
||||
# firmware
|
||||
firmware.x86_64.enable = true;
|
||||
|
||||
# disks
|
||||
remoteLuksUnlock.enable = true;
|
||||
boot.initrd.luks.devices."enc-pv" = {
|
||||
device = "/dev/disk/by-uuid/2e4a6960-a6b1-40ee-9c2c-2766eb718d52";
|
||||
allowDiscards = true;
|
||||
};
|
||||
fileSystems."/" =
|
||||
{
|
||||
device = "/dev/disk/by-uuid/1f62386c-3243-49f5-b72f-df8fc8f39db8";
|
||||
fsType = "btrfs";
|
||||
};
|
||||
fileSystems."/boot" =
|
||||
{
|
||||
device = "/dev/disk/by-uuid/F4D9-C5E8";
|
||||
fsType = "vfat";
|
||||
options = [ "fmask=0022" "dmask=0022" ];
|
||||
};
|
||||
swapDevices =
|
||||
[{ device = "/dev/disk/by-uuid/5f65cb11-2649-48fe-9c78-3e325b857c53"; }];
|
||||
|
||||
# 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.wlp1s0.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
}
|
||||
26
machines/howl/properties.nix
Normal file
26
machines/howl/properties.nix
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
hostNames = [
|
||||
"howl"
|
||||
];
|
||||
|
||||
arch = "x86_64-linux";
|
||||
|
||||
systemRoles = [
|
||||
"personal"
|
||||
];
|
||||
|
||||
hostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEQi3q8jU6vRruExAL60J7GFO1gS8HsmXVJuKRT4ljrG";
|
||||
|
||||
userKeys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKPnLt84bKhUgFxjQf10+Htro9Lo1Pabqm8mGalBUniv"
|
||||
];
|
||||
|
||||
deployKeys = [
|
||||
# TODO
|
||||
];
|
||||
|
||||
remoteUnlock = {
|
||||
hostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN0N80r0Sl2WlJaUqfxZPkOtYyGumFazkIqq7eq3Gd2o";
|
||||
onionHost = "ll6yjnkh4psmfwmtkmqoutl4gq4elqzbmjxv4s6gpgoavyi3kwhjvnqd.onion";
|
||||
};
|
||||
}
|
||||
@@ -9,7 +9,4 @@
|
||||
|
||||
networking.hostName = "nat";
|
||||
networking.interfaces.ens160.useDHCP = true;
|
||||
|
||||
de.enable = true;
|
||||
de.touchpad.enable = true;
|
||||
}
|
||||
|
||||
@@ -5,10 +5,5 @@
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
services.gitea-runner = {
|
||||
enable = true;
|
||||
instanceUrl = "https://git.neet.dev";
|
||||
};
|
||||
|
||||
system.autoUpgrade.enable = true;
|
||||
networking.hostName = "phil";
|
||||
}
|
||||
|
||||
@@ -20,7 +20,10 @@
|
||||
boot.kernelModules = [ ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
luks.devices = [ "/dev/disk/by-uuid/d26c1820-4c39-4615-98c2-51442504e194" ];
|
||||
boot.initrd.luks.devices."enc-pv" = {
|
||||
device = "/dev/disk/by-uuid/d26c1820-4c39-4615-98c2-51442504e194";
|
||||
allowDiscards = true;
|
||||
};
|
||||
|
||||
fileSystems."/" =
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
systemRoles = [
|
||||
"server"
|
||||
"gitea-runner"
|
||||
"nix-builder"
|
||||
];
|
||||
|
||||
hostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBlgRPpuUkZqe8/lHugRPm/m2vcN9psYhh5tENHZt9I2";
|
||||
|
||||
@@ -5,14 +5,13 @@
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
system.autoUpgrade.enable = true;
|
||||
# I want to manually trigger kexec updates for now on ponyo
|
||||
system.autoUpgrade.allowKexec = false;
|
||||
luks.enableKexec = true;
|
||||
# system.autoUpgrade.enable = true;
|
||||
|
||||
# p2p mesh network
|
||||
services.tailscale.exitNode = true;
|
||||
|
||||
services.iperf3.enable = true;
|
||||
|
||||
# email server
|
||||
mailserver.enable = true;
|
||||
|
||||
@@ -57,29 +56,6 @@
|
||||
config.services.drastikbot.dataDir
|
||||
];
|
||||
|
||||
# music radio
|
||||
vpn-container.enable = true;
|
||||
vpn-container.config = {
|
||||
services.radio = {
|
||||
enable = true;
|
||||
host = "radio.runyan.org";
|
||||
};
|
||||
};
|
||||
pia.wireguard.badPortForwardPorts = [ ];
|
||||
services.nginx.virtualHosts."radio.runyan.org" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations = {
|
||||
"/stream.mp3" = {
|
||||
proxyPass = "http://vpn.containers:8001/stream.mp3";
|
||||
extraConfig = ''
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
'';
|
||||
};
|
||||
"/".root = config.inputs.radio-web;
|
||||
};
|
||||
};
|
||||
|
||||
# matrix home server
|
||||
services.matrix = {
|
||||
enable = true;
|
||||
@@ -90,7 +66,7 @@
|
||||
host = "chat.neet.space";
|
||||
};
|
||||
jitsi-meet = {
|
||||
enable = true;
|
||||
enable = false; # disabled until vulnerable libolm dependency is removed/fixed
|
||||
host = "meet.neet.space";
|
||||
};
|
||||
turn = {
|
||||
@@ -99,21 +75,13 @@
|
||||
};
|
||||
};
|
||||
# pin postgresql for matrix (will need to migrate eventually)
|
||||
services.postgresql.package = pkgs.postgresql_11;
|
||||
services.postgresql.package = pkgs.postgresql_15;
|
||||
|
||||
# iodine DNS-based vpn
|
||||
services.iodine.server.enable = true;
|
||||
|
||||
# proxied web services
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts."jellyfin.neet.cloud" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://s0.koi-bebop.ts.net";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
services.nginx.virtualHosts."navidrome.neet.cloud" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
@@ -139,4 +107,8 @@
|
||||
# owncast live streaming
|
||||
services.owncast.enable = true;
|
||||
services.owncast.hostname = "live.neet.dev";
|
||||
|
||||
# librechat
|
||||
services.librechat.enable = true;
|
||||
services.librechat.host = "chat.neet.dev";
|
||||
}
|
||||
|
||||
@@ -16,18 +16,16 @@
|
||||
bios = {
|
||||
enable = true;
|
||||
device = "/dev/sda";
|
||||
configurationLimit = 3; # Save room in /nix/store
|
||||
};
|
||||
|
||||
remoteLuksUnlock.enable = true;
|
||||
|
||||
luks.devices = [
|
||||
"/dev/disk/by-uuid/4cc36be4-dbff-4afe-927d-69bf4637bae2"
|
||||
"/dev/disk/by-uuid/e52b01b3-81c8-4bb2-ae7e-a3d9c793cb00"
|
||||
];
|
||||
boot.initrd.luks.devices."enc-pv".device = "/dev/disk/by-uuid/4cc36be4-dbff-4afe-927d-69bf4637bae2";
|
||||
boot.initrd.luks.devices."enc-pv2".device = "/dev/disk/by-uuid/e52b01b3-81c8-4bb2-ae7e-a3d9c793cb00"; # expanded disk
|
||||
|
||||
fileSystems."/" =
|
||||
{
|
||||
device = "/dev/mapper/enc-pv1";
|
||||
device = "/dev/mapper/enc-pv";
|
||||
fsType = "btrfs";
|
||||
};
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"nextcloud"
|
||||
"dailybot"
|
||||
"gitea"
|
||||
"librechat"
|
||||
];
|
||||
|
||||
hostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMBBlTAIp38RhErU1wNNV5MBeb+WGH0mhF/dxh5RsAXN";
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
# for luks onlock over tor
|
||||
services.tor.enable = true;
|
||||
services.tor.client.enable = true;
|
||||
|
||||
# services.howdy.enable = true;
|
||||
|
||||
hardware.openrazer.enable = true;
|
||||
hardware.openrazer.users = [ "googlebot" ];
|
||||
hardware.openrazer.devicesOffOnScreensaver = false;
|
||||
users.users.googlebot.packages = [ pkgs.polychromatic ];
|
||||
|
||||
services.udev.extraRules = ''
|
||||
# depthai
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="03e7", MODE="0666"
|
||||
|
||||
# Moonlander
|
||||
# Rules for Oryx web flashing and live training
|
||||
KERNEL=="hidraw*", ATTRS{idVendor}=="16c0", MODE="0664", GROUP="plugdev"
|
||||
KERNEL=="hidraw*", ATTRS{idVendor}=="3297", MODE="0664", GROUP="plugdev"
|
||||
# Wally Flashing rules for the Moonlander and Planck EZ
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE:="0666", SYMLINK+="stm32_dfu"
|
||||
'';
|
||||
users.groups.plugdev = {
|
||||
members = [ "googlebot" ];
|
||||
};
|
||||
|
||||
# virt-manager
|
||||
virtualisation.libvirtd.enable = true;
|
||||
programs.dconf.enable = true;
|
||||
virtualisation.spiceUSBRedirection.enable = true;
|
||||
environment.systemPackages = with pkgs; [ virt-manager ];
|
||||
users.users.googlebot.extraGroups = [ "libvirtd" ];
|
||||
|
||||
# allow building ARM derivations
|
||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||
|
||||
services.spotifyd.enable = true;
|
||||
|
||||
virtualisation.docker.enable = true;
|
||||
|
||||
virtualisation.appvm.enable = true;
|
||||
virtualisation.appvm.user = "googlebot";
|
||||
|
||||
services.mount-samba.enable = true;
|
||||
|
||||
de.enable = true;
|
||||
de.touchpad.enable = true;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
# boot
|
||||
efi.enable = true;
|
||||
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ "dm-snapshot" ];
|
||||
|
||||
# kernel
|
||||
boot.kernelModules = [ "kvm-amd" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
# firmware
|
||||
firmware.x86_64.enable = true;
|
||||
hardware.enableAllFirmware = true;
|
||||
|
||||
# gpu
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
hardware.nvidia = {
|
||||
modesetting.enable = true; # for nvidia-vaapi-driver
|
||||
prime = {
|
||||
reverseSync.enable = true;
|
||||
offload.enableOffloadCmd = true;
|
||||
nvidiaBusId = "PCI:1:0:0";
|
||||
amdgpuBusId = "PCI:4:0:0";
|
||||
};
|
||||
};
|
||||
|
||||
# disks
|
||||
remoteLuksUnlock.enable = true;
|
||||
luks.devices = [ "/dev/disk/by-uuid/c1822e5f-4137-44e1-885f-954e926583ce" ];
|
||||
fileSystems."/" =
|
||||
{
|
||||
device = "/dev/vg/root";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=root" ];
|
||||
};
|
||||
fileSystems."/home" =
|
||||
{
|
||||
device = "/dev/vg/root";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=home" ];
|
||||
};
|
||||
fileSystems."/boot" =
|
||||
{
|
||||
device = "/dev/disk/by-uuid/2C85-2B59";
|
||||
fsType = "vfat";
|
||||
};
|
||||
swapDevices =
|
||||
[{ device = "/dev/vg/swap"; }];
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
hostNames = [
|
||||
"ray"
|
||||
];
|
||||
|
||||
arch = "x86_64-linux";
|
||||
|
||||
systemRoles = [
|
||||
"personal"
|
||||
"deploy"
|
||||
];
|
||||
|
||||
hostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDQM8hwKRgl8cZj7UVYATSLYu4LhG7I0WFJ9m2iWowiB";
|
||||
|
||||
userKeys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFeTK1iARlNIKP/DS8/ObBm9yUM/3L1Ub4XI5A2r9OzP"
|
||||
];
|
||||
|
||||
deployKeys = [
|
||||
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEaGIwLiUa6wQLlEF+keQOIYy/tCmJvV6eENzUQjSqW2AAAABHNzaDo="
|
||||
];
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
# disks
|
||||
remoteLuksUnlock.enable = true;
|
||||
luks.devices = [ "/dev/disk/by-uuid/9b090551-f78e-45ca-8570-196ed6a4af0c" ];
|
||||
boot.initrd.luks.devices."enc-pv".device = "/dev/disk/by-uuid/9b090551-f78e-45ca-8570-196ed6a4af0c";
|
||||
fileSystems."/" =
|
||||
{
|
||||
device = "/dev/disk/by-uuid/421c82b9-d67c-4811-8824-8bb57cb10fce";
|
||||
|
||||
@@ -92,7 +92,7 @@ in
|
||||
radios = {
|
||||
# 2.4GHz
|
||||
wlp4s0 = {
|
||||
hwMode = "g";
|
||||
band = "2g";
|
||||
noScan = true;
|
||||
channel = 6;
|
||||
countryCode = "US";
|
||||
@@ -124,15 +124,15 @@ in
|
||||
# authentication.saePasswordsFile = "/run/agenix/hostapd-pw-experimental-tower";
|
||||
# };
|
||||
};
|
||||
extraConfig = ''
|
||||
he_oper_centr_freq_seg0_idx=8
|
||||
vht_oper_centr_freq_seg0_idx=8
|
||||
'';
|
||||
settings = {
|
||||
he_oper_centr_freq_seg0_idx = 8;
|
||||
vht_oper_centr_freq_seg0_idx = 8;
|
||||
};
|
||||
};
|
||||
|
||||
# 5GHz
|
||||
wlan1 = {
|
||||
hwMode = "a";
|
||||
band = "5g";
|
||||
noScan = true;
|
||||
channel = 128;
|
||||
countryCode = "US";
|
||||
@@ -164,10 +164,10 @@ in
|
||||
# authentication.saePasswordsFile = "/run/agenix/hostapd-pw-experimental-tower";
|
||||
# };
|
||||
};
|
||||
extraConfig = ''
|
||||
vht_oper_centr_freq_seg0_idx=114
|
||||
he_oper_centr_freq_seg0_idx=114
|
||||
'';
|
||||
settings = {
|
||||
vht_oper_centr_freq_seg0_idx = 114;
|
||||
he_oper_centr_freq_seg0_idx = 114;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
297
machines/storage/s0/dashy.nix
Normal file
297
machines/storage/s0/dashy.nix
Normal file
@@ -0,0 +1,297 @@
|
||||
{
|
||||
appConfig = {
|
||||
theme = "vaporware";
|
||||
customColors = {
|
||||
"material-dark-original" = {
|
||||
primary = "#f36558";
|
||||
background = "#39434C";
|
||||
"background-darker" = "#eb615c";
|
||||
"material-light" = "#f36558";
|
||||
"item-text-color" = "#ff948a";
|
||||
"curve-factor" = "5px";
|
||||
};
|
||||
};
|
||||
enableErrorReporting = false;
|
||||
layout = "auto";
|
||||
iconSize = "large";
|
||||
language = "en";
|
||||
startingView = "default";
|
||||
defaultOpeningMethod = "sametab";
|
||||
statusCheck = true;
|
||||
statusCheckInterval = 20;
|
||||
faviconApi = "faviconkit";
|
||||
routingMode = "history";
|
||||
enableMultiTasking = false;
|
||||
webSearch = {
|
||||
disableWebSearch = false;
|
||||
searchEngine = "duckduckgo";
|
||||
openingMethod = "sametab";
|
||||
searchBangs = { };
|
||||
};
|
||||
enableFontAwesome = true;
|
||||
cssThemes = [ ];
|
||||
externalStyleSheet = [ ];
|
||||
hideComponents = {
|
||||
hideHeading = false;
|
||||
hideNav = false;
|
||||
hideSearch = false;
|
||||
hideSettings = false;
|
||||
hideFooter = false;
|
||||
hideSplashScreen = false;
|
||||
};
|
||||
auth = {
|
||||
enableGuestAccess = false;
|
||||
users = [ ];
|
||||
enableKeycloak = false;
|
||||
keycloak = { };
|
||||
};
|
||||
allowConfigEdit = true;
|
||||
enableServiceWorker = false;
|
||||
disableContextMenu = false;
|
||||
disableUpdateChecks = false;
|
||||
disableSmartSort = false;
|
||||
};
|
||||
|
||||
pageInfo = {
|
||||
title = "s0";
|
||||
description = "s0";
|
||||
};
|
||||
|
||||
sections = [
|
||||
(
|
||||
let
|
||||
# Define the media section items once.
|
||||
mediaItems = {
|
||||
jellyfin = {
|
||||
title = "Jellyfin";
|
||||
icon = "hl-jellyfin";
|
||||
url = "https://jellyfin.s0.neet.dev";
|
||||
target = "sametab";
|
||||
statusCheck = false;
|
||||
id = "0_1956_jellyfin";
|
||||
};
|
||||
sonarr = {
|
||||
title = "Sonarr";
|
||||
description = "Manage TV";
|
||||
icon = "hl-sonarr";
|
||||
url = "https://sonarr.s0.neet.dev";
|
||||
target = "sametab";
|
||||
statusCheck = false;
|
||||
id = "1_1956_sonarr";
|
||||
};
|
||||
radarr = {
|
||||
title = "Radarr";
|
||||
description = "Manage Movies";
|
||||
icon = "hl-radarr";
|
||||
url = "https://radarr.s0.neet.dev";
|
||||
target = "sametab";
|
||||
statusCheck = false;
|
||||
id = "2_1956_radarr";
|
||||
};
|
||||
lidarr = {
|
||||
title = "Lidarr";
|
||||
description = "Manage Music";
|
||||
icon = "hl-lidarr";
|
||||
url = "https://lidarr.s0.neet.dev";
|
||||
target = "sametab";
|
||||
statusCheck = false;
|
||||
id = "3_1956_lidarr";
|
||||
};
|
||||
prowlarr = {
|
||||
title = "Prowlarr";
|
||||
description = "Indexers";
|
||||
icon = "hl-prowlarr";
|
||||
url = "https://prowlarr.s0.neet.dev";
|
||||
target = "sametab";
|
||||
statusCheck = false;
|
||||
id = "4_1956_prowlarr";
|
||||
};
|
||||
bazarr = {
|
||||
title = "Bazarr";
|
||||
description = "Subtitles";
|
||||
icon = "hl-bazarr";
|
||||
url = "https://bazarr.s0.neet.dev";
|
||||
target = "sametab";
|
||||
statusCheck = false;
|
||||
id = "5_1956_bazarr";
|
||||
};
|
||||
navidrome = {
|
||||
title = "Navidrome";
|
||||
description = "Play Music";
|
||||
icon = "hl-navidrome";
|
||||
url = "https://music.s0.neet.dev";
|
||||
target = "sametab";
|
||||
statusCheck = false;
|
||||
id = "6_1956_navidrome";
|
||||
};
|
||||
transmission = {
|
||||
title = "Transmission";
|
||||
description = "Torrenting";
|
||||
icon = "hl-transmission";
|
||||
url = "https://transmission.s0.neet.dev";
|
||||
target = "sametab";
|
||||
statusCheck = false;
|
||||
id = "7_1956_transmission";
|
||||
};
|
||||
};
|
||||
# Build the list once.
|
||||
mediaList = [
|
||||
mediaItems.jellyfin
|
||||
mediaItems.sonarr
|
||||
mediaItems.radarr
|
||||
mediaItems.lidarr
|
||||
mediaItems.prowlarr
|
||||
mediaItems.bazarr
|
||||
mediaItems.navidrome
|
||||
mediaItems.transmission
|
||||
];
|
||||
in
|
||||
{
|
||||
name = "Media & Entertainment";
|
||||
icon = "fas fa-photo-video";
|
||||
displayData = {
|
||||
sortBy = "most-used";
|
||||
cols = 1;
|
||||
rows = 1;
|
||||
collapsed = false;
|
||||
hideForGuests = false;
|
||||
};
|
||||
items = mediaList;
|
||||
filteredItems = mediaList;
|
||||
}
|
||||
)
|
||||
(
|
||||
let
|
||||
networkItems = {
|
||||
gateway = {
|
||||
title = "Gateway";
|
||||
description = "openwrt";
|
||||
icon = "hl-openwrt";
|
||||
url = "http://openwrt.lan/";
|
||||
target = "sametab";
|
||||
statusCheck = true;
|
||||
id = "0_746_gateway";
|
||||
};
|
||||
wireless = {
|
||||
title = "Wireless";
|
||||
description = "openwrt (ish)";
|
||||
icon = "hl-openwrt";
|
||||
url = "http://PacketProvocateur.lan";
|
||||
target = "sametab";
|
||||
statusCheck = true;
|
||||
id = "1_746_wireless";
|
||||
};
|
||||
};
|
||||
networkList = [
|
||||
networkItems.gateway
|
||||
networkItems.wireless
|
||||
];
|
||||
in
|
||||
{
|
||||
name = "Network";
|
||||
icon = "fas fa-network-wired";
|
||||
items = networkList;
|
||||
filteredItems = networkList;
|
||||
displayData = {
|
||||
sortBy = "default";
|
||||
rows = 1;
|
||||
cols = 1;
|
||||
collapsed = false;
|
||||
hideForGuests = false;
|
||||
};
|
||||
}
|
||||
)
|
||||
|
||||
(
|
||||
let
|
||||
servicesItems = {
|
||||
matrix = {
|
||||
title = "Matrix";
|
||||
description = "";
|
||||
icon = "hl-matrix";
|
||||
url = "https://chat.neet.space";
|
||||
target = "sametab";
|
||||
statusCheck = true;
|
||||
id = "0_836_matrix";
|
||||
};
|
||||
mumble = {
|
||||
title = "Mumble";
|
||||
description = "voice.neet.space";
|
||||
icon = "hl-mumble";
|
||||
url = "https://voice.neet.space";
|
||||
target = "sametab";
|
||||
statusCheck = false;
|
||||
id = "2_836_mumble";
|
||||
};
|
||||
irc = {
|
||||
title = "IRC";
|
||||
description = "irc.neet.dev";
|
||||
icon = "hl-thelounge";
|
||||
url = "https://irc.neet.dev";
|
||||
target = "sametab";
|
||||
statusCheck = true;
|
||||
id = "3_836_irc";
|
||||
};
|
||||
git = {
|
||||
title = "Git";
|
||||
description = "git.neet.dev";
|
||||
icon = "hl-gitea";
|
||||
url = "https://git.neet.dev";
|
||||
target = "sametab";
|
||||
statusCheck = true;
|
||||
id = "4_836_git";
|
||||
};
|
||||
nextcloud = {
|
||||
title = "Nextcloud";
|
||||
description = "neet.cloud";
|
||||
icon = "hl-nextcloud";
|
||||
url = "https://neet.cloud";
|
||||
target = "sametab";
|
||||
statusCheck = true;
|
||||
id = "5_836_nextcloud";
|
||||
};
|
||||
roundcube = {
|
||||
title = "Roundcube";
|
||||
description = "mail.neet.dev";
|
||||
icon = "hl-roundcube";
|
||||
url = "https://mail.neet.dev";
|
||||
target = "sametab";
|
||||
statusCheck = true;
|
||||
id = "6_836_roundcube";
|
||||
};
|
||||
jitsimeet = {
|
||||
title = "Jitsi Meet";
|
||||
description = "meet.neet.space";
|
||||
icon = "hl-jitsimeet";
|
||||
url = "https://meet.neet.space";
|
||||
target = "sametab";
|
||||
statusCheck = true;
|
||||
id = "7_836_jitsimeet";
|
||||
};
|
||||
};
|
||||
servicesList = [
|
||||
servicesItems.matrix
|
||||
servicesItems.mumble
|
||||
servicesItems.irc
|
||||
servicesItems.git
|
||||
servicesItems.nextcloud
|
||||
servicesItems.roundcube
|
||||
servicesItems.jitsimeet
|
||||
];
|
||||
in
|
||||
{
|
||||
name = "Services";
|
||||
icon = "fas fa-monitor-heart-rate";
|
||||
items = servicesList;
|
||||
filteredItems = servicesList;
|
||||
displayData = {
|
||||
sortBy = "default";
|
||||
rows = 1;
|
||||
cols = 1;
|
||||
collapsed = false;
|
||||
hideForGuests = false;
|
||||
};
|
||||
}
|
||||
)
|
||||
];
|
||||
}
|
||||
@@ -3,9 +3,30 @@
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
./frigate.nix
|
||||
./home-automation.nix
|
||||
];
|
||||
|
||||
system.autoUpgrade.enable = true;
|
||||
networking.hostName = "s0";
|
||||
|
||||
# system.autoUpgrade.enable = true;
|
||||
|
||||
nix.gc.automatic = lib.mkForce false; # allow the nix store to serve as a build cache
|
||||
|
||||
# binary cache
|
||||
services.nix-serve = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
secretKeyFile = "/run/agenix/binary-cache-private-key";
|
||||
};
|
||||
age.secrets.binary-cache-private-key.file = ../../../secrets/binary-cache-private-key.age;
|
||||
users.users.cache-push = {
|
||||
isNormalUser = true;
|
||||
openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINpUZFFL9BpBVqeeU63sFPhR9ewuhEZerTCDIGW1NPSB" ];
|
||||
};
|
||||
nix.settings = {
|
||||
trusted-users = [ "cache-push" ];
|
||||
};
|
||||
|
||||
services.iperf3.enable = true;
|
||||
services.iperf3.openFirewall = true;
|
||||
@@ -20,9 +41,6 @@
|
||||
# samba
|
||||
services.samba.enable = true;
|
||||
|
||||
# disable suspend on lid close
|
||||
services.logind.lidSwitch = "ignore";
|
||||
|
||||
# navidrome
|
||||
services.navidrome = {
|
||||
enable = true;
|
||||
@@ -32,7 +50,6 @@
|
||||
MusicFolder = "/data/samba/Public/Media/Music";
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [ config.services.navidrome.settings.Port ];
|
||||
|
||||
# allow access to transmisson data
|
||||
users.users.googlebot.extraGroups = [ "transmission" ];
|
||||
@@ -58,6 +75,32 @@
|
||||
services.lidarr.enable = true;
|
||||
services.lidarr.user = "public_data";
|
||||
services.lidarr.group = "public_data";
|
||||
services.recyclarr = {
|
||||
enable = true;
|
||||
configuration = {
|
||||
radarr.radarr_main = {
|
||||
api_key = {
|
||||
_secret = "/run/credentials/recyclarr.service/radarr-api-key";
|
||||
};
|
||||
base_url = "http://localhost:7878";
|
||||
|
||||
quality_definition.type = "movie";
|
||||
};
|
||||
sonarr.sonarr_main = {
|
||||
api_key = {
|
||||
_secret = "/run/credentials/recyclarr.service/sonarr-api-key";
|
||||
};
|
||||
base_url = "http://localhost:8989";
|
||||
|
||||
quality_definition.type = "series";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.recyclarr.serviceConfig.LoadCredential = [
|
||||
"radarr-api-key:/run/agenix/radarr-api-key"
|
||||
"sonarr-api-key:/run/agenix/sonarr-api-key"
|
||||
];
|
||||
|
||||
services.transmission = {
|
||||
enable = true;
|
||||
@@ -100,13 +143,19 @@
|
||||
# "speed-limit-up-enabled" = true;
|
||||
|
||||
/* seeding limit */
|
||||
"ratio-limit" = 2;
|
||||
"ratio-limit" = 3;
|
||||
"ratio-limit-enabled" = true;
|
||||
|
||||
"download-queue-enabled" = true;
|
||||
"download-queue-size" = 20; # gotta go fast
|
||||
};
|
||||
};
|
||||
# https://github.com/NixOS/nixpkgs/issues/258793
|
||||
systemd.services.transmission.serviceConfig = {
|
||||
RootDirectoryStartOnly = lib.mkForce (lib.mkForce false);
|
||||
RootDirectory = lib.mkForce (lib.mkForce "");
|
||||
};
|
||||
|
||||
users.groups.public_data.gid = 994;
|
||||
users.users.public_data = {
|
||||
isSystemUser = true;
|
||||
@@ -122,6 +171,8 @@
|
||||
8686 # lidarr
|
||||
9091 # transmission web
|
||||
];
|
||||
age.secrets.radarr-api-key.file = ../../../secrets/radarr-api-key.age;
|
||||
age.secrets.sonarr-api-key.file = ../../../secrets/sonarr-api-key.age;
|
||||
|
||||
# jellyfin
|
||||
# jellyfin cannot run in the vpn container and use hardware encoding
|
||||
@@ -131,7 +182,7 @@
|
||||
nixpkgs.config.packageOverrides = pkgs: {
|
||||
vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; };
|
||||
};
|
||||
hardware.opengl = {
|
||||
hardware.graphics = {
|
||||
enable = true;
|
||||
extraPackages = with pkgs; [
|
||||
intel-media-driver
|
||||
@@ -143,23 +194,125 @@
|
||||
};
|
||||
|
||||
# nginx
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts."bazarr.s0".locations."/".proxyPass = "http://vpn.containers:6767";
|
||||
services.nginx.virtualHosts."radarr.s0".locations."/".proxyPass = "http://vpn.containers:7878";
|
||||
services.nginx.virtualHosts."lidarr.s0".locations."/".proxyPass = "http://vpn.containers:8686";
|
||||
services.nginx.virtualHosts."sonarr.s0".locations."/".proxyPass = "http://vpn.containers:8989";
|
||||
services.nginx.virtualHosts."prowlarr.s0".locations."/".proxyPass = "http://vpn.containers:9696";
|
||||
services.nginx.virtualHosts."music.s0".locations."/".proxyPass = "http://localhost:4533";
|
||||
services.nginx.virtualHosts."jellyfin.s0".locations."/" = {
|
||||
proxyPass = "http://localhost:8096";
|
||||
proxyWebsockets = true;
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
openFirewall = false; # All nginx services are internal
|
||||
virtualHosts =
|
||||
let
|
||||
mkHost = external: config:
|
||||
{
|
||||
${external} = {
|
||||
useACMEHost = "s0.neet.dev"; # Use wildcard cert
|
||||
forceSSL = true;
|
||||
locations."/" = config;
|
||||
};
|
||||
};
|
||||
mkVirtualHost = external: internal:
|
||||
mkHost external {
|
||||
proxyPass = internal;
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
mkStaticHost = external: static:
|
||||
mkHost external {
|
||||
root = static;
|
||||
tryFiles = "$uri /index.html ";
|
||||
};
|
||||
in
|
||||
lib.mkMerge [
|
||||
(mkVirtualHost "bazarr.s0.neet.dev" "http://vpn.containers:6767")
|
||||
(mkVirtualHost "radarr.s0.neet.dev" "http://vpn.containers:7878")
|
||||
(mkVirtualHost "lidarr.s0.neet.dev" "http://vpn.containers:8686")
|
||||
(mkVirtualHost "sonarr.s0.neet.dev" "http://vpn.containers:8989")
|
||||
(mkVirtualHost "prowlarr.s0.neet.dev" "http://vpn.containers:9696")
|
||||
(mkVirtualHost "transmission.s0.neet.dev" "http://vpn.containers:9091")
|
||||
(mkVirtualHost "unifi.s0.neet.dev" "https://localhost:8443")
|
||||
(mkVirtualHost "music.s0.neet.dev" "http://localhost:4533")
|
||||
(mkVirtualHost "jellyfin.s0.neet.dev" "http://localhost:8096")
|
||||
(mkStaticHost "s0.neet.dev" config.services.dashy.finalDrv)
|
||||
{
|
||||
# Landing page LAN redirect
|
||||
"s0" = {
|
||||
default = true;
|
||||
redirectCode = 302;
|
||||
globalRedirect = "s0.neet.dev";
|
||||
};
|
||||
}
|
||||
(mkVirtualHost "ha.s0.neet.dev" "http://localhost:8123") # home assistant
|
||||
(mkVirtualHost "esphome.s0.neet.dev" "http://localhost:6052")
|
||||
(mkVirtualHost "zigbee.s0.neet.dev" "http://localhost:55834")
|
||||
{
|
||||
"frigate.s0.neet.dev" = {
|
||||
# Just configure SSL, frigate module configures the rest of nginx
|
||||
useACMEHost = "s0.neet.dev";
|
||||
forceSSL = true;
|
||||
};
|
||||
}
|
||||
(mkVirtualHost "vacuum.s0.neet.dev" "http://192.168.1.125") # valetudo
|
||||
(mkVirtualHost "sandman.s0.neet.dev" "http://192.168.9.14:3000") # es
|
||||
(mkVirtualHost "todo.s0.neet.dev" "http://localhost:${toString config.services.vikunja.port}")
|
||||
(mkVirtualHost "budget.s0.neet.dev" "http://localhost:${toString config.services.actual.settings.port}") # actual budget
|
||||
];
|
||||
|
||||
tailscaleAuth = {
|
||||
enable = true;
|
||||
virtualHosts = [
|
||||
"bazarr.s0.neet.dev"
|
||||
"radarr.s0.neet.dev"
|
||||
"lidarr.s0.neet.dev"
|
||||
"sonarr.s0.neet.dev"
|
||||
"prowlarr.s0.neet.dev"
|
||||
"transmission.s0.neet.dev"
|
||||
"unifi.s0.neet.dev"
|
||||
# "music.s0.neet.dev" # messes up navidrome
|
||||
"jellyfin.s0.neet.dev"
|
||||
"s0.neet.dev"
|
||||
# "ha.s0.neet.dev" # messes up home assistant
|
||||
"esphome.s0.neet.dev"
|
||||
"zigbee.s0.neet.dev"
|
||||
"vacuum.s0.neet.dev"
|
||||
"todo.s0.neet.dev"
|
||||
];
|
||||
expectedTailnet = "koi-bebop.ts.net";
|
||||
};
|
||||
};
|
||||
services.nginx.virtualHosts."jellyfin.neet.cloud".locations."/" = {
|
||||
proxyPass = "http://localhost:8096";
|
||||
proxyWebsockets = true;
|
||||
|
||||
# Get wildcard cert
|
||||
security.acme.certs."s0.neet.dev" = {
|
||||
dnsProvider = "digitalocean";
|
||||
credentialsFile = "/run/agenix/digitalocean-dns-credentials";
|
||||
extraDomainNames = [ "*.s0.neet.dev" ];
|
||||
group = "nginx";
|
||||
dnsResolver = "1.1.1.1:53";
|
||||
dnsPropagationCheck = false; # sadly this erroneously fails
|
||||
};
|
||||
services.nginx.virtualHosts."transmission.s0".locations."/" = {
|
||||
proxyPass = "http://vpn.containers:9091";
|
||||
proxyWebsockets = true;
|
||||
age.secrets.digitalocean-dns-credentials.file = ../../../secrets/digitalocean-dns-credentials.age;
|
||||
|
||||
virtualisation.oci-containers.backend = "podman";
|
||||
virtualisation.podman.dockerSocket.enable = true; # TODO needed?
|
||||
services.dashy = {
|
||||
enable = true;
|
||||
settings = import ./dashy.nix;
|
||||
};
|
||||
|
||||
services.unifi = {
|
||||
enable = true;
|
||||
openMinimalFirewall = true;
|
||||
};
|
||||
|
||||
services.vikunja = {
|
||||
enable = true;
|
||||
port = 61473;
|
||||
frontendScheme = "https";
|
||||
frontendHostname = "todo.s0.neet.dev";
|
||||
settings = {
|
||||
service.enableregistration = false;
|
||||
};
|
||||
};
|
||||
backup.group."vikunja".paths = [
|
||||
"/var/lib/vikunja"
|
||||
];
|
||||
|
||||
services.actual.enable = true;
|
||||
|
||||
boot.binfmt.emulatedSystems = [ "aarch64-linux" "armv7l-linux" ];
|
||||
}
|
||||
|
||||
154
machines/storage/s0/frigate.nix
Normal file
154
machines/storage/s0/frigate.nix
Normal file
@@ -0,0 +1,154 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
frigateHostname = "frigate.s0.neet.dev";
|
||||
|
||||
mkGo2RtcStream = name: url: withAudio: {
|
||||
${name} = [
|
||||
url
|
||||
"ffmpeg:${name}#video=copy${if withAudio then "#audio=copy" else ""}"
|
||||
];
|
||||
};
|
||||
|
||||
# Assumes camera is set to output:
|
||||
# - rtsp
|
||||
# - H.264 + AAC
|
||||
# - a downscaled substream for detection
|
||||
mkCamera = name: primaryUrl: detectUrl: {
|
||||
# Reference https://docs.frigate.video/configuration/reference/
|
||||
services.frigate.settings = {
|
||||
cameras.${name} = {
|
||||
ffmpeg = {
|
||||
# Camera feeds are relayed through go2rtc
|
||||
inputs = [
|
||||
{
|
||||
path = "rtsp://127.0.0.1:8554/${name}";
|
||||
# input_args = "preset-rtsp-restream";
|
||||
input_args = "preset-rtsp-restream-low-latency";
|
||||
roles = [ "record" ];
|
||||
}
|
||||
{
|
||||
path = detectUrl;
|
||||
roles = [ "detect" ];
|
||||
}
|
||||
];
|
||||
output_args = {
|
||||
record = "preset-record-generic-audio-copy";
|
||||
};
|
||||
};
|
||||
detect = {
|
||||
width = 1280;
|
||||
height = 720;
|
||||
fps = 5;
|
||||
};
|
||||
};
|
||||
};
|
||||
services.go2rtc.settings.streams = lib.mkMerge [
|
||||
(mkGo2RtcStream name primaryUrl false)
|
||||
|
||||
# Sadly having the detection stream go through go2rpc too makes the stream unreadable by frigate for some reason.
|
||||
# It might need to be re-encoded to work. But I am not interested in wasting the processing power if only frigate
|
||||
# need the detection stream anyway. So just let frigate grab the stream directly since it works.
|
||||
# (mkGo2RtcStream detectName detectUrl false)
|
||||
];
|
||||
};
|
||||
|
||||
mkDahuaCamera = name: address:
|
||||
let
|
||||
# go2rtc and frigate have a slightly different syntax for inserting env vars. So the URLs are not interchangable :(
|
||||
# - go2rtc: ${VAR}
|
||||
# - frigate: {VAR}
|
||||
primaryUrl = "rtsp://admin:\${FRIGATE_RTSP_PASSWORD}@${address}/cam/realmonitor?channel=1&subtype=0";
|
||||
detectUrl = "rtsp://admin:{FRIGATE_RTSP_PASSWORD}@${address}/cam/realmonitor?channel=1&subtype=3";
|
||||
in
|
||||
mkCamera name primaryUrl detectUrl;
|
||||
|
||||
mkEsp32Camera = name: address: {
|
||||
services.frigate.settings.cameras.${name} = {
|
||||
ffmpeg = {
|
||||
input_args = "";
|
||||
inputs = [{
|
||||
path = "http://${address}:8080";
|
||||
roles = [ "detect" "record" ];
|
||||
}];
|
||||
|
||||
output_args.record = "-f segment -pix_fmt yuv420p -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v libx264 -preset ultrafast -an ";
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
lib.mkMerge [
|
||||
(mkDahuaCamera "dog-cam" "192.168.10.31")
|
||||
# (mkEsp32Camera "dahlia-cam" "dahlia-cam.lan")
|
||||
{
|
||||
services.frigate = {
|
||||
enable = true;
|
||||
hostname = frigateHostname;
|
||||
settings = {
|
||||
mqtt = {
|
||||
enabled = true;
|
||||
host = "localhost";
|
||||
port = 1883;
|
||||
user = "root";
|
||||
password = "{FRIGATE_MQTT_PASSWORD}";
|
||||
};
|
||||
snapshots = {
|
||||
enabled = true;
|
||||
bounding_box = true;
|
||||
};
|
||||
record = {
|
||||
enabled = true;
|
||||
# sync_recordings = true; # detect if recordings were deleted outside of frigate (expensive)
|
||||
retain = {
|
||||
days = 7; # Keep video for 7 days
|
||||
mode = "all";
|
||||
# mode = "motion";
|
||||
};
|
||||
events = {
|
||||
retain = {
|
||||
default = 10; # Keep video with detections for 10 days
|
||||
mode = "motion";
|
||||
# mode = "active_objects";
|
||||
};
|
||||
};
|
||||
};
|
||||
# Make frigate aware of the go2rtc streams
|
||||
go2rtc.streams = config.services.go2rtc.settings.streams;
|
||||
detect.enabled = false; # :(
|
||||
objects = {
|
||||
track = [ "person" "dog" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.go2rtc = {
|
||||
enable = true;
|
||||
settings = {
|
||||
rtsp.listen = ":8554";
|
||||
webrtc.listen = ":8555";
|
||||
};
|
||||
};
|
||||
|
||||
# Pass in env file with secrets to frigate/go2rtc
|
||||
systemd.services.frigate.serviceConfig.EnvironmentFile = "/run/agenix/frigate-credentials";
|
||||
systemd.services.go2rtc.serviceConfig.EnvironmentFile = "/run/agenix/frigate-credentials";
|
||||
age.secrets.frigate-credentials.file = ../../../secrets/frigate-credentials.age;
|
||||
}
|
||||
{
|
||||
# hardware encode/decode with amdgpu vaapi
|
||||
services.frigate.vaapiDriver = "radeonsi";
|
||||
services.frigate.settings.ffmpeg.hwaccel_args = "preset-vaapi";
|
||||
}
|
||||
{
|
||||
# Coral TPU for frigate
|
||||
services.frigate.settings.detectors.coral = {
|
||||
type = "edgetpu";
|
||||
device = "pci";
|
||||
};
|
||||
}
|
||||
{
|
||||
# Don't require authentication for frigate
|
||||
# This is ok because the reverse proxy already requires tailscale access anyway
|
||||
services.frigate.settings.auth.enabled = false;
|
||||
}
|
||||
]
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
# boot
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.systemd-boot.memtest86.enable = true;
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "uas" "sd_mod" "rtsx_pci_sdmmc" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
@@ -21,30 +22,23 @@
|
||||
# zfs
|
||||
networking.hostId = "5e6791f0";
|
||||
boot.supportedFilesystems = [ "zfs" ];
|
||||
boot.kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages;
|
||||
|
||||
# luks
|
||||
remoteLuksUnlock.enable = true;
|
||||
luks.devices = [
|
||||
"/dev/disk/by-uuid/d52e99a9-8825-4d0a-afc1-8edbef7e0a86"
|
||||
"/dev/disk/by-uuid/f7275585-7760-4230-97de-36704b9a2aa3"
|
||||
"/dev/disk/by-uuid/5d1002b8-a0ed-4a1c-99f5-24b8816d9e38"
|
||||
"/dev/disk/by-uuid/e2c7402a-e72c-4c4a-998f-82e4c10187bc"
|
||||
];
|
||||
boot.initrd.luks.devices."enc-pv1".device = "/dev/disk/by-uuid/d52e99a9-8825-4d0a-afc1-8edbef7e0a86";
|
||||
boot.initrd.luks.devices."enc-pv2".device = "/dev/disk/by-uuid/f7275585-7760-4230-97de-36704b9a2aa3";
|
||||
boot.initrd.luks.devices."enc-pv3".device = "/dev/disk/by-uuid/5d1002b8-a0ed-4a1c-99f5-24b8816d9e38";
|
||||
boot.initrd.luks.devices."enc-pv4".device = "/dev/disk/by-uuid/e2c7402a-e72c-4c4a-998f-82e4c10187bc";
|
||||
|
||||
# mounts
|
||||
services.zfs.autoScrub.enable = true;
|
||||
services.zfs.trim.enable = true;
|
||||
fileSystems."/" =
|
||||
{
|
||||
device = "rpool/nixos/root";
|
||||
fsType = "zfs";
|
||||
options = [ "zfsutil" "X-mount.mkdir" ];
|
||||
};
|
||||
fileSystems."/home" =
|
||||
{
|
||||
device = "rpool/nixos/home";
|
||||
fsType = "zfs";
|
||||
options = [ "zfsutil" "X-mount.mkdir" ];
|
||||
};
|
||||
fileSystems."/var/lib" =
|
||||
{
|
||||
device = "rpool/nixos/var/lib";
|
||||
@@ -57,13 +51,6 @@
|
||||
fsType = "zfs";
|
||||
options = [ "zfsutil" "X-mount.mkdir" ];
|
||||
};
|
||||
|
||||
fileSystems."/data" =
|
||||
{
|
||||
device = "rpool/nixos/data";
|
||||
fsType = "zfs";
|
||||
options = [ "zfsutil" "X-mount.mkdir" ];
|
||||
};
|
||||
fileSystems."/boot" =
|
||||
{
|
||||
device = "/dev/disk/by-uuid/4FB4-738E";
|
||||
@@ -71,7 +58,43 @@
|
||||
};
|
||||
swapDevices = [ ];
|
||||
|
||||
networking.interfaces.eth0.useDHCP = true;
|
||||
networking = {
|
||||
dhcpcd.enable = false;
|
||||
|
||||
vlans = {
|
||||
iot = {
|
||||
id = 2;
|
||||
interface = "eth1";
|
||||
};
|
||||
};
|
||||
|
||||
interfaces.eth1.ipv4.addresses = [{
|
||||
address = "192.168.1.2";
|
||||
prefixLength = 21;
|
||||
}];
|
||||
interfaces.iot.ipv4.addresses = [{
|
||||
address = "192.168.9.8";
|
||||
prefixLength = 22;
|
||||
}];
|
||||
|
||||
defaultGateway = "192.168.1.1";
|
||||
nameservers = [ "1.1.1.1" "8.8.8.8" ];
|
||||
};
|
||||
|
||||
# networking = {
|
||||
# vlans = {
|
||||
# iot = {
|
||||
# id = 2;
|
||||
# interface = "eth1";
|
||||
# };
|
||||
# };
|
||||
|
||||
# defaultGateway = {
|
||||
# interface = "eth1";
|
||||
# address = "192.168.1.1";
|
||||
# metric = 10; # always use this route as default gateway
|
||||
# };
|
||||
# };
|
||||
|
||||
powerManagement.cpuFreqGovernor = "powersave";
|
||||
}
|
||||
|
||||
108
machines/storage/s0/home-automation.nix
Normal file
108
machines/storage/s0/home-automation.nix
Normal file
@@ -0,0 +1,108 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
services.esphome.enable = true;
|
||||
|
||||
services.mosquitto = {
|
||||
enable = true;
|
||||
listeners = [
|
||||
{
|
||||
users.root = {
|
||||
acl = [ "readwrite #" ];
|
||||
hashedPassword = "$7$101$8+QnkTzCdGizaKqq$lpU4o84n6D/1uwfA9pZDVExr1NDm1D/8tNla2tE9J9HdUqkvu192yYfiySY1MFqVNgUKgWEFu5P1bUKqRnzbUw==";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
1883 # mqtt
|
||||
];
|
||||
|
||||
services.zigbee2mqtt = {
|
||||
enable = true;
|
||||
settings = {
|
||||
homeassistant = true;
|
||||
permit_join = false;
|
||||
serial = {
|
||||
adapter = "ember";
|
||||
port = "/dev/ttyACM0";
|
||||
};
|
||||
mqtt = {
|
||||
server = "mqtt://localhost:1883";
|
||||
user = "root";
|
||||
password = "!/run/agenix/zigbee2mqtt.yaml mqtt_password";
|
||||
};
|
||||
frontend = {
|
||||
host = "localhost";
|
||||
port = 55834;
|
||||
};
|
||||
};
|
||||
};
|
||||
age.secrets."zigbee2mqtt.yaml" = {
|
||||
file = ../../../secrets/zigbee2mqtt.yaml.age;
|
||||
owner = "zigbee2mqtt";
|
||||
};
|
||||
|
||||
services.home-assistant = {
|
||||
enable = true;
|
||||
extraComponents = [
|
||||
"default_config"
|
||||
"rest_command"
|
||||
"esphome"
|
||||
"met"
|
||||
"radio_browser"
|
||||
"wled"
|
||||
"mqtt"
|
||||
"apple_tv" # why is this even needed? I get `ModuleNotFoundError: No module named 'pyatv'` errors otherwise for some reason.
|
||||
"unifi"
|
||||
"digital_ocean"
|
||||
"downloader"
|
||||
"mailgun"
|
||||
"minecraft_server"
|
||||
"mullvad"
|
||||
"nextcloud"
|
||||
"ollama"
|
||||
"openweathermap"
|
||||
"jellyfin"
|
||||
"transmission"
|
||||
"radarr"
|
||||
"sonarr"
|
||||
"syncthing"
|
||||
"tailscale"
|
||||
"weather"
|
||||
"whois"
|
||||
"youtube"
|
||||
"homekit_controller"
|
||||
"zha"
|
||||
"bluetooth"
|
||||
];
|
||||
config = {
|
||||
# Includes dependencies for a basic setup
|
||||
# https://www.home-assistant.io/integrations/default_config/
|
||||
default_config = { };
|
||||
|
||||
# Enable reverse proxy support
|
||||
http = {
|
||||
use_x_forwarded_for = true;
|
||||
trusted_proxies = [
|
||||
"127.0.0.1"
|
||||
"::1"
|
||||
];
|
||||
};
|
||||
|
||||
"automation manual" = [
|
||||
];
|
||||
# Allow using automations generated from the UI
|
||||
"automation ui" = "!include automations.yaml";
|
||||
|
||||
"rest_command" = {
|
||||
json_post_request = {
|
||||
url = "{{ url }}";
|
||||
method = "POST";
|
||||
content_type = "application/json";
|
||||
payload = "{{ payload | default('{}') }}";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
hostNames = [
|
||||
"s0"
|
||||
"s0.neet.dev"
|
||||
];
|
||||
|
||||
arch = "x86_64-linux";
|
||||
@@ -9,12 +10,19 @@
|
||||
"storage"
|
||||
"server"
|
||||
"pia"
|
||||
"binary-cache"
|
||||
"gitea-actions-runner"
|
||||
"frigate"
|
||||
"zigbee"
|
||||
"media-server"
|
||||
];
|
||||
|
||||
hostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAwiXcUFtAvZCayhu4+AIcF+Ktrdgv9ee/mXSIhJbp4q";
|
||||
|
||||
remoteUnlock = {
|
||||
hostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFNiceeFMos5ZXcYem4yFxh8PiZNNnuvhlyLbQLrgIZH";
|
||||
|
||||
clearnetHost = "192.168.1.2";
|
||||
onionHost = "r3zvf7f2ppaeithzswigma46pajt3hqytmkg3rshgknbl3jbni455fqd.onion";
|
||||
};
|
||||
}
|
||||
|
||||
107
machines/zoidberg/default.nix
Normal file
107
machines/zoidberg/default.nix
Normal file
@@ -0,0 +1,107 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
# Login DE Option: Steam
|
||||
programs.steam.gamescopeSession.enable = true;
|
||||
# programs.gamescope.capSysNice = true;
|
||||
|
||||
# Login DE Option: Kodi
|
||||
services.xserver.desktopManager.kodi.enable = true;
|
||||
services.xserver.desktopManager.kodi.package =
|
||||
(
|
||||
pkgs.kodi.passthru.withPackages (kodiPackages: with kodiPackages; [
|
||||
jellyfin
|
||||
joystick
|
||||
])
|
||||
);
|
||||
services.mount-samba.enable = true;
|
||||
|
||||
# Login DE Option: RetroArch
|
||||
services.xserver.desktopManager.retroarch.enable = true;
|
||||
services.xserver.desktopManager.retroarch.package = pkgs.retroarchFull;
|
||||
|
||||
# wireless xbox controller support
|
||||
hardware.xone.enable = true;
|
||||
boot.kernelModules = [ "xone-wired" "xone-dongle" ];
|
||||
hardware.enableRedistributableFirmware = true;
|
||||
hardware.enableAllFirmware = true;
|
||||
|
||||
# ROCm
|
||||
hardware.graphics.extraPackages = with pkgs; [
|
||||
rocmPackages.clr.icd
|
||||
rocmPackages.clr
|
||||
];
|
||||
systemd.tmpfiles.rules = [
|
||||
"L+ /opt/rocm/hip - - - - ${pkgs.rocmPackages.clr}"
|
||||
];
|
||||
|
||||
# System wide barrier instance
|
||||
# systemd.services.barrier-sddm = {
|
||||
# description = "Barrier mouse/keyboard share";
|
||||
# requires = [ "display-manager.service" ];
|
||||
# after = [ "network.target" "display-manager.service" ];
|
||||
# wantedBy = [ "multi-user.target" ];
|
||||
# serviceConfig = {
|
||||
# Restart = "always";
|
||||
# RestartSec = 10;
|
||||
# # todo use user/group
|
||||
# };
|
||||
# path = with pkgs; [ barrier doas ];
|
||||
# script = ''
|
||||
# # Wait for file to show up. "display-manager.service" finishes a bit too soon
|
||||
# while ! [ -e /run/sddm/* ]; do sleep 1; done;
|
||||
# export XAUTHORITY=$(ls /run/sddm/*)
|
||||
# # Disable crypto is fine because tailscale is E2E encrypting better than barrier could anyway
|
||||
# barrierc -f --disable-crypto --name zoidberg ray.koi-bebop.ts.net
|
||||
# '';
|
||||
# };
|
||||
|
||||
# Login into X11 plasma so barrier works well
|
||||
services.displayManager.defaultSession = "plasma";
|
||||
|
||||
users.users.cris = {
|
||||
isNormalUser = true;
|
||||
hashedPassword = "$y$j9T$LMGwHVauFWAcAyWSSmcuS/$BQpDyjDHZZbvj54.ijvNb03tr7IgX9wcjYCuCxjSqf6";
|
||||
uid = 1001;
|
||||
packages = with pkgs; [
|
||||
maestral
|
||||
maestral-gui
|
||||
] ++ config.users.users.googlebot.packages;
|
||||
};
|
||||
|
||||
# Dr. John A. Zoidberg
|
||||
users.users.john = {
|
||||
isNormalUser = true;
|
||||
inherit (config.users.users.googlebot) hashedPassword packages;
|
||||
uid = 1002;
|
||||
};
|
||||
|
||||
# Auto login into Plasma in john zoidberg account
|
||||
services.displayManager.sddm.settings = {
|
||||
Autologin = {
|
||||
Session = "plasma";
|
||||
User = "john";
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
jellyfin-media-player
|
||||
config.services.xserver.desktopManager.kodi.package
|
||||
spotify
|
||||
retroarchFull
|
||||
];
|
||||
|
||||
# Command and Conquer Ports
|
||||
networking.firewall.allowedUDPPorts = [ 4321 27900 ];
|
||||
networking.firewall.allowedTCPPorts = [ 6667 28910 29900 29920 ];
|
||||
|
||||
nixpkgs.config.rocmSupport = true;
|
||||
services.ollama = {
|
||||
enable = true;
|
||||
acceleration = "rocm";
|
||||
};
|
||||
}
|
||||
47
machines/zoidberg/hardware-configuration.nix
Normal file
47
machines/zoidberg/hardware-configuration.nix
Normal file
@@ -0,0 +1,47 @@
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
# boot
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.timeout = lib.mkForce 15;
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "usbhid" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ "dm-snapshot" ];
|
||||
|
||||
# kernel
|
||||
boot.kernelModules = [ "kvm-amd" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
boot.kernelPackages = pkgs.linuxPackages_latest;
|
||||
|
||||
# luks unlock with clevis
|
||||
boot.initrd.systemd.enable = true;
|
||||
boot.initrd.clevis = {
|
||||
enable = true;
|
||||
devices."enc-pv".secretFile = "/secret/decrypt.jwe";
|
||||
};
|
||||
|
||||
# disks
|
||||
boot.initrd.luks.devices."enc-pv" = {
|
||||
device = "/dev/disk/by-uuid/04231c41-2f13-49c0-8fce-0357eea67990";
|
||||
allowDiscards = true;
|
||||
};
|
||||
fileSystems."/" =
|
||||
{
|
||||
device = "/dev/disk/by-uuid/39ee326c-a42f-49f3-84d9-f10091a903cd";
|
||||
fsType = "btrfs";
|
||||
};
|
||||
fileSystems."/boot" =
|
||||
{
|
||||
device = "/dev/disk/by-uuid/954B-AB3E";
|
||||
fsType = "vfat";
|
||||
};
|
||||
swapDevices =
|
||||
[{ device = "/dev/disk/by-uuid/44e36954-9f1c-49ae-af07-72b240f93a95"; }];
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
||||
14
machines/zoidberg/properties.nix
Normal file
14
machines/zoidberg/properties.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
hostNames = [
|
||||
"zoidberg"
|
||||
];
|
||||
|
||||
arch = "x86_64-linux";
|
||||
|
||||
systemRoles = [
|
||||
"personal"
|
||||
"media-center"
|
||||
];
|
||||
|
||||
hostKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHvdC1EiLqSNVmk5L1p7cWRIrrlelbK+NMj6tEBrwqIq";
|
||||
}
|
||||
7
overlays/default.nix
Normal file
7
overlays/default.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ inputs }:
|
||||
final: prev:
|
||||
|
||||
let
|
||||
system = prev.system;
|
||||
in
|
||||
{ }
|
||||
11
overlays/kernel-modules/default.nix
Normal file
11
overlays/kernel-modules/default.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
# Adds additional kernel modules to the nixos system
|
||||
# Not actually an overlay but a module. Has to be this way because kernel
|
||||
# modules are tightly coupled to the kernel version they were built against.
|
||||
# https://nixos.wiki/wiki/Linux_kernel
|
||||
|
||||
let
|
||||
cfg = config.kernel;
|
||||
in
|
||||
{ }
|
||||
15
patches/dont-break-nix-serve.patch
Normal file
15
patches/dont-break-nix-serve.patch
Normal file
@@ -0,0 +1,15 @@
|
||||
diff --git a/nixos/modules/services/video/frigate.nix b/nixos/modules/services/video/frigate.nix
|
||||
index 49f8ed673816..643b59d68dde 100644
|
||||
--- a/nixos/modules/services/video/frigate.nix
|
||||
+++ b/nixos/modules/services/video/frigate.nix
|
||||
@@ -482,10 +482,6 @@ in
|
||||
};
|
||||
};
|
||||
extraConfig = ''
|
||||
- # Frigate wants to connect on 127.0.0.1:5000 for unauthenticated requests
|
||||
- # https://github.com/NixOS/nixpkgs/issues/370349
|
||||
- listen 127.0.0.1:5000;
|
||||
-
|
||||
# vod settings
|
||||
vod_base_url "";
|
||||
vod_segments_base_url "";
|
||||
13
patches/gamepadui.patch
Normal file
13
patches/gamepadui.patch
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/nixos/modules/programs/steam.nix b/nixos/modules/programs/steam.nix
|
||||
index 29c449c16946..f6c728eb7f0c 100644
|
||||
--- a/nixos/modules/programs/steam.nix
|
||||
+++ b/nixos/modules/programs/steam.nix
|
||||
@@ -11,7 +11,7 @@ let
|
||||
in
|
||||
pkgs.writeShellScriptBin "steam-gamescope" ''
|
||||
${builtins.concatStringsSep "\n" exports}
|
||||
- gamescope --steam ${builtins.toString cfg.gamescopeSession.args} -- steam -tenfoot -pipewire-dmabuf
|
||||
+ gamescope --steam ${builtins.toString cfg.gamescopeSession.args} -- steam -gamepadui -steamdeck -pipewire-dmabuf &> /tmp/steamlog
|
||||
'';
|
||||
|
||||
gamescopeSessionFile =
|
||||
@@ -1,264 +0,0 @@
|
||||
diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix
|
||||
index b8f36538e70..cc320a04c70 100644
|
||||
--- a/nixos/modules/system/boot/luksroot.nix
|
||||
+++ b/nixos/modules/system/boot/luksroot.nix
|
||||
@@ -146,6 +146,7 @@ let
|
||||
csopen = "cryptsetup luksOpen ${dev.device} ${dev.name}"
|
||||
+ optionalString dev.allowDiscards " --allow-discards"
|
||||
+ optionalString dev.bypassWorkqueues " --perf-no_read_workqueue --perf-no_write_workqueue"
|
||||
+ + optionalString dev.disableKeyring " --disable-keyring"
|
||||
+ optionalString (dev.header != null) " --header=${dev.header}";
|
||||
cschange = "cryptsetup luksChangeKey ${dev.device} ${optionalString (dev.header != null) "--header=${dev.header}"}";
|
||||
fido2luksCredentials = dev.fido2.credentials ++ optional (dev.fido2.credential != null) dev.fido2.credential;
|
||||
@@ -243,6 +244,26 @@ let
|
||||
do_open_passphrase
|
||||
fi
|
||||
fi
|
||||
+ '' else if (dev.masterKeyFile != null) then ''
|
||||
+ if wait_target "key file" ${dev.masterKeyFile}; then
|
||||
+ ${csopen} --master-key-file=${dev.masterKeyFile}
|
||||
+ cs_status=$?
|
||||
+ if [ $cs_status -ne 0 ]; then
|
||||
+ echo "Key File ${dev.masterKeyFile} failed!"
|
||||
+ if ! try_empty_passphrase; then
|
||||
+ ${if dev.fallbackToPassword then "echo" else "die"} "${dev.masterKeyFile} is unavailable"
|
||||
+ echo " - failing back to interactive password prompt"
|
||||
+ do_open_passphrase
|
||||
+ fi
|
||||
+ fi
|
||||
+ else
|
||||
+ # If the key file never shows up we should also try the empty passphrase
|
||||
+ if ! try_empty_passphrase; then
|
||||
+ ${if dev.fallbackToPassword then "echo" else "die"} "${dev.masterKeyFile} is unavailable"
|
||||
+ echo " - failing back to interactive password prompt"
|
||||
+ do_open_passphrase
|
||||
+ fi
|
||||
+ fi
|
||||
'' else ''
|
||||
if ! try_empty_passphrase; then
|
||||
do_open_passphrase
|
||||
@@ -625,6 +646,15 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
+ masterKeyFile = mkOption {
|
||||
+ default = null;
|
||||
+ type = types.nullOr types.str;
|
||||
+ description = lib.mdDoc ''
|
||||
+ The name of the file (can be a raw device or a partition) that
|
||||
+ should be used as the master decryption key for the encrypted device.
|
||||
+ '';
|
||||
+ };
|
||||
+
|
||||
tryEmptyPassphrase = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
@@ -700,6 +730,15 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
+ disableKeyring = mkOption {
|
||||
+ default = false;
|
||||
+ type = types.bool;
|
||||
+ description = lib.mdDoc ''
|
||||
+ Disables using the kernel keyring for LUKS2 disks.
|
||||
+ This is already the default behavior for LUKS1
|
||||
+ '';
|
||||
+ };
|
||||
+
|
||||
fallbackToPassword = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
diff --git a/nixos/modules/tasks/auto-upgrade.nix b/nixos/modules/tasks/auto-upgrade.nix
|
||||
index 29e3e313336..050bf09c208 100644
|
||||
--- a/nixos/modules/tasks/auto-upgrade.nix
|
||||
+++ b/nixos/modules/tasks/auto-upgrade.nix
|
||||
@@ -4,7 +4,8 @@ with lib;
|
||||
|
||||
let cfg = config.system.autoUpgrade;
|
||||
|
||||
-in {
|
||||
+in
|
||||
+{
|
||||
|
||||
options = {
|
||||
|
||||
@@ -22,7 +23,7 @@ in {
|
||||
};
|
||||
|
||||
operation = mkOption {
|
||||
- type = types.enum ["switch" "boot"];
|
||||
+ type = types.enum [ "switch" "boot" ];
|
||||
default = "switch";
|
||||
example = "boot";
|
||||
description = lib.mdDoc ''
|
||||
@@ -86,14 +87,14 @@ in {
|
||||
'';
|
||||
};
|
||||
|
||||
- allowReboot = mkOption {
|
||||
+ allowKexec = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = lib.mdDoc ''
|
||||
- Reboot the system into the new generation instead of a switch
|
||||
+ kexec the system into the new generation instead of a switch
|
||||
if the new generation uses a different kernel, kernel modules
|
||||
or initrd than the booted system.
|
||||
- See {option}`rebootWindow` for configuring the times at which a reboot is allowed.
|
||||
+ See {option}`kexecWindow` for configuring the times at which a kexec is allowed.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -109,25 +110,25 @@ in {
|
||||
'';
|
||||
};
|
||||
|
||||
- rebootWindow = mkOption {
|
||||
+ kexecWindow = mkOption {
|
||||
description = lib.mdDoc ''
|
||||
Define a lower and upper time value (in HH:MM format) which
|
||||
- constitute a time window during which reboots are allowed after an upgrade.
|
||||
- This option only has an effect when {option}`allowReboot` is enabled.
|
||||
- The default value of `null` means that reboots are allowed at any time.
|
||||
+ constitute a time window during which kexecs are allowed after an upgrade.
|
||||
+ This option only has an effect when {option}`allowKexec` is enabled.
|
||||
+ The default value of `null` means that kexecs are allowed at any time.
|
||||
'';
|
||||
default = null;
|
||||
example = { lower = "01:00"; upper = "05:00"; };
|
||||
type = with types; nullOr (submodule {
|
||||
options = {
|
||||
lower = mkOption {
|
||||
- description = lib.mdDoc "Lower limit of the reboot window";
|
||||
+ description = lib.mdDoc "Lower limit of the kexec window";
|
||||
type = types.strMatching "[[:digit:]]{2}:[[:digit:]]{2}";
|
||||
example = "01:00";
|
||||
};
|
||||
|
||||
upper = mkOption {
|
||||
- description = lib.mdDoc "Upper limit of the reboot window";
|
||||
+ description = lib.mdDoc "Upper limit of the kexec window";
|
||||
type = types.strMatching "[[:digit:]]{2}:[[:digit:]]{2}";
|
||||
example = "05:00";
|
||||
};
|
||||
@@ -165,12 +166,12 @@ in {
|
||||
}];
|
||||
|
||||
system.autoUpgrade.flags = (if cfg.flake == null then
|
||||
- [ "--no-build-output" ] ++ optionals (cfg.channel != null) [
|
||||
- "-I"
|
||||
- "nixpkgs=${cfg.channel}/nixexprs.tar.xz"
|
||||
- ]
|
||||
- else
|
||||
- [ "--flake ${cfg.flake}" ]);
|
||||
+ [ "--no-build-output" ] ++ optionals (cfg.channel != null) [
|
||||
+ "-I"
|
||||
+ "nixpkgs=${cfg.channel}/nixexprs.tar.xz"
|
||||
+ ]
|
||||
+ else
|
||||
+ [ "--flake ${cfg.flake}" ]);
|
||||
|
||||
systemd.services.nixos-upgrade = {
|
||||
description = "NixOS Upgrade";
|
||||
@@ -195,54 +196,56 @@ in {
|
||||
config.programs.ssh.package
|
||||
];
|
||||
|
||||
- script = let
|
||||
- nixos-rebuild = "${config.system.build.nixos-rebuild}/bin/nixos-rebuild";
|
||||
- date = "${pkgs.coreutils}/bin/date";
|
||||
- readlink = "${pkgs.coreutils}/bin/readlink";
|
||||
- shutdown = "${config.systemd.package}/bin/shutdown";
|
||||
- upgradeFlag = optional (cfg.channel == null) "--upgrade";
|
||||
- in if cfg.allowReboot then ''
|
||||
- ${nixos-rebuild} boot ${toString (cfg.flags ++ upgradeFlag)}
|
||||
- booted="$(${readlink} /run/booted-system/{initrd,kernel,kernel-modules})"
|
||||
- built="$(${readlink} /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})"
|
||||
-
|
||||
- ${optionalString (cfg.rebootWindow != null) ''
|
||||
- current_time="$(${date} +%H:%M)"
|
||||
-
|
||||
- lower="${cfg.rebootWindow.lower}"
|
||||
- upper="${cfg.rebootWindow.upper}"
|
||||
-
|
||||
- if [[ "''${lower}" < "''${upper}" ]]; then
|
||||
- if [[ "''${current_time}" > "''${lower}" ]] && \
|
||||
- [[ "''${current_time}" < "''${upper}" ]]; then
|
||||
- do_reboot="true"
|
||||
+ script =
|
||||
+ let
|
||||
+ nixos-rebuild = "${config.system.build.nixos-rebuild}/bin/nixos-rebuild";
|
||||
+ date = "${pkgs.coreutils}/bin/date";
|
||||
+ readlink = "${pkgs.coreutils}/bin/readlink";
|
||||
+ systemctl_kexec = "${config.systemd.package}/bin/systemctl kexec";
|
||||
+ upgradeFlag = optional (cfg.channel == null) "--upgrade";
|
||||
+ in
|
||||
+ if cfg.allowKexec then ''
|
||||
+ ${nixos-rebuild} boot ${toString (cfg.flags ++ upgradeFlag)}
|
||||
+ booted="$(${readlink} /run/booted-system/{initrd,kernel,kernel-modules})"
|
||||
+ built="$(${readlink} /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})"
|
||||
+
|
||||
+ ${optionalString (cfg.kexecWindow != null) ''
|
||||
+ current_time="$(${date} +%H:%M)"
|
||||
+
|
||||
+ lower="${cfg.kexecWindow.lower}"
|
||||
+ upper="${cfg.kexecWindow.upper}"
|
||||
+
|
||||
+ if [[ "''${lower}" < "''${upper}" ]]; then
|
||||
+ if [[ "''${current_time}" > "''${lower}" ]] && \
|
||||
+ [[ "''${current_time}" < "''${upper}" ]]; then
|
||||
+ do_kexec="true"
|
||||
+ else
|
||||
+ do_kexec="false"
|
||||
+ fi
|
||||
else
|
||||
- do_reboot="false"
|
||||
+ # lower > upper, so we are crossing midnight (e.g. lower=23h, upper=6h)
|
||||
+ # we want to reboot if cur > 23h or cur < 6h
|
||||
+ if [[ "''${current_time}" < "''${upper}" ]] || \
|
||||
+ [[ "''${current_time}" > "''${lower}" ]]; then
|
||||
+ do_kexec="true"
|
||||
+ else
|
||||
+ do_kexec="false"
|
||||
+ fi
|
||||
fi
|
||||
+ ''}
|
||||
+
|
||||
+ if [ "''${booted}" = "''${built}" ]; then
|
||||
+ ${nixos-rebuild} ${cfg.operation} ${toString cfg.flags}
|
||||
+ ${optionalString (cfg.kexecWindow != null) ''
|
||||
+ elif [ "''${do_kexec}" != true ]; then
|
||||
+ echo "Outside of configured kexec window, skipping."
|
||||
+ ''}
|
||||
else
|
||||
- # lower > upper, so we are crossing midnight (e.g. lower=23h, upper=6h)
|
||||
- # we want to reboot if cur > 23h or cur < 6h
|
||||
- if [[ "''${current_time}" < "''${upper}" ]] || \
|
||||
- [[ "''${current_time}" > "''${lower}" ]]; then
|
||||
- do_reboot="true"
|
||||
- else
|
||||
- do_reboot="false"
|
||||
- fi
|
||||
+ ${systemctl_kexec}
|
||||
fi
|
||||
- ''}
|
||||
-
|
||||
- if [ "''${booted}" = "''${built}" ]; then
|
||||
- ${nixos-rebuild} ${cfg.operation} ${toString cfg.flags}
|
||||
- ${optionalString (cfg.rebootWindow != null) ''
|
||||
- elif [ "''${do_reboot}" != true ]; then
|
||||
- echo "Outside of configured reboot window, skipping."
|
||||
- ''}
|
||||
- else
|
||||
- ${shutdown} -r +1
|
||||
- fi
|
||||
- '' else ''
|
||||
- ${nixos-rebuild} ${cfg.operation} ${toString (cfg.flags ++ upgradeFlag)}
|
||||
- '';
|
||||
+ '' else ''
|
||||
+ ${nixos-rebuild} ${cfg.operation} ${toString (cfg.flags ++ upgradeFlag)}
|
||||
+ '';
|
||||
|
||||
startAt = cfg.dates;
|
||||
|
||||
Binary file not shown.
BIN
secrets/binary-cache-private-key.age
Normal file
BIN
secrets/binary-cache-private-key.age
Normal file
Binary file not shown.
BIN
secrets/binary-cache-push-sshkey.age
Normal file
BIN
secrets/binary-cache-push-sshkey.age
Normal file
Binary file not shown.
10
secrets/cris-hashed-email-pw.age
Normal file
10
secrets/cris-hashed-email-pw.age
Normal file
@@ -0,0 +1,10 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 6AT2/g WZ9p/pCsEDpKbgGDLcTtisn25kExQX9iv+tL3wyPwiY
|
||||
vom2z9QRIQSFB0+4/7lSWUEB0eoAG+08nXgiUg/OSX4
|
||||
-> ssh-ed25519 w3nu8g ECLZwCRJVJqyUMf70EOl2/3ExTruKaxCSQlY5fBZqxk
|
||||
VemnmGpzx1VprkybW1hPlkfmiDaNcBDoEzX0mDZgmu0
|
||||
-> ssh-ed25519 dMQYog QiPsbFE8MtXnRNBwkUEC+6grqXEbDstEtxYR8uJks2w
|
||||
O3JWQGppFeZEd6o3W0KVTEIyNVGeLxKfTYTlgsAEVHQ
|
||||
--- RncZzBFEyMAkpZRWrPORA0DPHuCTNswmWG5CMNnfm4A
|
||||
ñ/¼ÔËõôŒ8nàÅ¥«¸7hîtä?T˜=‘%zˆ°[¤ÝØ!(…uÔdÇuò@
|
||||
×¢Ebƒyަù¦D=Ü!‹„XþtÞÔ:#¦þþãÞXÈX@ú_M‘
|
||||
11
secrets/digitalocean-dns-credentials.age
Normal file
11
secrets/digitalocean-dns-credentials.age
Normal file
@@ -0,0 +1,11 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 WBT1Hw TGdD8Nw+GPITDOXGhevSu+880DWET7WYN3nIyJ0xy2o
|
||||
69xepRTnmaFwa4IsGJjDdwZqTSf5fz6EZK0/q3oz/ZA
|
||||
-> ssh-ed25519 6AT2/g EmqXrXXsRxSS6AsH+7VMgoJTYo9eGj8ebLiLT4IWNxg
|
||||
eKs5/3tQMdg5bGJKNz8PFh9C7HiV+IlOU9dzpYcGIjo
|
||||
-> ssh-ed25519 hPp1nw wsIF676is8FquF6oANNauPrumsMnfVUZpPeVKEtBOzQ
|
||||
qZR8LSF+TQ2K3K0An69NHfk53ZqNEWev0IVcb71SR40
|
||||
-> ssh-ed25519 w3nu8g TKHY/5JuzFMhbW9CQAOI3woX8M9b1H/XXUpIMT0Mylk
|
||||
byJV0/BJ3ftG5eYv5BeyIYBi0VoWG31HRiENUxSeYE8
|
||||
--- fwHXHtE/sMLqCLSD8tR0oCPgNuif9Y/ncHU97hbf/Bw
|
||||
f"+ÉŒqc<71>H†Ñjï!JSšË¡Ì|yMìðX¼þMl<4D>ýçCy™îUXn»Égk¨ë)¤óOY§uº„¦²¶g%è Håvn·œ5ô!$Jœ¤Š…¶›$<24>#Dö;±¥àÖ }ÏŸcçKšˆ{R/
|
||||
7
secrets/frigate-credentials.age
Normal file
7
secrets/frigate-credentials.age
Normal file
@@ -0,0 +1,7 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 hPp1nw zOXF7NsZjm+DCYrJ+Ap2mX35JUt37CLJP1RhyOjB/XE
|
||||
ePprJM2cnhYZhP8aJUXOZeGHJm/DHlRYomWN+lFaU6w
|
||||
-> ssh-ed25519 w3nu8g gjeFAbFWXyPdGauKHXAzuIP9fmaj2Oysq9fHO8q7u38
|
||||
KiMR0pgEPtsfZnYAIsH7UHNhnsB6rtsW/hqV03uS2dI
|
||||
--- BPzPECz1g6vEv4OlRn6+FnWP9oq3tn6TN2o867icxYA
|
||||
}ìjºùŽ+l&þàx<C3A0>-TïÝ‹b‡ÅèØÄ·<C384>€Dg‰ñgc’*ˆ0<CB86>÷µcp
|
||||
11
secrets/gitea-actions-runner-token.age
Normal file
11
secrets/gitea-actions-runner-token.age
Normal file
@@ -0,0 +1,11 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 WBT1Hw PbGwwDeulHF6kdh073rq0RvD1hlx6spnKNgKU+QeDAw
|
||||
7dITwSQ2p1LZuaVEzLxcGOhB97MQT2zGoRrnNUMcOFk
|
||||
-> ssh-ed25519 hPp1nw Dn+5Fpme+JmRZKkCkqtCuD87p+sDYDA6OZ2aUmBkCRs
|
||||
Dgg3orXF4RYT/fHtc2tRuIhOQu48zICMqgPyV47vpf4
|
||||
-> ssh-ed25519 w3nu8g dghNLDH1Tm+sm42HXDhrLFtmU4iDF1yCGrO2VSgzZjo
|
||||
71scUVrGr4c4dunAFJYKd+uJ6aYJpSWBAk9swbv+IzM
|
||||
-> ssh-ed25519 dMQYog Wnl1+rh0Q3YD2s1UD0OYVm39wY/Uw1NRK3K7EFhFMls
|
||||
wXF6QBonlCalS1vI9cxzWgv1Gi+yAtYn6HrYCfpl5Nw
|
||||
--- rLOoGk0iX+wuNd1CKv7g2PRd2Ic+8JHCQhrVBaF9zbE
|
||||
<EFBFBD>òüüˤ/A¦Ì(ØiHC¸@¢Þð‰h`ˆ3ªá´' ¬ÚöáDì>ð¿¤~¸ÿÁö?ÑÃMêÙ@<40>t°(“Ò@ö׿^xÆMÉ}
|
||||
Binary file not shown.
@@ -1,10 +1,9 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 6AT2/g 93Az2iuqeWL6H/S3XDPXFoEPcrY/n/z9mlSNb5wABkU
|
||||
LpMPjpDtBrY2aHpqHwT5AY7vtsYHNcOjpz+LFY4TGCg
|
||||
-> ssh-ed25519 dMQYog 4qT0aF1IHsTtN1avMPWYG5Az2xmEZhVUhqcwyNFdfU4
|
||||
+wD0hE035JqYdDgJmkvNXwJyMzXrquA+RsD8QdK3xP8
|
||||
-> !vfM7-grease
|
||||
7nQGFFUWY9UIjfrb+/VfaG0zJ21zmDnDh5khs/0tioJevrrrlhub9Bz8iM/Jsfxy
|
||||
KUhwV8O8tL/5+30RFSlFRaAB6xPCGg24Yq6E
|
||||
--- jVsDtz2xpvK/XCHcdN5JVZx5zSxyEAM6D/xJIgN4YfY
|
||||
Ñì°ßév.rK,Æ$
|
||||
-> ssh-ed25519 6AT2/g 98/m3t8axoVBE6WzdxBtRhV2uSQKSCXwQjyxfWXPmQk
|
||||
AxV0FTvqbWfk/gf65d05PcotbEnYr4PgDQnsaYxP/MU
|
||||
-> ssh-ed25519 w3nu8g jys7B4COD4iINANeSCD3BqGFoghxTmsbuXoOOIiP+wQ
|
||||
b7eSN5fe4szfliINOr7ZQ7AoSsIK5akmIQ6uLDabcIE
|
||||
-> ssh-ed25519 dMQYog ToNUqTPYmxpz9OUcC94egELcPfHQHCErfHN6l9kSrRY
|
||||
2KoSVoWp+FH29YfH57ri2KOvhkuqYew1+PXm99e0BaI
|
||||
--- Cjk3E/MjgCF45aLlFeyoGiaUEZk/QuKtsvPb6GpzD8Q
|
||||
m°å>‹“~czÆê匦†``ÜÏqX«š'ÁÎ%ôwÔž~×ÄL·eä'a±]û‹0ò´LÉÀ‰%ÍY‚TÊÓc9f¡W¶Ã^¤9ÊõÙÝ2®™æ¶ÆBÌa ƒ™
|
||||
@@ -1,11 +1,11 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 6AT2/g O0XP3tiD5bv5aFK54eTpo4I6oXHk+P0/zyy5A1GQlwg
|
||||
0D5I+dRmW6Ak7VvQrNDa4NiHgBtD4sAS87U9iXKHrRs
|
||||
-> ssh-ed25519 dMQYog pofEwx9ktCWDTYGp/rXwxq1ZkMLaR4q4JTWJxHl6rRw
|
||||
CoUEZHQaQd4wFi6pcZPZfhPACXI9qgrB1xAuSilGJpI
|
||||
-> /5^-grease e yP^gopW&
|
||||
8qWOBZeGzhSSfGdjHDOGhs2MoZEQneLFMj8DsBqTrnttzgjtg8VSwuMD2JA3yiA5
|
||||
43u5T24PCzhKor8puT830nMU3HfQ3FA1RtiUpu1FWPA
|
||||
--- gJaY0whK+GQ+F6m3jCfeGkPbJoIkGxmcJ++XVseDeWI
|
||||
'½<14>¤ kª†süVûÊ
|
||||
ƒ$÷"Ãý|ÕÞÆ^n“ÑàÆÜ hï~2Tô±Ì<>6/ ˆjÈO<C388>þõvMŠôé/e¯XÆr~GÚ&oèn;=,îÂÿô½ï2]?j
|
||||
-> ssh-ed25519 6AT2/g 3E1kcHjq89rNd4NN6n3AcG2f5teA8+Rmt1NXNwatwnk
|
||||
trLztKaYvmhNJYiT+SHZipePcZcSCDprNCugSjtVFjs
|
||||
-> ssh-ed25519 w3nu8g bR2A/UCxtD2POHI4Ky/rvfC23ZbGTGnBZc/1XtRq+3s
|
||||
UyX6/DEC9boQb/Ktgw47DzsPo64Tn0LoITax95JdskE
|
||||
-> ssh-ed25519 dMQYog haLpVq9+Tq2FytfsXTwLvCk1ZUQsZ4JCiRLPFAb0SCg
|
||||
vZ5e8P1uEDTVS83MsWwh1j0tON9FeVc5F1O6wzwX5Vw
|
||||
--- ZnZiddI8Uqr7da1gSahlryY004ii9G2mJS8C4u+lv6o
|
||||
|
||||
¹e£g“-}Þ[&`Ú<E0LË÷-gõ_E<5F>W¹?íèJž¸ñ-ɵ#ÝŽ‚íJÙñZÔõŒ4Š3ñ\÷0ðómÝTúf9žºÛÆ@àÅ©;
|
||||
øù©œÉ‰A–úß
|
||||
@@ -1,9 +1,7 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 VyYH/Q X+fXLJz227KkBLu45rb9mUkkIpENSMtZeEJjl6qj5Xw
|
||||
AFAFnvsiogoMMwsAJO0DDoaizL9lmCLsF4QHDjmubr0
|
||||
-> ssh-ed25519 dMQYog P84+7TBcMFSALTn6FR/aXyqFE9DfOzp38ImkdWj7nE0
|
||||
PqOn1OL9Zt0x1pBIYOSKkkS//mbk1OX5pnDGp+OLYeI
|
||||
-> @?-grease
|
||||
3JvpmcTxdTgvv6vPL8dXEwjR+g
|
||||
--- aMYF1SbC+p01YWmg24+Ih78VPQcwzGU/P1cEfgRvXV8
|
||||
Ÿ @$™sžQ¼z<15><>®xkÊNfÛuÕ;§¿ ÎvI0•ªÇÎ^4.?, 8…çî
|
||||
-> ssh-ed25519 w3nu8g ER07FH17Wm9op5F4pCftNK76f+nNjtA6zQc/2dLyAHI
|
||||
nxxq/8tS3ENJhAEIhJCiSi7dV+68AmcEMh9zvZoWpdY
|
||||
-> ssh-ed25519 dMQYog JelCfh+akP7C/i1kimq3fC5PRQa9gHbmBaOnjKu+PDw
|
||||
GVTwo7MzkpCereZRh0HVjGYmtdMY1gHowMZtUQl7XQw
|
||||
--- p2l83t3bEdBrrp1ctaqqKhwB4l2McgZqZTtc2SXgd8Q
|
||||
ø±ôeÆd\Yå4lXVF§U©<55>þM||)دÔûú•¶Ü8¿>ëž%ðóJ$à´Õè
|
||||
Binary file not shown.
@@ -1,10 +1,9 @@
|
||||
age-encryption.org/v1
|
||||
-> ssh-ed25519 6AT2/g yTW46JmDIftcOqogIDjheXJf2sw/dG2WEJxfCXU/LDk
|
||||
0Co5/Rn22kmdcPr61ZOrmZJbPFHx2wJ8/YkbDjcjqKo
|
||||
-> ssh-ed25519 dMQYog RtZT0PwVL4kxUHilOhH2GBp8Z9WfyBkaxB62pjKpHA4
|
||||
muMlIt8VYQftMYacfdnQFeejfWpKTEG5gxbFNy97GTc
|
||||
-> 4|)`7yq-grease P#\5k8 +f
|
||||
jMegn6ATsj2Ai9B5Xmy+tay1nppwxvF1IGJH+hLNanYMsTIDZypM6UsNdzYQ/3mw
|
||||
VZ9ooy8TKUgAJ7jsd6IrKw
|
||||
--- tLaPQWJA0Hh5MrxfhaySURgY02K16IlzvsxKpOWGva0
|
||||
5?lヌ'シ!ケコ<EFBDB9><EFBDBA>ワキ匪Nxス+<2B>A9゚ムリl/グ諟ホ|旙<>Sオ&コサ、繃<>Q;_<>K
|
||||
-> ssh-ed25519 6AT2/g Knb25oYknkiXyMqVBR3T0sFSO4hDjWUTq3xIml/b4ig
|
||||
n7xamnrZ+SCWiKqniF3r2JvH4G8q2pJaHzF0riNEDf4
|
||||
-> ssh-ed25519 w3nu8g 7+2R5RpLjBf4jjj3S8ibMquUWgRMrifziGQubwuLrhA
|
||||
3jLCalnbA3Z2jr8Zs+qrpzSoi3Jv6E5OV2binpr3Kk4
|
||||
-> ssh-ed25519 dMQYog Nh2e7me0tiG7ZwQK8669VS0LCYFSH+b33I9tr8uI5CY
|
||||
7Gs1N9eZa1CGR9pczzugHbqnghqevX7kQCOeqR4q0eI
|
||||
--- OzW+omJsZA/b4DMF4hdQga7JVgiEYluZok3r8JM258I
|
||||
*³²ÝPކAcèÈ1·@Át¸e÷nf&ù#I7‡a‰Ûâc†ÃÀ<C383>êbDâ–~aõ]1w=Á
|
||||
BIN
secrets/librechat-env-file.age
Normal file
BIN
secrets/librechat-env-file.age
Normal file
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user