Rebase to flake parts #10
This commit is contained in:
@@ -1,9 +1,15 @@
|
||||
# Export large Jellyfin media trees to nix-server. Local path must already exist
|
||||
# (e.g. /mnt/test/jellyfin/{movies,tv}). On nix-server this is mounted at /mnt/nixdesk-jellyfin.
|
||||
# NFS exports from nixdesk (14900k) to nix-server (192.168.2.238):
|
||||
# - /mnt/test/jellyfin → nix-server /mnt/nixdesk-jellyfin (Jellyfin bulk libraries)
|
||||
# - /mnt/media → nix-server /mnt/media (Btrfs MediaLibrary disk; see media-disk.nix)
|
||||
#
|
||||
# After deploy: ensure Jellyfin can read files over NFS — typical fix:
|
||||
# chmod -R a+rX /mnt/test/jellyfin
|
||||
{ ... }:
|
||||
# NTFS on nixdesk uses uid=olivier + gid=nfsmedia (990); dirs here are olivier:nfsmedia 2775 so
|
||||
# local writes and NFS all_squash (anonuid=olivier, anongid=990) get rwx via owner or group.
|
||||
#
|
||||
# Legacy trees may still need a one-time `chgrp -R nfsmedia` / `chmod -R g+rwX` on deep folders.
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
olivierUid = config.users.users.olivier.uid or 1000;
|
||||
in
|
||||
{
|
||||
# Avoid UID/GID mismatches across machines: map all NFS writes from nix-server to a single
|
||||
# local system user/group on this server.
|
||||
@@ -14,10 +20,32 @@
|
||||
group = "nfsmedia";
|
||||
};
|
||||
|
||||
systemd.tmpfiles.settings."14900k-jellyfin-media-dirs" = {
|
||||
"/mnt/test/jellyfin"."d" = { mode = "2775"; user = "nfsmedia"; group = "nfsmedia"; };
|
||||
"/mnt/test/jellyfin/movies"."d" = { mode = "2775"; user = "nfsmedia"; group = "nfsmedia"; };
|
||||
"/mnt/test/jellyfin/tv"."d" = { mode = "2775"; user = "nfsmedia"; group = "nfsmedia"; };
|
||||
# olivier: owner for local use; nfsmedia: group matches NTFS gid=990 and NFS all_squash (990).
|
||||
systemd.tmpfiles.settings."14900k-nfs-export-paths" = {
|
||||
"/mnt/test"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/test/jellyfin"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/test/jellyfin/movies"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/test/jellyfin/tv"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/media"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/media/Movies"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/media/TV"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
"/mnt/media/Videos"."d" = { mode = "2775"; user = "olivier"; group = "nfsmedia"; };
|
||||
};
|
||||
|
||||
# After exports are up, ensure group nfsmedia can write throughout library roots (idempotent;
|
||||
# scoped to library folders only — not whole disks). Runs on each `nixos-rebuild switch`.
|
||||
system.activationScripts.nfs-export-group-write = {
|
||||
deps = [ "specialfs" ];
|
||||
text = ''
|
||||
for d in \
|
||||
/mnt/media/TV /mnt/media/Movies /mnt/media/Videos \
|
||||
/mnt/test/jellyfin/tv /mnt/test/jellyfin/movies
|
||||
do
|
||||
[ -d "$d" ] || continue
|
||||
${pkgs.acl}/bin/setfacl -R -m g:nfsmedia:rwx "$d" 2>/dev/null || true
|
||||
${pkgs.acl}/bin/setfacl -R -d -m g:nfsmedia:rwx "$d" 2>/dev/null || true
|
||||
done
|
||||
'';
|
||||
};
|
||||
|
||||
# Fixed ports so the firewall can allow NFS v3 helpers (see networking.firewall below).
|
||||
@@ -26,9 +54,12 @@
|
||||
mountdPort = 4000;
|
||||
lockdPort = 4001;
|
||||
statdPort = 4002;
|
||||
# fsid= stabilizes file handles across server reboots/remounts of this tree (avoids client ESTALE).
|
||||
# fsid= unique per export tree (avoids client ESTALE when multiple paths are exported).
|
||||
# Squash nix-server clients to olivier:nfsmedia so Jellyfin can write .nfo/posters into
|
||||
# existing olivier-owned library folders (990-only squash was "other" r-x on typical 755 trees).
|
||||
exports = ''
|
||||
/mnt/test/jellyfin 192.168.2.238(rw,sync,no_subtree_check,crossmnt,root_squash,all_squash,anonuid=990,anongid=990,fsid=1)
|
||||
/mnt/test/jellyfin 192.168.2.238(rw,sync,no_subtree_check,crossmnt,root_squash,all_squash,anonuid=${toString olivierUid},anongid=990,fsid=1)
|
||||
/mnt/media 192.168.2.238(rw,sync,no_subtree_check,crossmnt,root_squash,all_squash,anonuid=${toString olivierUid},anongid=990,fsid=2)
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Extra local disks. Declared here, not in hardware.nix (hardware.nix is generated).
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
# Stable UID so NTFS `uid=` matches `users.users.olivier` (override if your account is not 1000).
|
||||
olivierUid = config.users.users.olivier.uid or 1000;
|
||||
in
|
||||
{
|
||||
users.users.olivier.uid = lib.mkDefault 1000;
|
||||
|
||||
fileSystems."/mnt/media" = {
|
||||
device = "/dev/disk/by-uuid/17d8a981-db3b-415e-a0f7-7dbc519e04ab";
|
||||
fsType = "btrfs";
|
||||
options = [
|
||||
"subvol=@"
|
||||
"compress=zstd"
|
||||
"noatime"
|
||||
];
|
||||
};
|
||||
|
||||
# LABEL="Deep Storage Unit". Owner olivier, group nfsmedia (990) so:
|
||||
# - local logins write as user 1000 (owner rwx);
|
||||
# - NFS (all_squash → uid/gid 990) matches group 990 → rwx (see jellyfin-nfs-export).
|
||||
fileSystems."/mnt/test" = {
|
||||
device = "/dev/disk/by-uuid/BC12E55E12E51DE0";
|
||||
fsType = "ntfs-3g";
|
||||
options = [
|
||||
"rw"
|
||||
"force"
|
||||
"uid=${toString olivierUid}"
|
||||
"gid=990"
|
||||
"umask=0002"
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
./_private/peripherals.nix
|
||||
# ./_private/printing-epson.nix
|
||||
./_private/displays.nix
|
||||
./_private/media-disk.nix
|
||||
./_private/jellyfin-nfs-export.nix
|
||||
];
|
||||
|
||||
@@ -108,8 +109,13 @@ services.cloudflare-warp.enable = true;
|
||||
# Native install (avoid flatpak sandbox issues for QSV/VAAPI).
|
||||
handbrake
|
||||
|
||||
qbittorrent
|
||||
|
||||
# Diagnostics
|
||||
libva-utils # vainfo
|
||||
vlc
|
||||
element-desktop
|
||||
thunderbird
|
||||
];
|
||||
|
||||
|
||||
@@ -136,6 +142,7 @@ services.cloudflare-warp.enable = true;
|
||||
self.homeManagerModules.wisdomAppsDiscord
|
||||
self.homeManagerModules.wisdomAppsSpotify
|
||||
self.homeManagerModules.wisdomAppsLocalsend
|
||||
self.homeManagerModules.wisdomAppsSpacedrive
|
||||
self.homeManagerModules.wisdomAppsPokeclicker
|
||||
self.homeManagerModules.wisdomDesktopScreenshot
|
||||
self.homeManagerModules.wisdomDesktopGtkQtTheming
|
||||
@@ -171,6 +178,7 @@ services.cloudflare-warp.enable = true;
|
||||
spotify.enable = true;
|
||||
spotify.openDiscoveryFirewall = true;
|
||||
localsend.enable = true;
|
||||
spacedrive.enable = true;
|
||||
pokeclicker.enable = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -7,9 +7,12 @@
|
||||
powerManagement.enable = true;
|
||||
|
||||
# ─────────────────────── logind: lid & power button ───────────────────────
|
||||
# Closing the lid suspends, even on AC — Duet 3 is a tablet, treat it like one.
|
||||
# Short press on power: suspend (matches ChromeOS/iOS); long press: poweroff.
|
||||
# The DMS bar power menu is the way to reboot / shut down explicitly.
|
||||
# Tablet form factor: lid close = suspend (even on AC), short power-press = suspend, long
|
||||
# power-press = poweroff. Niri's own power-key handler must stay disabled — see the
|
||||
# `input.disable-power-key-handling` flag in `_private/touch-tablet.nix` — otherwise niri's
|
||||
# `block` inhibitor on `handle-power-key` pre-empts logind and turns the wake-from-suspend
|
||||
# press (which the EC re-delivers as KEY_POWER) into an immediate re-suspend loop
|
||||
# (https://github.com/niri-wm/niri/issues/2233).
|
||||
services.logind.settings.Login = {
|
||||
HandleLidSwitch = "suspend";
|
||||
HandleLidSwitchExternalPower = "suspend";
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
# Host-only: ideapad tablet ergonomics — touchscreen calibration, IIO sensors, virtual keyboard,
|
||||
# and per-session helper daemons (tablet-mode toggle + auto-rotation via iio-sensor-proxy) for both
|
||||
# Niri and Hyprland.
|
||||
# touch-controller resume fix, and per-session helper daemons (tablet-mode toggle + auto-rotation
|
||||
# via iio-sensor-proxy) for both Niri and Hyprland. Lives at the NixOS layer because the hardware
|
||||
# bits are system-wide; the per-compositor autostart hooks are gated on `chiasson.desktop.<wm>.enable`
|
||||
# so they stay dormant if you pick the other session at the greeter.
|
||||
#
|
||||
# Why all of this lives at the *NixOS* layer (not the home-manager catalog under wisdom/):
|
||||
# - The hardware bits (`hardware.sensor.iio.enable`, the udev calibration matrix) are system-wide
|
||||
# and tied to this exact device, so they belong with the host module.
|
||||
# - The compositor helpers run via session-specific autostart hooks (Niri `spawn-at-startup`,
|
||||
# Hyprland `exec-once`); the wiring is gated on the matching `chiasson.desktop.<wm>.enable`,
|
||||
# so picking a different session at the greeter just leaves them dormant.
|
||||
#
|
||||
# Two compositor flavours of each daemon:
|
||||
# - Hyprland (CW transforms via `hyprctl`) — original; matches the old NixOS-New setup.
|
||||
# - Niri (CCW transforms via `niri msg output`) — needed because Niri is the V2 default.
|
||||
# Hyprland uses CW transforms via `hyprctl`; Niri uses CCW transforms via `niri msg output`.
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
@@ -268,15 +261,33 @@ in
|
||||
# ─────────────────────── Hardware ───────────────────────
|
||||
hardware.sensor.iio.enable = true;
|
||||
|
||||
# Touchscreen calibration — solved empirically with `niri msg output DSI-1 transform normal`
|
||||
# in the natural kb-down pose. The panel's touch hardware reports raw coordinates already
|
||||
# aligned with the panel-native frame (HW(visual_top_left) = (0,0), etc.), so identity is
|
||||
# correct. `niri input.touch.map-to-output = "DSI-1"` then handles per-orientation rotation
|
||||
# on top — never re-tune this matrix per orientation; rotate the *output* instead.
|
||||
# Touchscreen calibration — identity matrix is correct: hardware coordinates are already aligned
|
||||
# with the panel-native frame, and per-orientation rotation is handled by `niri msg output`,
|
||||
# not by re-tuning this matrix. Rotate the *output*, never this matrix.
|
||||
services.udev.extraRules = ''
|
||||
SUBSYSTEM=="input", ENV{ID_INPUT_TOUCHSCREEN}=="1", ENV{LIBINPUT_CALIBRATION_MATRIX}="1 0 0 0 1 0"
|
||||
'';
|
||||
|
||||
# ─────────────────────── Touch controller resume fix ───────────────────────
|
||||
# The hid-over-i2c touch controller at i2c bus 4-0001 wedges across S3 suspend: after resume it
|
||||
# re-enumerates with the correct capabilities but reports zero events on touch. Cycling the
|
||||
# `i2c_hid_of` driver (unbind + bind) un-wedges it. systemd-sleep runs every executable in
|
||||
# `/etc/systemd/system-sleep/` with `$1 = pre|post`; we only act on `post`. Driver name is
|
||||
# discovered at runtime so a future kernel rename to `i2c_hid` doesn't break this.
|
||||
environment.etc."systemd/system-sleep/ideapad-touch-rebind".source =
|
||||
pkgs.writeShellScript "ideapad-touch-rebind" ''
|
||||
set -eu
|
||||
[ "$1" = post ] || exit 0
|
||||
dev=4-0001
|
||||
dev_dir=/sys/bus/i2c/devices/$dev
|
||||
[ -L "$dev_dir/driver" ] || exit 0
|
||||
drv=$(${pkgs.coreutils}/bin/basename "$(${pkgs.coreutils}/bin/readlink "$dev_dir/driver")")
|
||||
echo "ideapad-touch-rebind: cycling $drv for $dev" >&2
|
||||
echo "$dev" > "/sys/bus/i2c/drivers/$drv/unbind" || true
|
||||
${pkgs.coreutils}/bin/sleep 0.3
|
||||
echo "$dev" > "/sys/bus/i2c/drivers/$drv/bind"
|
||||
'';
|
||||
|
||||
# ─────────────────────── User-facing tools ───────────────────────
|
||||
# System-wide so any user session (Niri or Hyprland) can launch wvkbd / hyprctl / niri-msg helpers.
|
||||
environment.systemPackages = [
|
||||
@@ -297,6 +308,12 @@ in
|
||||
chiasson.desktop.niri.extraSettings = lib.mkIf config.chiasson.desktop.niri.enable {
|
||||
input.touch.map-to-output = "DSI-1";
|
||||
|
||||
# Required for logind's `HandlePowerKey` in `_private/platform.nix` to take effect: otherwise
|
||||
# niri grabs a `block` inhibitor on `handle-power-key` and suspends via D-Bus, including on
|
||||
# the EC's wake-from-suspend KEY_POWER event → instant re-suspend loop.
|
||||
# https://github.com/niri-wm/niri/issues/2233
|
||||
input."disable-power-key-handling" = _: { };
|
||||
|
||||
# wrapper-modules schema: each entry is a `command argv` list of strings (or a single string).
|
||||
spawn-at-startup = [
|
||||
[ "ideapad-niri-autorotate-daemon" ]
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
{ self, inputs, ... }: {
|
||||
|
||||
# Lenovo Chromebook Duet 3 (`lenovo-wormdingler`) on Mobile NixOS.
|
||||
#
|
||||
# Phase 1 (minimal bootstrap) lived here previously; we now run the full V2 stack:
|
||||
# mobile-nixos device + Niri/Hyprland/DMS, DankGreeter, Waydroid (tablet-class), wvkbd,
|
||||
# IIO sensors, touchscreen calibration, attic cache, sops, and the standard user catalog.
|
||||
# Full V2 stack: mobile-nixos device + Niri/Hyprland/DMS, DankGreeter, wvkbd, IIO sensors,
|
||||
# touchscreen calibration + resume-rebind, attic cache, sops, and the standard user catalog.
|
||||
# Host-only quirks live in `_private/touch-tablet.nix` and `_private/platform.nix`.
|
||||
flake.nixosModules.ideapadConfiguration =
|
||||
{
|
||||
self,
|
||||
@@ -102,9 +101,8 @@
|
||||
};
|
||||
|
||||
# ─────────────────────── Desktop ───────────────────────
|
||||
# Both compositors enabled; DankGreeter lets you pick at login. Default = Niri (V2 convention),
|
||||
# Hyprland session is where the tablet-mode + autorotate daemons in `_private/touch-tablet.nix`
|
||||
# actually run (they hook `exec-once`).
|
||||
# Both compositors are enabled — DankGreeter picks at login, V2 default is Niri.
|
||||
# Per-session tablet-mode / autorotate daemons live in `_private/touch-tablet.nix`.
|
||||
chiasson.desktop = {
|
||||
niri.enable = true;
|
||||
hyprland.enable = true;
|
||||
@@ -113,6 +111,7 @@
|
||||
shell = "dms";
|
||||
shells.dms = {
|
||||
enableWvkbdToggle = true;
|
||||
enableRbwLockToggle = true;
|
||||
# Cross-build on the 14900k via binfmt and push back over LAN — much faster than
|
||||
# rebuilding aarch64 closure on the Snapdragon. Mirrors the old NixOS-New flow:
|
||||
# ssh out to nixdesk, run nixos-rebuild --target-host pointing back at us.
|
||||
@@ -126,15 +125,6 @@
|
||||
];
|
||||
};
|
||||
|
||||
# Tablet-class screen → constrain Waydroid to a sane portrait-ish frame and use gesture nav
|
||||
# instead of 3-button so it feels like the ChromeOS tablet UI.
|
||||
#waydroid = {
|
||||
# enable = true;
|
||||
# multiWindows = false;
|
||||
# width = 1600;
|
||||
# height = 960;
|
||||
# navigationMode = "gestures";
|
||||
#};
|
||||
};
|
||||
|
||||
# ─────────────────────── Users / HM ───────────────────────
|
||||
@@ -146,10 +136,12 @@
|
||||
self.homeManagerModules.wisdomTerminalsKitty
|
||||
self.homeManagerModules.wisdomBrowsersZen
|
||||
self.homeManagerModules.wisdomEditorsKate
|
||||
self.homeManagerModules.wisdomEditorsCursor
|
||||
self.homeManagerModules.wisdomShellFish
|
||||
self.homeManagerModules.wisdomShellOhMyPosh
|
||||
self.homeManagerModules.wisdomAppsSpotify
|
||||
self.homeManagerModules.wisdomAppsLocalsend
|
||||
self.homeManagerModules.wisdomAppsSpacedrive
|
||||
self.homeManagerModules.wisdomDesktopScreenshot
|
||||
{
|
||||
chiasson.home = {
|
||||
@@ -161,8 +153,10 @@
|
||||
filebrowsers.dolphin.enable = true;
|
||||
browsers.zen.enable = true;
|
||||
editors.kate.enable = true;
|
||||
editors.cursor.enable = true;
|
||||
apps.spotify.enable = true;
|
||||
apps.localsend.enable = true;
|
||||
apps.spacedrive.enable = true;
|
||||
desktop = {
|
||||
screenshot = {
|
||||
enable = true;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Dispatcharr — IPTV / M3U / EPG / HDHomeRun-style proxy (Docker, AIO image).
|
||||
# Docs: https://dispatcharr.github.io/Dispatcharr-Docs/
|
||||
# Compose reference: https://github.com/Dispatcharr/Dispatcharr/blob/main/docker/docker-compose.aio.yml
|
||||
#
|
||||
# Web UI: http://<host>:9191
|
||||
# After deploy: create an admin user, add playlists / EPG; point Jellyfin at the tuner/M3U URLs
|
||||
# Dispatcharr shows in its UI.
|
||||
{ lib, pkgs, ... }:
|
||||
{
|
||||
systemd.tmpfiles.settings."nix-server-dispatcharr-data" = {
|
||||
"/var/lib/dispatcharr"."d" = {
|
||||
mode = "0755";
|
||||
user = "root";
|
||||
group = "root";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.docker-dispatcharr.preStart = lib.mkBefore ''
|
||||
${pkgs.coreutils}/bin/mkdir -p /var/lib/dispatcharr
|
||||
'';
|
||||
|
||||
virtualisation.oci-containers.containers.dispatcharr = {
|
||||
image = "ghcr.io/dispatcharr/dispatcharr:latest";
|
||||
ports = [ "9191:9191" ];
|
||||
volumes = [
|
||||
"/var/lib/dispatcharr:/data"
|
||||
];
|
||||
environment = {
|
||||
DISPATCHARR_ENV = "aio";
|
||||
REDIS_HOST = "localhost";
|
||||
CELERY_BROKER_URL = "redis://localhost:6379/0";
|
||||
DISPATCHARR_LOG_LEVEL = "info";
|
||||
TZ = "America/Moncton";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 9191 ];
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
# NFS read-only mount of nixdesk (14900k) bulk storage for extra Jellyfin libraries.
|
||||
# Source: ssh inventory hostName for 14900k. Export is defined in
|
||||
# modules/hosts/14900k/_private/jellyfin-nfs-export.nix
|
||||
#
|
||||
# In Jellyfin (in addition to local /var/lib/media/...), add e.g.:
|
||||
# Movies → /mnt/nixdesk-jellyfin/movies
|
||||
# Shows → /mnt/nixdesk-jellyfin/tv
|
||||
{ ... }:
|
||||
let
|
||||
# Must match LAN IP of the NFS server (flake `sshInventory` → hosts."14900k".hostName).
|
||||
nfsExportHost = "192.168.2.25";
|
||||
in
|
||||
{
|
||||
fileSystems."/mnt/nixdesk-jellyfin" = {
|
||||
device = "${nfsExportHost}:/mnt/test/jellyfin";
|
||||
fsType = "nfs";
|
||||
options = [
|
||||
"rw"
|
||||
"noatime"
|
||||
"nofail"
|
||||
"_netdev"
|
||||
"x-systemd.automount"
|
||||
"x-systemd.idle-timeout=600"
|
||||
];
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
# Jellyfin (native NixOS service). Local media: /var/lib/media (group `media`; jellyfin + server).
|
||||
# Dashboard: Movies → /var/lib/media/movies, Shows → /var/lib/media/tv (see jellyfin-remote-storage.nix
|
||||
# Dashboard: Movies → /var/lib/media/movies, Shows → /var/lib/media/tv (see nixdesk-nfs-client.nix
|
||||
# for bulk libraries on nixdesk at /mnt/nixdesk-jellyfin/{movies,tv}).
|
||||
# Do not use "Mixed Movies and Shows" (deprecated): https://jellyfin.org/docs/general/server/media/mixed-movies-and-shows
|
||||
# Dedicated disk: fileSystems."/var/lib/media" in hardware.nix, then fix ownership.
|
||||
@@ -53,8 +53,9 @@
|
||||
# not writable by uid jellyfin (it only had group `jellyfin`), so deletes fail.
|
||||
systemd.services.jellyfin.serviceConfig = {
|
||||
SupplementaryGroups = [ "media" ];
|
||||
# Jellyfin libraries may live on NFS (e.g. /mnt/nixdesk-jellyfin). PrivateUsers breaks
|
||||
# uid mapping for NFS auth in practice; disable so deletes use the real host jellyfin uid.
|
||||
# Jellyfin libraries on NFS (e.g. /mnt/media, /mnt/nixdesk-jellyfin). PrivateUsers breaks
|
||||
# uid mapping for NFS auth in practice; disable so metadata writes use the real jellyfin uid
|
||||
# (squashed to olivier:nfsmedia on nixdesk exports).
|
||||
PrivateUsers = lib.mkForce false;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# NFS mounts of nixdesk (14900k) bulk storage for nix-server. Exports live in
|
||||
# modules/hosts/14900k/_private/jellyfin-nfs-export.nix
|
||||
#
|
||||
# Jellyfin library paths (see also services/jellyfin.nix):
|
||||
# Movies → /mnt/nixdesk-jellyfin/movies
|
||||
# Shows → /mnt/nixdesk-jellyfin/tv
|
||||
#
|
||||
# If you see "Stale file handle" under /mnt after changing exports or fsid on nixdesk, drop the
|
||||
# old client mount and let automount reattach, e.g.:
|
||||
# sudo umount -l /mnt/nixdesk-jellyfin
|
||||
# ls /mnt/nixdesk-jellyfin
|
||||
# (or reboot nix-server.)
|
||||
{ ... }:
|
||||
let
|
||||
nfsExportHost = "192.168.2.25";
|
||||
# nfsvers+tcp: predictable Linux↔Linux; lookupcache=none: fewer stale dentries after export changes.
|
||||
nfsClientOpts = [
|
||||
"rw"
|
||||
"noatime"
|
||||
"nofail"
|
||||
"_netdev"
|
||||
"nfsvers=3"
|
||||
"tcp"
|
||||
"lookupcache=none"
|
||||
"x-systemd.automount"
|
||||
"x-systemd.idle-timeout=3600"
|
||||
];
|
||||
in
|
||||
{
|
||||
fileSystems."/mnt/nixdesk-jellyfin" = {
|
||||
device = "${nfsExportHost}:/mnt/test/jellyfin";
|
||||
fsType = "nfs";
|
||||
options = nfsClientOpts;
|
||||
};
|
||||
|
||||
fileSystems."/mnt/media" = {
|
||||
device = "${nfsExportHost}:/mnt/media";
|
||||
fsType = "nfs";
|
||||
options = nfsClientOpts;
|
||||
};
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
./_services/swiftshare.nix
|
||||
./_services/immich.nix
|
||||
./_services/jellyfin.nix
|
||||
./_services/jellyfin-remote-storage.nix
|
||||
./_services/nixdesk-nfs-client.nix
|
||||
./_services/ddrm-media-server.nix
|
||||
./_services/sonarr.nix
|
||||
./_services/prowlarr.nix
|
||||
@@ -28,6 +28,7 @@
|
||||
./_services/radarr.nix
|
||||
./_services/qbittorrent.nix
|
||||
./_services/seerr.nix
|
||||
./_services/dispatcharr.nix
|
||||
];
|
||||
|
||||
boot.loader.grub = {
|
||||
|
||||
@@ -95,6 +95,9 @@
|
||||
};
|
||||
defaultSession = "niri";
|
||||
shell = "dms";
|
||||
shells.dms = {
|
||||
enableRbwLockToggle = true;
|
||||
};
|
||||
};
|
||||
|
||||
chiasson.system = {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
# cockpit-file-sharing expects a live Samba stack: /etc/samba/smb.conf, smbd, and
|
||||
# `include = registry` in [global] for net registry share management.
|
||||
services.samba = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
winbindd.enable = false;
|
||||
settings.global = {
|
||||
workgroup = "WORKGROUP";
|
||||
"server string" = config.networking.hostName;
|
||||
include = "registry";
|
||||
};
|
||||
};
|
||||
|
||||
services.nfs.server = {
|
||||
enable = true;
|
||||
mountdPort = 4000;
|
||||
lockdPort = 4001;
|
||||
statdPort = 4002;
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
111
|
||||
2049
|
||||
4000
|
||||
4001
|
||||
4002
|
||||
];
|
||||
networking.firewall.allowedUDPPorts = [
|
||||
111
|
||||
2049
|
||||
4000
|
||||
4001
|
||||
4002
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
acl,
|
||||
bash,
|
||||
coreutils,
|
||||
dpkg,
|
||||
fetchurl,
|
||||
findutils,
|
||||
hostname,
|
||||
iproute2,
|
||||
jq,
|
||||
lib,
|
||||
nfs-utils,
|
||||
python3Packages,
|
||||
samba,
|
||||
stdenv,
|
||||
systemd,
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "cockpit-file-sharing";
|
||||
version = "4.5.6-1";
|
||||
|
||||
src = fetchurl {
|
||||
url = "https://github.com/45Drives/cockpit-file-sharing/releases/download/v4.5.6-1/cockpit-file-sharing_4.5.6-1jammy_all.deb";
|
||||
hash = "sha256-ViTdhiCmqwuBvAfzT8hr2kqZqyWkV9OZ9FEPD10ajF8=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ dpkg ];
|
||||
|
||||
unpackPhase = "dpkg-deb -x $src source";
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/share/cockpit
|
||||
cp -r source/usr/share/cockpit/file-sharing $out/share/cockpit/
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
passthru.cockpitPath = [
|
||||
acl
|
||||
bash
|
||||
coreutils
|
||||
findutils
|
||||
hostname
|
||||
iproute2
|
||||
jq
|
||||
nfs-utils
|
||||
python3Packages.botocore
|
||||
samba
|
||||
systemd
|
||||
];
|
||||
|
||||
meta = {
|
||||
description = "Cockpit plugin to manage Samba and NFS file sharing (45Drives)";
|
||||
homepage = "https://github.com/45Drives/cockpit-file-sharing";
|
||||
license = lib.licenses.gpl3Plus;
|
||||
platforms = lib.platforms.linux;
|
||||
sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
cockpitFileSharing = pkgs.callPackage ./cockpit-file-sharing/package.nix { };
|
||||
in
|
||||
{
|
||||
imports = [ ./cockpit-file-sharing-services.nix ];
|
||||
|
||||
services.cockpit = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
allowed-origins = [
|
||||
"https://${config.networking.hostName}:${toString config.services.cockpit.port}"
|
||||
"https://192.168.2.60:${toString config.services.cockpit.port}"
|
||||
];
|
||||
plugins = with pkgs; [
|
||||
cockpit-files
|
||||
cockpit-machines
|
||||
cockpit-podman
|
||||
cockpitFileSharing
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# Pi 5 / CM5 onboard Wi-Fi (brcmfmac). Without a regulatory domain the driver scans
|
||||
# disallowed channels and spams: brcmf_set_channel: set chanspec … fail, reason -52
|
||||
# (open raspberrypi/linux#6049). Wi-Fi often still works; logs and scans are noisy.
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
wifiCountry = "CA"; # change if you are not in Canada
|
||||
in
|
||||
{
|
||||
boot.kernelParams = [
|
||||
"cfg80211.ieee80211_regdom=${wifiCountry}"
|
||||
];
|
||||
|
||||
# Firmware country code (config.txt) — picked up before userspace regdom.
|
||||
hardware.raspberry-pi.extra-config = ''
|
||||
country=${wifiCountry}
|
||||
'';
|
||||
|
||||
# Apply regdom before NetworkManager starts scanning.
|
||||
systemd.services.wifi-regulatory-domain = {
|
||||
description = "Set Wi-Fi regulatory domain for brcmfmac";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "NetworkManager.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
script = ''
|
||||
${pkgs.iw}/bin/iw reg set ${wifiCountry}
|
||||
'';
|
||||
};
|
||||
|
||||
networking.networkmanager.wifi.powersave = false;
|
||||
networking.networkmanager.wifi.scanRandMacAddress = false;
|
||||
networking.networkmanager.connectionConfig."wifi.bgscan" = "0";
|
||||
}
|
||||
@@ -29,7 +29,9 @@
|
||||
|
||||
self.nixosModules."client-services"
|
||||
./_private/platform.nix
|
||||
./_private/wifi-brcmfmac.nix
|
||||
./_private/services.nix
|
||||
./_private/cockpit.nix
|
||||
./_private/activation.nix
|
||||
./_private/4g/default.nix
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user