title: Serve Django Media Files via Nginx (Django/React/Nginx/Docker-Compose)
body: <h2>Context</h2>
  
  <p>I have a single page web app using the following stack:</p>
  
  <ul>
  <li>React for the frontend</li>
  <li>Django for the backend </li>
  <li>Nginx for the webserver</li>
  </ul>
  
  <p>The web application is dockerized using <code>docker-compose</code>. My React app, fetches data from the Django server (django is built as an api endpoint using Django Rest Framework).</p>
  
  <h2>Question/Problem</h2>
  
  <p>I am having an issue on deployment where I am unable to serve my media files via Nginx.</p>
  
  <h2>What have I tried so far</h2>
  
  <p>My initial thought was to serve the media files as shown on this stackoverflow <a href="https://stackoverflow.com/questions/8370658/how-to-serve-django-media-files-via-nginx">post</a> - which is pretty straight forward. Though, since Nginx runs in its own docker (and so does my django server), I unable to point to my django media files since they are in different containers.</p>
  
  <p>Ideally, I would not want to use webpack, and have Nginx take care of serving media files.</p>
  
  <p>If you look at the nginx Dockerfile below, you will see that I am copying my static files into <code>/usr/share/nginx/html/static/staticfiles</code> to then serve them using nginx (see <code>location ^~ /static/</code> in <code>nginx.conf</code>). I have tried to do the same thing for my media file (as a test) and it works - though, all the files I am uploding once the site is up are not accessible since the copy happens when I build my container.</p>
  
  <h2>File Structure</h2>
  
  <pre><code>Root Dirc  
   |__ docker-compose.yml  
   |__ backend  
        |__ root  
             |__ Project
                  |__ api
                       |__ models.py
                       |__ ...
                  |__ media
             |__ teddycrepineau
                  |__ settings.py
                  |__ ...
             |__ production
                  |__ Dockerfile
   |__ nginx
        |__ Dockerfile
        |__ nginx.conf
   |__ frontend
        |__ ...
  </code></pre>
  
  <h2>Relevant Code</h2>
  
  <p><strong>docker-compose.yml</strong>  </p>
  
  <pre><code>version: '3'
  
  volumes:
    postgres_data: {}
    postgres_backup: {}
  
  services:
    postgres:
      image: postgres
      volumes: 
        - postgres_data:/var/lib/postgresql/data
        - postgres_backup:/backups
      env_file: .env
  
    nginx:
      container_name: nginx
      build:
        context: .
        dockerfile: ./nginx/Dockerfile
      image: nginx
      restart: always
      depends_on: 
        - django
      ports:
        - "80:80"
  
    django:
      container_name: django
      build:
        context: backend
        dockerfile: ./root/production/Dockerfile
      hostname: django
      ports:
        - 8000:8000
      volumes:
        - ./backend:/app/
      depends_on: 
        - postgres
      command: &gt;
        bash -c '
        python3 ./root/manage.py makemigrations &amp;&amp;
        python3 ./root/manage.py migrate &amp;&amp;
        python3 ./root/manage.py initadmin &amp;&amp;
        gunicorn teddycrepineau.wsgi -b 0.0.0.0:8000 --chdir=./root/'
  
      env_file: .env
  </code></pre>
  
  <p><strong>nginx.conf</strong></p>
  
  <pre><code>user nginx;
  worker_processes 1;
  
  error_log   /var/log/nginx/error.log warn;
  pid         /var/run/nginx.pid;
  
  events {
      worker_connections  1024;
  }
  
  http {
      include         /etc/nginx/mime.types;
      default_type    application/octet-stream;
  
      log_format main '$remote_addr - $remote_user [$time_local] "$request" '
      '$status $body_bytes_sent "$http_referer" '
      '"$http_user_agent" "$http_x_forwarded_for"';
  
      access_log      /var/log/nginx/access.log main;
  
      upstream app {
          server django:8000;
      }
  
      server {
          listen  80 default_server;
          listen  [::]:80 default_server;
          server_name 0.0.0.0;
          charset utf-80;
  
          root /usr/share/nginx/html;
          index index.html;
  
          location / {
              try_files $uri $uri/ @proxy_to_app;
          }
  
          location @proxy_to_app {
              rewrite ^(.+)$ /index.html last;
          }
  
          location ^~ /static/ {
              autoindex on;
              alias /usr/share/nginx/html/static/;
          }
  
          location ~ ^/api {
              proxy_pass http://django:8000;
          }
          location ~ ^/admin {
              proxy_pass http://django:8000;
          }
      }
  }
  </code></pre>
  
  <p><strong>nginx Dockerfile</strong>  </p>
  
  <pre><code>FROM nginx:latest
  ADD ./nginx/nginx.conf /etc/nginx/nginx.conf
  COPY ./frontend/build /usr/share/nginx/html
  COPY ./backend/root/staticfiles /usr/share/nginx/html/static/staticfiles
  </code></pre>
  
  <p><strong>Django Dockerfile</strong></p>
  
  <pre><code>FROM python:3.7
  
  ENV PYTHONUNBUFFERED 1
  
  RUN export DEBIAN_FRONTEND=noninteractive
  
  RUN mkdir /app
  
  RUN pip install --upgrade pip
  ADD /root/requirements.txt /app/
  
  WORKDIR /app/
  ADD . /app/
  
  RUN pip install -r requirements.txt
  
  EXPOSE 8000
  </code></pre>
  
  <p><strong>Django settings.py</strong></p>
  
  <pre><code>BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  APPS_DIR = os.path.join(BASE_DIR, 'project')
  ....
  MEDIA_URL = '/media/'
  MEDIA_ROOT = os.path.join(APPS_DIR, 'media/')
  </code></pre>
  
  <p><strong>Django urls.py</strong>  </p>
  
  <pre><code>urlpatterns = [
      path('admin/', admin.site.urls),
      re_path(r'^api/', include('project.api.urls')),
      path('summernote/', include('django_summernote.urls')),
  ] 
  urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  </code></pre>
  
  <hr>
  
  <hr>
  
  <h2>Update</h2>
  
  <p>When I mount a shared volum and reference it in my <code>nginx.conf</code> I get a <code>404 page not found</code> when trying to access the image uploaded in the django backend.</p>
  
  <p><strong>docker-compose.yml</strong>  </p>
  
  <pre><code>version: '3'
  
  volumes:
    postgres_data: {}
    postgres_backup: {}
  
  services:
    postgres:
      image: postgres
      volumes: 
        - postgres_data:/var/lib/postgresql/data
        - postgres_backup:/backups
      env_file: .env
  
    nginx:
      container_name: nginx
      build:
        context: .
        dockerfile: ./nginx/Dockerfile
      image: nginx
      restart: always
      depends_on: 
        - django
      ports:
        - "80:80"
      volumes:
        - ./static:/app/backend/root/staticfiles
        - ./media:/app/backend/root/project/media
  
    django:
      container_name: django
      build:
        context: backend
        dockerfile: ./root/production/Dockerfile
      hostname: django
      ports:
        - 8000:8000
      volumes:
        - ./backend:/app/
        - ./static:/app/backend/root/staticfiles
        - ./media:/app/backend/root/project/media
      depends_on: 
        - postgres
      command: &gt;
        bash -c '
        python3 ./root/manage.py collectstatic --no-input &amp;&amp;
        python3 ./root/manage.py makemigrations &amp;&amp;
        python3 ./root/manage.py migrate &amp;&amp;
        python3 ./root/manage.py initadmin &amp;&amp;
        gunicorn teddycrepineau.wsgi -b 0.0.0.0:8000 --chdir=./root/'
  
      env_file: .env 
  </code></pre>
  
  <p><strong>nginx.conf</strong></p>
  
  <pre><code>user nginx;
  worker_processes 1;
  
  error_log   /var/log/nginx/error.log warn;
  pid         /var/run/nginx.pid;
  
  events {
      worker_connections  1024;
  }
  
  http {
      include         /etc/nginx/mime.types;
      default_type    application/octet-stream;
  
      log_format main '$remote_addr - $remote_user [$time_local] "$request" '
      '$status $body_bytes_sent "$http_referer" '
      '"$http_user_agent" "$http_x_forwarded_for"';
  
      access_log      /var/log/nginx/access.log main;
  
      upstream app {
          server django:8000;
      }
  
      server {
          listen  80 default_server;
          listen  [::]:80 default_server;
          server_name localhost;
          charset utf-80;
  
          root /usr/share/nginx/html;
          index index.html;
  
          location / {
              try_files $uri $uri/ @proxy_to_app;
          }
  
          location @proxy_to_app {
              rewrite ^(.+)$ /index.html last;
          }
  
          location ^~ /static/ {
              autoindex on;
              alias /usr/share/nginx/html/static/;
          }
  
          location ^~ /media/ {
              autoindex on;
              alias /app/backend/root/project/media/;
          }
  
          location ~ ^/api {
              proxy_pass http://django:8000;
          }
          location ~ ^/admin {
              proxy_pass http://django:8000;
          }
      }
  }
  </code></pre>