From 2476bd0b3b3b10650512b3ee257d22ebfb5c0da7 Mon Sep 17 00:00:00 2001 From: Goyban Date: Thu, 27 Aug 2026 16:17:16 +0200 Subject: [PATCH] added filebrowser Quantum since the main Filebrowser is not going to continue --- README.md | 1 + filebrowser/.env.example | 25 ++++++ filebrowser/README.md | 163 +++++++++++++++++++++++++++++++++++ filebrowser/compose.yaml | 32 +++++++ filebrowser/init/config.yaml | 26 ++++++ 5 files changed, 247 insertions(+) create mode 100644 filebrowser/.env.example create mode 100644 filebrowser/README.md create mode 100644 filebrowser/compose.yaml create mode 100644 filebrowser/init/config.yaml diff --git a/README.md b/README.md index 0492eb5..72d6ede 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ handled separately — see [Exposing services](#exposing-services). | [audiobookshelf](audiobookshelf/) | 13378 | Audiobooks and podcasts, with per-user progress sync | | [cloudflare-tunnel](cloudflare-tunnel/) | — | Outbound connector. Exposes other services without opening a port | | [codeserver](codeserver/) | 8443 | VS Code in a browser. Effectively a remote shell — read its README before exposing | +| [filebrowser](filebrowser/) | 3672 | Web file manager for one directory tree (FileBrowser Quantum fork) | | [jellyfin](jellyfin/) | 8096 | Media streaming. Also 7359/udp for auto-discovery | | [openwebui](openwebui/) | 3033 | LLM chat UI. One `OWUI_TAG` switches between CPU, CUDA and bundled-Ollama | | [overleaf](overleaf/) | 8020 | LaTeX editor. Four containers: app, Mongo (replica set), Redis, init | diff --git a/filebrowser/.env.example b/filebrowser/.env.example new file mode 100644 index 0000000..37b0c97 --- /dev/null +++ b/filebrowser/.env.example @@ -0,0 +1,25 @@ +# Copy to .env and adjust. .env is git-ignored; this file is not. + +# ─── Required ─────────────────────────────────────────────────────── +# The directory to browse. Mounted at /srv inside the container, which is +# what init/config.yaml points at. +# +# Add `:ro` to the volume line in compose.yaml if you want a viewer rather +# than a file manager -- worth considering, since anyone who logs in can +# delete whatever they can see. +BROWSE_PATH=/srv/downloads + +# ─── Paths ────────────────────────────────────────────────────────── +# SQLite database: users, shares, search index. Back this up. Small. +#DATA_PATH=./data + +# ─── Identity ─────────────────────────────────────────────────────── +# The image runs as its own non-root user, uid/gid 1000, and reads no +# PUID/PGID -- these feed Docker's `user:` directive instead. They must be +# able to read BROWSE_PATH and write DATA_PATH. +#PUID=1000 +#PGID=1000 +#TZ=Europe/Paris + +# ─── Ports ────────────────────────────────────────────────────────── +#PORT=3672 diff --git a/filebrowser/README.md b/filebrowser/README.md new file mode 100644 index 0000000..149a6e5 --- /dev/null +++ b/filebrowser/README.md @@ -0,0 +1,163 @@ +# File Browser + +Web file manager for a single directory tree — browse, preview, upload, +download, share links. Handy for reaching a downloads folder from a phone +without exposing SMB or SSH. + +This is **[FileBrowser Quantum](https://github.com/gtsteffaniak/filebrowser)**, +the maintained fork. See below for why not the original. + +## Quick start + +```bash +cp .env.example .env +$EDITOR .env # BROWSE_PATH is required +docker compose up -d +``` + +Open `http://:3672` and log in as **`admin` / `admin`** — then change the +password immediately, see below. + +## Ports + +| Port | Proto | Purpose | +|------|-------|---------| +| 3672 | http | Web UI (container listens on 80) | + +## Change the default password first + +First start creates an admin account with a default password and says so: + +``` +[INFO ] Resetting admin user to default username and password. +``` + +Change it in the UI under user settings, or from the CLI. **The database is +locked while the server runs**, so the container has to be stopped first: + +```bash +docker compose stop +docker compose run --rm filebrowser set -u "admin,your-new-password" -a +docker compose start +``` + +Running that against a live container fails with *"the database is locked, +please close all other instances"*, which is easy to misread as corruption. + +## Why not `filebrowser/filebrowser` + +The original project was wound down on **2026-09-01**. Its own binary announced +it on every start: + +``` +NOTICE: File Browser is being wound down. +NOTICE: The project is archived on 2026-09-01, after which there will be no +NOTICE: further releases and no security fixes. +``` + +At that point its advisory page listed around 30 published issues, including a +high-severity one where recursive copy, rename and delete ignored rules that +should have denied access to descendants. Those are now permanent. + +Quantum is the actively developed fork. It keeps the same idea but has its own +configuration format — a YAML file rather than `FB_*` environment variables — +so it is not a drop-in swap of the image name. + +## Why it looks like this + +**The config is a committed file, not environment variables.** Quantum reads a +YAML config and exits `FATAL` if it can't find one. Without +`FILEBROWSER_CONFIG` it looks for `config.yaml` *inside the data directory*, +which means the file you must write by hand and the database it generates end +up in the same place. Pointing it at `/config/config.yaml` keeps the two +separate: [`init/config.yaml`](init/config.yaml) is version-controlled and +mounted read-only, `DATA_PATH` holds only generated state. + +**`minLength: 5` in the config is deliberate.** Raise it and the first start +dies before serving anything: + +``` +[FATAL] store.Users.Save: password must be at least 8 characters long +``` + +That's the *default admin* being created — its password is shorter than the +limit you just set. Raise `minLength` only after setting a real password. + +**No `PUID`/`PGID`.** The image runs as its own `filebrowser` user (uid/gid +1000) and reads neither those nor `UID`/`GID`. Ownership is set with Docker's +`user:` directive, the same as [audiobookshelf](../audiobookshelf/). + +**One source, mounted at `/srv`.** `config.yaml` declares `sources: [/srv]` and +the compose file binds your directory there, so the path inside the container +never changes and the config stays generic. + +## Gotchas + +- **Anyone who logs in can delete anything they can see.** Mount `BROWSE_PATH` + with `:ro` if you only want to look and download. +- **Share links bypass login by design.** That's the feature, but it means a + leaked link is public access to that file. +- **The database is locked while the container runs** — user management needs + it stopped. +- **Back up `DATA_PATH`.** It holds users and share links; losing it means + recreating both. +- **A missing config file looks like a broken config file.** The error names + `Sources` as invalid rather than saying the file is absent. +- **Tags are `1.5.3-stable`, not `v1.5.3`.** The `v` prefix 404s, and `stable` + and `latest` are moving tags. + +## Running it on OpenMediaVault + +OMV's compose plugin deploys the compose file and the env file, nothing else. +Two things follow, and both cost me a round trip. + +**Put `config.yaml` in `init/`, not the stack root.** The compose mounts +`./init/config.yaml`, so that exact path must exist as a *file* before the +first start. Docker creates a **directory** for a missing bind-mount source, +and filebrowser then reports a validation failure rather than a missing file: + +``` +could not validate config: Key: 'Settings.Server.Sources' + Error:Field validation for 'Sources' failed on the 'required' tag +``` + +That message sends you looking for a mistake in your config when the config +isn't being read at all. Check the host first: + +```bash +stat -c '%F %n' init/config.yaml # must say "regular file" +``` + +If it says `directory`, `rmdir` it, put the real file there, and **recreate** +the container — a restart isn't enough, the mount is fixed at creation. + +**Make `DATA_PATH` writable by `PUID:PGID`.** Docker creates it as root, but +the container runs as your `PUID:PGID` — which on OMV is often `1000:100` +(the `users` group), not `1000:1000`. Otherwise: + +``` +[FATAL] could not open database: open /data/database.db: permission denied +``` + +```bash +chown -R 1000:100 data +``` + +Also: OMV names the env file `filebrowser.env`, so manual `docker compose` +commands fail on `BROWSE_PATH` unless you pass `--env-file filebrowser.env`. +Use plain `docker exec` / `docker logs` for one-offs. + +## Exposing it + +- [Reverse proxy with Caddy](../docs/reverse-proxy.md) — the minimum. +- [Single sign-on with Authentik](../docs/authentik-sso.md) — worth it here. + Forward auth means a stranger has to get past Authentik before reaching a + login form that guards your filesystem. +- [Cloudflare Tunnel](../cloudflare-tunnel/) — mind the ~100 MB upload cap, and + don't route large media downloads through it. + +## Links + +- Upstream: +- Image: `ghcr.io/gtsteffaniak/filebrowser` +- The wound-down original: diff --git a/filebrowser/compose.yaml b/filebrowser/compose.yaml new file mode 100644 index 0000000..97ccc3d --- /dev/null +++ b/filebrowser/compose.yaml @@ -0,0 +1,32 @@ +services: + filebrowser: + # FileBrowser Quantum -- the maintained fork. The original + # filebrowser/filebrowser was wound down on 2026-09-01 with ~30 unfixed + # security advisories; see the README before reaching for it again. + image: ghcr.io/gtsteffaniak/filebrowser:1.5.3-stable + container_name: filebrowser + restart: unless-stopped + + # The image already runs as its own non-root `filebrowser` user, uid/gid + # 1000. It reads no PUID/PGID, so ownership is set the Docker way. Change + # this if the files it must read are owned by someone else. + user: "${PUID:-1000}:${PGID:-1000}" + + environment: + - TZ=${TZ:-Etc/UTC} + # Without these it looks for config.yaml *inside* the data directory and + # exits FATAL when it is missing. Splitting them keeps the committed + # config separate from the database it generates. + - FILEBROWSER_CONFIG=/config/config.yaml + - FILEBROWSER_DATABASE=/data/database.db + + volumes: + - ./init/config.yaml:/config/config.yaml:ro + # SQLite database: users, shares, the search index. Back this up. + - ${DATA_PATH:-./data}:/data + # The directory you actually want to browse. Add `:ro` to make this a + # viewer rather than a file manager. + - "${BROWSE_PATH:?set BROWSE_PATH to the directory you want to browse}:/srv" + + ports: + - "${PORT:-3672}:80" diff --git a/filebrowser/init/config.yaml b/filebrowser/init/config.yaml new file mode 100644 index 0000000..3b3ba19 --- /dev/null +++ b/filebrowser/init/config.yaml @@ -0,0 +1,26 @@ +# FileBrowser Quantum configuration. +# +# Mounted read-only at /config/config.yaml; the container is pointed at it with +# FILEBROWSER_CONFIG. `./filebrowser -c` inside the image prints the full +# annotated default if you want to see every available option. + +server: + port: 80 + baseURL: "/" + logging: + - levels: "info|warning|error" + # What gets browsed. The compose file bind-mounts your directory here. + sources: + - path: "/srv" + +auth: + methods: + password: + enabled: true + # Leave at 5. The first run creates a default admin whose password is + # shorter than 8 characters, and raising this makes that creation fail + # with a FATAL before the server ever starts. Raise it only after you + # have set a real password -- see the README. + minLength: 5 + # No self-registration. Users are created by an admin. + signup: false