Serve Django media files via Nginx (Django / React / Nginx / Docker-Compose)

The context

I have a web application of one page using the following stack:

  • React for the frontend
  • Django for the backend
  • Nginx for the web server

The web application is dockerized with the help of docker-dial. My React application retrieves data from the Django server (django is built as an api endpoint using Django Rest Framework).

Question / Problem

I am having a deployment problem that does not allow to broadcast my media files via Nginx.

What have I tried until now?

My initial idea was to serve the media files as shown on this stackoverflow article – which is quite simple. However, since Nginx works in its own fixed menu (as well as my Django server), I can not designate my Django media files because they are in different containers.

Ideally, I would not want to use Webpack and let Nginx take care of serving the media files.

If you look at the Dockerfile nginx file below, you'll see that I'm copying my static files into / usr / share / nginx / html / static / staticfiles to serve them later with nginx (see location ^ ~ / static / in nginx.conf). I've tried doing the same thing for my media file (as a test) and it works. However, all the files I am updating once the site is created are not accessible because the copy takes place when I create my container.

File structure

Racine Dirc
| __ docker-compose.yml
| __ backend
| __ root
| __ Project
| __ api
| __ models.py
| __ ...
| __ media
| __ teddycrepineau
| __ settings.py
| __ ...
| __ production
| __ Dockerfile
| __ nginx
| __ Dockerfile
| __ nginx.conf
| __ frontend
| __ ...

Relevant code

docker-compose.yml

version: & # 39; 3 & # 39;

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
to build:
the context: .
dockerfile: ./nginx/Dockerfile
picture: nginx
restart: always
depend on:
- Django
ports:
- "80:80"

Django:
container name: django
to build:
context: backend
dockerfile: ./root/production/Dockerfile
host name: django
ports:
- 8000: 8000
volumes:
- ./backend:/app/
depend on:
- postgres
command:>
bash -c & # 39;
python3 ./root/manage.py makemigrations &&
python3 ./root/manage.py migrate &&
python3 ./root/manage.py initadmin &&
gunicorn teddycrepineau.wsgi -b 0.0.0.0:8000 --chdir =. / root / & # 39;

env_file: .env

nginx.conf

nginx user;
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" & # 39;
& # 39; $ status $ body_bytes_sent "$ http_referer" & # 39;
& # 39; "$ http_user_agent" "$ http_x_forwarded_for" & # 39 ;;

access_log /var/log/nginx/access.log main;

upstream app {
Django server: 8000;
}

server {
listen 80 default_server;
listening  [::]: 80 default_server;
server_name 0.0.0.0;
character set 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;
}
}
}

nginx Dockerfile

DE Nginx: last
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

Django Dockerfile

FROM Python: 3.7

ENV PYTHONUNBUFFERED 1

Export RUN DEBIAN_FRONTEND = non-interactive

RUN mkdir / app

RUN pip install --upgrade pip
ADD /root/requirements.txt / app /

WORKDIR / app /
ADD . / app /

RUN pip install -r Requirements.txt

EXHIBIT 8000

Django settings.py

BASE_DIR = os.path.dirname (os.path.dirname (os.path.abspath (__ file__)))
APPS_DIR = os.path.join (BASE_DIR, project & # 39;)
....
MEDIA_URL = & # 39; / media / & # 39;
MEDIA_ROOT = os.path.join (APPS_DIR, 'media /')

Django urls.py

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)


Update

When I mount a shared volume and reference in my nginx.conf I have a 404 Page not found when you try to access the downloaded image in Django's backend.

docker-compose.yml

version: & # 39; 3 & # 39;

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
to build:
the context: .
dockerfile: ./nginx/Dockerfile
picture: nginx
restart: always
depend on:
- Django
ports:
- "80:80"
volumes:
- ./static:/app/backend/root/staticfiles
- ./media:/app/backend/root/project/media

Django:
container name: django
to build:
context: backend
dockerfile: ./root/production/Dockerfile
host name: django
ports:
- 8000: 8000
volumes:
- ./backend:/app/
- ./static:/app/backend/root/staticfiles
- ./media:/app/backend/root/project/media
depend on:
- postgres
command:>
bash -c & # 39;
python3 ./root/manage.py collectstatic --no-input &&
python3 ./root/manage.py makemigrations &&
python3 ./root/manage.py migrate &&
python3 ./root/manage.py initadmin &&
gunicorn teddycrepineau.wsgi -b 0.0.0.0:8000 --chdir =. / root / & # 39;

env_file: .env 

nginx.conf

nginx user;
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" & # 39;
& # 39; $ status $ body_bytes_sent "$ http_referer" & # 39;
& # 39; "$ http_user_agent" "$ http_x_forwarded_for" & # 39 ;;

access_log /var/log/nginx/access.log main;

upstream app {
Django server: 8000;
}

server {
listen 80 default_server;
listening  [::]: 80 default_server;
server_name localhost;
character set 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;
}
}
}