Skip to main content

FileBrowser Quantum

A web file manager with multiple sources, search, previews and share links.

FileBrowser Quantum is the actively maintained fork of the original File Browser, which upstream archived in September 2026. It keeps the single-binary, one-page UI of its parent and adds what the parent never had: several sources instead of one root, an index for instant search, OIDC and proxy login, and share links with upload. It took over from Filebrowser in October 2026 on files.web.kueber.eu, and the same image serves the file view of Stagggy on the internal gateway.

Alternatives considered​

Self Hosted

ToolOpen SourceFull FeaturesNotes
copypartyYesYesBest at bulk transfer (resumable uploads, WebDAV, FTP); own user model, dated UI
SFTPGoYesYesThe right tool for giving someone an SFTP or WebDAV endpoint with an expiry; heavy for browsing
Nextcloud external storageYesYesNo new app, but slow on large external trees and a sharing workflow built for documents

Quantum won because it is a drop-in for the job the old app did, and because its two additions map onto this deployment: one source per NFS share instead of a tree of mount points, and a login model that does not need the gateway to do everything.

Installation​

Architecture​

  • Deployment: single filebrowser Deployment in the filebrowser-quantum namespace, Recreate strategy
  • Image: ghcr.io/gtsteffaniak/filebrowser, the -stable channel, pinned by tag and digest
  • Config: http, server, sources and auth in a config.yaml from the overlay, mounted read-only and pointed at by FILEBROWSER_CONFIG; the SQLite path is server.database.path in that file, since v2 refuses to start while the removed FILEBROWSER_DATABASE is set
  • Storage: a Longhorn-encrypted PVC for the database (users, shares, settings), an emptyDir for the thumbnail cache, and the eight TrueNAS NFS shares mounted read-write, one source each
  • Networking: ClusterIP on port 80; two HTTPRoutes on the public gateway, see below

Security​

  • Runs as runAsUser: 1000, runAsNonRoot: true, allowPrivilegeEscalation: false, all capabilities dropped, RuntimeDefault seccomp, no service-account token
  • Keycloak OIDC enforced at the gateway by the oidc-filebrowser SecurityPolicy on the catch-all route; Quantum's own password login is the inner gate
  • Anonymous share links bypass the gateway policy through a second route that carries only /public (share pages, their assets and the hash-validated public API) and the legacy /share redirect; the share hash and optional share password are checked by the app
  • Network policies admit only the public gateway's Envoy pods; egress is the namespace baseline
  • The config database PVC is encrypted at rest; the NFS shares are TrueNAS-owned

Updates​

Managed by Renovate. Upstream publishes <version>-stable and <version>-beta tags in parallel; the -stable suffix keeps Renovate on that channel, so a 2.x-beta never shows up as an update. The 2.0 line changes the config layout (HTTP settings move out of server) and the database to SQLite; moving to it is a deliberate migration with the upstream tool, not a bump.

Data Management​

  • PVC: filebrowser-config (1Gi, Longhorn-encrypted) holds the database; the first start creates it empty, so users and share links from the retired app were not migrated
  • Sources: archive, audio, downloads, gaming, images, reading, stash, videos, each a TrueNAS NFS share, all enabled for new users; the index of every source lives in memory, which is why the pod has headroom the old one never needed
  • Backups: k8up Schedules to Hetzner and Backblaze via restic, covering the database PVC; the shares are not part of it

User Management​

Two gates in sequence. The gateway SecurityPolicy sends every browser to Keycloak first (client filebrowser, realm kueber.eu); whoever passes lands on Quantum's own login, where accounts are local and signup is off. The built-in admin takes its password from the SOPS Secret through FILEBROWSER_ADMIN_PASSWORD. Quantum could do OIDC itself, which would fold the two gates into one; that stays an option, not the setup today.

Configuration Management​

  • config.yaml from a configMapGenerator in the overlay; a change rolls the pod
  • Admin password and the Longhorn encryption key from SOPS-encrypted Secrets
  • OIDC client secret in workspace-outputs, minted by the workspace that creates the client filebrowser; consumed by the gateway policy, not the app

Usage​

Open files.web.kueber.eu, log in with Keycloak and then with the Quantum account. Each share is a source in the sidebar; search spans all of them. Share a file or folder from its context menu; the link works without a login until it expires, with an optional password. Stagggy's copy at stagggy-files.int.kueber.eu shows one source, the stagggy stash, has no share links, and keeps its users in a throwaway database that is recreated on each start.

Cluster-specific deviations from the above live in the per-cluster README — see k8s/apps/filebrowser-quantum/talos/README.md.

Cluster Deployment​

FileBrowser Quantum — Talos cluster

Deviations from defaults​

  • OIDC at the gateway with a public-share carve-out — the Envoy Gateway SecurityPolicy (security-policy.yaml, Keycloak client filebrowser, realm kueber.eu, redirect https://files.web.kueber.eu/oauth2/callback) targets only the catch-all filebrowser HTTPRoute. The second route, filebrowser-share, carries what an anonymous share visitor needs — /public (share page, assets and the hash-validated public API) and the legacy /share redirect — and wins by longest path match, so shared links work without a Keycloak login. Quantum's own login remains the inner gate. Envoy reaches the issuer through a dedicated Backend validated against the proxy image's system CA bundle (wellKnownCACertificates: System), since the in-cluster DNS view of keycloak.web.kueber.eu points back at the gateway. The Keycloak client is created by the TofuWorkspace (workspace/patch-oidc.yaml, clientId: filebrowser since the namespace is filebrowser-quantum, not gated) and the policy reads its secret from workspace-outputs.
  • One source per share (config.yaml) — the eight TrueNAS NFS claims are mounted under /srv/<share> and declared as separate sources, all defaultEnabled, instead of one /srv tree. Users see sources, not mount points.
  • Memory headroom — Quantum indexes every source into memory and watches it. 256Mi request, 1Gi limit for eight shares with large media trees; the archived filebrowser ran in 128Mi because it never indexed anything. Revisit once the first days of metrics are in.
  • Carried over, not migrated — the admin password and the Longhorn encryption key moved over from the retired filebrowser app unchanged (the Keycloak client did too, until the workspace took it over on 2026-10-20). The database did not: Quantum's schema is its own, so users and share links start empty.
Kubernetes Metadata
  • Image: ghcr.io/gtsteffaniak/filebrowser:2.0.1-stable@sha256:2e3936caf7b12908f7d3ebb68ddfcea075cda5f732e4bd95beae6cfa529cbec7
Rendered manifests (kustomize build)
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kustomize.toolkit.fluxcd.io/force: enabled
labels:
app.kubernetes.io/name: filebrowser
name: filebrowser
namespace: filebrowser-quantum
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
app.kubernetes.io/name: filebrowser
strategy:
type: Recreate
template:
metadata:
labels:
app.kubernetes.io/name: filebrowser
spec:
automountServiceAccountToken: false
containers:
- env:
- name: FILEBROWSER_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
key: adminPassword
name: filebrowser
- name: FILEBROWSER_CONFIG
value: /config/config.yaml
image: ghcr.io/gtsteffaniak/filebrowser:2.0.1-stable@sha256:2e3936caf7b12908f7d3ebb68ddfcea075cda5f732e4bd95beae6cfa529cbec7
livenessProbe:
httpGet:
path: /health
port: web
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 5
name: filebrowser
ports:
- containerPort: 80
name: web
protocol: TCP
readinessProbe:
failureThreshold: 1
httpGet:
path: /health
port: web
initialDelaySeconds: 2
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 2
resources:
limits:
memory: 1Gi
requests:
cpu: 50m
memory: 256Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
volumeMounts:
- mountPath: /srv/archive
name: filebrowser-archive
- mountPath: /srv/audio
name: filebrowser-audio
- mountPath: /srv/downloads
name: filebrowser-downloads
- mountPath: /srv/gaming
name: filebrowser-gaming
- mountPath: /srv/images
name: filebrowser-images
- mountPath: /srv/reading
name: filebrowser-reading
- mountPath: /srv/stash
name: filebrowser-stash
- mountPath: /srv/videos
name: filebrowser-videos
- mountPath: /config
name: config
readOnly: true
- mountPath: /database
name: database
- mountPath: /cache
name: cache
priorityClassName: tier-2
securityContext:
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
volumes:
- name: database
persistentVolumeClaim:
claimName: filebrowser-config
- name: filebrowser-archive
persistentVolumeClaim:
claimName: filebrowser-truenas-nfs-archive
- name: filebrowser-audio
persistentVolumeClaim:
claimName: filebrowser-truenas-nfs-audio
- name: filebrowser-downloads
persistentVolumeClaim:
claimName: filebrowser-truenas-nfs-downloads
- name: filebrowser-gaming
persistentVolumeClaim:
claimName: filebrowser-truenas-nfs-gaming
- name: filebrowser-images
persistentVolumeClaim:
claimName: filebrowser-truenas-nfs-images
- name: filebrowser-reading
persistentVolumeClaim:
claimName: filebrowser-truenas-nfs-reading
- name: filebrowser-stash
persistentVolumeClaim:
claimName: filebrowser-truenas-nfs-stash
- name: filebrowser-videos
persistentVolumeClaim:
claimName: filebrowser-truenas-nfs-videos
- configMap:
name: filebrowser-config-g9kth4mc6g
name: config
- emptyDir: {}
name: cache