FerroS3 is a high-performance, minimalist S3-compatible proxy written in Rust. It serves local filesystem directories as S3 buckets, providing a lightweight alternative to MinIO for resource-constrained environments like old FreeBSD kernels or embedded Linux.
- High Performance: Built on top of
TokioandAxumfor asynchronous I/O. - Full AWS SigV4 Support: Compatible with official AWS CLI, SDKs, and standard S3 clients.
- Modular Architecture: Clean, extensible code structure.
- In-Memory Stat Cache: Lightning-fast metadata retrieval using
DashMap. - Advanced Listing: Supports ListObjects v1/v2 with
prefixanddelimiter. - Streaming Support: Handles large file uploads and downloads (Range Requests) efficiently.
- Cross-Platform: Designed to run seamlessly on Linux, macOS, and FreeBSD.
- Zero External DB: Pure filesystem-backed storage.
- Operational Safeguards: Configurable request timeout (a hung storage mount fails the request instead of holding the connection) and configurable PUT
fsyncdurability. - Self-Cleaning Layout: A DELETE that empties a directory removes it, and every empty directory above it, so deleting a "folder" leaves no skeleton behind on the storage mount.
- Build Stamp: Every binary knows the revision it was built from and prints it on startup.
Check the Releases page for pre-built binaries for Linux and FreeBSD.
git clone https://github.com/mysamimi/ferros3.git
cd ferros3
cargo build --releaseThe build stamps the git revision and build time into the binary, and the server prints them as the first line of its log:
ferros3 0.1.0 | version v0.1.0-3-gabc1234 | commit abc123456789 | built 2026-09-06T12:00:00Z
When building outside a git checkout (for example inside a container that only has the
sources), set FERROS3_GIT_COMMIT and FERROS3_GIT_DESCRIBE to fill in those values;
otherwise they read unknown. A missing git never fails the build.
Copy config.yaml.example to config.yaml and adjust the values:
cp config.yaml.example config.yamlExample configuration:
port: 8080
endpoint: "0.0.0.0"
verbose: true
# Maximum number of entries in the object stat cache (older entries are evicted).
cache_size: 10000
# Fsync each uploaded object before acknowledging the PUT (default true). Set to false
# to trade crash durability for PUT latency when this proxy is not the source of truth.
fsync: true
# Give up on a request that hasn't produced a response within this many seconds, so a
# hung storage mount fails the request instead of holding the connection open forever.
# Set to 0 to disable. Uploads (PUT/POST) and response-body streaming are not bounded.
request_timeout_secs: 30
# Remove a directory left empty by a DELETE, and every empty directory above it (default
# true). Only ever removes empty directories; set to false if something outside FerroS3
# depends on those directories existing.
prune_empty_dirs: true
auth:
access_key: "YOUR_ACCESS_KEY"
secret_key: "YOUR_SECRET_KEY"
buckets:
- name: "my-bucket"
storage: "/path/to/local/data"config.yaml is read as a relative path, so the server must be started from the
directory that contains it. See API.md for the full option reference.
- Available only in non-production builds (
cargo run/ debug builds). - Live Swagger UI:
http://127.0.0.1:8080/docs - Live OpenAPI JSON:
http://127.0.0.1:8080/openapi.json - Human-readable API reference: API.md
- Static OpenAPI file: openapi.yaml
Swagger UI uses HTTP Basic auth:
- Username:
access_key - Password:
secret_key
To cross-compile for modern FreeBSD or Linux from a macOS/Windows host:
- Install
cross:cargo install cross --git https://github.com/cross-rs/cross.git
- Build for your target:
# For FreeBSD 12+ make build-freebsd # For Linux (x86_64) make build-linux
If you need to deploy FerroS3 to an older system (like FreeBSD 11.2 or older TrueNAS Core versions), standard cross-compilation will fail due to libc version mismatches.
We provide a dedicated Docker-based build pipeline and a small FreeBSD 11 compatibility shim for this target. Please see the Legacy FreeBSD Build Guide for detailed instructions.
make build-freebsd11 # or: ./build-freebsd11.shbuild-freebsd11.sh probes a list of Debian mirrors and builds the image against the
fastest reachable, up-to-date one (deb.debian.org is unusably slow on some networks).
Set DEBIAN_MIRROR and/or DEBIAN_SECURITY_MIRROR to skip the corresponding probe:
DEBIAN_MIRROR=https://deb.debian.org/debian ./build-freebsd11.shdocker build -t ferros3 .
docker run -p 8080:8080 -v ./config.yaml:/app/config.yaml -v ./data:/data ferros3Ready-to-use service units live in packaging/. Both assume the binary and
its config.yaml sit together in /app, because the config path is relative.
sudo install -D -m 755 target/release/ferros3 /app/ferros3
sudo cp config.yaml /app/config.yaml
sudo cp packaging/ferros3.service /etc/systemd/system/ferros3.service
sudo systemctl daemon-reload
sudo systemctl enable --now ferros3
journalctl -u ferros3 -finstall -m 755 target/x86_64-unknown-freebsd/release/ferros3 /app/ferros3
cp config.yaml /app/config.yaml
cp packaging/ferros3.rc /usr/local/etc/rc.d/ferros3
chmod 755 /usr/local/etc/rc.d/ferros3
sysrc ferros3_enable=YES
service ferros3 startThe rc script runs the server under daemon(8), which restarts it if it exits and
forwards its output to syslog under the ferros3 tag. Optional rc.conf overrides:
ferros3_dir (default /app) and ferros3_user (default root).
Run the test suite (including filesystem integration tests) with:
cargo test
# or
make testContributions are welcome! Whether it's a bug fix, a new feature, or improved documentation, we appreciate your help.
- Fork the repository and clone your fork.
- Create a feature branch:
git checkout -b feature/my-awesome-feature
- Make your changes.
Please make sure your changes pass the following checks:
cargo fmt --all # Format the code
cargo clippy -- -D warnings # Lint (treat warnings as errors)
cargo test # Run the test suite- Commit your changes with a clear, descriptive message.
- Push to your fork and open a Pull Request against the
mainbranch. - Describe what you changed and why. Link any related issues.
Found a bug or have a feature request? Please open an issue with:
- A clear description of the problem or request.
- Steps to reproduce (for bugs).
- Your platform (Linux / macOS / FreeBSD) and FerroS3 version.
This project is licensed under the MIT License.
