File Browser in Depth: What It Is and How to Run It on Kubernetes
File Browser is a lightweight, self-hosted web file manager: upload, download, preview, share links, and manage users—all through a browser, backed by a directory on disk. This guide explains how it works under the hood, when it fits (and when it does not), how to configure it safely, and how to deploy it on Kubernetes with persistent storage, secrets, Ingress, and production-minded hardening.
In short
File Browser serves files from a root path on a volume and stores users, permissions, and share metadata in a SQLite database. On Kubernetes: mount a PVC for /srv (files) and /config (database), bootstrap admin credentials with an init container, expose a Deployment + Service, front it with Ingress + TLS, and treat it like any privileged admin surface—strong auth, network restrictions, and backups.
What File Browser is (and is not)
File Browser (often written filebrowser, project repo filebrowser/filebrowser) is a single Go binary with a built-in web UI. You point it at a filesystem directory—the root—and it becomes a multi-user file portal with role-based rules, public share links, and basic file operations (rename, move, zip, preview for common types).
It is not a replacement for object storage (S3, MinIO), a sync client (Nextcloud, Syncthing), or an enterprise document platform. It is a pragmatic choice when you need a small team to browse and exchange files on a server, NAS export, or PVC-backed folder without building a custom UI.
| Good fit | Poor fit |
|---|---|
| Internal file drop for ops, ML datasets on a shared volume, homelab media | Internet-facing anonymous uploads without hardening |
| Quick UI on top of an NFS/EFS mount already used by batch jobs | Fine-grained compliance workflows (legal hold, DLP, audit trails beyond basics) |
| Teaching Kubernetes storage + Ingress with a real app | Millions of small files or heavy concurrent writes (SQLite + single replica limits) |
For Kubernetes fundamentals—Pods, Services, storage—see Kubernetes architecture in simple terms, hands-on Part 3 (workloads), and PV, PVC, and StorageClass.
Architecture: three pieces that matter
Operationally, File Browser is three concerns wired together:
- File root — The directory users see (e.g.
/srv). Everything under this tree is reachable according to user rules. - SQLite database — Default
filebrowser.dbholds users, password hashes, share links, and per-path permission rules. Losing this file loses accounts and shares (not necessarily the files themselves). - HTTP server — Serves the SPA UI and JSON API on a TCP port (default
80in the official container image).
The process is typically started with flags such as --root, --database, and --port. Configuration can also be prepared offline with the CLI (filebrowser config init, filebrowser users add) before the server starts—this pattern maps cleanly to Kubernetes init containers.
Request path (mental model)
Browser → Ingress (TLS) → Service → Pod:8080 → File Browser
├─ reads/writes /srv (PVC)
└─ reads/writes /config/filebrowser.db (PVC)
Authentication is session-based in the app layer. Kubernetes RBAC governs who can change manifests; it does not replace File Browser login. For defense in depth, combine both.
Configuration deep dive
CLI and database bootstrap
On first install you initialize config and create an admin user against the database path you will use in production:
# Paths match the Kubernetes mounts in the manifests below
filebrowser config init \
--database=/config/filebrowser.db
filebrowser users add admin "$FB_ADMIN_PASSWORD" \
--database=/config/filebrowser.db \
--perm.admin
Additional users, per-directory scopes, and “execute” permissions are managed with filebrowser users and filebrowser rules. Prefer scoped non-admin users for day-to-day access; reserve admin for break-glass.
Runtime flags (container entrypoint)
Common production-oriented flags:
--root=/srv— File tree exposed in the UI.--database=/config/filebrowser.db— Keep the DB on persistent disk, not the container layer.--port=8080— Listen on a non-privileged port inside the pod (matches probes and ServicetargetPort).--address=0.0.0.0— Required in containers so the process accepts traffic from the cluster network.
Avoid --noauth outside local labs. Anonymous admin UIs on cluster networks have led to many incident reports across similar tools.
Branding and settings
Advanced installs mount a settings.json (branding, signup toggles, command execution). Treat that file like code: store in a ConfigMap only if it contains no secrets; keep credentials in Secret objects and inject via env vars referenced by init containers.
Kubernetes setup: end-to-end manifests
The following example deploys File Browser into namespace filebrowser with one replica, two PVCs (files + config), an init container to create the admin user once, ClusterIP Service, and Ingress. Adjust storage class, hostnames, and resource sizes for your cluster.
0 — Prerequisites
- A working cluster and
kubectlcontext (local lab: hands-on Part 1). - A StorageClass for dynamic PVCs (storage guide).
- An Ingress controller (nginx, Traefik, etc.) and optionally cert-manager for TLS.
1 — Namespace and secrets
apiVersion: v1
kind: Namespace
metadata:
name: filebrowser
---
apiVersion: v1
kind: Secret
metadata:
name: filebrowser-admin
namespace: filebrowser
type: Opaque
stringData:
FB_ADMIN_PASSWORD: "change-me-before-apply"
Generate a strong password (openssl rand -base64 24) and prefer sealing or external secrets in production rather than committing plaintext.
2 — PersistentVolumeClaims
Splitting data and config lets you resize, snapshot, or restore them independently. For NFS/EFS (ReadWriteMany), you can run more than one replica only if the app and database semantics allow it—File Browser’s embedded SQLite expects one writer; use replicas: 1 unless you externalize the database.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: filebrowser-files
namespace: filebrowser
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: standard # replace with your class
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: filebrowser-config
namespace: filebrowser
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: standard
3 — Deployment with init bootstrap
The init container uses the same image as the app and only runs CLI commands. The main container mounts both PVCs read/write, runs as non-root where possible, and defines probes on the HTTP port.
apiVersion: apps/v1
kind: Deployment
metadata:
name: filebrowser
namespace: filebrowser
labels:
app.kubernetes.io/name: filebrowser
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: filebrowser
template:
metadata:
labels:
app.kubernetes.io/name: filebrowser
spec:
securityContext:
fsGroup: 1000
initContainers:
- name: bootstrap
image: filebrowser/filebrowser:v2.27.0
imagePullPolicy: IfNotPresent
env:
- name: FB_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: filebrowser-admin
key: FB_ADMIN_PASSWORD
command:
- /bin/sh
- -c
- |
set -e
if [ ! -f /config/filebrowser.db ]; then
filebrowser config init --database=/config/filebrowser.db
filebrowser users add admin "$FB_ADMIN_PASSWORD" \
--database=/config/filebrowser.db \
--perm.admin
fi
volumeMounts:
- name: config
mountPath: /config
containers:
- name: filebrowser
image: filebrowser/filebrowser:v2.27.0
imagePullPolicy: IfNotPresent
args:
- --root=/srv
- --database=/config/filebrowser.db
- --port=8080
- --address=0.0.0.0
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 3
periodSeconds: 10
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 10
periodSeconds: 20
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
volumeMounts:
- name: files
mountPath: /srv
- name: config
mountPath: /config
volumes:
- name: files
persistentVolumeClaim:
claimName: filebrowser-files
- name: config
persistentVolumeClaim:
claimName: filebrowser-config
Permission tip: If the pod stays CrashLoopBackOff with “permission denied” on EFS/NFS, check UID/GID alignment (fsGroup, storage mount options) or consult provider docs—this is a common class of issues when mounting shared filesystems. See also the Kubernetes troubleshooting playbook.
4 — Service
apiVersion: v1
kind: Service
metadata:
name: filebrowser
namespace: filebrowser
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: filebrowser
ports:
- name: http
port: 80
targetPort: http
For local testing without Ingress: kubectl port-forward -n filebrowser svc/filebrowser 8080:80 then open http://127.0.0.1:8080.
5 — Ingress (TLS)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: filebrowser
namespace: filebrowser
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- files.example.com
secretName: filebrowser-tls
rules:
- host: files.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: filebrowser
port:
number: 80
Replace files.example.com, ingressClassName, and issuer annotations to match your platform. Restrict source IPs or place an OAuth2 proxy in front if the UI is reachable outside a trusted network.
Apply and verify
kubectl apply -f filebrowser/
kubectl get pods,svc,pvc -n filebrowser
kubectl logs -n filebrowser deploy/filebrowser -c bootstrap
kubectl logs -n filebrowser deploy/filebrowser -c filebrowser --tail=50
Expected flow: PVCs bound → init container creates DB once → main container listens on 8080 → Ingress routes HTTPS to the Service. Log in with user admin and the password from the Secret; change it in the UI or rotate the Secret and re-bootstrap only with a clear recovery plan.
Helm and GitOps alternatives
There is no official Helm chart merged in the upstream repo at the time of writing; community charts exist (for example third-party “filebrowser-chart” repositories). If you already standardize on Helm or GitOps, wrap the same primitives—PVC, Secret, Deployment, Service, Ingress—in a chart and pin image digests. The important part is not the packaging tool but the contract: persistent config, single replica with SQLite, version-pinned image, and sealed secrets.
Security hardening checklist
- Authentication — Never expose
--noauthon a network you do not fully trust. - TLS everywhere — Terminate HTTPS at Ingress; consider HSTS for public hostnames.
- NetworkPolicy — Allow Ingress controller → Pod only; deny east-west traffic you do not need.
- Least privilege users — Scoped folders per team; disable command execution unless required.
- Resource limits — Cap CPU/memory to avoid noisy-neighbor impact on shared nodes (day-one practices).
- Audit and backups — Snapshot PVCs or sync
/srvto object storage; exportfilebrowser.dbon a schedule. - Upgrades — Read release notes; test image bumps in a staging namespace before rolling production.
File Browser is effectively a remote admin surface over files. Treat it with the same seriousness as kubectl exec access to a node.
Operations: backup, upgrade, troubleshoot
Backup
- Files — Volume snapshots (CSI),
restic, or rsync from/srv. - Database — Copy
filebrowser.dbwhile quiesced or use brief maintenance windows; SQLite is sensitive to partial copies under write load.
Upgrade image tag
kubectl set image deployment/filebrowser -n filebrowser \
filebrowser=filebrowser/filebrowser:v2.27.0
kubectl rollout status deployment/filebrowser -n filebrowser
Prefer Git-managed manifest bumps over imperative sets when practicing GitOps.
Common failures
| Symptom | Likely cause | What to check |
|---|---|---|
Pod Pending |
PVC not bound | kubectl describe pvc -n filebrowser, StorageClass, quota |
CrashLoopBackOff on start |
Volume permissions | Pod events, fsGroup, mount UID on NFS/EFS |
| 502 from Ingress | Service has no endpoints | Label selectors, readiness probe failing |
| Login fails after redeploy | Ephemeral DB lost | Confirm /config PVC mounted; init only ran on empty DB |
When to choose something else
If you need S3 APIs, versioning, and IAM-style policies, use object storage and a dedicated client. If you need sync, calendar, and collaboration, use a full collaboration suite. File Browser shines when the requirement is simply: “give me a secure browser UI on top of this directory in the cluster.”
Further reading
- File Browser documentation — filebrowser.org (install, CLI, configuration)
- Kubernetes storage: PV, PVC, StorageClass
- Kubernetes cluster RBAC
- Kubernetes troubleshooting playbook
- Docker and containers — image layers vs mounted volumes