add qemu/libvirt/virt-manager packages and libvirtd service for Arch VM
This commit is contained in:
+20
-1
@@ -498,7 +498,7 @@
|
||||
users.users.harley = {
|
||||
isNormalUser = true;
|
||||
shell = lib.mkForce pkgs.zsh;
|
||||
extraGroups = [ "wheel" "networkmanager" "docker" "input" "uinput" "video"];
|
||||
extraGroups = [ "wheel" "networkmanager" "docker" "libvirtd" "input" "uinput" "video"];
|
||||
openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4OAJ8iC7CQIcedVbU86xgoL4YkMWAG9bU6aj9v4Skb harley@utumno" ];
|
||||
};
|
||||
|
||||
@@ -541,6 +541,14 @@
|
||||
mpv geeqie ffmpeg yt-dlp
|
||||
## Virtual display for Sunshine headless streaming (krfb-virtualmonitor)
|
||||
kdePackages.krfb
|
||||
|
||||
## Virtualization (Arch VM)
|
||||
qemu
|
||||
libvirt
|
||||
virt-manager
|
||||
OVMF
|
||||
spice-gtk
|
||||
swtpm
|
||||
];
|
||||
############################################################
|
||||
## ##
|
||||
@@ -736,6 +744,17 @@
|
||||
## uninput enable for Sunshine.
|
||||
hardware.uinput.enable = true;
|
||||
##
|
||||
## Libvirt/KVM virtualisation (Arch VM)
|
||||
virtualisation.libvirtd = {
|
||||
enable = true;
|
||||
qemu = {
|
||||
swtpm.enable = true;
|
||||
ovmf.enable = true;
|
||||
ovmf.packages = [ pkgs.OVMF ];
|
||||
runAsRoot = true;
|
||||
};
|
||||
};
|
||||
|
||||
##
|
||||
## 8.1: Docker
|
||||
##
|
||||
|
||||
@@ -0,0 +1,985 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
############################################################
|
||||
## Table of Contents ##
|
||||
## 1) Nix Configs/Flakes ##
|
||||
## 2) Boot Option ##
|
||||
## 3) Filesystems ##
|
||||
## 4) System Configuration ##
|
||||
## 5) Networking ##
|
||||
## |_5.1) Firewall ##
|
||||
## |_5.2) Wireguard ##
|
||||
## |_5.3) Pihole ##
|
||||
## |_5.4) Nginx ##
|
||||
## 6) Users and Sudo ##
|
||||
## 7) General Packages ##
|
||||
## 8) Services, Daemons, Scripts ##
|
||||
## |_8.1) Docker & Containers ##
|
||||
## |_8.2) Arrs suite ##
|
||||
## 9) Customizations & variables ##
|
||||
## |_9.1) Keyd keyboard settings ##
|
||||
## |_9.2) Enviroment Variables ##
|
||||
## ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
############################################################
|
||||
## ##
|
||||
## 1: Inital Nix configuration ##
|
||||
## ##
|
||||
############################################################
|
||||
imports = [ ./hardware-configuration.nix ];
|
||||
|
||||
## Flakes and nix-command
|
||||
nix.settings = {
|
||||
experimental-features = [ "nix-command" "flakes" ];
|
||||
trusted-users = [ "harley" ];
|
||||
};
|
||||
|
||||
## Allow unfree packages
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
## Overlay: stub broken python doc build (docutils bug in 26.11)
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
python312 = prev.python312.overrideAttrs (old: {
|
||||
passthru = old.passthru // { doc = null; };
|
||||
});
|
||||
})
|
||||
];
|
||||
|
||||
## Auto-upgrade
|
||||
system.autoUpgrade.enable = false;
|
||||
############################################################
|
||||
## ##
|
||||
## 2: Boot and Kernel ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
## btrfs support in the kernel and systemd boot stuff
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.initrd.supportedFilesystems = [ "btrfs"];
|
||||
|
||||
## SSH and remote LUKS unlocking in initramfs
|
||||
|
||||
boot.initrd.network.ssh.enable = true;
|
||||
boot.initrd.network.ssh.hostKeys = [ ./secrets/initrd/ssh_host_ed25519_key ];
|
||||
boot.initrd.network.ssh.authorizedKeys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4OAJ8iC7CQIcedVbU86xgoL4YkMWAG9bU6aj9v4Skb harley@utumno"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOnvzomqQoTWI7H2GpnqZO8tR7CwwwfUsylGu9IHWpAe u0_a392@localhost"
|
||||
];
|
||||
|
||||
## Initrd convenience: 'unlock' command
|
||||
boot.initrd.systemd.contents."/root/unlock".text = ''
|
||||
#!/bin/sh
|
||||
exec cryptsetup luksOpen /dev/disk/by-uuid/7d3b9cf3-0444-4cc9-80ba-e1401b783b6c nixroot
|
||||
'';
|
||||
boot.initrd.systemd.contents."/root/.profile".text = ''
|
||||
export PATH=$PATH:/root
|
||||
'';
|
||||
## DHCP for initrd network (systemd stage 1)
|
||||
boot.initrd.systemd.network.enable = true;
|
||||
boot.initrd.systemd.network.networks."10-eno1" = {
|
||||
matchConfig.Name = "eno1";
|
||||
networkConfig.DHCP = "ipv4";
|
||||
};
|
||||
|
||||
###########################################################
|
||||
## ##
|
||||
## 3: File systems ##
|
||||
## ##
|
||||
###########################################################
|
||||
|
||||
## Root, 512-GB, SSD-SATA, btrfs
|
||||
|
||||
fileSystems."/".options = [ "compress=zstd" "noatime" "space_cache=v2" ];
|
||||
|
||||
## 20TB Storage drive, HDD, btrfs
|
||||
|
||||
#fileSystems."/storage/20TB" = {
|
||||
# device = "/dev/disk/by-uuid/ec172aa7-85f7-4375-a661-88fc66221620";
|
||||
# fsType = "ext4";
|
||||
# };
|
||||
|
||||
## Post-boot unlock + mount 8TB LUKS data drive
|
||||
systemd.services.unlock-8tb = {
|
||||
description = "Unlock and mount 8TB storage";
|
||||
after = [ "local-fs.target" ];
|
||||
wants = [ "local-fs.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
serviceConfig.RemainAfterExit = true;
|
||||
script = ''
|
||||
/run/current-system/sw/bin/cryptsetup luksOpen \
|
||||
--key-file /root/keyfiles/8tb.key \
|
||||
/dev/disk/by-uuid/2bc4df99-677b-46d4-a1b8-38dd3c636a2b 8tb
|
||||
/run/current-system/sw/bin/mount /dev/mapper/8tb /storage/8TB
|
||||
/run/current-system/sw/bin/mount /storage/8TB/arrs-tmp/sabnzbd
|
||||
'';
|
||||
};
|
||||
## 1TB storage drive, SSD-NVME, btrfs
|
||||
#fileSystems."/storage/ssd/" = {
|
||||
#device = " ";
|
||||
#fstype = "btrfs";
|
||||
#};
|
||||
|
||||
## automated Snapper snapshots for the root filesystem
|
||||
services.snapper = {
|
||||
configs."root" = {
|
||||
SUBVOLUME = "/";
|
||||
ALLOW_USERS = [ "harley" ];
|
||||
TIMELINE_CREATE = true;
|
||||
TIMELINE_CLEANUP = true;
|
||||
TIMELINE_MIN_AGE = "1800";
|
||||
TIMELINE_LIMIT_HOURLY = "6";
|
||||
TIMELINE_LIMIT_DAILY = "7";
|
||||
TIMELINE_LIMIT_WEEKLY = "4";
|
||||
TIMELINE_LIMIT_MONTHLY = "6";
|
||||
TIMELINE_LIMIT_YEARLY = "0";
|
||||
NUMBER_CLEANUP = true;
|
||||
NUMBER_LIMIT = "50";
|
||||
};
|
||||
};
|
||||
|
||||
## snapper for recov
|
||||
services.snapper.configs."file7" = {
|
||||
SUBVOLUME = "/mnt/.recov";
|
||||
ALLOW_USERS = [ "harley" ];
|
||||
TIMELINE_CREATE = false;
|
||||
NUMBER_CLEANUP = false;
|
||||
};
|
||||
############################################################
|
||||
## ##
|
||||
## 4: System Configuration ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
## Time/Locale
|
||||
time.timeZone = "America/New_York";
|
||||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
|
||||
## Nvidia GPU
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
hardware.graphics.enable = true;
|
||||
hardware.nvidia = {
|
||||
modesetting.enable = true;
|
||||
powerManagement.enable = true;
|
||||
open = false;
|
||||
nvidiaSettings = true;
|
||||
};
|
||||
|
||||
## Greeter user for greetd login on tty6 LOOK INTO THIS, IDK WHAT IT IS
|
||||
users.users.greeter = {
|
||||
isSystemUser = true;
|
||||
group = "nogroup";
|
||||
extraGroups = [ "video" "input" "seat" ];
|
||||
description = "greetd login greeter";
|
||||
};
|
||||
|
||||
## greetd PAM service
|
||||
security.pam.services.greetd = {};
|
||||
|
||||
## Display Manager (SDDM) and Plasma 6
|
||||
services.xserver.enable = true;
|
||||
services.xserver.displayManager.sddm.enable = true;
|
||||
services.desktopManager.plasma6.enable = true;
|
||||
programs.kdeconnect.enable = true;
|
||||
|
||||
## Pipewire
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
pulse.enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = true;
|
||||
};
|
||||
|
||||
|
||||
# Xpadneo for xbox controller bluetooth
|
||||
hardware.xpadneo.enable = true;
|
||||
|
||||
|
||||
|
||||
############################################################
|
||||
## ##
|
||||
## 5) Networking ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
networking.hostName = "utumno";
|
||||
networking.networkmanager.enable = true;
|
||||
# Don't block boot waiting for all network profiles to come online
|
||||
systemd.services.NetworkManager-wait-online.enable = lib.mkForce false;
|
||||
|
||||
hardware.bluetooth = {
|
||||
enable = true;
|
||||
powerOnBoot = true;
|
||||
settings.General.Experimental = true;
|
||||
};
|
||||
|
||||
|
||||
##
|
||||
##
|
||||
## 5.1 Firewall
|
||||
##
|
||||
##
|
||||
networking.firewall = {
|
||||
|
||||
## UDP ports and ranges
|
||||
allowedUDPPorts = [ 51820 51812 5113 ];
|
||||
allowedUDPPortRanges = [
|
||||
{ from = 47884; to = 48010; }
|
||||
];
|
||||
|
||||
## TCP ports and ranges
|
||||
allowedTCPPorts = [ 22 3010 222 8084 443 80 8787 8180 7777 3180 47989 47990 47991 47992 48010 5113 8777 ];
|
||||
# Enable IP forwarding (needed for Wireguard routing)
|
||||
enable = true;
|
||||
};
|
||||
|
||||
## Enable Ip forwarding at the kernel level
|
||||
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
|
||||
|
||||
## SSHD
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PasswordAuthentication = false;
|
||||
PermitRootLogin = "prohibit-password";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
##
|
||||
##
|
||||
## 5.2: Wireguard
|
||||
##
|
||||
##
|
||||
networking.wireguard.interfaces = {
|
||||
wg0 = {
|
||||
ips = [ "10.10.10.1/24" ];
|
||||
listenPort = 51820;
|
||||
privateKeyFile = "/etc/nixos/secrets/wireguard/wg0-key.key";
|
||||
|
||||
# IP forwarding + NAT for wg0 clients to internet/LAN
|
||||
postSetup = ''
|
||||
${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT
|
||||
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -o eno1 -j MASQUERADE
|
||||
'';
|
||||
postShutdown = ''
|
||||
${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT
|
||||
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -o eno1 -j MASQUERADE
|
||||
'';
|
||||
|
||||
peers = [
|
||||
# Exos — routes remote subnets
|
||||
{
|
||||
publicKey = "8rO4j18cPAw6zv8b26PNXFHpEwxqjBq1r8yRmWNOMXY=";
|
||||
endpoint = "briggs.wiki:51820";
|
||||
allowedIPs = [
|
||||
"10.10.10.2/32"
|
||||
"10.0.0.0/24"
|
||||
"192.168.3.0/24"
|
||||
];
|
||||
}
|
||||
# Maroon / Roman Phone
|
||||
{
|
||||
publicKey = "Sih2qcJtmhdlSwxlaRont7ezwazo0FMyMxTjhWBtpjA=";
|
||||
allowedIPs = [ "192.168.3.1/32" ];
|
||||
}
|
||||
# Palantir (Phone)
|
||||
{
|
||||
publicKey = "RUPXirLLTY1KeFIjfwKQtVg3ckj8sLz2QN/AiLZOmFw=";
|
||||
allowedIPs = [ "192.168.2.1/32" ];
|
||||
}
|
||||
# Menegroth
|
||||
{
|
||||
publicKey = "DWhEqMQ7/RHkEuPtMrpuhQqnls7o/B6idSJxXJJy6ys=";
|
||||
allowedIPs = [ "192.168.2.2/32" ];
|
||||
}
|
||||
# iPad
|
||||
{
|
||||
publicKey = "lqTK2qoaNJ+Md8RZT3TVxN+fAHllTwIG2znZKI3Rt2c=";
|
||||
allowedIPs = [ "192.168.2.3/32" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
##
|
||||
##
|
||||
## 5.3) Pi-hole DNS
|
||||
##
|
||||
##
|
||||
services.pihole-ftl = {
|
||||
enable = true;
|
||||
openFirewallDNS = true;
|
||||
## Upstream DNS servers (Cloudflare and Quad9)
|
||||
settings = {
|
||||
dns = {
|
||||
upstreams = [
|
||||
"1.1.1.1#53"
|
||||
"1.0.0.1#53"
|
||||
"9.9.9.9#53"
|
||||
];
|
||||
## Listen on all interfaces
|
||||
listeningMode = "ALL";
|
||||
## Block ESNI, ICloud Private Relay, Firefox canary, etc.
|
||||
blocking.active = true;
|
||||
blocking.mode = "NULL";
|
||||
## Rate limiting
|
||||
rateLimit.count = 1000;
|
||||
rateLimit.interval = 60;
|
||||
## Cache
|
||||
cache.size = 10000;
|
||||
cache.optimizer = 3600;
|
||||
## DNSSEC
|
||||
dnssec = false;
|
||||
bogusPriv = true;
|
||||
domainNeeded = false;
|
||||
## Local DNS records
|
||||
hosts = [
|
||||
"10.0.1.49 jellyfin.wingard.pro"
|
||||
"10.0.1.49 speedtest.wingard.pro"
|
||||
];
|
||||
};
|
||||
## Web server on 8999, admin page at /admin/
|
||||
webserver = {
|
||||
port = lib.mkForce "8999";
|
||||
interface.boxed = "true";
|
||||
interface.theme = "default-dark";
|
||||
};
|
||||
## Privacy level 0 = full stats
|
||||
misc.privacylevel = 0;
|
||||
};
|
||||
## Blocklist: Steven Black's unified hosts
|
||||
lists = [
|
||||
{
|
||||
url = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts";
|
||||
description = "Steven Black's unified adlist";
|
||||
}
|
||||
];
|
||||
};
|
||||
## Pi-hole web admin dashboard
|
||||
services.pihole-web.enable = true;
|
||||
##
|
||||
##
|
||||
## 5.4: Nginx
|
||||
##
|
||||
##
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedProxySettings = true;
|
||||
virtualHosts = {
|
||||
"jellyfin.wingard.pro" = {
|
||||
enableACME = false;
|
||||
addSSL = true;
|
||||
sslCertificate = "/etc/letsencrypt/live/jellyfin.wingard.pro/fullchain.pem";
|
||||
sslCertificateKey = "/etc/letsencrypt/live/jellyfin.wingard.pro/privkey.pem";
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:8096";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
"speedtest.wingard.pro" = {
|
||||
enableACME = false;
|
||||
addSSL = true;
|
||||
sslCertificate = "/etc/letsencrypt/live/speedtest.wingard.pro/fullchain.pem";
|
||||
sslCertificateKey = "/etc/letsencrypt/live/speedtest.wingard.pro/privkey.pem";
|
||||
root = "/opt/openspeedtest";
|
||||
locations."/" = {
|
||||
index = "index.html";
|
||||
tryFiles = "$uri $uri/ /index.html";
|
||||
};
|
||||
locations."~ \\.php$" = {
|
||||
extraConfig = ''
|
||||
fastcgi_pass unix:/run/phpfpm-openspeedtest.sock;
|
||||
fastcgi_index index.php;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_param SCRIPT_FILENAME /opt/openspeedtest$fastcgi_script_name;
|
||||
'';
|
||||
};
|
||||
};
|
||||
"speedtest-http" = {
|
||||
listen = [ { addr = "0.0.0.0"; port = 8084; } ];
|
||||
root = "/opt/openspeedtest";
|
||||
locations."/" = {
|
||||
index = "index.html";
|
||||
tryFiles = "$uri $uri/ /index.html";
|
||||
};
|
||||
locations."~ \\.php$" = {
|
||||
extraConfig = ''
|
||||
fastcgi_pass unix:/run/phpfpm-openspeedtest.sock;
|
||||
fastcgi_index index.php;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_param SCRIPT_FILENAME /opt/openspeedtest$fastcgi_script_name;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
############################################################
|
||||
## ##
|
||||
## 6: Users ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
## setting up sudo wheel group
|
||||
security.sudo.extraRules = [
|
||||
{ groups = [ "wheel" ]; commands = [ { command = "ALL"; options = [ "NOPASSWD" ]; } ]; }
|
||||
];
|
||||
|
||||
## Harley
|
||||
users.users.harley = {
|
||||
isNormalUser = true;
|
||||
shell = lib.mkForce pkgs.zsh;
|
||||
extraGroups = [ "wheel" "networkmanager" "docker" "input" "uinput" "video"];
|
||||
openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4OAJ8iC7CQIcedVbU86xgoL4YkMWAG9bU6aj9v4Skb harley@utumno" ];
|
||||
};
|
||||
|
||||
## Roman
|
||||
users.users.roman = {
|
||||
isNormalUser = true;
|
||||
description = "Roman";
|
||||
home = "/home/roman/";
|
||||
createHome = true;
|
||||
shell = pkgs.bash;
|
||||
extraGroups = [ "wheel" "users" ];
|
||||
openssh.authorizedKeys.keys = [ " " ];
|
||||
};
|
||||
## The Ephemeral user and filesystem
|
||||
|
||||
## The actual Ephemeral user
|
||||
users.users.atomic = {
|
||||
isNormalUser = true;
|
||||
description = "Ephemeral User - home directory inside a tmpfs";
|
||||
home = "/home/atomic";
|
||||
group = "users";
|
||||
createHome = false;
|
||||
extraGroups = [ "wheel" ];
|
||||
shell = lib.mkForce pkgs.zsh;
|
||||
openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4OAJ8iC7CQIcedVbU86xgoL4YkMWAG9bU6aj9v4Skb harley@utumno" ];
|
||||
};
|
||||
|
||||
## filesystem for the Ephemeral user
|
||||
fileSystems."/home/atomic" = {
|
||||
device = "tmpfs";
|
||||
fsType = "tmpfs";
|
||||
options = [ "mode=0700" "uid=1001" "gid=100" "noatime" ];
|
||||
};
|
||||
|
||||
## Populate the Ephemeral user from seed on boot
|
||||
systemd.services.populate-atomic-home = {
|
||||
description = " Populate atomic user's tmpfs home from seed";
|
||||
after = [ "home-atomic.mount" ];
|
||||
requires = [ "home-atomic.mount" ];
|
||||
wantedBy = [ "home-atomic.mount" "systemd-logind.service" ];
|
||||
script = ''
|
||||
cp -rT /home/.atomic-persist /home/atomic
|
||||
chown -R 1001:100 /home/atomic
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
serviceConfig.RemainAfterExit = true;
|
||||
};
|
||||
|
||||
## Periodic Ephemeral home cleaner (reseed from skeleton)
|
||||
systemd.services.atomic-home-cleaner = {
|
||||
description = "Wipe atomic home if user has no active logind sessions";
|
||||
script = ''
|
||||
if ! pgrep -u atomic >/dev/null 2>&1; then
|
||||
umount /home/atomic/mnt 2>/dev/null || true
|
||||
rm -rf /home/atomic/.??* /home/atomic/** 2>/dev/null
|
||||
cp -rT /home/.atomic-persist/ /home/atomic/
|
||||
chown -R 1001:100 /home/atomic/
|
||||
fi
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
};
|
||||
|
||||
systemd.timers.atomic-home-cleaner = {
|
||||
description = "Check every 2 min if atomic user's sessions ended";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnBootSec = "1min";
|
||||
OnUnitActiveSec = "30s";
|
||||
};
|
||||
};
|
||||
|
||||
## One-shot service to unmount and re-populate atomic's tmpfs home
|
||||
systemd.services.atomic-fresh = {
|
||||
description = "Wipe and re-populate atomic's tmpfs home";
|
||||
after = [ "home-atomic.mount" ];
|
||||
script = ''
|
||||
loginctl terminate-user atomic 2>/dev/null || true
|
||||
sleep 1
|
||||
rm -rf /home/atomic/.??* /home/atomic/** 2>/dev/null || true
|
||||
umount /home/atomic 2>/dev/null || true
|
||||
mount /home/atomic
|
||||
cp -rT /home/.atomic-persist/ /home/atomic/
|
||||
chown -R 1001:100 /home/atomic/
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
path = [ pkgs.util-linux ];
|
||||
serviceConfig.User = "root";
|
||||
};
|
||||
############################################################
|
||||
## ##
|
||||
## 7: General Packages ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
|
||||
## Cli tools
|
||||
vim wget curl progress git btop neovim tmux lsof bat ncdu nvtopPackages.full fastfetch
|
||||
unzip unrar p7zip xclip
|
||||
testdisk btdu
|
||||
|
||||
## Games
|
||||
lutris rpcs3 mednafen mednafen-server mednaffe dolphin-emu
|
||||
|
||||
## System
|
||||
adwaita-icon-theme tela-circle-icon-theme
|
||||
sshfs sshpass pciutils usbutils python312 (pkgs.kdePackages.bluedevil) gtkgreet
|
||||
cage guake android-tools patool pv ghostscript imagemagick nodejs go deno socat
|
||||
fzf smartmontools shadow ripgrep fd jq tree qdirstat uv
|
||||
|
||||
firefox
|
||||
obsidian
|
||||
|
||||
## Multimedia
|
||||
mpv geeqie ffmpeg yt-dlp
|
||||
## Virtual display for Sunshine headless streaming (krfb-virtualmonitor)
|
||||
kdePackages.krfb
|
||||
];
|
||||
############################################################
|
||||
## ##
|
||||
## 8) Services ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
## Hermes WebUI (port 8787)
|
||||
#systemd.services.hermes-webui = {
|
||||
# description = "Hermes Web UI";
|
||||
# after = [ "network-online.target" ];
|
||||
# wants = [ "network-online.target" ];
|
||||
# wantedBy = [ "multi-user.target" ];
|
||||
# environment = {
|
||||
# HERMES_WEBUI_HOST = "0.0.0.0";
|
||||
# HERMES_WEBUI_PORT = "8787";
|
||||
# HERMES_HOME = "/storage/8TB/Backups/Agents/.hermes";
|
||||
# HERMES_WEBUI_STATE_DIR = "/storage/8TB/Backups/Agents/.hermes/webui";
|
||||
# SEARXNG_URL = "http://10.0.1.49:8888";
|
||||
# };
|
||||
# serviceConfig = {
|
||||
# Type = "simple";
|
||||
# User = "harley";
|
||||
# WorkingDirectory = "/opt/hermes-webui";
|
||||
# ExecStart = "/opt/hermes-webui/venv/bin/python server.py";
|
||||
# Restart = "on-failure";
|
||||
# RestartSec = 5;
|
||||
# };
|
||||
# };
|
||||
## SearXNG meta search engine (Port 8888)
|
||||
services.searx = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
redisCreateLocally = true;
|
||||
settings = {
|
||||
general.instance_name = "Utumno Search";
|
||||
search = {
|
||||
safe_search = 0;
|
||||
formats = [ "html" "json" ];
|
||||
autocomplete = "";
|
||||
};
|
||||
server = {
|
||||
port = 8888;
|
||||
bind_address = "0.0.0.0";
|
||||
secret_key = "@SEARXNG_SECRET@";
|
||||
limiter = false;
|
||||
method = "POST";
|
||||
image_proxy = false;
|
||||
};
|
||||
ui = {
|
||||
default_theme = "simple";
|
||||
theme_args.simple_style = "dark";
|
||||
query_in_title = false;
|
||||
};
|
||||
outgoing = {
|
||||
request_timeout = 5.0;
|
||||
max_request_timeout = 15.0;
|
||||
pool_connections = 100;
|
||||
pool_maxsize = 20;
|
||||
enable_http2 = true;
|
||||
};
|
||||
};
|
||||
environmentFile = "/opt/searxng/secrets.env";
|
||||
};
|
||||
|
||||
## Gitea (Port 3010)
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
stateDir = "/storage/8TB/Backups/Gitea";
|
||||
repositoryRoot = "/storage/8TB/Backups/Gitea/repositories";
|
||||
database.type = "sqlite3";
|
||||
settings = {
|
||||
server = {
|
||||
DOMAIN = "10.0.1.49";
|
||||
ROOT_URL = "http://10.0.1.49:3010";
|
||||
HTTP_PORT = 3010;
|
||||
SSH_PORT = 222;
|
||||
DISABLE_SSH = false;
|
||||
LFS_START_SERVER = false;
|
||||
};
|
||||
service = {
|
||||
DISABLE_REGISTRATION = false;
|
||||
REQUIRE_SIGNIN_VIEW = false;
|
||||
};
|
||||
security.INSTALL_LOCK = true;
|
||||
};
|
||||
};
|
||||
|
||||
## Kiwix ZIM server (port 8098)
|
||||
services.kiwix-serve = {
|
||||
enable = true;
|
||||
port = 8098;
|
||||
openFirewall = true;
|
||||
library = {
|
||||
# Update paths when ZIM files are added/removed
|
||||
wikipedia = "/storage/20TB/Media/Kiwix/wikipedia_en_all_maxi_2026-02.zim";
|
||||
archlinux = "/storage/20TB/Media/Kiwix/archlinux_en_all_maxi_2025-08.zim";
|
||||
ifixit = "/storage/20TB/Media/Kiwix/ifixit_en_all_2025-06.zim";
|
||||
khanacademy = "/storage/20TB/Media/Kiwix/khanacademy_en_all_2023-03.zim";
|
||||
survivorlibrary = "/storage/20TB/Media/Kiwix/survivorlibrary.com_en_all_2025-06.zim";
|
||||
urbanprepper = "/storage/20TB/Media/Kiwix/urban-prepper_en_all_2025-06.zim";
|
||||
anonymousplanet = "/storage/20TB/Media/Kiwix/anonymousplanet.org_en_all_2025-08.zim";
|
||||
basedcooking = "/storage/20TB/Media/Kiwix/based.cooking_en_all_2025-08.zim";
|
||||
};
|
||||
extraArgs = [ "--skipInvalid" ];
|
||||
};
|
||||
|
||||
## OpenSpeedTest (Port 8084)
|
||||
services.phpfpm.pools.openspeedtest = {
|
||||
user = "nginx";
|
||||
group = "nginx";
|
||||
settings = {
|
||||
pm = "dynamic";
|
||||
"pm.max_children" = 5;
|
||||
"pm.start_servers" = 2;
|
||||
"pm.min_spare_servers" = 1;
|
||||
"pm.max_spare_servers" = 3;
|
||||
"listen" = "/run/phpfpm-openspeedtest.sock";
|
||||
};
|
||||
};
|
||||
|
||||
## Immich (Port 2283)
|
||||
#services.immich = {
|
||||
#enable = true;
|
||||
#host = "10.10.10.1";
|
||||
#mediaLocation = "/storage/8TB/Documents/immich";
|
||||
#port = 2283;
|
||||
#openFirewall = true;
|
||||
#database.enable = true;
|
||||
#redis.enable = true;
|
||||
#};
|
||||
|
||||
## Roku Remote (Port 7777)
|
||||
## btop-web system monitor (Port 8777)
|
||||
systemd.services.btop-web = {
|
||||
description = "btop-style web system monitor";
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = "harley";
|
||||
WorkingDirectory = "/opt/btop-web";
|
||||
ExecStart = "${pkgs.python3}/bin/python server.py";
|
||||
Restart = "always";
|
||||
RestartSec = 5;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.roku-remote = {
|
||||
description = "Roku TV Web Remote";
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = "harley";
|
||||
WorkingDirectory = "/opt/roku-remote";
|
||||
ExecStart = "${pkgs.python3}/bin/python server.py";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 5;
|
||||
};
|
||||
};
|
||||
|
||||
##Sunshine
|
||||
services.sunshine = {
|
||||
enable = true;
|
||||
autoStart = true;
|
||||
capSysAdmin = true; # only needed for Wayland -- omit this when using with Xorg
|
||||
openFirewall = true;
|
||||
};
|
||||
## uninput enable for Sunshine.
|
||||
hardware.uinput.enable = true;
|
||||
##
|
||||
##
|
||||
## 8.1: Docker
|
||||
##
|
||||
##
|
||||
virtualisation.docker = {
|
||||
enable = true;
|
||||
# Allow non-root users (harley is in docker group)
|
||||
enableOnBoot = true;
|
||||
# Use the overlay2 storage driver (default on modern kernels)
|
||||
storageDriver = "overlay2";
|
||||
# Auto-prune unused data
|
||||
autoPrune.enable = true;
|
||||
autoPrune.dates = "weekly";
|
||||
};
|
||||
## Firecrawl web-scraper (Port 3002)
|
||||
systemd.services.firecrawl = {
|
||||
description = "Firecrawl web scraping stack";
|
||||
after = [ "docker.service" "network-online.target" ];
|
||||
wants = [ "docker.service" "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.docker ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
WorkingDirectory = "/opt/firecrawl";
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose up -d";
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose down";
|
||||
};
|
||||
};
|
||||
|
||||
########## ##########
|
||||
########## ##########
|
||||
########## 8.2: ARRS ##########
|
||||
########## ##########
|
||||
########## ##########
|
||||
|
||||
## PIA VPN + qBittorrent (Port 8088) + SOCKS5 (Port 1080) (Docker compose)
|
||||
systemd.services.pia-qbit = {
|
||||
description = "PIA VPN + qBittorrent + SOCKS5 proxy stack";
|
||||
after = [ "docker.service" "network-online.target" ];
|
||||
wants = [ "docker.service" "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.docker ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
WorkingDirectory = "/opt/pia-qbit";
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose up -d";
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose down";
|
||||
# Give VPN time to establish before declaring "done"
|
||||
ExecStartPost = "${pkgs.coreutils}/bin/sleep 10";
|
||||
};
|
||||
};
|
||||
|
||||
## Bitmagnet (Port 3333)
|
||||
#services.bitmagnet = {
|
||||
# enable = true;
|
||||
#openFirewall = true;
|
||||
#settings = {
|
||||
#http_server.local_address = ":3333";
|
||||
#dht_server.port = 3334;
|
||||
#postgres = {
|
||||
#name = "bitmagnet";
|
||||
#user = "bitmagnet";
|
||||
#password = "";
|
||||
#};
|
||||
#};
|
||||
#};
|
||||
|
||||
#services.postgresql = {
|
||||
#dataDir = "/storage/20TB/Computer-Related/Bitmagnet-data";
|
||||
#package = pkgs.postgresql_16;
|
||||
#};
|
||||
|
||||
## Jellyfin (Port 8096)
|
||||
services.jellyfin = {
|
||||
enable = true;
|
||||
dataDir = "/storage/8TB/arrs-tmp/jellyfin";
|
||||
cacheDir = "/storage/8TB/arrs-tmp/jellyfin-cache";
|
||||
openFirewall = true;
|
||||
};
|
||||
## Prowlarr (port 9696)
|
||||
services.prowlarr = {
|
||||
enable = true;
|
||||
dataDir = "/storage/8TB/arrs-tmp/prowlarr";
|
||||
openFirewall = true;
|
||||
};
|
||||
## Sonarr (port 8989)
|
||||
services.sonarr = {
|
||||
enable = true;
|
||||
dataDir = "/storage/8TB/arrs-tmp/sonarr";
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
## Radarr (port 7878)
|
||||
services.radarr = {
|
||||
enable = true;
|
||||
dataDir = "/storage/8TB/arrs-tmp/radarr";
|
||||
openFirewall = true;
|
||||
};
|
||||
## SABnzbd (port 8180)
|
||||
fileSystems."/var/lib/sabnzbd" = {
|
||||
device = "/storage/8TB/arrs-tmp/sabnzbd";
|
||||
options = [ "bind" "noauto" ];
|
||||
fsType = "none";
|
||||
};
|
||||
|
||||
services.sabnzbd = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
settings = {
|
||||
host = "0.0.0.0";
|
||||
port = 8180;
|
||||
misc = {
|
||||
host = "0.0.0.0";
|
||||
port = 8180;
|
||||
enable_https = false;
|
||||
html_login = true;
|
||||
inet_exposure = 0;
|
||||
auto_browser = false;
|
||||
config_lock = false;
|
||||
check_new_rel = false;
|
||||
cache_limit = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
############################################################
|
||||
## ##
|
||||
## 9: Customization ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
##
|
||||
##
|
||||
## 9.1: Keyd keyboard remappings
|
||||
##
|
||||
##
|
||||
services.keyd = {
|
||||
enable = true;
|
||||
keyboards = {
|
||||
default = {
|
||||
ids = [ "*" ];
|
||||
settings = {
|
||||
main = {
|
||||
esc = "capslock";
|
||||
capslock = "overload(nav, esc)";
|
||||
};
|
||||
nav = {
|
||||
w = "up";
|
||||
a = "left";
|
||||
s = "down";
|
||||
d = "right";
|
||||
b = "C-left";
|
||||
u = "pageup";
|
||||
x = "delete";
|
||||
g = "home";
|
||||
n = "end";
|
||||
h = "left";
|
||||
j = "down";
|
||||
k = "up";
|
||||
l = "right";
|
||||
space = "capslock";
|
||||
};
|
||||
};
|
||||
};
|
||||
q = {
|
||||
ids = [ "*" ];
|
||||
settings = {
|
||||
main = {
|
||||
esc = "capslock";
|
||||
capslock = "overload(nav, esc)";
|
||||
};
|
||||
nav = {
|
||||
w = "up";
|
||||
a = "left";
|
||||
s = "down";
|
||||
d = "right";
|
||||
h = "left";
|
||||
j = "down";
|
||||
k = "up";
|
||||
l = "right";
|
||||
space = "capslock";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
##
|
||||
##
|
||||
## 9.2 Enviroment Variables
|
||||
##
|
||||
##
|
||||
environment.variables = {
|
||||
GTK_THEME = "Adwaita:dark";
|
||||
GTK_ICON_THEME = "Tela-circle-dark";
|
||||
HERMES_HOME = "/storage/8TB/Backups/Agents/.hermes";
|
||||
};
|
||||
|
||||
## ZSH with Oh-My-Zsh
|
||||
programs.zsh.enable = true;
|
||||
programs.zsh.ohMyZsh = {
|
||||
enable = true;
|
||||
theme = "jonathan";
|
||||
plugins = [
|
||||
"git"
|
||||
"sudo"
|
||||
"web-search"
|
||||
"history"
|
||||
"extract"
|
||||
"colored-man-pages"
|
||||
];
|
||||
customPkgs = [
|
||||
(pkgs.runCommand "jonathan-zsh-theme" {
|
||||
themeFile = builtins.readFile ./jonathan.zsh-theme;
|
||||
passAsFile = [ "themeFile" ];
|
||||
} ''
|
||||
mkdir -p $out/share/zsh/themes
|
||||
cp "$themeFilePath" $out/share/zsh/themes/jonathan.zsh-theme
|
||||
'')
|
||||
];
|
||||
};
|
||||
|
||||
programs.zsh.syntaxHighlighting.enable = true;
|
||||
|
||||
programs.zsh.interactiveShellInit = ''
|
||||
source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh
|
||||
'';
|
||||
programs.zsh.promptInit = ''
|
||||
bindkey '^F' autosuggest-accept
|
||||
bindkey '^[[C' autosuggest-accept
|
||||
'';
|
||||
|
||||
programs.zsh.shellAliases = {
|
||||
cl = "clear";
|
||||
tt = "tmux";
|
||||
tta = "tmux attach";
|
||||
ttls = "tmux ls";
|
||||
xclipp = "xclip -selection clipboard";
|
||||
palantir = "ssh palantir";
|
||||
rcp = "rsync -avP --partial --append";
|
||||
};
|
||||
# Make theme packages available to all users
|
||||
environment.sessionVariables = {
|
||||
XDG_DATA_DIRS = [
|
||||
"${pkgs.tela-circle-icon-theme}/share/icons"
|
||||
"${pkgs.catppuccin}/share/plasma"
|
||||
];
|
||||
};
|
||||
############################################################
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
############################################################
|
||||
## ── State version ────────────────────────────────────────
|
||||
system.stateVersion = "26.11";
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,977 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
############################################################
|
||||
## Table of Contents ##
|
||||
## 1) Nix Configs/Flakes ##
|
||||
## 2) Boot Option ##
|
||||
## 3) Filesystems ##
|
||||
## 4) System Configuration ##
|
||||
## 5) Networking ##
|
||||
## |_5.1) Firewall ##
|
||||
## |_5.2) Wireguard ##
|
||||
## |_5.3) Pihole ##
|
||||
## |_5.4) Nginx ##
|
||||
## 6) Users and Sudo ##
|
||||
## 7) General Packages ##
|
||||
## 8) Services, Daemons, Scripts ##
|
||||
## |_8.1) Docker & Containers ##
|
||||
## |_8.2) Arrs suite ##
|
||||
## 9) Customizations & variables ##
|
||||
## |_9.1) Keyd keyboard settings ##
|
||||
## |_9.2) Enviroment Variables ##
|
||||
## ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
############################################################
|
||||
## ##
|
||||
## 1: Inital Nix configuration ##
|
||||
## ##
|
||||
############################################################
|
||||
imports = [ ./hardware-configuration.nix ];
|
||||
|
||||
## Flakes and nix-command
|
||||
nix.settings = {
|
||||
experimental-features = [ "nix-command" "flakes" ];
|
||||
trusted-users = [ "harley" ];
|
||||
};
|
||||
|
||||
## Allow unfree packages
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
## Overlay: stub broken python doc build (docutils bug in 26.11)
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
python312 = prev.python312.overrideAttrs (old: {
|
||||
passthru = old.passthru // { doc = null; };
|
||||
});
|
||||
})
|
||||
];
|
||||
|
||||
## Auto-upgrade
|
||||
system.autoUpgrade.enable = false;
|
||||
############################################################
|
||||
## ##
|
||||
## 2: Boot and Kernel ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
## btrfs support in the kernel and systemd boot stuff
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.initrd.supportedFilesystems = [ "btrfs"];
|
||||
|
||||
## SSH and remote LUKS unlocking in initramfs
|
||||
|
||||
boot.initrd.network.ssh.enable = true;
|
||||
boot.initrd.network.ssh.hostKeys = [ ./secrets/initrd/ssh_host_ed25519_key ];
|
||||
boot.initrd.network.ssh.authorizedKeys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4OAJ8iC7CQIcedVbU86xgoL4YkMWAG9bU6aj9v4Skb harley@utumno"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOnvzomqQoTWI7H2GpnqZO8tR7CwwwfUsylGu9IHWpAe u0_a392@localhost"
|
||||
];
|
||||
|
||||
## Initrd convenience: 'unlock' command
|
||||
boot.initrd.systemd.contents."/root/unlock".text = ''
|
||||
#!/bin/sh
|
||||
exec cryptsetup luksOpen /dev/disk/by-uuid/7d3b9cf3-0444-4cc9-80ba-e1401b783b6c nixroot
|
||||
'';
|
||||
boot.initrd.systemd.contents."/root/.profile".text = ''
|
||||
export PATH=$PATH:/root
|
||||
'';
|
||||
## DHCP for initrd network (systemd stage 1)
|
||||
boot.initrd.systemd.network.enable = true;
|
||||
boot.initrd.systemd.network.networks."10-eno1" = {
|
||||
matchConfig.Name = "eno1";
|
||||
networkConfig.DHCP = "ipv4";
|
||||
};
|
||||
|
||||
###########################################################
|
||||
## ##
|
||||
## 3: File systems ##
|
||||
## ##
|
||||
###########################################################
|
||||
|
||||
## Root, 512-GB, SSD-SATA, btrfs
|
||||
|
||||
fileSystems."/".options = [ "compress=zstd" "noatime" "space_cache=v2" ];
|
||||
|
||||
## 20TB Storage drive, HDD, btrfs
|
||||
|
||||
#fileSystems."/storage/20TB" = {
|
||||
# device = "/dev/disk/by-uuid/ec172aa7-85f7-4375-a661-88fc66221620";
|
||||
# fsType = "ext4";
|
||||
# };
|
||||
|
||||
## Post-boot unlock + mount 8TB LUKS data drive
|
||||
systemd.services.unlock-8tb = {
|
||||
description = "Unlock and mount 8TB storage";
|
||||
after = [ "local-fs.target" ];
|
||||
wants = [ "local-fs.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
serviceConfig.RemainAfterExit = true;
|
||||
script = ''
|
||||
/run/current-system/sw/bin/cryptsetup luksOpen \
|
||||
--key-file /root/keyfiles/8tb.key \
|
||||
/dev/disk/by-uuid/2bc4df99-677b-46d4-a1b8-38dd3c636a2b 8tb
|
||||
/run/current-system/sw/bin/mount /dev/mapper/8tb /storage/8TB
|
||||
/run/current-system/sw/bin/mount /storage/8TB/arrs-tmp/sabnzbd
|
||||
'';
|
||||
};
|
||||
## 1TB storage drive, SSD-NVME, btrfs
|
||||
#fileSystems."/storage/ssd/" = {
|
||||
#device = " ";
|
||||
#fstype = "btrfs";
|
||||
#};
|
||||
|
||||
## automated Snapper snapshots for the root filesystem
|
||||
services.snapper = {
|
||||
configs."root" = {
|
||||
SUBVOLUME = "/";
|
||||
ALLOW_USERS = [ "harley" ];
|
||||
TIMELINE_CREATE = true;
|
||||
TIMELINE_CLEANUP = true;
|
||||
TIMELINE_MIN_AGE = "1800";
|
||||
TIMELINE_LIMIT_HOURLY = "6";
|
||||
TIMELINE_LIMIT_DAILY = "7";
|
||||
TIMELINE_LIMIT_WEEKLY = "4";
|
||||
TIMELINE_LIMIT_MONTHLY = "6";
|
||||
TIMELINE_LIMIT_YEARLY = "0";
|
||||
NUMBER_CLEANUP = true;
|
||||
NUMBER_LIMIT = "50";
|
||||
};
|
||||
};
|
||||
|
||||
## snapper for recov
|
||||
services.snapper.configs."file7" = {
|
||||
SUBVOLUME = "/mnt/.recov";
|
||||
ALLOW_USERS = [ "harley" ];
|
||||
TIMELINE_CREATE = false;
|
||||
NUMBER_CLEANUP = false;
|
||||
};
|
||||
############################################################
|
||||
## ##
|
||||
## 4: System Configuration ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
## Time/Locale
|
||||
time.timeZone = "America/New_York";
|
||||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
|
||||
## Nvidia GPU
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
hardware.graphics.enable = true;
|
||||
hardware.nvidia = {
|
||||
modesetting.enable = true;
|
||||
powerManagement.enable = true;
|
||||
open = false;
|
||||
nvidiaSettings = true;
|
||||
};
|
||||
|
||||
## Greeter user for greetd login on tty6 LOOK INTO THIS, IDK WHAT IT IS
|
||||
users.users.greeter = {
|
||||
isSystemUser = true;
|
||||
group = "nogroup";
|
||||
extraGroups = [ "video" "input" "seat" ];
|
||||
description = "greetd login greeter";
|
||||
};
|
||||
|
||||
## greetd PAM service
|
||||
security.pam.services.greetd = {};
|
||||
|
||||
## Display Manager (SDDM) and Plasma 6
|
||||
services.xserver.enable = true;
|
||||
services.xserver.displayManager.sddm.enable = true;
|
||||
services.desktopManager.plasma6.enable = true;
|
||||
programs.kdeconnect.enable = true;
|
||||
|
||||
## Pipewire
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
pulse.enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = true;
|
||||
};
|
||||
############################################################
|
||||
## ##
|
||||
## 5) Networking ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
networking.hostName = "utumno";
|
||||
networking.networkmanager.enable = true;
|
||||
# Don't block boot waiting for all network profiles to come online
|
||||
systemd.services.NetworkManager-wait-online.enable = lib.mkForce false;
|
||||
|
||||
hardware.bluetooth = {
|
||||
enable = true;
|
||||
powerOnBoot = true;
|
||||
settings.General.Experimental = true;
|
||||
};
|
||||
|
||||
|
||||
##
|
||||
##
|
||||
## 5.1 Firewall
|
||||
##
|
||||
##
|
||||
networking.firewall = {
|
||||
|
||||
## UDP ports and ranges
|
||||
allowedUDPPorts = [ 51820 51812 5113 ];
|
||||
allowedUDPPortRanges = [
|
||||
{ from = 47884; to = 48010; }
|
||||
];
|
||||
|
||||
## TCP ports and ranges
|
||||
allowedTCPPorts = [ 22 3010 222 8084 443 80 8787 8180 7777 3180 47989 47990 47991 47992 48010 5113 8777 ];
|
||||
# Enable IP forwarding (needed for Wireguard routing)
|
||||
enable = true;
|
||||
};
|
||||
|
||||
## Enable Ip forwarding at the kernel level
|
||||
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
|
||||
|
||||
## SSHD
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PasswordAuthentication = false;
|
||||
PermitRootLogin = "prohibit-password";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
##
|
||||
##
|
||||
## 5.2: Wireguard
|
||||
##
|
||||
##
|
||||
networking.wireguard.interfaces = {
|
||||
wg0 = {
|
||||
ips = [ "10.10.10.1/24" ];
|
||||
listenPort = 51820;
|
||||
privateKeyFile = "/etc/nixos/secrets/wireguard/wg0-key.key";
|
||||
|
||||
# IP forwarding + NAT for wg0 clients to internet/LAN
|
||||
postSetup = ''
|
||||
${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT
|
||||
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -o eno1 -j MASQUERADE
|
||||
'';
|
||||
postShutdown = ''
|
||||
${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT
|
||||
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -o eno1 -j MASQUERADE
|
||||
'';
|
||||
|
||||
peers = [
|
||||
# Exos — routes remote subnets
|
||||
{
|
||||
publicKey = "8rO4j18cPAw6zv8b26PNXFHpEwxqjBq1r8yRmWNOMXY=";
|
||||
endpoint = "briggs.wiki:51820";
|
||||
allowedIPs = [
|
||||
"10.10.10.2/32"
|
||||
"10.0.0.0/24"
|
||||
"192.168.3.0/24"
|
||||
];
|
||||
}
|
||||
# Maroon / Roman Phone
|
||||
{
|
||||
publicKey = "Sih2qcJtmhdlSwxlaRont7ezwazo0FMyMxTjhWBtpjA=";
|
||||
allowedIPs = [ "192.168.3.1/32" ];
|
||||
}
|
||||
# Palantir (Phone)
|
||||
{
|
||||
publicKey = "RUPXirLLTY1KeFIjfwKQtVg3ckj8sLz2QN/AiLZOmFw=";
|
||||
allowedIPs = [ "192.168.2.1/32" ];
|
||||
}
|
||||
# Menegroth
|
||||
{
|
||||
publicKey = "DWhEqMQ7/RHkEuPtMrpuhQqnls7o/B6idSJxXJJy6ys=";
|
||||
allowedIPs = [ "192.168.2.2/32" ];
|
||||
}
|
||||
# iPad
|
||||
{
|
||||
publicKey = "lqTK2qoaNJ+Md8RZT3TVxN+fAHllTwIG2znZKI3Rt2c=";
|
||||
allowedIPs = [ "192.168.2.3/32" ];
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
##
|
||||
##
|
||||
## 5.3) Pi-hole DNS
|
||||
##
|
||||
##
|
||||
services.pihole-ftl = {
|
||||
enable = true;
|
||||
openFirewallDNS = true;
|
||||
## Upstream DNS servers (Cloudflare and Quad9)
|
||||
settings = {
|
||||
dns = {
|
||||
upstreams = [
|
||||
"1.1.1.1#53"
|
||||
"1.0.0.1#53"
|
||||
"9.9.9.9#53"
|
||||
];
|
||||
## Listen on all interfaces
|
||||
listeningMode = "ALL";
|
||||
## Block ESNI, ICloud Private Relay, Firefox canary, etc.
|
||||
blocking.active = true;
|
||||
blocking.mode = "NULL";
|
||||
## Rate limiting
|
||||
rateLimit.count = 1000;
|
||||
rateLimit.interval = 60;
|
||||
## Cache
|
||||
cache.size = 10000;
|
||||
cache.optimizer = 3600;
|
||||
## DNSSEC
|
||||
dnssec = false;
|
||||
bogusPriv = true;
|
||||
domainNeeded = false;
|
||||
## Local DNS records
|
||||
hosts = [
|
||||
"10.0.1.49 jellyfin.wingard.pro"
|
||||
"10.0.1.49 speedtest.wingard.pro"
|
||||
];
|
||||
};
|
||||
## Web server on 8999, admin page at /admin/
|
||||
webserver = {
|
||||
port = lib.mkForce "8999";
|
||||
interface.boxed = "true";
|
||||
interface.theme = "default-dark";
|
||||
};
|
||||
## Privacy level 0 = full stats
|
||||
misc.privacylevel = 0;
|
||||
};
|
||||
## Blocklist: Steven Black's unified hosts
|
||||
lists = [
|
||||
{
|
||||
url = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts";
|
||||
description = "Steven Black's unified adlist";
|
||||
}
|
||||
];
|
||||
};
|
||||
## Pi-hole web admin dashboard
|
||||
services.pihole-web.enable = true;
|
||||
##
|
||||
##
|
||||
## 5.4: Nginx
|
||||
##
|
||||
##
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedProxySettings = true;
|
||||
virtualHosts = {
|
||||
"jellyfin.wingard.pro" = {
|
||||
enableACME = false;
|
||||
addSSL = true;
|
||||
sslCertificate = "/etc/letsencrypt/live/jellyfin.wingard.pro/fullchain.pem";
|
||||
sslCertificateKey = "/etc/letsencrypt/live/jellyfin.wingard.pro/privkey.pem";
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:8096";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
"speedtest.wingard.pro" = {
|
||||
enableACME = false;
|
||||
addSSL = true;
|
||||
sslCertificate = "/etc/letsencrypt/live/speedtest.wingard.pro/fullchain.pem";
|
||||
sslCertificateKey = "/etc/letsencrypt/live/speedtest.wingard.pro/privkey.pem";
|
||||
root = "/opt/openspeedtest";
|
||||
locations."/" = {
|
||||
index = "index.html";
|
||||
tryFiles = "$uri $uri/ /index.html";
|
||||
};
|
||||
locations."~ \\.php$" = {
|
||||
extraConfig = ''
|
||||
fastcgi_pass unix:/run/phpfpm-openspeedtest.sock;
|
||||
fastcgi_index index.php;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_param SCRIPT_FILENAME /opt/openspeedtest$fastcgi_script_name;
|
||||
'';
|
||||
};
|
||||
};
|
||||
"speedtest-http" = {
|
||||
listen = [ { addr = "0.0.0.0"; port = 8084; } ];
|
||||
root = "/opt/openspeedtest";
|
||||
locations."/" = {
|
||||
index = "index.html";
|
||||
tryFiles = "$uri $uri/ /index.html";
|
||||
};
|
||||
locations."~ \\.php$" = {
|
||||
extraConfig = ''
|
||||
fastcgi_pass unix:/run/phpfpm-openspeedtest.sock;
|
||||
fastcgi_index index.php;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_param SCRIPT_FILENAME /opt/openspeedtest$fastcgi_script_name;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
############################################################
|
||||
## ##
|
||||
## 6: Users ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
## setting up sudo wheel group
|
||||
security.sudo.extraRules = [
|
||||
{ groups = [ "wheel" ]; commands = [ { command = "ALL"; options = [ "NOPASSWD" ]; } ]; }
|
||||
];
|
||||
|
||||
## Harley
|
||||
users.users.harley = {
|
||||
isNormalUser = true;
|
||||
shell = lib.mkForce pkgs.zsh;
|
||||
extraGroups = [ "wheel" "networkmanager" "docker" "input" "uinput" "video"];
|
||||
openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4OAJ8iC7CQIcedVbU86xgoL4YkMWAG9bU6aj9v4Skb harley@utumno" ];
|
||||
};
|
||||
|
||||
## Roman
|
||||
users.users.roman = {
|
||||
isNormalUser = true;
|
||||
description = "Roman";
|
||||
home = "/home/roman/";
|
||||
createHome = true;
|
||||
shell = pkgs.bash;
|
||||
extraGroups = [ "wheel" "users" ];
|
||||
openssh.authorizedKeys.keys = [ " " ];
|
||||
};
|
||||
## The Ephemeral user and filesystem
|
||||
|
||||
## The actual Ephemeral user
|
||||
users.users.atomic = {
|
||||
isNormalUser = true;
|
||||
description = "Ephemeral User - home directory inside a tmpfs";
|
||||
home = "/home/atomic";
|
||||
group = "users";
|
||||
createHome = false;
|
||||
extraGroups = [ "wheel" ];
|
||||
shell = lib.mkForce pkgs.zsh;
|
||||
openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH4OAJ8iC7CQIcedVbU86xgoL4YkMWAG9bU6aj9v4Skb harley@utumno" ];
|
||||
};
|
||||
|
||||
## filesystem for the Ephemeral user
|
||||
fileSystems."/home/atomic" = {
|
||||
device = "tmpfs";
|
||||
fsType = "tmpfs";
|
||||
options = [ "mode=0700" "uid=1001" "gid=100" "noatime" ];
|
||||
};
|
||||
|
||||
## Populate the Ephemeral user from seed on boot
|
||||
systemd.services.populate-atomic-home = {
|
||||
description = " Populate atomic user's tmpfs home from seed";
|
||||
after = [ "home-atomic.mount" ];
|
||||
requires = [ "home-atomic.mount" ];
|
||||
wantedBy = [ "home-atomic.mount" "systemd-logind.service" ];
|
||||
script = ''
|
||||
cp -rT /home/.atomic-persist /home/atomic
|
||||
chown -R 1001:100 /home/atomic
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
serviceConfig.RemainAfterExit = true;
|
||||
};
|
||||
|
||||
## Periodic Ephemeral home cleaner (reseed from skeleton)
|
||||
systemd.services.atomic-home-cleaner = {
|
||||
description = "Wipe atomic home if user has no active logind sessions";
|
||||
script = ''
|
||||
if ! pgrep -u atomic >/dev/null 2>&1; then
|
||||
umount /home/atomic/mnt 2>/dev/null || true
|
||||
rm -rf /home/atomic/.??* /home/atomic/** 2>/dev/null
|
||||
cp -rT /home/.atomic-persist/ /home/atomic/
|
||||
chown -R 1001:100 /home/atomic/
|
||||
fi
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
};
|
||||
|
||||
systemd.timers.atomic-home-cleaner = {
|
||||
description = "Check every 2 min if atomic user's sessions ended";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnBootSec = "1min";
|
||||
OnUnitActiveSec = "30s";
|
||||
};
|
||||
};
|
||||
|
||||
## One-shot service to unmount and re-populate atomic's tmpfs home
|
||||
systemd.services.atomic-fresh = {
|
||||
description = "Wipe and re-populate atomic's tmpfs home";
|
||||
after = [ "home-atomic.mount" ];
|
||||
script = ''
|
||||
loginctl terminate-user atomic 2>/dev/null || true
|
||||
sleep 1
|
||||
rm -rf /home/atomic/.??* /home/atomic/** 2>/dev/null || true
|
||||
umount /home/atomic 2>/dev/null || true
|
||||
mount /home/atomic
|
||||
cp -rT /home/.atomic-persist/ /home/atomic/
|
||||
chown -R 1001:100 /home/atomic/
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
path = [ pkgs.util-linux ];
|
||||
serviceConfig.User = "root";
|
||||
};
|
||||
############################################################
|
||||
## ##
|
||||
## 7: General Packages ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
|
||||
## Cli tools
|
||||
vim wget curl progress git btop neovim tmux lsof bat ncdu nvtopPackages.full fastfetch
|
||||
unzip unrar p7zip xclip
|
||||
testdisk btdu
|
||||
|
||||
## Games
|
||||
lutris rpcs3 mednafen mednafen-server mednaffe dolphin-emu
|
||||
|
||||
## System
|
||||
adwaita-icon-theme tela-circle-icon-theme
|
||||
sshfs sshpass pciutils usbutils python312 (pkgs.kdePackages.bluedevil) gtkgreet
|
||||
cage guake android-tools patool pv ghostscript imagemagick nodejs go deno socat
|
||||
fzf smartmontools shadow ripgrep fd jq tree qdirstat
|
||||
|
||||
firefox
|
||||
|
||||
## Multimedia
|
||||
mpv geeqie ffmpeg yt-dlp
|
||||
## Virtual display for Sunshine headless streaming (krfb-virtualmonitor)
|
||||
kdePackages.krfb
|
||||
];
|
||||
############################################################
|
||||
## ##
|
||||
## 8) Services ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
## Hermes WebUI (port 8787)
|
||||
#systemd.services.hermes-webui = {
|
||||
# description = "Hermes Web UI";
|
||||
# after = [ "network-online.target" ];
|
||||
# wants = [ "network-online.target" ];
|
||||
# wantedBy = [ "multi-user.target" ];
|
||||
# environment = {
|
||||
# HERMES_WEBUI_HOST = "0.0.0.0";
|
||||
# HERMES_WEBUI_PORT = "8787";
|
||||
# HERMES_HOME = "/storage/8TB/Backups/Agents/.hermes";
|
||||
# HERMES_WEBUI_STATE_DIR = "/storage/8TB/Backups/Agents/.hermes/webui";
|
||||
# SEARXNG_URL = "http://10.0.1.49:8888";
|
||||
# };
|
||||
# serviceConfig = {
|
||||
# Type = "simple";
|
||||
# User = "harley";
|
||||
# WorkingDirectory = "/opt/hermes-webui";
|
||||
# ExecStart = "/opt/hermes-webui/venv/bin/python server.py";
|
||||
# Restart = "on-failure";
|
||||
# RestartSec = 5;
|
||||
# };
|
||||
# };
|
||||
## SearXNG meta search engine (Port 8888)
|
||||
services.searx = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
redisCreateLocally = true;
|
||||
settings = {
|
||||
general.instance_name = "Utumno Search";
|
||||
search = {
|
||||
safe_search = 0;
|
||||
formats = [ "html" "json" ];
|
||||
autocomplete = "";
|
||||
};
|
||||
server = {
|
||||
port = 8888;
|
||||
bind_address = "0.0.0.0";
|
||||
secret_key = "@SEARXNG_SECRET@";
|
||||
limiter = false;
|
||||
method = "POST";
|
||||
image_proxy = false;
|
||||
};
|
||||
ui = {
|
||||
default_theme = "simple";
|
||||
theme_args.simple_style = "dark";
|
||||
query_in_title = false;
|
||||
};
|
||||
outgoing = {
|
||||
request_timeout = 5.0;
|
||||
max_request_timeout = 15.0;
|
||||
pool_connections = 100;
|
||||
pool_maxsize = 20;
|
||||
enable_http2 = true;
|
||||
};
|
||||
};
|
||||
environmentFile = "/opt/searxng/secrets.env";
|
||||
};
|
||||
|
||||
## Gitea (Port 3010)
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
stateDir = "/storage/8TB/Backups/Gitea";
|
||||
repositoryRoot = "/storage/8TB/Backups/Gitea/repositories";
|
||||
database.type = "sqlite3";
|
||||
settings = {
|
||||
server = {
|
||||
DOMAIN = "10.0.1.49";
|
||||
ROOT_URL = "http://10.0.1.49:3010";
|
||||
HTTP_PORT = 3010;
|
||||
SSH_PORT = 222;
|
||||
DISABLE_SSH = false;
|
||||
LFS_START_SERVER = false;
|
||||
};
|
||||
service = {
|
||||
DISABLE_REGISTRATION = false;
|
||||
REQUIRE_SIGNIN_VIEW = false;
|
||||
};
|
||||
security.INSTALL_LOCK = true;
|
||||
};
|
||||
};
|
||||
|
||||
## Kiwix ZIM server (port 8098)
|
||||
services.kiwix-serve = {
|
||||
enable = true;
|
||||
port = 8098;
|
||||
openFirewall = true;
|
||||
library = {
|
||||
# Update paths when ZIM files are added/removed
|
||||
wikipedia = "/storage/20TB/Media/Kiwix/wikipedia_en_all_maxi_2026-02.zim";
|
||||
archlinux = "/storage/20TB/Media/Kiwix/archlinux_en_all_maxi_2025-08.zim";
|
||||
ifixit = "/storage/20TB/Media/Kiwix/ifixit_en_all_2025-06.zim";
|
||||
khanacademy = "/storage/20TB/Media/Kiwix/khanacademy_en_all_2023-03.zim";
|
||||
survivorlibrary = "/storage/20TB/Media/Kiwix/survivorlibrary.com_en_all_2025-06.zim";
|
||||
urbanprepper = "/storage/20TB/Media/Kiwix/urban-prepper_en_all_2025-06.zim";
|
||||
anonymousplanet = "/storage/20TB/Media/Kiwix/anonymousplanet.org_en_all_2025-08.zim";
|
||||
basedcooking = "/storage/20TB/Media/Kiwix/based.cooking_en_all_2025-08.zim";
|
||||
};
|
||||
extraArgs = [ "--skipInvalid" ];
|
||||
};
|
||||
|
||||
## OpenSpeedTest (Port 8084)
|
||||
services.phpfpm.pools.openspeedtest = {
|
||||
user = "nginx";
|
||||
group = "nginx";
|
||||
settings = {
|
||||
pm = "dynamic";
|
||||
"pm.max_children" = 5;
|
||||
"pm.start_servers" = 2;
|
||||
"pm.min_spare_servers" = 1;
|
||||
"pm.max_spare_servers" = 3;
|
||||
"listen" = "/run/phpfpm-openspeedtest.sock";
|
||||
};
|
||||
};
|
||||
|
||||
## Immich (Port 2283)
|
||||
#services.immich = {
|
||||
#enable = true;
|
||||
#host = "10.10.10.1";
|
||||
#mediaLocation = "/storage/8TB/Documents/immich";
|
||||
#port = 2283;
|
||||
#openFirewall = true;
|
||||
#database.enable = true;
|
||||
#redis.enable = true;
|
||||
#};
|
||||
|
||||
## Roku Remote (Port 7777)
|
||||
## btop-web system monitor (Port 8777)
|
||||
systemd.services.btop-web = {
|
||||
description = "btop-style web system monitor";
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = "harley";
|
||||
WorkingDirectory = "/opt/btop-web";
|
||||
ExecStart = "${pkgs.python3}/bin/python server.py";
|
||||
Restart = "always";
|
||||
RestartSec = 5;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.roku-remote = {
|
||||
description = "Roku TV Web Remote";
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = "harley";
|
||||
WorkingDirectory = "/opt/roku-remote";
|
||||
ExecStart = "${pkgs.python3}/bin/python server.py";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 5;
|
||||
};
|
||||
};
|
||||
|
||||
##Sunshine
|
||||
services.sunshine = {
|
||||
enable = true;
|
||||
autoStart = true;
|
||||
capSysAdmin = true; # only needed for Wayland -- omit this when using with Xorg
|
||||
openFirewall = true;
|
||||
};
|
||||
## uninput enable for Sunshine.
|
||||
hardware.uinput.enable = true;
|
||||
##
|
||||
##
|
||||
## 8.1: Docker
|
||||
##
|
||||
##
|
||||
virtualisation.docker = {
|
||||
enable = true;
|
||||
# Allow non-root users (harley is in docker group)
|
||||
enableOnBoot = true;
|
||||
# Use the overlay2 storage driver (default on modern kernels)
|
||||
storageDriver = "overlay2";
|
||||
# Auto-prune unused data
|
||||
autoPrune.enable = true;
|
||||
autoPrune.dates = "weekly";
|
||||
};
|
||||
## Firecrawl web-scraper (Port 3002)
|
||||
systemd.services.firecrawl = {
|
||||
description = "Firecrawl web scraping stack";
|
||||
after = [ "docker.service" "network-online.target" ];
|
||||
wants = [ "docker.service" "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.docker ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
WorkingDirectory = "/opt/firecrawl";
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose up -d";
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose down";
|
||||
};
|
||||
};
|
||||
|
||||
########## ##########
|
||||
########## ##########
|
||||
########## 8.2: ARRS ##########
|
||||
########## ##########
|
||||
########## ##########
|
||||
|
||||
## PIA VPN + qBittorrent (Port 8088) + SOCKS5 (Port 1080) (Docker compose)
|
||||
systemd.services.pia-qbit = {
|
||||
description = "PIA VPN + qBittorrent + SOCKS5 proxy stack";
|
||||
after = [ "docker.service" "network-online.target" ];
|
||||
wants = [ "docker.service" "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.docker ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
WorkingDirectory = "/opt/pia-qbit";
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose up -d";
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose down";
|
||||
# Give VPN time to establish before declaring "done"
|
||||
ExecStartPost = "${pkgs.coreutils}/bin/sleep 10";
|
||||
};
|
||||
};
|
||||
|
||||
## Bitmagnet (Port 3333)
|
||||
#services.bitmagnet = {
|
||||
# enable = true;
|
||||
#openFirewall = true;
|
||||
#settings = {
|
||||
#http_server.local_address = ":3333";
|
||||
#dht_server.port = 3334;
|
||||
#postgres = {
|
||||
#name = "bitmagnet";
|
||||
#user = "bitmagnet";
|
||||
#password = "";
|
||||
#};
|
||||
#};
|
||||
#};
|
||||
|
||||
#services.postgresql = {
|
||||
#dataDir = "/storage/20TB/Computer-Related/Bitmagnet-data";
|
||||
#package = pkgs.postgresql_16;
|
||||
#};
|
||||
|
||||
## Jellyfin (Port 8096)
|
||||
services.jellyfin = {
|
||||
enable = true;
|
||||
dataDir = "/storage/8TB/arrs-tmp/jellyfin";
|
||||
cacheDir = "/storage/8TB/arrs-tmp/jellyfin-cache";
|
||||
openFirewall = true;
|
||||
};
|
||||
## Prowlarr (port 9696)
|
||||
services.prowlarr = {
|
||||
enable = true;
|
||||
dataDir = "/storage/8TB/arrs-tmp/prowlarr";
|
||||
openFirewall = true;
|
||||
};
|
||||
## Sonarr (port 8989)
|
||||
services.sonarr = {
|
||||
enable = true;
|
||||
dataDir = "/storage/8TB/arrs-tmp/sonarr";
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
## Radarr (port 7878)
|
||||
services.radarr = {
|
||||
enable = true;
|
||||
dataDir = "/storage/8TB/arrs-tmp/radarr";
|
||||
openFirewall = true;
|
||||
};
|
||||
## SABnzbd (port 8180)
|
||||
fileSystems."/var/lib/sabnzbd" = {
|
||||
device = "/storage/8TB/arrs-tmp/sabnzbd";
|
||||
options = [ "bind" "noauto" ];
|
||||
fsType = "none";
|
||||
};
|
||||
|
||||
services.sabnzbd = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
settings = {
|
||||
host = "0.0.0.0";
|
||||
port = 8180;
|
||||
misc = {
|
||||
host = "0.0.0.0";
|
||||
port = 8180;
|
||||
enable_https = false;
|
||||
html_login = true;
|
||||
inet_exposure = 0;
|
||||
auto_browser = false;
|
||||
config_lock = false;
|
||||
check_new_rel = false;
|
||||
cache_limit = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
############################################################
|
||||
## ##
|
||||
## 9: Customization ##
|
||||
## ##
|
||||
############################################################
|
||||
|
||||
##
|
||||
##
|
||||
## 9.1: Keyd keyboard remappings
|
||||
##
|
||||
##
|
||||
services.keyd = {
|
||||
enable = true;
|
||||
keyboards = {
|
||||
default = {
|
||||
ids = [ "*" ];
|
||||
settings = {
|
||||
main = {
|
||||
esc = "capslock";
|
||||
capslock = "overload(nav, esc)";
|
||||
};
|
||||
nav = {
|
||||
w = "up";
|
||||
a = "left";
|
||||
s = "down";
|
||||
d = "right";
|
||||
b = "C-left";
|
||||
u = "pageup";
|
||||
x = "delete";
|
||||
g = "home";
|
||||
n = "end";
|
||||
h = "left";
|
||||
j = "down";
|
||||
k = "up";
|
||||
l = "right";
|
||||
space = "capslock";
|
||||
};
|
||||
};
|
||||
};
|
||||
q = {
|
||||
ids = [ "*" ];
|
||||
settings = {
|
||||
main = {
|
||||
esc = "capslock";
|
||||
capslock = "overload(nav, esc)";
|
||||
};
|
||||
nav = {
|
||||
w = "up";
|
||||
a = "left";
|
||||
s = "down";
|
||||
d = "right";
|
||||
h = "left";
|
||||
j = "down";
|
||||
k = "up";
|
||||
l = "right";
|
||||
space = "capslock";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
##
|
||||
##
|
||||
## 9.2 Enviroment Variables
|
||||
##
|
||||
##
|
||||
environment.variables = {
|
||||
GTK_THEME = "Adwaita:dark";
|
||||
GTK_ICON_THEME = "Tela-circle-dark";
|
||||
HERMES_HOME = "/storage/8TB/Backups/Agents/.hermes";
|
||||
};
|
||||
|
||||
## ZSH with Oh-My-Zsh
|
||||
programs.zsh.enable = true;
|
||||
programs.zsh.ohMyZsh = {
|
||||
enable = true;
|
||||
theme = "jonathan";
|
||||
plugins = [
|
||||
"git"
|
||||
"sudo"
|
||||
"web-search"
|
||||
"history"
|
||||
"extract"
|
||||
"colored-man-pages"
|
||||
];
|
||||
customPkgs = [
|
||||
(pkgs.runCommand "jonathan-zsh-theme" {
|
||||
themeFile = builtins.readFile ./jonathan.zsh-theme;
|
||||
passAsFile = [ "themeFile" ];
|
||||
} ''
|
||||
mkdir -p $out/share/zsh/themes
|
||||
cp "$themeFilePath" $out/share/zsh/themes/jonathan.zsh-theme
|
||||
'')
|
||||
];
|
||||
};
|
||||
|
||||
programs.zsh.syntaxHighlighting.enable = true;
|
||||
|
||||
programs.zsh.interactiveShellInit = ''
|
||||
source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh
|
||||
'';
|
||||
programs.zsh.promptInit = ''
|
||||
bindkey '^F' autosuggest-accept
|
||||
bindkey '^[[C' autosuggest-accept
|
||||
'';
|
||||
|
||||
programs.zsh.shellAliases = {
|
||||
cl = "clear";
|
||||
tt = "tmux";
|
||||
tta = "tmux attach";
|
||||
ttls = "tmux ls";
|
||||
xclipp = "xclip -selection clipboard";
|
||||
palantir = "ssh palantir";
|
||||
rcp = "rsync -avP --partial --append";
|
||||
};
|
||||
# Make theme packages available to all users
|
||||
environment.sessionVariables = {
|
||||
XDG_DATA_DIRS = [
|
||||
"${pkgs.tela-circle-icon-theme}/share/icons"
|
||||
"${pkgs.catppuccin}/share/plasma"
|
||||
];
|
||||
};
|
||||
############################################################
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
############################################################
|
||||
## ── State version ────────────────────────────────────────
|
||||
system.stateVersion = "26.11";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user