Media & object storage for Django in production
User uploads: where they are stored, how they are served, and how to keep them safe and persistent.
Media files are what users upload. They must survive every release and every server replacement, which usually means object storage such as S3 or R2 instead of the local disk.
The guides cover storage setup, private files and signed URLs, direct uploads, backups, and the permission and access errors that uploads run into.
Set it up
Guides that take this from nothing to running in production.
- How to Store Django Media Files on Amazon S3
Local disk storage for Django media files works in development, but it breaks quickly in production.
- Store Django Media Files on Cloudflare R2
Store Django uploads on Cloudflare R2 with django-storages: scoped API tokens, STORAGES settings, custom domains, signed URLs, and migration.
- Serve Private Django Media Files with Nginx X-Accel-Redirect
Serve permission-checked Django downloads efficiently: Django authorises the request and returns X-Accel-Redirect, and an internal Nginx location streams the file without tying up workers.
- Upload Files Directly to S3 from Django with Presigned URLs
Let browsers upload large files straight to S3 with presigned POST policies: size and type limits, bucket CORS, server-side confirmation, FileField wiring, and cleanup of abandoned uploads.
- Store Django Media Files on Google Cloud Storage
Store Django user uploads on Google Cloud Storage with django-storages: create a bucket with uniform access, authenticate with Workload Identity or the runtime service account, serve private files with signed URLs, and set CORS and lifecycle rules.
- Store Django Media Files on Azure Blob Storage
Store Django uploads in Azure Blob Storage with django-storages: create a storage account and private container, authenticate with managed identity instead of account keys, serve files with SAS URLs, and add Azure CDN or Front Door for public assets.
- Store Django Media Files on DigitalOcean Spaces
Store Django uploads on DigitalOcean Spaces with django-storages’ S3 backend: set the regional endpoint, create scoped access keys, choose private files with presigned URLs or public files behind the Spaces CDN, and configure CORS.
- Store Django Media Files on Backblaze B2
Store Django uploads on Backblaze B2 through its S3-compatible API: create a bucket and application key, configure django-storages with the B2 endpoint, serve private files with presigned URLs, and put public files behind Cloudflare.
- Self-Host Django Media Storage With MinIO
Run MinIO as self-hosted S3-compatible storage for Django uploads: deploy it with Docker Compose or systemd, create a bucket and scoped user, configure django-storages, put MinIO behind Nginx with TLS, and back it up.
- Store and Transform Django Media With Cloudinary
Use Cloudinary for Django media uploads: configure django-cloudinary-storage or the Cloudinary SDK, upload user images and video, generate resized and optimized URLs on the fly, sign uploads from the browser, and keep secrets and costs under control.
- Store Django Media on Hetzner Object Storage
Use Hetzner Object Storage for Django media and static files with django-storages: create a bucket and S3 credentials, set the regional endpoint and addressing style, choose public or private access with presigned URLs, configure CORS, and keep costs low next to Hetzner Cloud servers.
- Store Django Media on Wasabi Hot Cloud Storage
Use Wasabi S3-compatible storage for Django media and backups with django-storages: set the regional endpoint, create a restricted policy, serve files with presigned URLs or a CDN, and understand minimum storage duration and egress terms.
- Django Static vs Media Files in Production
Many Django deployments break because static files and media files are treated as the same thing.
- Deploy Wagtail CMS to Production
Deploy a Wagtail site to production: Sites and WAGTAILADMIN_BASE_URL, image renditions and media storage, scheduled publishing, search indexing, document serving, and caching.
- Serve Django Static and Media Files Through Bunny CDN
Put Bunny CDN in front of a Django site: create a pull zone for WhiteNoise static files or an object storage origin, use hashed file names with long cache headers, serve media from Bunny Storage with django-storages, and purge or sign URLs when needed.
Run it well
Tuning, reliability, and operations once it works.
- Serve Optimised Images and Thumbnails From Django
Serve fast, right-sized images from a Django app: generate thumbnails in background tasks, use WebP and AVIF, responsive srcset, CDN or image service resizing, cache headers for media, and avoid resizing images inside web requests.
- Handle Large and Resumable File Uploads in Django
Accept large uploads in Django without timeouts or memory spikes: upload directly to S3 with multipart presigned URLs, use the tus resumable protocol, tune Nginx and Django upload limits, process files in Celery, and validate files after upload.
- Back Up Django Media Files
Back up Django uploads reliably: MEDIA_ROOT with restic, S3 versioning and replication, consistency with database backups, retention, and restores.
- Speed Up Django collectstatic to S3
Make collectstatic to S3 or other object storage fast: skip unchanged files, use storage backends that compare hashes, collect locally then sync with the AWS CLI, skip post-processing where safe, and run it once per release in CI instead of on every server.
Check it
Review lists to run before launch or after a change.
- Django File Upload Security Checklist
Secure user uploads in Django production: size limits at every layer, content-based type checks, image re-encoding, safe file names, private storage, serving user content safely, scanning, and quotas.
- Wagtail Production Checklist
A production checklist for Wagtail CMS sites: WAGTAILADMIN_BASE_URL and Sites, image renditions and storage, search backend, cache invalidation and frontend caching, admin security, scheduled publishing, backups of media, and upgrade routine.
- Django Media Files Production Checklist
A production checklist for Django user uploads: object storage instead of local disk, upload limits and validation, private versus public files, unique names, image processing in workers, CDN delivery, backups and versioning, and cleanup of orphaned files.
Fix it
Errors and symptoms, each traced to a cause and a fix.
- Fix Django Media Files Not Serving (Uploads Broken in Production)
Fix Django media files returning 404 or 403 in production: MEDIA_URL and MEDIA_ROOT, the static() helper, Nginx alias rules, permissions, and object storage.
- Fix Permission Denied on Django Media Uploads
Fix PermissionError when Django saves uploads: service user ownership, MEDIA_ROOT location, upload file modes, systemd sandboxing, Docker volumes, and SELinux.
- Fix RequestDataTooBig and TooManyFieldsSent in Django
Fix Django RequestDataTooBig, TooManyFieldsSent, and TooManyFilesSent errors: what each upload limit measures, raising limits safely per endpoint, and proxy limits.
- Fix AccessDenied Errors Uploading Django Files to S3
Fix AccessDenied from S3 when django-storages uploads files: IAM policy actions, bucket policies, Object Ownership and ACLs, KMS keys, and credentials.
- Fix Uploaded Files Disappearing After a Django Redeploy
Fix Django media uploads that vanish after a redeploy: ephemeral container and PaaS filesystems, MEDIA_ROOT inside release directories, missing volumes, and moving uploads to object storage.
- Fix Pillow Errors on Django Image Uploads in Production
Fix Pillow errors when uploading images to Django in production: Cannot use ImageField because Pillow is not installed, decoder jpeg not available, cannot identify image file, DecompressionBombError, and HEIC uploads.
- Fix django-storages Overwriting Files With the Same Name
Fix uploads replacing each other on S3 or R2 with django-storages: understand AWS_S3_FILE_OVERWRITE, generate unique upload_to paths, avoid cache-stale files at the same URL, and recover overwritten objects with bucket versioning.
- Fix S3 SignatureDoesNotMatch and AWS4-HMAC-SHA256 Errors in Django
Fix SignatureDoesNotMatch and The authorization mechanism you have provided is not supported, please use AWS4-HMAC-SHA256 in django-storages: set the bucket region and signature version, fix presigned URLs, clock skew, and custom endpoints for R2, Spaces, and MinIO.
- Fix django-storages "AccessControlListNotSupported: The Bucket Does Not Allow ACLs"
Fix the S3 error AccessControlListNotSupported, the bucket does not allow ACLs, in django-storages: stop sending ACL headers with default_acl None, use bucket policies for public static files, and keep private media behind presigned URLs.
- Fix Django SuspiciousFileOperation: Joined Path Is Outside the Base Path
Fix Django SuspiciousFileOperation errors such as the joined path is located outside of the base path component and detected path traversal attempt: build upload paths safely, avoid absolute names and leading slashes, and handle static files referenced with ../.
- Fix Nginx 413 Request Entity Too Large for Django Uploads
If a Django file upload fails with 413 Request Entity Too Large, the rejection usually happens before Django sees the request. In a production stack like:
- Fix boto3 NoCredentialsError in Django
Fix botocore NoCredentialsError Unable to locate credentials in Django with django-storages or SES: give the process an IAM role or environment credentials, fix systemd and Docker env loading, IMDSv2 hop limits, and region settings.