FileFerry
FileFerry is a terminal-native local file transfer tool for moving files
between machines on the same network without a cloud account, relay, or GUI.
The command is ferry.
It is built around a single binary for Linux, macOS, and Windows that can:
- Discover nearby peers automatically on the local network.
- Send files and directories over a native QUIC fast path between
ferryinstances. - Receive transfers in foreground, TUI, or daemon mode.
- Provide clean human output by default and newline-delimited JSON when used from scripts.
FileFerry is pre-1.0, but the native binary already supports native mDNS peer
discovery, direct-address and peer-targeted QUIC transfer, manifest-backed
skip/resume, scriptable CLI output, long-running daemon receive mode, an
interactive TUI send flow, foreground Ctrl+C transfer cancellation with
partial-file cleanup, trust-on-first-use prompting and persistence for first
contact, release packaging automation, and the public website. The remaining
build plan lives in BUILD.md.
The public project site is live at https://fileferry.app/.
A separate web send portal is planned for send.fileferry.app after the
native CLI, TUI, daemon, release, and documentation foundations are solid.
Why
Local file transfer tools proved that discovery, trust, and receiving files
can feel simple. ferry brings that simplicity to a fast, scriptable,
terminal-native workflow.
FileFerry fills that gap:
- Move large files between machines at LAN line rate.
- Use aliases, fingerprint prefixes, or direct addresses instead of copy-paste URLs.
- Run interactively when you want a file picker and transfer queue.
- Run quietly and predictably in scripts, SSH sessions, cron jobs, and headless machines.
Quick Start
JSON mode is designed for tools:
Events are emitted as one JSON object per line, including version, transfer start, progress, completion, cancellation, and failure events for implemented commands.
Architecture
The project is one Cargo workspace with focused crates:
crates/
ferry-core/ protocol, transport, discovery, crypto, filesystem engine
ferry-cli/ clap CLI, progress output, JSON events, daemon commands
ferry-tui/ ratatui interactive interface
ferry-site/ public fileferry.app project website (Leptos + Axum SSR)
ferry-send-web/ future send.fileferry.app web portal
xtask/ build, release, benchmark, and packaging automation
ferry-site is self-contained: its CSS and favicon are embedded with
include_str!, it listens on plain HTTP at FERRY_SITE_ADDR (default
127.0.0.1:3000), and the Ubuntu + Caddy deployment is documented in
docs/site-deployment.md. The native ferry
binary does not depend on the site at runtime.
ferry-core owns all network, protocol, filesystem, discovery, trust, and
resume behavior. Frontends should stay thin.
Discovery
FileFerry advertises and browses native peers with mDNS:
- Service:
_ferry._udp.local - TXT records: protocol version, transport support, fingerprint, alias, and ports
Discovered peers are unified into a single registry keyed by fingerprint. Aliases, hostnames, and fingerprint prefixes are lookup hints only.
Transport
Native ferry transfers use QUIC via quinn. The current protocol uses one
QUIC connection and one bidirectional stream per transfer session for
negotiation, manifest, receive plan, payload, and acknowledgement frames.
Transport selection is automatic:
- Discovered
ferrypeer: QUIC. - Direct address: QUIC.
Resume
Every transfer starts with a manifest containing session id, file entries, sizes, hashes, permissions where supported, and modification times.
The receiver compares the manifest against the destination:
- Existing matching file: skip.
- Matching partial file: resume from verified offset.
- Anything else: transfer from byte zero.
BLAKE3 is used because it is fast, parallel-friendly, and suitable for cheap prefix verification.
Trust
FileFerry's target native trust model is trust-on-first-use:
- A persistent device key is generated on first run.
- Self-signed TLS certificates identify peers by public key fingerprint.
- First contact shows a short fingerprint for user confirmation.
- Known peers are pinned in the platform config directory.
ferry peers trustcan pin a full fingerprint or a discovered peer resolved by alias, hostname, or unique fingerprint prefix.ferry identityprints the local alias and full device fingerprint for explicit inspection or out-of-band confirmation.- Discovered-peer sends and TUI sends require the receiver certificate fingerprint to match the discovered peer fingerprint before payload bytes are sent.
- Direct-address sends can require a specific receiver certificate with
ferry send --fingerprint <full-fingerprint> <ip:port> <path>. - Scripted and headless workflows can require an explicit PSK with
--psk-fileor the redactedtrust.pskconfig field.
Important current limitation: the transfer path is encrypted, persistent
identity and trust-store commands exist, and discovered-peer sends now verify
the advertised fingerprint before payload. Direct-address sends can be pinned
with an explicitly confirmed fingerprint, and unknown direct-address receivers
are now confirmed before any manifest or payload bytes are sent when the sender
is interactive. Non-interactive first contact should use ferry peers trust,
--fingerprint, or an explicit policy change in config. Explicit PSK mode
exists for scripted/headless workflows, but it is opt-in and must be configured
on both peers. See
docs/security.md for the exact current boundary.
Target Commands
ferry send <peer> <path>... Send files or directories
ferry recv [--accept-all] Receive in foreground
ferry recv --dest <dir> Receive into a specific directory
ferry peers List discovered peers
ferry peers trust <fingerprint> Trust a peer fingerprint
ferry peers forget <fingerprint> Remove a known peer
ferry daemon Run as a background receiver
ferry config Print or edit configuration
ferry identity Print the local alias and fingerprint
ferry version Print version information
ferry tui Force interactive TUI mode
Global flags:
--port <PORT> Override default listen port
--bind <IFACE> Bind to a specific interface
--json Emit newline-delimited JSON events
--no-discovery Disable discovery
--quiet, -q Reduce output
--verbose, -v Increase output
Send-specific flags:
--fingerprint <FINGERPRINT> Require a direct-address receiver certificate
to match this full fingerprint
--psk-file <FILE> Read an explicit transfer PSK from a file
Planned exit codes:
0 success
1 generic error
2 peer not found
3 peer rejected transfer
4 transfer started but failed mid-flight
5 config or permission error
Configuration
ferry uses platform-native config directories through directories.
Example:
= "stephen-desktop"
= 53317
= 53318
= "~/Downloads/ferry"
= true
= false
= ["native"]
= 8
[]
= true
= ""
Web Surfaces
The public project website is fileferry.app. It is
a Rust web app built with Leptos and Axum, deployed separately from the native
binary.
The later hosted send portal at send.fileferry.app is a separate product
surface. It is not part of the v1 LAN boundary and must keep its own trust,
relay, retention, abuse, and operating-cost design before any hosted transfer
capability ships.
Performance Targets
On commodity desktop hardware with NVMe storage and 1GbE:
- Single large file: at least 110 MB/s on the wire.
- Many small files, 10k files at 4KB each: at least 50 MB/s effective.
- Resume detection for a 50 percent complete 10GB file: under 5 seconds.
Tuning knobs should include QUIC congestion behavior, stream buffer size, hashing parallelism, chunk size, and concurrent files in flight.
Possible Future Work
- Compatibility bridge for third-party LAN transfer tools.
- Mobile companion app.
Development
The implementation plan lives in BUILD.md. The expected local
loop is:
The command package is published on crates.io as ferry-cli, which installs
a binary named ferry:
Tagged releases are built through cargo-dist for Linux, macOS, and Windows
with SHA-256 checksums and Sigstore/cosign signature bundles.
Crates are published in dependency order: ferry-core, ferry-tui, then
ferry-cli.
For docs-only changes, the narrow verification command is:
Durable implementation references now live under docs/, including
the current architecture, native protocol, discovery contract, security state,
daemon/headless notes, performance plan, release plan, and CLI/JSON examples.
License
MIT. See LICENSE.