| Crates.io | fernfs |
| lib.rs | fernfs |
| version | 0.1.5 |
| created_at | 2026-01-03 19:57:27.356046+00 |
| updated_at | 2026-01-17 06:38:50.905681+00 |
| description | A Rust NFS Server implementation |
| homepage | https://github.com/lunixbochs/fernfs |
| repository | https://github.com/lunixbochs/fernfs |
| max_upload_size | |
| id | 2020714 |
| size | 1,016,972 |
A complete NFSv3 server implementation in Rust that allows you to export any custom file system over the network.
Add this to your Cargo.toml:
[dependencies]
fernfs = "0.0.0"
tokio = { version = "1.0", features = ["full"] }
The demo example creates an in-memory file system with some sample files:
cargo run --example demofs
Then mount it:
Linux:
mkdir /mnt/nfs
sudo mount -o proto=tcp,port=11111,mountport=11111,nolock,addr=127.0.0.1 127.0.0.1:/ /mnt/nfs
macOS:
mkdir /mnt/nfs
sudo mount_nfs -o nolocks,vers=3,tcp,rsize=131072,port=11111,mountport=11111 localhost:/ /mnt/nfs
Windows (Pro/Enterprise):
mount.exe -o anon,nolock,mtype=soft,fileaccess=6,casesensitive,lang=ansi,rsize=128,wsize=128,timeout=60,retry=2 \\127.0.0.1\\ X:
The fernfs binary exports an existing directory over NFS:
cargo install fernfs
fernfs /path/to/directory
For local development builds:
cargo run --bin fernfs -- /path/to/directory
-h, --host <HOST> Bind host (default: 127.0.0.1)-p, --port <PORT> Bind port (default: 11111)--allow-unprivileged-source-port Allow client source ports >= 1024 (default: require privileged)--help Show help and exitTo create a custom NFS server, implement the NFSFileSystem trait:
use fernfs::{tcp::NFSTcpListener, vfs::NFSFileSystem};
use async_trait::async_trait;
struct MyFileSystem {
// Your file system state
}
#[async_trait]
impl NFSFileSystem for MyFileSystem {
fn capabilities(&self) -> fernfs::vfs::Capabilities {
fernfs::vfs::Capabilities::ReadWrite
}
fn root_dir(&self) -> u64 {
1 // Root directory file ID
}
async fn lookup(&self, dirid: u64, filename: &[u8]) -> Result<u64, fernfs::nfs::nfsstat3> {
// Implement file lookup logic
todo!()
}
async fn getattr(&self, id: u64) -> Result<fernfs::nfs::fattr3, fernfs::nfs::nfsstat3> {
// Return file attributes
todo!()
}
// Implement other required methods...
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let fs = MyFileSystem::new();
let listener = NFSTcpListener::bind("127.0.0.1:11111", fs).await?;
listener.handle_forever().await?;
Ok(())
}
The library is structured into several key components:
vfs: Virtual File System trait that you implement for your storage backendtcp: TCP server that handles client connections and protocol dispatchprotocol: Internal implementation of NFS, MOUNT, and PORTMAP protocolsxdr: XDR (External Data Representation) encoding/decodingThe NFSFileSystem trait provides a clean abstraction with these key concepts:
This implementation follows these RFCs: