Compare commits
17
Commits
f8552bc7bb
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9abc47a8e1 | ||
|
|
d63409dad8 | ||
|
|
66f9e08617 | ||
|
|
36b1f78886 | ||
|
|
15be29ba2a | ||
|
|
eab86bebc7 | ||
|
|
a0d9135695 | ||
|
|
d7894065f7 | ||
|
|
6a66db0b20 | ||
|
|
46271e24bb | ||
|
|
63c1037c85 | ||
|
|
64cbb91aac | ||
|
|
3220ab4300 | ||
|
|
97b5f89182 | ||
|
|
61c36b6eef | ||
|
|
91332d7e16 | ||
|
|
a009a4d984 |
-18
@@ -4,21 +4,3 @@
|
||||
# churns on every build, so it must not be tracked.
|
||||
result
|
||||
result-*
|
||||
|
||||
# git-secret. `git secret init` writes the random_seed and the `!*.secret`
|
||||
# negation; the rest is hardening.
|
||||
#
|
||||
# WARNING: `!*.secret` only un-ignores the *encrypted* blobs. It does nothing to
|
||||
# protect the plaintext originals -- that relies entirely on `git secret add`
|
||||
# appending each plaintext path below. Always run `git secret add <file>` from
|
||||
# the repo root (never hand-edit .gitsecret/paths/mapping.cfg) and verify with
|
||||
# `git status` before committing.
|
||||
.gitsecret/keys/random_seed
|
||||
# .gitsecret/keys is git-secret's GPG homedir. pubring.kbx is meant to be
|
||||
# committed; private key material and sockets never are.
|
||||
.gitsecret/keys/private-keys-v1.d/
|
||||
.gitsecret/keys/openpgp-revocs.d/
|
||||
.gitsecret/keys/*.gpg~
|
||||
.gitsecret/keys/.#*
|
||||
.gitsecret/keys/S.*
|
||||
!*.secret
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
self,
|
||||
moduleWithSystem,
|
||||
...
|
||||
}: {
|
||||
flake.nixosModules.cad = moduleWithSystem ({...}: let
|
||||
modules = with self.nixosModules; [
|
||||
freecad
|
||||
openscad
|
||||
prusa-slicer
|
||||
];
|
||||
in {
|
||||
imports = modules;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
self,
|
||||
moduleWithSystem,
|
||||
...
|
||||
}: {
|
||||
flake.nixosModules.netops = moduleWithSystem ({...}: let
|
||||
modules = with self.nixosModules; [
|
||||
winbox
|
||||
unraid-usb-creator
|
||||
];
|
||||
in {
|
||||
imports = modules;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{...}: {
|
||||
# Screenshot capture, region selection, annotation, and clipboard support for
|
||||
# the Hyprland screenshot keybinds managed in the dotfiles repo.
|
||||
flake.nixosModules.freecad = {pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
freecad
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
ghostty
|
||||
waybar
|
||||
quickshell
|
||||
screenshot
|
||||
];
|
||||
in {
|
||||
imports = modules;
|
||||
@@ -148,7 +149,6 @@
|
||||
udiskie
|
||||
brightnessctl
|
||||
# clipboard
|
||||
wl-clipboard
|
||||
cliphist
|
||||
# theming
|
||||
gsettings-desktop-schemas
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{...}: {
|
||||
flake.nixosModules.moonlight = {pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
moonlight-qt
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{...}: {
|
||||
# Nextcloud desktop sync client. Account and sync settings remain per-user.
|
||||
flake.nixosModules.nextcloud = {pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
nextcloud-client
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{...}: {
|
||||
# Screenshot capture, region selection, annotation, and clipboard support for
|
||||
# the Hyprland screenshot keybinds managed in the dotfiles repo.
|
||||
flake.nixosModules.openscad = {pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
openscad
|
||||
openscad-lsp
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
{...}: {
|
||||
# CUPS printing + eSCL scanning for the networked EPSON ET-8550.
|
||||
#
|
||||
# Two queues, deliberately:
|
||||
# EPSON_ET_8550 driverless / IPP Everywhere. The default. PDF is
|
||||
# passed straight through and the printer's own RIP
|
||||
# does the work. 51 page sizes, 26 borderless, and the
|
||||
# only queue that can print CD/DVDs (MediaType Disc).
|
||||
# EPSON_ET_8550_Photo Epson ESC/P-R. Host rasterises to ESC/P-R at 360dpi.
|
||||
# 34 sizes, 12 borderless, no disc support - but it is
|
||||
# the only way to reach Epson's named media/quality
|
||||
# presets ("Epson Ultra Glossy-Max Quality" etc) that
|
||||
# IPP Everywhere cannot express. Kept for photo A/B.
|
||||
#
|
||||
# Note both PPDs are 360x360 HWResolution - escpr2 is not higher resolution.
|
||||
#
|
||||
# Both queues use the mDNS name, not 10.10.20.62, so a DHCP lease change
|
||||
# doesn't break them. services.avahi.nssmdns4 is what resolves it.
|
||||
# Port 9100 is closed on this printer, so socket:// is not an option.
|
||||
#
|
||||
# cups-browsed is off: it would auto-create a third duplicate queue for the
|
||||
# same printer. avahi stays on for mDNS resolution and scanner discovery.
|
||||
flake.nixosModules.printing = {
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
programs.system-config-printer.enable = true;
|
||||
|
||||
services.avahi = {
|
||||
enable = true;
|
||||
nssmdns4 = true;
|
||||
};
|
||||
|
||||
services.printing = {
|
||||
enable = true;
|
||||
browsed.enable = false;
|
||||
drivers = with pkgs; [
|
||||
epson-escpr2
|
||||
];
|
||||
};
|
||||
|
||||
hardware.printers = {
|
||||
ensureDefaultPrinter = "EPSON_ET_8550";
|
||||
ensurePrinters = [
|
||||
{
|
||||
name = "EPSON_ET_8550";
|
||||
description = "EPSON ET-8550 (driverless)";
|
||||
location = "Network";
|
||||
deviceUri = "ipp://EPSONA70973.local:631/ipp/print";
|
||||
model = "everywhere";
|
||||
}
|
||||
{
|
||||
name = "EPSON_ET_8550_Photo";
|
||||
description = "EPSON ET-8550 (ESC/P-R photo presets)";
|
||||
location = "Network";
|
||||
deviceUri = "ipp://EPSONA70973.local:631/ipp/print";
|
||||
model = "epson-inkjet-printer-escpr2/Epson-ET-8550_Series-epson-escpr2-en.ppd";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# hardware/printers.nix orders ensure-printers only after cups.service, but
|
||||
# our deviceUri is an mDNS name and the driverless queue queries the printer
|
||||
# while it is created. Run the generated script asynchronously so an offline
|
||||
# printer cannot fail boot or nixos-rebuild, then retry until it is reachable.
|
||||
systemd.services.ensure-printers = lib.mkIf (config.hardware.printers.ensurePrinters != [] && config.services.printing.enable) {
|
||||
after = [
|
||||
"avahi-daemon.service"
|
||||
"network-online.target"
|
||||
"nss-lookup.target"
|
||||
];
|
||||
wants = [
|
||||
"avahi-daemon.service"
|
||||
"network-online.target"
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = lib.mkForce "simple";
|
||||
Restart = "on-failure";
|
||||
RestartSec = "1min";
|
||||
};
|
||||
};
|
||||
|
||||
# eSCL/AirScan. The printer advertises _uscan._tcp with rs=eSCL and
|
||||
# mopria-certified-scan=1.3, so sane-airscan drives it with no vendor
|
||||
# backend. No scanner/lp group needed - there's no local udev device.
|
||||
#
|
||||
# sane-backends ships its own `escl` backend which also claims eSCL
|
||||
# devices. Left enabled it double-lists the scanner and, worse, GETs the
|
||||
# printer's web root and dumps the HTML response onto scanimage's stdout.
|
||||
# Disabling it leaves sane-airscan as the only eSCL backend, which reports
|
||||
# a far better device string (airscan:e0:EPSON ET-8550 Series).
|
||||
hardware.sane = {
|
||||
enable = true;
|
||||
extraBackends = [pkgs.sane-airscan];
|
||||
disabledDefaultBackends = ["escl"];
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
simple-scan
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{...}: {
|
||||
# PrusaSlicer package only; printer and filament profiles remain per-user.
|
||||
flake.nixosModules.prusa-slicer = {pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
prusa-slicer
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -5,5 +5,6 @@
|
||||
environment.systemPackages = with pkgs; [
|
||||
quickshell
|
||||
];
|
||||
qt.enable = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{...}: {
|
||||
# Screenshot capture, region selection, annotation, and clipboard support for
|
||||
# the Hyprland screenshot keybinds managed in the dotfiles repo.
|
||||
flake.nixosModules.screenshot = {pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
grim
|
||||
slurp
|
||||
satty
|
||||
wl-clipboard
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{...}: {
|
||||
# TODO: previously injected SLSsteam via LD_AUDIT from the sls-steam flake. Now stock.
|
||||
flake.nixosModules.sunshine = {pkgs, ...}: {
|
||||
services.sunshine = {
|
||||
enable = true;
|
||||
autoStart = true;
|
||||
capSysAdmin = true;
|
||||
openFirewall = true;
|
||||
settings.output_name = "DP-3"
|
||||
};
|
||||
hardware.uinput.enable = true;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
{...}: {
|
||||
# Unraid USB Creator - writes Unraid OS straight to a USB stick, streaming the
|
||||
# image from unraid.net instead of making you download it first.
|
||||
#
|
||||
# Not in nixpkgs, and upstream ships an AppImage only, so this is a repack.
|
||||
# The AppImage is a Qt6/QML app (a fork of rpi-imager) built with linuxdeploy,
|
||||
# meaning it already vendors the entire Qt6 stack, xcb, icu, gnutls and krb5 in
|
||||
# usr/lib. We keep that bundle verbatim and only autoPatchelf it against the
|
||||
# handful of libraries linuxdeploy deliberately left out (libc, libstdc++, GL,
|
||||
# X11, fontconfig, ...). No FHS wrapper needed, so no 400MB buildFHSEnv closure.
|
||||
flake.nixosModules.unraid-usb-creator = {
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
pname = "unraid-usb-creator";
|
||||
version = "1.1.0";
|
||||
|
||||
# unraid.net/download's "stable" link is a redirect to this GitHub asset.
|
||||
# Note the v1.1.0 tag is not returned by the releases API (the API only lists
|
||||
# the v2.0.x line), but the download URL is live and matches the checksum.
|
||||
appimage = pkgs.fetchurl {
|
||||
url = "https://github.com/unraid/usb-creator-next/releases/download/v${version}/${pname}-${version}.appimage";
|
||||
hash = "sha256-NI/SMgOuzifvjhtK4Py96lbuI/uvJO0NiMr2zNtNSUk=";
|
||||
};
|
||||
|
||||
unraid-usb-creator = pkgs.stdenvNoCC.mkDerivation {
|
||||
inherit pname version;
|
||||
|
||||
src = pkgs.appimageTools.extract {
|
||||
inherit pname version;
|
||||
src = appimage;
|
||||
};
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
autoPatchelfHook
|
||||
makeWrapper
|
||||
];
|
||||
|
||||
# Only the libraries the AppImage does *not* vendor. Everything else
|
||||
# resolves inside $out/share/unraid-usb-creator/lib.
|
||||
buildInputs = with pkgs; [
|
||||
e2fsprogs # libcom_err.so.2, pulled in by the vendored krb5
|
||||
fontconfig
|
||||
freetype
|
||||
gmp # pulled in by the vendored nettle/gnutls
|
||||
libgpg-error
|
||||
libglvnd # libGL / libGLX / libEGL / libOpenGL
|
||||
libx11 # also provides libX11-xcb
|
||||
libxcb
|
||||
stdenv.cc.cc # libstdc++ / libgcc_s
|
||||
zlib
|
||||
];
|
||||
|
||||
# Qt's openssl TLS backend resolves libssl/libcrypto with dlopen, so
|
||||
# autoPatchelf never sees the dependency. Without this the app cannot fetch
|
||||
# the release JSON or stream the image over HTTPS.
|
||||
#
|
||||
# This has to be appendRunpaths and NOT runtimeDependencies: in
|
||||
# auto-patchelf, `rpath += runtime_deps` lives inside the set-interpreter
|
||||
# branch, so it only ever reaches executables, while `rpath.extend(
|
||||
# append_rpaths)` runs for every patched file. The dlopen happens from
|
||||
# plugins/tls/libqopensslbackend.so, and glibc resolves dlopen against the
|
||||
# calling object's DT_RUNPATH - the wrapper binary's RUNPATH is not
|
||||
# consulted - so the path has to be on the plugin itself.
|
||||
appendRunpaths = ["${pkgs.openssl.out}/lib"];
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
# qt.conf next to the binary declares Prefix=../ with Plugins=plugins and
|
||||
# Qml2Imports=qml, so the usr/ layout has to be preserved as a unit.
|
||||
install -Dm755 usr/bin/unraid-usb-creator -t $out/share/${pname}/bin
|
||||
install -Dm444 usr/bin/qt.conf -t $out/share/${pname}/bin
|
||||
cp -r usr/lib usr/plugins usr/qml $out/share/${pname}/
|
||||
|
||||
cp -r usr/share/icons $out/share/
|
||||
install -Dm444 usr/share/metainfo/*.xml -t $out/share/metainfo
|
||||
install -Dm444 usr/share/applications/*.desktop -t $out/share/applications
|
||||
|
||||
# mkfs.fat is shelled out to when formatting the stick; syslinux is NOT
|
||||
# needed as a runtime dep because upstream statically vendors it.
|
||||
#
|
||||
# linuxdeploy only bundled the xcb platform plugin - there is no
|
||||
# libqwayland*.so anywhere in the AppImage - so this always runs through
|
||||
# XWayland under Hyprland. Pinning the platform avoids Qt first trying
|
||||
# wayland and falling back; --set-default rather than --set so it can
|
||||
# still be overridden if upstream ever ships the Wayland plugin.
|
||||
makeWrapper $out/share/${pname}/bin/unraid-usb-creator $out/bin/${pname} \
|
||||
--prefix PATH : ${lib.makeBinPath (with pkgs; [dosfstools util-linux])} \
|
||||
--set-default QT_QPA_PLATFORM xcb
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
postFixup = ''
|
||||
substituteInPlace $out/share/applications/*.desktop \
|
||||
--replace-fail "Exec=unraid-usb-creator" "Exec=$out/bin/${pname}"
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "Tool for writing Unraid OS to USB drives";
|
||||
homepage = "https://github.com/unraid/usb-creator-next";
|
||||
license = lib.licenses.asl20;
|
||||
sourceProvenance = [lib.sourceTypes.binaryNativeCode];
|
||||
platforms = ["x86_64-linux"];
|
||||
mainProgram = pname;
|
||||
};
|
||||
};
|
||||
in {
|
||||
environment.systemPackages = [unraid-usb-creator];
|
||||
|
||||
# The app enumerates and unmounts removable drives over the UDisks2 D-Bus API
|
||||
# rather than poking /dev directly, which is also how it avoids needing root.
|
||||
# hyprland/default.nix already enables this for udiskie; repeated here so the
|
||||
# module is self-contained on a host that does not use Hyprland.
|
||||
services.udisks2.enable = true;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{...}: {
|
||||
# QMK/VIA keyboard tooling. QMK's uaccess rule lets the active local seat talk
|
||||
# to HID devices; remote and non-seat sessions intentionally get no access.
|
||||
flake.nixosModules.via = {pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
via
|
||||
qmk
|
||||
vial
|
||||
];
|
||||
|
||||
# Do not add pkgs.via or pkgs.vial to services.udev.packages: both make
|
||||
# every hidraw device world-writable. QMK's rules use seat-scoped ACLs.
|
||||
hardware.keyboard.qmk.enable = true;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{...}: {
|
||||
# MikroTik RouterOS configuration client. pkgs.winbox is winbox4, which is
|
||||
# already autoPatchelf'd against the Qt/xcb stack it needs, so it does not
|
||||
# rely on nix-ld. Note the installed binary is `WinBox`, not `winbox`.
|
||||
flake.nixosModules.winbox = {pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
winbox
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{...}: {
|
||||
# Yazi a cli file explorer.
|
||||
flake.nixosModules.yazi = {pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
yazi
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -19,7 +19,12 @@
|
||||
discord
|
||||
gaming
|
||||
bottles
|
||||
netops
|
||||
prusa-slicer
|
||||
printing
|
||||
via
|
||||
nextcloud
|
||||
sunshine
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,22 @@
|
||||
"x-systemd.device-timeout=10"
|
||||
];
|
||||
};
|
||||
|
||||
# Pin the NFS server until nas.hfx.ahmza.com points at 10.10.100.4.
|
||||
# Automounting keeps an unavailable NAS out of the boot path.
|
||||
nfsShare = export: {
|
||||
device = "10.10.100.4:${export}";
|
||||
fsType = "nfs";
|
||||
options = [
|
||||
"nfsvers=4.2"
|
||||
"noauto"
|
||||
"nofail"
|
||||
"_netdev"
|
||||
"x-systemd.automount"
|
||||
"x-systemd.idle-timeout=600"
|
||||
"x-systemd.mount-timeout=10"
|
||||
];
|
||||
};
|
||||
in {
|
||||
fileSystems = {
|
||||
# Boot essentials, by UUID. UUIDs rather than labels here on purpose:
|
||||
@@ -72,6 +88,8 @@
|
||||
"/mnt/dump" = spinningDrive "DUMP";
|
||||
"/mnt/bak" = spinningDrive "BAK";
|
||||
"/mnt/games" = eagerDrive "GAMES";
|
||||
"/mnt/nas" = nfsShare "/srv/nas";
|
||||
"/mnt/media" = nfsShare "/srv/media";
|
||||
};
|
||||
|
||||
# Swap exists for hibernation, not for memory pressure — 31GiB of RAM on a
|
||||
|
||||
@@ -19,6 +19,13 @@
|
||||
obsidian
|
||||
discord
|
||||
gaming
|
||||
winbox
|
||||
cad
|
||||
prusa-slicer
|
||||
netops
|
||||
via
|
||||
t480UsbWakeup
|
||||
moonlight
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
networking = {
|
||||
hostName = "t480";
|
||||
};
|
||||
services.logind.settings.Login = {
|
||||
HandleLidSwitch = "suspend";
|
||||
HandleLidSwitchDocked = "ignore";
|
||||
};
|
||||
services.fwupd = {
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{...}: {
|
||||
flake.nixosModules.t480UsbWakeup = {...}: {
|
||||
services.udev.extraRules = ''
|
||||
# Wake the T480 from S3 suspend via a keyboard plugged into a built-in USB
|
||||
# port. The dock connects over the Thunderbolt-3 controller (3c:00.0), which
|
||||
# powers down in S3 and cannot detect a cold replug — so dock-connected input
|
||||
# cannot wake the machine after an unplug-triggered suspend. The built-in xHCI
|
||||
# (00:14.0) stays wake-capable in S3, so a keyboard on a built-in port works.
|
||||
#
|
||||
# Arm ONLY the keyboard itself (match by VID:PID — the USB bus path is
|
||||
# unstable across re-enumeration). Deliberately do NOT arm the built-in root
|
||||
# hubs: arming a whole root hub makes it wake on hub-level events (USB-C PD
|
||||
# negotiation, the SD card reader, internal peripherals), causing spurious
|
||||
# self-wakes. A leaf device's remote-wakeup propagates through the hub without
|
||||
# the hub's own wakeup flag being set.
|
||||
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="320f", ATTR{idProduct}=="5055", ATTR{power/wakeup}="enabled"
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -36,6 +36,7 @@
|
||||
extraGroups = [
|
||||
"networkmanager"
|
||||
"wheel"
|
||||
"uinput"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
hyprland
|
||||
sddm
|
||||
network
|
||||
yazi
|
||||
];
|
||||
in {
|
||||
imports = modules;
|
||||
|
||||
Reference in New Issue
Block a user