Question:
How to load static files using Nginx, Docker, and Django?

Problem:

I'm trying to load static files using nginx and gunicorn, it works when i go to http://0.0.0.0/static/css/base.css >static hosted via nginx, but doesn't when i add django port http://0.0.0.0:8000/static/css/base.css >static not found using django server


these are the errors i get in my nginx container

nginx_1  | 172.22.0.1 - - [04/Oct/2023:04:59:33 +0000] "GET /static/css/base.css HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" "-"

nginx_1  | 2023/10/04 04:59:34 [error] 8#8: *2 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 172.22.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "localhost", referrer: "http://localhost/static/css/base.css"

nginx_1  | 172.22.0.1 - - [04/Oct/2023:04:59:34 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://localhost/static/css/base.css" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36" "-"



This is all what I've tried, in conf.d i put container name as server_name and tried to add types to determine css files, but it didnt work settings.py

STATIC_URL = '/static/'

STATIC_ROOT = BASE_DIR / 'static'


Dockerfile

FROM python:3.10


ENV PYTHONDONTWRITEBYTECODE=1 \

    PYTHONBUFFERED=1 \

    POETRY_VERSION=1.4.2 \

    POETRY_VIRTUALENVS_CREATE="false"


RUN pip install "poetry==$POETRY_VERSION"


WORKDIR /education_platform


COPY pyproject.toml poetry.lock docker-entrypoint.sh ./


RUN poetry install --no-interaction --no-ansi --no-dev


COPY . /education_platform


EXPOSE 8000

RUN chmod +x wait-for-it.sh


docker-compose.yaml

version: '3'


services:

  db:

    image: postgres:13.1-alpine

    restart: unless-stopped

    env_file:

      - ./.env

    volumes:

      - ./data/db:/var/lib/postgresql/data

    environment:

      - POSTGRES_DB=postgres

      - POSTGRES_USER=postgres

      - POSTGRES_PASSWORD=postgres


  cache:

    image: redis:7.0.4

    restart: unless-stopped

    volumes:

      - .data/cache:/data


  web:

    restart: unless-stopped

    build:

      context: .

      dockerfile: Dockerfile

    command: [ "/education_platform/wait-for-it.sh", "db:5432", "--",

               "gunicorn", "education_platform.wsgi:application", "-b", "0.0.0.0:8000"]

    env_file:

      - ./.env

    volumes:

      - .:/education_platform

      - ./static:/education_platform/static

    ports:

      - "8000:8000"

    environment:

      - DJANGO_SETTINGS_MODULE=education_platform.settings.prod

      - POSTGRES_DB=postgres

      - POSTGRES_USER=postgres

      - POSTGRES_PASSWORD=postgres

    depends_on:

      - db

      - cache


  nginx:

    image: nginx:1.23.1

    restart: unless-stopped

    volumes:

      - ./config/nginx/conf.d:/etc/config/nginx/conf.d/default.conf

      - ./static:/usr/share/nginx/html/static

    ports:

      - "80:80"

    command: ["/bin/sh", "-c", "nginx -g 'daemon off;'"]

    depends_on:

      - web


conf.d

server {

    listen 80;

    server_name education_platform_web_1;

    error_log stderr warn;

    access_log /dev/stdout main;


    location / {

        proxy_pass http://education_platform_web_1:8000;

        proxy_set_header Host $host;

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_set_header X-Forwarded-Host $host;

    }


    location /static/ {

        alias /usr/share/nginx/html/static/;


    }


    location /media/ {

        alias /education_platform/media/;

    }


    types {

            text/javascript js;

            application/javascript js;

            text/css css;

        }

}


Solution:

There are a couple of things missing for as far as I could see:


A volume in your Dockerfile that mounts the static files

Collectstatic

In order to prevent an extensive command in your docker-compose file I would like to suggest to following in your Dockerfile itself:


from this (docker-compose):

command: [ "/education_platform/wait-for-it.sh", "db:5432", "--",

           "gunicorn", "education_platform.wsgi:application", "-b", "0.0.0.0:8000"]

to something like this (at the end of your Dockerfile):



ENTRYPOINT ["/entrypoint.sh"]


VOLUME ["/education_platform/static"]


EXPOSE 8000


CMD ["gunicorn", "education_platform.wsgi:application", "-b", "0.0.0.0:8000"]


Now you might be wondering, where did my wait-for-it.sh script went to? And what is entrypoint.sh doing.


Here is the entrypoint.sh file:

#!/bin/bash


# wait for Postgres

/wait-for-it.sh $POSTGRES_HOST:$POSTGRES_PORT -t 60


# run migrations, collect media, start the server

python manage.py migrate

echo "yes" | python manage.py collectstatic --noinput



exec $@


And, one more thing, I see two ways of specifying environment variables. Both the env_file and environment entries are being used in your docker-compose file. Now, there might be a valid reason in your case, but if not, it might be better to use one or the other:

web:

    restart: unless-stopped

    build:

      context: .

      dockerfile: Dockerfile

    env_file:                       <---- HERE

      - ./.env

    volumes:

      - .:/education_platform

      - ./static:/education_platform/static

    ports:

      - "8000:8000"

    environment:                    <---- HERE

      - DJANGO_SETTINGS_MODULE=education_platform.settings.prod

      - POSTGRES_DB=postgres

      - POSTGRES_USER=postgres

      - POSTGRES_PASSWORD=postgres

    depends_on:

      - db

      - cache



Suggested blogs:

>How you can Show or hide elements in React?

>Implement nested serializers in the Django rest framework

>Define blade component property in server - Laravel

>Can not run phpstan under docker with memory lack error

>Attempt to read property "data_audit" on array laravel view loop foreach

>How to use start and limit on DataTables in Laravel for mobile API?

>Login to Laravel API- Laravel

>Make Xdebug stop at breakpoints in PhpStorm using Docker

>Creating a service in Laravel using app(FQCN)


Ritu Singh

Ritu Singh

Submit
0 Answers