Skip to main content

Home Stream

Test suites REUSE status The latest version of this application can be found on PyPI. Information on what versions of Python this application supports can be found on PyPI.

A web-based browser and streaming interface for local media files. Supports in-browser playback, HTTP Basic Auth streaming (e.g. VLC), and user-based login with permanent stream URLs.

Features

  • Browse local folders and media files
  • Show titles and metadata in the browse view (toggleable): Kodi-style .nfo files for video, embedded tags for audio
  • Secure user login
  • In-browser audio/video player (if supported by your browser)
  • HTTP Basic Auth fallback for external players (VLC, mpv, etc.) using authenticated links
  • Lightweight and dependency-minimal Python Flask app

Use-Cases for home-stream

The application is mainly designed with the use-case of running it on a NAS or home server with direct media access to allow accessing your media files remotely.

For this, you may put this application behind a reverse proxy or make it accessible via a VPN connection.

Of course, you can also use it purely locally, although there are probably better tools to administrate your media files.

Installation

Minimum Python version: 3.10

pipx makes installing and running Python programs easier and avoids conflicts with other packages. Install it with

pip3 install pipx

The following one-liner both installs and runs this program from PyPI:

pipx run home-stream

If you want to be able to use the application without prepending it with pipx run every time, install it globally like so:

pipx install home-stream

The application will then be available in ~/.local/bin, which must be added to your $PATH. So make sure that ~/.local/bin is in your $PATH. On Windows, the required path for your environment may look like %USERPROFILE%\AppData\Roaming\Python\Python310\Scripts, depending on the Python version you have installed. Recent pipx versions allow you to do this via pipx ensurepath.

To upgrade the application to the newest available version, run this command:

pipx upgrade home-stream

Other installation methods

You may also use pure pip or poetry to install this package.

Configuration

Create a config.yaml file in the project root. You can derive your configuration from config.sample.yaml.

Passwords must be bcrypt-hashed. You can generate them using Python:

import bcrypt

print(bcrypt.hashpw(b"your-password", bcrypt.gensalt()).decode())

or by using online tools like bcrypt-generator.com, although not recommended for production passwords.

Usage

Start the app (session login + streaming):

home-stream -c config.yaml  # uses Flask development server

Log in via browser, by default on localhost:8000. Browse and play media, or copy permanent stream URLs.

Production Webserver

For productive use, you should use a proper WSGI server. uWSGI is officially supported and ships in the Docker image. With the default download_method: direct, large file transfers run through the WSGI worker, which can strain servers like gunicorn (worker blocking, timeouts) — uWSGI tolerates this better. If you enable download offloading (see below), large files are served by your webserver instead, so the WSGI server only handles short requests and this distinction no longer matters.

For a quick start, run uv run uwsgi --ini uwsgi.ini. Using the docker image ghcr.io/mxmehl/home-stream you would have everything contained into one container, ready to be use locally or behind a reverse proxy. Note that depending on your use-cases, you may want to reconfigure some uwsgi settings. This currently would need to be done manually.

Large file downloads (offloading)

By default (download_method: direct), the application serves file bytes itself through the Python/uWSGI worker. This works, but for large files (movies) it ties up a worker for the whole transfer, interacts poorly with proxy buffering, and can hit timeouts (e.g. uWSGI's harakiri). This is the classic reason large downloads drop while a plain nginx/sftp serve never does.

The robust solution is to keep authentication and discovery in the app, but let your webserver push the bytes using a zero-copy sendfile() path. The app authorizes the request exactly as before (your permanent per-user tokens are unchanged), then hands the file to the webserver via a response header. Choose the mechanism that matches your front-end webserver via download_method in config.yaml:

The one rule that matters: whatever webserver serves the bytes must have direct read access to the media files at the same paths the app sees. This is the part that trips people up — see the note below.

You do not need to bundle nginx into the app image, and you do not need your existing internet-facing reverse proxy to touch the media. The simplest robust setup is a dedicated nginx container that sits next to the app in the same docker-compose.yaml, shares the media volume, and does the offload. Your outer proxy (Caddy, Traefik, an existing nginx, …) just forwards HTTP to this sidecar and handles TLS as before.

Why a sidecar rather than your existing host/edge webserver? Because of the file-access rule above. The app container can already read the media (it runs as its own user). A different webserver — for example a host nginx running as www-data, or an edge proxy on another machine — usually cannot read your media (especially with read-only NFS mounts and restrictive ownership), so its offload attempts fail with 403/404 even though the app authorized them. A sidecar container avoids this entirely by mounting the same volume and running as the same user as the app.

Ready-to-use samples are provided: docker-compose.sample.yaml (app + nginx sidecar + valkey) and nginx.sample.conf (the matching nginx config). Set download_method: xaccel in config.yaml, adjust the media path and port, and point your TLS-terminating reverse proxy at the sidecar.

The remaining subsections describe the underlying mechanisms if you prefer to use an existing nginx/Apache that does have media access instead of a sidecar.

nginx (download_method: xaccel)

The app emits an X-Accel-Redirect header pointing into an internal location that nginx maps to your media root. See nginx.sample.conf for a ready-to-use example. The key points:

Apache / Lighttpd (download_method: xsendfile)

Requires mod_xsendfile. The app emits an X-Sendfile header with the absolute file path, which Apache serves directly:

XSendFile On
# Scope strictly to the media root so only intended files can be served.
XSendFilePath /media/data

Notes

  • The offloading webserver must see the same media files at the configured path. With the sidecar above, this is handled by mounting the same volume into the nginx container. If you instead reuse an existing host/edge webserver, it must have read access to the media itself — a separate user like www-data often does not, especially with read-only NFS mounts and restrictive ownership, which is exactly why the sidecar is recommended. Read-only access is sufficient.
  • Symlinks are resolved. The app hands the webserver the symlink-resolved (real) path. If media_root is itself a symlink (or sits under one), point nginx's alias and Apache's XSendFilePath at the real target directory, not the symlink.
  • Security: keep the nginx location internal, and scope XSendFilePath to exactly the media root. Authorization stays entirely in the app — the webserver only serves paths the app explicitly hands it.
  • Folder downloads (generated M3U8 playlists) are always served directly by the app, since they are tiny.
  • With offloading enabled, uWSGI's harakiri/keepalive settings no longer affect downloads.

License

This project is licensed under the terms of the GPL-3.0-only license, but contains elements under different licenses.

The project is REUSE compliant, so licensing and copyright information is available for every single file.

Metadata

Release files for home-stream 1.7.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for home-stream 1.7.1
File Size Uploaded
home_stream-1.7.1.tar.gz 71.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for home-stream 1.7.1
File Interpreter ABI Platform
home_stream-1.7.1-py3-none-any.whl Python 3 none any Details

Total release size: 147.3 kB

Release files / home_stream-1.7.1.tar.gz

Download URL home_stream-1.7.1.tar.gz
Size 71.9 kB
Tags Source
SHA-256 checksum
How to use checksums
42dca8f28a3ddf10c8a7f2d0e4b30b76aebaf424ecf9d3a399743fd85675e69a
BLAKE2b-256 checksum
How to use checksums
c90d813e199b8dd97917f14b2b176ce97632f6e412f76a7277a209e64de9f693
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / home_stream-1.7.1-py3-none-any.whl

Download URL home_stream-1.7.1-py3-none-any.whl
Size 75.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2523a071f589d55bbb1e16250a61d46d0a30db06f148aea8c6c1c9eaa6e733d5
BLAKE2b-256 checksum
How to use checksums
47673bcecad4e369d3b1ac8d9e98718e4fb03053c629d323cddc8fc62744be6b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.7.1 This release

2 release files

1.7.0

2 release files

1.6.0

2 release files

1.5.5

2 release files

1.5.4

2 release files

1.5.3

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.3

2 release files

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page