FileBrowser Quantum Docker Setup: Self-Hosted File Manager
Deploy FileBrowser Quantum with Docker Compose: the actively maintained FileBrowser fork. Multiple sources, share links with expiry, 2FA, and how I use it with my Mastra AI assistant.

FileBrowser Quantum Docker Setup: Self-Hosted File Manager
Why Quantum and not FileBrowser
The original FileBrowser project is being archived on 2026-09-01. The final release (v2.63.23) shipped with no further security patches planned, and known issues like command execution vulnerabilities (#5199) and non-revocable JWT sessions (#5216) will stay unpatched.
FileBrowser Quantum is the actively maintained fork that took over: 7.6k+ GitHub stars, a stable release track, Apache-2.0 license, and it removed the shell command feature entirely. This guide deploys Quantum from scratch — if you’re already running the original, the migration notes section covers what changes.
FileBrowser Quantum is a web-based file manager for self-hosted servers. It gives you a browser UI for uploading, downloading, previewing, renaming, and editing files — with the polish of a modern SaaS product and none of the subscriptions. It’s the fork of FileBrowser that keeps getting updates, and it’s what I run on my own server today.
This guide covers the full FileBrowser Quantum Docker setup: Docker Compose deployment, multiple file sources, share links with expiration, reverse proxy access, security hardening, and how I use it as the file window into my AI agent setup (a self-hosted Mastra assistant).
What Makes FileBrowser Quantum Different
If you’ve used the original FileBrowser, these are the changes that matter:
- Multiple sources — you can mount several directories (workspace, projects, media) with include/exclude rules, instead of one root
- Real-time indexed search — SQLite-backed, searches filenames, contents, and sizes as you type
- Modern authentication — OIDC, LDAP, JWT, password + 2FA, and proxy auth
- Share links with expiry — anonymous public links with expiration, permissions (view/edit/upload), and even custom themes
- OnlyOffice integration — edit office documents right in the browser
- API tokens + Swagger docs — long-lived API tokens and a documented API at
/swagger, useful for automation - No shell commands — the command runner was removed completely. This is the single biggest security improvement over the original
Config format changed
Quantum uses a config.yaml instead of the original settings.json, and the database schema is different. You can’t swap the Docker image on an existing original install — the old filebrowser.db is not compatible. Migration means reconfiguring from scratch (see below).
If you’re comparing other options, Cloudreve is another solid self-hosted file manager worth a look.
Prerequisites
- A VPS or home server — Hetzner (from ~€4/mo) or Hostinger work well, or a Mini PC as a home server
- Docker and Docker Compose v2 (the
docker composeplugin;docker-composev1 was removed in April 2025) - A reverse proxy (Caddy, Traefik, Nginx) or Cloudflare Tunnel for TLS — never expose FileBrowser directly to the internet
- A domain or subdomain pointed at your server
- Optionally, Dockge or another self-hosted management panel to manage containers via UI
You can also use Traefik as a reverse proxy for Docker — I have a full tutorial with Dockge.
Deploy FileBrowser Quantum with Docker Compose
Step 1: Create the base directory
Quantum stores its config, database, and cache in one data directory. Inside the container that’s /home/filebrowser/data.
mkdir -p filebrowser/data && cd filebrowser
Step 2: Create the config
The config key is server.sources
Quantum’s Docker docs had a typo at some point showing a top-level sources key. The correct schema nests sources under server — a config without server.sources fails startup validation with Settings.Server.Sources required.
Create data/config.yaml:
server:
cacheDir: /home/filebrowser/data/tmp # inside the data volume so it persists across restarts
sources:
- path: /srv/workspace
name: "Agent Workspace"
config:
defaultEnabled: true
- path: /srv/projects
name: "Projects"
config:
defaultEnabled: true
Notes on the config:
pathis from the container’s point of view — it must match the right side of your volume mounts.nameis the display name shown in the UI sidebar.defaultEnabled: truemakes a source available to new users by default. Without it, users won’t see the source until you grant access.cacheDirshould live in the data volume so the search index and thumbnails survive restarts.- Don’t use a root
/directory or include/varas a source — Quantum warns against both.
Step 3: Create the Docker Compose file
services:
filebrowser:
image: gtstef/filebrowser:stable
container_name: filebrowser
restart: unless-stopped
volumes:
- /opt/workspace:/srv/workspace
- /opt/projects:/srv/projects
- ./data:/home/filebrowser/data
ports:
- "8080:80"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 30s
timeout: 3s
start_period: 10s
retries: 3
What’s going on here:
- Image tags:
stable(60MB, includes FFmpeg + document preview) orstable-slim(15MB, core only). Usestableif you want media previews and thumbnails. Also available on GHCR asghcr.io/gtsteffaniak/filebrowser. ./data:/home/filebrowser/data— persistsconfig.yaml,database.db, and thetmpcache. This volume is the whole state of the app./opt/workspace:/srv/workspace— your first source. Change the host path to wherever your files actually live.8080:80— host port : container port. The container listens on 80 by default (you can changeserver.portin the config, then the healthcheck must match).- Non-root default: since v1.3 the image runs as the
filebrowseruser (UID/GID 1000:1000), not root. If your host user is a different UID,chown -Rthe mounted directories accordingly. - Healthcheck: the image ships a built-in healthcheck for port 80; I’ve made it explicit so it’s easy to adjust if you change the port.
Step 4: Start and verify
docker compose up -d
Verify the deployment
# Container should be Up (healthy)
docker ps --filter name=filebrowser
# Watch the startup logs
docker logs -f filebrowser
# Health endpoint returns 200
curl -f http://localhost:8080/health
# Config and DB were created in the data volume
ls -la data/Log in at http://your-server:8080 with the default credentials — admin / admin — and change the password immediately.
Change the password and enable 2FA now
The default admin credentials are known to the entire internet. After first login: change the password, then enable two-factor authentication in the user settings. Quantum supports TOTP 2FA out of the box — the bots that scan every public IP will find your instance, so lock it before pointing a domain at it.
Adding more sources later
Sources can be added without recreating the container — but there’s a gotcha: Quantum caches the config into database.db on first run. If you edit config.yaml after the first start and nothing changes, that’s why.
# Stop the container, clear the cached config, restart to re-init from config.yaml
docker compose down
rm -f data/database.db
rm -rf data/tmp
docker compose up -d
This wipes user accounts and settings stored in the DB — export/recreate them if needed. For day-to-day source additions there’s also a UI admin panel (Settings → Sources) that updates things live without touching the file.
Share Links: Send Files Without Accounts
Sharing is one of Quantum’s strongest features and the reason I reach for it daily. Select any file or folder → Share → and you get:
- Public/anonymous links — the recipient doesn’t need an account or login
- Expiration time on every share
- Per-share permissions: view, edit, or upload
- Custom styling/theme for the share page
This turns Quantum into a poor man’s file-drop service: right-click a file, copy the https://files.yourdomain.com/s/... link, send it anywhere.
Secure Remote Access with a Reverse Proxy
Never expose the port directly
Quantum has no TLS of its own — always terminate TLS at a reverse proxy and keep the container port private. Prefer running Quantum on a shared Docker network so you don’t even publish a host port.
Option 1: Same Docker network as your proxy (what I do).
Drop the ports: section and attach both containers to the proxy’s network:
services:
filebrowser:
image: gtstef/filebrowser:stable
container_name: filebrowser
restart: unless-stopped
networks:
- web
volumes:
- /opt/workspace:/srv/workspace
- /opt/projects:/srv/projects
- ./data:/home/filebrowser/data
networks:
web:
external: true
Then in Caddy:
files.example.com {
reverse_proxy filebrowser:80
}
docker compose up -d and Caddy gets a Let’s Encrypt certificate automatically. This is exactly how my instance runs at files.ai.bitdoze.com — no host port exposed, only reachable through the proxy.
Option 2: Cloudflare Tunnel.
If you use Cloudflare, add a hostname to your existing tunnel pointing at the service:

Point it at http://localhost:8080 (or the host port you chose) and let Cloudflare handle TLS.
Option 3: Traefik.
Check Traefik as a reverse proxy for Docker or CloudPanel as a reverse proxy for the full walkthroughs.
If you get a 502/503 through the proxy, verify the container is running (docker ps) and that the proxy’s target port matches the container’s internal port (80 unless you changed server.port).
How I Use FileBrowser Quantum with My AI Agent Setup
This is the part that changed my workflow. I run a self-hosted Mastra AI assistant — the same assistant that helps me write articles on this blog. I documented the full build in Build Your Own AI Agent with Mastra (Files, Web, Browser), and the code is open source at github.com/bitdoze/mastra-assistant.
The agent lives on the same server as FileBrowser Quantum, and the two work together as a loop:
1. The agent’s files are a Quantum source.
My agent’s workspace and project directories are mounted directly into Quantum as sources. When the agent writes a draft, generates a cover image, or produces an audio file, I see it instantly in the browser — no SSH, no terminal. Markdown renders nicely, images and PDFs preview natively, and audio/video play inline (that’s the ffmpeg in the stable image).
2. Share links are the handoff mechanism.
When the agent finishes something — say a blog post draft — I open Quantum, right-click the file, and create a share link with an expiry. That link goes into Slack, Discord, or an email, and anyone can view it without an account. For my own review loop, the share link is also what I paste into other AI chats when I want a second opinion on a file the agent produced.
3. The reverse direction: I drop reference files in.
If I want the agent to work from a specific source — a brief, an exported notes file, a competitor’s screenshot — I drag it into the mounted source directory via Quantum. The agent reads it from the same path on disk. Both of us see the same files; Quantum is simply my human-friendly window into the agent’s filesystem.
4. Automation via the API (optional).
Quantum exposes a documented REST API with long-lived API tokens (/swagger when API is enabled). You could wire an agent tool that lists or downloads files from Quantum programmatically. I keep it simple — direct file access through mounted volumes is faster — but the API is there if you want a decoupled setup.
5. Security posture for the agent setup.
- Only the workspace and projects directories are mounted as sources — not
/, not the whole home directory - The instance sits behind the reverse proxy with 2FA enabled, no public port
- Sources that shouldn’t be shared can be marked
private: truein the config (disables sharing for that source) - The agent’s credentials and secrets live outside the mounted directories
The result: my AI assistant does the heavy lifting, and Quantum gives me a zero-friction way to see, review, and distribute what it produces. If you’re building your own agent, start with the Mastra guide, then wire Quantum as its file front-end.
Security Hardening for FileBrowser Quantum
- Never expose Quantum directly — always reverse proxy with TLS
- Enable 2FA on the admin account, and on any user with write access
- Change the default admin password immediately
- Run as non-root — the default
filebrowseruser (1000:1000) since v1.3; don’t switch back to root - Mount only the directories you serve. Don’t mount
/or/var - Mark sensitive sources
private: trueso they can’t be shared - Use
denyByDefault+ explicit allow rules for per-directory access control - Create separate users with restricted source scopes instead of sharing admin
- Keep the image pinned (
stableis updated; pin a specific version if you need reproducibility) - Block direct access to the container port with firewall rules if you publish one
If you’re behind a rootless runtime (Podman, Docker rootless) and Quantum fails to bind a port below 1024, add cap_add: [NET_BIND_SERVICE] to the compose service instead of running privileged.
For VPS-level protection beyond the app, see securing your VPS with CrowdSec. For secrets in compose files, see Docker Compose secrets management.
Switching from the Original FileBrowser
Do I need to migrate?
If the original works for you and you accept the risk of an archived project (no more security patches), you can keep running it. But the known unpatched issues — the command execution bugs and non-revocable JWTs — are exactly the kind of thing that ages badly. Quantum is a strict upgrade: same UI concept, actively maintained, and it removed the shell command feature entirely.
What's involved?
Quantum uses a different config format (config.yaml vs settings.json) and a different database schema, so there’s no in-place upgrade:
- Deploy Quantum fresh following the steps above
- Mount the same host directories as sources
- Recreate your users (with 2FA this time)
- Point your reverse proxy at the new container
- Keep the old container running until you’ve verified everything — then stop it
Troubleshooting
Config changes don't apply after editing config.yaml
Quantum caches the config into database.db on first run. Stop the container, delete data/database.db and data/tmp, then start again to re-init from the YAML. Note this also resets users stored in the DB. Prefer the Settings → Sources admin UI for day-to-day changes.
Startup error: Settings.Server.Sources required
Your config.yaml is missing the server.sources key (the docs once showed a wrong top-level sources). The correct structure nests sources under server:
server:
sources:
- path: /srv/workspace
config:
defaultEnabled: truepermission denied on sources or data directory
Since v1.3 the container runs as filebrowser (1000:1000). Make the mounted directories match:
chown -R 1000:1000 /opt/workspace /opt/projects
chown -R 1000:1000 ./dataIf you run with a different UID (e.g. user: "1001:1001"), chown to that instead.
502/503 through the reverse proxy
Check docker logs filebrowser. Common causes:
- Port mismatch — the proxy must target the container’s internal port (80 by default)
baseURL— if you serve Quantum under a path prefix, set the matchingbaseURLin the config- Container not healthy yet — wait for the healthcheck (
start_periodis 10s)
Can't bind port 80/443 inside the container
On rootless engines or stricter capability profiles, a non-root user can’t bind privileged ports. Add cap_add: [NET_BIND_SERVICE] to the service, or just use a high port in server.port and proxy to it.
Backing Up FileBrowser Quantum
What to back up
database.db holds all user accounts, hashed passwords, share settings, and config cache. config.yaml holds your source definitions. The actual served files live in your mounted directories and need their own backup strategy.
The data volume holds everything app-specific:
# Simple daily backup of the whole data directory
cp -r filebrowser/data filebrowser/data.bak-$(date +%Y%m%d)
# Or archive it
tar czf filebrowser-data-$(date +%Y%m%d).tar.gz filebrowser/data
I back up the data/ directory to S3-compatible storage with a cron job, and the source directories are covered by the server’s regular backup routine. Test a restore at least once — a backup you’ve never restored from is not a backup.
Conclusion
FileBrowser Quantum is what FileBrowser should have become: the same self-hosted file manager concept, actively maintained, with multiple sources, modern auth, indexed search, and proper share links — and none of the shell-command attack surface. The Docker Compose setup is a few files and one command: docker compose up -d.
On my server it does double duty: a general file manager behind the reverse proxy, and the file window into my Mastra AI assistant — browse what the agent produces, share it with a link, drop reference files back in. If you’re self-hosting AI agents, I can’t recommend this combination enough.
To monitor server CPU, memory, and disk usage after deployment, check my server monitoring guide.
Explore FileBrowser Quantum

