feat(configurations)!: flatten down, introduce meta.nix

Flatten down directory structure:
- From: `./hosts/${configuration-type}/${system}/{configuration,deploy}.nix`
-   To: `./hosts/${configuration-type}/{meta,configuration}.nix`
Keep `system` and `deploy-rs` config in `meta.nix`
Update `flake.lock`
This commit is contained in:
reo101 2024-08-13 15:53:14 +03:00
parent 29738555b1
commit 9b8f894a1a
Signed by: reo101
GPG key ID: 675AA7EF13964ACB
43 changed files with 459 additions and 344 deletions

View file

@ -0,0 +1,165 @@
{ inputs, lib, pkgs, config, ... }:
{
imports = [
inputs.hardware.nixosModules.common-cpu-amd
inputs.hardware.nixosModules.common-gpu-amd
./disko.nix
./network.nix
./wireguard.nix
./nginx.nix
./jellyfin.nix
./transmission.nix
./mindustry.nix
# ./home-assistant
./samba.nix
# ./steam.nix
# ./ollama.nix
# ./sunshine.nix
# ./photoprism.nix
# ./immich.nix
# ./nextcloud.nix
];
# services.kanidm = { };
age.rekey = {
# TODO: store in `meta`
hostPubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPopSTZ81UyKp9JSljCLp+Syk51zacjh9fLteqxQ6/aB";
# masterIdentities = [ "${inputs.self}/secrets/privkey.age" ];
# storageMode = "local";
# localStorageDir = "${inputs.self}/secrets/rekeyed/${config.networking.hostName}";
};
networking.hostName = "jeeves";
boot = {
loader.systemd-boot.enable = true;
kernelPackages = pkgs.linuxPackages_latest;
binfmt.emulatedSystems = [ "aarch64-linux" ];
initrd = {
availableKernelModules = [
"nvme"
];
# kernelModules = [
# "amdgpu"
# ];
};
};
hardware.enableRedistributableFirmware = true;
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
nix = let
flakeInputs = lib.filterAttrs (lib.const (lib.isType "flake")) inputs;
in {
# This will add each flake input as a registry
# To make nix3 commands consistent with your flake
registry = lib.mapAttrs (_: value: { flake = value; }) flakeInputs;
# This will additionally add your inputs to the system's legacy channels
# Making legacy nix commands consistent as well, awesome!
nixPath = lib.mapAttrsToList (key: value: "${key}=flake:${key}") flakeInputs;
settings = {
trusted-users = [
"root"
"jeeves"
];
experimental-features = "nix-command flakes";
auto-optimise-store = true;
};
};
programs.zsh.enable = true;
environment.systemPackages = with pkgs; [
git
# FIXME: cannot deploy neovim-nightly
# V neovim source
# > error: cannot add path '/nix/store/rhjznh5jdzdkzbnn0fhhvcf9rys0s59d-source' because it lacks a signature by a trusted key
# neovim
];
# NOTE: made with `mkpasswd -m sha-512`
age.secrets."jeeves.user.password" = {
rekeyFile = "${inputs.self}/secrets/home/jeeves/user/password.age";
generator = {
script = { pkgs, ... }: ''
${pkgs.mkpasswd}/bin/mkpasswd -m sha-512
'';
};
};
users = {
mutableUsers = true;
users = {
jeeves = {
isNormalUser = true;
shell = pkgs.zsh;
hashedPasswordFile = config.age.secrets."jeeves.user.password".path;
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBj8ZGcvI80WrJWV+dNy1a3L973ydSNqtwcVHzurDUaW (none)"
];
extraGroups = [
"wheel"
"networkmanager"
"audio"
"docker"
"transmission"
"input"
];
};
};
};
# reo101.jellyfin = {
# enable = true;
# image = "docker.io/jellyfin/jellyfin:latest";
# volumes = [
# "/var/cache/jellyfin/config:/config"
# "/var/cache/jellyfin/cache:/cache"
# "/var/log/jellyfin:/log"
# "/data/media/jellyfin:/media:ro"
# ];
# ports = [
# "8096:8096"
# ];
# };
# security.sudo-rs = {
# enable = !config.security.sudo.enable;
# inherit (config.security.sudo) extraRules;
# };
security.sudo = {
enable = true;
extraRules = [
{
users = [
"jeeves"
];
commands = [
{
command = "ALL";
options = [ "NOPASSWD" ]; # "SETENV" # Adding the following could be a good idea
}
];
}
];
};
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "no";
PasswordAuthentication = false;
};
};
boot.plymouth = {
enable = true;
};
# https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion
system.stateVersion = "23.05";
}

View file

@ -0,0 +1,205 @@
{ inputs, lib, pkgs, config, ... }:
{
imports = [
inputs.disko.nixosModules.disko
];
environment.systemPackages = with pkgs; [
# `statfs` for btrfs commands
gocryptfs
];
# If on installer
disko.enableConfig = true;
# `head -c 8 /etc/machine-id`
networking.hostId = "1418566e";
# NOTE: needed for mounting `/key` (for LUKS)
boot.initrd.kernelModules = [
"uas"
"ext4"
];
# HACK: for troubleshooting
# see https://github.com/NixOS/nixpkgs/blob/9d6655c6222211adada5eeec4a91cb255b50dcb6/nixos/modules/system/boot/stage-1-init.sh#L45-L49
boot.initrd.preFailCommands = ''
export allowShell=1
'';
# NOTE: doesn't get mounted early enough, see below
# fileSystems."/key" = {
# device = "/dev/disk/by-partlabel/key";
# fsType = "ext4";
# neededForBoot = true;
# };
disko = {
devices = {
disk = {
# NOTE: we could do this to setup a usb for the keys
# but disko overrides it with no option of ignoring when partitioning
# (i.e. tell disko to only use this only for decalartion)
# key = {
# type = "disk";
# device = "/dev/disk/by-id/usb-USB2.0_Flash_Disk_1000000000001D8B-0";
# content = {
# type = "gpt";
# partitions = {
# key = {
# label = "key";
# size = "100%";
# content = {
# type = "filesystem";
# format = "ext4";
# mountpoint = "/key";
# };
# };
# };
# };
# };
ssd1 = {
type = "disk";
device = "/dev/disk/by-id/nvme-eui.e8238fa6bf530001001b448b4ebde3a6";
content = {
type = "gpt";
partitions = {
boot = {
label = "boot_mbr";
size = "1M";
type = "EF02"; # for grub MBR
priority = 1;
};
ESP = {
label = "boot";
size = "512M";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
priority = 2;
};
root = {
label = "root";
size = "100%";
content = {
type = "luks";
name = "root";
extraOpenArgs = [ ];
settings = {
keyFile = "/key/root";
# HACK: we need to manually wait for and mount the partition containing the keys
preOpenCommands = ''
# Prepare (kernel modules and directory for mounting)
modprobe uas
modprobe ext4
mkdir -m "0755" -p "/key"
# Loop until mounted (+ initial wait)
sleep 5
until mount -n -t "ext4" -o "ro" "/dev/disk/by-partlabel/key" "/key" 2>&1 1>/dev/null; do
echo 'Could not find a partition with label `key` (at `/dev/disk/by-partlabel/key`), retrying...'
sleep 2
done
'';
};
content = {
type = "btrfs";
extraArgs = [ "-f" ]; # Override existing partition
subvolumes = {
"/root" = {
mountpoint = "/";
};
};
};
};
priority = 3;
};
};
};
};
hdd1 = {
type = "disk";
device = "/dev/disk/by-id/ata-WDC_WD8003FFBX-68B9AN0_VYJB5TUM";
content = {
type = "gpt";
partitions = {
mdadm = {
label = "hdd1";
size = "100%";
content = {
type = "mdraid";
name = "tank";
};
};
};
};
};
hdd2 = {
type = "disk";
device = "/dev/disk/by-id/ata-WDC_WD8003FFBX-68B9AN0_VYHZTWSM";
content = {
type = "gpt";
partitions = {
mdadm = {
label = "hdd2";
size = "100%";
content = {
type = "mdraid";
name = "tank";
};
};
};
};
};
};
mdadm = {
tank = {
type = "mdadm";
level = 1;
content = {
type = "luks";
name = "tank";
extraOpenArgs = [ "--allow-discards" ];
settings.keyFile = "/key/tank";
content = {
type = "btrfs";
extraArgs = [ "-f" ]; # Override existing partition
subvolumes = {
"/home" = {
mountpoint = "/home";
mountOptions = [
"compress=zstd"
];
};
"/nix" = {
mountpoint = "/nix";
mountOptions = [
"compress=zstd"
"noatime"
];
};
"/data" = {
mountpoint = "/data";
mountOptions = [
"compress=zstd"
];
};
"/data/media" = { };
"/data/torrents" = { };
"/data/torrents/download" = { };
"/data/torrents/incomplete" = { };
"/data/media/jellyfin" = { };
"/data/samba" = { };
"/data/samba/private" = { };
"/data/samba/public" = { };
};
};
};
};
};
};
};
}

View file

@ -0,0 +1,23 @@
{
services.home-assistant.config = {
conversation.intents = {
FindAndroid = [
"(Find|Fight) my (phone|android|android phone)"
];
};
intent_script = {
FindAndroid = {
speech.text = "Send notification";
action = {
service = "notify.pushover";
data = {
message = "Phonefinderalert";
target = "android";
data.sound = "echo";
data.priority = 1;
};
};
};
};
};
}

View file

@ -0,0 +1,39 @@
{ inputs, lib, pkgs, config, ... }:
{
environment.systemPackages = with pkgs; [
];
nixpkgs.config.permittedInsecurePackages = [
"openssl-1.1.1w"
];
services.home-assistant = {
enable = true;
extraComponents = [
# Components required to complete the onboarding
"esphome"
"met"
"radio_browser"
"tuya"
];
config = {
# Includes dependencies for a basic setup
# https://www.home-assistant.io/integrations/default_config/
default_config = { };
mobile_app = { };
map = { };
};
};
networking.firewall =
lib.pipe
[ "TCP" "UDP" ]
[
(builtins.map
(protocol:
lib.nameValuePair
"allowed${protocol}Ports"
[ 8123 ]))
builtins.listToAttrs
];
}

View file

@ -0,0 +1,27 @@
{
services.home-assistant.config = {
conversation.intents = {
TellJoke = [
"Tell [me] (a joke|something funny|a dad joke)"
];
};
sensor = [
{
name = "random_joke";
platform = "rest";
json_attributes = "joke";
resource = "https://icanhazdadjoke.com/";
scan_interval = "3600";
headers.Accept = "application/json";
}
];
intent_script.TellJoke = {
speech.text = ''{{ state_attr("sensor.random_joke", "joke") }}'';
action = {
service = "homeassistant.update_entity";
entity_id = "sensor.random_joke";
};
};
};
}

View file

@ -0,0 +1,63 @@
{ inputs, lib, pkgs, config, ... }:
{
imports = [
inputs.wired.homeManagerModules.default
];
home = {
username = "jeeves";
homeDirectory = "/home/jeeves";
stateVersion = "23.05";
};
# Let Home Manager install and manage itself.
programs.home-manager.enable = true;
home.packages = with pkgs; [
## Core
# neovim
git
gnupg
pciutils # lspci
usbutils # lsusb
## Shell
# zsh
# starship
# zoxide
ripgrep
## Nix
direnv
## Torrents
tremc
## Rust
rustc
cargo
rust-analyzer
clang
openssl
pkg-config
];
reo101 = {
shell = {
enable = true;
direnv = true;
zoxide = true;
shells = [
"zsh"
"nushell"
];
};
};
home.file = {
".config/nvim" = {
source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/.local/src/reovim";
};
};
}

View file

@ -0,0 +1,49 @@
{ lib, pkgs, config, ... }:
{
hardware.graphics = {
enable = true;
enable32Bit = true;
extraPackages = with pkgs; [
vaapiVdpau
libva1
vulkan-loader
vulkan-validation-layers
vulkan-extension-layer
];
};
services = {
nginx = {
virtualHosts."jellyfin.jeeves.local" = {
enableACME = false;
forceSSL = false;
locations."/".proxyPass = "http://127.0.0.1:8096";
};
};
jellyfin = {
enable = true;
openFirewall = true;
};
# sonarr = {
# enable = true;
# openFirewall = true;
# };
# radarr = {
# enable = true;
# openFirewall = true;
# };
# bazarr = {
# enable = true;
# openFirewall = true;
# };
# readarr = {
# enable = true;
# openFirewall = true;
# };
# prowlarr = {
# enable = true;
# openFirewall = true;
# };
};
}

View file

@ -0,0 +1,48 @@
{
# The `system` of the host
system = "x86_64-linux";
# `deploy-rs` configuration
deploy = {
# This is the hostname by which you'll refer to this machine using reploy-rs
hostname = "jeeves.reo101.xyz";
# This is the user that deploy-rs will use when connecting.
# This will default to your own username if not specified anywhere
sshUser = "jeeves";
# This is the user that the profile will be deployed to (will use sudo if not the same as above).
# If `sshUser` is specified, this will be the default (though it will _not_ default to your own username)
user = "root";
# Which sudo command to use. Must accept at least two arguments:
# the user name to execute commands as and the rest is the command to execute
# This will default to "sudo -u" if not specified anywhere.
sudo = "sudo -u";
# This is an optional list of arguments that will be passed to SSH.
sshOpts = [ "-p" "727" ];
# Fast connection to the node. If this is true, copy the whole closure instead of letting the node substitute.
# This defaults to `false`
fastConnection = false;
# If the previous profile should be re-activated if activation fails.
# This defaults to `true`
autoRollback = true;
# See the earlier section about Magic Rollback for more information.
# This defaults to `true`
magicRollback = true;
# The path which deploy-rs will use for temporary files, this is currently only used by `magicRollback` to create an inotify watcher in for confirmations
# If not specified, this will default to `/tmp`
# (if `magicRollback` is in use, this _must_ be writable by `user`)
tempPath = "/tmp";
# Build the derivation on the target system
# Will also fetch all external dependencies from the target system's substituters.
# This default to `false`
remoteBuild = true;
};
}

View file

@ -0,0 +1,6 @@
{ lib, pkgs, config, ... }:
{
reo101.mindustry = {
enable = false;
};
}

View file

@ -0,0 +1,58 @@
{ inputs, lib, pkgs, config, ... }:
{
environment.systemPackages = with pkgs; [
];
networking.extraHosts = ''
127.0.0.1 jeeves.local
'';
# networking.nftables.enable = true;
age.secrets."home.wifi.env" = {
rekeyFile = "${inputs.self}/secrets/home/wifi/env.age";
};
networking.wireless = {
iwd.enable = true;
environmentFile = config.age.secrets."home.wifi.env".path;
networks = {
home = {
ssid = "@HOME_WIFI_SSID@";
psk = "@HOME_WIFI_PSK@";
};
};
};
networking.useNetworkd = true;
systemd.network = {
enable = true;
wait-online = {
enable = false;
anyInterface = true;
ignoredInterfaces = [
"eth0"
];
};
networks."10-eth0" = {
matchConfig.Name = "eth0";
networkConfig.DHCP = "yes";
networkConfig.DHCPServer = "yes";
};
links."10-eth0" = {
matchConfig.PermanentMACAddress = "04:7c:16:80:3c:2c";
linkConfig.Name = "eth0"; # "enp8s0";
};
networks."15-wan0" = {
matchConfig.Name = "wan0";
networkConfig.DHCP = "yes";
};
links."15-wan0" = {
matchConfig.PermanentMACAddress = "bc:f4:d4:40:5c:ed";
linkConfig.Name = "wan0"; # "wlp15s0";
};
};
# systemd.services.systemd-networkd.environment.SYSTEMD_LOG_LEVEL = "debug";
}

View file

@ -0,0 +1,32 @@
{ inputs, lib, pkgs, config, ... }:
{
# age.secrets."nextcloud.adminpass" = {
# rekeyFile = "${inputs.self}/secrets/home/jeeves/nextcloud/adminpass.age";
# mode = "770";
# owner = "nextcloud";
# group = "nextcloud";
# };
environment.systemPackages = [
# config.services.nextcloud.package
];
networking.firewall.allowedTCPPorts = [ 80 443 ];
services.nginx = {
enable = true;
package = pkgs.openresty;
# virtualHosts."_.${config.networking.hostName}.local" = {
# # listen = [
# # {
# # addr = "127.0.0.1";
# # port = 1234;
# # }
# # ];
# enableACME = false;
# forceSSL = false;
# locations."/".proxyPass = "http://127.0.0.1:1234";
# };
};
}

View file

@ -0,0 +1,30 @@
{ inputs, lib, pkgs, config, ... }:
{
networking.firewall.allowedTCPPorts = [11434];
services.ollama = {
enable = true;
host = "0.0.0.0";
port = 11434;
acceleration = "rocm";
environmentVariables = {
OLLAMA_ORIGINS = "*";
};
};
services.open-webui = {
enable = true;
host = "0.0.0.0";
port = 3000;
environment = {
ANONYMIZED_TELEMETRY = "False";
DO_NOT_TRACK = "True";
SCARF_NO_ANALYTICS = "True";
TRANSFORMERS_CACHE = "${config.services.open-webui.stateDir}/cache";
OLLAMA_API_BASE_URL = "http://127.0.0.1:11434";
# Disable authentication
WEBUI_AUTH = "False";
};
openFirewall = true;
};
}

View file

@ -0,0 +1,66 @@
{ lib, pkgs, config, ... }:
{
environment.systemPackages = with pkgs; [
];
# TODO: smbpasswd -a <USER>
services.samba-wsdd = {
# make shares visible for Windows clients
enable = true;
openFirewall = true;
};
services.samba = {
enable = true;
package = pkgs.sambaFull;
openFirewall = true;
securityType = "user";
extraConfig = ''
# Files
workgroup = WORKGROUP
server string = Jeeves
netbios name = jeeves
security = user
#use sendfile = yes
#max protocol = smb2
# NOTE: localhost is the ipv6 localhost ::1
hosts allow = 192.168.0. 192.168.1. 10.100.0. 127.0.0.1 localhost
hosts deny = 0.0.0.0/0
guest account = nobody
map to guest = bad user
# Symlinks
allow insecure wide links = yes
# Printers
load printers = yes
printing = cups
printcap name = cups
'';
shares = {
public = {
path = "/data/samba/public";
browseable = "yes";
"read only" = "no";
"guest ok" = "yes";
"create mask" = "0644";
"directory mask" = "0755";
"force user" = "jeeves";
"force group" = "users";
};
private = {
path = "/data/samba/private";
browseable = "yes";
"read only" = "no";
"guest ok" = "no";
"create mask" = "0644";
"directory mask" = "0755";
"force user" = "jeeves";
"force group" = "users";
"follow symlinks" = "yes";
"wide links" = "yes";
};
};
};
}

View file

@ -0,0 +1,31 @@
{ lib, pkgs, config, ... }:
{
environment.systemPackages = with pkgs; [
tremc
];
services = {
transmission = {
enable = true;
package = pkgs.transmission_4;
openRPCPort = true;
webHome = pkgs.flood-for-transmission;
# TODO: `credentialsFile` for RPC password with agenix
settings = {
download-dir = "/data/torrents/download";
incomplete-dir = "/data/torrents/incomplete";
incomplete-dir-enabled = true;
rpc-bind-address = "0.0.0.0";
rpc-whitelist = "127.0.0.1,192.168.*.*,10.100.0.*,*.local";
};
};
nginx = {
virtualHosts."transmission.jeeves.local" = {
enableACME = false;
forceSSL = false;
locations."/".proxyPass = "http://127.0.0.1:9091";
};
};
};
}

View file

@ -0,0 +1,112 @@
{ inputs, lib, pkgs, config, ... }:
{
environment.systemPackages = with pkgs; [
wireguard-tools
];
# NOTE: key generation
# umask 077
# wg genkey > key
# wg pubkey < key > key.pub
# Server
age.secrets."wireguard.privateKey" = {
mode = "077";
rekeyFile = "${inputs.self}/secrets/home/jeeves/wireguard/key.age";
generator = {
script = { lib, pkgs, file, ... }: /* bash */ ''
priv=$(${pkgs.wireguard-tools}/bin/wg genkey)
${pkgs.wireguard-tools}/bin/wg pubkey <<< "$priv" > ${lib.escapeShellArg (lib.removeSuffix ".age" file + ".pub")}
echo "$priv"
'';
};
};
# Enable NAT
networking.nat = {
enable = true;
enableIPv6 = true;
externalInterface = "eth0";
internalInterfaces = [ "wg0" ];
};
# Open ports in the firewall
networking.firewall = {
allowedTCPPorts = [ 53 ];
allowedUDPPorts = [ 53 51820 ];
};
systemd.network = {
netdevs = {
"50-wg0" = {
netdevConfig = {
Kind = "wireguard";
Name = "wg0";
MTUBytes = "1300";
};
wireguardConfig = {
PrivateKeyFile = config.age.secrets."wireguard.privateKey".path;
ListenPort = 51820;
};
wireguardPeers =
lib.mapAttrsToList
(host: peerConfig: peerConfig)
{
cheetah = {
PublicKey = "CFTGvBcly791ClwyS6PzTjmqztvYJW2eklR7it/QhxI=";
AllowedIPs = [
"10.100.0.2/32"
"0.0.0.0/0"
# "::/0"
];
};
limonka = {
PublicKey = "+x4cKc16KxhW/M3wv64FU1J0AkiLyXT5Oar6I1n1xk4=";
AllowedIPs = [
"10.100.0.3/32"
"0.0.0.0/0"
];
};
peshoDjam = {
PublicKey = "37QEe3Lsq5BTIzxqAh9z7clHYeaOaMH31oqi5YvAPBY=";
AllowedIPs = [
"10.100.0.4/32"
"192.168.1.134/32"
];
};
s42 = {
PublicKey = "pZF6M8TZ1FSBtTwFz4xzlMqwqRScEqgBfqHBk7ddixc=";
AllowedIPs = [
"10.100.0.5/32"
"0.0.0.0/0"
];
};
a41 = {
PublicKey = "/YEBfjDO+CfmYOKg9pO//ZAZQNutAS5z/Ggt2pX2gn0=";
AllowedIPs = [
"10.100.0.6/32"
"0.0.0.0/0"
];
};
t410 = {
PublicKey = "YSTgtHXcvbCwYrnBCNujsTkLy+umVZWLGECtV88NIW0=";
AllowedIPs = [
"10.100.0.7/32"
"0.0.0.0/0"
];
};
};
};
};
networks.wg0 = {
matchConfig.Name = "wg0";
address = [ "10.100.0.1/24" ];
networkConfig = {
IPMasquerade = "ipv4";
IPv4Forwarding = true;
IPv6Forwarding = true;
};
};
};
}