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
I was able to solve this by adding
include mime.types;
in thelocation /static
block: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:
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 runmakemigrations
, apply them withmigrate
and test them. When everything works, you commit the migration files to your git repo. Then for prod-DB you do not runmakemigrations
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
andmigrate
. Only apply the migrations to prod-DB withmigrate
and do not usemakemigrations
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
Obviously you need to make sure your container contains that file.