Nginx responds 404 not found on Django media URL in preprod, dev ok

I have a quite standard Django application with a Vuejs frontend.

I have different environments (preprod/dev) in which I have file upload/download features.

For files, everything works fine because they are returned through standard API views in attachment (Content-Disposition: attachment). When it comes to images though, like profile pictures, there is a problem.

In development (DEBUG=True), I have this :

from django.conf import settings
from django.conf.urls.static import static
from django.urls import include, path

from backend.applications.base.views.authentication_views import LoginAPIView, LogoutAPIView

urlpatterns = [
    path("api/login", LoginAPIView.as_view()),
    path("api/logout", LogoutAPIView.as_view()),
    path("api/base/", include("backend.applications.base.urls")),
    path("api/contact/", include("")),
    path("api/helpdesk/", include("backend.applications.helpdesk.urls")),
    path("api/inventory/", include("backend.applications.inventory.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)  # For serving media files when DEBUG=True

and images are correctly served (no nginx in dev mode, just frontend and backend dev servers django's runserver).

My preprod however, is made of a nginx container which serves my built vuejs frontend, and a backend container which contains my Django (DEBUG=False) application (which runs with gunicorn this time, like this : gunicorn backend.wsgi:application --bind --access-logfile="-").

Before trying to serve images, I had this nginx configuration :

http {
    client_max_body_size 5M;

    upstream backend_api {
        server backend:8000;
        # 'backend' is the name of the backend service in my docker-compose config

    server {
        listen 80;

        include /etc/nginx/mime.types;

        root /usr/share/nginx/html;
        index index.html;

        location = /favicon.ico {
            access_log off;
            log_not_found off;

        location /api {
            proxy_pass http://backend_api;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_redirect off;

        location / {
            try_files $uri $uri/ /index.html;

Then I thought that /media requests should also be passed to the backend and I changed

location /api


location ~ ^/(api|media)/ {

My /api URLs are still handled correctly but /media URLs are answered by a 404 :

trying to load profile pictures of my user(s) in a kanban view (trying to load profile pictures of my user(s) in a kanban view).

Also trying directly http://localhost/media/base/users/8/picture.jpg directly in my browser doesn't work :

enter image description here enter image description here

From here I don't know what to do to solve the issue. If something is missing, mention it and I'll update the post. I think that is because my urlpatterns do not have media/ route but I do not know how I should handle this..

Thanks in advance for your help !

Django does not serve static- and media files with runserver, you will need WhiteNoise for that. See Whitenoise however is not suitable for serving user-uploaded media files. See

(Optionally, skip whitenoise, and host static/media files through NGINX.)

You really shouldn't be hosting your server with py runserver. This is not secure. See Why not use "runserver" for production at Django? and

Use something like Gunicorn instead.


(Or waitress, the windows alternative)

To host static/media files with nginx, paste this into your nginx conf:

    location /media  {
        alias /PATH/TO/DIRECTORY; #Absolute path.

And in your, set the media root to that same directory.

Back to Top