DEV Community

Cover image for BoxBox v0.3.0: file and folder sharing for a self-hosted file manager
Radhey Kalra
Radhey Kalra

Posted on AI-assisted

BoxBox v0.3.0: file and folder sharing for a self-hosted file manager

A few months ago I wrote about building BoxBox, a self-hosted file manager for homelabs and NAS boxes. v0.3.0 is out, with file and folder sharing.

Music: "the kill 2" by Lex Amarni & 2muchmotion.

What's new

  • File and folder sharing. Every file or folder gets a token link. Folder links come in four levels: View only, Upload only, Upload + delete, and Full access. Links can expire and can be revoked.
  • A public share page. Recipients get a path bar, a file list, previews, a read-only code editor (editable with full access), arrow-key navigation, and ZIP downloads. No account needed.
  • Folder uploads. Drop a whole folder in. Uploads go in chunks and keep nested paths.
  • Drives and Places. Top-level mounts are drives. A mount inside another mount (like Downloads inside home) shows up under Places. You can override either with kind: in the config.
  • Your wallpaper on share pages. Each user's wallpaper is stored on the server and shown to their recipients.

The hard part: sharing from a box that holds everything

A homelab file manager usually runs with access to your disks, backups, and configs. Public links need to keep recipients inside the shared path. These are the rules BoxBox follows.

The token is the only credential. Each link is 32 random bytes from crypto/rand, encoded as 43 URL-safe characters. Recipient endpoints are public, so they get their own per-IP rate limit, separate from login.

Every failure looks the same. Unknown, expired, and revoked tokens all return the same 404. Someone guessing tokens learns nothing about which links ever existed.

Re-check the path on every request. A share stores a path, not a promise. On every recipient request BoxBox resolves the path against the current mount config. If you remove or rename a mount, its links stop working. If a mount becomes read-only, its links can still read but can't upload.

Upload-only means upload-only. Recipients with upload access must not overwrite existing files. Uploads land in a temp file and are published with renameat2(RENAME_NOREPLACE) on Linux, so the kernel refuses to replace an existing file atomically.
On other platforms it falls back to a hard link plus remove, which gives the same no-replace guarantee.

Revocation wins races. If you revoke a link while someone is mid-upload, the upload is not published.

Treat previews as hostile. Recipient downloads and previews use the same sandboxed Content-Security-Policy as the main app. HTML, SVG, and XML are always downloaded, never rendered inline, so a shared file can't run script on your BoxBox origin.

ZIPs stay inside the share. Folder archives check every entry's traversal and resolved path against the share root before streaming, so a symlink can't pull in files from outside it.

Keep internals private. Recipient responses never include mount names or server paths. The share store is 0700, and the token-bearing shares.json is 0600.

Upgrading

One breaking change: the container now listens on 8080 instead of 80. The container side of your port mapping, the healthcheck, and any reverse proxy must match port in config.yaml. The release notes cover this, plus rollback.

BOXBOX_IMAGE=ghcr.io/jr4dh3y/boxbox:v0.3.0 docker compose pull
BOXBOX_IMAGE=ghcr.io/jr4dh3y/boxbox:v0.3.0 docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Try it

If you run a homelab, I'd like to know what you'd share first, and what would stop you from exposing a share page to the internet.

Top comments (0)