feat(ai): add webdav mount (#253)

feat(aquamarine): add group for filesharing, protect /data on subvolume mount failures
This commit is contained in:
Ryan Yin
2026-03-19 22:25:48 +08:00
committed by GitHub
parent 94e4598681
commit b143a89443
7 changed files with 74 additions and 51 deletions

6
flake.lock generated
View File

@@ -583,10 +583,10 @@
"mysecrets": {
"flake": false,
"locked": {
"lastModified": 1773850740,
"narHash": "sha256-izDf+wgii0KGAfNZ3/RFt2HJgUY/s+u8qKyKvNi0uGc=",
"lastModified": 1773927262,
"narHash": "sha256-nxx7jAiHGTYU6hXdjHYjdR1SJNgFcVPokiFlR8MZwTc=",
"ref": "refs/heads/main",
"rev": "86de5313787257806723f03dccabd52bb7501ff3",
"rev": "c388ca33beb5c099bf4603e6ab25a2e94af00b80",
"shallow": true,
"type": "git",
"url": "ssh://git@github.com/ryan4yin/nix-secrets.git"

View File

@@ -1,38 +1,25 @@
{
config,
myvars,
...
}:
{
# supported file systems, so we can mount any removable disks with these filesystems
boot.supportedFilesystems = [
# "cifs"
"davfs"
];
# mount a smb/cifs share
# fileSystems."/home/${myvars.username}/SMB-Downloads" = {
# device = "//windows-server-nas/Downloads";
# fsType = "cifs";
# options = [
# # https://www.freedesktop.org/software/systemd/man/latest/systemd.mount.html
# "nofail,_netdev"
# "uid=1000,gid=100,dir_mode=0755,file_mode=0755"
# "vers=3.0,credentials=${config.age.secrets.smb-credentials.path}"
# ];
# };
# enable davfs2 driver for webdav
services.davfs2.enable = true;
# mount a webdav share
# https://wiki.archlinux.org/title/Davfs2
# fileSystems."/home/${myvars.username}/webdav-downloads" = {
# device = "https://webdav.writefor.fun/Downloads";
# fsType = "davfs";
# options = [
# # https://www.freedesktop.org/software/systemd/man/latest/systemd.mount.html
# "nofail,_netdev"
# "uid=1000,gid=100,dir_mode=0755,file_mode=0755"
# ];
# };
fileSystems."/mnt/fileshare" = {
device = "https://webdav.writefor.fun/";
fsType = "davfs";
options = [
# https://www.freedesktop.org/software/systemd/man/latest/systemd.mount.html
"nofail,_netdev"
"uid=1000,gid=100,dir_mode=0750,file_mode=0750"
];
};
# davfs2 reads its credentials from /etc/davfs2/secrets
# environment.etc."davfs2/secrets".source = config.age.secrets."davfs-secrets".path;
environment.etc."davfs2/secrets" = {
source = config.age.secrets."davfs-secrets".path;
mode = "0600";
};
}

View File

@@ -7,6 +7,30 @@ let
unlockDisk = "data-encrypted";
in
{
# Bind-mount a dedicated backing directory (/data-ro) onto /data as read-only.
# Using a separate source instead of a self-bind avoids the duplicate mount
# entries that a self-bind (device == mountpoint) would produce in lsblk.
# Disk subvolumes (/data/apps, /data/fileshare, …) are mounted on top by
# systemd automatically (path-hierarchy ordering). If any subvolume fails
# (nofail), its subdirectory falls back to this read-only layer and ALL
# writes — including root — are rejected with EROFS.
fileSystems."/data" = {
device = "/data-ro";
fsType = "none";
options = [
"bind"
"ro"
];
};
# Pre-create the backing directory and subvolume mountpoints on the root
# filesystem. activation runs before sysinit.target (before all mount
# units), and writes to /data-ro (not the ro-mounted /data), so this is
# safe to re-run on nixos-rebuild switch.
system.activationScripts.data-ro-backing.text = ''
mkdir -p /data-ro/fileshare /data-ro/apps /data-ro/backups /data-ro/apps-snapshots
'';
fileSystems."/data/fileshare/public".depends = [ "/data/fileshare" ];
# By adding this crypttab entry, the disk will be unlocked by systemd-cryptsetup@xxx.service at boot time.

View File

@@ -5,12 +5,21 @@ let
in
{
# Read SFTPGO_DEFAULT_ADMIN_USERNAME and SFTPGO_DEFAULT_ADMIN_PASSWORD from a file
systemd.services.sftpgo.serviceConfig.EnvironmentFile = config.age.secrets."sftpgo.env".path;
systemd.services.sftpgo.serviceConfig = {
EnvironmentFile = config.age.secrets."sftpgo.env".path;
};
# Join the shared fileshare group (defined globally in user-group.nix) so
# sftpgo can read/write files created by transmission, and vice versa.
users.users.${user}.extraGroups = [ "fileshare" ];
# Create Directories
# https://www.freedesktop.org/software/systemd/man/latest/tmpfiles.d.html#Type
# Mode 2775: setgid ensures new files/dirs inherit the 'fileshare' group
# regardless of the creating process's primary group.
systemd.tmpfiles.rules = [
"d ${dataDir} 0755 ${user} ${user}"
"d ${dataDir} 0755 ${user} ${user} -"
"d /data/fileshare/public 2775 root fileshare -"
];
services.sftpgo = {

View File

@@ -9,6 +9,17 @@ let
name = "transmission";
in
{
# Join the shared fileshare group so transmission can read/write files
# created by sftpgo, and vice versa (via setgid directories).
users.users.${name}.extraGroups = [ "fileshare" ];
# Set up transmission's home dir with setgid + fileshare group ownership.
# The setgid bit (2) causes all files created here to inherit the group
# 'fileshare', regardless of which service creates them.
systemd.tmpfiles.rules = [
"d ${dataDir} 2775 ${name} fileshare -"
];
# the headless Transmission BitTorrent daemon
# https://github.com/NixOS/nixpkgs/blob/nixos-25.11/nixos/modules/services/torrent/transmission.nix
# https://wiki.archlinux.org/title/transmission
@@ -18,7 +29,8 @@ in
user = name;
group = name;
home = dataDir;
downloadDirPermissions = "0770";
# 2770: setgid preserves fileshare group on download/incomplete dirs.
downloadDirPermissions = "2770";
# Whether to enable tweaking of kernel parameters to open many more connections at the same time.
# Note that you may also want to increase peer-limit-global.

View File

@@ -19,6 +19,9 @@
plugdev = { };
# misc
uinput = { };
# shared group for services that read/write the same data directory
# (e.g. sftpgo + transmission on aquamarine)
fileshare = { };
};
users.users."${myvars.username}" = {
@@ -36,6 +39,7 @@
"wireshark"
"adbusers" # android debugging
"libvirtd" # virt-viewer / qemu
"fileshare"
];
};

View File

@@ -99,19 +99,11 @@ in
}
// noaccess;
# ---------------------------------------------
# only root can read this file.
# ---------------------------------------------
"wg-business.conf" = {
file = "${mysecrets}/wg-business.conf.age";
}
// high_security;
# Used only by NixOS Modules
# smb-credentials is referenced in /etc/fstab, by ../hosts/ai/cifs-mount.nix
"smb-credentials" = {
file = "${mysecrets}/smb-credentials.age";
# referenced in /etc/fstab to mount davfs volume
"davfs-secrets" = {
file = "${mysecrets}/davfs-secrets.age";
}
// high_security;
@@ -138,11 +130,6 @@ in
# place secrets in /etc/
environment.etc = {
# wireguard config used with `wg-quick up wg-business`
"wireguard/wg-business.conf" = {
source = config.age.secrets."wg-business.conf".path;
};
"agenix/rclone.conf" = {
source = config.age.secrets."rclone.conf".path;
};