Dufs vs miniserve: who can write?

By Built with Rust editorial · Published · Sources and exercise checked November 3, 2026

Choose miniserve for a temporary browser share where accepted accounts use the same enabled operations. Evaluate Dufs when different accounts need different writable paths or a WebDAV client must write. This Dufs vs miniserve comparison uses a disposable, version-pinned exercise to show why an account name, an upload button and a successful directory listing are different kinds of evidence.

Dufs and miniserve are Rust file-sharing servers you run against a local directory. Both can offer browser downloads and optional uploads; their permission models and WebDAV write support differ.

Built with Rust ran four local server profiles with Dufs 0.47.0, miniserve 0.35.0 and Python 3.11.2 on Linux. Fourteen checks paired HTTP responses with file contents or file absence. Both tools served the sample. The useful difference was which identity could change which path through which interface, not a speed ranking.

Start with the Dufs catalog entry or miniserve catalog entry for project links. For other jobs, use the infrastructure tool chooser. Neither tool should be assumed to provide synchronization, backup retention or a managed collaboration service merely because it can serve files.

Dufs vs miniserve: choose by sharing policy

Selection guidance from pinned documentation and our local exercise; not a security rating
Your actual requirementStart hereAcceptance question
A trusted group downloads one folderminiserve; Dufs also fitsCan the intended account read the exact sample?
One writable subtree per accountDufs path rulesDoes an allowed write succeed while a sibling-path write fails?
Browser uploads for all accepted accountsminiserve upload directoryIs shared upload permission what you intended?
A WebDAV client creates filesDufs with required operations enabledCan the actual client write and read back, not merely list?
Uploaders cannot read submitted filesNeither example here establishes thatDoes direct GET fail for every identity that must not read?

miniserve earns its place when the sharing policy is small: serve this folder, accept these credentials, optionally accept uploads here. Do not add account-specific policy machinery when everyone legitimately has the same access. Its 0.35.0 options also include opt-in deletion and directory creation; calling it a download-only tool would be misleading. Those options are separate from writable WebDAV.

Dufs is the more direct candidate when the policy names different accounts and paths. Its 0.47.0 access-control documentation assigns read-only or read-write rules to path scopes. That is useful for a reader of the whole share and a writer limited to an inbox. It also creates more policy to inspect: a plausible-looking rule is not proof the finished setup matches your intention.

Dufs vs miniserve permissions: three separate decisions

Authentication answers which credentials the server accepts. A path rule answers where an identity may act. An operation switch answers whether the server enables an action at all. Write these as separate requirements before starting either tool; do not infer permissions from a username such as reader.

In Dufs, our writer had a read-write account rule but could not upload until the global upload operation was enabled. After that, the writer could create a file inside inbox, the read-only account could read its exact bytes, and that read-only account still could not upload. The writer could not create a sibling file outside its allowed subtree. Deletion stayed disabled despite the writer's read-write rule. These are deliberately different checks.

In miniserve, our upload profile accepted accounts named writer and reader. Both uploaded successfully into the enabled directory. That result agrees with the pinned authentication implementation: it accepts matching credentials; the names do not assign different upload roles. A reverse proxy could introduce another policy layer, but that would be a different setup requiring its own checks.

WebDAV is a further interface decision. PROPFIND asks for resource properties or a directory listing; PUT sends file contents. Our miniserve DAV profile answered PROPFIND but did not accept PUT. Enabling its browser-upload endpoint did not change that result. The 0.35.0 DAV handler uses a read-only method set. Do not mistake a mounted directory or a browser-upload success for a writable DAV connection.

Run the disposable four-profile exercise

Download lab.py and read it first. It needs Python 3.11 or newer and two executable paths, not your existing share directory. Obtain the checked binaries from the official Dufs 0.47.0 release and miniserve 0.35.0 release. Use trusted packages for your platform and inspect the projects' installation instructions. The lab itself downloads nothing.

python3 lab.py --dufs /absolute/path/to/dufs --miniserve /absolute/path/to/miniserve

The script rejects other version strings, generates fresh throwaway credentials and creates a new temporary share for each profile. Each child receives a small environment without inherited DUFS or MINISERVE settings. It binds to 127.0.0.1, ignores HTTP proxy settings and preserves the immediate response code instead of following redirects. Only the supplied local executables run; their version checks also execute code, so the paths must point to binaries you trust.

Each profile starts a server, sends bounded requests, checks its synthetic files and stops the process. The temporary files are removed when the run ends. A failed startup or changed observation stops the exercise; it does not weaken an expected denial to get a passing result. Python optimization does not remove these checks. A small free-port race can make startup fail, in which case inspect the environment and rerun the disposable trial.

Success prints JSON with fourteen checks, version strings and SHA-256 hashes of your binaries. Compare package provenance as well as version output; a matching label alone is not a supply-chain guarantee. The tested path was Linux with official x86_64 musl release binaries. Other operating systems, browsers and DAV clients remain untested here.

What our fourteen checks observed

The four profiles separate the permission questions. The table groups their fourteen assertions. A positive write checks exact bytes on disk. A denied creation checks that the target does not exist; the denied deletion checks that the original bytes remain. Three successful GET checks also compare response bodies.

Built with Rust · November 3, 2026 · Dufs 0.47.0 / miniserve 0.35.0 · Linux loopback HTTP
Profile and requestImmediate HTTP resultFile-state evidence
Dufs: rw account, no global uploadGET 200; PUT 403Original read matches; upload absent
Dufs: upload enabled, writer scoped to inboxWriter PUT 201; reader GET 200Both checks match writer-v1 bytes
Same Dufs profile: reader PUT / writer outside-path PUT403 / 403Neither target created
Same Dufs profile: writer DELETE403Uploaded bytes remain
miniserve: auth and read-only DAVAnonymous GET 401; account GET 200Original file unchanged; authorized body matches
Same miniserve profile: PROPFIND / PUT207 / 404Listing contains sample; PUT creates nothing
miniserve: auth, DAV and inbox browser uploadsWriter POST 303; reader POST 303Both accounts create their exact sample bytes
Same upload profile: DAV PUT404No DAV target created

The miniserve 303 responses redirect after multipart uploads. The lab deliberately does not follow them: a later directory page returning 200 would describe the redirect destination, not the upload response. The bytes on disk establish that the accepted upload happened. Conversely, the 404 on PUT is an observed result for this route and version, not a universal status-code requirement for every read-only server.

The Dufs path test is a sibling file under the disposable served root. It is not a path-traversal attack, an outside-root symlink test or evidence that every filesystem boundary is enforced. The miniserve reader name is intentionally misleading: it demonstrates why a label must not stand in for a permission test.

Turn your sharing policy into an acceptance contract

Use the downloadable acceptance worksheet before adapting a command. It separates identity, path, interface, expected result and observed file state. Mark each row allow, deny or not needed before running it. An untested requirement stays untested; it does not inherit a pass from the sample lab.

  1. Name the smallest share root and the intended identities. Keep the release artifact separate from the inbox if they have different write policies.
  2. For each identity, test a direct download as well as a listing. A visible name and readable contents are separate observations.
  3. Test one allowed upload and one denied upload into another path. Read back the allowed file, then inspect the denied target for unintended changes.
  4. Decide overwrite and deletion behavior explicitly. Our lab tests denied Dufs deletion, but does not establish either tool's complete overwrite policy.
  5. Use the real browser or DAV client for a second acceptance pass. Browser authentication prompts, client retries and reverse-proxy paths are outside this Python HTTP exercise.
  6. Stop the server after the trial. Check that the former share address is no longer reachable before considering the experiment finished.

For a one-team release share, a successful miniserve trial may be enough to choose the application, while remote deployment still needs separate review. For mixed reader/writer roles, use Dufs's path rules and repeat both positive and negative cases for each identity. If your requirement is an upload-only drop box, add direct-read denials to the contract. Neither our read-write Dufs profile nor our shared-upload miniserve profile demonstrates that requirement.

Boundaries this comparison does not certify

Loopback HTTP checks application behavior in a disposable folder. They do not validate TLS, Internet exposure, container mounts, proxy authentication, concurrent clients, large uploads or recovery after a crash. Do not publish the lab's local setup as a production deployment recipe. Enable only required operations, and review the installed release's documentation and current maintainer notices before exposing real files.

Archives and symlinks need their own boundary tests. On November 3, 2026, miniserve's archive/symlink issue report and proposed fix were still open. We did not reproduce that report, and our profiles leave archive generation disabled. Do not infer archive containment from a passing ordinary download or upload check.

Dufs's security policy explains that some unauthenticated DAV listings expose protected entry names without granting file access. It also warns that served active content runs on the file server's origin. Keep untrusted uploads away from trusted application origins; a name hidden from a listing is not the access-control test you need.

This is a functional comparison of tiny synthetic fixtures, not a vulnerability assessment, throughput benchmark or endorsement of a deployment. The original contribution is the paired-response-and-state method and reusable policy worksheet. Keep the observations attached to their versions, then rerun the checks that matter when you upgrade.

Common Dufs and miniserve questions

Does miniserve support writable WebDAV?

The miniserve 0.35.0 documentation describes read-only WebDAV. In our disposable trial, PROPFIND returned 207 while PUT returned 404, including with browser uploads enabled. Choose Dufs for evaluation when a DAV client must write; then test that client and the intended account rules.

Why can a Dufs read-write account fail to upload?

Dufs account permissions are limited by globally enabled operations. In our Dufs 0.47.0 trial, an account with a read-write rule received 403 for PUT until global upload was enabled. After enabling uploads, path and account rules still determined which writes succeeded.

Can two miniserve accounts have different upload permissions?

Our miniserve 0.35.0 profile accepted two accounts and enabled uploads to inbox. Both accounts could upload there, even though one was named reader. The names did not create roles. For per-account writable paths, evaluate Dufs rules rather than treating miniserve account names as permissions.