A self-hosted web file-sharing application — like alist, but it only serves the local folders you choose to share, and it keeps real filesystem paths out of the browser.
Features
- 📂 Responsive web UI to browse and manage local directories
- ⬆⬇ Fast uploads & downloads powered by libfw — HTTP streaming, byte-range downloads, upload resume, real (server-confirmed) progress
- ✏️ Move (drag & drop or menu), rename, delete, create folders
- 🗑️ Optional trash directory — deleted files/folders are moved there (relative path preserved) instead of being permanently deleted
- 🔐 OIDC authentication (Authentik, Keycloak, Google, Microsoft Entra ID, …) with ID-token signature verification (JWKS)
- 🔒 ACL-based access control — per path, per user, per group; fail-closed by default
- 👥 Groups for simplified permission management, plus reserved
defaultandguestgroups - 🌐 Samba-style virtual web root — shared folders appear as top-level shares; real paths never reach non-admin users
- ⚙️ Admin panel to manage ACLs, groups and users
- 🔀 Optional URL prefix (
base_url) to mount behind a reverse proxy on a shared domain
Architecture
- Backend — Rust: Axum, libfw-server, SQLite (rusqlite), openidconnect
- Frontend — vanilla JavaScript (no framework), minified with Vite/esbuild
- Transfers — the libfw WASM SDK talks to the embedded libfw server over plain HTTP (
/file,/dir) with parallel byte-range downloads and chunked uploads
cp config.example.toml config.tomlEdit config.toml:
[oidc]— your OIDC provider'sissuer_url,client_id,client_secret(the callback URL is derived from the request, so there is noredirect_urito set).[server] hmac_secret— a strong random value (≥ 16 bytes; the server refuses to start otherwise).[libfw] path_key— a 64-hex AES-256 key:openssl rand -hex 32.
The frontend is vanilla JS in frontend/. Debug builds serve it straight from disk; release builds minify it into ../static and embed it into the binary. pnpm build also re-bundles the libfw WASM SDK into frontend/vendor/ (served from disk in debug), so run it once after pnpm install.
# One-time frontend build (minifies JS/CSS into ../static AND generates
# frontend/vendor/ — the libfw SDK served from disk in debug)
cd frontend && pnpm install && pnpm build
cd ..
# Debug — serves ./frontend from disk
cargo run
# Release — embeds the minified frontend into the binary
cd frontend && pnpm build
cd ..
cargo run --releaseFully static musl binary (what the GitHub release workflow produces):
rustup target add x86_64-unknown-linux-musl # once
sudo apt-get install -y musl-tools perl # once (ring needs a C toolchain + perl)
CC=musl-gcc CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=musl-gcc \
cargo build --release --target x86_64-unknown-linux-muslOpen http://localhost:3456. The first user to log in becomes admin automatically.
All settings live in config.toml. config.example.toml is a fully commented template.
| Key | Default | Description |
|---|---|---|
listen_addr |
0.0.0.0 |
Listen address |
listen_port |
3456 |
HTTP port |
root_dir |
./data |
Root directory to serve |
database_url |
oneshare.db |
SQLite database path |
hmac_secret |
(required) | Signs libfw bearer tokens; must be ≥ 16 bytes, not the default |
base_url |
"" |
URL prefix behind a reverse proxy, e.g. /oneshare; empty = domain root |
session_cookie_secure |
false |
Mark the session cookie Secure (set true when serving over HTTPS) |
allowed_origins |
[] |
CORS allowlist; empty = same-origin only (recommended) |
trash_dir |
"" |
When set, deleted files/folders are moved here (relative path preserved) instead of permanently deleted; empty = permanent delete |
| Key | Default | Description |
|---|---|---|
issuer_url |
(required) | OIDC issuer URL |
client_id / client_secret |
(required) | OIDC client credentials |
authorization_endpoint / token_endpoint / userinfo_endpoint / jwks_uri |
(auto) | Optional endpoint overrides; when all are set, .well-known discovery is skipped (offline start) and jwks_uri is used for ID-token verification |
The callback URL (redirect_uri) needs no configuration: it is derived per-login from the request's scheme + Host header + base_url ({scheme}://{host}{base_url}/auth/callback), so it always matches the origin the user actually used. Register that exact URL in your provider (include the base_url prefix when set). |
| Key | Default | Description |
|---|---|---|
path_key |
(required) | 64-hex AES-256 key encrypting paths into opaque shadows (openssl rand -hex 32) |
compression |
"none" |
Download compression: none or zrip |
compress_level |
"balanced" |
Client zrip level policy: fast / balanced / max / auto / a numeric level |
max_upload_size |
107374182400 |
Upper bound for a single upload body (bytes) |
concurrency |
4 |
Parallel transfer requests |
chunk_size |
2097152 |
Upload chunk and download byte-range size |
upload_window / download_window |
4 |
Per-file in-flight chunks (progress granularity vs. throughput) |
max_fallback_bytes |
536870912 |
Memory ceiling for a browser download without the File System Access API (buffered, then saved); 0 is rejected |
max_retries / base_retry_delay_ms / max_retry_delay_ms |
3 / 500 / 30000 |
Retry policy |
timeout_ms |
600000 |
Per-read idle timeout — keep generous; aborts a transfer if any single read stalls |
auto_tune / tune_ttl_ms |
false / 3600000 |
Adaptive client tuning via /capabilities; 0 disables the settle cache |
auto_tune_max_chunk_size |
8388608 |
Chunk-size ceiling the adaptive engine may grow to (only with auto_tune) |
To mount OneShare under a sub-path of a shared domain, set base_url and make the proxy forward the full path (do not strip the prefix):
[server]
base_url = "/oneshare"The OIDC callback URL is derived automatically as
{scheme}://{host}/oneshare/auth/callback(noredirect_urito configure).
location /oneshare/ {
proxy_pass http://127.0.0.1:3456; # no trailing slash: keep the prefix
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Large file uploads/downloads
client_max_body_size 0;
proxy_request_buffering off;
proxy_buffering off;
}With base_url empty (or /) the app is served at the domain root.
OneShare uses OIDC (OpenID Connect) for login. On every login the server verifies the ID token's signature (RS256 via the provider's JWKS) plus iss/aud/exp/nonce. Users are created on first login.
- Role → group auto-join: if the provider's
userinfocarries aroleclaim whose value matches an existing group name, the user is automatically added to that group (never removed). - The first user to log in becomes admin.
- Read — list directories and download files
- Write — upload, create folders, rename, move, delete
- Admin — full control; admin users bypass all ACLs
- Fail-closed — a path with no matching ACL is accessible to nobody. ACLs grant access; they never default to "readable".
ACL entries can target a specific user or a group, and are path-prefix based: an entry for /photos also applies to every subdirectory.
Every user who has not been assigned to any explicit group is treated as a member of the reserved default group — a single ACL (e.g. /public → default (read)) grants base access to all unassigned users. Users with explicit group memberships use exactly those groups and do not inherit default. It cannot be deleted.
Every unauthenticated visitor is treated as a member of the reserved guest group — a single ACL (e.g. /public → guest (read)) makes that folder public. Guests are never admins and never see the admin UI; logged-out visitors simply browse whatever guest grants (a login link stays in the header). It cannot be deleted.
For non-admin users the browser root (/) is a virtual share root: every ACL-configured directory the user can read appears as a top-level folder named after its leaf directory. ACLs on /public (r), /private (rw) and /nested/public2 show up as three folders — public, private, public2 — with the parts above each share hidden. The address bar reflects the current folder (#/public2/sub).
Real filesystem paths are never sent to the frontend for non-admin users: the server resolves virtual paths internally and ACL checks always run against the real path. Admins are not affected by the virtual root — they browse the real filesystem tree so they can configure ACLs on real paths.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/me |
Session | Current user info ({"user": null} for guests) |
| GET | /api/files/list?path= |
Session | Directory listing |
| GET | /api/files/token?path=&op= |
Session | Issue a libfw bearer token (op=read|write) |
| GET | /api/files/names?paths= |
Session | Resolve opaque shadow paths to display names |
| GET | /api/files/size?path=&limit= |
Session | Recursive byte size (download pre-flight) |
| DELETE | /api/files/delete?path= |
Session | Delete (or move to trash) |
| PUT | /api/files/rename?path=&new_name= |
Session | Rename |
| PUT | /api/files/move?source=&destination= |
Session | Move |
| POST | /api/files/mkdir?path=&name= |
Session | Create folder |
| GET | /api/admin/users |
Admin | List users |
| GET/POST | /api/admin/groups |
Admin | List / create groups |
| DELETE | /api/admin/groups/{id} |
Admin | Delete group |
| GET | /api/admin/groups/{id}/members |
Admin | List group members |
| POST | /api/admin/groups/add-user / remove-user |
Admin | Manage members |
| GET/POST/DELETE | /api/admin/acl |
Admin | Manage ACLs |
| GET | /config.js |
Public | Frontend bootstrap config (base URL, libfw options, version) |
| GET | /file/{*path} |
Bearer token | Download (libfw; Range/ETag) |
| POST | /file/{*path} |
Bearer token | Upload (libfw) |
| GET | /dir/{*path} |
Bearer token | Directory listing (libfw) |
| GET | /capabilities |
Public | libfw capability advertisement (auto-tune) |
| GET | /auth/login / /auth/callback · POST /auth/logout |
— | OIDC flow |
- Build the frontend:
cd frontend && pnpm build— minifiesjs/*+css/into../staticand re-bundles the libfw SDK intostatic/vendor/. - Run tests:
cargo test. - Release build:
cargo build --release— embeds the minified frontend; static asset URLs are cache-busted with a content-hash?v=and servedimmutable.
- README.zh-CN.md — 中文版说明
- docs/README.md — 中文文档索引
- docs/configuration.md — 配置详解
- docs/deployment.md — 部署与反向代理
- docs/acl.md — 权限模型
- docs/development.md — 开发与构建