Blog

How Media Storage Works

by Elder.Evil

Images, renditions, and uploads all go to RustFS S3 — no local disk, no PVC for media.

When you upload an image in the Wagtail admin, it doesn’t land on the server’s disk. Instead, it goes straight to RustFS — an S3-compatible object store running right here on the cluster.

The pipeline

Every upload follows the same path:

  1. You drop an image into the Wagtail admin
  2. Django hands it to django-storages
  3. The file lands in the blog-media bucket on RustFS
  4. Wagtail auto-generates renditions (thumbnails, crops) — also stored in S3
  5. The public URL points directly to s3-api.evillab.tech

Why not local disk?

Running on a single-node k3s cluster means the pod can restart, reschedule, or get replaced. A PVC for media files works, but S3 is simpler: no volume management, no permissions headaches, and backups are a bucket sync away.

The code

# settings.py
AWS_S3_ENDPOINT_URL = "https://s3-api.evillab.tech"
AWS_STORAGE_BUCKET_NAME = "blog-media"

STORAGES = {
"default": {"BACKEND": "storages.backends.s3.S3Storage"},
}

One gotcha

Django 6.0 requires the STORAGES dict — the old DEFAULT_FILE_STORAGE setting is ignored. If you skip it, uploads silently fall back to the local filesystem. Took 20 minutes to debug.

← Back to blog