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
| Tool | Open Source | Full Features | Notes |
|---|---|---|---|
| copyparty | Yes | Yes | Best at bulk transfer (resumable uploads, WebDAV, FTP); own user model, dated UI |
| SFTPGo | Yes | Yes | The right tool for giving someone an SFTP or WebDAV endpoint with an expiry; heavy for browsing |
| Nextcloud external storage | Yes | Yes | No 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
filebrowserDeployment in thefilebrowser-quantumnamespace,Recreatestrategy - Image:
ghcr.io/gtsteffaniak/filebrowser, the-stablechannel, pinned by tag and digest - Config:
http,server,sourcesandauthin aconfig.yamlfrom the overlay, mounted read-only and pointed at byFILEBROWSER_CONFIG; the SQLite path isserver.database.pathin that file, since v2 refuses to start while the removedFILEBROWSER_DATABASEis set - Storage: a Longhorn-encrypted PVC for the database (users, shares, settings), an
emptyDirfor 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,RuntimeDefaultseccomp, no service-account token - Keycloak OIDC enforced at the gateway by the
oidc-filebrowserSecurityPolicyon 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/shareredirect; 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.yamlfrom aconfigMapGeneratorin 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 clientfilebrowser; 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 clientfilebrowser, realmkueber.eu, redirecthttps://files.web.kueber.eu/oauth2/callback) targets only the catch-allfilebrowserHTTPRoute. 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/shareredirect — 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 dedicatedBackendvalidated against the proxy image's system CA bundle (wellKnownCACertificates: System), since the in-cluster DNS view ofkeycloak.web.kueber.eupoints back at the gateway. The Keycloak client is created by the TofuWorkspace (workspace/patch-oidc.yaml,clientId: filebrowsersince the namespace isfilebrowser-quantum, not gated) and the policy reads its secret fromworkspace-outputs. - One source per share (
config.yaml) — the eight TrueNAS NFS claims are mounted under/srv/<share>and declared as separate sources, alldefaultEnabled, instead of one/srvtree. 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
filebrowserapp 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.
- 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