skip to Main Content

Despite seeing many similar issues in other threads, I’ve been unable to configure Nginx to serve static files from my Django project.

Here are my two static variables in my settings.py:

STATIC_URL = '/static/'
STATIC_ROOT='/opt/django/portfolio/collectstatic'

Here is my dockerfile to build project image:

FROM python:3.11-slim

WORKDIR opt/django/
COPY pyproject.toml .
RUN python -m pip install .

COPY ./portfolio/ ./portfolio/

WORKDIR portfolio/

RUN python manage.py collectstatic --noinput
RUN python manage.py makemigrations
RUN python manage.py migrate

EXPOSE 8000

CMD ["gunicorn", "portfolio.wsgi:application", "--bind", "0.0.0.0:8000"]

Here is the docker-compose.yml:

services:
  web:
    build:
      context: .
      dockerfile: ./docker/Dockerfile_django
    container_name: webserver
    volumes:
      - static_data:/opt/django/portfolio/collectstatic
    expose:
      - "8000"
    ports:
      - "8000:8000"
    depends_on:
      - db
    networks:
      - docker_network

  db:
    image: postgres:15
    container_name: db_postgres
    expose:
      - "5432"
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    networks:
      - docker_network

  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - static_data:/opt/django/portfolio/collectstatic
    depends_on:
      - web
    networks:
      - docker_network

volumes:
  postgres_data:
  static_data:

networks:
  docker_network:
    driver: bridge
    name: docker_network

And finally, here is my nginx.conf:

events {}

http {
    server {
        listen 80;
        server_name localhost;

        location /static {
            alias /opt/django/portfolio/collectstatic;
            autoindex on;
        }

        # skip favicon.ico
        location /favicon.ico {
            access_log off;
            return 204;
        }

        location / {
            proxy_pass http://web:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

I see no errors in my logs, and nginx is reporting 200’s when I make a GET to a url in the project. When I visit http://127.0.0.1/static/website/style.css I can see the css (and js files). I’ve cleared my cache. When I go to /opt/django/portfolio/collectstatic in my web container, I can see the static files. The structure of my project is like this:

 - my_project/
   - nginx/
     - nginx.conf
   - my_project/
     - my_project/
       - settings.py
       ...
     - web/
       - js/
         - some_js.js
         - some_other_js.js
       - website/
         - style.css
       admin.py
       apps.py
       forms.py
       models.py
       tests.py
       ...

What am I missing? I appreciate any direction / feedback on potential misconfigurations I may be overlooking.

2

Answers


  1. Chosen as BEST ANSWER

    I was able to solve this by adding include mime.types; in the location /static block:

    location /static {
        alias /opt/django/portfolio/static;
        autoindex on;
        include mime.types;
    }
    

  2. The reason is most likely that the nginx process does not have the required permissions to access the /opt/django/portfolio/collectstatic folder.

    First add some debugging statements to your nginx conf like this:

    location /static {
        alias /opt/django/portfolio/collectstatic;
        autoindex on;
        access_log /var/log/nginx/static_access.log;
        error_log /var/log/nginx/static_error.log debug;
    }
    

    Obviously you have to then check the logs…

    As a first try you could startup your project, then opt into the web container and do chmod -R 755 /opt/django/portfolio/collectstatic. This should pass the correct permissions to the folder. Check if it helps, if not, again, check the error logs.

    This is a handy command to constantly monitor the error logs:
    docker-compose exec nginx tail -f /var/log/nginx/static_error.log

    Unrelated to your question a sidenote:
    It is very unusual to run the makemigrations command in production mode. In theory your dev-DB has the same structure as your prod-DB. Then you do changes during development. Here, on the dev-DB you run makemigrations, apply them with migrate and test them. When everything works, you commit the migration files to your git repo. Then for prod-DB you do not run makemigrations again. For prod-DB you only apply the migrations coming from your development/ your git repo.
    TL/DR: Develop the migrations on dev-DB with makemigrations and migrate. Only apply the migrations to prod-DB with migrate and do not use makemigrations again.

    Edit 1:

    You might need to add the mime types to your nginx.conf. I am no specialist when it comes to this; in fact I only know that I always add them. They are kind of meta-data to the file explaining the browser what type of file it is and respectively how to render it

    location /static {
        alias /opt/django/portfolio/collectstatic;
        autoindex on;
        access_log /var/log/nginx/static_access.log;
        error_log /var/log/nginx/static_error.log debug;
        include /etc/nginx/mime.types;
    }
    

    Obviously you need to make sure your container contains that file.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search