𝔩𝔢𝔩𝕠𝔭𝔢𝔷
Theme

Homelab

Plex FileBrowser Upload

Adding FileBrowser to Plex: Drag-and-Drop Media Uploads via Web UI

Overview

This article adds FileBrowser as a sidecar container to Plex for drag-and-drop media uploads. Instead of using kubectl cp or temporary pods, you get a web UI where you can drag files directly into your media library. FileBrowser runs alongside Plex in the same pod, sharing the media PVC with write access while Plex keeps read-only access.

Tip

Having trouble? See v1.12.0 for what your setup should look like after completing this article.

Before You Begin

Prerequisites

  • Plex Hardening completed (Plex running on encrypted PVCs)
  • Firewall Rules completed (VLAN segmentation with Trusted → Lab policies)
  • Access to UniFi console for adding firewall rules

What We're Setting Up

ComponentPurpose
FileBrowser sidecarWeb UI for media uploads
LoadBalancer ServiceExpose FileBrowser on port 80
Firewall ruleAllow Trusted VLANs to access FileBrowser

Why Sidecar Instead of Separate Deployment

The Plex media PVC uses ReadWriteOnce - only one pod can mount it at a time. A separate FileBrowser deployment would fail with Multi-Attach error.

By adding FileBrowser as a sidecar container via postRenderers, it runs in the same pod as Plex and shares the volume directly. This pattern matches how playit.gg agents are added to game servers1.

Why Firewall Rule Required

With VLAN segmentation (v3-01), your devices on Trusted VLANs can't reach the Lab VLAN by default. The existing Plex Streaming rule only allows port 32400. FileBrowser needs port 80 allowed from Trusted to Lab.

Configure FileBrowser Sidecar

HelmRelease: Add postRenderers

Add postRenderers to inject the FileBrowser container and an emptyDir volume for its database.

k8s/apps/plex/helmrelease.yaml:

# ... existing HelmRepository + HelmRelease header ...
# ... existing spec.interval, chart, valuesFrom, values ...

postRenderers:
    - kustomize:
          patches:
              - target:
                    kind: StatefulSet
                    name: plex-plex-media-server
                patch: |
                    - op: add
                      path: /spec/template/spec/volumes/-
                      value:
                        name: filebrowser-db
                        emptyDir: {}
                    - op: add
                      path: /spec/template/spec/containers/-
                      value:
                        name: filebrowser
                        image: filebrowser/filebrowser:v2.31.2
                        args:
                          - --noauth
                          - --root=/srv
                          - --database=/database/filebrowser.db
                        ports:
                          - containerPort: 80
                        volumeMounts:
                          - name: media
                            mountPath: /srv
                          - name: filebrowser-db
                            mountPath: /database
                        resources:
                          requests:
                            cpu: 50m
                            memory: 64Mi
                          limits:
                            cpu: 500m
                            memory: 256Mi
Note

Using --noauth since FileBrowser is only accessible from Trusted VLANs behind the firewall. Add authentication if exposing externally.

Service: Expose FileBrowser

Create a LoadBalancer service targeting the Plex pod's FileBrowser container.

k8s/apps/plex/filebrowser-service.yaml:

---
apiVersion: v1
kind: Service
metadata:
    name: filebrowser
    namespace: plex
spec:
    type: LoadBalancer
    selector:
        app.kubernetes.io/name: plex-media-server
        app.kubernetes.io/instance: plex
    ports:
        - port: 80
          targetPort: 80

Kustomization: Add Service

k8s/apps/plex/kustomization.yaml:

# ... existing header ...
resources:
    - namespace.yaml
    - configmap.yaml
    - pvc.yaml
    - secret.sops.yaml
    - helmrelease.yaml
    - networkpolicy.yaml
    - filebrowser-service.yaml # ADD

Create Firewall Rule

Navigate to Settings -> Security -> Zones in UniFi. Click the Trusted -> Lab cell and create a policy.

FieldValue
NameFileBrowser Upload
ActionAllow
ProtocolTCP
Source ZoneTrusted
SourceAny
Destination ZoneLab
DestinationAny
Destination Port80

This allows devices on Trusted VLANs (Unrestricted-Trusted, Things-Trusted, Restricted-Trusted) to reach FileBrowser directly without Tailscale.

Tip

Without this rule, traffic routes through Tailscale's subnet router, reducing upload speeds from ~15 MB/s to ~1.7 MB/s.

Deploy FileBrowser

Git: Commit Changes

cd ~/homelab
git add k8s/apps/plex/helmrelease.yaml k8s/apps/plex/filebrowser-service.yaml k8s/apps/plex/kustomization.yaml
git commit -m "feat(plex): add filebrowser sidecar for media uploads"
git push

Flux: Reconcile

flux reconcile source git flux-system
flux reconcile kustomization sync

The Plex pod will restart with the FileBrowser sidecar (2/2 containers).

Verify FileBrowser

Verify: Pod Running

kubectl get pods -n plex

Expected: plex-plex-media-server-0 shows 2/2 containers running.

Verify: Service IP

kubectl get svc filebrowser -n plex

Expected: External IP assigned by MetalLB (e.g., 192.168.10.51).

Verify: FileBrowser Logs

kubectl logs -n plex plex-plex-media-server-0 -c filebrowser

Expected: Listening on [::]:80

Verify: Web Access

Open http://<EXTERNAL-IP> in your browser. You should see the FileBrowser interface with your media directory.

Verify: Upload Speed

Drag a file into FileBrowser and verify upload speeds:

Access MethodExpected Speed
Direct (firewall rule)~15+ MB/s
Via Tailscale subnet~1-2 MB/s

Next Steps

With FileBrowser configured, you can drag and drop media files directly into your Plex library from any device on your Trusted VLANs.

Resources

Footnotes

  1. L. Lopez, "Factorio playit.gg Public Access," lelopez.io. Accessed: Apr. 11, 2026. [Online]. Available: https://lelopez.io/blog/homelab-v2-11a-factorio-playit-public-access

Previous
Plex Remote Access via frp