home-lab/research/nfs.md
Geir Okkenhaug Jerstad c3d1333538 Fix NFS configuration: Remove ZFS mount point conflict with tmpfiles
- Remove /mnt/storage/media from systemd.tmpfiles.rules (it's a ZFS dataset mount point)
- Add ExecStartPost to set proper permissions on ZFS-mounted media directory
- Update NFS research documentation with ZFS integration best practices
- Add section explaining ZFS mount point vs tmpfiles.rules conflicts

This resolves the potential conflict where tmpfiles tries to create a directory
that ZFS wants to use as a mount point for the storage/media dataset.
2025-06-11 10:12:51 +02:00

675 lines
19 KiB
Markdown

# NFS Best Practices and Troubleshooting Guide
## Overview
Network File System (NFS) is a distributed file system protocol that allows remote file access over a network. This document outlines best practices for configuring NFS in a home lab environment, focusing on permission management, security, and performance optimization.
## Current Configuration Analysis
### Identified Issues
1. **Missing User ID Mapping**: The current configuration doesn't ensure consistent UIDs/GIDs between server and clients
2. **Security Concerns**: Using `no_root_squash` poses security risks
3. **No ID Mapping Configuration**: NFSv4 ID mapping is not configured
4. **Missing Export Options**: Several important security and performance options are not set
## NFS Permission Management Best Practices
### 1. User and Group ID Consistency
**Problem**: NFS relies on UID/GID matching between server and clients. If a user has UID 1000 on the server but UID 1001 on the client, permission issues will occur.
**Solutions**:
#### Option A: Synchronized UIDs/GIDs (Recommended for Home Lab)
- Ensure the `media` group has the same GID (993) on all machines
- Create users with consistent UIDs across all systems
- Use centralized user management (LDAP/AD) for larger setups
#### Option B: NFSv4 ID Mapping
Configure NFSv4 ID mapping to translate between different UID/GID spaces:
```nix
# On both server and clients
services.rpcbind.enable = true;
services.nfs.idmapd = {
enable = true;
settings = {
General = {
Domain = "home.lab"; # Same domain on all machines
Verbosity = 0;
};
Mapping = {
Nobody-User = "nobody";
Nobody-Group = "nogroup";
};
};
};
```
#### Option C: Use all_squash for Public Shares
For truly shared directories where ownership doesn't matter:
```nix
exports = ''
/mnt/storage/shares 10.0.0.0/24(rw,sync,all_squash,anonuid=993,anongid=993)
'';
```
### 2. Security Best Practices
#### Root Squashing (Critical)
**Current Issue**: Using `no_root_squash` allows root on clients to access files as root on the server.
**Fix**: Use root squashing by default and only disable when absolutely necessary:
```nix
exports = ''
# Default: root_squash is enabled (secure)
/mnt/storage/media 10.0.0.0/24(rw,sync,no_subtree_check,root_squash)
# Only for trusted admin workstations
/mnt/storage/backups 10.0.0.100(rw,sync,no_subtree_check,no_root_squash)
'';
```
#### Port Security
Always use the `secure` option (enabled by default) to restrict access to privileged ports:
```nix
exports = ''
/mnt/storage/media 10.0.0.0/24(rw,sync,secure,no_subtree_check)
'';
```
#### Client Mount Security
On client systems, use security options:
```bash
# Mount with nosuid to prevent privilege escalation
mount -t nfs -o nosuid,nodev server:/mnt/storage/media /mnt/media
# In /etc/fstab
server:/mnt/storage/media /mnt/media nfs nosuid,nodev,rw,hard,timeo=600 0 0
```
### 3. Export Options Explained
#### Permission and Security Options
- `root_squash`: Map root UID to anonymous user (default, secure)
- `no_root_squash`: Allow root access (use carefully)
- `all_squash`: Map all users to anonymous user
- `anonuid=N`: Set anonymous user UID
- `anongid=N`: Set anonymous group GID
#### Performance Options
- `sync`: Writes are committed before responding (safer, slower)
- `async`: Writes may be cached (faster, less safe)
- `no_wdelay`: Don't delay writes (for small random writes)
#### Access Control Options
- `rw`: Read-write access
- `ro`: Read-only access
- `secure`: Only accept requests from privileged ports (default)
- `insecure`: Accept requests from any port
#### Filesystem Options
- `no_subtree_check`: Don't verify file is in exported subtree (recommended)
- `subtree_check`: Verify file location (slight security benefit, performance cost)
## Recommended NFS Configuration
### Server Configuration (nfs.nix)
```nix
{
config,
pkgs,
...
}: {
imports = [
../../modules/users/media-group.nix
];
# NFSv4 ID mapping
services.rpcbind.enable = true;
services.nfs.idmapd = {
enable = true;
settings = {
General = {
Domain = "home.lab";
Verbosity = 0;
};
Mapping = {
Nobody-User = "nobody";
Nobody-Group = "nogroup";
};
};
};
# NFS server configuration
services.nfs.server = {
enable = true;
# Optimized exports with proper security
exports = ''
# Main storage - root squashed for security
/mnt/storage 10.0.0.0/24(rw,sync,no_subtree_check,crossmnt) 100.64.0.0/10(rw,sync,no_subtree_check,crossmnt)
# Media directory - accessible to media group
/mnt/storage/media 10.0.0.0/24(rw,sync,no_subtree_check,root_squash) 100.64.0.0/10(rw,sync,no_subtree_check,root_squash)
# Downloads - squash all users to media group
/mnt/storage/downloads 10.0.0.0/24(rw,sync,no_subtree_check,all_squash,anonuid=993,anongid=993) 100.64.0.0/10(rw,sync,no_subtree_check,all_squash,anonuid=993,anongid=993)
# Backups - admin only with root access
/mnt/storage/backups 10.0.0.100(rw,sync,no_subtree_check,no_root_squash)
# Public shares - anonymous access
/mnt/storage/shares 10.0.0.0/24(rw,sync,no_subtree_check,all_squash,anonuid=993,anongid=993) 100.64.0.0/10(ro,sync,no_subtree_check,all_squash)
'';
createMountPoints = true;
};
# Directory permissions and ownership
# IMPORTANT: Only create directories that are NOT ZFS mount points with tmpfiles
# ZFS mount points must have their permissions set after mounting
systemd.tmpfiles.rules = [
# Only create non-ZFS directories - media is a ZFS dataset mount point
"d /mnt/storage/downloads 2775 media media -" # Owned by media group
"d /mnt/storage/backups 0750 root root -" # Admin only
"d /mnt/storage/shares 2775 media media -" # Public access via media group
];
# Set permissions on ZFS-mounted datasets after they're mounted
systemd.services.nfs-server.serviceConfig.ExecStartPost = [
"${pkgs.coreutils}/bin/chown root:media /mnt/storage/media"
"${pkgs.coreutils}/bin/chmod 2775 /mnt/storage/media"
];
# Performance tuning
boot.kernel.sysctl = {
# Increase NFS server thread count for better performance
"fs.nfs.nlm_tcpport" = 32768;
"fs.nfs.nlm_udpport" = 32768;
};
# Required packages
environment.systemPackages = with pkgs; [
nfs-utils
];
# Firewall configuration
networking.firewall = {
allowedTCPPorts = [
111 # portmapper
2049 # nfsd
32768 # lockd
];
allowedUDPPorts = [
111 # portmapper
2049 # nfsd
32768 # lockd
];
};
}
```
### Client Configuration
```nix
# Enable NFS client services
services.rpcbind.enable = true;
services.nfs.idmapd = {
enable = true;
settings = {
General = {
Domain = "home.lab"; # Must match server
};
};
};
# Example mount in /etc/fstab
# server:/mnt/storage/media /mnt/media nfs4 rw,hard,timeo=600,retrans=5,_netdev,nosuid 0 0
```
## NixOS-Specific NFS Research
### NFS Service Configuration in NixOS
NixOS provides declarative configuration for both NFS servers and clients through the `services.nfs` module. The configuration is highly modular and allows for comprehensive setup of NFS services.
#### Key NixOS NFS Modules and Options
Based on the nixpkgs documentation, NFS configuration in NixOS involves several key components:
1. **Basic NFS Support**:
```nix
boot.supportedFilesystems = [ "nfs" ];
services.rpcbind.enable = true;
```
2. **NFS Server Configuration**:
- `services.nfs.server.enable` - Enable NFS server
- `services.nfs.server.exports` - Define export configurations
- `services.nfs.server.createMountPoints` - Auto-create mount points
- `services.nfs.server.threads` - Number of NFS daemon threads
3. **NFS Client Configuration**:
- `services.rpcbind.enable` - Required for NFS client operations
- `services.nfs.idmapd` - NFSv4 ID mapping service
- `fileSystems` - Declarative mount point definitions
4. **NFSv4 ID Mapping**:
```nix
services.nfs.idmapd = {
enable = true;
settings = {
General = {
Domain = "home.lab";
Verbosity = 0;
};
Mapping = {
Nobody-User = "nobody";
Nobody-Group = "nogroup";
};
};
};
```
#### NixOS Advantages for NFS
1. **Declarative Configuration**: All NFS settings are defined in configuration files, making them reproducible and version-controlled.
2. **Automatic Service Dependencies**: NixOS automatically handles service dependencies (rpcbind, nfsd, mountd, etc.).
3. **Integrated Firewall Management**: Firewall rules can be declared alongside NFS configuration.
4. **Atomic Updates**: Configuration changes are applied atomically, reducing the risk of service disruption.
5. **Rollback Capability**: Previous configurations can be easily restored if issues occur.
### NixOS NFS Implementation Patterns
#### Pattern 1: Single-Host NFS Server
```nix
{
services.nfs.server = {
enable = true;
exports = ''
/mnt/storage 192.168.1.0/24(rw,sync,no_subtree_check)
'';
createMountPoints = true;
};
networking.firewall.allowedTCPPorts = [ 111 2049 ];
networking.firewall.allowedUDPPorts = [ 111 2049 ];
}
```
#### Pattern 2: NFS Client with Declarative Mounts
```nix
{
boot.supportedFilesystems = [ "nfs" ];
services.rpcbind.enable = true;
fileSystems."/mnt/nfs-share" = {
device = "server.local:/mnt/storage";
fsType = "nfs";
options = [ "rw" "hard" "timeo=600" "_netdev" ];
};
}
```
#### Pattern 3: High-Security NFS with Kerberos
```nix
{
security.krb5 = {
enable = true;
package = pkgs.krb5;
settings = {
libdefaults.default_realm = "HOME.LAB";
realms."HOME.LAB" = {
kdc = "kerberos.home.lab";
admin_server = "kerberos.home.lab";
};
};
};
services.nfs.server = {
enable = true;
exports = ''
/secure/data 192.168.1.0/24(rw,sync,sec=krb5p,no_subtree_check)
'';
};
}
```
## Implementation Plan
### Phase 1: Basic NFS Server Setup (Week 1)
#### Objectives
- Set up basic NFS server on `sleeper-service`
- Configure secure exports with proper permission management
- Establish client connectivity from other home lab machines
#### Tasks
**1.1 Update sleeper-service NFS Configuration**
- Location: `machines/sleeper-service/nfs.nix`
- Actions:
- Enable NFSv4 ID mapping service
- Configure secure export options
- Set up proper directory permissions with systemd tmpfiles
- Add performance tuning parameters
**1.2 Create Media Group Module Enhancement**
- Location: `modules/users/media-group.nix`
- Actions:
- Ensure consistent GID (993) across all machines
- Add group-specific directory management
- Configure proper setgid permissions
**1.3 Client Configuration Module**
- Location: `modules/services/nfs-client.nix` (new)
- Actions:
- Create reusable NFS client configuration
- Include NFSv4 ID mapping setup
- Add common mount options and security settings
**1.4 Update Machine Configurations**
- Locations:
- `machines/congenital-optimist/configuration.nix`
- `machines/grey-area/configuration.nix`
- Actions:
- Import NFS client module
- Add declarative mount points for shared storage
- Configure firewall rules
#### Deliverables
- [ ] Updated `sleeper-service/nfs.nix` with secure configuration
- [ ] New `modules/services/nfs-client.nix` module
- [ ] Enhanced `modules/users/media-group.nix`
- [ ] Client configurations for all machines
- [ ] Documentation updates in this file
### Phase 2: Security Hardening (Week 2)
#### Objectives
- Implement security best practices
- Set up proper access controls
- Configure monitoring and logging
#### Tasks
**2.1 Security Enhancement**
- Actions:
- Implement root squashing by default
- Configure all_squash for public shares
- Set up proper anonymous user mapping
- Review and minimize export permissions
**2.2 Network Security**
- Actions:
- Configure UFW/iptables rules for NFS ports
- Set up VPN-only access for sensitive shares
- Implement port restrictions (secure option)
**2.3 Monitoring Setup**
- Location: `modules/services/nfs-monitoring.nix` (new)
- Actions:
- Set up NFS statistics collection
- Configure log monitoring for access patterns
- Create alerting for failed mount attempts
#### Deliverables
- [ ] Security-hardened NFS configuration
- [ ] Network security rules
- [ ] Monitoring and alerting system
- [ ] Security audit documentation
### Phase 3: Performance Optimization (Week 3)
#### Objectives
- Optimize NFS performance for home lab workloads
- Implement caching strategies
- Tune network and filesystem parameters
#### Tasks
**3.1 Server Performance Tuning**
- Actions:
- Increase NFS daemon threads
- Optimize kernel parameters for NFS
- Configure appropriate read/write sizes
- Set up async vs sync based on use case
**3.2 Client Optimization**
- Actions:
- Configure optimal mount options
- Set up client-side caching
- Tune timeout and retry parameters
**3.3 Network Optimization**
- Actions:
- Optimize TCP window sizes
- Configure jumbo frames if supported
- Set up link aggregation if available
#### Deliverables
- [ ] Performance-optimized server configuration
- [ ] Client performance tuning
- [ ] Network optimization settings
- [ ] Performance benchmarking results
### Phase 4: Advanced Features (Week 4)
#### Objectives
- Implement advanced NFS features
- Set up backup and disaster recovery
- Create automation and maintenance tools
#### Tasks
**4.1 NFSv4 Advanced Features**
- Actions:
- Implement NFSv4 ACLs where appropriate
- Set up NFSv4 referrals for distributed storage
- Configure NFSv4 migration support
**4.2 Backup Integration**
- Actions:
- Set up NFS-aware backup procedures
- Configure snapshot-based backups for ZFS
- Implement cross-site backup replication
**4.3 Automation and Maintenance**
- Location: `scripts/nfs-maintenance.sh` (new)
- Actions:
- Create automated health checks
- Set up export verification scripts
- Implement automatic client discovery
#### Deliverables
- [ ] Advanced NFSv4 features configuration
- [ ] Integrated backup solution
- [ ] Automation scripts and tools
- [ ] Maintenance procedures documentation
### Implementation Steps
#### Step 1: Prepare the Environment
```bash
# Clone the repository and create feature branch
cd /home/geir/Home-lab
git checkout -b feature/nfs-implementation
# Create new module directories
mkdir -p modules/services
```
#### Step 2: Create Base NFS Client Module
```nix
# modules/services/nfs-client.nix
{ config, lib, pkgs, ... }:
with lib;
{
imports = [
../users/media-group.nix
];
config = {
boot.supportedFilesystems = [ "nfs" ];
services.rpcbind.enable = true;
services.nfs.idmapd = {
enable = true;
settings = {
General = {
Domain = "home.lab";
Verbosity = 0;
};
};
};
environment.systemPackages = with pkgs; [
nfs-utils
];
};
}
```
#### Step 3: Update sleeper-service Configuration
Update the existing `machines/sleeper-service/nfs.nix` with the comprehensive configuration shown in the recommended section above.
#### Step 4: Test and Validate
```bash
# Build and test the configuration
sudo nixos-rebuild test
# Verify NFS services
systemctl status nfs-server
exportfs -v
# Test client connectivity
showmount -e sleeper-service
```
#### Step 5: Deploy to Other Machines
```bash
# Update each machine configuration
# Add imports and mount points
# Test connectivity from each client
```
### Risk Mitigation
#### Configuration Backup
- Always backup working configurations before changes
- Use git branches for experimental configurations
- Test changes on non-production machines first
#### Service Dependencies
- Ensure proper service ordering in systemd
- Handle network dependencies correctly
- Plan for graceful degradation if NFS is unavailable
#### Data Protection
- Implement proper backup strategies before enabling NFS
- Use read-only mounts for critical data initially
- Set up monitoring for unauthorized access
### Success Criteria
#### Phase 1 Success Criteria
- [ ] NFS server running on sleeper-service
- [ ] All home lab machines can mount shared storage
- [ ] Proper permissions for media group access
- [ ] Basic security measures in place
#### Phase 2 Success Criteria
- [ ] Security audit passes with no critical issues
- [ ] Monitoring system reports normal operations
- [ ] Access controls prevent unauthorized access
#### Phase 3 Success Criteria
- [ ] Performance benchmarks show acceptable speeds
- [ ] No timeout or connection issues under normal load
- [ ] Network utilization optimized
#### Phase 4 Success Criteria
- [ ] Advanced features working as expected
- [ ] Backup and recovery procedures tested
- [ ] Automation reduces manual maintenance
This implementation plan provides a structured approach to deploying NFS in your NixOS home lab environment, with proper security, performance, and maintainability considerations.
## ZFS and NFS Integration
### Important Considerations
When using ZFS datasets as NFS export points, there are several important considerations:
#### ZFS Mount Points vs tmpfiles.rules
**Critical Issue**: Do not use `systemd.tmpfiles.rules` to create directories that are ZFS dataset mount points. This can cause conflicts and permission issues.
**Example Problem**:
```nix
# WRONG - Don't do this if /mnt/storage/media is a ZFS dataset
systemd.tmpfiles.rules = [
"d /mnt/storage/media 2775 root media -" # This conflicts with ZFS mounting
];
```
**Correct Approach**:
```nix
# Only create directories that are NOT ZFS mount points
systemd.tmpfiles.rules = [
"d /mnt/storage/downloads 2775 media media -" # Regular directory
"d /mnt/storage/backups 0750 root root -" # Regular directory
];
# Set permissions on ZFS mount points after mounting
systemd.services.nfs-server.serviceConfig.ExecStartPost = [
"${pkgs.coreutils}/bin/chown root:media /mnt/storage/media"
"${pkgs.coreutils}/bin/chmod 2775 /mnt/storage/media"
];
```
#### ZFS Dataset Structure for NFS
A typical ZFS layout for NFS exports might look like:
```
storage # Pool (mounted at /mnt/storage)
├── storage/media # Dataset (mounted at /mnt/storage/media)
├── storage/backups # Dataset (mounted at /mnt/storage/backups)
└── Regular directories: # Created with tmpfiles.rules
├── downloads/
└── shares/
```
#### Service Dependencies
Ensure NFS services start after ZFS mounting:
```nix
systemd.services.nfs-server = {
after = [ "zfs-mount.service" ];
wants = [ "zfs-mount.service" ];
};
```
#### ZFS Native NFS Sharing
ZFS supports native NFS sharing, but NixOS typically uses the Linux kernel NFS server. For ZFS native sharing:
```bash
# Enable ZFS native NFS (alternative approach)
zfs set sharenfs="rw=@10.0.0.0/24,root=10.0.0.100" storage/media
```
However, the recommended approach for NixOS is to use the kernel NFS server with ZFS as the underlying filesystem.