A lightweight Python-based HTTP file server with built-in streaming for video and audio.
Supports ACL-based access control, uploads, and file operations.
This service exposes a filesystem directory over HTTP, enabling:
- File operations: copy/move, rename, upload, create, delete.
- Streaming: streaming via browser-supported formats using HTTP 206. No transcoding, no overhead.
- Access control via on-memory hashmap-based ACLs (read/write/deny per resource and user).
- Detects if a directory is a mount point and changes its type (and icon).
- Server rendered HTML with small sizes.
- Fast dir file listing with intelligent cache.
- Fast recursive directory size calculation (disabled by default).
- Leverages browser-native codecs only.
- Custom cache system for metadata and subtitles to minimize
ffmpegcalls. - Switch audio tracks in-browser (requires experimental Web Platform Features).
- SSA/ASS subtitle support via
JASSUBon the client. - On-demand SSA/ASS → WebVTT conversion, use when JASSUB does not render or fails.
- Extracts embedded subtitles and chapter data from
.mkv,.mp4, etc. - Auto-loads external
.mkssubtitles matching video basename.
- Managed by
aclmgr.pyin thescripts/directory. - ACLs define per-path permissions: read-only, write, or denied.
- User accounts stored in JSON, specified by
env:USERS_FILE. - ACL rules stored in JSON, specified by
env:ACL_FILE. - Both files loaded into RAM as a dictionary.
- Default user (not logged in) is
DEFAULT. - See aclmgr documentation.
On an E5‑1660v4 with 16 workers, is able to reach up to 1.6K RPS when listing directories with 600 items, and around 4K–6K RPS for listings with an more normal amount of items.
Even such large listing stay lightweight, producing only ~30 KB of HTML without compression.
It would not be archiveable without some manual optimizations: custom mtime formatting and HTML rendering (both 2–4× faster than Python/Jinja2), minimal syscalls via scandir + cached stat, and a 1‑minute mtime‑invalidated cache that keeps listings real‑time while deferring metadata refresh and optimized ACL-based permissions as on-memory HASHMAP.
pip install -r requirements.txt- Install
ffmpegat the system level for video playback support. - A
Redisserver for session storage and other cache.
- The web interface requires a modern browser (2021 or newer).
- If you're using something ancient, like a 2018-era fossil that hasn't seen an update in half a decade, expect broken styles and layout quirks.
Configure via environment variables:
| Variable | Required | Default | Description |
|---|---|---|---|
| SERVE_PATH | Yes | — | Directory to serve. |
| ERRLOG_FILE | No | data/error.log | Server error log. |
| ACL_FILE | No | data/acl.json | ACL rules file. |
| USERS_FILE | No | data/users.json | User accounts file. |
| SHOW_DIRSIZE | No | False | Display directory sizes. |
| REDIS_PORT | No | 6379 | Port number to connect to REDIS. |
| REDIS_ADDR | No | 127.0.0.1 | IP address to connect to REDIS. |
| SECRET_KEY | No | Auto-generated | Secret key for multi-worker setups. |
Development (Flask builtin, 127.0.0.1:8000):
python3 app.pyProduction (WSGI, e.g., Gunicorn):
gunicorn -b 127.0.0.1:8000 app:app -w $(nproc) -t 900When deploying with Gunicorn, set an appropriate timeout (-t). For large uploads or long-running file operations, a timeout of 300–900 seconds is recommended to prevent premature termination. Also is recomended to disable post buffering on the proxy to avoid weird file upload behaviour.
If running behind a reverse proxy (e.g., Nginx), ensure its timeout settings match Gunicorn’s to avoid mismatches.
This server has no general-purpose endpoints; everything is path-based with optional query modifiers.
The entire /srv/ namespace is reserved for server functionality.
No part of /srv/ can be used as a folder name in the root directory.
Static files are served from /srv/static.
GET /srv/login?redirect=encoded_url→ Returns login page, redirecting after successful login or exit.POST /srv/login→ Authenticates withusername,password(form data).GET /srv/logout→ Logs out and ends current session.
Responses:
200→ login successful / logout acknowledged.401→ invalid credentials or not logged in.
-
GET /path?get=file→ Always return the file or its file representation.- Regular files: returns the file directly.
- Directories: returns a TAR archive of contents.
- Useful to avoid player page for audio/video.
-
GET /path?get=cached→ Return the file with cache headers.- Applies only to files.
- Uses same cache headers as
/srv/static/. - Intended for plugin usage.
GET /videopath?get=chapters→ Get chapters (JSON).GET /videopath?get=tracks→ Get subtitle tracks (JSON list).GET /videopath?get=subs_ssa&id=x→ Get subtitle track by ID in SSA format.GET /videopath?get=subs_vtt&id=x→ Get subtitle track by ID in VTT format (legacy).
GET /path?sort=XY→ Sorts directory listing by field and order.X: sort field →n= name,s= size,d= date.Y: sort order →p= ascending,d= descending.
GET /dir_path?get=json→ Retrieve directory listings in JSON format.- Works only for directories.
- Sorting parameter ignored.
Behavior:
- Results follow server’s default order.
- Valid
typevalues:disk,directory,text,file. - Additional types defined in
app/file_types.json.
Example response for /:
[
{
"name": "media",
"path": "/media",
"type": "directory",
"mtime": 1750592302.2184954,
"size": 0
},
{
"name": "something.txt",
"path": "/something.txt",
"type": "text",
"mtime": 1750589251.4473305,
"size": 9823
},
{
"name": "STORAGE",
"path": "/STORAGE",
"type": "disk",
"capacity": 2147483648000,
"size": 509872014832,
"mtime": null
}
]The server internally uses some WebDAV methods for file/folder operations.
Note: This is not full WebDAV support—methods are adopted for internal use only.
| Method | Action performed |
|---|---|
| DELETE | Delete a file or folder |
| MKCOL | Create a new folder |
| MOVE | Rename or move an item |
| COPY | Duplicate a file or folder |
| PUT | Upload a file |
.htmlfiles are treated as plain text..webfiles are recognized as HTML pages.- Placing
index.webin any folder auto-loads that page instead of default listing. - Disable with
?get=defaultto get file listing page.
Plugins allow creation of new pages and customization of the frontend GUI by dropping .web extensions into served directories.
Available at: webFILE-plugins
Distributed under the GPLv3 License. See LICENSE for details.