Files
nixos-config/hosts/common/features/smb-mounts.nix
T
Miguel Palhas 3c7a65b190
CI / lint (push) Successful in 1m21s
CI / eval (push) Failing after 2m29s
retroarch
2026-07-06 16:28:40 +01:00

93 lines
3.4 KiB
Nix

{
config,
lib,
pkgs,
...
}:
# Lazy, VPN-friendly SMB/CIFS automounts.
#
# Each entry becomes a systemd *automount* rather than a plain mount, so:
# * boot never hangs — nothing connects to the server at boot; only the
# lightweight .automount unit is installed (noauto + x-systemd.automount).
# * it mounts on first access — when something touches the mount point (e.g.
# RetroArch reading its save dir), systemd performs the real CIFS mount.
# * it's VPN-safe — a short mount-timeout means an access while the VPN is
# down fails fast instead of blocking, and the automount re-arms so the next
# access retries. Once wg-home is up, the next access succeeds. An idle
# timeout unmounts the share so it re-mounts fresh after a VPN drop (no
# stale handles).
#
# NOTE: wg-home is a NetworkManager connection managed outside the flake, so the
# mount deliberately does NOT depend on the wg interface unit — the on-access
# retry model needs no knowledge of when the VPN is up.
let
cfg = config.custom.smbMounts;
in
{
options.custom.smbMounts = lib.mkOption {
description = "Guest SMB/CIFS shares to expose as lazy, VPN-safe automounts.";
default = [ ];
type = lib.types.listOf (
lib.types.submodule {
options = {
server = lib.mkOption {
type = lib.types.str;
description = "SMB server host or IP (reachable over the VPN), e.g. \"10.10.0.1\".";
};
share = lib.mkOption {
type = lib.types.str;
description = "Share name on the server, e.g. \"retroarch\".";
};
mountPoint = lib.mkOption {
type = lib.types.str;
description = "Local mount point, e.g. \"/mnt/retroarch\".";
};
user = lib.mkOption {
type = lib.types.str;
default = "naps62";
description = "Local owner of the mounted files (CIFS uid/gid).";
};
idleTimeout = lib.mkOption {
type = lib.types.str;
default = "600";
description = "Seconds of inactivity before the share is unmounted.";
};
};
}
);
};
config = lib.mkIf (cfg != [ ]) {
# mount.cifs helper must be on PATH for systemd to perform the mount.
environment.systemPackages = [ pkgs.cifs-utils ];
fileSystems = lib.listToAttrs (
map (m: {
name = m.mountPoint;
value = {
device = "//${m.server}/${m.share}";
fsType = "cifs";
options = [
# --- guest auth (no credentials) ---
"guest"
# --- lazy, VPN-safe automount ---
"_netdev" # network fs: don't treat as a boot-blocking local mount
"noauto" # don't mount at boot…
"x-systemd.automount" # …mount on first access instead
"x-systemd.mount-timeout=10s" # fail fast if the server is unreachable
"x-systemd.idle-timeout=${m.idleTimeout}" # unmount when idle → fresh remount after VPN drop
"nofail" # never let a failed mount fault the system
# --- ownership / perms so ${m.user} can read+write ---
"uid=${m.user}"
"gid=users"
"file_mode=0664"
"dir_mode=0775"
# If the server is old and rejects the negotiated dialect, pin it,
# e.g. add "vers=1.0" and "sec=ntlm". Modern servers auto-negotiate.
];
};
}) cfg
);
};
}