fs-relay
Rootless Linux FUSE filesystem over HTTP and WebSockets, ~10x faster than s3fs and fuse-nfs
Why This Was Built
Sharing directories across machines or coding agents via NFS, SMB, or s3fs requires root privileges or complex firewall rules, suffers from high per-file round-trip latency, and corrupts SQLite databases due to missing or local-only POSIX locks.
The Architectural Answer
A rootless FUSE v3 mount over standard HTTP and WebSockets that batches small-file and directory prefetches, streams large files via splice pipes, and coordinates POSIX byte-range locks on the server so concurrent SQLite writers stay consistent.
Upstreamed to muayyad-alsadi/fs-relay
Muayyad Alsadi (@muayyadalsadi) created fs-relay to give Linux machines and cloud sandboxes a fast, rootless remote filesystem over plain HTTP without the per-file latency of s3fs or the fragility of NFS. He invited me to contribute to the project, where we collaborated on multi-mount SQLite POSIX locking, data-root safety, clean unmount handling, and the v0.2.0 release. Read the full background and benchmarks in Mounting Remote Disks Over Plain HTTP: Contributing to fs-relay.
-
https://github.com/muayyad-alsadi/fs-relay/pull/3 -
https://github.com/muayyad-alsadi/fs-relay/pull/17 -
https://github.com/muayyad-alsadi/fs-relay/pull/19 -
https://github.com/muayyad-alsadi/fs-relay/pull/20 -
https://github.com/muayyad-alsadi/fs-relay/pull/24 -
https://github.com/muayyad-alsadi/fs-relay/pull/33 -
https://github.com/muayyad-alsadi/fs-relay/pull/34 -
https://github.com/muayyad-alsadi/fs-relay/pull/35 -
https://github.com/muayyad-alsadi/fs-relay/pull/37 -
https://github.com/muayyad-alsadi/fs-relay/pull/38 -
https://github.com/muayyad-alsadi/fs-relay/pull/39 -
https://github.com/muayyad-alsadi/fs-relay/pull/40
Key Features & Architecture
How-To Guide
Install fs-relay and fs-relay-bind
Install both static pure-Go binaries (server and FUSE v3 client) onto your PATH, or build them from a local clone with just build. Ensure fuse3 (fusermount3) is installed on any Linux machine that will mount a share.
go install github.com/muayyad-alsadi/fs-relay/cmd/fs-relay@v0.2.0
go install github.com/muayyad-alsadi/fs-relay/cmd/fs-relay-bind@v0.2.0 Create a bearer token file and start the server
Write a shared secret to a mode-0600 file so the token never appears in process listings (ps aux), create the namespace directory under ./data/<namespace>/, and start fs-relay.
umask 077 && openssl rand -hex 32 > ./token.txt
mkdir -p ./data/myproject
fs-relay -listen 127.0.0.1:8080 -data ./data -token-file ./token.txt Mount a namespace on one or more Linux clients
Create an empty mountpoint directory and run fs-relay-bind. By default it uses a persistent WebSocket for low-latency RPCs and blocking lock wakeups; pass -post if your reverse proxy blocks WebSockets.
mkdir -p /tmp/demo
fs-relay-bind -url http://127.0.0.1:8080 -ns myproject -token-file ./token.txt /tmp/demo Run concurrent SQLite or DuckDB workloads across mounts
Point SQLite at the mounted directory using rollback journal mode (DELETE or TRUNCATE, which is SQLite's default). Server-side POSIX byte-range locks serialize writers across multiple mounts and flush/invalidate client caches at lock boundaries.
sqlite3 /tmp/demo/app.db "PRAGMA journal_mode=DELETE; CREATE TABLE IF NOT EXISTS runs (id INTEGER PRIMARY KEY, host TEXT); INSERT INTO runs (host) VALUES (hex(randomblob(4))); SELECT * FROM runs;" Unmount cleanly or self-update in place
Press Ctrl+C (SIGINT) or send SIGTERM to fs-relay-bind: it attempts a clean unmount within 2 seconds and falls back to a lazy detach (fusermount3 -uz) if a process still holds an open file. To upgrade both binaries in place with SHA-256 verification and automatic rollback, run fs-relay update.
fusermount3 -u /tmp/demo
fs-relay update Technical Specifications
- Primary Languages
- Go
- Frameworks & Tooling
- go-fuseGoogle FlatBuffers
- Architecture & Execution Model
- 5-package pure Go design (CGO_ENABLED=0): FUSE v3 client with batch small-file/dir prefetching and 1 MiB write-behind, FlatBuffers over HTTP/WebSockets, raw splice socket, and server-side POSIX lock table
- Licensing Model
- Dual: MIT / WaqfDPL-1.0 (permissive)
- Release & Lineage
- Active release cycle since 2026 · Maintained by @JadMadi
Frequently Asked Questions
Why use fs-relay instead of NFS, SSHFS, or s3fs?
Muayyad Alsadi (@muayyadalsadi) designed fs-relay so remote folders mount over standard HTTP and WebSockets without root, VPNs, or kernel modules, while batching small-file and directory prefetches to run ~10x faster than s3fs and fuse-nfs on source-tree workloads.
Does fs-relay support concurrent SQLite access across mounts?
Yes, in rollback journal mode (DELETE or TRUNCATE). The server coordinates POSIX byte-range locks across mounts, and fs-relay-bind drains buffered writes before unlocking and invalidates cached bytes on lock grant. WAL mode is not supported because it requires shared memory (mmap) across hosts.
Do I need root access or kernel modules to run it?
No. Both fs-relay and fs-relay-bind are pure Go static binaries (CGO_ENABLED=0) that run as an unprivileged user on Linux with FUSE v3 (fusermount3).