Django Static and Media Files on a VPS: Separate Their Lifecycles
Keep generated assets replaceable and user uploads persistent with a deployment layout you can verify.
Missing CSS after a Django release and disappearing uploads after a container replacement usually have different causes. Static assets come from your application and build process. Media files arrive while the application is running and may be irreplaceable customer data. Treating both as one directory makes upgrades and restores fragile. A VPS gives you control over the storage layout, but that also makes the distinction your responsibility. Record the storage owner for each path alongside its backup schedule so deployment automation cannot mistake customer uploads for disposable build output.
Identify what can be rebuilt
Stylesheets, JavaScript bundles, and application icons should be reproducible from a specific release. A customer's attached document cannot be recreated from your Git repository. Make an inventory of each file type, its writer, its reader, and its recovery source. Include generated reports: some can be recreated from database records, while signed exports may need retention. This exercise determines which directories belong in deployment artifacts and which belong in the application backup plan.
Publish static files as part of the release
The Django static deployment documentation describes collecting assets and arranging for a web server or storage backend to serve them. Validate collection before switching live application workers. If templates reference hashed asset names, the corresponding files must already exist. Keep earlier assets for a sensible overlap period when old pages may still be open in browsers. Removing every previous bundle immediately can break a long lived tab after an otherwise successful release.
Give media an independent home
Store user uploads outside the release directory and ensure the application has the required access without making the directory broadly writable. Container deployments need an explicit persistent mount or an appropriate storage backend. Record the absolute storage location in your operations notes; a relative path can change meaning when the working directory changes. Uploaded content should be served as data and never interpreted as executable application code, a boundary highlighted in Django's deployment guidance.
Diagnose the right layer
When an image fails, inspect its actual URL and response status in the browser. A 404 may indicate a wrong URL prefix, a missing file, or an old asset reference. A permission failure points elsewhere. Compare the requested path with the configured document root before changing Django settings. For example, if the browser requests a new hashed stylesheet but only the old hash exists, repeating migrations will not help. Repair the missing artifact and rerun the page check.
Test replacement and recovery
Upload a distinctive test file, deploy a new release, and confirm that the same database record still opens the same file. Restart the application and repeat the check. In a disposable environment, restore a coordinated database and media backup and verify several older uploads as well. A database restore alone may leave references to absent files. Use LayerOne's backup responsibility guide when planning off-server copies, and leave storage headroom for both retained releases and growing media when reviewing VPS sizes.